diff options
Diffstat (limited to 'dom/flex')
-rw-r--r-- | dom/flex/Flex.cpp | 67 | ||||
-rw-r--r-- | dom/flex/Flex.h | 51 | ||||
-rw-r--r-- | dom/flex/FlexItemValues.cpp | 96 | ||||
-rw-r--r-- | dom/flex/FlexItemValues.h | 69 | ||||
-rw-r--r-- | dom/flex/FlexLineValues.cpp | 73 | ||||
-rw-r--r-- | dom/flex/FlexLineValues.h | 60 | ||||
-rw-r--r-- | dom/flex/moz.build | 28 | ||||
-rw-r--r-- | dom/flex/test/.eslintrc.js | 5 | ||||
-rw-r--r-- | dom/flex/test/chrome.ini | 7 | ||||
-rw-r--r-- | dom/flex/test/chrome/test_flex_axis_directions.html | 204 | ||||
-rw-r--r-- | dom/flex/test/chrome/test_flex_item_clamp.html | 169 | ||||
-rw-r--r-- | dom/flex/test/chrome/test_flex_item_rect.html | 124 | ||||
-rw-r--r-- | dom/flex/test/chrome/test_flex_items.html | 316 | ||||
-rw-r--r-- | dom/flex/test/chrome/test_flex_lines.html | 336 | ||||
-rw-r--r-- | dom/flex/test/chrome/test_flex_object.html | 132 | ||||
-rw-r--r-- | dom/flex/test/chrome/test_flex_parent.html | 133 |
16 files changed, 1870 insertions, 0 deletions
diff --git a/dom/flex/Flex.cpp b/dom/flex/Flex.cpp new file mode 100644 index 0000000000..898e81d4f5 --- /dev/null +++ b/dom/flex/Flex.cpp @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Flex.h" + +#include "FlexLineValues.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/FlexBinding.h" +#include "nsFlexContainerFrame.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Flex, mParent, mLines) +NS_IMPL_CYCLE_COLLECTING_ADDREF(Flex) +NS_IMPL_CYCLE_COLLECTING_RELEASE(Flex) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Flex) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +Flex::Flex(Element* aParent, nsFlexContainerFrame* aFrame) : mParent(aParent) { + MOZ_ASSERT(aFrame, + "Should never be instantiated with a null nsFlexContainerFrame"); + + // Eagerly create property values from aFrame, because we're not + // going to keep it around. + const ComputedFlexContainerInfo* containerInfo = + aFrame->GetFlexContainerInfo(); + if (!containerInfo) { + // It's weird but possible to fail to get a ComputedFlexContainerInfo + // structure. Assign sensible default values. + mMainAxisDirection = FlexPhysicalDirection::Horizontal_lr; + mCrossAxisDirection = FlexPhysicalDirection::Vertical_tb; + return; + } + mLines.SetLength(containerInfo->mLines.Length()); + uint32_t index = 0; + for (auto&& l : containerInfo->mLines) { + FlexLineValues* line = new FlexLineValues(this, &l); + mLines.ElementAt(index) = line; + index++; + } + + mMainAxisDirection = containerInfo->mMainAxisDirection; + mCrossAxisDirection = containerInfo->mCrossAxisDirection; +} + +JSObject* Flex::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { + return Flex_Binding::Wrap(aCx, this, aGivenProto); +} + +void Flex::GetLines(nsTArray<RefPtr<FlexLineValues>>& aResult) { + aResult.AppendElements(mLines); +} + +FlexPhysicalDirection Flex::MainAxisDirection() const { + return mMainAxisDirection; +} + +FlexPhysicalDirection Flex::CrossAxisDirection() const { + return mCrossAxisDirection; +} + +} // namespace mozilla::dom diff --git a/dom/flex/Flex.h b/dom/flex/Flex.h new file mode 100644 index 0000000000..27237acb3d --- /dev/null +++ b/dom/flex/Flex.h @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_Flex_h +#define mozilla_dom_Flex_h + +#include "mozilla/dom/FlexBinding.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" + +class nsFlexContainerFrame; + +namespace mozilla { +namespace dom { + +class Element; +class FlexLineValues; + +class Flex : public nsISupports, public nsWrapperCache { + public: + explicit Flex(Element* aParent, nsFlexContainerFrame* aFrame); + + protected: + virtual ~Flex() = default; + + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Flex) + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + Element* GetParentObject() { return mParent; } + + void GetLines(nsTArray<RefPtr<FlexLineValues>>& aResult); + FlexPhysicalDirection MainAxisDirection() const; + FlexPhysicalDirection CrossAxisDirection() const; + + protected: + nsCOMPtr<Element> mParent; + nsTArray<RefPtr<FlexLineValues>> mLines; + FlexPhysicalDirection mMainAxisDirection; + FlexPhysicalDirection mCrossAxisDirection; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_Flex_h */ diff --git a/dom/flex/FlexItemValues.cpp b/dom/flex/FlexItemValues.cpp new file mode 100644 index 0000000000..9a9be8412f --- /dev/null +++ b/dom/flex/FlexItemValues.cpp @@ -0,0 +1,96 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FlexItemValues.h" + +#include "mozilla/dom/DOMRect.h" +#include "mozilla/dom/FlexBinding.h" +#include "mozilla/dom/FlexLineValues.h" +#include "nsFlexContainerFrame.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FlexItemValues, mParent, mNode, + mFrameRect) +NS_IMPL_CYCLE_COLLECTING_ADDREF(FlexItemValues) +NS_IMPL_CYCLE_COLLECTING_RELEASE(FlexItemValues) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlexItemValues) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +/** + * Utility function to convert a nscoord size to CSS pixel values, with + * graceful treatment of NS_UNCONSTRAINEDSIZE (which this function converts to + * the double "positive infinity" value). + * + * This function is suitable for converting quantities that are expected to + * sometimes legitimately (rather than arbitrarily/accidentally) contain the + * sentinel value NS_UNCONSTRAINEDSIZE -- e.g. to handle "max-width: none". + */ +static double ToPossiblyUnconstrainedPixels(nscoord aSize) { + if (aSize == NS_UNCONSTRAINEDSIZE) { + return std::numeric_limits<double>::infinity(); + } + return nsPresContext::AppUnitsToDoubleCSSPixels(aSize); +} + +FlexItemValues::FlexItemValues(FlexLineValues* aParent, + const ComputedFlexItemInfo* aItem) + : mParent(aParent) { + MOZ_ASSERT(aItem, + "Should never be instantiated with a null ComputedFlexLineInfo."); + + // Eagerly copy values from aItem, because we're not + // going to keep it around. + mNode = aItem->mNode; + + // Since mNode might be null, we associate the mFrameRect with + // our parent. + mFrameRect = new DOMRectReadOnly( + mParent, nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mFrameRect.X()), + nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mFrameRect.Y()), + nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mFrameRect.Width()), + nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mFrameRect.Height())); + + // Convert app unit sizes to css pixel sizes. + mMainBaseSize = + nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mMainBaseSize); + mMainDeltaSize = + nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mMainDeltaSize); + mMainMinSize = nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mMainMinSize); + mMainMaxSize = ToPossiblyUnconstrainedPixels(aItem->mMainMaxSize); + mCrossMinSize = + nsPresContext::AppUnitsToDoubleCSSPixels(aItem->mCrossMinSize); + mCrossMaxSize = ToPossiblyUnconstrainedPixels(aItem->mCrossMaxSize); + + mClampState = aItem->mClampState; +} + +JSObject* FlexItemValues::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return FlexItemValues_Binding::Wrap(aCx, this, aGivenProto); +} + +nsINode* FlexItemValues::GetNode() const { return mNode; } + +DOMRectReadOnly* FlexItemValues::FrameRect() const { return mFrameRect; } + +double FlexItemValues::MainBaseSize() const { return mMainBaseSize; } + +double FlexItemValues::MainDeltaSize() const { return mMainDeltaSize; } + +double FlexItemValues::MainMinSize() const { return mMainMinSize; } + +double FlexItemValues::MainMaxSize() const { return mMainMaxSize; } + +double FlexItemValues::CrossMinSize() const { return mCrossMinSize; } + +double FlexItemValues::CrossMaxSize() const { return mCrossMaxSize; } + +FlexItemClampState FlexItemValues::ClampState() const { return mClampState; } + +} // namespace mozilla::dom diff --git a/dom/flex/FlexItemValues.h b/dom/flex/FlexItemValues.h new file mode 100644 index 0000000000..c775cdbcfa --- /dev/null +++ b/dom/flex/FlexItemValues.h @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FlexItemValues_h +#define mozilla_dom_FlexItemValues_h + +#include "mozilla/dom/FlexBinding.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" + +struct ComputedFlexItemInfo; + +class nsINode; + +namespace mozilla { +namespace dom { + +class DOMRectReadOnly; + +class FlexLineValues; + +class FlexItemValues : public nsISupports, public nsWrapperCache { + public: + explicit FlexItemValues(FlexLineValues* aParent, + const ComputedFlexItemInfo* aItem); + + protected: + virtual ~FlexItemValues() = default; + + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlexItemValues) + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + FlexLineValues* GetParentObject() { return mParent; } + + nsINode* GetNode() const; + DOMRectReadOnly* FrameRect() const; + double MainBaseSize() const; + double MainDeltaSize() const; + double MainMinSize() const; + double MainMaxSize() const; + double CrossMinSize() const; + double CrossMaxSize() const; + FlexItemClampState ClampState() const; + + protected: + RefPtr<FlexLineValues> mParent; + RefPtr<nsINode> mNode; + RefPtr<DOMRectReadOnly> mFrameRect; + + // These sizes are all CSS pixel units. + double mMainBaseSize; + double mMainDeltaSize; + double mMainMinSize; + double mMainMaxSize; + double mCrossMinSize; + double mCrossMaxSize; + FlexItemClampState mClampState; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_FlexItemValues_h */ diff --git a/dom/flex/FlexLineValues.cpp b/dom/flex/FlexLineValues.cpp new file mode 100644 index 0000000000..aac403d58a --- /dev/null +++ b/dom/flex/FlexLineValues.cpp @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FlexLineValues.h" + +#include "Flex.h" +#include "FlexItemValues.h" +#include "mozilla/dom/FlexBinding.h" +#include "nsFlexContainerFrame.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FlexLineValues, mParent, mItems) +NS_IMPL_CYCLE_COLLECTING_ADDREF(FlexLineValues) +NS_IMPL_CYCLE_COLLECTING_RELEASE(FlexLineValues) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlexLineValues) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +FlexLineValues::FlexLineValues(Flex* aParent, const ComputedFlexLineInfo* aLine) + : mParent(aParent) { + MOZ_ASSERT(aLine, + "Should never be instantiated with a null ComputedFlexLineInfo."); + + // Eagerly copy values from aLine, because we're not + // going to keep it around. + mGrowthState = aLine->mGrowthState; + + // Convert all the app unit values into css pixels. + mCrossStart = nsPresContext::AppUnitsToDoubleCSSPixels(aLine->mCrossStart); + mCrossSize = nsPresContext::AppUnitsToDoubleCSSPixels(aLine->mCrossSize); + mFirstBaselineOffset = + nsPresContext::AppUnitsToDoubleCSSPixels(aLine->mFirstBaselineOffset); + mLastBaselineOffset = + nsPresContext::AppUnitsToDoubleCSSPixels(aLine->mLastBaselineOffset); + + mItems.SetLength(aLine->mItems.Length()); + uint32_t index = 0; + for (auto&& i : aLine->mItems) { + FlexItemValues* item = new FlexItemValues(this, &i); + mItems.ElementAt(index) = item; + index++; + } +} + +JSObject* FlexLineValues::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return FlexLineValues_Binding::Wrap(aCx, this, aGivenProto); +} + +FlexLineGrowthState FlexLineValues::GrowthState() const { return mGrowthState; } + +double FlexLineValues::CrossStart() const { return mCrossStart; } + +double FlexLineValues::CrossSize() const { return mCrossSize; } + +double FlexLineValues::FirstBaselineOffset() const { + return mFirstBaselineOffset; +} + +double FlexLineValues::LastBaselineOffset() const { + return mLastBaselineOffset; +} + +void FlexLineValues::GetItems(nsTArray<RefPtr<FlexItemValues>>& aResult) { + aResult.AppendElements(mItems); +} + +} // namespace mozilla::dom diff --git a/dom/flex/FlexLineValues.h b/dom/flex/FlexLineValues.h new file mode 100644 index 0000000000..ec8625d6b2 --- /dev/null +++ b/dom/flex/FlexLineValues.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FlexLineValues_h +#define mozilla_dom_FlexLineValues_h + +#include "mozilla/dom/FlexBinding.h" +#include "nsISupports.h" +#include "nsWrapperCache.h" + +struct ComputedFlexLineInfo; + +namespace mozilla { +namespace dom { + +class Flex; +class FlexItemValues; + +class FlexLineValues : public nsISupports, public nsWrapperCache { + public: + explicit FlexLineValues(Flex* aParent, const ComputedFlexLineInfo* aLine); + + protected: + virtual ~FlexLineValues() = default; + + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlexLineValues) + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + Flex* GetParentObject() { return mParent; } + + FlexLineGrowthState GrowthState() const; + double CrossStart() const; + double CrossSize() const; + double FirstBaselineOffset() const; + double LastBaselineOffset() const; + + void GetItems(nsTArray<RefPtr<FlexItemValues>>& aResult); + + protected: + RefPtr<Flex> mParent; + + FlexLineGrowthState mGrowthState; + double mCrossStart; + double mCrossSize; + double mFirstBaselineOffset; + double mLastBaselineOffset; + + nsTArray<RefPtr<FlexItemValues>> mItems; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_FlexLineValues_h */ diff --git a/dom/flex/moz.build b/dom/flex/moz.build new file mode 100644 index 0000000000..802ac5b18c --- /dev/null +++ b/dom/flex/moz.build @@ -0,0 +1,28 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +with Files("**"): + BUG_COMPONENT = ("Core", "CSS Parsing and Computation") + +MOCHITEST_CHROME_MANIFESTS += ["test/chrome.ini"] + +EXPORTS.mozilla.dom += [ + "Flex.h", + "FlexItemValues.h", + "FlexLineValues.h", +] + +UNIFIED_SOURCES += [ + "Flex.cpp", + "FlexItemValues.cpp", + "FlexLineValues.cpp", +] + +LOCAL_INCLUDES += [ + "/layout/generic", +] + +FINAL_LIBRARY = "xul" diff --git a/dom/flex/test/.eslintrc.js b/dom/flex/test/.eslintrc.js new file mode 100644 index 0000000000..f667a57bf5 --- /dev/null +++ b/dom/flex/test/.eslintrc.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + extends: ["plugin:mozilla/chrome-test"], +}; diff --git a/dom/flex/test/chrome.ini b/dom/flex/test/chrome.ini new file mode 100644 index 0000000000..4b4bc02272 --- /dev/null +++ b/dom/flex/test/chrome.ini @@ -0,0 +1,7 @@ +[chrome/test_flex_axis_directions.html] +[chrome/test_flex_item_clamp.html] +[chrome/test_flex_item_rect.html] +[chrome/test_flex_items.html] +[chrome/test_flex_lines.html] +[chrome/test_flex_object.html] +[chrome/test_flex_parent.html] diff --git a/dom/flex/test/chrome/test_flex_axis_directions.html b/dom/flex/test/chrome/test_flex_axis_directions.html new file mode 100644 index 0000000000..cc9f85eaf6 --- /dev/null +++ b/dom/flex/test/chrome/test_flex_axis_directions.html @@ -0,0 +1,204 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> + f { + display: flex; + width: 400px; + height: 50px; + margin-bottom: 2px; + } + + b { + background-color: gold; + width: 100px; + height: 15px; + } + b::after { + content: "B"; + } + + c { + background-color: yellow; + width: 100px; + height: 15px; + } + c::after { + content: "C"; + } + + d { + background-color: orange; + width: 100px; + height: 15px; + } + d::after { + content: "D"; + } + + .fdR { + flex-direction: row; + background-color: lightgrey; + } + .fdRR { + flex-direction: row-reverse; + background-color: lightgreen; + } + .fdC { + flex-direction: column; + background-color: lightblue; + } + .fdCR { + flex-direction: column-reverse; + background-color: lavender; + } + + .wmHTB { + writing-mode: horizontal-tb; + } + .wmVLR { + writing-mode: vertical-lr; + } + .wmVRL { + writing-mode: vertical-rl; + } + .wmSLR { + writing-mode: sideways-lr; + } + .wmSRL { + writing-mode: sideways-rl; + } + + .dLR { + direction: ltr; + } + .dRL { + direction: rtl; + } +</style> + +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +function testContainerMatchesExpectedValues(flex, values, flexIndex) { + is(flex.mainAxisDirection, values.m, "Flex index " + flexIndex + " should have expected mainAxisDirection."); + is(flex.crossAxisDirection, values.c, "Flex index " + flexIndex + " should have expected crossAxisDirection."); +} + +function runTests() { + const expectedValues = [ + { m: "horizontal-lr", c: "vertical-tb" }, + { m: "horizontal-rl", c: "vertical-tb" }, + { m: "vertical-tb", c: "horizontal-lr" }, + { m: "vertical-bt", c: "horizontal-lr" }, + { m: "vertical-tb", c: "horizontal-rl" }, + { m: "vertical-bt", c: "horizontal-rl" }, + { m: "vertical-bt", c: "horizontal-lr" }, + { m: "vertical-tb", c: "horizontal-lr" }, + { m: "vertical-tb", c: "horizontal-rl" }, + { m: "vertical-bt", c: "horizontal-rl" }, + + { m: "horizontal-rl", c: "vertical-tb" }, + { m: "horizontal-lr", c: "vertical-tb" }, + { m: "vertical-bt", c: "horizontal-lr" }, + { m: "vertical-tb", c: "horizontal-lr" }, + { m: "vertical-bt", c: "horizontal-rl" }, + { m: "vertical-tb", c: "horizontal-rl" }, + { m: "vertical-tb", c: "horizontal-lr" }, + { m: "vertical-bt", c: "horizontal-lr" }, + { m: "vertical-bt", c: "horizontal-rl" }, + { m: "vertical-tb", c: "horizontal-rl" }, + + { m: "vertical-tb", c: "horizontal-lr" }, + { m: "vertical-tb", c: "horizontal-rl" }, + { m: "horizontal-lr", c: "vertical-tb" }, + { m: "horizontal-lr", c: "vertical-bt" }, + { m: "horizontal-rl", c: "vertical-tb" }, + { m: "horizontal-rl", c: "vertical-bt" }, + { m: "horizontal-lr", c: "vertical-bt" }, + { m: "horizontal-lr", c: "vertical-tb" }, + { m: "horizontal-rl", c: "vertical-tb" }, + { m: "horizontal-rl", c: "vertical-bt" }, + + { m: "vertical-bt", c: "horizontal-lr" }, + { m: "vertical-bt", c: "horizontal-rl" }, + { m: "horizontal-rl", c: "vertical-tb" }, + { m: "horizontal-rl", c: "vertical-bt" }, + { m: "horizontal-lr", c: "vertical-tb" }, + { m: "horizontal-lr", c: "vertical-bt" }, + { m: "horizontal-rl", c: "vertical-bt" }, + { m: "horizontal-rl", c: "vertical-tb" }, + { m: "horizontal-lr", c: "vertical-tb" }, + { m: "horizontal-lr", c: "vertical-bt" }, + ]; + + const children = document.body.children; + is(children.length, expectedValues.length, "Document should have expected number of flex containers."); + + for (let i = 0; i < children.length; ++i) { + const flex = children.item(i).getAsFlexContainer(); + ok(flex, "Document child index " + i + " should be a flex container."); + if (flex) { + const values = expectedValues[i]; + testContainerMatchesExpectedValues(flex, values, i); + } + } + + SimpleTest.finish(); +} +</script> +</head> + +<body onLoad="runTests();"> + +<f class="fdR wmHTB dLR"><b></b><c></c><d></d></f> +<f class="fdR wmHTB dRL"><b></b><c></c><d></d></f> +<f class="fdR wmVLR dLR"><b></b><c></c><d></d></f> +<f class="fdR wmVLR dRL"><b></b><c></c><d></d></f> +<f class="fdR wmVRL dLR"><b></b><c></c><d></d></f> +<f class="fdR wmVRL dRL"><b></b><c></c><d></d></f> +<f class="fdR wmSLR dLR"><b></b><c></c><d></d></f> +<f class="fdR wmSLR dRL"><b></b><c></c><d></d></f> +<f class="fdR wmSRL dLR"><b></b><c></c><d></d></f> +<f class="fdR wmSRL dRL"><b></b><c></c><d></d></f> + +<f class="fdRR wmHTB dLR"><b></b><c></c><d></d></f> +<f class="fdRR wmHTB dRL"><b></b><c></c><d></d></f> +<f class="fdRR wmVLR dLR"><b></b><c></c><d></d></f> +<f class="fdRR wmVLR dRL"><b></b><c></c><d></d></f> +<f class="fdRR wmVRL dLR"><b></b><c></c><d></d></f> +<f class="fdRR wmVRL dRL"><b></b><c></c><d></d></f> +<f class="fdRR wmSLR dLR"><b></b><c></c><d></d></f> +<f class="fdRR wmSLR dRL"><b></b><c></c><d></d></f> +<f class="fdRR wmSRL dLR"><b></b><c></c><d></d></f> +<f class="fdRR wmSRL dRL"><b></b><c></c><d></d></f> + +<f class="fdC wmHTB dLR"><b></b><c></c><d></d></f> +<f class="fdC wmHTB dRL"><b></b><c></c><d></d></f> +<f class="fdC wmVLR dLR"><b></b><c></c><d></d></f> +<f class="fdC wmVLR dRL"><b></b><c></c><d></d></f> +<f class="fdC wmVRL dLR"><b></b><c></c><d></d></f> +<f class="fdC wmVRL dRL"><b></b><c></c><d></d></f> +<f class="fdC wmSLR dLR"><b></b><c></c><d></d></f> +<f class="fdC wmSLR dRL"><b></b><c></c><d></d></f> +<f class="fdC wmSRL dLR"><b></b><c></c><d></d></f> +<f class="fdC wmSRL dRL"><b></b><c></c><d></d></f> + +<f class="fdCR wmHTB dLR"><b></b><c></c><d></d></f> +<f class="fdCR wmHTB dRL"><b></b><c></c><d></d></f> +<f class="fdCR wmVLR dLR"><b></b><c></c><d></d></f> +<f class="fdCR wmVLR dRL"><b></b><c></c><d></d></f> +<f class="fdCR wmVRL dLR"><b></b><c></c><d></d></f> +<f class="fdCR wmVRL dRL"><b></b><c></c><d></d></f> +<f class="fdCR wmSLR dLR"><b></b><c></c><d></d></f> +<f class="fdCR wmSLR dRL"><b></b><c></c><d></d></f> +<f class="fdCR wmSRL dLR"><b></b><c></c><d></d></f> +<f class="fdCR wmSRL dRL"><b></b><c></c><d></d></f> + +</body> +</html> diff --git a/dom/flex/test/chrome/test_flex_item_clamp.html b/dom/flex/test/chrome/test_flex_item_clamp.html new file mode 100644 index 0000000000..6624b3ee20 --- /dev/null +++ b/dom/flex/test/chrome/test_flex_item_clamp.html @@ -0,0 +1,169 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> +f { + display: flex; + background-color: grey; + width: 400px; + height: 20px; + margin-bottom: 5px; +} + +b { + flex-basis: 100px; + flex-grow: 1; + flex-shrink: 1; + background-color: gold; +} + +c { + flex-basis: 100px; + flex-grow: 1; + flex-shrink: 1; + background-color: yellow; +} + +d { + flex: none; + background-color: orange; +} + +b::after, c::after, d::after { + content: ""; + display: block; + width: 10px; + height: 10px; + border: 1px solid teal; +} + + +.min50 { + min-width: 50px; +} +.min370 { + min-width: 370px; +} +.min400 { + min-width: 400px; +} + +.max5 { + max-width: 5px; +} +.max50 { + max-width: 50px; +} + +</style> + +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +const TEXT_NODE = Node.TEXT_NODE; + +function testItemMatchesExpectedValues(item, values, index) { + is(item.clampState, values.cs, "Item index " + index + " should have expected clampState."); +} + +function runTests() { + /** + * The expectedValues array contains one element for each flex container child of + * of the body. The values in this object are compared against the returned flex + * API values of the first flex item in the first line of the corresponding flex + * container. The "cs" value is compared against the flex item's clampState. + **/ + const expectedValues = [ + { cs: "unclamped" }, + { cs: "unclamped" }, + { cs: "unclamped" }, + { cs: "unclamped" }, + + { cs: "clamped_to_min" }, + { cs: "clamped_to_min" }, + { cs: "clamped_to_min" }, + { cs: "clamped_to_min" }, + { cs: "clamped_to_min" }, + + { cs: "clamped_to_max" }, + { cs: "clamped_to_max" }, + { cs: "clamped_to_max" }, + { cs: "clamped_to_max" }, + { cs: "clamped_to_max" }, + ]; + + let children = document.body.children; + is(children.length, expectedValues.length, "Document should have expected number of flex containers."); + + for (let i = 0; i < children.length; ++i) { + const flex = children.item(i).getAsFlexContainer(); + ok(flex, "Document child index " + i + " should be a flex container."); + if (flex) { + const values = expectedValues[i]; + const item = flex.getLines()[0].getItems()[0]; + testItemMatchesExpectedValues(item, values, i); + } + } + + SimpleTest.finish(); +} +</script> +</head> + +<body onLoad="runTests();"> + <!-- unclamped cases --> + <!-- a flex:none item --> + <f><d></d></f> + + <!-- a flex-grow item with room to grow --> + <f><b class="min370"></b></f> + + <!-- a flex-shrink item with room to shrink --> + <f><b class="max50"></b><c class="min370"></c></f> + + <!-- a flex-grow basis 100px item paired with a basis 200px item, where the second item is clamped, + and the first item then can grow past its minimum --> + <f><b style="min-width: 170px"></b><c class="max50" style="flex-basis:200px"></c></f> + + + <!-- clamped_to_min cases --> + <!-- a flex-grow item with a min smaller than the container --> + <f><b class="min370"></b><c></c></f> + + <!-- a flex-shrink item with a min, paired with another that in total exceeds the container --> + <f><b class="min50"></b><c class="min370"></c></f> + + <!-- a flex-shrink item shrunk to its (content-based) automatic minimum size --> + <f><b></b><c class="min400"></c></f> + + <!-- a flex:none item with a min that is larger than its flex base size --> + <f><d class="min50"></d><c></c></f> + + <!-- a flex-grow item paired with another flex-grow item that have equal-sized violations of + the first item's min with the second item's max --> + <f><b style="min-width: 200px"></b><c style="flex-basis:150px; max-width:200px"></c></f> + + + <!-- clamped_to_max cases --> + <!-- a flexible item with a max --> + <f><b class="max50"></b></f> + + <!-- a flexible item with a max, paired with another flex-grow item --> + <f><b class="max50"></b><c></c></f> + + <!-- a flexible item with a max smaller than its content size --> + <f><b class="max5"></b><c></c></f> + + <!-- a flex:none item with a max smaller than its content size --> + <f><d class="max5"></d><c></c></f> + + <!-- a flex-grow item paired with another flex-grow item that have equal-sized violations of + the first item's max with the second item's min --> + <f><b style="flex-basis:150px; max-width:200px"></b><c style="min-width: 200px"></c></f> +</body> +</html> diff --git a/dom/flex/test/chrome/test_flex_item_rect.html b/dom/flex/test/chrome/test_flex_item_rect.html new file mode 100644 index 0000000000..c535ea756b --- /dev/null +++ b/dom/flex/test/chrome/test_flex_item_rect.html @@ -0,0 +1,124 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> +f { + display: flex; + background-color: grey; + width: 400px; + height: 25px; + margin-bottom: 5px; +} + +f > * { + width: 100px; + height: 10px; +} + +b { + background-color: gold; +} + +c { + background-color: yellow; +} +</style> + +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +function testItemMatchesExpectedValues(item, values, index) { + is(item.frameRect.x, values.x, + "Item index " + index + " should have expected frameRect.x."); + is(item.frameRect.y, values.y, + "Item index " + index + " should have expected frameRect.y."); + if (typeof(values.width) != "undefined") { + is(item.frameRect.width, values.width, + "Item index " + index + " should have expected frameRect.width."); + } + is(item.frameRect.height, values.height, + "Item index " + index + " should have expected frameRect.height."); +} + +function runTests() { + /** + * The expectedValues array contains one rect for each flex container child of + * of the body. The values in this object are compared against the returned flex + * API values of the LAST flex item in the first line of the corresponding flex + * container. + **/ + const expectedValues = [ + { x: 0, y: 0, width: 100, height: 10 }, + { x: 0, y: 0, width: undefined /* not tested */, height: 25 /* stretched to container */ }, + { x: 0, y: 0, width: 100, height: 10 }, + { x: 0, y: 0, width: 100, height: 10 }, + { x: 100, y: 0, width: 100, height: 10 }, + { x: 10, y: 10, width: 100, height: 10 }, + { x: 10, y: 10, width: 100, height: 10 }, + { x: 0, y: 0, width: 200, height: 20 }, + { x: 0, y: 0, width: 400, height: 25 }, + { x: 0, y: 0, width: 100, height: 10 }, + { x: 0, y: 0, width: 100, height: 10 }, + ]; + + let children = document.body.children; + is(children.length, expectedValues.length, "Document should have expected number of flex containers."); + + for (let i = 0; i < children.length; ++i) { + const flex = children.item(i).getAsFlexContainer(); + ok(flex, "Document child index " + i + " should be a flex container."); + if (flex) { + const values = expectedValues[i]; + const firstLine = flex.getLines()[0]; + const items = firstLine.getItems(); + const lastItem = items[items.length - 1]; + testItemMatchesExpectedValues(lastItem, values, i); + } + } + + SimpleTest.finish(); +} +</script> +</head> + +<body onLoad="runTests();"> + <!-- a single item --> + <f><b></b></f> + + <!-- an anonymous box item around a text node --> + <f style="font-size: 10px">anonymous</f> + + <!-- a table item --> + <f><table></table></f> + + <!-- a display:table-cell item --> + <f><b style="display: table-cell"></b></f> + + <!-- an item after a fixed size item --> + <f><b></b><c></c></f> + + <!-- a relatively-positioned item --> + <f><b style="position: relative; top: 10px; left: 10px"></b></f> + + <!-- a margin-adjusted item --> + <f><b style="margin-top: 10px; margin-left: 10px"></b></f> + + <!-- an item sized with inline styles --> + <f><b style="width: 200px; height: 20px"></b></f> + + <!-- an item that is flexed/stretched, in both axes --> + <f style="align-items: stretch"><b style="flex-grow: 1; height: auto"></b></f> + + <!-- These stylings should have no effect on the frameRect. --> + <!-- a transform:scale item --> + <f><b style="transform: scale(2.0)"></b></f> + + <!-- a transform:translate item --> + <f><b style="transform: translate(10px, 10px)"></b></f> +</body> +</html> diff --git a/dom/flex/test/chrome/test_flex_items.html b/dom/flex/test/chrome/test_flex_items.html new file mode 100644 index 0000000000..0bed577ae7 --- /dev/null +++ b/dom/flex/test/chrome/test_flex_items.html @@ -0,0 +1,316 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> + .container { + display: flex; + background-color: grey; + font: 14px sans-serif; + height: 50px; + } + #flex-sanity { + /* This just needs to be large enough so that no shrinking is required. */ + width: 1600px; + } + .clamped-huge-item { + flex: 1 1 1650px; /* This needs to be bigger than #flex-sanity, to test + the scenario it's aiming to test (early clamping of a + flex item which, if left unclamped, would've reversed + the direction of flexing & made everything shrink). */ + max-width: 10px; + } + + .base { align-self: baseline; } + .lastbase { align-self: last baseline; } + + .offset { margin-top: 10px; + margin-bottom: 3px; } + + .lime { background: lime; } + .yellow { background: yellow; } + .orange { background: orange; } + .pink { background: pink; } + .tan { background: tan; } + .white { background: white; } + + .crossMinMax { min-height: 40px; + max-height: 120px; } + + .mainMinMax { min-width: 120px; + max-width: 500px; } + + .flexGrow { flex-grow: 1; } + .spacer150 { width: 150px; + box-sizing: border-box; + height: 10px; + border: 1px solid teal; } + +</style> + +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +const TEXT_NODE = Node.TEXT_NODE; + +function testItemMatchesExpectedValues(item, values, index) { + if (typeof(values.node) != "undefined") { + is(item.node, values.node, "Item index " + index + " has expected node."); + } + + if (typeof(values.mainBaseSize) != "undefined") { + is(item.mainBaseSize, values.mainBaseSize, "Item index " + index + " has expected mainBaseSize."); + } + + if (typeof(values.mainDeltaSize) != "undefined") { + is(item.mainDeltaSize, values.mainDeltaSize, "Item index " + index + " has expected mainDeltaSize."); + } + + if (typeof(values.mainMinSize) != "undefined") { + is(item.mainMinSize, values.mainMinSize, "Item index " + index + " has expected mainMinSize."); + } + + if (typeof(values.mainMaxSize) != "undefined") { + is(item.mainMaxSize, values.mainMaxSize, "Item index " + index + " has expected mainMaxSize."); + } else { + // If we didn't specify an expected mainMaxSize, then it's implied + // that the max main-size property (max-width/max-height) is at its + // default "none" value, which our FlexItem API represents as +infinity. + is(item.mainMaxSize, Number.POSITIVE_INFINITY, + "Item index " + index + " has expected (default) mainMaxSize."); + } + + if (typeof(values.crossMinSize) != "undefined") { + is(item.crossMinSize, values.crossMinSize, "Item index " + index + " has expected crossMinSize."); + } + + if (typeof(values.crossMaxSize) != "undefined") { + is(item.crossMaxSize, values.crossMaxSize, "Item index " + index + " has expected crossMaxSize."); + } else { + // As above for mainMaxSize, no-expected-value implies we expect +infinity. + is(item.crossMaxSize, Number.POSITIVE_INFINITY, + "Item index " + index + " has expected (default) crossMaxSize."); + } +} + +// Test for items in "flex-sanity" flex container: +function testFlexSanity() { + let container = document.getElementById("flex-sanity"); + let flex = container.getAsFlexContainer(); + let lines = flex.getLines(); + is(lines.length, 1, "Container should have expected number of lines."); + + let line = lines[0]; + let containerHeight = container.getBoundingClientRect().height; + is(line.crossSize, containerHeight, + "Line crossSize should equal the height of the container."); + + // We can't compare baselines precisely, so we'll just confirm that they + // appear somewhere within the elements that determine them. + // (This assumes the first rect is baseline-aligned.) + let firstRect = container.firstElementChild.getBoundingClientRect(); + ok(line.firstBaselineOffset > firstRect.top && + line.firstBaselineOffset < firstRect.bottom, + "Line firstBaselineOffset should land somewhere within the element " + + "that determines it."); + + // For last baseline, it's measured from the bottom, so we have to compare + // against the element bounds subtracted from the container height. + // We use the first node which uses last-baseline ("lb") alignment to + // provide the rect: + let lbElem = document.querySelector(".lastbase"); + let lbElemBoundingRect = lbElem.getBoundingClientRect(); + ok(line.lastBaselineOffset > containerHeight - lbElemBoundingRect.bottom && + line.lastBaselineOffset < containerHeight - lbElemBoundingRect.top, + "Line lastBaselineOffset should land somewhere within the element" + + "that determines it."); + + let expectedValues = [ + { crossMinSize: 0 }, + { mainBaseSize: 100, + mainDeltaSize: 0 }, + { crossMinSize: 40, + crossMaxSize: 120, + mainDeltaSize: 0 }, + { mainMinSize: 120, + mainMaxSize: 500, + mainDeltaSize: 0 }, + { mainMinSize: 120, + mainMaxSize: 500, + mainBaseSize: 150, + mainDeltaSize: 0 }, + { mainBaseSize: 10, + mainMaxSize: 5, + mainDeltaSize: 0 }, + { mainBaseSize: 10, + mainMinSize: 15, + mainDeltaSize: 0 }, + { mainBaseSize: 50, + mainMaxSize: 10 }, + { mainBaseSize: 1650, + mainMaxSize: 10, + mainDeltaSize: 0 }, + { mainDeltaSize: 0 }, + { /* final item is anonymous flex item */ }, + ]; + + let items = line.getItems(); + is(items.length, expectedValues.length, + "Line should have expected number of items."); + is(items.length, container.children.length + 1, + "Line should have as many items as the flex container has child elems, " + + "plus 1 for anonymous flex item"); + + for (let i = 0; i < items.length; ++i) { + let item = items[i]; + let values = expectedValues[i]; + // set the expected node to the node we're currently iterating over, + // except for: + // - the display:contents element (whose item is its first child) + // - the final item (which is an anonymous flex item around text) + if (i < container.children.length) { + let curElem = container.children[i]; + values.node = (curElem.style.display == "contents" + ? curElem.firstElementChild + : curElem); + } else { + is(container.lastChild.nodeType, TEXT_NODE, + "container's last child should be a text node"); + values.node = container.lastChild; + } + testItemMatchesExpectedValues(item, values, i); + } + + // Check that the delta size of the first item is (roughly) equal to the + // actual size minus the base size. + isfuzzy(items[0].mainDeltaSize, firstRect.width - items[0].mainBaseSize, 1e-4, + "flex-grow item should have expected mainDeltaSize."); +} + +// Test for items in "flex-growing" flex container: +function testFlexGrowing() { + let expectedValues = [ + { mainBaseSize: 10, + mainDeltaSize: 10, + mainMinSize: 35 }, + { mainBaseSize: 20, + mainDeltaSize: 5, + mainMinSize: 28 }, + { mainBaseSize: 30, + mainDeltaSize: 7 }, + { mainBaseSize: 0, + mainDeltaSize: 48, + mainMaxSize: 20 }, + ]; + + let container = document.getElementById("flex-growing"); + let items = container.getAsFlexContainer().getLines()[0].getItems(); + is(items.length, container.children.length, + "Line should have as many items as the flex container has child elems"); + + for (let i = 0; i < items.length; ++i) { + let item = items[i]; + let values = expectedValues[i]; + testItemMatchesExpectedValues(item, values, i); + } +} + +function runTests() { + testFlexSanity(); + testFlexGrowing(); + SimpleTest.finish(); +} +</script> +</head> + +<body onLoad="runTests();"> + <!-- First flex container to be tested: "flex-sanity". + We test a few general things, e.g.: + - accuracy of reported baselines. + - accuracy of reported flex base size, min/max sizes, & trivial deltas. + - flex items formation for display:contents subtrees & text nodes. + --> + <div id="flex-sanity" class="container"> + <div class="lime base flexGrow">one line (first)</div> + <div class="yellow lastbase" style="width: 100px">one line (last)</div> + <div class="orange offset lastbase crossMinMax">two<br/>lines and offset (last)</div> + <div class="pink offset base mainMinMax">offset (first)</div> + <!-- Inflexible item w/ content-derived flex base size, which has min/max + but doesn't violate them: --> + <div class="tan mainMinMax"> + <div class="spacer150"></div> + </div> + <!-- Inflexible item that is trivially clamped to smaller max-width: --> + <div style="flex: 0 0 10px; max-width: 5px"></div> + <!-- Inflexible item that is trivially clamped to larger min-width: --> + <div style="flex: 0 0 10px; min-width: 15px"></div> + <!-- Item that wants to grow but is trivially clamped to max-width + below base size: --> + <div style="flex: 1 1 50px; max-width: 10px"></div> + <div class="clamped-huge-item"></div> + <div style="display:contents"> + <div class="white">replaced</div> + </div> + anon item for text + </div> + + <!-- Second flex container to be tested, with items that grow by specific + predictable amounts. This ends up triggering 4 passes of the main + flexbox layout algorithm loop - and note that for each item, we only + report (via 'mainDeltaSize') the delta that it wanted in the *last pass + of the loop before that item was frozen*. + + Here's what goes on in each pass (and the tentative deltas) + * PASS 1 + - Available space = 120 - 10 - 20 - 30 - 0 = 60px. + - Sum of flex values = 1+1+2+16 = 20. So 1 "share" is 60px/20 = 3px. + - Deltas (space distributed): +3px, +3px, +6px, +48px + VIOLATIONS: + item0 is now 10+3 = 13px, which under its min + item1 is now 20+3 = 23px, which under its min + item3 is now 0+48 = 48px, which over its max + - the magnitude of max-violations (how far we're out of bounds) exceeds + magnitude of min-violations, so we prioritize the max-violations. + - So we freeze item3 at its max-width, 20px, leaving its final "desired" + mainDeltaSize at +48px from this pass. + + * PASS 2 + - Available space = 120 - 10 - 20 - 30 - 20 = 40px. + - Sum of flex values = 1+1+2 = 4. So 1 "share" is 40px/4 = 10px. + - Deltas (space distributed): +10px, +10px, +20px, +0px. + VIOLATIONS: + item0 is now 10+10 = 20px, which is under its min + - So we freeze item0 at its min-width, 35px, leaving its final "desired" + mainDeltaSize at +10px from this pass. + + * PASS 3 + - Available space = 120 - 35 - 20 - 30 - 20 = 15px. + - Sum of flex values = 1+2 = 3. So 1 "share" is 15px/3 = 5px. + - Deltas (space distributed): +0px, +5px, +10px, +0px. + VIOLATIONS: + item1 is now 20+5 = 25px, which is under its min + - So we freeze item1 at its min-width, 28px, leaving its final "desired" + mainDeltaSize at +5px from this pass. + + * PASS 4 + - Available space = 120 - 35 - 28 - 30 - 20 = 7px. + - Sum of flex values = 2. So 1 "share" is 7px/2 = 3.5px + - Deltas (space distributed): +0px, +0px, +7px, +0px. + VIOLATIONS: + None! (So, we'll be done after this pass!) + - So we freeze item2 (the only unfrozen item) at its flexed size, 37px, + and set its final "desired" mainDeltaSize to +7px from this pass. + - And we're done! + --> + <div id="flex-growing" class="container" style="width: 120px"> + <div style="flex: 1 10px; min-width: 35px"></div> + <div style="flex: 1 20px; min-width: 28px"></div> + <div style="flex: 2 30px; min-width: 0"></div> + <div style="flex: 16 0px; max-width: 20px"></div> + </div> +</body> +</html> diff --git a/dom/flex/test/chrome/test_flex_lines.html b/dom/flex/test/chrome/test_flex_lines.html new file mode 100644 index 0000000000..aef5a5394b --- /dev/null +++ b/dom/flex/test/chrome/test_flex_lines.html @@ -0,0 +1,336 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> + f { + display: flex; + background-color: grey; + font: 12px sans-serif; + width: 800px; + height: 42px; + margin-bottom: 5px; + } + + .withZ::after { + background-color: pink; + content: "Z"; + width: 100px; + height: 10px; + } + + .wrap { + flex-wrap: wrap; + } + + .wrapReverse { + flex-wrap: wrap-reverse; + } + + b { + background-color: gold; + min-width: 100px; + height: 20px; + flex-grow: 1; + } + b::after { + content: "B"; + } + + c { + background-color: yellow; + width: 200px; + height: 15px; + } + c::after { + content: "C"; + } + + d { + background-color: orange; + width: 300px; + height: 10px; + } + d::after { + content: "D"; + } + + e { + background-color: silver; + width: 300px; + height: 10px; + flex-shrink: 2; + } + e::after { + content: "E"; + } +</style> + +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +function testLineMatchesExpectedValues(line, values, lineIndex, flexIndex) { + if (typeof(values.growthState) != "undefined") { + is(line.growthState, values.growthState, "Flex index " + flexIndex + " line index " + lineIndex + " has expected growthState."); + } + + if (typeof(values.crossStart) != "undefined") { + is(line.crossStart, values.crossStart, "Flex index " + flexIndex + " line index " + lineIndex + " has expected crossStart."); + } + + if (typeof(values.crossSize) != "undefined") { + is(line.crossSize, values.crossSize, "Flex index " + flexIndex + " line index " + lineIndex + " has expected crossSize."); + } + + if (typeof(values.itemCount) != "undefined") { + is(line.getItems().length, values.itemCount, "Flex index " + flexIndex + " line index " + lineIndex + " has expected number of items."); + } +} + +function runTests() { + let expectedValues = [ + // items don't fill container, no grow, shrink, or min-width + [{ crossStart: 0, + crossSize: 42, + itemCount: 2, + growthState: "growing" }], + [{ crossStart: 0, + crossSize: 42, + itemCount: 3, + growthState: "growing" }], + + // items don't fill container, no grow, shrink, or min-width, with wrap and align-content:center --> + [{ crossStart: 13.5, + crossSize: 15, + itemCount: 2, + growthState: "growing" }], + [{ crossStart: 13.5, + crossSize: 15, + itemCount: 3, + growthState: "growing" }], + + // items don't fill container, with grow + [{ crossStart: 0, + crossSize: 42, + itemCount: 3, + growthState: "growing" }], + [{ crossStart: 0, + crossSize: 42, + itemCount: 4, + growthState: "growing" }], + + // items overfill container, with min-width, and sometimes with wrap + [{ crossStart: 0, + crossSize: 42, + itemCount: 5, + growthState: "shrinking" }], + [{ crossStart: 0, + crossSize: 21, + itemCount: 3, + growthState: "growing" }, + { crossStart: 21, + crossSize: 21, + itemCount: 2, + growthState: "growing" }], + [{ crossStart: 0, + crossSize: 42, + itemCount: 6, + growthState: "shrinking" }], + [{ crossStart: 0, + crossSize: 21, + itemCount: 3, + growthState: "growing" }, + { crossStart: 21, + crossSize: 21, + itemCount: 3, + growthState: "growing" }], + + // items overfill container, with shrink and sometimes with wrap + [{ crossStart: 0, + crossSize: 42, + itemCount: 3, + growthState: "shrinking" }], + [{ crossStart: 0, + crossSize: 21, + itemCount: 2, + growthState: "growing" }, + { crossStart: 21, + crossSize: 21, + itemCount: 1, + growthState: "growing" }], + [{ crossStart: 0, + crossSize: 42, + itemCount: 4, + growthState: "shrinking" }], + [{ crossStart: 0, + crossSize: 21, + itemCount: 2, + growthState: "growing" }, + { crossStart: 21, + crossSize: 21, + itemCount: 2, + growthState: "growing" }], + + // items overfill container, with wrap and different types of align-content + [{ crossStart: 0, + crossSize: 26, + itemCount: 3 }, + { crossStart: 26, + crossSize: 16, + itemCount: 1 }], + [{ crossStart: 0, + crossSize: 20, + itemCount: 3 }, + { crossStart: 20, + crossSize: 10, + itemCount: 1 }], + [{ crossStart: 12, + crossSize: 20, + itemCount: 3 }, + { crossStart: 32, + crossSize: 10, + itemCount: 1 }], + [{ crossStart: 6, + crossSize: 20, + itemCount: 3 }, + { crossStart: 26, + crossSize: 10, + itemCount: 1 }], + [{ crossStart: 0, + crossSize: 20, + itemCount: 3 }, + { crossStart: 32, + crossSize: 10, + itemCount: 1 }], + [{ crossStart: 3, + crossSize: 20, + itemCount: 3 }, + { crossStart: 29, + crossSize: 10, + itemCount: 1 }], + + // items overfill container, with wrap-reverse and different types of align-content + [{ crossStart: 0, + crossSize: 26, + itemCount: 3 }, + { crossStart: 26, + crossSize: 16, + itemCount: 2 }], + [{ crossStart: 0, + crossSize: 20, + itemCount: 3 }, + { crossStart: 20, + crossSize: 10, + itemCount: 2 }], + [{ crossStart: 12, + crossSize: 20, + itemCount: 3 }, + { crossStart: 32, + crossSize: 10, + itemCount: 2 }], + [{ crossStart: 6, + crossSize: 20, + itemCount: 3 }, + { crossStart: 26, + crossSize: 10, + itemCount: 2 }], + [{ crossStart: 0, + crossSize: 20, + itemCount: 3 }, + { crossStart: 32, + crossSize: 10, + itemCount: 2 }], + [{ crossStart: 3, + crossSize: 20, + itemCount: 3 }, + { crossStart: 29, + crossSize: 10, + itemCount: 2 }], + + // other strange types of flex containers + [{ itemCount: 3 }], + [{ crossStart: 100, + crossSize: 300, + mainSize: 40, + itemCount: 3 }, + { crossStart: 400, + crossSize: 300, + mainSize: 20, + itemCount: 2 }], + ]; + + let children = document.body.children; + is(children.length, expectedValues.length, "Document has expected number of flex containers."); + + for (let i = 0; i < children.length; ++i) { + let flex = children.item(i).getAsFlexContainer(); + ok(flex, "Document child index " + i + " is a flex container."); + if (flex) { + let values = expectedValues[i]; + + let lines = flex.getLines(); + is(lines.length, values.length, "Flex index " + i + " has expected number of lines."); + + for (let j = 0; j < lines.length; ++j) { + testLineMatchesExpectedValues(lines[j], values[j], j, i); + } + } + } + + SimpleTest.finish(); +} +</script> +</head> + +<body onLoad="runTests();"> + +<!-- items don't fill container, no grow, shrink, or min-width --> +<f><c></c><d></d></f> +<f class="withZ"><c></c><d></d></f> + +<!-- items don't fill container, no grow, shrink, or min-width, with wrap and align-content:center --> +<f class="wrap" style="align-content:center"><c></c><d></d></f> +<f class="withZ wrap" style="align-content:center"><c></c><d></d></f> + +<!-- items don't fill container, with grow --> +<f><b></b><c></c><d></d></f> +<f class="withZ"><b></b><c></c><d></d></f> + +<!-- items overfill container, with min-width, and sometimes with wrap --> +<f><b></b><d></d><d></d><d></d><b></b></f> +<f class="wrap"><b></b><d></d><d></d><d></d><b></b></f> +<f class="withZ"><b></b><d></d><d></d><d></d><b></b></f> +<f class="wrap withZ"><b></b><d></d><d></d><d></d><b></b></f> + +<!-- items overfill container, with shrink and sometimes with wrap --> +<f><d></d><d></d><e></e></f> +<f class="wrap"><d></d><d></d><e></e></f> +<f class="withZ"><d></d><d></d><e></e></f> +<f class="wrap withZ"><d></d><d></d><e></e></f> + +<!-- items overfill container, with wrap and different types of align-content --> +<f class="wrap"><b></b><c></c><d></d><e></e></f> +<f class="wrap" style="align-content:flex-start"><b></b><c></c><d></d><e></e></f> +<f class="wrap" style="align-content:flex-end"><b></b><c></c><d></d><e></e></f> +<f class="wrap" style="align-content:center"><b></b><c></c><d></d><e></e></f> +<f class="wrap" style="align-content:space-between"><b></b><c></c><d></d><e></e></f> +<f class="wrap" style="align-content:space-around"><b></b><c></c><d></d><e></e></f> + +<!-- items overfill container, with wrap-reverse and different types of align-content --> +<f class="wrapReverse withZ"><b></b><c></c><d></d><e></e></f> +<f class="wrapReverse withZ" style="align-content:flex-start"><b></b><c></c><d></d><e></e></f> +<f class="wrapReverse withZ" style="align-content:flex-end"><b></b><c></c><d></d><e></e></f> +<f class="wrapReverse withZ" style="align-content:center"><b></b><c></c><d></d><e></e></f> +<f class="wrapReverse withZ" style="align-content:space-between"><b></b><c></c><d></d><e></e></f> +<f class="wrapReverse withZ" style="align-content:space-around"><b></b><c></c><d></d><e></e></f> + +<!-- other strange types of flex containers --> +<f style="overflow:scroll"><d></d><d></d><e></e></f> +<f class="wrap" style="flex-direction:column; align-content:center"><c></c><d></d><c></c><d></d><e></e></f> + +</body> +</html> diff --git a/dom/flex/test/chrome/test_flex_object.html b/dom/flex/test/chrome/test_flex_object.html new file mode 100644 index 0000000000..c984663fdf --- /dev/null +++ b/dom/flex/test/chrome/test_flex_object.html @@ -0,0 +1,132 @@ +<!doctype html> +<html> +<head> +<meta charset="utf-8"> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> +body { + margin: 40px; +} +.flexWrapper { + display: flex; + width: 400px; +} +.nonFlexWrapper { + display: block; + width: 400px; +} +.oh { + overflow: hidden; +} +.box { + background-color: #444; + color: #fff; +} +</style> + +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +function runTests() { + // Test 1: elements styled with display:flex + let idsWithFlex = [ + "flexDiv", + "flexDivOh", + + "flexFieldset", + "flexFieldsetEmpty", + "flexFieldsetOh", + + "flexButton", + "flexButtonOh", + ]; + + for (let id of idsWithFlex) { + let wrapper = document.getElementById(id); + + // Test that we got a flex info object from the element. + let flex = wrapper.getAsFlexContainer(); + ok(flex, `Expected that element id ${id} would have flex info.`); + } + + // Test 2: elements styled without display:flex + let idsWithoutFlex = [ + "boxA", + + "nonFlexFieldset", + "nonFlexFieldsetOh", + + "nonFlexButton", + "nonFlexButtonOh", + ]; + + for (let id of idsWithoutFlex) { + let wrapper = document.getElementById(id); + + // Test that we didn't get a flex info object from the element. + let flex = wrapper.getAsFlexContainer(); + ok(!flex, `Expected that element id ${id} would not have flex info.`); + } + + SimpleTest.finish(); +} +</script> +</head> +<body onLoad="runTests();"> + + <div id="flexDiv" class="flexWrapper"> + <div id="boxA" class="box">A</div> + </div> + + <div id="flexDivOh" class="flexWrapper oh"> + <div id="boxAOh" class="box">A</div> + </div> + + <fieldset id="flexFieldset" class="flexWrapper"> + <legend>a fieldset</legend> + <label for="name">name</label> + <input id="name"> + </fieldset> + + <fieldset id="flexFieldsetEmpty" class="flexWrapper"> + </fieldset> + + <fieldset id="flexFieldsetOh" class="flexWrapper oh"> + <legend>a fieldset</legend> + <label for="nameOh">name</label> + <input id="nameOh"> + </fieldset> + + <button id="flexButton" class="flexWrapper"> + <span>test</span> + </button> + + <button id="flexButtonOh" class="flexWrapper oh"> + <span>test</span> + </button> + + <fieldset id="nonFlexFieldset" class="nonFlexWrapper"> + <legend>a fieldset</legend> + <label for="name">name</label> + <input id="name"> + </fieldset> + + <fieldset id="nonFlexFieldsetOh" class="nonFlexWrapper oh"> + <legend>a fieldset</legend> + <label for="name">name</label> + <input id="name"> + </fieldset> + + <button id="nonFlexButton" class="nonFlexWrapper"> + <span>test</span> + </button> + + <button id="nonFlexButtonOh" class="nonFlexWrapper oh"> + <span>test</span> + </button> + +</body> +</html> diff --git a/dom/flex/test/chrome/test_flex_parent.html b/dom/flex/test/chrome/test_flex_parent.html new file mode 100644 index 0000000000..6ab050e735 --- /dev/null +++ b/dom/flex/test/chrome/test_flex_parent.html @@ -0,0 +1,133 @@ +<!doctype html> +<html id="nonitem0"> +<head> +<meta charset="utf-8"> +<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> +<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> +<style> + .container { + display: flex; + background-color: grey; + font: 14px sans-serif; + height: 20px; + } + + .lime { background: lime; } + .yellow { background: yellow; } + .orange { background: orange; } +</style> + +<script> +"use strict"; + +SimpleTest.waitForExplicitFinish(); + +function testFlexParentExpectedValues(values) { + let expectedParent; + if (values.parent) { + expectedParent = document.getElementById(values.parent); + } + + let item, itemLabel; + + if (values.id) { + item = document.getElementById(values.id); + itemLabel = values.id; + } else { + item = expectedParent.firstChild; + itemLabel = "[text node]"; + } + + const actualParent = item.parentFlexElement; + + if (values.parent) { + is(actualParent, expectedParent, "Item " + itemLabel + " should have a parent with id " + values.parent + "."); + } else { + is(actualParent, null, "Non-item " + itemLabel + " should not have a parent."); + } +} + +function testFlexParents() { + let expectedValues = [ + // These items expect to have a flex parent. + { id: "item0", parent: "container0" }, + { id: "item1", parent: "container1" }, + { id: "item2", parent: "container2" }, + { id: "item3", parent: "container3" }, + { id: "item4", parent: "container4" }, + { id: null /* choose the first child of the expected parent */, parent: "container5" }, + + + // These elements do NOT expect to have a flex parent. + { id: "nonitem0" }, + { id: "nonitem1" }, + { id: "nonitem2" }, + { id: "nonitem3" }, + ]; + + for (let i = 0; i < expectedValues.length; ++i) { + testFlexParentExpectedValues(expectedValues[i]); + } +} + +function runTests() { + testFlexParents(); + SimpleTest.finish(); +} +</script> +</head> + +<body onLoad="runTests();"> + <!-- These items expect to have a flex parent. --> + <div id="container0" class="container"> + <div id="item0" class="lime">first item</div> + </div> + + <div id="container1" class="container"> + <div class="orange">first item</div> + <div id="item1" class="lime">second item</div> + </div> + + <div id="container2" class="container"> + <div style="display:contents"> + <div id="item2" class="lime">display-contents-child item</div> + </div> + </div> + + <div id="container3" class="container"> + A <span id="item3" class="lime">middle item</span> surrounded by anonymous text items</div> + </div> + + <div id="container4" class="container"> + <div id="item4" style="display: table-cell">display: table-cell item</div> + </div> + + <div id="container5" class="container"> + Text that gets wrapped in anonymous flex item + </div> + + <!-- These elements do NOT expect to have a flex parent. --> + + <!-- nonitem0 is the root html element --> + + <div class="container"> + <div> + <div id="nonitem1" class="yellow">child element of an item</div> + </div> + </div> + + <div class="container"> + <div> + <div id="nonitem2" style="position: absolute" class="yellow">position: absolute element</div> + </div> + </div> + + <div class="container" style="position:relative"> + <div> + <div id="nonitem3" style="position: absolute" class="yellow"> + position: absolute element, with flex as containing block + </div> + </div> + </div> +</body> +</html> |