2012-06-27 02:12:13 +04:00
|
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
/* vim: set ts=2 et sw=2 tw=80: */
|
|
|
|
|
|
|
|
|
|
/* This Source Code is subject to the terms of the Mozilla Public License
|
|
|
|
|
* version 2.0 (the "License"). You can obtain a copy of the License at
|
|
|
|
|
* http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
2012-10-15 23:42:43 +04:00
|
|
|
|
/* rendering object for CSS "display: flex" */
|
2012-06-27 02:12:13 +04:00
|
|
|
|
|
|
|
|
|
#include "nsFlexContainerFrame.h"
|
2012-12-27 00:17:52 +04:00
|
|
|
|
#include "nsContentUtils.h"
|
2013-03-03 04:31:48 +04:00
|
|
|
|
#include "nsCSSAnonBoxes.h"
|
2012-11-30 12:13:23 +04:00
|
|
|
|
#include "nsDisplayList.h"
|
2014-01-21 02:02:20 +04:00
|
|
|
|
#include "nsIFrameInlines.h"
|
2012-09-30 10:38:46 +04:00
|
|
|
|
#include "nsLayoutUtils.h"
|
2013-06-01 09:14:03 +04:00
|
|
|
|
#include "nsPlaceholderFrame.h"
|
2012-06-27 02:12:13 +04:00
|
|
|
|
#include "nsPresContext.h"
|
2014-07-22 19:24:37 +04:00
|
|
|
|
#include "nsRenderingContext.h"
|
2012-06-27 02:12:13 +04:00
|
|
|
|
#include "nsStyleContext.h"
|
2015-05-19 21:15:34 +03:00
|
|
|
|
#include "mozilla/Logging.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
|
#include <algorithm>
|
2014-03-18 05:23:23 +04:00
|
|
|
|
#include "mozilla/LinkedList.h"
|
2014-10-01 13:26:00 +04:00
|
|
|
|
#include "mozilla/FloatingPoint.h"
|
2015-03-27 22:06:03 +03:00
|
|
|
|
#include "WritingModes.h"
|
2012-06-27 02:12:13 +04:00
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
using namespace mozilla;
|
2013-05-22 07:59:36 +04:00
|
|
|
|
using namespace mozilla::layout;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-01-22 02:51:58 +04:00
|
|
|
|
// Convenience typedefs for helper classes that we forward-declare in .h file
|
|
|
|
|
// (so that nsFlexContainerFrame methods can use them as parameters):
|
2014-01-22 05:05:07 +04:00
|
|
|
|
typedef nsFlexContainerFrame::FlexItem FlexItem;
|
|
|
|
|
typedef nsFlexContainerFrame::FlexLine FlexLine;
|
|
|
|
|
typedef nsFlexContainerFrame::FlexboxAxisTracker FlexboxAxisTracker;
|
2014-01-22 02:51:58 +04:00
|
|
|
|
typedef nsFlexContainerFrame::StrutInfo StrutInfo;
|
|
|
|
|
|
2015-11-06 01:35:03 +03:00
|
|
|
|
static mozilla::LazyLogModule gFlexContainerLog("nsFlexContainerFrame");
|
2012-06-27 02:12:13 +04:00
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// XXXdholbert Some of this helper-stuff should be separated out into a general
|
2015-03-27 00:37:48 +03:00
|
|
|
|
// "main/cross-axis utils" header, shared by grid & flexbox?
|
|
|
|
|
// (Particularly when grid gets support for align-*/justify-* properties.)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Helper enums
|
|
|
|
|
// ============
|
|
|
|
|
|
|
|
|
|
// Represents a physical orientation for an axis.
|
|
|
|
|
// The directional suffix indicates the direction in which the axis *grows*.
|
|
|
|
|
// So e.g. eAxis_LR means a horizontal left-to-right axis, whereas eAxis_BT
|
|
|
|
|
// means a vertical bottom-to-top axis.
|
|
|
|
|
// NOTE: The order here is important -- these values are used as indices into
|
|
|
|
|
// the static array 'kAxisOrientationToSidesMap', defined below.
|
|
|
|
|
enum AxisOrientationType {
|
|
|
|
|
eAxis_LR,
|
|
|
|
|
eAxis_RL,
|
|
|
|
|
eAxis_TB,
|
|
|
|
|
eAxis_BT,
|
|
|
|
|
eNumAxisOrientationTypes // For sizing arrays that use these values as indices
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Represents one or the other extreme of an axis (e.g. for the main axis, the
|
|
|
|
|
// main-start vs. main-end edge.
|
|
|
|
|
// NOTE: The order here is important -- these values are used as indices into
|
|
|
|
|
// the sub-arrays in 'kAxisOrientationToSidesMap', defined below.
|
|
|
|
|
enum AxisEdgeType {
|
|
|
|
|
eAxisEdge_Start,
|
|
|
|
|
eAxisEdge_End,
|
|
|
|
|
eNumAxisEdges // For sizing arrays that use these values as indices
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// This array maps each axis orientation to a pair of corresponding
|
2014-06-28 14:13:13 +04:00
|
|
|
|
// [start, end] physical mozilla::Side values.
|
|
|
|
|
static const mozilla::Side
|
2012-09-30 10:38:46 +04:00
|
|
|
|
kAxisOrientationToSidesMap[eNumAxisOrientationTypes][eNumAxisEdges] = {
|
|
|
|
|
{ eSideLeft, eSideRight }, // eAxis_LR
|
|
|
|
|
{ eSideRight, eSideLeft }, // eAxis_RL
|
|
|
|
|
{ eSideTop, eSideBottom }, // eAxis_TB
|
|
|
|
|
{ eSideBottom, eSideTop } // eAxis_BT
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Helper structs / classes / methods
|
|
|
|
|
// ==================================
|
|
|
|
|
|
|
|
|
|
// Indicates whether advancing along the given axis is equivalent to
|
|
|
|
|
// increasing our X or Y position (as opposed to decreasing it).
|
|
|
|
|
static inline bool
|
|
|
|
|
AxisGrowsInPositiveDirection(AxisOrientationType aAxis)
|
|
|
|
|
{
|
|
|
|
|
return eAxis_LR == aAxis || eAxis_TB == aAxis;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Given an AxisOrientationType, returns the "reverse" AxisOrientationType
|
|
|
|
|
// (in the same dimension, but the opposite direction)
|
|
|
|
|
static inline AxisOrientationType
|
|
|
|
|
GetReverseAxis(AxisOrientationType aAxis)
|
|
|
|
|
{
|
|
|
|
|
AxisOrientationType reversedAxis;
|
|
|
|
|
|
|
|
|
|
if (aAxis % 2 == 0) {
|
|
|
|
|
// even enum value. Add 1 to reverse.
|
|
|
|
|
reversedAxis = AxisOrientationType(aAxis + 1);
|
|
|
|
|
} else {
|
|
|
|
|
// odd enum value. Subtract 1 to reverse.
|
|
|
|
|
reversedAxis = AxisOrientationType(aAxis - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check that we're still in the enum's valid range
|
|
|
|
|
MOZ_ASSERT(reversedAxis >= eAxis_LR &&
|
|
|
|
|
reversedAxis <= eAxis_BT);
|
|
|
|
|
|
|
|
|
|
return reversedAxis;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 22:57:52 +04:00
|
|
|
|
/**
|
2015-03-27 00:37:48 +03:00
|
|
|
|
* Converts a "flex-relative" coordinate in a single axis (a main- or cross-axis
|
|
|
|
|
* coordinate) into a coordinate in the corresponding physical (x or y) axis. If
|
|
|
|
|
* the flex-relative axis in question already maps *directly* to a physical
|
|
|
|
|
* axis (i.e. if it's LTR or TTB), then the physical coordinate has the same
|
|
|
|
|
* numeric value as the provided flex-relative coordinate. Otherwise, we have to
|
|
|
|
|
* subtract the flex-relative coordinate from the flex container's size in that
|
|
|
|
|
* axis, to flip the polarity. (So e.g. a main-axis position of 2px in a RTL
|
|
|
|
|
* 20px-wide container would correspond to a physical coordinate (x-value) of
|
|
|
|
|
* 18px.)
|
2013-12-05 22:57:52 +04:00
|
|
|
|
*/
|
|
|
|
|
static nscoord
|
2015-03-27 00:37:48 +03:00
|
|
|
|
PhysicalCoordFromFlexRelativeCoord(nscoord aFlexRelativeCoord,
|
|
|
|
|
nscoord aContainerSize,
|
|
|
|
|
AxisOrientationType aAxis) {
|
2013-12-05 22:57:52 +04:00
|
|
|
|
if (AxisGrowsInPositiveDirection(aAxis)) {
|
2015-03-27 00:37:48 +03:00
|
|
|
|
return aFlexRelativeCoord;
|
2013-12-05 22:57:52 +04:00
|
|
|
|
}
|
2015-03-27 00:37:48 +03:00
|
|
|
|
return aContainerSize - aFlexRelativeCoord;
|
2013-12-05 22:57:52 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-09-21 00:26:52 +04:00
|
|
|
|
// Helper-macro to let us pick one of two expressions to evaluate
|
|
|
|
|
// (a width expression vs. a height expression), to get a main-axis or
|
|
|
|
|
// cross-axis component.
|
|
|
|
|
// For code that has e.g. a nsSize object, FlexboxAxisTracker::GetMainComponent
|
|
|
|
|
// and GetCrossComponent are cleaner; but in cases where we simply have
|
|
|
|
|
// two separate expressions for width and height (which may be expensive to
|
|
|
|
|
// evaluate), these macros will ensure that only the expression for the correct
|
|
|
|
|
// axis gets evaluated.
|
|
|
|
|
#define GET_MAIN_COMPONENT(axisTracker_, width_, height_) \
|
2015-03-27 22:06:03 +03:00
|
|
|
|
(axisTracker_).IsMainAxisHorizontal() ? (width_) : (height_)
|
2013-09-21 00:26:52 +04:00
|
|
|
|
|
|
|
|
|
#define GET_CROSS_COMPONENT(axisTracker_, width_, height_) \
|
2015-03-27 22:06:03 +03:00
|
|
|
|
(axisTracker_).IsCrossAxisHorizontal() ? (width_) : (height_)
|
2013-09-21 00:26:52 +04:00
|
|
|
|
|
2015-05-12 23:34:25 +03:00
|
|
|
|
// Logical versions of helper-macros above:
|
2015-06-13 00:28:24 +03:00
|
|
|
|
#define GET_MAIN_COMPONENT_LOGICAL(axisTracker_, wm_, isize_, bsize_) \
|
|
|
|
|
wm_.IsOrthogonalTo(axisTracker_.GetWritingMode()) != \
|
|
|
|
|
(axisTracker_).IsRowOriented() ? (isize_) : (bsize_)
|
2015-05-12 23:34:25 +03:00
|
|
|
|
|
2015-06-13 00:28:24 +03:00
|
|
|
|
#define GET_CROSS_COMPONENT_LOGICAL(axisTracker_, wm_, isize_, bsize_) \
|
|
|
|
|
wm_.IsOrthogonalTo(axisTracker_.GetWritingMode()) != \
|
|
|
|
|
(axisTracker_).IsRowOriented() ? (bsize_) : (isize_)
|
2015-05-15 21:57:08 +03:00
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Encapsulates our flex container's main & cross axes.
|
2014-01-22 05:05:07 +04:00
|
|
|
|
class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
public:
|
2015-03-27 22:06:03 +03:00
|
|
|
|
FlexboxAxisTracker(const nsStylePosition* aStylePosition,
|
|
|
|
|
const WritingMode& aWM);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Accessors:
|
2015-04-10 23:35:15 +03:00
|
|
|
|
// XXXdholbert [BEGIN DEPRECATED]
|
2012-09-30 10:38:46 +04:00
|
|
|
|
AxisOrientationType GetMainAxis() const { return mMainAxis; }
|
|
|
|
|
AxisOrientationType GetCrossAxis() const { return mCrossAxis; }
|
|
|
|
|
|
2015-04-10 23:35:42 +03:00
|
|
|
|
bool IsMainAxisHorizontal() const {
|
|
|
|
|
// If we're row-oriented, and our writing mode is NOT vertical,
|
|
|
|
|
// or we're column-oriented and our writing mode IS vertical,
|
|
|
|
|
// then our main axis is horizontal. This handles all cases:
|
|
|
|
|
return mIsRowOriented != mWM.IsVertical();
|
|
|
|
|
}
|
|
|
|
|
bool IsCrossAxisHorizontal() const {
|
|
|
|
|
return !IsMainAxisHorizontal();
|
|
|
|
|
}
|
2015-04-10 23:35:15 +03:00
|
|
|
|
// XXXdholbert [END DEPRECATED]
|
|
|
|
|
|
2015-06-13 00:28:24 +03:00
|
|
|
|
// Returns the flex container's writing mode.
|
|
|
|
|
WritingMode GetWritingMode() const { return mWM; }
|
|
|
|
|
|
2015-04-10 23:35:15 +03:00
|
|
|
|
// Returns true if our main axis is in the reverse direction of our
|
|
|
|
|
// writing mode's corresponding axis. (From 'flex-direction: *-reverse')
|
|
|
|
|
bool IsMainAxisReversed() const {
|
|
|
|
|
return mIsMainAxisReversed;
|
|
|
|
|
}
|
|
|
|
|
// Returns true if our cross axis is in the reverse direction of our
|
|
|
|
|
// writing mode's corresponding axis. (From 'flex-wrap: *-reverse')
|
|
|
|
|
bool IsCrossAxisReversed() const {
|
|
|
|
|
return mIsCrossAxisReversed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsRowOriented() const { return mIsRowOriented; }
|
2015-05-12 23:34:25 +03:00
|
|
|
|
bool IsColumnOriented() const { return !mIsRowOriented; }
|
2015-03-27 22:06:03 +03:00
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord GetMainComponent(const nsSize& aSize) const {
|
2013-09-21 00:26:52 +04:00
|
|
|
|
return GET_MAIN_COMPONENT(*this, aSize.width, aSize.height);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
2015-03-30 18:36:14 +03:00
|
|
|
|
int32_t GetMainComponent(const LayoutDeviceIntSize& aIntSize) const {
|
2013-09-21 00:26:52 +04:00
|
|
|
|
return GET_MAIN_COMPONENT(*this, aIntSize.width, aIntSize.height);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nscoord GetCrossComponent(const nsSize& aSize) const {
|
2013-09-21 00:26:52 +04:00
|
|
|
|
return GET_CROSS_COMPONENT(*this, aSize.width, aSize.height);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
2015-03-30 18:36:14 +03:00
|
|
|
|
int32_t GetCrossComponent(const LayoutDeviceIntSize& aIntSize) const {
|
2013-09-21 00:26:52 +04:00
|
|
|
|
return GET_CROSS_COMPONENT(*this, aIntSize.width, aIntSize.height);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nscoord GetMarginSizeInMainAxis(const nsMargin& aMargin) const {
|
2015-03-27 22:06:03 +03:00
|
|
|
|
return IsMainAxisHorizontal() ?
|
2012-09-30 10:38:46 +04:00
|
|
|
|
aMargin.LeftRight() :
|
|
|
|
|
aMargin.TopBottom();
|
|
|
|
|
}
|
|
|
|
|
nscoord GetMarginSizeInCrossAxis(const nsMargin& aMargin) const {
|
2015-03-27 22:06:03 +03:00
|
|
|
|
return IsCrossAxisHorizontal() ?
|
2012-09-30 10:38:46 +04:00
|
|
|
|
aMargin.LeftRight() :
|
|
|
|
|
aMargin.TopBottom();
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-27 22:06:03 +03:00
|
|
|
|
// Returns aFrame's computed value for 'height' or 'width' -- whichever is in
|
|
|
|
|
// the cross-axis. (NOTE: This is cross-axis-specific for now. If we need a
|
|
|
|
|
// main-axis version as well, we could generalize or clone this function.)
|
|
|
|
|
const nsStyleCoord& ComputedCrossSize(const nsIFrame* aFrame) const {
|
|
|
|
|
const nsStylePosition* stylePos = aFrame->StylePosition();
|
|
|
|
|
|
|
|
|
|
return IsCrossAxisHorizontal() ?
|
|
|
|
|
stylePos->mWidth :
|
|
|
|
|
stylePos->mHeight;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-18 01:54:02 +04:00
|
|
|
|
/**
|
2015-03-27 00:37:48 +03:00
|
|
|
|
* Converts a "flex-relative" point (a main-axis & cross-axis coordinate)
|
2015-04-16 22:01:14 +03:00
|
|
|
|
* into a LogicalPoint, using the flex container's writing mode.
|
2013-09-18 01:54:02 +04:00
|
|
|
|
*
|
2015-03-27 00:37:48 +03:00
|
|
|
|
* @arg aMainCoord The main-axis coordinate -- i.e an offset from the
|
2015-04-16 22:01:14 +03:00
|
|
|
|
* main-start edge of the flex container's content box.
|
2015-03-27 00:37:48 +03:00
|
|
|
|
* @arg aCrossCoord The cross-axis coordinate -- i.e an offset from the
|
2015-04-16 22:01:14 +03:00
|
|
|
|
* cross-start edge of the flex container's content box.
|
|
|
|
|
* @arg aContainerMainSize The main size of flex container's content box.
|
|
|
|
|
* @arg aContainerCrossSize The cross size of flex container's content box.
|
|
|
|
|
* @return A LogicalPoint, with the flex container's writing mode, that
|
|
|
|
|
* represents the same position. The logical coordinates are
|
|
|
|
|
* relative to the flex container's content box.
|
2013-09-18 01:54:02 +04:00
|
|
|
|
*/
|
2015-04-16 22:01:14 +03:00
|
|
|
|
LogicalPoint
|
|
|
|
|
LogicalPointFromFlexRelativePoint(nscoord aMainCoord,
|
|
|
|
|
nscoord aCrossCoord,
|
|
|
|
|
nscoord aContainerMainSize,
|
|
|
|
|
nscoord aContainerCrossSize) const {
|
|
|
|
|
nscoord logicalCoordInMainAxis = mIsMainAxisReversed ?
|
|
|
|
|
aContainerMainSize - aMainCoord : aMainCoord;
|
|
|
|
|
nscoord logicalCoordInCrossAxis = mIsCrossAxisReversed ?
|
|
|
|
|
aContainerCrossSize - aCrossCoord : aCrossCoord;
|
2013-09-18 01:54:02 +04:00
|
|
|
|
|
2015-04-16 22:01:14 +03:00
|
|
|
|
return mIsRowOriented ?
|
|
|
|
|
LogicalPoint(mWM, logicalCoordInMainAxis, logicalCoordInCrossAxis) :
|
|
|
|
|
LogicalPoint(mWM, logicalCoordInCrossAxis, logicalCoordInMainAxis);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
2015-03-27 00:37:48 +03:00
|
|
|
|
|
2015-04-16 22:01:14 +03:00
|
|
|
|
/**
|
|
|
|
|
* Converts a "flex-relative" size (a main-axis & cross-axis size)
|
|
|
|
|
* into a LogicalSize, using the flex container's writing mode.
|
|
|
|
|
*
|
|
|
|
|
* @arg aMainSize The main-axis size.
|
|
|
|
|
* @arg aCrossSize The cross-axis size.
|
|
|
|
|
* @return A LogicalSize, with the flex container's writing mode, that
|
|
|
|
|
* represents the same size.
|
|
|
|
|
*/
|
|
|
|
|
LogicalSize LogicalSizeFromFlexRelativeSizes(nscoord aMainSize,
|
|
|
|
|
nscoord aCrossSize) const {
|
|
|
|
|
return mIsRowOriented ?
|
|
|
|
|
LogicalSize(mWM, aMainSize, aCrossSize) :
|
|
|
|
|
LogicalSize(mWM, aCrossSize, aMainSize);
|
|
|
|
|
}
|
2015-03-27 00:37:48 +03:00
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// Are my axes reversed with respect to what the author asked for?
|
|
|
|
|
// (We may reverse the axes in the FlexboxAxisTracker constructor and set
|
|
|
|
|
// this flag, to avoid reflowing our children in bottom-to-top order.)
|
|
|
|
|
bool AreAxesInternallyReversed() const
|
|
|
|
|
{
|
|
|
|
|
return mAreAxesInternallyReversed;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
private:
|
2015-04-10 19:27:54 +03:00
|
|
|
|
// Delete copy-constructor & reassignment operator, to prevent accidental
|
|
|
|
|
// (unnecessary) copying.
|
|
|
|
|
FlexboxAxisTracker(const FlexboxAxisTracker&) = delete;
|
|
|
|
|
FlexboxAxisTracker& operator=(const FlexboxAxisTracker&) = delete;
|
|
|
|
|
|
2015-04-10 23:35:15 +03:00
|
|
|
|
// XXXdholbert [BEGIN DEPRECATED]
|
2012-09-30 10:38:46 +04:00
|
|
|
|
AxisOrientationType mMainAxis;
|
|
|
|
|
AxisOrientationType mCrossAxis;
|
2015-04-10 23:35:15 +03:00
|
|
|
|
// XXXdholbert [END DEPRECATED]
|
|
|
|
|
|
|
|
|
|
const WritingMode mWM; // The flex container's writing mode.
|
|
|
|
|
|
|
|
|
|
bool mIsRowOriented; // Is our main axis the inline axis?
|
|
|
|
|
// (Are we 'flex-direction:row[-reverse]'?)
|
|
|
|
|
|
|
|
|
|
bool mIsMainAxisReversed; // Is our main axis in the opposite direction
|
|
|
|
|
// as mWM's corresponding axis? (e.g. RTL vs LTR)
|
|
|
|
|
bool mIsCrossAxisReversed; // Is our cross axis in the opposite direction
|
|
|
|
|
// as mWM's corresponding axis? (e.g. BTT vs TTB)
|
|
|
|
|
|
|
|
|
|
// Implementation detail -- this indicates whether we've decided to
|
|
|
|
|
// transparently reverse our axes & our child ordering, to avoid having
|
|
|
|
|
// frames flow from bottom to top in either axis (& to make pagination saner).
|
2014-04-08 04:17:42 +04:00
|
|
|
|
bool mAreAxesInternallyReversed;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
};
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
/**
|
|
|
|
|
* Represents a flex item.
|
|
|
|
|
* Includes the various pieces of input that the Flexbox Layout Algorithm uses
|
|
|
|
|
* to resolve a flexible width.
|
|
|
|
|
*/
|
|
|
|
|
class nsFlexContainerFrame::FlexItem : public LinkedListElement<FlexItem>
|
|
|
|
|
{
|
2012-09-30 10:38:46 +04:00
|
|
|
|
public:
|
2014-01-22 02:52:27 +04:00
|
|
|
|
// Normal constructor:
|
2014-07-22 19:24:36 +04:00
|
|
|
|
FlexItem(nsHTMLReflowState& aFlexItemReflowState,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
float aFlexGrow, float aFlexShrink, nscoord aMainBaseSize,
|
|
|
|
|
nscoord aMainMinSize, nscoord aMainMaxSize,
|
2015-01-22 06:45:37 +03:00
|
|
|
|
nscoord aTentativeCrossSize,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord aCrossMinSize, nscoord aCrossMaxSize,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker);
|
|
|
|
|
|
2014-01-22 02:52:27 +04:00
|
|
|
|
// Simplified constructor, to be used only for generating "struts":
|
2015-06-13 00:28:24 +03:00
|
|
|
|
// (NOTE: This "strut" constructor uses the *container's* writing mode, which
|
|
|
|
|
// we'll use on this FlexItem instead of the child frame's real writing mode.
|
|
|
|
|
// This is fine - it doesn't matter what writing mode we use for a
|
|
|
|
|
// strut, since it won't render any content and we already know its size.)
|
|
|
|
|
FlexItem(nsIFrame* aChildFrame, nscoord aCrossSize, WritingMode aContainerWM);
|
2014-01-22 02:52:27 +04:00
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Accessors
|
|
|
|
|
nsIFrame* Frame() const { return mFrame; }
|
|
|
|
|
nscoord GetFlexBaseSize() const { return mFlexBaseSize; }
|
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
nscoord GetMainMinSize() const {
|
|
|
|
|
MOZ_ASSERT(!mNeedsMinSizeAutoResolution,
|
|
|
|
|
"Someone's using an unresolved 'auto' main min-size");
|
|
|
|
|
return mMainMinSize;
|
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord GetMainMaxSize() const { return mMainMaxSize; }
|
|
|
|
|
|
|
|
|
|
// Note: These return the main-axis position and size of our *content box*.
|
|
|
|
|
nscoord GetMainSize() const { return mMainSize; }
|
|
|
|
|
nscoord GetMainPosition() const { return mMainPosn; }
|
|
|
|
|
|
|
|
|
|
nscoord GetCrossMinSize() const { return mCrossMinSize; }
|
|
|
|
|
nscoord GetCrossMaxSize() const { return mCrossMaxSize; }
|
|
|
|
|
|
|
|
|
|
// Note: These return the cross-axis position and size of our *content box*.
|
|
|
|
|
nscoord GetCrossSize() const { return mCrossSize; }
|
|
|
|
|
nscoord GetCrossPosition() const { return mCrossPosn; }
|
|
|
|
|
|
2015-01-23 02:12:11 +03:00
|
|
|
|
nscoord ResolvedAscent() const {
|
|
|
|
|
if (mAscent == nsHTMLReflowMetrics::ASK_FOR_BASELINE) {
|
|
|
|
|
// XXXdholbert We should probably be using the *container's* writing-mode
|
|
|
|
|
// here, instead of the item's -- though it doesn't much matter right
|
|
|
|
|
// now, because all of the baseline-handling code here essentially
|
|
|
|
|
// assumes that the container & items have the same writing-mode. This
|
|
|
|
|
// will matter more (& can be expanded/tested) once we officially support
|
|
|
|
|
// logical directions & vertical writing-modes in flexbox, in bug 1079155
|
|
|
|
|
// or a dependency.
|
|
|
|
|
// Use GetFirstLineBaseline(), or just GetBaseline() if that fails.
|
2015-06-13 00:28:24 +03:00
|
|
|
|
if (!nsLayoutUtils::GetFirstLineBaseline(mWM, mFrame, &mAscent)) {
|
|
|
|
|
mAscent = mFrame->GetLogicalBaseline(mWM);
|
2015-01-23 02:12:11 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return mAscent;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-03 21:40:12 +04:00
|
|
|
|
// Convenience methods to compute the main & cross size of our *margin-box*.
|
|
|
|
|
// The caller is responsible for telling us the right axis, so that we can
|
|
|
|
|
// pull out the appropriate components of our margin/border/padding structs.
|
|
|
|
|
nscoord GetOuterMainSize(AxisOrientationType aMainAxis) const
|
|
|
|
|
{
|
|
|
|
|
return mMainSize + GetMarginBorderPaddingSizeInAxis(aMainAxis);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nscoord GetOuterCrossSize(AxisOrientationType aCrossAxis) const
|
|
|
|
|
{
|
|
|
|
|
return mCrossSize + GetMarginBorderPaddingSizeInAxis(aCrossAxis);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
// Returns the distance between this FlexItem's baseline and the cross-start
|
|
|
|
|
// edge of its margin-box. Used in baseline alignment.
|
2015-03-27 22:06:03 +03:00
|
|
|
|
// (This function needs to be told which edge we're measuring the baseline
|
|
|
|
|
// from, so that it can look up the appropriate components from mMargin.)
|
|
|
|
|
nscoord GetBaselineOffsetFromOuterCrossEdge(
|
|
|
|
|
AxisEdgeType aEdge,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker) const;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float GetShareOfWeightSoFar() const { return mShareOfWeightSoFar; }
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
bool IsFrozen() const { return mIsFrozen; }
|
|
|
|
|
|
|
|
|
|
bool HadMinViolation() const { return mHadMinViolation; }
|
|
|
|
|
bool HadMaxViolation() const { return mHadMaxViolation; }
|
|
|
|
|
|
2013-02-16 02:01:48 +04:00
|
|
|
|
// Indicates whether this item received a preliminary "measuring" reflow
|
|
|
|
|
// before its actual reflow.
|
|
|
|
|
bool HadMeasuringReflow() const { return mHadMeasuringReflow; }
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Indicates whether this item's cross-size has been stretched (from having
|
|
|
|
|
// "align-self: stretch" with an auto cross-size and no auto margins in the
|
|
|
|
|
// cross axis).
|
|
|
|
|
bool IsStretched() const { return mIsStretched; }
|
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Indicates whether we need to resolve an 'auto' value for the main-axis
|
|
|
|
|
// min-[width|height] property.
|
|
|
|
|
bool NeedsMinSizeAutoResolution() const
|
|
|
|
|
{ return mNeedsMinSizeAutoResolution; }
|
|
|
|
|
|
2014-01-22 02:52:27 +04:00
|
|
|
|
// Indicates whether this item is a "strut" left behind by an element with
|
|
|
|
|
// visibility:collapse.
|
|
|
|
|
bool IsStrut() const { return mIsStrut; }
|
|
|
|
|
|
2015-06-13 00:28:24 +03:00
|
|
|
|
WritingMode GetWritingMode() const { return mWM; }
|
2012-09-30 10:38:46 +04:00
|
|
|
|
uint8_t GetAlignSelf() const { return mAlignSelf; }
|
|
|
|
|
|
2014-05-04 20:10:28 +04:00
|
|
|
|
// Returns the flex factor (flex-grow or flex-shrink), depending on
|
2014-05-05 06:05:51 +04:00
|
|
|
|
// 'aIsUsingFlexGrow'.
|
|
|
|
|
//
|
|
|
|
|
// Asserts fatally if called on a frozen item (since frozen items are not
|
|
|
|
|
// flexible).
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float GetFlexFactor(bool aIsUsingFlexGrow)
|
|
|
|
|
{
|
2014-05-05 06:05:51 +04:00
|
|
|
|
MOZ_ASSERT(!IsFrozen(), "shouldn't need flex factor after item is frozen");
|
|
|
|
|
|
2014-05-04 20:10:28 +04:00
|
|
|
|
return aIsUsingFlexGrow ? mFlexGrow : mFlexShrink;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-04 20:10:28 +04:00
|
|
|
|
// Returns the weight that we should use in the "resolving flexible lengths"
|
|
|
|
|
// algorithm. If we're using the flex grow factor, we just return that;
|
|
|
|
|
// otherwise, we return the "scaled flex shrink factor" (scaled by our flex
|
|
|
|
|
// base size, so that when both large and small items are shrinking, the large
|
|
|
|
|
// items shrink more).
|
|
|
|
|
//
|
|
|
|
|
// I'm calling this a "weight" instead of a "[scaled] flex-[grow|shrink]
|
|
|
|
|
// factor", to more clearly distinguish it from the actual flex-grow &
|
|
|
|
|
// flex-shrink factors.
|
2014-05-05 06:05:51 +04:00
|
|
|
|
//
|
|
|
|
|
// Asserts fatally if called on a frozen item (since frozen items are not
|
|
|
|
|
// flexible).
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float GetWeight(bool aIsUsingFlexGrow)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2014-05-05 06:05:51 +04:00
|
|
|
|
MOZ_ASSERT(!IsFrozen(), "shouldn't need weight after item is frozen");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-01-06 08:18:12 +04:00
|
|
|
|
if (aIsUsingFlexGrow) {
|
|
|
|
|
return mFlexGrow;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We're using flex-shrink --> return mFlexShrink * mFlexBaseSize
|
|
|
|
|
if (mFlexBaseSize == 0) {
|
|
|
|
|
// Special-case for mFlexBaseSize == 0 -- we have no room to shrink, so
|
|
|
|
|
// regardless of mFlexShrink, we should just return 0.
|
|
|
|
|
// (This is really a special-case for when mFlexShrink is infinity, to
|
|
|
|
|
// avoid performing mFlexShrink * mFlexBaseSize = inf * 0 = undefined.)
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
return mFlexShrink * mFlexBaseSize;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Getters for margin:
|
|
|
|
|
// ===================
|
|
|
|
|
const nsMargin& GetMargin() const { return mMargin; }
|
|
|
|
|
|
2014-06-28 14:13:13 +04:00
|
|
|
|
// Returns the margin component for a given mozilla::Side
|
|
|
|
|
nscoord GetMarginComponentForSide(mozilla::Side aSide) const
|
2014-07-01 21:58:14 +04:00
|
|
|
|
{ return mMargin.Side(aSide); }
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Returns the total space occupied by this item's margins in the given axis
|
|
|
|
|
nscoord GetMarginSizeInAxis(AxisOrientationType aAxis) const
|
|
|
|
|
{
|
2014-06-28 14:13:13 +04:00
|
|
|
|
mozilla::Side startSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_Start];
|
|
|
|
|
mozilla::Side endSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_End];
|
2012-09-30 10:38:46 +04:00
|
|
|
|
return GetMarginComponentForSide(startSide) +
|
|
|
|
|
GetMarginComponentForSide(endSide);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Getters for border/padding
|
|
|
|
|
// ==========================
|
2013-03-28 12:50:21 +04:00
|
|
|
|
const nsMargin& GetBorderPadding() const { return mBorderPadding; }
|
|
|
|
|
|
2014-06-28 14:13:13 +04:00
|
|
|
|
// Returns the border+padding component for a given mozilla::Side
|
|
|
|
|
nscoord GetBorderPaddingComponentForSide(mozilla::Side aSide) const
|
2014-07-01 21:58:14 +04:00
|
|
|
|
{ return mBorderPadding.Side(aSide); }
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Returns the total space occupied by this item's borders and padding in
|
|
|
|
|
// the given axis
|
|
|
|
|
nscoord GetBorderPaddingSizeInAxis(AxisOrientationType aAxis) const
|
|
|
|
|
{
|
2014-06-28 14:13:13 +04:00
|
|
|
|
mozilla::Side startSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_Start];
|
|
|
|
|
mozilla::Side endSide = kAxisOrientationToSidesMap[aAxis][eAxisEdge_End];
|
2012-09-30 10:38:46 +04:00
|
|
|
|
return GetBorderPaddingComponentForSide(startSide) +
|
|
|
|
|
GetBorderPaddingComponentForSide(endSide);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Getter for combined margin/border/padding
|
|
|
|
|
// =========================================
|
|
|
|
|
// Returns the total space occupied by this item's margins, borders and
|
|
|
|
|
// padding in the given axis
|
|
|
|
|
nscoord GetMarginBorderPaddingSizeInAxis(AxisOrientationType aAxis) const
|
|
|
|
|
{
|
|
|
|
|
return GetMarginSizeInAxis(aAxis) + GetBorderPaddingSizeInAxis(aAxis);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Setters
|
|
|
|
|
// =======
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Helper to set the resolved value of min-[width|height]:auto for the main
|
|
|
|
|
// axis. (Should only be used if NeedsMinSizeAutoResolution() returns true.)
|
2014-07-22 19:24:35 +04:00
|
|
|
|
void UpdateMainMinSize(nscoord aNewMinSize)
|
|
|
|
|
{
|
2014-07-22 19:24:37 +04:00
|
|
|
|
NS_ASSERTION(aNewMinSize >= 0,
|
|
|
|
|
"How did we end up with a negative min-size?");
|
|
|
|
|
MOZ_ASSERT(mMainMaxSize >= aNewMinSize,
|
|
|
|
|
"Should only use this function for resolving min-size:auto, "
|
|
|
|
|
"and main max-size should be an upper-bound for resolved val");
|
|
|
|
|
MOZ_ASSERT(mNeedsMinSizeAutoResolution &&
|
|
|
|
|
(mMainMinSize == 0 || mFrame->IsThemed(mFrame->StyleDisplay())),
|
|
|
|
|
"Should only use this function for resolving min-size:auto, "
|
|
|
|
|
"so we shouldn't already have a nonzero min-size established "
|
|
|
|
|
"(unless it's a themed-widget-imposed minimum size)");
|
2014-07-22 19:24:35 +04:00
|
|
|
|
|
|
|
|
|
if (aNewMinSize > mMainMinSize) {
|
|
|
|
|
mMainMinSize = aNewMinSize;
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Also clamp main-size to be >= new min-size:
|
2014-07-22 19:24:35 +04:00
|
|
|
|
mMainSize = std::max(mMainSize, aNewMinSize);
|
|
|
|
|
}
|
2014-07-22 19:24:37 +04:00
|
|
|
|
mNeedsMinSizeAutoResolution = false;
|
2014-07-22 19:24:35 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-18 05:49:06 +04:00
|
|
|
|
// This sets our flex base size, and then sets our main size to the
|
|
|
|
|
// resulting "hypothetical main size" (the base size clamped to our
|
|
|
|
|
// main-axis [min,max] sizing constraints).
|
2013-11-01 06:39:02 +04:00
|
|
|
|
void SetFlexBaseSizeAndMainSize(nscoord aNewFlexBaseSize)
|
|
|
|
|
{
|
2013-11-01 06:39:02 +04:00
|
|
|
|
MOZ_ASSERT(!mIsFrozen || mFlexBaseSize == NS_INTRINSICSIZE,
|
|
|
|
|
"flex base size shouldn't change after we're frozen "
|
|
|
|
|
"(unless we're just resolving an intrinsic size)");
|
2013-11-01 06:39:02 +04:00
|
|
|
|
mFlexBaseSize = aNewFlexBaseSize;
|
|
|
|
|
|
|
|
|
|
// Before we've resolved flexible lengths, we keep mMainSize set to
|
|
|
|
|
// the 'hypothetical main size', which is the flex base size, clamped
|
|
|
|
|
// to the [min,max] range:
|
|
|
|
|
mMainSize = NS_CSS_MINMAX(mFlexBaseSize, mMainMinSize, mMainMaxSize);
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Setters used while we're resolving flexible lengths
|
|
|
|
|
// ---------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// Sets the main-size of our flex item's content-box.
|
|
|
|
|
void SetMainSize(nscoord aNewMainSize)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(!mIsFrozen, "main size shouldn't change after we're frozen");
|
|
|
|
|
mMainSize = aNewMainSize;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-04 20:10:28 +04:00
|
|
|
|
void SetShareOfWeightSoFar(float aNewShare)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(!mIsFrozen || aNewShare == 0.0f,
|
|
|
|
|
"shouldn't be giving this item any share of the weight "
|
|
|
|
|
"after it's frozen");
|
2014-05-04 20:10:28 +04:00
|
|
|
|
mShareOfWeightSoFar = aNewShare;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Freeze() { mIsFrozen = true; }
|
|
|
|
|
|
|
|
|
|
void SetHadMinViolation()
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(!mIsFrozen,
|
|
|
|
|
"shouldn't be changing main size & having violations "
|
|
|
|
|
"after we're frozen");
|
|
|
|
|
mHadMinViolation = true;
|
|
|
|
|
}
|
|
|
|
|
void SetHadMaxViolation()
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(!mIsFrozen,
|
|
|
|
|
"shouldn't be changing main size & having violations "
|
|
|
|
|
"after we're frozen");
|
|
|
|
|
mHadMaxViolation = true;
|
|
|
|
|
}
|
|
|
|
|
void ClearViolationFlags()
|
|
|
|
|
{ mHadMinViolation = mHadMaxViolation = false; }
|
|
|
|
|
|
|
|
|
|
// Setters for values that are determined after we've resolved our main size
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// Sets the main-axis position of our flex item's content-box.
|
|
|
|
|
// (This is the distance between the main-start edge of the flex container
|
|
|
|
|
// and the main-start edge of the flex item's content-box.)
|
|
|
|
|
void SetMainPosition(nscoord aPosn) {
|
|
|
|
|
MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
|
|
|
|
|
mMainPosn = aPosn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sets the cross-size of our flex item's content-box.
|
|
|
|
|
void SetCrossSize(nscoord aCrossSize) {
|
2013-11-01 06:39:02 +04:00
|
|
|
|
MOZ_ASSERT(!mIsStretched,
|
|
|
|
|
"Cross size shouldn't be modified after it's been stretched");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mCrossSize = aCrossSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sets the cross-axis position of our flex item's content-box.
|
|
|
|
|
// (This is the distance between the cross-start edge of the flex container
|
|
|
|
|
// and the cross-start edge of the flex item.)
|
|
|
|
|
void SetCrossPosition(nscoord aPosn) {
|
|
|
|
|
MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
|
|
|
|
|
mCrossPosn = aPosn;
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 02:12:10 +03:00
|
|
|
|
// After a FlexItem has had a reflow, this method can be used to cache its
|
2015-01-23 02:12:11 +03:00
|
|
|
|
// (possibly-unresolved) ascent, in case it's needed later for
|
|
|
|
|
// baseline-alignment or to establish the container's baseline.
|
2015-01-23 02:12:10 +03:00
|
|
|
|
// (NOTE: This can be marked 'const' even though it's modifying mAscent,
|
|
|
|
|
// because mAscent is mutable. It's nice for this to be 'const', because it
|
|
|
|
|
// means our final reflow can iterate over const FlexItem pointers, and we
|
|
|
|
|
// can be sure it's not modifying those FlexItems, except via this method.)
|
|
|
|
|
void SetAscent(nscoord aAscent) const {
|
2015-01-23 02:12:11 +03:00
|
|
|
|
mAscent = aAscent; // NOTE: this may be ASK_FOR_BASELINE
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-16 02:01:48 +04:00
|
|
|
|
void SetHadMeasuringReflow() {
|
|
|
|
|
mHadMeasuringReflow = true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
void SetIsStretched() {
|
|
|
|
|
MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
|
|
|
|
|
mIsStretched = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Setter for margin components (for resolving "auto" margins)
|
2014-06-28 14:13:13 +04:00
|
|
|
|
void SetMarginComponentForSide(mozilla::Side aSide, nscoord aLength)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mIsFrozen, "main size should be resolved before this");
|
2014-07-01 21:58:14 +04:00
|
|
|
|
mMargin.Side(aSide) = aLength;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 06:39:02 +04:00
|
|
|
|
void ResolveStretchedCrossSize(nscoord aLineCrossSize,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker);
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
uint32_t GetNumAutoMarginsInAxis(AxisOrientationType aAxis) const;
|
|
|
|
|
|
|
|
|
|
protected:
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Helper called by the constructor, to set mNeedsMinSizeAutoResolution:
|
|
|
|
|
void CheckForMinSizeAuto(const nsHTMLReflowState& aFlexItemReflowState,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker);
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Our frame:
|
|
|
|
|
nsIFrame* const mFrame;
|
|
|
|
|
|
|
|
|
|
// Values that we already know in constructor: (and are hence mostly 'const')
|
|
|
|
|
const float mFlexGrow;
|
|
|
|
|
const float mFlexShrink;
|
|
|
|
|
|
|
|
|
|
const nsMargin mBorderPadding;
|
|
|
|
|
nsMargin mMargin; // non-const because we need to resolve auto margins
|
|
|
|
|
|
2014-07-22 19:24:35 +04:00
|
|
|
|
// These are non-const so that we can lazily update them with the item's
|
|
|
|
|
// intrinsic size (obtained via a "measuring" reflow), when necessary.
|
2014-11-25 22:28:15 +03:00
|
|
|
|
// (e.g. for "flex-basis:auto;height:auto" & "min-height:auto")
|
2013-11-01 06:39:02 +04:00
|
|
|
|
nscoord mFlexBaseSize;
|
2014-07-22 19:24:35 +04:00
|
|
|
|
nscoord mMainMinSize;
|
|
|
|
|
nscoord mMainMaxSize;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
const nscoord mCrossMinSize;
|
|
|
|
|
const nscoord mCrossMaxSize;
|
|
|
|
|
|
|
|
|
|
// Values that we compute after constructor:
|
|
|
|
|
nscoord mMainSize;
|
|
|
|
|
nscoord mMainPosn;
|
|
|
|
|
nscoord mCrossSize;
|
|
|
|
|
nscoord mCrossPosn;
|
2015-01-23 02:12:11 +03:00
|
|
|
|
mutable nscoord mAscent; // Mutable b/c it's set & resolved lazily, sometimes
|
|
|
|
|
// via const pointer. See comment above SetAscent().
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Temporary state, while we're resolving flexible widths (for our main size)
|
|
|
|
|
// XXXdholbert To save space, we could use a union to make these variables
|
|
|
|
|
// overlay the same memory as some other member vars that aren't touched
|
|
|
|
|
// until after main-size has been resolved. In particular, these could share
|
|
|
|
|
// memory with mMainPosn through mAscent, and mIsStretched.
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float mShareOfWeightSoFar;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
bool mIsFrozen;
|
|
|
|
|
bool mHadMinViolation;
|
|
|
|
|
bool mHadMaxViolation;
|
|
|
|
|
|
|
|
|
|
// Misc:
|
2013-02-16 02:01:48 +04:00
|
|
|
|
bool mHadMeasuringReflow; // Did this item get a preliminary reflow,
|
|
|
|
|
// to measure its desired height?
|
2012-09-30 10:38:46 +04:00
|
|
|
|
bool mIsStretched; // See IsStretched() documentation
|
2014-01-22 02:52:27 +04:00
|
|
|
|
bool mIsStrut; // Is this item a "strut" left behind by an element
|
|
|
|
|
// with visibility:collapse?
|
2014-07-22 19:24:37 +04:00
|
|
|
|
|
|
|
|
|
// Does this item need to resolve a min-[width|height]:auto (in main-axis).
|
|
|
|
|
bool mNeedsMinSizeAutoResolution;
|
|
|
|
|
|
2015-06-13 00:28:24 +03:00
|
|
|
|
const WritingMode mWM; // The flex item's writing mode.
|
2012-09-30 10:38:46 +04:00
|
|
|
|
uint8_t mAlignSelf; // My "align-self" computed value (with "auto"
|
|
|
|
|
// swapped out for parent"s "align-items" value,
|
|
|
|
|
// in our constructor).
|
|
|
|
|
};
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
/**
|
|
|
|
|
* Represents a single flex line in a flex container.
|
|
|
|
|
* Manages a linked list of the FlexItems that are in the line.
|
|
|
|
|
*/
|
|
|
|
|
class nsFlexContainerFrame::FlexLine : public LinkedListElement<FlexLine>
|
|
|
|
|
{
|
2013-11-26 22:27:50 +04:00
|
|
|
|
public:
|
2013-11-26 22:27:51 +04:00
|
|
|
|
FlexLine()
|
2014-03-18 05:23:23 +04:00
|
|
|
|
: mNumItems(0),
|
2014-05-05 06:05:51 +04:00
|
|
|
|
mNumFrozenItems(0),
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mTotalInnerHypotheticalMainSize(0),
|
2013-11-26 22:27:52 +04:00
|
|
|
|
mTotalOuterHypotheticalMainSize(0),
|
|
|
|
|
mLineCrossSize(0),
|
2014-04-08 04:17:43 +04:00
|
|
|
|
mBaselineOffset(nscoord_MIN)
|
2013-11-26 22:27:51 +04:00
|
|
|
|
{}
|
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
// Returns the sum of our FlexItems' outer hypothetical main sizes.
|
|
|
|
|
// ("outer" = margin-box, and "hypothetical" = before flexing)
|
|
|
|
|
nscoord GetTotalOuterHypotheticalMainSize() const {
|
|
|
|
|
return mTotalOuterHypotheticalMainSize;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
// Accessors for our FlexItems & information about them:
|
|
|
|
|
FlexItem* GetFirstItem()
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
|
|
|
|
|
"mNumItems bookkeeping is off");
|
|
|
|
|
return mItems.getFirst();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FlexItem* GetFirstItem() const
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
|
|
|
|
|
"mNumItems bookkeeping is off");
|
|
|
|
|
return mItems.getFirst();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IsEmpty() const
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
|
|
|
|
|
"mNumItems bookkeeping is off");
|
|
|
|
|
return mItems.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t NumItems() const
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(mItems.isEmpty() == (mNumItems == 0),
|
|
|
|
|
"mNumItems bookkeeping is off");
|
|
|
|
|
return mNumItems;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// Adds the given FlexItem to our list of items (at the front or back
|
|
|
|
|
// depending on aShouldInsertAtFront), and adds its hypothetical
|
2014-03-18 05:23:23 +04:00
|
|
|
|
// outer & inner main sizes to our totals. Use this method instead of
|
|
|
|
|
// directly modifying the item list, so that our bookkeeping remains correct.
|
|
|
|
|
void AddItem(FlexItem* aItem,
|
2014-04-08 04:17:42 +04:00
|
|
|
|
bool aShouldInsertAtFront,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
nscoord aItemInnerHypotheticalMainSize,
|
|
|
|
|
nscoord aItemOuterHypotheticalMainSize)
|
|
|
|
|
{
|
2014-04-08 04:17:42 +04:00
|
|
|
|
if (aShouldInsertAtFront) {
|
|
|
|
|
mItems.insertFront(aItem);
|
|
|
|
|
} else {
|
|
|
|
|
mItems.insertBack(aItem);
|
|
|
|
|
}
|
2014-05-05 06:05:51 +04:00
|
|
|
|
|
|
|
|
|
// Update our various bookkeeping member-vars:
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mNumItems++;
|
2014-05-05 06:05:51 +04:00
|
|
|
|
if (aItem->IsFrozen()) {
|
|
|
|
|
mNumFrozenItems++;
|
|
|
|
|
}
|
2013-11-26 22:27:52 +04:00
|
|
|
|
mTotalInnerHypotheticalMainSize += aItemInnerHypotheticalMainSize;
|
|
|
|
|
mTotalOuterHypotheticalMainSize += aItemOuterHypotheticalMainSize;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
// Computes the cross-size and baseline position of this FlexLine, based on
|
|
|
|
|
// its FlexItems.
|
|
|
|
|
void ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker);
|
|
|
|
|
|
|
|
|
|
// Returns the cross-size of this line.
|
|
|
|
|
nscoord GetLineCrossSize() const { return mLineCrossSize; }
|
|
|
|
|
|
|
|
|
|
// Setter for line cross-size -- needed for cases where the flex container
|
|
|
|
|
// imposes a cross-size on the line. (e.g. for single-line flexbox, or for
|
|
|
|
|
// multi-line flexbox with 'align-content: stretch')
|
|
|
|
|
void SetLineCrossSize(nscoord aLineCrossSize) {
|
|
|
|
|
mLineCrossSize = aLineCrossSize;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:43 +04:00
|
|
|
|
/**
|
|
|
|
|
* Returns the offset within this line where any baseline-aligned FlexItems
|
|
|
|
|
* should place their baseline. Usually, this represents a distance from the
|
|
|
|
|
* line's cross-start edge, but if we're internally reversing the axes (see
|
|
|
|
|
* AreAxesInternallyReversed()), this instead represents the distance from
|
|
|
|
|
* its cross-end edge.
|
|
|
|
|
*
|
|
|
|
|
* If there are no baseline-aligned FlexItems, returns nscoord_MIN.
|
|
|
|
|
*/
|
|
|
|
|
nscoord GetBaselineOffset() const {
|
|
|
|
|
return mBaselineOffset;
|
2013-11-26 22:27:51 +04:00
|
|
|
|
}
|
2013-11-26 22:27:50 +04:00
|
|
|
|
|
2014-04-12 01:22:10 +04:00
|
|
|
|
// Runs the "Resolving Flexible Lengths" algorithm from section 9.7 of the
|
|
|
|
|
// CSS flexbox spec to distribute aFlexContainerMainSize among our flex items.
|
2013-11-26 22:27:53 +04:00
|
|
|
|
void ResolveFlexibleLengths(nscoord aFlexContainerMainSize);
|
2013-11-26 22:27:52 +04:00
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
void PositionItemsInMainAxis(uint8_t aJustifyContent,
|
|
|
|
|
nscoord aContentBoxMainSize,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker);
|
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
void PositionItemsInCrossAxis(nscoord aLineStartPosition,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker);
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
friend class AutoFlexLineListClearer; // (needs access to mItems)
|
2014-04-12 01:22:10 +04:00
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
private:
|
2014-05-18 05:49:06 +04:00
|
|
|
|
// Helpers for ResolveFlexibleLengths():
|
|
|
|
|
void FreezeItemsEarly(bool aIsUsingFlexGrow);
|
|
|
|
|
|
2014-03-18 02:09:40 +04:00
|
|
|
|
void FreezeOrRestoreEachFlexibleSize(const nscoord aTotalViolation,
|
|
|
|
|
bool aIsFinalIteration);
|
2014-03-18 05:23:23 +04:00
|
|
|
|
|
|
|
|
|
LinkedList<FlexItem> mItems; // Linked list of this line's flex items.
|
|
|
|
|
|
|
|
|
|
uint32_t mNumItems; // Number of FlexItems in this line (in |mItems|).
|
|
|
|
|
// (Shouldn't change after GenerateFlexLines finishes
|
|
|
|
|
// with this line -- at least, not until we add support
|
|
|
|
|
// for splitting lines across continuations. Then we can
|
|
|
|
|
// update this count carefully.)
|
|
|
|
|
|
2014-05-05 06:05:51 +04:00
|
|
|
|
// Number of *frozen* FlexItems in this line, based on FlexItem::IsFrozen().
|
|
|
|
|
// Mostly used for optimization purposes, e.g. to bail out early from loops
|
|
|
|
|
// when we can tell they have nothing left to do.
|
|
|
|
|
uint32_t mNumFrozenItems;
|
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
nscoord mTotalInnerHypotheticalMainSize;
|
|
|
|
|
nscoord mTotalOuterHypotheticalMainSize;
|
2013-11-26 22:27:51 +04:00
|
|
|
|
nscoord mLineCrossSize;
|
2014-04-08 04:17:43 +04:00
|
|
|
|
nscoord mBaselineOffset;
|
2013-11-26 22:27:50 +04:00
|
|
|
|
};
|
|
|
|
|
|
2014-01-22 02:51:58 +04:00
|
|
|
|
// Information about a strut left behind by a FlexItem that's been collapsed
|
|
|
|
|
// using "visibility:collapse".
|
|
|
|
|
struct nsFlexContainerFrame::StrutInfo {
|
|
|
|
|
StrutInfo(uint32_t aItemIdx, nscoord aStrutCrossSize)
|
|
|
|
|
: mItemIdx(aItemIdx),
|
|
|
|
|
mStrutCrossSize(aStrutCrossSize)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t mItemIdx; // Index in the child list.
|
|
|
|
|
nscoord mStrutCrossSize; // The cross-size of this strut.
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
2014-03-18 05:23:23 +04:00
|
|
|
|
BuildStrutInfoFromCollapsedItems(const FlexLine* aFirstLine,
|
2014-01-22 02:51:58 +04:00
|
|
|
|
nsTArray<StrutInfo>& aStruts)
|
|
|
|
|
{
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(aFirstLine, "null first line pointer");
|
2014-01-22 02:51:58 +04:00
|
|
|
|
MOZ_ASSERT(aStruts.IsEmpty(),
|
|
|
|
|
"We should only build up StrutInfo once per reflow, so "
|
|
|
|
|
"aStruts should be empty when this is called");
|
|
|
|
|
|
|
|
|
|
uint32_t itemIdxInContainer = 0;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (const FlexLine* line = aFirstLine; line; line = line->getNext()) {
|
|
|
|
|
for (const FlexItem* item = line->GetFirstItem(); item;
|
|
|
|
|
item = item->getNext()) {
|
2014-01-22 02:51:58 +04:00
|
|
|
|
if (NS_STYLE_VISIBILITY_COLLAPSE ==
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->Frame()->StyleVisibility()->mVisible) {
|
2014-01-22 02:51:58 +04:00
|
|
|
|
// Note the cross size of the line as the item's strut size.
|
|
|
|
|
aStruts.AppendElement(StrutInfo(itemIdxInContainer,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
line->GetLineCrossSize()));
|
2014-01-22 02:51:58 +04:00
|
|
|
|
}
|
|
|
|
|
itemIdxInContainer++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-19 07:37:56 +04:00
|
|
|
|
// Helper-function to find the first non-anonymous-box descendent of aFrame.
|
|
|
|
|
static nsIFrame*
|
|
|
|
|
GetFirstNonAnonBoxDescendant(nsIFrame* aFrame)
|
2012-12-27 00:17:52 +04:00
|
|
|
|
{
|
2013-05-22 07:59:35 +04:00
|
|
|
|
while (aFrame) {
|
2013-02-16 09:38:33 +04:00
|
|
|
|
nsIAtom* pseudoTag = aFrame->StyleContext()->GetPseudo();
|
2012-12-27 00:17:52 +04:00
|
|
|
|
|
|
|
|
|
// If aFrame isn't an anonymous container, then it'll do.
|
|
|
|
|
if (!pseudoTag || // No pseudotag.
|
|
|
|
|
!nsCSSAnonBoxes::IsAnonBox(pseudoTag) || // Pseudotag isn't anon.
|
|
|
|
|
pseudoTag == nsCSSAnonBoxes::mozNonElement) { // Text, not a container.
|
2013-05-22 07:59:35 +04:00
|
|
|
|
break;
|
2012-12-27 00:17:52 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Otherwise, descend to its first child and repeat.
|
2013-05-22 07:59:36 +04:00
|
|
|
|
|
|
|
|
|
// SPECIAL CASE: if we're dealing with an anonymous table, then it might
|
|
|
|
|
// be wrapping something non-anonymous in its caption or col-group lists
|
|
|
|
|
// (instead of its principal child list), so we have to look there.
|
|
|
|
|
// (Note: For anonymous tables that have a non-anon cell *and* a non-anon
|
|
|
|
|
// column, we'll always return the column. This is fine; we're really just
|
|
|
|
|
// looking for a handle to *anything* with a meaningful content node inside
|
|
|
|
|
// the table, for use in DOM comparisons to things outside of the table.)
|
|
|
|
|
if (MOZ_UNLIKELY(aFrame->GetType() == nsGkAtoms::tableOuterFrame)) {
|
|
|
|
|
nsIFrame* captionDescendant =
|
2015-11-26 12:12:39 +03:00
|
|
|
|
GetFirstNonAnonBoxDescendant(aFrame->GetChildList(kCaptionList).FirstChild());
|
2013-05-22 07:59:36 +04:00
|
|
|
|
if (captionDescendant) {
|
|
|
|
|
return captionDescendant;
|
|
|
|
|
}
|
|
|
|
|
} else if (MOZ_UNLIKELY(aFrame->GetType() == nsGkAtoms::tableFrame)) {
|
|
|
|
|
nsIFrame* colgroupDescendant =
|
2015-11-26 12:12:39 +03:00
|
|
|
|
GetFirstNonAnonBoxDescendant(aFrame->GetChildList(kColGroupList).FirstChild());
|
2013-05-22 07:59:36 +04:00
|
|
|
|
if (colgroupDescendant) {
|
|
|
|
|
return colgroupDescendant;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// USUAL CASE: Descend to the first child in principal list.
|
2012-12-27 00:17:52 +04:00
|
|
|
|
aFrame = aFrame->GetFirstPrincipalChild();
|
|
|
|
|
}
|
2013-05-22 07:59:35 +04:00
|
|
|
|
return aFrame;
|
2012-12-27 00:17:52 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sorting helper-function that compares two frames' "order" property-values,
|
|
|
|
|
* and if they're equal, compares the DOM positions of their corresponding
|
|
|
|
|
* content nodes. Returns true if aFrame1 is "less than or equal to" aFrame2
|
|
|
|
|
* according to this comparison.
|
|
|
|
|
*
|
|
|
|
|
* Note: This can't be a static function, because we need to pass it as a
|
|
|
|
|
* template argument. (Only functions with external linkage can be passed as
|
|
|
|
|
* template arguments.)
|
|
|
|
|
*
|
|
|
|
|
* @return true if the computed "order" property of aFrame1 is less than that
|
|
|
|
|
* of aFrame2, or if the computed "order" values are equal and aFrame1's
|
|
|
|
|
* corresponding DOM node is earlier than aFrame2's in the DOM tree.
|
|
|
|
|
* Otherwise, returns false.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
IsOrderLEQWithDOMFallback(nsIFrame* aFrame1,
|
|
|
|
|
nsIFrame* aFrame2)
|
|
|
|
|
{
|
2013-05-22 07:59:35 +04:00
|
|
|
|
MOZ_ASSERT(aFrame1->IsFlexItem() && aFrame2->IsFlexItem(),
|
|
|
|
|
"this method only intended for comparing flex items");
|
|
|
|
|
|
2012-12-27 00:17:52 +04:00
|
|
|
|
if (aFrame1 == aFrame2) {
|
|
|
|
|
// Anything is trivially LEQ itself, so we return "true" here... but it's
|
|
|
|
|
// probably bad if we end up actually needing this, so let's assert.
|
|
|
|
|
NS_ERROR("Why are we checking if a frame is LEQ itself?");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-01 09:14:03 +04:00
|
|
|
|
// If we've got a placeholder frame, use its out-of-flow frame's 'order' val.
|
|
|
|
|
{
|
|
|
|
|
nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
|
|
|
|
|
nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
|
|
|
|
|
|
|
|
|
|
int32_t order1 = aRealFrame1->StylePosition()->mOrder;
|
|
|
|
|
int32_t order2 = aRealFrame2->StylePosition()->mOrder;
|
2012-12-27 00:17:52 +04:00
|
|
|
|
|
2013-06-01 09:14:03 +04:00
|
|
|
|
if (order1 != order2) {
|
|
|
|
|
return order1 < order2;
|
|
|
|
|
}
|
2012-12-27 00:17:52 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-19 07:37:56 +04:00
|
|
|
|
// The "order" values are equal, so we need to fall back on DOM comparison.
|
|
|
|
|
// For that, we need to dig through any anonymous box wrapper frames to find
|
|
|
|
|
// the actual frame that corresponds to our child content.
|
|
|
|
|
aFrame1 = GetFirstNonAnonBoxDescendant(aFrame1);
|
|
|
|
|
aFrame2 = GetFirstNonAnonBoxDescendant(aFrame2);
|
2013-05-22 07:59:35 +04:00
|
|
|
|
MOZ_ASSERT(aFrame1 && aFrame2,
|
|
|
|
|
"why do we have an anonymous box without any "
|
|
|
|
|
"non-anonymous descendants?");
|
|
|
|
|
|
2013-05-19 07:37:56 +04:00
|
|
|
|
|
|
|
|
|
// Special case:
|
2013-05-17 02:02:16 +04:00
|
|
|
|
// If either frame is for generated content from ::before or ::after, then
|
2013-05-03 01:04:47 +04:00
|
|
|
|
// we can't use nsContentUtils::PositionIsBefore(), since that method won't
|
|
|
|
|
// recognize generated content as being an actual sibling of other nodes.
|
|
|
|
|
// We know where ::before and ::after nodes *effectively* insert in the DOM
|
|
|
|
|
// tree, though (at the beginning & end), so we can just special-case them.
|
2015-11-04 18:48:59 +03:00
|
|
|
|
nsIAtom* pseudo1 =
|
|
|
|
|
nsPlaceholderFrame::GetRealFrameFor(aFrame1)->StyleContext()->GetPseudo();
|
|
|
|
|
nsIAtom* pseudo2 =
|
|
|
|
|
nsPlaceholderFrame::GetRealFrameFor(aFrame2)->StyleContext()->GetPseudo();
|
|
|
|
|
|
2013-05-03 01:04:47 +04:00
|
|
|
|
if (pseudo1 == nsCSSPseudoElements::before ||
|
|
|
|
|
pseudo2 == nsCSSPseudoElements::after) {
|
|
|
|
|
// frame1 is ::before and/or frame2 is ::after => frame1 is LEQ frame2.
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (pseudo1 == nsCSSPseudoElements::after ||
|
|
|
|
|
pseudo2 == nsCSSPseudoElements::before) {
|
|
|
|
|
// frame1 is ::after and/or frame2 is ::before => frame1 is not LEQ frame2.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-19 07:37:56 +04:00
|
|
|
|
// Usual case: Compare DOM position.
|
|
|
|
|
nsIContent* content1 = aFrame1->GetContent();
|
|
|
|
|
nsIContent* content2 = aFrame2->GetContent();
|
2012-12-27 00:17:52 +04:00
|
|
|
|
MOZ_ASSERT(content1 != content2,
|
|
|
|
|
"Two different flex items are using the same nsIContent node for "
|
|
|
|
|
"comparison, so we may be sorting them in an arbitrary order");
|
|
|
|
|
|
|
|
|
|
return nsContentUtils::PositionIsBefore(content1, content2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sorting helper-function that compares two frames' "order" property-values.
|
|
|
|
|
* Returns true if aFrame1 is "less than or equal to" aFrame2 according to this
|
|
|
|
|
* comparison.
|
|
|
|
|
*
|
|
|
|
|
* Note: This can't be a static function, because we need to pass it as a
|
|
|
|
|
* template argument. (Only functions with external linkage can be passed as
|
|
|
|
|
* template arguments.)
|
|
|
|
|
*
|
|
|
|
|
* @return true if the computed "order" property of aFrame1 is less than or
|
|
|
|
|
* equal to that of aFrame2. Otherwise, returns false.
|
|
|
|
|
*/
|
|
|
|
|
bool
|
|
|
|
|
IsOrderLEQ(nsIFrame* aFrame1,
|
|
|
|
|
nsIFrame* aFrame2)
|
|
|
|
|
{
|
2013-05-22 07:59:35 +04:00
|
|
|
|
MOZ_ASSERT(aFrame1->IsFlexItem() && aFrame2->IsFlexItem(),
|
|
|
|
|
"this method only intended for comparing flex items");
|
|
|
|
|
|
2013-06-01 09:14:03 +04:00
|
|
|
|
// If we've got a placeholder frame, use its out-of-flow frame's 'order' val.
|
|
|
|
|
nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1);
|
|
|
|
|
nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2);
|
|
|
|
|
|
|
|
|
|
int32_t order1 = aRealFrame1->StylePosition()->mOrder;
|
|
|
|
|
int32_t order2 = aRealFrame2->StylePosition()->mOrder;
|
2012-12-27 00:17:52 +04:00
|
|
|
|
|
|
|
|
|
return order1 <= order2;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
bool
|
|
|
|
|
nsFlexContainerFrame::IsHorizontal()
|
|
|
|
|
{
|
2015-03-27 22:06:03 +03:00
|
|
|
|
const FlexboxAxisTracker axisTracker(StylePosition(), GetWritingMode());
|
2015-03-27 22:06:03 +03:00
|
|
|
|
return axisTracker.IsMainAxisHorizontal();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
FlexItem*
|
2013-11-01 06:39:02 +04:00
|
|
|
|
nsFlexContainerFrame::GenerateFlexItemForChild(
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
|
nsIFrame* aChildFrame,
|
|
|
|
|
const nsHTMLReflowState& aParentReflowState,
|
2013-11-01 06:39:02 +04:00
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
|
|
|
|
// Create temporary reflow state just for sizing -- to get hypothetical
|
|
|
|
|
// main-size and the computed values of min / max main-size property.
|
|
|
|
|
// (This reflow state will _not_ be used for reflow.)
|
2014-07-24 12:28:46 +04:00
|
|
|
|
nsHTMLReflowState
|
|
|
|
|
childRS(aPresContext, aParentReflowState, aChildFrame,
|
|
|
|
|
aParentReflowState.ComputedSize(aChildFrame->GetWritingMode()));
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-02-16 02:01:48 +04:00
|
|
|
|
// FLEX GROW & SHRINK WEIGHTS
|
|
|
|
|
// --------------------------
|
2013-02-17 01:51:02 +04:00
|
|
|
|
const nsStylePosition* stylePos = aChildFrame->StylePosition();
|
2013-02-16 02:01:48 +04:00
|
|
|
|
float flexGrow = stylePos->mFlexGrow;
|
|
|
|
|
float flexShrink = stylePos->mFlexShrink;
|
2015-06-13 00:28:24 +03:00
|
|
|
|
WritingMode childWM = childRS.GetWritingMode();
|
2013-02-16 02:01:48 +04:00
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// MAIN SIZES (flex base size, min/max size)
|
|
|
|
|
// -----------------------------------------
|
2015-06-13 00:28:24 +03:00
|
|
|
|
nscoord flexBaseSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
|
2015-05-15 21:57:08 +03:00
|
|
|
|
childRS.ComputedISize(),
|
|
|
|
|
childRS.ComputedBSize());
|
2015-06-13 00:28:24 +03:00
|
|
|
|
nscoord mainMinSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
|
2015-05-15 21:57:08 +03:00
|
|
|
|
childRS.ComputedMinISize(),
|
|
|
|
|
childRS.ComputedMinBSize());
|
2015-06-13 00:28:24 +03:00
|
|
|
|
nscoord mainMaxSize = GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, childWM,
|
2015-05-15 21:57:08 +03:00
|
|
|
|
childRS.ComputedMaxISize(),
|
|
|
|
|
childRS.ComputedMaxBSize());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// This is enforced by the nsHTMLReflowState where these values come from:
|
|
|
|
|
MOZ_ASSERT(mainMinSize <= mainMaxSize, "min size is larger than max size");
|
|
|
|
|
|
2015-01-22 06:45:37 +03:00
|
|
|
|
// CROSS SIZES (tentative cross size, min/max cross size)
|
|
|
|
|
// ------------------------------------------------------
|
|
|
|
|
// Grab the cross size from the reflow state. This might be the right value,
|
|
|
|
|
// or we might resolve it to something else in SizeItemInCrossAxis(); hence,
|
|
|
|
|
// it's tentative. See comment under "Cross Size Determination" for more.
|
2015-05-15 21:57:08 +03:00
|
|
|
|
nscoord tentativeCrossSize =
|
2015-06-13 00:28:24 +03:00
|
|
|
|
GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, childWM,
|
2015-05-15 21:57:08 +03:00
|
|
|
|
childRS.ComputedISize(),
|
|
|
|
|
childRS.ComputedBSize());
|
|
|
|
|
nscoord crossMinSize =
|
2015-06-13 00:28:24 +03:00
|
|
|
|
GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, childWM,
|
2015-05-15 21:57:08 +03:00
|
|
|
|
childRS.ComputedMinISize(),
|
|
|
|
|
childRS.ComputedMinBSize());
|
|
|
|
|
nscoord crossMaxSize =
|
2015-06-13 00:28:24 +03:00
|
|
|
|
GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, childWM,
|
2015-05-15 21:57:08 +03:00
|
|
|
|
childRS.ComputedMaxISize(),
|
|
|
|
|
childRS.ComputedMaxBSize());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// SPECIAL-CASE FOR WIDGET-IMPOSED SIZES
|
|
|
|
|
// Check if we're a themed widget, in which case we might have a minimum
|
|
|
|
|
// main & cross size imposed by our widget (which we can't go below), or
|
|
|
|
|
// (more severe) our widget might have only a single valid size.
|
|
|
|
|
bool isFixedSizeWidget = false;
|
2013-02-17 01:51:02 +04:00
|
|
|
|
const nsStyleDisplay* disp = aChildFrame->StyleDisplay();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
if (aChildFrame->IsThemed(disp)) {
|
2015-03-30 18:36:14 +03:00
|
|
|
|
LayoutDeviceIntSize widgetMinSize;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
bool canOverride = true;
|
|
|
|
|
aPresContext->GetTheme()->
|
2014-06-27 13:19:00 +04:00
|
|
|
|
GetMinimumWidgetSize(aPresContext, aChildFrame,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
disp->mAppearance,
|
|
|
|
|
&widgetMinSize, &canOverride);
|
|
|
|
|
|
|
|
|
|
nscoord widgetMainMinSize =
|
|
|
|
|
aPresContext->DevPixelsToAppUnits(
|
|
|
|
|
aAxisTracker.GetMainComponent(widgetMinSize));
|
|
|
|
|
nscoord widgetCrossMinSize =
|
|
|
|
|
aPresContext->DevPixelsToAppUnits(
|
|
|
|
|
aAxisTracker.GetCrossComponent(widgetMinSize));
|
|
|
|
|
|
2014-01-07 07:17:26 +04:00
|
|
|
|
// GMWS() returns border-box. We need content-box, so subtract
|
|
|
|
|
// borderPadding (but don't let that push our min sizes below 0).
|
|
|
|
|
nsMargin& bp = childRS.ComputedPhysicalBorderPadding();
|
|
|
|
|
widgetMainMinSize = std::max(widgetMainMinSize -
|
|
|
|
|
aAxisTracker.GetMarginSizeInMainAxis(bp), 0);
|
|
|
|
|
widgetCrossMinSize = std::max(widgetCrossMinSize -
|
|
|
|
|
aAxisTracker.GetMarginSizeInCrossAxis(bp), 0);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
if (!canOverride) {
|
|
|
|
|
// Fixed-size widget: freeze our main-size at the widget's mandated size.
|
|
|
|
|
// (Set min and max main-sizes to that size, too, to keep us from
|
|
|
|
|
// clamping to any other size later on.)
|
|
|
|
|
flexBaseSize = mainMinSize = mainMaxSize = widgetMainMinSize;
|
2015-01-22 06:45:37 +03:00
|
|
|
|
tentativeCrossSize = crossMinSize = crossMaxSize = widgetCrossMinSize;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
isFixedSizeWidget = true;
|
|
|
|
|
} else {
|
|
|
|
|
// Variable-size widget: ensure our min/max sizes are at least as large
|
|
|
|
|
// as the widget's mandated minimum size, so we don't flex below that.
|
2013-01-15 16:22:03 +04:00
|
|
|
|
mainMinSize = std::max(mainMinSize, widgetMainMinSize);
|
|
|
|
|
mainMaxSize = std::max(mainMaxSize, widgetMainMinSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-01-22 06:45:37 +03:00
|
|
|
|
if (tentativeCrossSize != NS_INTRINSICSIZE) {
|
|
|
|
|
tentativeCrossSize = std::max(tentativeCrossSize, widgetCrossMinSize);
|
|
|
|
|
}
|
2013-01-15 16:22:03 +04:00
|
|
|
|
crossMinSize = std::max(crossMinSize, widgetCrossMinSize);
|
|
|
|
|
crossMaxSize = std::max(crossMaxSize, widgetCrossMinSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 06:39:02 +04:00
|
|
|
|
// Construct the flex item!
|
2014-07-22 19:24:36 +04:00
|
|
|
|
FlexItem* item = new FlexItem(childRS,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
flexGrow, flexShrink, flexBaseSize,
|
|
|
|
|
mainMinSize, mainMaxSize,
|
2015-01-22 06:45:37 +03:00
|
|
|
|
tentativeCrossSize,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
crossMinSize, crossMaxSize,
|
|
|
|
|
aAxisTracker);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// If we're inflexible, we can just freeze to our hypothetical main-size
|
|
|
|
|
// up-front. Similarly, if we're a fixed-size widget, we only have one
|
|
|
|
|
// valid size, so we freeze to keep ourselves from flexing.
|
|
|
|
|
if (isFixedSizeWidget || (flexGrow == 0.0f && flexShrink == 0.0f)) {
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->Freeze();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Resolve "flex-basis:auto" and/or "min-[width|height]:auto" (which might
|
2014-07-22 19:24:36 +04:00
|
|
|
|
// require us to reflow the item to measure content height)
|
|
|
|
|
ResolveAutoFlexBasisAndMinSize(aPresContext, *item,
|
2014-07-22 19:24:37 +04:00
|
|
|
|
childRS, aAxisTracker);
|
2013-11-01 06:39:02 +04:00
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Static helper-functions for ResolveAutoFlexBasisAndMinSize():
|
|
|
|
|
// -------------------------------------------------------------
|
|
|
|
|
// Indicates whether the cross-size property is set to something definite.
|
|
|
|
|
// The logic here should be similar to the logic for isAutoWidth/isAutoHeight
|
|
|
|
|
// in nsLayoutUtils::ComputeSizeWithIntrinsicDimensions().
|
|
|
|
|
static bool
|
|
|
|
|
IsCrossSizeDefinite(const nsHTMLReflowState& aItemReflowState,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
|
|
|
|
{
|
|
|
|
|
const nsStylePosition* pos = aItemReflowState.mStylePosition;
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsCrossAxisHorizontal()) {
|
2014-07-22 19:24:37 +04:00
|
|
|
|
return pos->mWidth.GetUnit() != eStyleUnit_Auto;
|
|
|
|
|
}
|
|
|
|
|
// else, vertical. (We need to use IsAutoHeight() to catch e.g. %-height
|
|
|
|
|
// applied to indefinite-height containing block, which counts as auto.)
|
|
|
|
|
nscoord cbHeight = aItemReflowState.mCBReflowState->ComputedHeight();
|
|
|
|
|
return !nsLayoutUtils::IsAutoHeight(pos->mHeight, cbHeight);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If aFlexItem has a definite cross size, this function returns it, for usage
|
|
|
|
|
// (in combination with an intrinsic ratio) for resolving the item's main size
|
|
|
|
|
// or main min-size.
|
|
|
|
|
//
|
|
|
|
|
// The parameter "aMinSizeFallback" indicates whether we should fall back to
|
|
|
|
|
// returning the cross min-size, when the cross size is indefinite. (This param
|
|
|
|
|
// should be set IFF the caller intends to resolve the main min-size.) If this
|
|
|
|
|
// param is true, then this function is guaranteed to return a definite value
|
|
|
|
|
// (i.e. not NS_AUTOHEIGHT, excluding cases where huge sizes are involved).
|
|
|
|
|
//
|
|
|
|
|
// XXXdholbert the min-size behavior here is based on my understanding in
|
|
|
|
|
// http://lists.w3.org/Archives/Public/www-style/2014Jul/0053.html
|
|
|
|
|
// If my understanding there ends up being wrong, we'll need to update this.
|
|
|
|
|
static nscoord
|
|
|
|
|
CrossSizeToUseWithRatio(const FlexItem& aFlexItem,
|
|
|
|
|
const nsHTMLReflowState& aItemReflowState,
|
|
|
|
|
bool aMinSizeFallback,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
|
|
|
|
{
|
|
|
|
|
if (aFlexItem.IsStretched()) {
|
|
|
|
|
// Definite cross-size, imposed via 'align-self:stretch' & flex container.
|
|
|
|
|
return aFlexItem.GetCrossSize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsCrossSizeDefinite(aItemReflowState, aAxisTracker)) {
|
|
|
|
|
// Definite cross size.
|
2015-06-13 00:28:24 +03:00
|
|
|
|
return GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, aFlexItem.GetWritingMode(),
|
2015-05-15 21:57:08 +03:00
|
|
|
|
aItemReflowState.ComputedISize(),
|
|
|
|
|
aItemReflowState.ComputedBSize());
|
2014-07-22 19:24:37 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aMinSizeFallback) {
|
|
|
|
|
// Indefinite cross-size, and we're resolving main min-size, so we'll fall
|
|
|
|
|
// back to ussing the cross min-size (which should be definite).
|
2015-06-13 00:28:24 +03:00
|
|
|
|
return GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, aFlexItem.GetWritingMode(),
|
2015-05-15 21:57:08 +03:00
|
|
|
|
aItemReflowState.ComputedMinISize(),
|
|
|
|
|
aItemReflowState.ComputedMinBSize());
|
2014-07-22 19:24:37 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Indefinite cross-size.
|
|
|
|
|
return NS_AUTOHEIGHT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convenience function; returns a main-size, given a cross-size and an
|
|
|
|
|
// intrinsic ratio. The intrinsic ratio must not have 0 in its cross-axis
|
|
|
|
|
// component (or else we'll divide by 0).
|
|
|
|
|
static nscoord
|
|
|
|
|
MainSizeFromAspectRatio(nscoord aCrossSize,
|
|
|
|
|
const nsSize& aIntrinsicRatio,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0,
|
|
|
|
|
"Invalid ratio; will divide by 0! Caller should've checked...");
|
|
|
|
|
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsCrossAxisHorizontal()) {
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// cross axis horiz --> aCrossSize is a width. Converting to height.
|
2014-08-29 09:14:00 +04:00
|
|
|
|
return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.height, aIntrinsicRatio.width);
|
2014-07-22 19:24:37 +04:00
|
|
|
|
}
|
|
|
|
|
// cross axis vert --> aCrossSize is a height. Converting to width.
|
2014-08-29 09:14:00 +04:00
|
|
|
|
return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.width, aIntrinsicRatio.height);
|
2014-07-22 19:24:37 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Partially resolves "min-[width|height]:auto" and returns the resulting value.
|
|
|
|
|
// By "partially", I mean we don't consider the min-content size (but we do
|
|
|
|
|
// consider flex-basis, main max-size, and the intrinsic aspect ratio).
|
|
|
|
|
// The caller is responsible for computing & considering the min-content size
|
|
|
|
|
// in combination with the partially-resolved value that this function returns.
|
|
|
|
|
//
|
|
|
|
|
// Spec reference: http://dev.w3.org/csswg/css-flexbox/#min-size-auto
|
|
|
|
|
static nscoord
|
|
|
|
|
PartiallyResolveAutoMinSize(const FlexItem& aFlexItem,
|
|
|
|
|
const nsHTMLReflowState& aItemReflowState,
|
|
|
|
|
const nsSize& aIntrinsicRatio,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aFlexItem.NeedsMinSizeAutoResolution(),
|
|
|
|
|
"only call for FlexItems that need min-size auto resolution");
|
|
|
|
|
|
|
|
|
|
nscoord minMainSize = nscoord_MAX; // Intentionally huge; we'll shrink it
|
|
|
|
|
// from here, w/ std::min().
|
|
|
|
|
|
|
|
|
|
// We need the smallest of:
|
2014-11-25 22:28:15 +03:00
|
|
|
|
// * the used flex-basis, if the computed flex-basis was 'auto':
|
|
|
|
|
// XXXdholbert ('auto' might be renamed to 'main-size'; see bug 1032922)
|
|
|
|
|
if (eStyleUnit_Auto ==
|
|
|
|
|
aItemReflowState.mStylePosition->mFlexBasis.GetUnit() &&
|
2014-07-22 19:24:37 +04:00
|
|
|
|
aFlexItem.GetFlexBaseSize() != NS_AUTOHEIGHT) {
|
|
|
|
|
// NOTE: We skip this if the flex base size depends on content & isn't yet
|
|
|
|
|
// resolved. This is OK, because the caller is responsible for computing
|
|
|
|
|
// the min-content height and min()'ing it with the value we return, which
|
|
|
|
|
// is equivalent to what would happen if we min()'d that at this point.
|
|
|
|
|
minMainSize = std::min(minMainSize, aFlexItem.GetFlexBaseSize());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// * the computed max-width (max-height), if that value is definite:
|
|
|
|
|
nscoord maxSize =
|
2015-06-13 00:28:24 +03:00
|
|
|
|
GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, aFlexItem.GetWritingMode(),
|
2015-05-15 21:57:08 +03:00
|
|
|
|
aItemReflowState.ComputedMaxISize(),
|
|
|
|
|
aItemReflowState.ComputedMaxBSize());
|
2014-07-22 19:24:37 +04:00
|
|
|
|
if (maxSize != NS_UNCONSTRAINEDSIZE) {
|
|
|
|
|
minMainSize = std::min(minMainSize, maxSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// * if the item has no intrinsic aspect ratio, its min-content size:
|
|
|
|
|
// --- SKIPPING THIS IN THIS FUNCTION --- caller's responsibility.
|
|
|
|
|
|
|
|
|
|
// * if the item has an intrinsic aspect ratio, the width (height) calculated
|
|
|
|
|
// from the aspect ratio and any definite size constraints in the opposite
|
|
|
|
|
// dimension.
|
|
|
|
|
if (aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0) {
|
|
|
|
|
// We have a usable aspect ratio. (not going to divide by 0)
|
|
|
|
|
const bool useMinSizeIfCrossSizeIsIndefinite = true;
|
|
|
|
|
nscoord crossSizeToUseWithRatio =
|
|
|
|
|
CrossSizeToUseWithRatio(aFlexItem, aItemReflowState,
|
|
|
|
|
useMinSizeIfCrossSizeIsIndefinite,
|
|
|
|
|
aAxisTracker);
|
|
|
|
|
nscoord minMainSizeFromRatio =
|
|
|
|
|
MainSizeFromAspectRatio(crossSizeToUseWithRatio,
|
|
|
|
|
aIntrinsicRatio, aAxisTracker);
|
|
|
|
|
minMainSize = std::min(minMainSize, minMainSizeFromRatio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return minMainSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Resolves flex-basis:auto, using the given intrinsic ratio and the flex
|
|
|
|
|
// item's cross size. On success, updates the flex item with its resolved
|
|
|
|
|
// flex-basis and returns true. On failure (e.g. if the ratio is invalid or
|
|
|
|
|
// the cross-size is indefinite), returns false.
|
|
|
|
|
static bool
|
|
|
|
|
ResolveAutoFlexBasisFromRatio(FlexItem& aFlexItem,
|
|
|
|
|
const nsHTMLReflowState& aItemReflowState,
|
|
|
|
|
const nsSize& aIntrinsicRatio,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize(),
|
|
|
|
|
"Should only be called to resolve an 'auto' flex-basis");
|
|
|
|
|
// If the flex item has ...
|
|
|
|
|
// - an intrinsic aspect ratio,
|
2014-11-25 22:28:15 +03:00
|
|
|
|
// - a [used] flex-basis of 'main-size' [auto?] [We have this, if we're here.]
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// - a definite cross size
|
|
|
|
|
// then the flex base size is calculated from its inner cross size and the
|
|
|
|
|
// flex item’s intrinsic aspect ratio.
|
|
|
|
|
if (aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0) {
|
|
|
|
|
// We have a usable aspect ratio. (not going to divide by 0)
|
|
|
|
|
const bool useMinSizeIfCrossSizeIsIndefinite = false;
|
|
|
|
|
nscoord crossSizeToUseWithRatio =
|
|
|
|
|
CrossSizeToUseWithRatio(aFlexItem, aItemReflowState,
|
|
|
|
|
useMinSizeIfCrossSizeIsIndefinite,
|
|
|
|
|
aAxisTracker);
|
|
|
|
|
if (crossSizeToUseWithRatio != NS_AUTOHEIGHT) {
|
|
|
|
|
// We have a definite cross-size
|
|
|
|
|
nscoord mainSizeFromRatio =
|
|
|
|
|
MainSizeFromAspectRatio(crossSizeToUseWithRatio,
|
|
|
|
|
aIntrinsicRatio, aAxisTracker);
|
|
|
|
|
aFlexItem.SetFlexBaseSizeAndMainSize(mainSizeFromRatio);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Note: If & when we handle "min-height: min-content" for flex items,
|
|
|
|
|
// we may want to resolve that in this function, too.
|
2014-06-13 19:37:02 +04:00
|
|
|
|
void
|
2013-11-01 06:39:02 +04:00
|
|
|
|
nsFlexContainerFrame::
|
2014-07-22 19:24:36 +04:00
|
|
|
|
ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
|
|
|
|
|
FlexItem& aFlexItem,
|
2014-07-22 19:24:37 +04:00
|
|
|
|
const nsHTMLReflowState& aItemReflowState,
|
2014-07-22 19:24:36 +04:00
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2013-11-01 06:39:02 +04:00
|
|
|
|
{
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// (Note: We should never have a used flex-basis of "auto" if our main axis
|
|
|
|
|
// is horizontal; width values should always be resolvable without reflow.)
|
2015-03-27 22:06:03 +03:00
|
|
|
|
const bool isMainSizeAuto = (!aAxisTracker.IsMainAxisHorizontal() &&
|
2014-07-22 19:24:37 +04:00
|
|
|
|
NS_AUTOHEIGHT == aFlexItem.GetFlexBaseSize());
|
2014-07-22 19:24:35 +04:00
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
const bool isMainMinSizeAuto = aFlexItem.NeedsMinSizeAutoResolution();
|
2014-07-22 19:24:35 +04:00
|
|
|
|
|
|
|
|
|
if (!isMainSizeAuto && !isMainMinSizeAuto) {
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Nothing to do; this function is only needed for flex items
|
|
|
|
|
// with a used flex-basis of "auto" or a min-main-size of "auto".
|
2014-06-13 19:37:02 +04:00
|
|
|
|
return;
|
2013-11-01 06:39:02 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// We may be about to do computations based on our item's cross-size
|
|
|
|
|
// (e.g. using it as a contstraint when measuring our content in the
|
|
|
|
|
// main axis, or using it with the intrinsic ratio to obtain a main size).
|
|
|
|
|
// BEFORE WE DO THAT, we need let the item "pre-stretch" its cross size (if
|
|
|
|
|
// it's got 'align-self:stretch'), for a certain case where the spec says
|
|
|
|
|
// the stretched cross size is considered "definite". That case is if we
|
|
|
|
|
// have a single-line (nowrap) flex container which itself has a definite
|
|
|
|
|
// cross-size. Otherwise, we'll wait to do stretching, since (in other
|
|
|
|
|
// cases) we don't know how much the item should stretch yet.
|
|
|
|
|
const nsHTMLReflowState* flexContainerRS = aItemReflowState.parentReflowState;
|
|
|
|
|
MOZ_ASSERT(flexContainerRS,
|
|
|
|
|
"flex item's reflow state should have ptr to container's state");
|
|
|
|
|
if (NS_STYLE_FLEX_WRAP_NOWRAP == flexContainerRS->mStylePosition->mFlexWrap) {
|
|
|
|
|
// XXXdholbert Maybe this should share logic with ComputeCrossSize()...
|
|
|
|
|
// Alternately, maybe tentative container cross size should be passed down.
|
|
|
|
|
nscoord containerCrossSize =
|
2015-06-13 00:28:24 +03:00
|
|
|
|
GET_CROSS_COMPONENT_LOGICAL(aAxisTracker, aAxisTracker.GetWritingMode(),
|
2015-05-15 21:57:08 +03:00
|
|
|
|
flexContainerRS->ComputedISize(),
|
|
|
|
|
flexContainerRS->ComputedBSize());
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// Is container's cross size "definite"?
|
|
|
|
|
// (Container's cross size is definite if cross-axis is horizontal, or if
|
|
|
|
|
// cross-axis is vertical and the cross-size is not NS_AUTOHEIGHT.)
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsCrossAxisHorizontal() ||
|
2014-07-22 19:24:37 +04:00
|
|
|
|
containerCrossSize != NS_AUTOHEIGHT) {
|
|
|
|
|
aFlexItem.ResolveStretchedCrossSize(containerCrossSize, aAxisTracker);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-22 19:24:36 +04:00
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// We'll need the intrinsic ratio (if there is one), regardless of whether
|
|
|
|
|
// we're resolving min-[width|height]:auto or flex-basis:auto.
|
|
|
|
|
const nsSize ratio = aFlexItem.Frame()->GetIntrinsicRatio();
|
|
|
|
|
|
|
|
|
|
nscoord resolvedMinSize; // (only set/used if isMainMinSizeAuto==true)
|
|
|
|
|
bool minSizeNeedsToMeasureContent = false; // assume the best
|
|
|
|
|
if (isMainMinSizeAuto) {
|
|
|
|
|
// Resolve the min-size, except for considering the min-content size.
|
|
|
|
|
// (We'll consider that later, if we need to.)
|
|
|
|
|
resolvedMinSize = PartiallyResolveAutoMinSize(aFlexItem, aItemReflowState,
|
|
|
|
|
ratio, aAxisTracker);
|
|
|
|
|
if (resolvedMinSize > 0 &&
|
|
|
|
|
aAxisTracker.GetCrossComponent(ratio) == 0) {
|
|
|
|
|
// We don't have a usable aspect ratio, so we need to consider our
|
|
|
|
|
// min-content size as another candidate min-size, which we'll have to
|
|
|
|
|
// min() with the current resolvedMinSize.
|
|
|
|
|
// (If resolvedMinSize were already at 0, we could skip this measurement
|
|
|
|
|
// because it can't go any lower. But it's not 0, so we need it.)
|
|
|
|
|
minSizeNeedsToMeasureContent = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool flexBasisNeedsToMeasureContent = false; // assume the best
|
2014-07-22 19:24:36 +04:00
|
|
|
|
if (isMainSizeAuto) {
|
2014-07-22 19:24:37 +04:00
|
|
|
|
if (!ResolveAutoFlexBasisFromRatio(aFlexItem, aItemReflowState,
|
|
|
|
|
ratio, aAxisTracker)) {
|
|
|
|
|
flexBasisNeedsToMeasureContent = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Measure content, if needed (w/ intrinsic-width method or a reflow)
|
|
|
|
|
if (minSizeNeedsToMeasureContent || flexBasisNeedsToMeasureContent) {
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsMainAxisHorizontal()) {
|
2014-07-22 19:24:37 +04:00
|
|
|
|
if (minSizeNeedsToMeasureContent) {
|
2015-05-22 04:35:16 +03:00
|
|
|
|
nscoord frameMinISize =
|
|
|
|
|
aFlexItem.Frame()->GetMinISize(aItemReflowState.rendContext);
|
|
|
|
|
resolvedMinSize = std::min(resolvedMinSize, frameMinISize);
|
2014-07-22 19:24:37 +04:00
|
|
|
|
}
|
|
|
|
|
NS_ASSERTION(!flexBasisNeedsToMeasureContent,
|
|
|
|
|
"flex-basis:auto should have been resolved in the "
|
|
|
|
|
"reflow state, for horizontal flexbox. It shouldn't need "
|
|
|
|
|
"special handling here");
|
|
|
|
|
} else {
|
|
|
|
|
// If this item is flexible (vertically), or if we're measuring the
|
|
|
|
|
// 'auto' min-height and our main-size is something else, then we assume
|
|
|
|
|
// that the computed-height we're reflowing with now could be different
|
|
|
|
|
// from the one we'll use for this flex item's "actual" reflow later on.
|
|
|
|
|
// In that case, we need to be sure the flex item treats this as a
|
|
|
|
|
// vertical resize, even though none of its ancestors are necessarily
|
|
|
|
|
// being vertically resized.
|
|
|
|
|
// (Note: We don't have to do this for width, because InitResizeFlags
|
|
|
|
|
// will always turn on mHResize on when it sees that the computed width
|
|
|
|
|
// is different from current width, and that's all we need.)
|
|
|
|
|
bool forceVerticalResizeForMeasuringReflow =
|
|
|
|
|
!aFlexItem.IsFrozen() || // Is the item flexible?
|
|
|
|
|
!flexBasisNeedsToMeasureContent; // Are we *only* measuring it for
|
|
|
|
|
// 'min-height:auto'?
|
|
|
|
|
|
|
|
|
|
nscoord contentHeight =
|
|
|
|
|
MeasureFlexItemContentHeight(aPresContext, aFlexItem,
|
|
|
|
|
forceVerticalResizeForMeasuringReflow,
|
|
|
|
|
*flexContainerRS);
|
|
|
|
|
if (minSizeNeedsToMeasureContent) {
|
|
|
|
|
resolvedMinSize = std::min(resolvedMinSize, contentHeight);
|
|
|
|
|
}
|
|
|
|
|
if (flexBasisNeedsToMeasureContent) {
|
|
|
|
|
aFlexItem.SetFlexBaseSizeAndMainSize(contentHeight);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-22 19:24:36 +04:00
|
|
|
|
}
|
2014-07-22 19:24:37 +04:00
|
|
|
|
|
2014-07-22 19:24:36 +04:00
|
|
|
|
if (isMainMinSizeAuto) {
|
2014-07-22 19:24:37 +04:00
|
|
|
|
aFlexItem.UpdateMainMinSize(resolvedMinSize);
|
2014-07-22 19:24:36 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nscoord
|
|
|
|
|
nsFlexContainerFrame::
|
|
|
|
|
MeasureFlexItemContentHeight(nsPresContext* aPresContext,
|
|
|
|
|
FlexItem& aFlexItem,
|
|
|
|
|
bool aForceVerticalResizeForMeasuringReflow,
|
|
|
|
|
const nsHTMLReflowState& aParentReflowState)
|
|
|
|
|
{
|
|
|
|
|
// Set up a reflow state for measuring the flex item's auto-height:
|
2014-07-24 12:28:46 +04:00
|
|
|
|
WritingMode wm = aFlexItem.Frame()->GetWritingMode();
|
|
|
|
|
LogicalSize availSize = aParentReflowState.ComputedSize(wm);
|
|
|
|
|
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
|
2014-07-22 19:24:36 +04:00
|
|
|
|
nsHTMLReflowState
|
|
|
|
|
childRSForMeasuringHeight(aPresContext, aParentReflowState,
|
2014-07-24 12:28:46 +04:00
|
|
|
|
aFlexItem.Frame(), availSize,
|
2015-06-04 13:43:02 +03:00
|
|
|
|
nullptr, nsHTMLReflowState::CALLER_WILL_INIT);
|
2014-07-22 19:24:36 +04:00
|
|
|
|
childRSForMeasuringHeight.mFlags.mIsFlexContainerMeasuringHeight = true;
|
|
|
|
|
childRSForMeasuringHeight.Init(aPresContext);
|
|
|
|
|
|
|
|
|
|
if (aFlexItem.IsStretched()) {
|
|
|
|
|
childRSForMeasuringHeight.SetComputedWidth(aFlexItem.GetCrossSize());
|
2014-11-28 12:44:02 +03:00
|
|
|
|
childRSForMeasuringHeight.SetHResize(true);
|
2014-07-22 19:24:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (aForceVerticalResizeForMeasuringReflow) {
|
2014-11-28 12:44:02 +03:00
|
|
|
|
childRSForMeasuringHeight.SetVResize(true);
|
2013-11-01 06:39:02 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-31 17:50:31 +04:00
|
|
|
|
nsHTMLReflowMetrics childDesiredSize(childRSForMeasuringHeight);
|
2013-11-01 06:39:02 +04:00
|
|
|
|
nsReflowStatus childReflowStatus;
|
2013-12-18 22:34:46 +04:00
|
|
|
|
const uint32_t flags = NS_FRAME_NO_MOVE_FRAME;
|
2014-05-13 04:47:53 +04:00
|
|
|
|
ReflowChild(aFlexItem.Frame(), aPresContext,
|
|
|
|
|
childDesiredSize, childRSForMeasuringHeight,
|
|
|
|
|
0, 0, flags, childReflowStatus);
|
2013-11-01 06:39:02 +04:00
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus),
|
|
|
|
|
"We gave flex item unconstrained available height, so it "
|
|
|
|
|
"should be complete");
|
|
|
|
|
|
2014-05-13 04:47:53 +04:00
|
|
|
|
FinishReflowChild(aFlexItem.Frame(), aPresContext,
|
|
|
|
|
childDesiredSize, &childRSForMeasuringHeight,
|
|
|
|
|
0, 0, flags);
|
2013-11-01 06:39:02 +04:00
|
|
|
|
|
2014-07-22 19:24:36 +04:00
|
|
|
|
aFlexItem.SetHadMeasuringReflow();
|
|
|
|
|
|
2015-01-23 02:12:10 +03:00
|
|
|
|
// If this is the first child, save its ascent, since it may be what
|
|
|
|
|
// establishes the container's baseline. Also save the ascent if this child
|
|
|
|
|
// needs to be baseline-aligned. (Else, we don't care about ascent/baseline.)
|
|
|
|
|
if (aFlexItem.Frame() == mFrames.FirstChild() ||
|
2015-11-03 17:18:06 +03:00
|
|
|
|
aFlexItem.GetAlignSelf() == NS_STYLE_ALIGN_BASELINE) {
|
2015-01-23 02:12:10 +03:00
|
|
|
|
aFlexItem.SetAscent(childDesiredSize.BlockStartAscent());
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-01 06:39:02 +04:00
|
|
|
|
// Subtract border/padding in vertical axis, to get _just_
|
|
|
|
|
// the effective computed value of the "height" property.
|
2013-12-27 21:59:52 +04:00
|
|
|
|
nscoord childDesiredHeight = childDesiredSize.Height() -
|
2013-12-27 21:59:21 +04:00
|
|
|
|
childRSForMeasuringHeight.ComputedPhysicalBorderPadding().TopBottom();
|
2013-11-01 06:39:02 +04:00
|
|
|
|
|
2014-07-22 19:24:36 +04:00
|
|
|
|
return std::max(0, childDesiredHeight);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-22 19:24:36 +04:00
|
|
|
|
FlexItem::FlexItem(nsHTMLReflowState& aFlexItemReflowState,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
float aFlexGrow, float aFlexShrink, nscoord aFlexBaseSize,
|
|
|
|
|
nscoord aMainMinSize, nscoord aMainMaxSize,
|
2015-01-22 06:45:37 +03:00
|
|
|
|
nscoord aTentativeCrossSize,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord aCrossMinSize, nscoord aCrossMaxSize,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2014-07-22 19:24:36 +04:00
|
|
|
|
: mFrame(aFlexItemReflowState.frame),
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mFlexGrow(aFlexGrow),
|
|
|
|
|
mFlexShrink(aFlexShrink),
|
2014-07-22 19:24:36 +04:00
|
|
|
|
mBorderPadding(aFlexItemReflowState.ComputedPhysicalBorderPadding()),
|
|
|
|
|
mMargin(aFlexItemReflowState.ComputedPhysicalMargin()),
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mMainMinSize(aMainMinSize),
|
|
|
|
|
mMainMaxSize(aMainMaxSize),
|
|
|
|
|
mCrossMinSize(aCrossMinSize),
|
|
|
|
|
mCrossMaxSize(aCrossMaxSize),
|
|
|
|
|
mMainPosn(0),
|
2015-01-22 06:45:37 +03:00
|
|
|
|
mCrossSize(aTentativeCrossSize),
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mCrossPosn(0),
|
|
|
|
|
mAscent(0),
|
2014-05-04 20:10:28 +04:00
|
|
|
|
mShareOfWeightSoFar(0.0f),
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mIsFrozen(false),
|
|
|
|
|
mHadMinViolation(false),
|
|
|
|
|
mHadMaxViolation(false),
|
2013-02-16 02:01:48 +04:00
|
|
|
|
mHadMeasuringReflow(false),
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mIsStretched(false),
|
2014-01-22 02:52:27 +04:00
|
|
|
|
mIsStrut(false),
|
2014-07-22 19:24:37 +04:00
|
|
|
|
// mNeedsMinSizeAutoResolution is initialized in CheckForMinSizeAuto()
|
2015-11-03 17:18:06 +03:00
|
|
|
|
mWM(aFlexItemReflowState.GetWritingMode())
|
|
|
|
|
// mAlignSelf, see below
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2014-01-22 02:52:32 +04:00
|
|
|
|
MOZ_ASSERT(mFrame, "expecting a non-null child frame");
|
2014-03-04 23:08:54 +04:00
|
|
|
|
MOZ_ASSERT(mFrame->GetType() != nsGkAtoms::placeholderFrame,
|
|
|
|
|
"placeholder frames should not be treated as flex items");
|
|
|
|
|
MOZ_ASSERT(!(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
|
|
|
|
|
"out-of-flow frames should not be treated as flex items");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
mAlignSelf = aFlexItemReflowState.mStylePosition->ComputedAlignSelf(
|
|
|
|
|
aFlexItemReflowState.mStyleDisplay,
|
|
|
|
|
mFrame->StyleContext()->GetParent());
|
|
|
|
|
if (MOZ_UNLIKELY(mAlignSelf == NS_STYLE_ALIGN_AUTO)) {
|
|
|
|
|
// Happens in rare edge cases when 'position' was ignored by the frame
|
|
|
|
|
// constructor (and the style system computed 'auto' based on 'position').
|
|
|
|
|
mAlignSelf = NS_STYLE_ALIGN_STRETCH;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// XXX strip off the <overflow-position> bit until we implement that
|
|
|
|
|
mAlignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS;
|
|
|
|
|
|
2013-11-01 06:39:02 +04:00
|
|
|
|
SetFlexBaseSizeAndMainSize(aFlexBaseSize);
|
2014-07-22 19:24:37 +04:00
|
|
|
|
CheckForMinSizeAuto(aFlexItemReflowState, aAxisTracker);
|
2013-11-01 06:39:02 +04:00
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Assert that any "auto" margin components are set to 0.
|
|
|
|
|
// (We'll resolve them later; until then, we want to treat them as 0-sized.)
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
{
|
2014-07-22 19:24:36 +04:00
|
|
|
|
const nsStyleSides& styleMargin =
|
|
|
|
|
aFlexItemReflowState.mStyleMargin->mMargin;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
NS_FOR_CSS_SIDES(side) {
|
|
|
|
|
if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
|
|
|
|
|
MOZ_ASSERT(GetMarginComponentForSide(side) == 0,
|
|
|
|
|
"Someone else tried to resolve our auto margin");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
|
|
|
|
// If the flex item's inline axis is the same as the cross axis, then
|
|
|
|
|
// 'align-self:baseline' is identical to 'flex-start'. If that's the case, we
|
|
|
|
|
// just directly convert our align-self value here, so that we don't have to
|
|
|
|
|
// handle this with special cases elsewhere.
|
|
|
|
|
// Moreover: for the time being (until we support writing-modes),
|
|
|
|
|
// all inline axes are horizontal -- so we can just check if the cross axis
|
|
|
|
|
// is horizontal.
|
2015-03-27 22:06:03 +03:00
|
|
|
|
// FIXME: Once we support writing-mode (vertical text), this
|
|
|
|
|
// IsCrossAxisHorizontal check won't be sufficient anymore -- we'll actually
|
|
|
|
|
// need to compare our inline axis vs. the cross axis.
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (mAlignSelf == NS_STYLE_ALIGN_BASELINE &&
|
2015-03-27 22:06:03 +03:00
|
|
|
|
aAxisTracker.IsCrossAxisHorizontal()) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
mAlignSelf = NS_STYLE_ALIGN_FLEX_START;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-22 02:52:27 +04:00
|
|
|
|
// Simplified constructor for creating a special "strut" FlexItem, for a child
|
|
|
|
|
// with visibility:collapse. The strut has 0 main-size, and it only exists to
|
|
|
|
|
// impose a minimum cross size on whichever FlexLine it ends up in.
|
2015-06-13 00:28:24 +03:00
|
|
|
|
FlexItem::FlexItem(nsIFrame* aChildFrame, nscoord aCrossSize,
|
|
|
|
|
WritingMode aContainerWM)
|
2014-01-22 02:52:27 +04:00
|
|
|
|
: mFrame(aChildFrame),
|
|
|
|
|
mFlexGrow(0.0f),
|
|
|
|
|
mFlexShrink(0.0f),
|
|
|
|
|
// mBorderPadding uses default constructor,
|
|
|
|
|
// mMargin uses default constructor,
|
|
|
|
|
mFlexBaseSize(0),
|
|
|
|
|
mMainMinSize(0),
|
|
|
|
|
mMainMaxSize(0),
|
|
|
|
|
mCrossMinSize(0),
|
|
|
|
|
mCrossMaxSize(0),
|
|
|
|
|
mMainSize(0),
|
|
|
|
|
mMainPosn(0),
|
|
|
|
|
mCrossSize(aCrossSize),
|
|
|
|
|
mCrossPosn(0),
|
|
|
|
|
mAscent(0),
|
2014-05-04 20:10:28 +04:00
|
|
|
|
mShareOfWeightSoFar(0.0f),
|
2014-01-22 02:52:27 +04:00
|
|
|
|
mIsFrozen(true),
|
|
|
|
|
mHadMinViolation(false),
|
|
|
|
|
mHadMaxViolation(false),
|
|
|
|
|
mHadMeasuringReflow(false),
|
|
|
|
|
mIsStretched(false),
|
|
|
|
|
mIsStrut(true), // (this is the constructor for making struts, after all)
|
2014-07-22 19:24:37 +04:00
|
|
|
|
mNeedsMinSizeAutoResolution(false),
|
2015-06-13 00:28:24 +03:00
|
|
|
|
mWM(aContainerWM),
|
2015-11-03 17:18:06 +03:00
|
|
|
|
mAlignSelf(NS_STYLE_ALIGN_FLEX_START)
|
2014-01-22 02:52:27 +04:00
|
|
|
|
{
|
2014-01-22 02:52:32 +04:00
|
|
|
|
MOZ_ASSERT(mFrame, "expecting a non-null child frame");
|
2014-01-22 02:52:27 +04:00
|
|
|
|
MOZ_ASSERT(NS_STYLE_VISIBILITY_COLLAPSE ==
|
|
|
|
|
mFrame->StyleVisibility()->mVisible,
|
|
|
|
|
"Should only make struts for children with 'visibility:collapse'");
|
2014-03-04 23:08:54 +04:00
|
|
|
|
MOZ_ASSERT(mFrame->GetType() != nsGkAtoms::placeholderFrame,
|
|
|
|
|
"placeholder frames should not be treated as flex items");
|
|
|
|
|
MOZ_ASSERT(!(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
|
|
|
|
|
"out-of-flow frames should not be treated as flex items");
|
2014-01-22 02:52:27 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-07-22 19:24:37 +04:00
|
|
|
|
void
|
|
|
|
|
FlexItem::CheckForMinSizeAuto(const nsHTMLReflowState& aFlexItemReflowState,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
|
|
|
|
{
|
|
|
|
|
const nsStylePosition* pos = aFlexItemReflowState.mStylePosition;
|
|
|
|
|
const nsStyleDisplay* disp = aFlexItemReflowState.mStyleDisplay;
|
|
|
|
|
|
|
|
|
|
// We'll need special behavior for "min-[width|height]:auto" (whichever is in
|
|
|
|
|
// the main axis) iff:
|
|
|
|
|
// (a) its computed value is "auto"
|
|
|
|
|
// (b) the "overflow" sub-property in the same axis (the main axis) has a
|
|
|
|
|
// computed value of "visible"
|
|
|
|
|
const nsStyleCoord& minSize = GET_MAIN_COMPONENT(aAxisTracker,
|
|
|
|
|
pos->mMinWidth,
|
|
|
|
|
pos->mMinHeight);
|
|
|
|
|
|
|
|
|
|
const uint8_t overflowVal = GET_MAIN_COMPONENT(aAxisTracker,
|
|
|
|
|
disp->mOverflowX,
|
|
|
|
|
disp->mOverflowY);
|
|
|
|
|
|
|
|
|
|
mNeedsMinSizeAutoResolution = (minSize.GetUnit() == eStyleUnit_Auto &&
|
|
|
|
|
overflowVal == NS_STYLE_OVERFLOW_VISIBLE);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
nscoord
|
2015-03-27 22:06:03 +03:00
|
|
|
|
FlexItem::GetBaselineOffsetFromOuterCrossEdge(
|
|
|
|
|
AxisEdgeType aEdge,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker) const
|
2013-11-26 22:27:51 +04:00
|
|
|
|
{
|
|
|
|
|
// NOTE: Currently, 'mAscent' (taken from reflow) is an inherently vertical
|
|
|
|
|
// measurement -- it's the distance from the border-top edge of this FlexItem
|
|
|
|
|
// to its baseline. So, we can really only do baseline alignment when the
|
|
|
|
|
// cross axis is vertical. (The FlexItem constructor enforces this when
|
|
|
|
|
// resolving the item's "mAlignSelf" value).
|
2015-03-27 22:06:03 +03:00
|
|
|
|
MOZ_ASSERT(!aAxisTracker.IsCrossAxisHorizontal(),
|
2013-11-26 22:27:51 +04:00
|
|
|
|
"Only expecting to be doing baseline computations when the "
|
|
|
|
|
"cross axis is vertical");
|
2014-02-27 11:28:38 +04:00
|
|
|
|
|
2015-03-27 22:06:03 +03:00
|
|
|
|
AxisOrientationType crossAxis = aAxisTracker.GetCrossAxis();
|
|
|
|
|
mozilla::Side sideToMeasureFrom = kAxisOrientationToSidesMap[crossAxis][aEdge];
|
2014-04-08 04:17:43 +04:00
|
|
|
|
|
2015-01-23 02:12:11 +03:00
|
|
|
|
nscoord marginTopToBaseline = ResolvedAscent() + mMargin.top;
|
2013-11-26 22:27:51 +04:00
|
|
|
|
|
2014-04-08 04:17:43 +04:00
|
|
|
|
if (sideToMeasureFrom == eSideTop) {
|
|
|
|
|
// Measuring from top (normal case): the distance from the margin-box top
|
|
|
|
|
// edge to the baseline is just ascent + margin-top.
|
2013-11-26 22:27:51 +04:00
|
|
|
|
return marginTopToBaseline;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:43 +04:00
|
|
|
|
MOZ_ASSERT(sideToMeasureFrom == eSideBottom,
|
|
|
|
|
"We already checked that we're dealing with a vertical axis, and "
|
|
|
|
|
"we're not using the top side, so that only leaves the bottom...");
|
|
|
|
|
|
|
|
|
|
// Measuring from bottom: The distance from the margin-box bottom edge to the
|
|
|
|
|
// baseline is just the margin-box cross size (i.e. outer cross size), minus
|
|
|
|
|
// the already-computed distance from margin-top to baseline.
|
2015-03-27 22:06:03 +03:00
|
|
|
|
return GetOuterCrossSize(crossAxis) - marginTopToBaseline;
|
2013-11-26 22:27:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
uint32_t
|
|
|
|
|
FlexItem::GetNumAutoMarginsInAxis(AxisOrientationType aAxis) const
|
|
|
|
|
{
|
|
|
|
|
uint32_t numAutoMargins = 0;
|
2013-02-17 01:51:02 +04:00
|
|
|
|
const nsStyleSides& styleMargin = mFrame->StyleMargin()->mMargin;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
for (uint32_t i = 0; i < eNumAxisEdges; i++) {
|
2014-06-28 14:13:13 +04:00
|
|
|
|
mozilla::Side side = kAxisOrientationToSidesMap[aAxis][i];
|
2012-09-30 10:38:46 +04:00
|
|
|
|
if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
|
|
|
|
|
numAutoMargins++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mostly for clarity:
|
|
|
|
|
MOZ_ASSERT(numAutoMargins <= 2,
|
|
|
|
|
"We're just looking at one item along one dimension, so we "
|
|
|
|
|
"should only have examined 2 margins");
|
|
|
|
|
|
|
|
|
|
return numAutoMargins;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Keeps track of our position along a particular axis (where a '0' position
|
|
|
|
|
// corresponds to the 'start' edge of that axis).
|
|
|
|
|
// This class shouldn't be instantiated directly -- rather, it should only be
|
|
|
|
|
// instantiated via its subclasses defined below.
|
2013-04-12 07:20:45 +04:00
|
|
|
|
class MOZ_STACK_CLASS PositionTracker {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
public:
|
|
|
|
|
// Accessor for the current value of the position that we're tracking.
|
|
|
|
|
inline nscoord GetPosition() const { return mPosition; }
|
|
|
|
|
inline AxisOrientationType GetAxis() const { return mAxis; }
|
|
|
|
|
|
|
|
|
|
// Advances our position across the start edge of the given margin, in the
|
|
|
|
|
// axis we're tracking.
|
|
|
|
|
void EnterMargin(const nsMargin& aMargin)
|
|
|
|
|
{
|
2014-06-28 14:13:13 +04:00
|
|
|
|
mozilla::Side side = kAxisOrientationToSidesMap[mAxis][eAxisEdge_Start];
|
2014-07-01 21:58:14 +04:00
|
|
|
|
mPosition += aMargin.Side(side);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Advances our position across the end edge of the given margin, in the axis
|
|
|
|
|
// we're tracking.
|
|
|
|
|
void ExitMargin(const nsMargin& aMargin)
|
|
|
|
|
{
|
2014-06-28 14:13:13 +04:00
|
|
|
|
mozilla::Side side = kAxisOrientationToSidesMap[mAxis][eAxisEdge_End];
|
2014-07-01 21:58:14 +04:00
|
|
|
|
mPosition += aMargin.Side(side);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Advances our current position from the start side of a child frame's
|
|
|
|
|
// border-box to the frame's upper or left edge (depending on our axis).
|
2015-04-16 22:01:14 +03:00
|
|
|
|
// (Note that this is a no-op if our axis grows in the same direction as
|
|
|
|
|
// the corresponding logical axis.)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
void EnterChildFrame(nscoord aChildFrameSize)
|
|
|
|
|
{
|
2015-04-16 22:01:14 +03:00
|
|
|
|
if (mIsAxisReversed) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mPosition += aChildFrameSize;
|
2015-04-16 22:01:14 +03:00
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Advances our current position from a frame's upper or left border-box edge
|
|
|
|
|
// (whichever is in the axis we're tracking) to the 'end' side of the frame
|
|
|
|
|
// in the axis that we're tracking. (Note that this is a no-op if our axis
|
2015-04-16 22:01:14 +03:00
|
|
|
|
// is reversed with respect to the corresponding logical axis.)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
void ExitChildFrame(nscoord aChildFrameSize)
|
|
|
|
|
{
|
2015-04-16 22:01:14 +03:00
|
|
|
|
if (!mIsAxisReversed) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mPosition += aChildFrameSize;
|
2015-04-16 22:01:14 +03:00
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
// Protected constructor, to be sure we're only instantiated via a subclass.
|
2015-04-16 22:01:14 +03:00
|
|
|
|
PositionTracker(AxisOrientationType aAxis, bool aIsAxisReversed)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
: mPosition(0),
|
2015-04-16 22:01:14 +03:00
|
|
|
|
mAxis(aAxis),
|
|
|
|
|
mIsAxisReversed(aIsAxisReversed)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{}
|
|
|
|
|
|
2015-04-10 19:27:54 +03:00
|
|
|
|
// Delete copy-constructor & reassignment operator, to prevent accidental
|
|
|
|
|
// (unnecessary) copying.
|
|
|
|
|
PositionTracker(const PositionTracker&) = delete;
|
|
|
|
|
PositionTracker& operator=(const PositionTracker&) = delete;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Member data:
|
|
|
|
|
nscoord mPosition; // The position we're tracking
|
2015-04-16 22:01:14 +03:00
|
|
|
|
// XXXdholbert [BEGIN DEPRECATED]
|
|
|
|
|
const AxisOrientationType mAxis; // The axis along which we're moving.
|
|
|
|
|
// XXXdholbert [END DEPRECATED]
|
|
|
|
|
const bool mIsAxisReversed; // Is the axis along which we're moving reversed
|
|
|
|
|
// (e.g. LTR vs RTL) with respect to the
|
|
|
|
|
// corresponding axis on the flex container's WM?
|
2012-09-30 10:38:46 +04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Tracks our position in the main axis, when we're laying out flex items.
|
2013-09-18 01:53:56 +04:00
|
|
|
|
// The "0" position represents the main-start edge of the flex container's
|
|
|
|
|
// content-box.
|
2013-04-12 07:20:45 +04:00
|
|
|
|
class MOZ_STACK_CLASS MainAxisPositionTracker : public PositionTracker {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
public:
|
2013-11-26 22:27:52 +04:00
|
|
|
|
MainAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
const FlexLine* aLine,
|
2013-11-26 22:27:52 +04:00
|
|
|
|
uint8_t aJustifyContent,
|
2013-10-01 03:38:36 +04:00
|
|
|
|
nscoord aContentBoxMainSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
~MainAxisPositionTracker() {
|
|
|
|
|
MOZ_ASSERT(mNumPackingSpacesRemaining == 0,
|
|
|
|
|
"miscounted the number of packing spaces");
|
|
|
|
|
MOZ_ASSERT(mNumAutoMarginsInMainAxis == 0,
|
|
|
|
|
"miscounted the number of auto margins");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Advances past the packing space (if any) between two flex items
|
|
|
|
|
void TraversePackingSpace();
|
|
|
|
|
|
|
|
|
|
// If aItem has any 'auto' margins in the main axis, this method updates the
|
|
|
|
|
// corresponding values in its margin.
|
|
|
|
|
void ResolveAutoMarginsInMainAxis(FlexItem& aItem);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
nscoord mPackingSpaceRemaining;
|
|
|
|
|
uint32_t mNumAutoMarginsInMainAxis;
|
|
|
|
|
uint32_t mNumPackingSpacesRemaining;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// XXX this should be uint16_t when we add explicit fallback handling
|
2012-09-30 10:38:46 +04:00
|
|
|
|
uint8_t mJustifyContent;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Utility class for managing our position along the cross axis along
|
2013-09-18 01:53:56 +04:00
|
|
|
|
// the whole flex container (at a higher level than a single line).
|
|
|
|
|
// The "0" position represents the cross-start edge of the flex container's
|
|
|
|
|
// content-box.
|
2013-04-12 07:20:45 +04:00
|
|
|
|
class MOZ_STACK_CLASS CrossAxisPositionTracker : public PositionTracker {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
public:
|
2014-03-18 05:23:23 +04:00
|
|
|
|
CrossAxisPositionTracker(FlexLine* aFirstLine,
|
2013-12-05 22:57:51 +04:00
|
|
|
|
uint8_t aAlignContent,
|
|
|
|
|
nscoord aContentBoxCrossSize,
|
|
|
|
|
bool aIsCrossSizeDefinite,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker);
|
|
|
|
|
|
|
|
|
|
// Advances past the packing space (if any) between two flex lines
|
|
|
|
|
void TraversePackingSpace();
|
|
|
|
|
|
|
|
|
|
// Advances past the given FlexLine
|
|
|
|
|
void TraverseLine(FlexLine& aLine) { mPosition += aLine.GetLineCrossSize(); }
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// Redeclare the frame-related methods from PositionTracker as private with
|
2015-01-07 02:35:02 +03:00
|
|
|
|
// = delete, to be sure (at compile time) that no client code can invoke
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// them. (Unlike the other PositionTracker derived classes, this class here
|
|
|
|
|
// deals with FlexLines, not with individual FlexItems or frames.)
|
2015-01-07 02:35:02 +03:00
|
|
|
|
void EnterMargin(const nsMargin& aMargin) = delete;
|
|
|
|
|
void ExitMargin(const nsMargin& aMargin) = delete;
|
|
|
|
|
void EnterChildFrame(nscoord aChildFrameSize) = delete;
|
|
|
|
|
void ExitChildFrame(nscoord aChildFrameSize) = delete;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
|
|
|
|
nscoord mPackingSpaceRemaining;
|
|
|
|
|
uint32_t mNumPackingSpacesRemaining;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// XXX this should be uint16_t when we add explicit fallback handling
|
2013-12-05 22:57:51 +04:00
|
|
|
|
uint8_t mAlignContent;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Utility class for managing our position along the cross axis, *within* a
|
|
|
|
|
// single flex line.
|
2013-04-12 07:20:45 +04:00
|
|
|
|
class MOZ_STACK_CLASS SingleLineCrossAxisPositionTracker : public PositionTracker {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
public:
|
2014-09-01 07:36:37 +04:00
|
|
|
|
explicit SingleLineCrossAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
void ResolveAutoMarginsInCrossAxis(const FlexLine& aLine,
|
|
|
|
|
FlexItem& aItem);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
void EnterAlignPackingSpace(const FlexLine& aLine,
|
2014-04-08 04:17:42 +04:00
|
|
|
|
const FlexItem& aItem,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Resets our position to the cross-start edge of this line.
|
|
|
|
|
inline void ResetPosition() { mPosition = 0; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// Frame class boilerplate
|
|
|
|
|
// =======================
|
|
|
|
|
|
|
|
|
|
NS_QUERYFRAME_HEAD(nsFlexContainerFrame)
|
|
|
|
|
NS_QUERYFRAME_ENTRY(nsFlexContainerFrame)
|
|
|
|
|
NS_QUERYFRAME_TAIL_INHERITING(nsFlexContainerFrameSuper)
|
|
|
|
|
|
2012-06-27 02:12:13 +04:00
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsFlexContainerFrame)
|
|
|
|
|
|
2014-05-25 02:20:40 +04:00
|
|
|
|
nsContainerFrame*
|
2012-06-27 02:12:13 +04:00
|
|
|
|
NS_NewFlexContainerFrame(nsIPresShell* aPresShell,
|
|
|
|
|
nsStyleContext* aContext)
|
|
|
|
|
{
|
|
|
|
|
return new (aPresShell) nsFlexContainerFrame(aContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// nsFlexContainerFrame Method Implementations
|
|
|
|
|
// ===========================================
|
|
|
|
|
|
2012-06-27 02:12:13 +04:00
|
|
|
|
/* virtual */
|
|
|
|
|
nsFlexContainerFrame::~nsFlexContainerFrame()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-27 00:17:52 +04:00
|
|
|
|
template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
|
|
|
|
|
/* static */ bool
|
|
|
|
|
nsFlexContainerFrame::SortChildrenIfNeeded()
|
|
|
|
|
{
|
2013-10-01 01:26:04 +04:00
|
|
|
|
if (nsIFrame::IsFrameListSorted<IsLessThanOrEqual>(mFrames)) {
|
2012-12-27 00:17:52 +04:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-01 01:26:04 +04:00
|
|
|
|
nsIFrame::SortFrameList<IsLessThanOrEqual>(mFrames);
|
2012-12-27 00:17:52 +04:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
/* virtual */
|
2012-06-27 02:12:13 +04:00
|
|
|
|
nsIAtom*
|
|
|
|
|
nsFlexContainerFrame::GetType() const
|
|
|
|
|
{
|
|
|
|
|
return nsGkAtoms::flexContainerFrame;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-06 03:31:14 +04:00
|
|
|
|
#ifdef DEBUG_FRAME_DUMP
|
2014-02-18 11:47:48 +04:00
|
|
|
|
nsresult
|
2012-06-27 02:12:13 +04:00
|
|
|
|
nsFlexContainerFrame::GetFrameName(nsAString& aResult) const
|
|
|
|
|
{
|
|
|
|
|
return MakeFrameName(NS_LITERAL_STRING("FlexContainer"), aResult);
|
|
|
|
|
}
|
2014-01-06 03:31:14 +04:00
|
|
|
|
#endif
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2012-11-21 05:24:59 +04:00
|
|
|
|
// Helper for BuildDisplayList, to implement this special-case for flex items
|
|
|
|
|
// from the spec:
|
|
|
|
|
// Flex items paint exactly the same as block-level elements in the
|
|
|
|
|
// normal flow, except that 'z-index' values other than 'auto' create
|
|
|
|
|
// a stacking context even if 'position' is 'static'.
|
|
|
|
|
// http://www.w3.org/TR/2012/CR-css3-flexbox-20120918/#painting
|
|
|
|
|
uint32_t
|
|
|
|
|
GetDisplayFlagsForFlexItem(nsIFrame* aFrame)
|
|
|
|
|
{
|
|
|
|
|
MOZ_ASSERT(aFrame->IsFlexItem(), "Should only be called on flex items");
|
|
|
|
|
|
2013-02-17 01:51:02 +04:00
|
|
|
|
const nsStylePosition* pos = aFrame->StylePosition();
|
2012-11-21 05:24:59 +04:00
|
|
|
|
if (pos->mZIndex.GetUnit() == eStyleUnit_Integer) {
|
|
|
|
|
return nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT;
|
|
|
|
|
}
|
2013-04-18 20:51:18 +04:00
|
|
|
|
return nsIFrame::DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT;
|
2012-11-21 05:24:59 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-14 15:12:27 +04:00
|
|
|
|
void
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nsFlexContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
|
const nsDisplayListSet& aLists)
|
|
|
|
|
{
|
2014-08-28 04:48:21 +04:00
|
|
|
|
// XXXdholbert hacky temporary band-aid for bug 1059138: Trivially pass this
|
|
|
|
|
// assertion (skip it, basically) if the first child is part of a shadow DOM.
|
|
|
|
|
// (IsOrderLEQWithDOMFallback doesn't know how to compare tree-position of a
|
|
|
|
|
// shadow-DOM element vs. a non-shadow-DOM element.)
|
2013-05-28 20:39:02 +04:00
|
|
|
|
NS_ASSERTION(
|
2014-08-28 04:48:21 +04:00
|
|
|
|
(!mFrames.IsEmpty() &&
|
|
|
|
|
mFrames.FirstChild()->GetContent()->GetContainingShadow()) ||
|
2013-10-01 01:26:04 +04:00
|
|
|
|
nsIFrame::IsFrameListSorted<IsOrderLEQWithDOMFallback>(mFrames),
|
2013-05-28 20:39:02 +04:00
|
|
|
|
"Child frames aren't sorted correctly");
|
2012-12-27 00:17:52 +04:00
|
|
|
|
|
2013-02-14 15:08:08 +04:00
|
|
|
|
DisplayBorderBackgroundOutline(aBuilder, aLists);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2012-11-30 12:13:23 +04:00
|
|
|
|
// Our children are all block-level, so their borders/backgrounds all go on
|
|
|
|
|
// the BlockBorderBackgrounds list.
|
|
|
|
|
nsDisplayListSet childLists(aLists, aLists.BlockBorderBackgrounds());
|
2015-04-01 07:50:46 +03:00
|
|
|
|
for (nsIFrame* childFrame : mFrames) {
|
|
|
|
|
BuildDisplayListForChild(aBuilder, childFrame, aDirtyRect, childLists,
|
|
|
|
|
GetDisplayFlagsForFlexItem(childFrame));
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
// helper for the debugging method below
|
|
|
|
|
bool
|
|
|
|
|
FrameWantsToBeInAnonymousFlexItem(nsIFrame* aFrame)
|
|
|
|
|
{
|
|
|
|
|
// Note: This needs to match the logic in
|
2014-05-20 03:57:00 +04:00
|
|
|
|
// nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem()
|
2012-09-30 10:38:46 +04:00
|
|
|
|
return (aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
|
|
|
|
|
nsGkAtoms::placeholderFrame == aFrame->GetType());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Debugging method, to let us assert that our anonymous flex items are
|
|
|
|
|
// set up correctly -- in particular, we assert:
|
|
|
|
|
// (1) we don't have any inline non-replaced children
|
|
|
|
|
// (2) we don't have any consecutive anonymous flex items
|
|
|
|
|
// (3) we don't have any empty anonymous flex items
|
|
|
|
|
//
|
|
|
|
|
// XXXdholbert This matches what nsCSSFrameConstructor currently does, and what
|
|
|
|
|
// the spec used to say. However, the spec has now changed regarding what
|
|
|
|
|
// types of content get wrapped in an anonymous flexbox item. The patch that
|
|
|
|
|
// implements those changes (in nsCSSFrameConstructor) will need to change
|
|
|
|
|
// this method as well.
|
|
|
|
|
void
|
|
|
|
|
nsFlexContainerFrame::SanityCheckAnonymousFlexItems() const
|
|
|
|
|
{
|
|
|
|
|
bool prevChildWasAnonFlexItem = false;
|
2015-04-01 07:50:46 +03:00
|
|
|
|
for (nsIFrame* child : mFrames) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
MOZ_ASSERT(!FrameWantsToBeInAnonymousFlexItem(child),
|
|
|
|
|
"frame wants to be inside an anonymous flex item, "
|
|
|
|
|
"but it isn't");
|
2013-02-16 09:38:33 +04:00
|
|
|
|
if (child->StyleContext()->GetPseudo() ==
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nsCSSAnonBoxes::anonymousFlexItem) {
|
2014-03-08 03:58:38 +04:00
|
|
|
|
MOZ_ASSERT(!prevChildWasAnonFlexItem ||
|
|
|
|
|
HasAnyStateBits(NS_STATE_FLEX_CHILDREN_REORDERED),
|
2014-01-09 02:37:13 +04:00
|
|
|
|
"two anon flex items in a row (shouldn't happen, unless our "
|
|
|
|
|
"children have been reordered with the 'order' property)");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
nsIFrame* firstWrappedChild = child->GetFirstPrincipalChild();
|
|
|
|
|
MOZ_ASSERT(firstWrappedChild,
|
|
|
|
|
"anonymous flex item is empty (shouldn't happen)");
|
|
|
|
|
prevChildWasAnonFlexItem = true;
|
|
|
|
|
} else {
|
|
|
|
|
prevChildWasAnonFlexItem = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
2014-05-18 05:49:06 +04:00
|
|
|
|
void
|
|
|
|
|
FlexLine::FreezeItemsEarly(bool aIsUsingFlexGrow)
|
|
|
|
|
{
|
|
|
|
|
// After we've established the type of flexing we're doing (growing vs.
|
|
|
|
|
// shrinking), and before we try to flex any items, we freeze items that
|
|
|
|
|
// obviously *can't* flex.
|
|
|
|
|
//
|
|
|
|
|
// Quoting the spec:
|
|
|
|
|
// # Freeze, setting its target main size to its hypothetical main size...
|
|
|
|
|
// # - any item that has a flex factor of zero
|
|
|
|
|
// # - if using the flex grow factor: any item that has a flex base size
|
|
|
|
|
// # greater than its hypothetical main size
|
|
|
|
|
// # - if using the flex shrink factor: any item that has a flex base size
|
|
|
|
|
// # smaller than its hypothetical main size
|
|
|
|
|
// http://dev.w3.org/csswg/css-flexbox/#resolve-flexible-lengths-flex-factors
|
|
|
|
|
//
|
|
|
|
|
// (NOTE: At this point, item->GetMainSize() *is* the item's hypothetical
|
|
|
|
|
// main size, since SetFlexBaseSizeAndMainSize() sets it up that way, and the
|
|
|
|
|
// item hasn't had a chance to flex away from that yet.)
|
|
|
|
|
|
|
|
|
|
// Since this loop only operates on unfrozen flex items, we can break as
|
|
|
|
|
// soon as we have seen all of them.
|
|
|
|
|
uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
|
|
|
|
|
for (FlexItem* item = mItems.getFirst();
|
|
|
|
|
numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
|
|
|
|
|
MOZ_ASSERT(item, "numUnfrozenItemsToBeSeen says items remain to be seen");
|
|
|
|
|
|
|
|
|
|
if (!item->IsFrozen()) {
|
|
|
|
|
numUnfrozenItemsToBeSeen--;
|
|
|
|
|
bool shouldFreeze = (0.0f == item->GetFlexFactor(aIsUsingFlexGrow));
|
|
|
|
|
if (!shouldFreeze) {
|
|
|
|
|
if (aIsUsingFlexGrow) {
|
|
|
|
|
if (item->GetFlexBaseSize() > item->GetMainSize()) {
|
|
|
|
|
shouldFreeze = true;
|
|
|
|
|
}
|
|
|
|
|
} else { // using flex-shrink
|
|
|
|
|
if (item->GetFlexBaseSize() < item->GetMainSize()) {
|
|
|
|
|
shouldFreeze = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (shouldFreeze) {
|
|
|
|
|
// Freeze item! (at its hypothetical main size)
|
|
|
|
|
item->Freeze();
|
|
|
|
|
mNumFrozenItems++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Based on the sign of aTotalViolation, this function freezes a subset of our
|
|
|
|
|
// flexible sizes, and restores the remaining ones to their initial pref sizes.
|
2014-03-18 02:09:40 +04:00
|
|
|
|
void
|
|
|
|
|
FlexLine::FreezeOrRestoreEachFlexibleSize(const nscoord aTotalViolation,
|
|
|
|
|
bool aIsFinalIteration)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
|
|
|
|
enum FreezeType {
|
|
|
|
|
eFreezeEverything,
|
|
|
|
|
eFreezeMinViolations,
|
|
|
|
|
eFreezeMaxViolations
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
FreezeType freezeType;
|
|
|
|
|
if (aTotalViolation == 0) {
|
|
|
|
|
freezeType = eFreezeEverything;
|
|
|
|
|
} else if (aTotalViolation > 0) {
|
|
|
|
|
freezeType = eFreezeMinViolations;
|
|
|
|
|
} else { // aTotalViolation < 0
|
|
|
|
|
freezeType = eFreezeMaxViolations;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-05 06:05:51 +04:00
|
|
|
|
// Since this loop only operates on unfrozen flex items, we can break as
|
|
|
|
|
// soon as we have seen all of them.
|
|
|
|
|
uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
|
|
|
|
|
for (FlexItem* item = mItems.getFirst();
|
|
|
|
|
numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
|
|
|
|
|
MOZ_ASSERT(item, "numUnfrozenItemsToBeSeen says items remain to be seen");
|
2014-03-18 05:23:23 +04:00
|
|
|
|
if (!item->IsFrozen()) {
|
2014-05-05 06:05:51 +04:00
|
|
|
|
numUnfrozenItemsToBeSeen--;
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(!item->HadMinViolation() || !item->HadMaxViolation(),
|
|
|
|
|
"Can have either min or max violation, but not both");
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
if (eFreezeEverything == freezeType ||
|
2014-03-18 05:23:23 +04:00
|
|
|
|
(eFreezeMinViolations == freezeType && item->HadMinViolation()) ||
|
|
|
|
|
(eFreezeMaxViolations == freezeType && item->HadMaxViolation())) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(item->GetMainSize() >= item->GetMainMinSize(),
|
2012-09-30 10:38:46 +04:00
|
|
|
|
"Freezing item at a size below its minimum");
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(item->GetMainSize() <= item->GetMainMaxSize(),
|
2012-09-30 10:38:46 +04:00
|
|
|
|
"Freezing item at a size above its maximum");
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->Freeze();
|
2014-05-05 06:05:51 +04:00
|
|
|
|
mNumFrozenItems++;
|
2014-03-18 02:09:40 +04:00
|
|
|
|
} else if (MOZ_UNLIKELY(aIsFinalIteration)) {
|
2013-12-31 20:47:47 +04:00
|
|
|
|
// XXXdholbert If & when bug 765861 is fixed, we should upgrade this
|
|
|
|
|
// assertion to be fatal except in documents with enormous lengths.
|
2013-12-31 20:47:43 +04:00
|
|
|
|
NS_ERROR("Final iteration still has unfrozen items, this shouldn't"
|
|
|
|
|
" happen unless there was nscoord under/overflow.");
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->Freeze();
|
2014-05-05 06:05:51 +04:00
|
|
|
|
mNumFrozenItems++;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
} // else, we'll reset this item's main size to its flex base size on the
|
|
|
|
|
// next iteration of this algorithm.
|
|
|
|
|
|
|
|
|
|
// Clear this item's violation(s), now that we've dealt with them
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->ClearViolationFlags();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2013-11-26 22:27:53 +04:00
|
|
|
|
FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2015-11-06 01:35:03 +03:00
|
|
|
|
MOZ_LOG(gFlexContainerLog, LogLevel::Debug, ("ResolveFlexibleLengths\n"));
|
2014-05-18 05:49:06 +04:00
|
|
|
|
|
|
|
|
|
// Determine whether we're going to be growing or shrinking items.
|
|
|
|
|
const bool isUsingFlexGrow =
|
|
|
|
|
(mTotalOuterHypotheticalMainSize < aFlexContainerMainSize);
|
|
|
|
|
|
|
|
|
|
// Do an "early freeze" for flex items that obviously can't flex in the
|
|
|
|
|
// direction we've chosen:
|
|
|
|
|
FreezeItemsEarly(isUsingFlexGrow);
|
|
|
|
|
|
2014-05-05 06:05:51 +04:00
|
|
|
|
if (mNumFrozenItems == mNumItems) {
|
|
|
|
|
// All our items are frozen, so we have no flexible lengths to resolve.
|
2012-09-30 10:38:46 +04:00
|
|
|
|
return;
|
|
|
|
|
}
|
2014-05-05 06:05:51 +04:00
|
|
|
|
MOZ_ASSERT(!IsEmpty(), "empty lines should take the early-return above");
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Subtract space occupied by our items' margins/borders/padding, so we can
|
|
|
|
|
// just be dealing with the space available for our flex items' content
|
|
|
|
|
// boxes.
|
2013-11-26 22:27:53 +04:00
|
|
|
|
nscoord spaceReservedForMarginBorderPadding =
|
|
|
|
|
mTotalOuterHypotheticalMainSize - mTotalInnerHypotheticalMainSize;
|
|
|
|
|
|
|
|
|
|
nscoord spaceAvailableForFlexItemsContentBoxes =
|
|
|
|
|
aFlexContainerMainSize - spaceReservedForMarginBorderPadding;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-05-04 20:10:28 +04:00
|
|
|
|
nscoord origAvailableFreeSpace;
|
|
|
|
|
bool isOrigAvailFreeSpaceInitialized = false;
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// NOTE: I claim that this chunk of the algorithm (the looping part) needs to
|
2014-03-18 05:23:23 +04:00
|
|
|
|
// run the loop at MOST mNumItems times. This claim should hold up
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// because we'll freeze at least one item on each loop iteration, and once
|
|
|
|
|
// we've run out of items to freeze, there's nothing left to do. However,
|
|
|
|
|
// in most cases, we'll break out of this loop long before we hit that many
|
|
|
|
|
// iterations.
|
|
|
|
|
for (uint32_t iterationCounter = 0;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
iterationCounter < mNumItems; iterationCounter++) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Set every not-yet-frozen item's used main size to its
|
|
|
|
|
// flex base size, and subtract all the used main sizes from our
|
|
|
|
|
// total amount of space to determine the 'available free space'
|
|
|
|
|
// (positive or negative) to be distributed among our flexible items.
|
|
|
|
|
nscoord availableFreeSpace = spaceAvailableForFlexItemsContentBoxes;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
|
|
|
|
|
if (!item->IsFrozen()) {
|
|
|
|
|
item->SetMainSize(item->GetFlexBaseSize());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
2014-03-18 05:23:23 +04:00
|
|
|
|
availableFreeSpace -= item->GetMainSize();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-06 01:35:03 +03:00
|
|
|
|
MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
(" available free space = %d\n", availableFreeSpace));
|
|
|
|
|
|
2014-06-03 02:15:23 +04:00
|
|
|
|
|
|
|
|
|
// The sign of our free space should agree with the type of flexing
|
|
|
|
|
// (grow/shrink) that we're doing (except if we've had integer overflow;
|
|
|
|
|
// then, all bets are off). Any disagreement should've made us use the
|
|
|
|
|
// other type of flexing, or should've been resolved in FreezeItemsEarly.
|
|
|
|
|
// XXXdholbert If & when bug 765861 is fixed, we should upgrade this
|
|
|
|
|
// assertion to be fatal except in documents with enormous lengths.
|
|
|
|
|
NS_ASSERTION((isUsingFlexGrow && availableFreeSpace >= 0) ||
|
|
|
|
|
(!isUsingFlexGrow && availableFreeSpace <= 0),
|
|
|
|
|
"availableFreeSpace's sign should match isUsingFlexGrow");
|
2014-05-18 05:49:47 +04:00
|
|
|
|
|
|
|
|
|
// If we have any free space available, give each flexible item a portion
|
|
|
|
|
// of availableFreeSpace.
|
|
|
|
|
if (availableFreeSpace != 0) {
|
2014-05-04 20:10:28 +04:00
|
|
|
|
// The first time we do this, we initialize origAvailableFreeSpace.
|
|
|
|
|
if (!isOrigAvailFreeSpaceInitialized) {
|
|
|
|
|
origAvailableFreeSpace = availableFreeSpace;
|
|
|
|
|
isOrigAvailFreeSpaceInitialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// STRATEGY: On each item, we compute & store its "share" of the total
|
2014-05-04 20:10:28 +04:00
|
|
|
|
// weight that we've seen so far:
|
|
|
|
|
// curWeight / weightSum
|
2012-09-30 10:38:46 +04:00
|
|
|
|
//
|
|
|
|
|
// Then, when we go to actually distribute the space (in the next loop),
|
|
|
|
|
// we can simply walk backwards through the elements and give each item
|
|
|
|
|
// its "share" multiplied by the remaining available space.
|
|
|
|
|
//
|
2014-05-04 20:10:28 +04:00
|
|
|
|
// SPECIAL CASE: If the sum of the weights is larger than the
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// maximum representable float (overflowing to infinity), then we can't
|
|
|
|
|
// sensibly divide out proportional shares anymore. In that case, we
|
2014-05-04 20:10:28 +04:00
|
|
|
|
// simply treat the flex item(s) with the largest weights as if
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// their weights were infinite (dwarfing all the others), and we
|
|
|
|
|
// distribute all of the available space among them.
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float weightSum = 0.0f;
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float flexFactorSum = 0.0f;
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float largestWeight = 0.0f;
|
|
|
|
|
uint32_t numItemsWithLargestWeight = 0;
|
2014-05-05 06:05:51 +04:00
|
|
|
|
|
|
|
|
|
// Since this loop only operates on unfrozen flex items, we can break as
|
|
|
|
|
// soon as we have seen all of them.
|
|
|
|
|
uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
|
|
|
|
|
for (FlexItem* item = mItems.getFirst();
|
|
|
|
|
numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
|
|
|
|
|
MOZ_ASSERT(item,
|
|
|
|
|
"numUnfrozenItemsToBeSeen says items remain to be seen");
|
|
|
|
|
if (!item->IsFrozen()) {
|
|
|
|
|
numUnfrozenItemsToBeSeen--;
|
|
|
|
|
|
|
|
|
|
float curWeight = item->GetWeight(isUsingFlexGrow);
|
|
|
|
|
float curFlexFactor = item->GetFlexFactor(isUsingFlexGrow);
|
|
|
|
|
MOZ_ASSERT(curWeight >= 0.0f, "weights are non-negative");
|
|
|
|
|
MOZ_ASSERT(curFlexFactor >= 0.0f, "flex factors are non-negative");
|
|
|
|
|
|
|
|
|
|
weightSum += curWeight;
|
|
|
|
|
flexFactorSum += curFlexFactor;
|
|
|
|
|
|
2014-10-01 13:26:00 +04:00
|
|
|
|
if (IsFinite(weightSum)) {
|
2014-05-05 06:05:51 +04:00
|
|
|
|
if (curWeight == 0.0f) {
|
|
|
|
|
item->SetShareOfWeightSoFar(0.0f);
|
|
|
|
|
} else {
|
|
|
|
|
item->SetShareOfWeightSoFar(curWeight / weightSum);
|
|
|
|
|
}
|
|
|
|
|
} // else, the sum of weights overflows to infinity, in which
|
|
|
|
|
// case we don't bother with "SetShareOfWeightSoFar" since
|
|
|
|
|
// we know we won't use it. (instead, we'll just give every
|
|
|
|
|
// item with the largest weight an equal share of space.)
|
|
|
|
|
|
|
|
|
|
// Update our largest-weight tracking vars
|
|
|
|
|
if (curWeight > largestWeight) {
|
|
|
|
|
largestWeight = curWeight;
|
|
|
|
|
numItemsWithLargestWeight = 1;
|
|
|
|
|
} else if (curWeight == largestWeight) {
|
|
|
|
|
numItemsWithLargestWeight++;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-04 20:10:28 +04:00
|
|
|
|
if (weightSum != 0.0f) {
|
|
|
|
|
MOZ_ASSERT(flexFactorSum != 0.0f,
|
|
|
|
|
"flex factor sum can't be 0, if a weighted sum "
|
|
|
|
|
"of its components (weightSum) is nonzero");
|
|
|
|
|
if (flexFactorSum < 1.0f) {
|
|
|
|
|
// Our unfrozen flex items don't want all of the original free space!
|
|
|
|
|
// (Their flex factors add up to something less than 1.)
|
|
|
|
|
// Hence, make sure we don't distribute any more than the portion of
|
|
|
|
|
// our original free space that these items actually want.
|
|
|
|
|
nscoord totalDesiredPortionOfOrigFreeSpace =
|
|
|
|
|
NSToCoordRound(origAvailableFreeSpace * flexFactorSum);
|
|
|
|
|
|
|
|
|
|
// Clamp availableFreeSpace to be no larger than that ^^.
|
|
|
|
|
// (using min or max, depending on sign).
|
|
|
|
|
// This should not change the sign of availableFreeSpace (except
|
|
|
|
|
// possibly by setting it to 0), as enforced by this assertion:
|
|
|
|
|
MOZ_ASSERT(totalDesiredPortionOfOrigFreeSpace == 0 ||
|
|
|
|
|
((totalDesiredPortionOfOrigFreeSpace > 0) ==
|
|
|
|
|
(availableFreeSpace > 0)),
|
|
|
|
|
"When we reduce available free space for flex factors < 1,"
|
|
|
|
|
"we shouldn't change the sign of the free space...");
|
|
|
|
|
|
|
|
|
|
if (availableFreeSpace > 0) {
|
|
|
|
|
availableFreeSpace = std::min(availableFreeSpace,
|
|
|
|
|
totalDesiredPortionOfOrigFreeSpace);
|
|
|
|
|
} else {
|
|
|
|
|
availableFreeSpace = std::max(availableFreeSpace,
|
|
|
|
|
totalDesiredPortionOfOrigFreeSpace);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-06 01:35:03 +03:00
|
|
|
|
MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
(" Distributing available space:"));
|
2014-05-05 06:05:51 +04:00
|
|
|
|
// Since this loop only operates on unfrozen flex items, we can break as
|
|
|
|
|
// soon as we have seen all of them.
|
|
|
|
|
numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
// NOTE: It's important that we traverse our items in *reverse* order
|
|
|
|
|
// here, for correct width distribution according to the items'
|
2014-05-04 20:10:28 +04:00
|
|
|
|
// "ShareOfWeightSoFar" progressively-calculated values.
|
2014-05-05 06:05:51 +04:00
|
|
|
|
for (FlexItem* item = mItems.getLast();
|
|
|
|
|
numUnfrozenItemsToBeSeen > 0; item = item->getPrevious()) {
|
|
|
|
|
MOZ_ASSERT(item,
|
|
|
|
|
"numUnfrozenItemsToBeSeen says items remain to be seen");
|
2014-03-18 05:23:23 +04:00
|
|
|
|
if (!item->IsFrozen()) {
|
2014-05-05 06:05:51 +04:00
|
|
|
|
numUnfrozenItemsToBeSeen--;
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// To avoid rounding issues, we compute the change in size for this
|
|
|
|
|
// item, and then subtract it from the remaining available space.
|
|
|
|
|
nscoord sizeDelta = 0;
|
2014-10-01 13:26:00 +04:00
|
|
|
|
if (IsFinite(weightSum)) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
float myShareOfRemainingSpace =
|
2014-05-04 20:10:28 +04:00
|
|
|
|
item->GetShareOfWeightSoFar();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(myShareOfRemainingSpace >= 0.0f &&
|
|
|
|
|
myShareOfRemainingSpace <= 1.0f,
|
|
|
|
|
"my share should be nonnegative fractional amount");
|
|
|
|
|
|
|
|
|
|
if (myShareOfRemainingSpace == 1.0f) {
|
|
|
|
|
// (We special-case 1.0f to avoid float error from converting
|
|
|
|
|
// availableFreeSpace from integer*1.0f --> float --> integer)
|
|
|
|
|
sizeDelta = availableFreeSpace;
|
|
|
|
|
} else if (myShareOfRemainingSpace > 0.0f) {
|
|
|
|
|
sizeDelta = NSToCoordRound(availableFreeSpace *
|
|
|
|
|
myShareOfRemainingSpace);
|
|
|
|
|
}
|
2014-05-04 20:10:28 +04:00
|
|
|
|
} else if (item->GetWeight(isUsingFlexGrow) == largestWeight) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Total flexibility is infinite, so we're just distributing
|
|
|
|
|
// the available space equally among the items that are tied for
|
|
|
|
|
// having the largest weight (and this is one of those items).
|
|
|
|
|
sizeDelta =
|
|
|
|
|
NSToCoordRound(availableFreeSpace /
|
2014-05-04 20:10:28 +04:00
|
|
|
|
float(numItemsWithLargestWeight));
|
|
|
|
|
numItemsWithLargestWeight--;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
availableFreeSpace -= sizeDelta;
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->SetMainSize(item->GetMainSize() + sizeDelta);
|
2015-11-06 01:35:03 +03:00
|
|
|
|
MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
(" child %p receives %d, for a total of %d\n",
|
|
|
|
|
item, sizeDelta, item->GetMainSize()));
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fix min/max violations:
|
|
|
|
|
nscoord totalViolation = 0; // keeps track of adjustments for min/max
|
2015-11-06 01:35:03 +03:00
|
|
|
|
MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
(" Checking for violations:"));
|
|
|
|
|
|
2014-05-05 06:05:51 +04:00
|
|
|
|
// Since this loop only operates on unfrozen flex items, we can break as
|
|
|
|
|
// soon as we have seen all of them.
|
|
|
|
|
uint32_t numUnfrozenItemsToBeSeen = mNumItems - mNumFrozenItems;
|
|
|
|
|
for (FlexItem* item = mItems.getFirst();
|
|
|
|
|
numUnfrozenItemsToBeSeen > 0; item = item->getNext()) {
|
|
|
|
|
MOZ_ASSERT(item, "numUnfrozenItemsToBeSeen says items remain to be seen");
|
2014-03-18 05:23:23 +04:00
|
|
|
|
if (!item->IsFrozen()) {
|
2014-05-05 06:05:51 +04:00
|
|
|
|
numUnfrozenItemsToBeSeen--;
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
if (item->GetMainSize() < item->GetMainMinSize()) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// min violation
|
2014-03-18 05:23:23 +04:00
|
|
|
|
totalViolation += item->GetMainMinSize() - item->GetMainSize();
|
|
|
|
|
item->SetMainSize(item->GetMainMinSize());
|
|
|
|
|
item->SetHadMinViolation();
|
|
|
|
|
} else if (item->GetMainSize() > item->GetMainMaxSize()) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// max violation
|
2014-03-18 05:23:23 +04:00
|
|
|
|
totalViolation += item->GetMainMaxSize() - item->GetMainSize();
|
|
|
|
|
item->SetMainSize(item->GetMainMaxSize());
|
|
|
|
|
item->SetHadMaxViolation();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-18 02:09:40 +04:00
|
|
|
|
FreezeOrRestoreEachFlexibleSize(totalViolation,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
iterationCounter + 1 == mNumItems);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-11-06 01:35:03 +03:00
|
|
|
|
MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
(" Total violation: %d\n", totalViolation));
|
|
|
|
|
|
2014-05-05 06:05:51 +04:00
|
|
|
|
if (mNumFrozenItems == mNumItems) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
|
|
|
|
}
|
2014-05-05 06:05:51 +04:00
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(totalViolation != 0,
|
|
|
|
|
"Zero violation should've made us freeze all items & break");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2014-05-05 06:05:51 +04:00
|
|
|
|
// Post-condition: all items should've been frozen.
|
|
|
|
|
// Make sure the counts match:
|
|
|
|
|
MOZ_ASSERT(mNumFrozenItems == mNumItems, "All items should be frozen");
|
|
|
|
|
|
|
|
|
|
// For good measure, check each item directly, in case our counts are busted:
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (const FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
|
2014-05-05 06:05:51 +04:00
|
|
|
|
MOZ_ASSERT(item->IsFrozen(), "All items should be frozen");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MainAxisPositionTracker::
|
2013-11-26 22:27:52 +04:00
|
|
|
|
MainAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
const FlexLine* aLine,
|
2013-11-26 22:27:52 +04:00
|
|
|
|
uint8_t aJustifyContent,
|
2013-10-01 03:38:36 +04:00
|
|
|
|
nscoord aContentBoxMainSize)
|
2015-04-16 22:01:14 +03:00
|
|
|
|
: PositionTracker(aAxisTracker.GetMainAxis(),
|
|
|
|
|
aAxisTracker.IsMainAxisReversed()),
|
2013-10-01 03:38:36 +04:00
|
|
|
|
mPackingSpaceRemaining(aContentBoxMainSize), // we chip away at this below
|
2012-09-30 10:38:46 +04:00
|
|
|
|
mNumAutoMarginsInMainAxis(0),
|
2013-11-26 22:27:52 +04:00
|
|
|
|
mNumPackingSpacesRemaining(0),
|
|
|
|
|
mJustifyContent(aJustifyContent)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// 'auto' behaves as 'stretch' which behaves as 'flex-start' in the main axis
|
|
|
|
|
if (mJustifyContent == NS_STYLE_JUSTIFY_AUTO) {
|
|
|
|
|
mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX strip off the <overflow-position> bit until we implement that
|
|
|
|
|
mJustifyContent &= ~NS_STYLE_JUSTIFY_FLAG_BITS;
|
|
|
|
|
|
2013-10-01 03:38:36 +04:00
|
|
|
|
// mPackingSpaceRemaining is initialized to the container's main size. Now
|
|
|
|
|
// we'll subtract out the main sizes of our flex items, so that it ends up
|
|
|
|
|
// with the *actual* amount of packing space.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (const FlexItem* item = aLine->GetFirstItem(); item;
|
|
|
|
|
item = item->getNext()) {
|
2014-04-03 21:40:12 +04:00
|
|
|
|
mPackingSpaceRemaining -= item->GetOuterMainSize(mAxis);
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mNumAutoMarginsInMainAxis += item->GetNumAutoMarginsInAxis(mAxis);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-01 07:30:24 +04:00
|
|
|
|
if (mPackingSpaceRemaining <= 0) {
|
|
|
|
|
// No available packing space to use for resolving auto margins.
|
|
|
|
|
mNumAutoMarginsInMainAxis = 0;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-25 12:22:30 +04:00
|
|
|
|
// If packing space is negative, 'space-between' behaves like 'flex-start',
|
|
|
|
|
// and 'space-around' behaves like 'center'. In those cases, it's simplest to
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// just pretend we have a different 'justify-content' value and share code.
|
|
|
|
|
if (mPackingSpaceRemaining < 0) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (mJustifyContent == NS_STYLE_JUSTIFY_SPACE_BETWEEN) {
|
|
|
|
|
mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
|
|
|
|
|
} else if (mJustifyContent == NS_STYLE_JUSTIFY_SPACE_AROUND) {
|
|
|
|
|
mJustifyContent = NS_STYLE_JUSTIFY_CENTER;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// Map 'start'/'end' to 'flex-start'/'flex-end'.
|
|
|
|
|
if (mJustifyContent == NS_STYLE_JUSTIFY_START) {
|
|
|
|
|
mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
|
|
|
|
|
} else if (mJustifyContent == NS_STYLE_JUSTIFY_END) {
|
|
|
|
|
mJustifyContent = NS_STYLE_JUSTIFY_FLEX_END;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// If our main axis is (internally) reversed, swap the justify-content
|
|
|
|
|
// "flex-start" and "flex-end" behaviors:
|
|
|
|
|
if (aAxisTracker.AreAxesInternallyReversed()) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (mJustifyContent == NS_STYLE_JUSTIFY_FLEX_START) {
|
|
|
|
|
mJustifyContent = NS_STYLE_JUSTIFY_FLEX_END;
|
|
|
|
|
} else if (mJustifyContent == NS_STYLE_JUSTIFY_FLEX_END) {
|
|
|
|
|
mJustifyContent = NS_STYLE_JUSTIFY_FLEX_START;
|
2014-04-08 04:17:42 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Figure out how much space we'll set aside for auto margins or
|
|
|
|
|
// packing spaces, and advance past any leading packing-space.
|
|
|
|
|
if (mNumAutoMarginsInMainAxis == 0 &&
|
|
|
|
|
mPackingSpaceRemaining != 0 &&
|
2014-03-18 05:23:23 +04:00
|
|
|
|
!aLine->IsEmpty()) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
switch (mJustifyContent) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_LEFT:
|
|
|
|
|
case NS_STYLE_JUSTIFY_RIGHT:
|
|
|
|
|
case NS_STYLE_JUSTIFY_BASELINE:
|
|
|
|
|
case NS_STYLE_JUSTIFY_LAST_BASELINE:
|
|
|
|
|
case NS_STYLE_JUSTIFY_SPACE_EVENLY:
|
|
|
|
|
NS_WARNING("NYI: justify-content:left/right/baseline/last-baseline/space-evenly");
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_FLEX_START:
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// All packing space should go at the end --> nothing to do here.
|
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_FLEX_END:
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// All packing space goes at the beginning
|
|
|
|
|
mPosition += mPackingSpaceRemaining;
|
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_CENTER:
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Half the packing space goes at the beginning
|
|
|
|
|
mPosition += mPackingSpaceRemaining / 2;
|
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_SPACE_BETWEEN:
|
2012-09-30 10:38:46 +04:00
|
|
|
|
MOZ_ASSERT(mPackingSpaceRemaining >= 0,
|
|
|
|
|
"negative packing space should make us use 'flex-start' "
|
|
|
|
|
"instead of 'space-between'");
|
|
|
|
|
// 1 packing space between each flex item, no packing space at ends.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mNumPackingSpacesRemaining = aLine->NumItems() - 1;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_SPACE_AROUND:
|
2012-09-30 10:38:46 +04:00
|
|
|
|
MOZ_ASSERT(mPackingSpaceRemaining >= 0,
|
|
|
|
|
"negative packing space should make us use 'center' "
|
|
|
|
|
"instead of 'space-around'");
|
|
|
|
|
// 1 packing space between each flex item, plus half a packing space
|
|
|
|
|
// at beginning & end. So our number of full packing-spaces is equal
|
|
|
|
|
// to the number of flex items.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mNumPackingSpacesRemaining = aLine->NumItems();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
if (mNumPackingSpacesRemaining > 0) {
|
|
|
|
|
// The edges (start/end) share one full packing space
|
|
|
|
|
nscoord totalEdgePackingSpace =
|
|
|
|
|
mPackingSpaceRemaining / mNumPackingSpacesRemaining;
|
|
|
|
|
|
|
|
|
|
// ...and we'll use half of that right now, at the start
|
|
|
|
|
mPosition += totalEdgePackingSpace / 2;
|
|
|
|
|
// ...but we need to subtract all of it right away, so that we won't
|
|
|
|
|
// hand out any of it to intermediate packing spaces.
|
|
|
|
|
mPackingSpaceRemaining -= totalEdgePackingSpace;
|
|
|
|
|
mNumPackingSpacesRemaining--;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2013-06-29 05:38:30 +04:00
|
|
|
|
MOZ_CRASH("Unexpected justify-content value");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(mNumPackingSpacesRemaining == 0 ||
|
|
|
|
|
mNumAutoMarginsInMainAxis == 0,
|
|
|
|
|
"extra space should either go to packing space or to "
|
|
|
|
|
"auto margins, but not to both");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MainAxisPositionTracker::ResolveAutoMarginsInMainAxis(FlexItem& aItem)
|
|
|
|
|
{
|
|
|
|
|
if (mNumAutoMarginsInMainAxis) {
|
2013-02-17 01:51:02 +04:00
|
|
|
|
const nsStyleSides& styleMargin = aItem.Frame()->StyleMargin()->mMargin;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
for (uint32_t i = 0; i < eNumAxisEdges; i++) {
|
2014-06-28 14:13:13 +04:00
|
|
|
|
mozilla::Side side = kAxisOrientationToSidesMap[mAxis][i];
|
2012-09-30 10:38:46 +04:00
|
|
|
|
if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
|
|
|
|
|
// NOTE: This integer math will skew the distribution of remainder
|
|
|
|
|
// app-units towards the end, which is fine.
|
|
|
|
|
nscoord curAutoMarginSize =
|
|
|
|
|
mPackingSpaceRemaining / mNumAutoMarginsInMainAxis;
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(aItem.GetMarginComponentForSide(side) == 0,
|
|
|
|
|
"Expecting auto margins to have value '0' before we "
|
|
|
|
|
"resolve them");
|
|
|
|
|
aItem.SetMarginComponentForSide(side, curAutoMarginSize);
|
|
|
|
|
|
|
|
|
|
mNumAutoMarginsInMainAxis--;
|
|
|
|
|
mPackingSpaceRemaining -= curAutoMarginSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
MainAxisPositionTracker::TraversePackingSpace()
|
|
|
|
|
{
|
|
|
|
|
if (mNumPackingSpacesRemaining) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
MOZ_ASSERT(mJustifyContent == NS_STYLE_JUSTIFY_SPACE_BETWEEN ||
|
|
|
|
|
mJustifyContent == NS_STYLE_JUSTIFY_SPACE_AROUND,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
"mNumPackingSpacesRemaining only applies for "
|
|
|
|
|
"space-between/space-around");
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(mPackingSpaceRemaining >= 0,
|
|
|
|
|
"ran out of packing space earlier than we expected");
|
|
|
|
|
|
|
|
|
|
// NOTE: This integer math will skew the distribution of remainder
|
|
|
|
|
// app-units towards the end, which is fine.
|
|
|
|
|
nscoord curPackingSpace =
|
|
|
|
|
mPackingSpaceRemaining / mNumPackingSpacesRemaining;
|
|
|
|
|
|
|
|
|
|
mPosition += curPackingSpace;
|
|
|
|
|
mNumPackingSpacesRemaining--;
|
|
|
|
|
mPackingSpaceRemaining -= curPackingSpace;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
CrossAxisPositionTracker::
|
2014-03-18 05:23:23 +04:00
|
|
|
|
CrossAxisPositionTracker(FlexLine* aFirstLine,
|
2013-12-05 22:57:51 +04:00
|
|
|
|
uint8_t aAlignContent,
|
|
|
|
|
nscoord aContentBoxCrossSize,
|
|
|
|
|
bool aIsCrossSizeDefinite,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2015-04-16 22:01:14 +03:00
|
|
|
|
: PositionTracker(aAxisTracker.GetCrossAxis(),
|
|
|
|
|
aAxisTracker.IsCrossAxisReversed()),
|
2013-12-05 22:57:51 +04:00
|
|
|
|
mPackingSpaceRemaining(0),
|
|
|
|
|
mNumPackingSpacesRemaining(0),
|
|
|
|
|
mAlignContent(aAlignContent)
|
|
|
|
|
{
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(aFirstLine, "null first line pointer");
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// 'auto' behaves as 'stretch'
|
|
|
|
|
if (mAlignContent == NS_STYLE_ALIGN_AUTO) {
|
|
|
|
|
mAlignContent = NS_STYLE_ALIGN_STRETCH;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXX strip of the <overflow-position> bit until we implement that
|
|
|
|
|
mAlignContent &= ~NS_STYLE_ALIGN_FLAG_BITS;
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
if (aIsCrossSizeDefinite && !aFirstLine->getNext()) {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// "If the flex container has only a single line (even if it's a
|
|
|
|
|
// multi-line flex container) and has a definite cross size, the cross
|
|
|
|
|
// size of the flex line is the flex container's inner cross size."
|
|
|
|
|
// SOURCE: http://dev.w3.org/csswg/css-flexbox/#algo-line-break
|
|
|
|
|
// NOTE: This means (by definition) that there's no packing space, which
|
|
|
|
|
// means we don't need to be concerned with "align-conent" at all and we
|
|
|
|
|
// can return early. This is handy, because this is the usual case (for
|
|
|
|
|
// single-line flexbox).
|
2014-03-18 05:23:23 +04:00
|
|
|
|
aFirstLine->SetLineCrossSize(aContentBoxCrossSize);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NOTE: The rest of this function should essentially match
|
|
|
|
|
// MainAxisPositionTracker's constructor, though with FlexLines instead of
|
|
|
|
|
// FlexItems, and with the additional value "stretch" (and of course with
|
|
|
|
|
// cross sizes instead of main sizes.)
|
|
|
|
|
|
|
|
|
|
// Figure out how much packing space we have (container's cross size minus
|
2014-03-18 05:23:23 +04:00
|
|
|
|
// all the lines' cross sizes). Also, share this loop to count how many
|
|
|
|
|
// lines we have. (We need that count in some cases below.)
|
2013-12-05 22:57:51 +04:00
|
|
|
|
mPackingSpaceRemaining = aContentBoxCrossSize;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
uint32_t numLines = 0;
|
|
|
|
|
for (FlexLine* line = aFirstLine; line; line = line->getNext()) {
|
|
|
|
|
mPackingSpaceRemaining -= line->GetLineCrossSize();
|
|
|
|
|
numLines++;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If packing space is negative, 'space-between' and 'stretch' behave like
|
|
|
|
|
// 'flex-start', and 'space-around' behaves like 'center'. In those cases,
|
|
|
|
|
// it's simplest to just pretend we have a different 'align-content' value
|
|
|
|
|
// and share code.
|
|
|
|
|
if (mPackingSpaceRemaining < 0) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (mAlignContent == NS_STYLE_ALIGN_SPACE_BETWEEN ||
|
|
|
|
|
mAlignContent == NS_STYLE_ALIGN_STRETCH) {
|
|
|
|
|
mAlignContent = NS_STYLE_ALIGN_FLEX_START;
|
|
|
|
|
} else if (mAlignContent == NS_STYLE_ALIGN_SPACE_AROUND) {
|
|
|
|
|
mAlignContent = NS_STYLE_ALIGN_CENTER;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// Map 'start'/'end' to 'flex-start'/'flex-end'.
|
|
|
|
|
if (mAlignContent == NS_STYLE_ALIGN_START) {
|
|
|
|
|
mAlignContent = NS_STYLE_ALIGN_FLEX_START;
|
|
|
|
|
} else if (mAlignContent == NS_STYLE_ALIGN_END) {
|
|
|
|
|
mAlignContent = NS_STYLE_ALIGN_FLEX_END;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// If our cross axis is (internally) reversed, swap the align-content
|
|
|
|
|
// "flex-start" and "flex-end" behaviors:
|
|
|
|
|
if (aAxisTracker.AreAxesInternallyReversed()) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (mAlignContent == NS_STYLE_ALIGN_FLEX_START) {
|
|
|
|
|
mAlignContent = NS_STYLE_ALIGN_FLEX_END;
|
|
|
|
|
} else if (mAlignContent == NS_STYLE_ALIGN_FLEX_END) {
|
|
|
|
|
mAlignContent = NS_STYLE_ALIGN_FLEX_START;
|
2014-04-08 04:17:42 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Figure out how much space we'll set aside for packing spaces, and advance
|
|
|
|
|
// past any leading packing-space.
|
|
|
|
|
if (mPackingSpaceRemaining != 0) {
|
|
|
|
|
switch (mAlignContent) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_LEFT:
|
|
|
|
|
case NS_STYLE_JUSTIFY_RIGHT:
|
|
|
|
|
case NS_STYLE_ALIGN_SELF_START:
|
|
|
|
|
case NS_STYLE_ALIGN_SELF_END:
|
|
|
|
|
case NS_STYLE_ALIGN_SPACE_EVENLY:
|
|
|
|
|
case NS_STYLE_ALIGN_BASELINE:
|
|
|
|
|
case NS_STYLE_ALIGN_LAST_BASELINE:
|
|
|
|
|
NS_WARNING("NYI: align-self:left/right/self-start/self-end/space-evenly/baseline/last-baseline");
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_FLEX_START:
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// All packing space should go at the end --> nothing to do here.
|
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_FLEX_END:
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// All packing space goes at the beginning
|
|
|
|
|
mPosition += mPackingSpaceRemaining;
|
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_CENTER:
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Half the packing space goes at the beginning
|
|
|
|
|
mPosition += mPackingSpaceRemaining / 2;
|
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_SPACE_BETWEEN:
|
2013-12-05 22:57:51 +04:00
|
|
|
|
MOZ_ASSERT(mPackingSpaceRemaining >= 0,
|
|
|
|
|
"negative packing space should make us use 'flex-start' "
|
|
|
|
|
"instead of 'space-between'");
|
|
|
|
|
// 1 packing space between each flex line, no packing space at ends.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mNumPackingSpacesRemaining = numLines - 1;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_SPACE_AROUND: {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
MOZ_ASSERT(mPackingSpaceRemaining >= 0,
|
|
|
|
|
"negative packing space should make us use 'center' "
|
|
|
|
|
"instead of 'space-around'");
|
|
|
|
|
// 1 packing space between each flex line, plus half a packing space
|
|
|
|
|
// at beginning & end. So our number of full packing-spaces is equal
|
|
|
|
|
// to the number of flex lines.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mNumPackingSpacesRemaining = numLines;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// The edges (start/end) share one full packing space
|
|
|
|
|
nscoord totalEdgePackingSpace =
|
|
|
|
|
mPackingSpaceRemaining / mNumPackingSpacesRemaining;
|
|
|
|
|
|
|
|
|
|
// ...and we'll use half of that right now, at the start
|
|
|
|
|
mPosition += totalEdgePackingSpace / 2;
|
|
|
|
|
// ...but we need to subtract all of it right away, so that we won't
|
|
|
|
|
// hand out any of it to intermediate packing spaces.
|
|
|
|
|
mPackingSpaceRemaining -= totalEdgePackingSpace;
|
|
|
|
|
mNumPackingSpacesRemaining--;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_STRETCH: {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Split space equally between the lines:
|
|
|
|
|
MOZ_ASSERT(mPackingSpaceRemaining > 0,
|
|
|
|
|
"negative packing space should make us use 'flex-start' "
|
|
|
|
|
"instead of 'stretch' (and we shouldn't bother with this "
|
|
|
|
|
"code if we have 0 packing space)");
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
uint32_t numLinesLeft = numLines;
|
|
|
|
|
for (FlexLine* line = aFirstLine; line; line = line->getNext()) {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Our share is the amount of space remaining, divided by the number
|
2014-02-27 11:28:38 +04:00
|
|
|
|
// of lines remainig.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(numLinesLeft > 0, "miscalculated num lines");
|
|
|
|
|
nscoord shareOfExtraSpace = mPackingSpaceRemaining / numLinesLeft;
|
|
|
|
|
nscoord newSize = line->GetLineCrossSize() + shareOfExtraSpace;
|
|
|
|
|
line->SetLineCrossSize(newSize);
|
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
mPackingSpaceRemaining -= shareOfExtraSpace;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
numLinesLeft--;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(numLinesLeft == 0, "miscalculated num lines");
|
2013-12-05 22:57:51 +04:00
|
|
|
|
break;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
}
|
2013-12-05 22:57:51 +04:00
|
|
|
|
default:
|
|
|
|
|
MOZ_CRASH("Unexpected align-content value");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
CrossAxisPositionTracker::TraversePackingSpace()
|
|
|
|
|
{
|
|
|
|
|
if (mNumPackingSpacesRemaining) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
MOZ_ASSERT(mAlignContent == NS_STYLE_ALIGN_SPACE_BETWEEN ||
|
|
|
|
|
mAlignContent == NS_STYLE_ALIGN_SPACE_AROUND,
|
2013-12-05 22:57:51 +04:00
|
|
|
|
"mNumPackingSpacesRemaining only applies for "
|
|
|
|
|
"space-between/space-around");
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(mPackingSpaceRemaining >= 0,
|
|
|
|
|
"ran out of packing space earlier than we expected");
|
|
|
|
|
|
|
|
|
|
// NOTE: This integer math will skew the distribution of remainder
|
|
|
|
|
// app-units towards the end, which is fine.
|
|
|
|
|
nscoord curPackingSpace =
|
|
|
|
|
mPackingSpaceRemaining / mNumPackingSpacesRemaining;
|
|
|
|
|
|
|
|
|
|
mPosition += curPackingSpace;
|
|
|
|
|
mNumPackingSpacesRemaining--;
|
|
|
|
|
mPackingSpaceRemaining -= curPackingSpace;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
SingleLineCrossAxisPositionTracker::
|
2013-11-23 23:07:33 +04:00
|
|
|
|
SingleLineCrossAxisPositionTracker(const FlexboxAxisTracker& aAxisTracker)
|
2015-04-16 22:01:14 +03:00
|
|
|
|
: PositionTracker(aAxisTracker.GetCrossAxis(),
|
|
|
|
|
aAxisTracker.IsCrossAxisReversed())
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2013-11-26 22:27:51 +04:00
|
|
|
|
FlexLine::ComputeCrossSizeAndBaseline(const FlexboxAxisTracker& aAxisTracker)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2014-02-27 11:28:38 +04:00
|
|
|
|
nscoord crossStartToFurthestBaseline = nscoord_MIN;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord crossEndToFurthestBaseline = nscoord_MIN;
|
|
|
|
|
nscoord largestOuterCrossSize = 0;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (const FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
|
2014-04-03 21:40:12 +04:00
|
|
|
|
nscoord curOuterCrossSize =
|
|
|
|
|
item->GetOuterCrossSize(aAxisTracker.GetCrossAxis());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (item->GetAlignSelf() == NS_STYLE_ALIGN_BASELINE &&
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->GetNumAutoMarginsInAxis(aAxisTracker.GetCrossAxis()) == 0) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// FIXME: Once we support "writing-mode", we'll have to do baseline
|
|
|
|
|
// alignment in vertical flex containers here (w/ horizontal cross-axes).
|
|
|
|
|
|
|
|
|
|
// Find distance from our item's cross-start and cross-end margin-box
|
|
|
|
|
// edges to its baseline.
|
|
|
|
|
//
|
|
|
|
|
// Here's a diagram of a flex-item that we might be doing this on.
|
|
|
|
|
// "mmm" is the margin-box, "bbb" is the border-box. The bottom of
|
|
|
|
|
// the text "BASE" is the baseline.
|
|
|
|
|
//
|
|
|
|
|
// ---(cross-start)---
|
|
|
|
|
// ___ ___ ___
|
|
|
|
|
// mmmmmmmmmmmm | |margin-start |
|
|
|
|
|
// m m | _|_ ___ |
|
|
|
|
|
// m bbbbbbbb m |curOuterCrossSize | |crossStartToBaseline
|
|
|
|
|
// m b b m | |ascent |
|
|
|
|
|
// m b BASE b m | _|_ _|_
|
|
|
|
|
// m b b m | |
|
|
|
|
|
// m bbbbbbbb m | |crossEndToBaseline
|
|
|
|
|
// m m | |
|
|
|
|
|
// mmmmmmmmmmmm _|_ _|_
|
|
|
|
|
//
|
|
|
|
|
// ---(cross-end)---
|
|
|
|
|
//
|
|
|
|
|
// We already have the curOuterCrossSize, margin-start, and the ascent.
|
|
|
|
|
// * We can get crossStartToBaseline by adding margin-start + ascent.
|
|
|
|
|
// * If we subtract that from the curOuterCrossSize, we get
|
|
|
|
|
// crossEndToBaseline.
|
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
nscoord crossStartToBaseline =
|
2015-03-27 22:06:03 +03:00
|
|
|
|
item->GetBaselineOffsetFromOuterCrossEdge(eAxisEdge_Start,
|
|
|
|
|
aAxisTracker);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord crossEndToBaseline = curOuterCrossSize - crossStartToBaseline;
|
|
|
|
|
|
|
|
|
|
// Now, update our "largest" values for these (across all the flex items
|
2013-11-26 22:27:51 +04:00
|
|
|
|
// in this flex line), so we can use them in computing the line's cross
|
|
|
|
|
// size below:
|
|
|
|
|
crossStartToFurthestBaseline = std::max(crossStartToFurthestBaseline,
|
|
|
|
|
crossStartToBaseline);
|
2013-01-15 16:22:03 +04:00
|
|
|
|
crossEndToFurthestBaseline = std::max(crossEndToFurthestBaseline,
|
2013-03-22 23:13:51 +04:00
|
|
|
|
crossEndToBaseline);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
} else {
|
2013-01-15 16:22:03 +04:00
|
|
|
|
largestOuterCrossSize = std::max(largestOuterCrossSize, curOuterCrossSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:43 +04:00
|
|
|
|
// The line's baseline offset is the distance from the line's edge (start or
|
|
|
|
|
// end, depending on whether we've flipped the axes) to the furthest
|
|
|
|
|
// item-baseline. The item(s) with that baseline will be exactly aligned with
|
|
|
|
|
// the line's edge.
|
|
|
|
|
mBaselineOffset = aAxisTracker.AreAxesInternallyReversed() ?
|
|
|
|
|
crossEndToFurthestBaseline : crossStartToFurthestBaseline;
|
2013-11-26 22:27:51 +04:00
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// The line's cross-size is the larger of:
|
|
|
|
|
// (a) [largest cross-start-to-baseline + largest baseline-to-cross-end] of
|
|
|
|
|
// all baseline-aligned items with no cross-axis auto margins...
|
|
|
|
|
// and
|
|
|
|
|
// (b) largest cross-size of all other children.
|
2013-11-26 22:27:51 +04:00
|
|
|
|
mLineCrossSize = std::max(crossStartToFurthestBaseline +
|
2013-03-22 23:13:51 +04:00
|
|
|
|
crossEndToFurthestBaseline,
|
|
|
|
|
largestOuterCrossSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2013-11-01 06:39:02 +04:00
|
|
|
|
FlexItem::ResolveStretchedCrossSize(nscoord aLineCrossSize,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2013-11-01 06:39:02 +04:00
|
|
|
|
AxisOrientationType crossAxis = aAxisTracker.GetCrossAxis();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// We stretch IFF we are align-self:stretch, have no auto margins in
|
|
|
|
|
// cross axis, and have cross-axis size property == "auto". If any of those
|
2013-11-01 06:39:02 +04:00
|
|
|
|
// conditions don't hold up, we won't stretch.
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (mAlignSelf != NS_STYLE_ALIGN_STRETCH ||
|
2013-11-01 06:39:02 +04:00
|
|
|
|
GetNumAutoMarginsInAxis(crossAxis) != 0 ||
|
2015-03-27 22:06:03 +03:00
|
|
|
|
eStyleUnit_Auto != aAxisTracker.ComputedCrossSize(mFrame).GetUnit()) {
|
2013-11-01 06:39:02 +04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we've already been stretched, we can bail out early, too.
|
|
|
|
|
// No need to redo the calculation.
|
|
|
|
|
if (mIsStretched) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reserve space for margins & border & padding, and then use whatever
|
|
|
|
|
// remains as our item's cross-size (clamped to its min/max range).
|
2013-11-01 06:39:02 +04:00
|
|
|
|
nscoord stretchedSize = aLineCrossSize -
|
|
|
|
|
GetMarginBorderPaddingSizeInAxis(crossAxis);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-11-01 06:39:02 +04:00
|
|
|
|
stretchedSize = NS_CSS_MINMAX(stretchedSize, mCrossMinSize, mCrossMaxSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Update the cross-size & make a note that it's stretched, so we know to
|
|
|
|
|
// override the reflow state's computed cross-size in our final reflow.
|
2013-11-01 06:39:02 +04:00
|
|
|
|
SetCrossSize(stretchedSize);
|
|
|
|
|
mIsStretched = true;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SingleLineCrossAxisPositionTracker::
|
2013-11-26 22:27:51 +04:00
|
|
|
|
ResolveAutoMarginsInCrossAxis(const FlexLine& aLine,
|
|
|
|
|
FlexItem& aItem)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
|
|
|
|
// Subtract the space that our item is already occupying, to see how much
|
|
|
|
|
// space (if any) is available for its auto margins.
|
2013-11-26 22:27:51 +04:00
|
|
|
|
nscoord spaceForAutoMargins = aLine.GetLineCrossSize() -
|
2014-04-03 21:40:12 +04:00
|
|
|
|
aItem.GetOuterCrossSize(mAxis);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
if (spaceForAutoMargins <= 0) {
|
|
|
|
|
return; // No available space --> nothing to do
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t numAutoMargins = aItem.GetNumAutoMarginsInAxis(mAxis);
|
|
|
|
|
if (numAutoMargins == 0) {
|
|
|
|
|
return; // No auto margins --> nothing to do.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OK, we have at least one auto margin and we have some available space.
|
|
|
|
|
// Give each auto margin a share of the space.
|
2013-02-17 01:51:02 +04:00
|
|
|
|
const nsStyleSides& styleMargin = aItem.Frame()->StyleMargin()->mMargin;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
for (uint32_t i = 0; i < eNumAxisEdges; i++) {
|
2014-06-28 14:13:13 +04:00
|
|
|
|
mozilla::Side side = kAxisOrientationToSidesMap[mAxis][i];
|
2012-09-30 10:38:46 +04:00
|
|
|
|
if (styleMargin.GetUnit(side) == eStyleUnit_Auto) {
|
|
|
|
|
MOZ_ASSERT(aItem.GetMarginComponentForSide(side) == 0,
|
|
|
|
|
"Expecting auto margins to have value '0' before we "
|
|
|
|
|
"update them");
|
|
|
|
|
|
|
|
|
|
// NOTE: integer divison is fine here; numAutoMargins is either 1 or 2.
|
|
|
|
|
// If it's 2 & spaceForAutoMargins is odd, 1st margin gets smaller half.
|
|
|
|
|
nscoord curAutoMarginSize = spaceForAutoMargins / numAutoMargins;
|
|
|
|
|
aItem.SetMarginComponentForSide(side, curAutoMarginSize);
|
|
|
|
|
numAutoMargins--;
|
|
|
|
|
spaceForAutoMargins -= curAutoMarginSize;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
SingleLineCrossAxisPositionTracker::
|
2013-11-26 22:27:51 +04:00
|
|
|
|
EnterAlignPackingSpace(const FlexLine& aLine,
|
2014-04-08 04:17:42 +04:00
|
|
|
|
const FlexItem& aItem,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
|
|
|
|
// We don't do align-self alignment on items that have auto margins
|
|
|
|
|
// in the cross axis.
|
|
|
|
|
if (aItem.GetNumAutoMarginsInAxis(mAxis)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
uint8_t alignSelf = aItem.GetAlignSelf();
|
|
|
|
|
// NOTE: 'stretch' behaves like 'flex-start' once we've stretched any
|
|
|
|
|
// auto-sized items (which we've already done).
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (alignSelf == NS_STYLE_ALIGN_STRETCH) {
|
|
|
|
|
alignSelf = NS_STYLE_ALIGN_FLEX_START;
|
2014-04-08 04:17:42 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
// Map 'start'/'end' to 'flex-start'/'flex-end'.
|
|
|
|
|
if (alignSelf == NS_STYLE_ALIGN_START) {
|
|
|
|
|
alignSelf = NS_STYLE_ALIGN_FLEX_START;
|
|
|
|
|
} else if (alignSelf == NS_STYLE_ALIGN_END) {
|
|
|
|
|
alignSelf = NS_STYLE_ALIGN_FLEX_END;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// If our cross axis is (internally) reversed, swap the align-self
|
|
|
|
|
// "flex-start" and "flex-end" behaviors:
|
|
|
|
|
if (aAxisTracker.AreAxesInternallyReversed()) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (alignSelf == NS_STYLE_ALIGN_FLEX_START) {
|
|
|
|
|
alignSelf = NS_STYLE_ALIGN_FLEX_END;
|
|
|
|
|
} else if (alignSelf == NS_STYLE_ALIGN_FLEX_END) {
|
|
|
|
|
alignSelf = NS_STYLE_ALIGN_FLEX_START;
|
2014-04-08 04:17:42 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (alignSelf) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_JUSTIFY_LEFT:
|
|
|
|
|
case NS_STYLE_JUSTIFY_RIGHT:
|
|
|
|
|
case NS_STYLE_ALIGN_SELF_START:
|
|
|
|
|
case NS_STYLE_ALIGN_SELF_END:
|
|
|
|
|
case NS_STYLE_ALIGN_LAST_BASELINE:
|
|
|
|
|
NS_WARNING("NYI: align-self:left/right/self-start/self-end/last-baseline");
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_FLEX_START:
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// No space to skip over -- we're done.
|
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_FLEX_END:
|
2014-04-03 21:40:12 +04:00
|
|
|
|
mPosition += aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_CENTER:
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// Note: If cross-size is odd, the "after" space will get the extra unit.
|
|
|
|
|
mPosition +=
|
2014-04-03 21:40:12 +04:00
|
|
|
|
(aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis)) / 2;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
2015-11-03 17:18:06 +03:00
|
|
|
|
case NS_STYLE_ALIGN_BASELINE: {
|
2014-04-08 04:17:43 +04:00
|
|
|
|
// Normally, baseline-aligned items are collectively aligned with the
|
|
|
|
|
// line's cross-start edge; however, if our cross axis is (internally)
|
|
|
|
|
// reversed, we instead align them with the cross-end edge.
|
2015-03-27 22:06:03 +03:00
|
|
|
|
AxisEdgeType baselineAlignEdge =
|
|
|
|
|
aAxisTracker.AreAxesInternallyReversed() ?
|
|
|
|
|
eAxisEdge_End : eAxisEdge_Start;
|
|
|
|
|
|
2013-11-26 22:27:51 +04:00
|
|
|
|
nscoord itemBaselineOffset =
|
2015-03-27 22:06:03 +03:00
|
|
|
|
aItem.GetBaselineOffsetFromOuterCrossEdge(baselineAlignEdge,
|
|
|
|
|
aAxisTracker);
|
2014-04-08 04:17:43 +04:00
|
|
|
|
|
|
|
|
|
nscoord lineBaselineOffset = aLine.GetBaselineOffset();
|
|
|
|
|
|
|
|
|
|
NS_ASSERTION(lineBaselineOffset >= itemBaselineOffset,
|
|
|
|
|
"failed at finding largest baseline offset");
|
|
|
|
|
|
|
|
|
|
// How much do we need to adjust our position (from the line edge),
|
|
|
|
|
// to get the item's baseline to hit the line's baseline offset:
|
|
|
|
|
nscoord baselineDiff = lineBaselineOffset - itemBaselineOffset;
|
|
|
|
|
|
|
|
|
|
if (aAxisTracker.AreAxesInternallyReversed()) {
|
|
|
|
|
// Advance to align item w/ line's flex-end edge (as in FLEX_END case):
|
|
|
|
|
mPosition += aLine.GetLineCrossSize() - aItem.GetOuterCrossSize(mAxis);
|
|
|
|
|
// ...and step *back* by the baseline adjustment:
|
|
|
|
|
mPosition -= baselineDiff;
|
|
|
|
|
} else {
|
|
|
|
|
// mPosition is already at line's flex-start edge.
|
|
|
|
|
// From there, we step *forward* by the baseline adjustment:
|
|
|
|
|
mPosition += baselineDiff;
|
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
2013-11-26 22:27:51 +04:00
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
default:
|
|
|
|
|
NS_NOTREACHED("Unexpected align-self value");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-27 22:06:03 +03:00
|
|
|
|
// Utility function to convert an InlineDir to an AxisOrientationType
|
|
|
|
|
static inline AxisOrientationType
|
|
|
|
|
InlineDirToAxisOrientation(WritingMode::InlineDir aInlineDir)
|
|
|
|
|
{
|
|
|
|
|
switch (aInlineDir) {
|
|
|
|
|
case WritingMode::eInlineLTR:
|
|
|
|
|
return eAxis_LR;
|
|
|
|
|
case WritingMode::eInlineRTL:
|
|
|
|
|
return eAxis_RL;
|
|
|
|
|
case WritingMode::eInlineTTB:
|
|
|
|
|
return eAxis_TB;
|
|
|
|
|
case WritingMode::eInlineBTT:
|
|
|
|
|
return eAxis_BT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Unhandled InlineDir");
|
|
|
|
|
return eAxis_LR; // in case of unforseen error, assume English LTR text flow.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Utility function to convert a BlockDir to an AxisOrientationType
|
|
|
|
|
static inline AxisOrientationType
|
|
|
|
|
BlockDirToAxisOrientation(WritingMode::BlockDir aBlockDir)
|
|
|
|
|
{
|
|
|
|
|
switch (aBlockDir) {
|
|
|
|
|
case WritingMode::eBlockLR:
|
|
|
|
|
return eAxis_LR;
|
|
|
|
|
case WritingMode::eBlockRL:
|
|
|
|
|
return eAxis_RL;
|
|
|
|
|
case WritingMode::eBlockTB:
|
|
|
|
|
return eAxis_TB;
|
|
|
|
|
// NOTE: WritingMode::eBlockBT (bottom-to-top) does not exist.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Unhandled BlockDir");
|
|
|
|
|
return eAxis_TB; // in case of unforseen error, assume English TTB block-flow
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FlexboxAxisTracker::FlexboxAxisTracker(const nsStylePosition* aStylePosition,
|
|
|
|
|
const WritingMode& aWM)
|
2015-04-10 23:35:15 +03:00
|
|
|
|
: mWM(aWM),
|
|
|
|
|
mAreAxesInternallyReversed(false)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2015-03-27 22:06:03 +03:00
|
|
|
|
uint32_t flexDirection = aStylePosition->mFlexDirection;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Inline dimension ("start-to-end"):
|
2015-03-27 22:06:03 +03:00
|
|
|
|
// (NOTE: I'm intentionally not calling these "inlineAxis"/"blockAxis", since
|
|
|
|
|
// those terms have explicit definition in the writing-modes spec, which are
|
|
|
|
|
// the opposite of how I'd be using them here.)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
AxisOrientationType inlineDimension =
|
2015-04-10 23:35:15 +03:00
|
|
|
|
InlineDirToAxisOrientation(mWM.GetInlineDir());
|
2015-03-27 22:06:03 +03:00
|
|
|
|
AxisOrientationType blockDimension =
|
2015-04-10 23:35:15 +03:00
|
|
|
|
BlockDirToAxisOrientation(mWM.GetBlockDir());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Determine main axis:
|
|
|
|
|
switch (flexDirection) {
|
|
|
|
|
case NS_STYLE_FLEX_DIRECTION_ROW:
|
|
|
|
|
mMainAxis = inlineDimension;
|
2015-04-10 23:35:15 +03:00
|
|
|
|
mIsRowOriented = true;
|
|
|
|
|
mIsMainAxisReversed = false;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
|
|
|
|
case NS_STYLE_FLEX_DIRECTION_ROW_REVERSE:
|
|
|
|
|
mMainAxis = GetReverseAxis(inlineDimension);
|
2015-04-10 23:35:15 +03:00
|
|
|
|
mIsRowOriented = true;
|
|
|
|
|
mIsMainAxisReversed = true;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
|
|
|
|
case NS_STYLE_FLEX_DIRECTION_COLUMN:
|
|
|
|
|
mMainAxis = blockDimension;
|
2015-04-10 23:35:15 +03:00
|
|
|
|
mIsRowOriented = false;
|
|
|
|
|
mIsMainAxisReversed = false;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
|
|
|
|
case NS_STYLE_FLEX_DIRECTION_COLUMN_REVERSE:
|
|
|
|
|
mMainAxis = GetReverseAxis(blockDimension);
|
2015-04-10 23:35:15 +03:00
|
|
|
|
mIsRowOriented = false;
|
|
|
|
|
mIsMainAxisReversed = true;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2013-06-29 05:38:30 +04:00
|
|
|
|
MOZ_CRASH("Unexpected computed value for 'flex-flow' property");
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine cross axis:
|
|
|
|
|
// (This is set up so that a bogus |flexDirection| value will
|
|
|
|
|
// give us blockDimension.
|
|
|
|
|
if (flexDirection == NS_STYLE_FLEX_DIRECTION_COLUMN ||
|
|
|
|
|
flexDirection == NS_STYLE_FLEX_DIRECTION_COLUMN_REVERSE) {
|
|
|
|
|
mCrossAxis = inlineDimension;
|
|
|
|
|
} else {
|
|
|
|
|
mCrossAxis = blockDimension;
|
|
|
|
|
}
|
2013-11-13 06:50:39 +04:00
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// "flex-wrap: wrap-reverse" reverses our cross axis.
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aStylePosition->mFlexWrap == NS_STYLE_FLEX_WRAP_WRAP_REVERSE) {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
mCrossAxis = GetReverseAxis(mCrossAxis);
|
2015-04-10 23:35:15 +03:00
|
|
|
|
mIsCrossAxisReversed = true;
|
|
|
|
|
} else {
|
|
|
|
|
mIsCrossAxisReversed = false;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// Master switch to enable/disable bug 983427's code for reversing our axes
|
|
|
|
|
// and reversing some logic, to avoid reflowing children in bottom-to-top
|
|
|
|
|
// order. (This switch can be removed eventually, but for now, it allows
|
|
|
|
|
// this special-case code path to be compared against the normal code path.)
|
2014-04-12 01:22:12 +04:00
|
|
|
|
static bool sPreventBottomToTopChildOrdering = true;
|
2014-04-08 04:17:42 +04:00
|
|
|
|
|
|
|
|
|
if (sPreventBottomToTopChildOrdering) {
|
|
|
|
|
// If either axis is bottom-to-top, we flip both axes (and set a flag
|
|
|
|
|
// so that we can flip some logic to make the reversal transparent).
|
|
|
|
|
if (eAxis_BT == mMainAxis || eAxis_BT == mCrossAxis) {
|
|
|
|
|
mMainAxis = GetReverseAxis(mMainAxis);
|
|
|
|
|
mCrossAxis = GetReverseAxis(mCrossAxis);
|
|
|
|
|
mAreAxesInternallyReversed = true;
|
2015-04-10 23:35:15 +03:00
|
|
|
|
mIsMainAxisReversed = !mIsMainAxisReversed;
|
|
|
|
|
mIsCrossAxisReversed = !mIsCrossAxisReversed;
|
2014-04-08 04:17:42 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// Allocates a new FlexLine, adds it to the given LinkedList (at the front or
|
|
|
|
|
// back depending on aShouldInsertAtFront), and returns a pointer to it.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
static FlexLine*
|
2014-04-08 04:17:42 +04:00
|
|
|
|
AddNewFlexLineToList(LinkedList<FlexLine>& aLines,
|
|
|
|
|
bool aShouldInsertAtFront)
|
2014-03-18 05:23:23 +04:00
|
|
|
|
{
|
|
|
|
|
FlexLine* newLine = new FlexLine();
|
2014-04-08 04:17:42 +04:00
|
|
|
|
if (aShouldInsertAtFront) {
|
|
|
|
|
aLines.insertFront(newLine);
|
|
|
|
|
} else {
|
|
|
|
|
aLines.insertBack(newLine);
|
|
|
|
|
}
|
2014-03-18 05:23:23 +04:00
|
|
|
|
return newLine;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 19:37:02 +04:00
|
|
|
|
void
|
2013-12-05 22:57:51 +04:00
|
|
|
|
nsFlexContainerFrame::GenerateFlexLines(
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
2013-12-05 22:57:51 +04:00
|
|
|
|
nscoord aContentBoxMainSize,
|
2015-05-12 23:34:22 +03:00
|
|
|
|
nscoord aAvailableBSizeForContent,
|
2014-01-22 02:52:27 +04:00
|
|
|
|
const nsTArray<StrutInfo>& aStruts,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
const FlexboxAxisTracker& aAxisTracker,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
LinkedList<FlexLine>& aLines)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(aLines.isEmpty(), "Expecting outparam to start out empty");
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
const bool isSingleLine =
|
|
|
|
|
NS_STYLE_FLEX_WRAP_NOWRAP == aReflowState.mStylePosition->mFlexWrap;
|
|
|
|
|
|
2014-04-08 04:17:42 +04:00
|
|
|
|
// If we're transparently reversing axes, then we'll need to link up our
|
|
|
|
|
// FlexItems and FlexLines in the reverse order, so that the rest of flex
|
|
|
|
|
// layout (with flipped axes) will still produce the correct result.
|
|
|
|
|
// Here, we declare a convenience bool that we'll pass when adding a new
|
|
|
|
|
// FlexLine or FlexItem, to make us insert it at the beginning of its list
|
|
|
|
|
// (so the list ends up reversed).
|
|
|
|
|
const bool shouldInsertAtFront = aAxisTracker.AreAxesInternallyReversed();
|
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// We have at least one FlexLine. Even an empty flex container has a single
|
|
|
|
|
// (empty) flex line.
|
2014-04-08 04:17:42 +04:00
|
|
|
|
FlexLine* curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
|
|
|
|
nscoord wrapThreshold;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
if (isSingleLine) {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Not wrapping. Set threshold to sentinel value that tells us not to wrap.
|
|
|
|
|
wrapThreshold = NS_UNCONSTRAINEDSIZE;
|
|
|
|
|
} else {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Wrapping! Set wrap threshold to flex container's content-box main-size.
|
|
|
|
|
wrapThreshold = aContentBoxMainSize;
|
|
|
|
|
|
|
|
|
|
// If the flex container doesn't have a definite content-box main-size
|
2015-05-12 23:34:25 +03:00
|
|
|
|
// (e.g. if main axis is vertical & 'height' is 'auto'), make sure we at
|
|
|
|
|
// least wrap when we hit its max main-size.
|
2013-12-05 22:57:51 +04:00
|
|
|
|
if (wrapThreshold == NS_UNCONSTRAINEDSIZE) {
|
|
|
|
|
const nscoord flexContainerMaxMainSize =
|
2015-06-13 00:28:24 +03:00
|
|
|
|
GET_MAIN_COMPONENT_LOGICAL(aAxisTracker, aAxisTracker.GetWritingMode(),
|
2015-05-12 23:34:25 +03:00
|
|
|
|
aReflowState.ComputedMaxISize(),
|
|
|
|
|
aReflowState.ComputedMaxBSize());
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
|
|
|
|
wrapThreshold = flexContainerMaxMainSize;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-12 23:34:25 +03:00
|
|
|
|
// Also: if we're column-oriented and paginating in the block dimension,
|
|
|
|
|
// we may need to wrap to a new flex line sooner (before we grow past the
|
|
|
|
|
// available BSize, potentially running off the end of the page).
|
|
|
|
|
if (aAxisTracker.IsColumnOriented() &&
|
2015-05-12 23:34:22 +03:00
|
|
|
|
aAvailableBSizeForContent != NS_UNCONSTRAINEDSIZE) {
|
|
|
|
|
wrapThreshold = std::min(wrapThreshold, aAvailableBSizeForContent);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-01-22 02:52:27 +04:00
|
|
|
|
// Tracks the index of the next strut, in aStruts (and when this hits
|
|
|
|
|
// aStruts.Length(), that means there are no more struts):
|
|
|
|
|
uint32_t nextStrutIdx = 0;
|
|
|
|
|
|
|
|
|
|
// Overall index of the current flex item in the flex container. (This gets
|
|
|
|
|
// checked against entries in aStruts.)
|
|
|
|
|
uint32_t itemIdxInContainer = 0;
|
|
|
|
|
|
2015-04-01 07:50:46 +03:00
|
|
|
|
for (nsIFrame* childFrame : mFrames) {
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Honor "page-break-before", if we're multi-line and this line isn't empty:
|
2014-03-18 05:23:23 +04:00
|
|
|
|
if (!isSingleLine && !curLine->IsEmpty() &&
|
2013-12-05 22:57:51 +04:00
|
|
|
|
childFrame->StyleDisplay()->mBreakBefore) {
|
2014-04-08 04:17:42 +04:00
|
|
|
|
curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
nsAutoPtr<FlexItem> item;
|
2014-01-22 02:52:27 +04:00
|
|
|
|
if (nextStrutIdx < aStruts.Length() &&
|
|
|
|
|
aStruts[nextStrutIdx].mItemIdx == itemIdxInContainer) {
|
|
|
|
|
|
|
|
|
|
// Use the simplified "strut" FlexItem constructor:
|
2015-06-13 00:28:24 +03:00
|
|
|
|
item = new FlexItem(childFrame, aStruts[nextStrutIdx].mStrutCrossSize,
|
|
|
|
|
aReflowState.GetWritingMode());
|
2014-01-22 02:52:27 +04:00
|
|
|
|
nextStrutIdx++;
|
|
|
|
|
} else {
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item = GenerateFlexItemForChild(aPresContext, childFrame,
|
|
|
|
|
aReflowState, aAxisTracker);
|
2014-01-22 02:52:27 +04:00
|
|
|
|
}
|
2013-11-01 06:39:02 +04:00
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
nscoord itemInnerHypotheticalMainSize = item->GetMainSize();
|
2014-04-03 21:40:12 +04:00
|
|
|
|
nscoord itemOuterHypotheticalMainSize =
|
|
|
|
|
item->GetOuterMainSize(aAxisTracker.GetMainAxis());
|
2013-11-26 22:27:52 +04:00
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Check if we need to wrap |item| to a new line
|
|
|
|
|
// (i.e. check if its outer hypothetical main size pushes our line over
|
|
|
|
|
// the threshold)
|
|
|
|
|
if (wrapThreshold != NS_UNCONSTRAINEDSIZE &&
|
2014-03-18 05:23:23 +04:00
|
|
|
|
!curLine->IsEmpty() && // No need to wrap at start of a line.
|
2013-12-05 22:57:51 +04:00
|
|
|
|
wrapThreshold < (curLine->GetTotalOuterHypotheticalMainSize() +
|
|
|
|
|
itemOuterHypotheticalMainSize)) {
|
2014-04-08 04:17:42 +04:00
|
|
|
|
curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2013-11-26 22:27:52 +04:00
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
// Add item to current flex line (and update the line's bookkeeping about
|
|
|
|
|
// how large its items collectively are).
|
2014-04-08 04:17:42 +04:00
|
|
|
|
curLine->AddItem(item.forget(), shouldInsertAtFront,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
itemInnerHypotheticalMainSize,
|
|
|
|
|
itemOuterHypotheticalMainSize);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
|
|
|
|
// Honor "page-break-after", if we're multi-line and have more children:
|
|
|
|
|
if (!isSingleLine && childFrame->GetNextSibling() &&
|
|
|
|
|
childFrame->StyleDisplay()->mBreakAfter) {
|
2014-04-08 04:17:42 +04:00
|
|
|
|
curLine = AddNewFlexLineToList(aLines, shouldInsertAtFront);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2014-01-22 02:52:27 +04:00
|
|
|
|
itemIdxInContainer++;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Retrieves the content-box main-size of our flex container from the
|
|
|
|
|
// reflow state (specifically, the main-size of *this continuation* of the
|
|
|
|
|
// flex container).
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord
|
2013-12-05 22:57:51 +04:00
|
|
|
|
nsFlexContainerFrame::GetMainSizeFromReflowState(
|
2012-09-30 10:38:46 +04:00
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
2013-12-05 22:57:51 +04:00
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2015-05-15 21:57:06 +03:00
|
|
|
|
if (aAxisTracker.IsRowOriented()) {
|
|
|
|
|
// Row-oriented --> our main axis is the inline axis, so our main size
|
|
|
|
|
// is our inline size (which should already be resolved).
|
|
|
|
|
// XXXdholbert ISize may be (wrongly) unconstrained right now: bug 1163238
|
|
|
|
|
// Uncomment when that's fixed:
|
|
|
|
|
/*
|
|
|
|
|
NS_WARN_IF_FALSE(aReflowState.ComputedISize() != NS_UNCONSTRAINEDSIZE,
|
|
|
|
|
"Unconstrained inline size; this should only result from "
|
|
|
|
|
"huge sizes (not intrinsic sizing w/ orthogonal flows)");
|
|
|
|
|
*/
|
2014-06-20 13:55:35 +04:00
|
|
|
|
return aReflowState.ComputedISize();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// Note: This may be unconstrained, if our block size is "auto":
|
2014-06-20 13:55:35 +04:00
|
|
|
|
return GetEffectiveComputedBSize(aReflowState);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Returns the largest outer hypothetical main-size of any line in |aLines|.
|
|
|
|
|
// (i.e. the hypothetical main-size of the largest line)
|
|
|
|
|
static nscoord
|
2014-03-18 05:23:23 +04:00
|
|
|
|
GetLargestLineMainSize(const FlexLine* aFirstLine)
|
2013-12-05 22:57:51 +04:00
|
|
|
|
{
|
|
|
|
|
nscoord largestLineOuterSize = 0;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (const FlexLine* line = aFirstLine; line; line = line->getNext()) {
|
|
|
|
|
largestLineOuterSize = std::max(largestLineOuterSize,
|
|
|
|
|
line->GetTotalOuterHypotheticalMainSize());
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
|
|
|
|
return largestLineOuterSize;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 21:57:05 +03:00
|
|
|
|
/* Resolves the content-box main-size of a flex container frame,
|
|
|
|
|
* primarily based on:
|
|
|
|
|
* - the "tentative" main size, taken from the reflow state ("tentative"
|
|
|
|
|
* because it may be unconstrained or may run off the page).
|
|
|
|
|
* - the available BSize (needed if the main axis is the block axis).
|
|
|
|
|
* - the sizes of our lines of flex items.
|
|
|
|
|
*
|
|
|
|
|
* Guaranteed to return a definite length, i.e. not NS_UNCONSTRAINEDSIZE,
|
|
|
|
|
* aside from cases with huge lengths which happen to compute to that value.
|
2015-05-15 21:57:06 +03:00
|
|
|
|
* XXXdholbert (this^ isn't quite true, if we're row-oriented and in an
|
|
|
|
|
* orthogonal flow, per mentions of bug 1163238 in GetMainSizeFromReflowState.)
|
2015-05-15 21:57:05 +03:00
|
|
|
|
*
|
|
|
|
|
* (Note: This function should be structurally similar to 'ComputeCrossSize()',
|
|
|
|
|
* except that here, the caller has already grabbed the tentative size from the
|
|
|
|
|
* reflow state.)
|
|
|
|
|
*/
|
2013-12-05 22:57:51 +04:00
|
|
|
|
static nscoord
|
2015-05-15 21:57:05 +03:00
|
|
|
|
ResolveFlexContainerMainSize(const nsHTMLReflowState& aReflowState,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker,
|
|
|
|
|
nscoord aTentativeMainSize,
|
|
|
|
|
nscoord aAvailableBSizeForContent,
|
|
|
|
|
const FlexLine* aFirstLine,
|
|
|
|
|
nsReflowStatus& aStatus)
|
2013-12-05 22:57:51 +04:00
|
|
|
|
{
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MOZ_ASSERT(aFirstLine, "null first line pointer");
|
|
|
|
|
|
2015-05-15 21:57:06 +03:00
|
|
|
|
if (aAxisTracker.IsRowOriented()) {
|
|
|
|
|
// Row-oriented --> our main axis is the inline axis, so our main size
|
|
|
|
|
// is our inline size (which should already be resolved).
|
2015-05-15 21:57:05 +03:00
|
|
|
|
return aTentativeMainSize;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 21:57:05 +03:00
|
|
|
|
if (aTentativeMainSize != NS_INTRINSICSIZE) {
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// Column-oriented case, with fixed BSize:
|
2015-05-12 23:34:22 +03:00
|
|
|
|
if (aAvailableBSizeForContent == NS_UNCONSTRAINEDSIZE ||
|
2015-05-15 21:57:05 +03:00
|
|
|
|
aTentativeMainSize < aAvailableBSizeForContent) {
|
2013-11-21 22:20:01 +04:00
|
|
|
|
// Not in a fragmenting context, OR no need to fragment because we have
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// more available BSize than we need. Either way, we don't need to clamp.
|
|
|
|
|
// (Note that the reflow state has already done the appropriate
|
|
|
|
|
// min/max-BSize clamping.)
|
2015-05-15 21:57:05 +03:00
|
|
|
|
return aTentativeMainSize;
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// Fragmenting *and* our fixed BSize is larger than available BSize:
|
2013-11-21 22:20:01 +04:00
|
|
|
|
// Mark incomplete so we get a next-in-flow, and take up all of the
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// available BSize (or the amount of BSize required by our children, if
|
|
|
|
|
// that's larger; but of course not more than our own computed BSize).
|
2013-11-21 22:20:01 +04:00
|
|
|
|
// XXXdholbert For now, we don't support pushing children to our next
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// continuation or splitting children, so "amount of BSize required by
|
|
|
|
|
// our children" is just the main-size (BSize) of our longest flex line.
|
2013-11-21 22:20:01 +04:00
|
|
|
|
NS_FRAME_SET_INCOMPLETE(aStatus);
|
2014-03-18 05:23:23 +04:00
|
|
|
|
nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
2015-05-12 23:34:22 +03:00
|
|
|
|
if (largestLineOuterSize <= aAvailableBSizeForContent) {
|
|
|
|
|
return aAvailableBSizeForContent;
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
2015-05-15 21:57:05 +03:00
|
|
|
|
return std::min(aTentativeMainSize, largestLineOuterSize);
|
2013-07-12 03:47:03 +04:00
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// Column-oriented case, with auto BSize:
|
|
|
|
|
// Resolve auto BSize to the largest FlexLine length, clamped to our
|
|
|
|
|
// computed min/max main-size properties.
|
2015-05-12 23:34:22 +03:00
|
|
|
|
// XXXdholbert Handle constrained-aAvailableBSizeForContent case here.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
nscoord largestLineOuterSize = GetLargestLineMainSize(aFirstLine);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
return NS_CSS_MINMAX(largestLineOuterSize,
|
2015-05-15 21:57:06 +03:00
|
|
|
|
aReflowState.ComputedMinBSize(),
|
|
|
|
|
aReflowState.ComputedMaxBSize());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-21 22:20:01 +04:00
|
|
|
|
nscoord
|
2013-12-07 01:38:49 +04:00
|
|
|
|
nsFlexContainerFrame::ComputeCrossSize(const nsHTMLReflowState& aReflowState,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker,
|
2014-02-07 05:04:52 +04:00
|
|
|
|
nscoord aSumLineCrossSizes,
|
2015-05-12 23:34:22 +03:00
|
|
|
|
nscoord aAvailableBSizeForContent,
|
2013-12-07 01:38:49 +04:00
|
|
|
|
bool* aIsDefinite,
|
|
|
|
|
nsReflowStatus& aStatus)
|
2013-11-21 22:20:01 +04:00
|
|
|
|
{
|
2014-02-27 11:28:38 +04:00
|
|
|
|
MOZ_ASSERT(aIsDefinite, "outparam pointer must be non-null");
|
2013-11-21 22:20:01 +04:00
|
|
|
|
|
2015-05-15 21:57:06 +03:00
|
|
|
|
if (aAxisTracker.IsColumnOriented()) {
|
|
|
|
|
// Column-oriented --> our cross axis is the inline axis, so our cross size
|
|
|
|
|
// is our inline size (which should already be resolved).
|
|
|
|
|
// XXXdholbert ISize may be (wrongly) unconstrained right now: bug 1163238.
|
|
|
|
|
// Uncomment when that's fixed:
|
|
|
|
|
/*
|
|
|
|
|
NS_WARN_IF_FALSE(aReflowState.ComputedISize() != NS_UNCONSTRAINEDSIZE,
|
|
|
|
|
"Unconstrained inline size; this should only result from "
|
|
|
|
|
"huge sizes (not intrinsic sizing w/ orthogonal flows)");
|
|
|
|
|
*/
|
2013-11-21 22:20:01 +04:00
|
|
|
|
*aIsDefinite = true;
|
2014-06-20 13:55:35 +04:00
|
|
|
|
return aReflowState.ComputedISize();
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-20 13:55:35 +04:00
|
|
|
|
nscoord effectiveComputedBSize = GetEffectiveComputedBSize(aReflowState);
|
|
|
|
|
if (effectiveComputedBSize != NS_INTRINSICSIZE) {
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// Row-oriented case (cross axis is block-axis), with fixed BSize:
|
2013-11-21 22:20:01 +04:00
|
|
|
|
*aIsDefinite = true;
|
2015-05-12 23:34:22 +03:00
|
|
|
|
if (aAvailableBSizeForContent == NS_UNCONSTRAINEDSIZE ||
|
|
|
|
|
effectiveComputedBSize < aAvailableBSizeForContent) {
|
2013-11-21 22:20:01 +04:00
|
|
|
|
// Not in a fragmenting context, OR no need to fragment because we have
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// more available BSize than we need. Either way, just use our fixed
|
|
|
|
|
// BSize. (Note that the reflow state has already done the appropriate
|
|
|
|
|
// min/max-BSize clamping.)
|
2014-06-20 13:55:35 +04:00
|
|
|
|
return effectiveComputedBSize;
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// Fragmenting *and* our fixed BSize is too tall for available BSize:
|
2013-11-21 22:20:01 +04:00
|
|
|
|
// Mark incomplete so we get a next-in-flow, and take up all of the
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// available BSize (or the amount of BSize required by our children, if
|
|
|
|
|
// that's larger; but of course not more than our own computed BSize).
|
2013-11-21 22:20:01 +04:00
|
|
|
|
// XXXdholbert For now, we don't support pushing children to our next
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// continuation or splitting children, so "amount of BSize required by
|
|
|
|
|
// our children" is just the sum of our FlexLines' BSizes (cross sizes).
|
2013-11-21 22:20:01 +04:00
|
|
|
|
NS_FRAME_SET_INCOMPLETE(aStatus);
|
2015-05-12 23:34:22 +03:00
|
|
|
|
if (aSumLineCrossSizes <= aAvailableBSizeForContent) {
|
|
|
|
|
return aAvailableBSizeForContent;
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
2014-06-20 13:55:35 +04:00
|
|
|
|
return std::min(effectiveComputedBSize, aSumLineCrossSizes);
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-15 21:57:06 +03:00
|
|
|
|
// Row-oriented case (cross axis is block axis), with auto BSize:
|
|
|
|
|
// Shrink-wrap our line(s), subject to our min-size / max-size
|
|
|
|
|
// constraints in that (block) axis.
|
2015-05-12 23:34:22 +03:00
|
|
|
|
// XXXdholbert Handle constrained-aAvailableBSizeForContent case here.
|
2013-11-21 22:20:01 +04:00
|
|
|
|
*aIsDefinite = false;
|
2014-02-07 05:04:52 +04:00
|
|
|
|
return NS_CSS_MINMAX(aSumLineCrossSizes,
|
2015-05-15 21:57:06 +03:00
|
|
|
|
aReflowState.ComputedMinBSize(),
|
|
|
|
|
aReflowState.ComputedMaxBSize());
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
void
|
2013-11-26 22:27:52 +04:00
|
|
|
|
FlexLine::PositionItemsInMainAxis(uint8_t aJustifyContent,
|
|
|
|
|
nscoord aContentBoxMainSize,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2014-03-18 05:23:23 +04:00
|
|
|
|
MainAxisPositionTracker mainAxisPosnTracker(aAxisTracker, this,
|
2013-11-26 22:27:52 +04:00
|
|
|
|
aJustifyContent,
|
|
|
|
|
aContentBoxMainSize);
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
|
2013-11-26 22:27:52 +04:00
|
|
|
|
nscoord itemMainBorderBoxSize =
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->GetMainSize() +
|
|
|
|
|
item->GetBorderPaddingSizeInAxis(mainAxisPosnTracker.GetAxis());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
// Resolve any main-axis 'auto' margins on aChild to an actual value.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mainAxisPosnTracker.ResolveAutoMarginsInMainAxis(*item);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
// Advance our position tracker to child's upper-left content-box corner,
|
|
|
|
|
// and use that as its position in the main axis.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mainAxisPosnTracker.EnterMargin(item->GetMargin());
|
2013-11-26 22:27:52 +04:00
|
|
|
|
mainAxisPosnTracker.EnterChildFrame(itemMainBorderBoxSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->SetMainPosition(mainAxisPosnTracker.GetPosition());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-11-26 22:27:52 +04:00
|
|
|
|
mainAxisPosnTracker.ExitChildFrame(itemMainBorderBoxSize);
|
2014-03-18 05:23:23 +04:00
|
|
|
|
mainAxisPosnTracker.ExitMargin(item->GetMargin());
|
2013-11-26 22:27:52 +04:00
|
|
|
|
mainAxisPosnTracker.TraversePackingSpace();
|
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:43 +04:00
|
|
|
|
/**
|
2015-03-27 00:37:48 +03:00
|
|
|
|
* Given the flex container's "flex-relative ascent" (i.e. distance from the
|
2014-04-08 04:17:43 +04:00
|
|
|
|
* flex container's content-box cross-start edge to its baseline), returns
|
|
|
|
|
* its actual physical ascent value (the distance from the *border-box* top
|
|
|
|
|
* edge to its baseline).
|
|
|
|
|
*/
|
|
|
|
|
static nscoord
|
2015-03-27 00:37:48 +03:00
|
|
|
|
ComputePhysicalAscentFromFlexRelativeAscent(
|
|
|
|
|
nscoord aFlexRelativeAscent,
|
|
|
|
|
nscoord aContentBoxCrossSize,
|
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2014-04-08 04:17:43 +04:00
|
|
|
|
{
|
|
|
|
|
return aReflowState.ComputedPhysicalBorderPadding().top +
|
2015-03-27 00:37:48 +03:00
|
|
|
|
PhysicalCoordFromFlexRelativeCoord(aFlexRelativeAscent,
|
|
|
|
|
aContentBoxCrossSize,
|
|
|
|
|
aAxisTracker.GetCrossAxis());
|
2014-04-08 04:17:43 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-13 19:37:02 +04:00
|
|
|
|
void
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nsFlexContainerFrame::SizeItemInCrossAxis(
|
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker,
|
2013-02-16 02:01:48 +04:00
|
|
|
|
nsHTMLReflowState& aChildReflowState,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
FlexItem& aItem)
|
|
|
|
|
{
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsCrossAxisHorizontal()) {
|
2015-01-22 06:45:37 +03:00
|
|
|
|
// XXXdholbert NOTE: For now, we should never hit this case, due to a
|
2015-03-27 22:06:03 +03:00
|
|
|
|
// !aAxisTracker.IsCrossAxisHorizontal() check that guards this
|
2015-01-22 06:45:37 +03:00
|
|
|
|
// call in the caller. BUT, when we add support for vertical writing-modes,
|
|
|
|
|
// (in bug 1079155 or a dependency), we'll relax that check, and we'll need
|
|
|
|
|
// to be able to measure the baseline & width (given our resolved height)
|
|
|
|
|
// of vertical-writing-mode flex items here.
|
|
|
|
|
MOZ_ASSERT_UNREACHABLE("Caller should use tentative cross size instead "
|
|
|
|
|
"of calling SizeItemInCrossAxis");
|
|
|
|
|
// (But if we do happen to get here, just trust the passed-in reflow state
|
|
|
|
|
// for our cross size [width].)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
aItem.SetCrossSize(aChildReflowState.ComputedWidth());
|
2014-06-13 19:37:02 +04:00
|
|
|
|
return;
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-16 02:01:48 +04:00
|
|
|
|
MOZ_ASSERT(!aItem.HadMeasuringReflow(),
|
|
|
|
|
"We shouldn't need more than one measuring reflow");
|
|
|
|
|
|
2015-11-03 17:18:06 +03:00
|
|
|
|
if (aItem.GetAlignSelf() == NS_STYLE_ALIGN_STRETCH) {
|
2013-02-16 02:01:48 +04:00
|
|
|
|
// This item's got "align-self: stretch", so we probably imposed a
|
|
|
|
|
// stretched computed height on it during its previous reflow. We're
|
|
|
|
|
// not imposing that height for *this* measuring reflow, so we need to
|
|
|
|
|
// tell it to treat this reflow as a vertical resize (regardless of
|
|
|
|
|
// whether any of its ancestors are being resized).
|
2014-11-28 12:44:02 +03:00
|
|
|
|
aChildReflowState.SetVResize(true);
|
2013-02-16 02:01:48 +04:00
|
|
|
|
}
|
2013-12-31 17:50:31 +04:00
|
|
|
|
nsHTMLReflowMetrics childDesiredSize(aChildReflowState);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nsReflowStatus childReflowStatus;
|
2013-12-18 22:34:46 +04:00
|
|
|
|
const uint32_t flags = NS_FRAME_NO_MOVE_FRAME;
|
2014-05-13 04:47:53 +04:00
|
|
|
|
ReflowChild(aItem.Frame(), aPresContext,
|
|
|
|
|
childDesiredSize, aChildReflowState,
|
|
|
|
|
0, 0, flags, childReflowStatus);
|
2013-02-16 02:01:48 +04:00
|
|
|
|
aItem.SetHadMeasuringReflow();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// XXXdholbert Once we do pagination / splitting, we'll need to actually
|
|
|
|
|
// handle incomplete childReflowStatuses. But for now, we give our kids
|
|
|
|
|
// unconstrained available height, which means they should always complete.
|
|
|
|
|
MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus),
|
|
|
|
|
"We gave flex item unconstrained available height, so it "
|
|
|
|
|
"should be complete");
|
|
|
|
|
|
|
|
|
|
// Tell the child we're done with its initial reflow.
|
|
|
|
|
// (Necessary for e.g. GetBaseline() to work below w/out asserting)
|
2014-05-13 04:47:53 +04:00
|
|
|
|
FinishReflowChild(aItem.Frame(), aPresContext,
|
|
|
|
|
childDesiredSize, &aChildReflowState, 0, 0, flags);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
|
|
|
|
// Save the sizing info that we learned from this reflow
|
|
|
|
|
// -----------------------------------------------------
|
|
|
|
|
|
2013-03-28 12:50:21 +04:00
|
|
|
|
// Tentatively store the child's desired content-box cross-size.
|
|
|
|
|
// Note that childDesiredSize is the border-box size, so we have to
|
|
|
|
|
// subtract border & padding to get the content-box size.
|
|
|
|
|
// (Note that at this point in the code, we know our cross axis is vertical,
|
|
|
|
|
// so we don't bother with making aAxisTracker pick the cross-axis component
|
|
|
|
|
// for us.)
|
|
|
|
|
nscoord crossAxisBorderPadding = aItem.GetBorderPadding().TopBottom();
|
2013-12-27 21:59:52 +04:00
|
|
|
|
if (childDesiredSize.Height() < crossAxisBorderPadding) {
|
2013-03-28 12:50:21 +04:00
|
|
|
|
// Child's requested size isn't large enough for its border/padding!
|
|
|
|
|
// This is OK for the trivial nsFrame::Reflow() impl, but other frame
|
|
|
|
|
// classes should know better. So, if we get here, the child had better be
|
|
|
|
|
// an instance of nsFrame (i.e. it should return null from GetType()).
|
|
|
|
|
// XXXdholbert Once we've fixed bug 765861, we should upgrade this to an
|
|
|
|
|
// assertion that trivially passes if bug 765861's flag has been flipped.
|
|
|
|
|
NS_WARN_IF_FALSE(!aItem.Frame()->GetType(),
|
|
|
|
|
"Child should at least request space for border/padding");
|
|
|
|
|
aItem.SetCrossSize(0);
|
|
|
|
|
} else {
|
|
|
|
|
// (normal case)
|
2013-12-27 21:59:52 +04:00
|
|
|
|
aItem.SetCrossSize(childDesiredSize.Height() - crossAxisBorderPadding);
|
2013-03-28 12:50:21 +04:00
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-01-23 02:12:10 +03:00
|
|
|
|
// If this is the first child, save its ascent, since it may be what
|
|
|
|
|
// establishes the container's baseline. Also save the ascent if this child
|
|
|
|
|
// needs to be baseline-aligned. (Else, we don't care about baseline/ascent.)
|
|
|
|
|
if (aItem.Frame() == mFrames.FirstChild() ||
|
2015-11-03 17:18:06 +03:00
|
|
|
|
aItem.GetAlignSelf() == NS_STYLE_ALIGN_BASELINE) {
|
2014-06-11 13:45:31 +04:00
|
|
|
|
aItem.SetAscent(childDesiredSize.BlockStartAscent());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2013-11-26 22:27:52 +04:00
|
|
|
|
FlexLine::PositionItemsInCrossAxis(nscoord aLineStartPosition,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2013-11-26 22:27:52 +04:00
|
|
|
|
SingleLineCrossAxisPositionTracker lineCrossAxisPosnTracker(aAxisTracker);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (FlexItem* item = mItems.getFirst(); item; item = item->getNext()) {
|
2013-11-26 22:27:52 +04:00
|
|
|
|
// First, stretch the item's cross size (if appropriate), and resolve any
|
|
|
|
|
// auto margins in this axis.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->ResolveStretchedCrossSize(mLineCrossSize, aAxisTracker);
|
|
|
|
|
lineCrossAxisPosnTracker.ResolveAutoMarginsInCrossAxis(*this, *item);
|
2013-11-26 22:27:52 +04:00
|
|
|
|
|
|
|
|
|
// Compute the cross-axis position of this item
|
|
|
|
|
nscoord itemCrossBorderBoxSize =
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->GetCrossSize() +
|
|
|
|
|
item->GetBorderPaddingSizeInAxis(aAxisTracker.GetCrossAxis());
|
2014-04-08 04:17:42 +04:00
|
|
|
|
lineCrossAxisPosnTracker.EnterAlignPackingSpace(*this, *item, aAxisTracker);
|
2014-03-18 05:23:23 +04:00
|
|
|
|
lineCrossAxisPosnTracker.EnterMargin(item->GetMargin());
|
2013-11-26 22:27:52 +04:00
|
|
|
|
lineCrossAxisPosnTracker.EnterChildFrame(itemCrossBorderBoxSize);
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->SetCrossPosition(aLineStartPosition +
|
|
|
|
|
lineCrossAxisPosnTracker.GetPosition());
|
2013-11-26 22:27:52 +04:00
|
|
|
|
|
|
|
|
|
// Back out to cross-axis edge of the line.
|
|
|
|
|
lineCrossAxisPosnTracker.ResetPosition();
|
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-05-13 04:47:52 +04:00
|
|
|
|
void
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
|
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
|
nsReflowStatus& aStatus)
|
|
|
|
|
{
|
2015-03-30 01:38:40 +03:00
|
|
|
|
MarkInReflow();
|
2012-09-30 10:38:46 +04:00
|
|
|
|
DO_GLOBAL_REFLOW_COUNT("nsFlexContainerFrame");
|
|
|
|
|
DISPLAY_REFLOW(aPresContext, this, aReflowState, aDesiredSize, aStatus);
|
2015-11-06 01:35:03 +03:00
|
|
|
|
MOZ_LOG(gFlexContainerLog, LogLevel::Debug,
|
2012-09-30 10:38:46 +04:00
|
|
|
|
("Reflow() for nsFlexContainerFrame %p\n", this));
|
|
|
|
|
|
2013-01-08 06:29:22 +04:00
|
|
|
|
if (IsFrameTreeTooDeep(aReflowState, aDesiredSize, aStatus)) {
|
2014-05-13 04:47:52 +04:00
|
|
|
|
return;
|
2013-01-08 06:29:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-18 09:33:50 +03:00
|
|
|
|
// We (and our children) can only depend on our ancestor's bsize if we have
|
|
|
|
|
// a percent-bsize, or if we're positioned and we have "block-start" and "block-end"
|
|
|
|
|
// set and have block-size:auto. (There are actually other cases, too -- e.g. if
|
|
|
|
|
// our parent is itself a block-dir flex container and we're flexible -- but
|
2013-03-14 12:18:53 +04:00
|
|
|
|
// we'll let our ancestors handle those sorts of cases.)
|
2015-06-18 09:33:50 +03:00
|
|
|
|
WritingMode wm = aReflowState.GetWritingMode();
|
2013-03-14 12:18:53 +04:00
|
|
|
|
const nsStylePosition* stylePos = StylePosition();
|
2015-06-18 09:33:50 +03:00
|
|
|
|
const nsStyleCoord& bsize = stylePos->BSize(wm);
|
|
|
|
|
if (bsize.HasPercent() ||
|
2013-03-14 12:18:53 +04:00
|
|
|
|
(StyleDisplay()->IsAbsolutelyPositionedStyle() &&
|
2015-06-18 09:33:50 +03:00
|
|
|
|
eStyleUnit_Auto == bsize.GetUnit() &&
|
|
|
|
|
eStyleUnit_Auto != stylePos->mOffset.GetBStartUnit(wm) &&
|
|
|
|
|
eStyleUnit_Auto != stylePos->mOffset.GetBEndUnit(wm))) {
|
|
|
|
|
AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
SanityCheckAnonymousFlexItems();
|
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
2012-12-27 00:17:52 +04:00
|
|
|
|
// If we've never reordered our children, then we can trust that they're
|
|
|
|
|
// already in DOM-order, and we only need to consider their "order" property
|
|
|
|
|
// when checking them for sortedness & sorting them.
|
|
|
|
|
//
|
|
|
|
|
// After we actually sort them, though, we can't trust that they're in DOM
|
|
|
|
|
// order anymore. So, from that point on, our sort & sorted-order-checking
|
|
|
|
|
// operations need to use a fancier LEQ function that also takes DOM order
|
|
|
|
|
// into account, so that we can honor the spec's requirement that frames w/
|
|
|
|
|
// equal "order" values are laid out in DOM order.
|
2014-03-08 03:58:38 +04:00
|
|
|
|
|
|
|
|
|
if (!HasAnyStateBits(NS_STATE_FLEX_CHILDREN_REORDERED)) {
|
|
|
|
|
if (SortChildrenIfNeeded<IsOrderLEQ>()) {
|
|
|
|
|
AddStateBits(NS_STATE_FLEX_CHILDREN_REORDERED);
|
|
|
|
|
}
|
2012-12-27 00:17:52 +04:00
|
|
|
|
} else {
|
|
|
|
|
SortChildrenIfNeeded<IsOrderLEQWithDOMFallback>();
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-27 22:06:03 +03:00
|
|
|
|
const FlexboxAxisTracker axisTracker(aReflowState.mStylePosition,
|
|
|
|
|
aReflowState.GetWritingMode());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-05-12 23:34:23 +03:00
|
|
|
|
// If we're being fragmented into a constrained BSize, then subtract off
|
|
|
|
|
// borderpadding BStart from that constrained BSize, to get the available
|
|
|
|
|
// BSize for our content box. (No need to subtract the borderpadding BStart
|
|
|
|
|
// if we're already skipping it via GetLogicalSkipSides, though.)
|
2015-05-12 23:34:22 +03:00
|
|
|
|
nscoord availableBSizeForContent = aReflowState.AvailableBSize();
|
|
|
|
|
if (availableBSizeForContent != NS_UNCONSTRAINEDSIZE &&
|
2015-05-12 23:34:23 +03:00
|
|
|
|
!(GetLogicalSkipSides(&aReflowState).BStart())) {
|
|
|
|
|
availableBSizeForContent -=
|
|
|
|
|
aReflowState.ComputedLogicalBorderPadding().BStart(wm);
|
2015-05-12 23:34:22 +03:00
|
|
|
|
// (Don't let that push availableBSizeForContent below zero, though):
|
|
|
|
|
availableBSizeForContent = std::max(availableBSizeForContent, 0);
|
2013-11-21 22:20:01 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-22 02:51:57 +04:00
|
|
|
|
nscoord contentBoxMainSize = GetMainSizeFromReflowState(aReflowState,
|
|
|
|
|
axisTracker);
|
|
|
|
|
|
2014-01-22 02:51:58 +04:00
|
|
|
|
nsAutoTArray<StrutInfo, 1> struts;
|
2014-06-13 19:37:02 +04:00
|
|
|
|
DoFlexLayout(aPresContext, aDesiredSize, aReflowState, aStatus,
|
2015-05-12 23:34:22 +03:00
|
|
|
|
contentBoxMainSize, availableBSizeForContent,
|
2014-06-13 19:37:02 +04:00
|
|
|
|
struts, axisTracker);
|
2014-01-22 02:51:57 +04:00
|
|
|
|
|
2014-06-13 19:37:02 +04:00
|
|
|
|
if (!struts.IsEmpty()) {
|
2014-01-22 02:51:58 +04:00
|
|
|
|
// We're restarting flex layout, with new knowledge of collapsed items.
|
2014-05-13 04:47:52 +04:00
|
|
|
|
DoFlexLayout(aPresContext, aDesiredSize, aReflowState, aStatus,
|
2015-05-12 23:34:22 +03:00
|
|
|
|
contentBoxMainSize, availableBSizeForContent,
|
2014-05-13 04:47:52 +04:00
|
|
|
|
struts, axisTracker);
|
2014-01-22 02:51:58 +04:00
|
|
|
|
}
|
2014-01-22 02:51:57 +04:00
|
|
|
|
}
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
// RAII class to clean up a list of FlexLines.
|
|
|
|
|
// Specifically, this removes each line from the list, deletes all the
|
|
|
|
|
// FlexItems in its list, and deletes the FlexLine.
|
2015-09-03 19:15:23 +03:00
|
|
|
|
class MOZ_RAII AutoFlexLineListClearer
|
2014-03-18 06:27:51 +04:00
|
|
|
|
{
|
2014-03-18 05:23:23 +04:00
|
|
|
|
public:
|
2014-09-01 07:36:37 +04:00
|
|
|
|
explicit AutoFlexLineListClearer(LinkedList<FlexLine>& aLines
|
|
|
|
|
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
2014-03-18 05:23:23 +04:00
|
|
|
|
: mLines(aLines)
|
|
|
|
|
{
|
|
|
|
|
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~AutoFlexLineListClearer()
|
|
|
|
|
{
|
|
|
|
|
while (FlexLine* line = mLines.popFirst()) {
|
|
|
|
|
while (FlexItem* item = line->mItems.popFirst()) {
|
|
|
|
|
delete item;
|
|
|
|
|
}
|
|
|
|
|
delete line;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
LinkedList<FlexLine>& mLines;
|
|
|
|
|
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
|
|
|
|
};
|
|
|
|
|
|
2014-06-13 19:37:02 +04:00
|
|
|
|
void
|
2014-01-22 02:51:57 +04:00
|
|
|
|
nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext,
|
|
|
|
|
nsHTMLReflowMetrics& aDesiredSize,
|
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
|
nsReflowStatus& aStatus,
|
|
|
|
|
nscoord aContentBoxMainSize,
|
2015-05-12 23:34:22 +03:00
|
|
|
|
nscoord aAvailableBSizeForContent,
|
2014-01-22 02:51:58 +04:00
|
|
|
|
nsTArray<StrutInfo>& aStruts,
|
2014-01-22 02:51:57 +04:00
|
|
|
|
const FlexboxAxisTracker& aAxisTracker)
|
|
|
|
|
{
|
|
|
|
|
aStatus = NS_FRAME_COMPLETE;
|
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
LinkedList<FlexLine> lines;
|
|
|
|
|
AutoFlexLineListClearer cleanupLines(lines);
|
|
|
|
|
|
2014-06-13 19:37:02 +04:00
|
|
|
|
GenerateFlexLines(aPresContext, aReflowState,
|
|
|
|
|
aContentBoxMainSize,
|
2015-05-12 23:34:22 +03:00
|
|
|
|
aAvailableBSizeForContent,
|
2014-06-13 19:37:02 +04:00
|
|
|
|
aStruts, aAxisTracker, lines);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
2014-01-22 02:51:57 +04:00
|
|
|
|
aContentBoxMainSize =
|
2015-05-15 21:57:05 +03:00
|
|
|
|
ResolveFlexContainerMainSize(aReflowState, aAxisTracker,
|
|
|
|
|
aContentBoxMainSize, aAvailableBSizeForContent,
|
|
|
|
|
lines.getFirst(), aStatus);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
|
|
|
|
|
line->ResolveFlexibleLengths(aContentBoxMainSize);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2013-07-10 01:38:59 +04:00
|
|
|
|
// Cross Size Determination - Flexbox spec section 9.4
|
|
|
|
|
// ===================================================
|
|
|
|
|
// Calculate the hypothetical cross size of each item:
|
2014-02-07 05:04:52 +04:00
|
|
|
|
nscoord sumLineCrossSizes = 0;
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
|
|
|
|
|
for (FlexItem* item = line->GetFirstItem(); item; item = item->getNext()) {
|
2015-01-22 06:45:37 +03:00
|
|
|
|
// Note that we may already have the correct cross size. (We guess at it
|
|
|
|
|
// in GenerateFlexItemForChild(), and we also may resolve it early for
|
|
|
|
|
// stretched flex items.)
|
|
|
|
|
//
|
|
|
|
|
// We can skip measuring an item's cross size here in a few scenarios:
|
|
|
|
|
// (A) If the flex item has already been stretched, then we're imposing
|
|
|
|
|
// the container's cross size on it; no need to measure.
|
|
|
|
|
// (B) If the flex item is a "strut", then it's just a placeholder with a
|
|
|
|
|
// predetermined cross size; no need to measure.
|
|
|
|
|
// (C) If the item's main-size can't affect its cross-size, then the
|
|
|
|
|
// item's tentative cross size (which we got from the reflow state in
|
|
|
|
|
// GenerateFlexItemForChild()) is correct. So, no need to re-measure.
|
|
|
|
|
// (For now, this is equivalent to checking if the cross-axis is
|
|
|
|
|
// horizontal, because until we enable vertical writing-modes, an
|
|
|
|
|
// element's computed width can't be influenced by its computed
|
|
|
|
|
// height.)
|
|
|
|
|
if (!item->IsStretched() && // !A
|
|
|
|
|
!item->IsStrut() && // !B
|
2015-03-27 22:06:03 +03:00
|
|
|
|
!aAxisTracker.IsCrossAxisHorizontal()) { // !C
|
2014-07-24 12:28:46 +04:00
|
|
|
|
WritingMode wm = item->Frame()->GetWritingMode();
|
|
|
|
|
LogicalSize availSize = aReflowState.ComputedSize(wm);
|
|
|
|
|
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
|
2014-07-24 12:28:46 +04:00
|
|
|
|
item->Frame(), availSize);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Override computed main-size
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsMainAxisHorizontal()) {
|
2014-03-18 05:23:23 +04:00
|
|
|
|
childReflowState.SetComputedWidth(item->GetMainSize());
|
2013-12-05 22:57:51 +04:00
|
|
|
|
} else {
|
2015-01-22 06:45:37 +03:00
|
|
|
|
// XXXdholbert NOTE: For now, we'll never hit this case, due to the
|
2015-03-27 22:06:03 +03:00
|
|
|
|
// !aAxisTracker.IsCrossAxisHorizontal() check above. But
|
2015-01-22 06:45:37 +03:00
|
|
|
|
// when we add support for vertical writing modes, we'll relax that
|
|
|
|
|
// check and be able to hit this code.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
childReflowState.SetComputedHeight(item->GetMainSize());
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2014-06-13 19:37:02 +04:00
|
|
|
|
|
|
|
|
|
SizeItemInCrossAxis(aPresContext, aAxisTracker,
|
|
|
|
|
childReflowState, *item);
|
2013-11-01 06:39:02 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-07 05:04:52 +04:00
|
|
|
|
// Now that we've finished with this line's items, size the line itself:
|
2014-03-18 05:23:23 +04:00
|
|
|
|
line->ComputeCrossSizeAndBaseline(aAxisTracker);
|
|
|
|
|
sumLineCrossSizes += line->GetLineCrossSize();
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2013-11-26 22:27:51 +04:00
|
|
|
|
|
2013-11-21 22:20:01 +04:00
|
|
|
|
bool isCrossSizeDefinite;
|
|
|
|
|
const nscoord contentBoxCrossSize =
|
2014-02-07 05:04:52 +04:00
|
|
|
|
ComputeCrossSize(aReflowState, aAxisTracker, sumLineCrossSizes,
|
2015-05-12 23:34:22 +03:00
|
|
|
|
aAvailableBSizeForContent, &isCrossSizeDefinite, aStatus);
|
2013-11-21 22:20:01 +04:00
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Set up state for cross-axis alignment, at a high level (outside the
|
|
|
|
|
// scope of a particular flex line)
|
|
|
|
|
CrossAxisPositionTracker
|
2014-03-18 05:23:23 +04:00
|
|
|
|
crossAxisPosnTracker(lines.getFirst(),
|
2015-11-03 17:18:06 +03:00
|
|
|
|
aReflowState.mStylePosition->ComputedAlignContent(
|
|
|
|
|
aReflowState.mStyleDisplay),
|
2014-01-22 02:51:57 +04:00
|
|
|
|
contentBoxCrossSize, isCrossSizeDefinite,
|
|
|
|
|
aAxisTracker);
|
2013-07-10 01:38:59 +04:00
|
|
|
|
|
2014-01-22 02:51:58 +04:00
|
|
|
|
// Now that we know the cross size of each line (including
|
|
|
|
|
// "align-content:stretch" adjustments, from the CrossAxisPositionTracker
|
|
|
|
|
// constructor), we can create struts for any flex items with
|
|
|
|
|
// "visibility: collapse" (and restart flex layout).
|
|
|
|
|
if (aStruts.IsEmpty()) { // (Don't make struts if we already did)
|
2014-03-18 05:23:23 +04:00
|
|
|
|
BuildStrutInfoFromCollapsedItems(lines.getFirst(), aStruts);
|
2014-01-22 02:51:58 +04:00
|
|
|
|
if (!aStruts.IsEmpty()) {
|
|
|
|
|
// Restart flex layout, using our struts.
|
2014-06-13 19:37:02 +04:00
|
|
|
|
return;
|
2014-01-22 02:51:58 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-08 04:17:43 +04:00
|
|
|
|
// If the container should derive its baseline from the first FlexLine,
|
|
|
|
|
// do that here (while crossAxisPosnTracker is conveniently pointing
|
|
|
|
|
// at the cross-start edge of that line, which the line's baseline offset is
|
|
|
|
|
// measured from):
|
2013-12-05 22:57:52 +04:00
|
|
|
|
nscoord flexContainerAscent;
|
2014-04-08 04:17:43 +04:00
|
|
|
|
if (!aAxisTracker.AreAxesInternallyReversed()) {
|
|
|
|
|
nscoord firstLineBaselineOffset = lines.getFirst()->GetBaselineOffset();
|
|
|
|
|
if (firstLineBaselineOffset == nscoord_MIN) {
|
|
|
|
|
// No baseline-aligned items in line. Use sentinel value to prompt us to
|
|
|
|
|
// get baseline from the first FlexItem after we've reflowed it.
|
|
|
|
|
flexContainerAscent = nscoord_MIN;
|
|
|
|
|
} else {
|
|
|
|
|
flexContainerAscent =
|
2015-03-27 00:37:48 +03:00
|
|
|
|
ComputePhysicalAscentFromFlexRelativeAscent(
|
2014-04-08 04:17:43 +04:00
|
|
|
|
crossAxisPosnTracker.GetPosition() + firstLineBaselineOffset,
|
|
|
|
|
contentBoxCrossSize, aReflowState, aAxisTracker);
|
|
|
|
|
}
|
2013-03-30 05:32:08 +04:00
|
|
|
|
}
|
2013-03-16 09:40:57 +04:00
|
|
|
|
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
|
2013-07-10 01:38:59 +04:00
|
|
|
|
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// Main-Axis Alignment - Flexbox spec section 9.5
|
|
|
|
|
// ==============================================
|
2015-11-03 17:18:05 +03:00
|
|
|
|
auto justifyContent =
|
|
|
|
|
aReflowState.mStylePosition->ComputedJustifyContent(aReflowState.mStyleDisplay);
|
|
|
|
|
line->PositionItemsInMainAxis(justifyContent,
|
2014-03-18 05:23:23 +04:00
|
|
|
|
aContentBoxMainSize,
|
|
|
|
|
aAxisTracker);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
|
|
|
|
// Cross-Axis Alignment - Flexbox spec section 9.6
|
|
|
|
|
// ===============================================
|
2014-03-18 05:23:23 +04:00
|
|
|
|
line->PositionItemsInCrossAxis(crossAxisPosnTracker.GetPosition(),
|
|
|
|
|
aAxisTracker);
|
|
|
|
|
crossAxisPosnTracker.TraverseLine(*line);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
crossAxisPosnTracker.TraversePackingSpace();
|
2013-12-05 22:57:51 +04:00
|
|
|
|
}
|
2013-03-16 09:40:57 +04:00
|
|
|
|
|
2014-04-08 04:17:43 +04:00
|
|
|
|
// If the container should derive its baseline from the last FlexLine,
|
|
|
|
|
// do that here (while crossAxisPosnTracker is conveniently pointing
|
|
|
|
|
// at the cross-end edge of that line, which the line's baseline offset is
|
|
|
|
|
// measured from):
|
|
|
|
|
if (aAxisTracker.AreAxesInternallyReversed()) {
|
|
|
|
|
nscoord lastLineBaselineOffset = lines.getLast()->GetBaselineOffset();
|
|
|
|
|
if (lastLineBaselineOffset == nscoord_MIN) {
|
|
|
|
|
// No baseline-aligned items in line. Use sentinel value to prompt us to
|
|
|
|
|
// get baseline from the last FlexItem after we've reflowed it.
|
|
|
|
|
flexContainerAscent = nscoord_MIN;
|
|
|
|
|
} else {
|
|
|
|
|
flexContainerAscent =
|
2015-03-27 00:37:48 +03:00
|
|
|
|
ComputePhysicalAscentFromFlexRelativeAscent(
|
2014-04-08 04:17:43 +04:00
|
|
|
|
crossAxisPosnTracker.GetPosition() - lastLineBaselineOffset,
|
|
|
|
|
contentBoxCrossSize, aReflowState, aAxisTracker);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-18 01:53:56 +04:00
|
|
|
|
// Before giving each child a final reflow, calculate the origin of the
|
|
|
|
|
// flex container's content box (with respect to its border-box), so that
|
|
|
|
|
// we can compute our flex item's final positions.
|
2015-04-16 22:01:14 +03:00
|
|
|
|
WritingMode flexWM = aReflowState.GetWritingMode();
|
|
|
|
|
LogicalMargin containerBP = aReflowState.ComputedLogicalBorderPadding();
|
|
|
|
|
|
|
|
|
|
// Unconditionally skip block-end border & padding for now, regardless of
|
|
|
|
|
// writing-mode/GetLogicalSkipSides. We add it lower down, after we've
|
|
|
|
|
// established baseline and decided whether bottom border-padding fits (if
|
|
|
|
|
// we're fragmented).
|
2015-04-17 20:41:23 +03:00
|
|
|
|
const nscoord blockEndContainerBP = containerBP.BEnd(flexWM);
|
2015-04-16 22:01:14 +03:00
|
|
|
|
const LogicalSides skipSides =
|
|
|
|
|
GetLogicalSkipSides(&aReflowState) | LogicalSides(eLogicalSideBitsBEnd);
|
|
|
|
|
containerBP.ApplySkipSides(skipSides);
|
|
|
|
|
|
|
|
|
|
const LogicalPoint containerContentBoxOrigin(flexWM,
|
|
|
|
|
containerBP.IStart(flexWM),
|
|
|
|
|
containerBP.BStart(flexWM));
|
|
|
|
|
|
2015-07-16 12:08:05 +03:00
|
|
|
|
// Determine flex container's border-box size (used in positioning children):
|
|
|
|
|
LogicalSize logSize =
|
|
|
|
|
aAxisTracker.LogicalSizeFromFlexRelativeSizes(aContentBoxMainSize,
|
|
|
|
|
contentBoxCrossSize);
|
|
|
|
|
logSize += aReflowState.ComputedLogicalBorderPadding().Size(flexWM);
|
|
|
|
|
nsSize containerSize = logSize.GetPhysicalSize(flexWM);
|
2013-09-18 01:53:56 +04:00
|
|
|
|
|
2013-03-16 09:40:57 +04:00
|
|
|
|
// FINAL REFLOW: Give each child frame another chance to reflow, now that
|
|
|
|
|
// we know its final size and position.
|
2014-03-18 05:23:23 +04:00
|
|
|
|
for (const FlexLine* line = lines.getFirst(); line; line = line->getNext()) {
|
|
|
|
|
for (const FlexItem* item = line->GetFirstItem(); item;
|
|
|
|
|
item = item->getNext()) {
|
2015-04-16 22:01:14 +03:00
|
|
|
|
LogicalPoint framePos = aAxisTracker.LogicalPointFromFlexRelativePoint(
|
2014-03-18 05:23:23 +04:00
|
|
|
|
item->GetMainPosition(),
|
|
|
|
|
item->GetCrossPosition(),
|
2014-01-22 02:51:57 +04:00
|
|
|
|
aContentBoxMainSize,
|
2013-12-05 22:57:51 +04:00
|
|
|
|
contentBoxCrossSize);
|
2015-04-16 22:01:14 +03:00
|
|
|
|
// Adjust framePos to be relative to the container's border-box
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// (i.e. its frame rect), instead of the container's content-box:
|
2015-04-16 22:01:14 +03:00
|
|
|
|
framePos += containerContentBoxOrigin;
|
2015-01-07 10:10:07 +03:00
|
|
|
|
|
2015-01-23 02:12:11 +03:00
|
|
|
|
// (Intentionally snapshotting this before ApplyRelativePositioning, to
|
|
|
|
|
// maybe use for setting the flex container's baseline.)
|
2015-04-16 22:01:14 +03:00
|
|
|
|
const nscoord itemNormalBPos = framePos.B(flexWM);
|
2015-01-23 02:12:11 +03:00
|
|
|
|
|
2015-01-24 01:15:11 +03:00
|
|
|
|
// Check if we actually need to reflow the item -- if we already reflowed
|
|
|
|
|
// it with the right size, we can just reposition it as-needed.
|
|
|
|
|
bool itemNeedsReflow = true; // (Start out assuming the worst.)
|
|
|
|
|
if (item->HadMeasuringReflow()) {
|
2015-04-16 22:01:14 +03:00
|
|
|
|
LogicalSize finalFlexItemCBSize =
|
|
|
|
|
aAxisTracker.LogicalSizeFromFlexRelativeSizes(item->GetMainSize(),
|
|
|
|
|
item->GetCrossSize());
|
2015-01-24 01:15:11 +03:00
|
|
|
|
// We've already reflowed the child once. Was the size we gave it in
|
|
|
|
|
// that reflow the same as its final (post-flexing/stretching) size?
|
2015-04-16 22:01:14 +03:00
|
|
|
|
if (finalFlexItemCBSize ==
|
|
|
|
|
LogicalSize(flexWM,
|
|
|
|
|
item->Frame()->GetContentRectRelativeToSelf().Size())) {
|
2015-03-20 09:00:05 +03:00
|
|
|
|
// Even if our size hasn't changed, some of our descendants might
|
2015-06-18 09:33:50 +03:00
|
|
|
|
// care that our bsize is now considered "definite" (whereas it
|
2015-03-20 09:00:05 +03:00
|
|
|
|
// wasn't in our previous "measuring" reflow), if they have a
|
2015-06-18 09:33:50 +03:00
|
|
|
|
// relative bsize.
|
2015-03-20 09:00:05 +03:00
|
|
|
|
if (!(item->Frame()->GetStateBits() &
|
2015-06-18 09:33:50 +03:00
|
|
|
|
NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
|
2015-03-20 09:00:05 +03:00
|
|
|
|
// Item has the correct size (and its children don't care that
|
|
|
|
|
// it's now "definite"). Let's just make sure it's at the right
|
|
|
|
|
// position.
|
|
|
|
|
itemNeedsReflow = false;
|
|
|
|
|
MoveFlexItemToFinalPosition(aReflowState, *item, framePos,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
containerSize);
|
2015-03-20 09:00:05 +03:00
|
|
|
|
}
|
2015-01-24 01:15:11 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (itemNeedsReflow) {
|
|
|
|
|
ReflowFlexItem(aPresContext, aAxisTracker, aReflowState,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
*item, framePos, containerSize);
|
2015-01-24 01:15:11 +03:00
|
|
|
|
}
|
2015-01-23 21:25:58 +03:00
|
|
|
|
|
|
|
|
|
// If this is our first child and we haven't established a baseline for
|
|
|
|
|
// the container yet (i.e. if we don't have 'align-self: baseline' on any
|
|
|
|
|
// children), then use this child's baseline as the container's baseline.
|
|
|
|
|
if (item->Frame() == mFrames.FirstChild() &&
|
|
|
|
|
flexContainerAscent == nscoord_MIN) {
|
|
|
|
|
flexContainerAscent = itemNormalBPos + item->ResolvedAscent();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 20:41:23 +03:00
|
|
|
|
// Compute flex container's desired size (in its own writing-mode),
|
|
|
|
|
// starting w/ content-box size & growing from there:
|
|
|
|
|
LogicalSize desiredSizeInFlexWM =
|
|
|
|
|
aAxisTracker.LogicalSizeFromFlexRelativeSizes(aContentBoxMainSize,
|
|
|
|
|
contentBoxCrossSize);
|
|
|
|
|
// Add border/padding (w/ skipSides already applied):
|
|
|
|
|
desiredSizeInFlexWM.ISize(flexWM) += containerBP.IStartEnd(flexWM);
|
|
|
|
|
desiredSizeInFlexWM.BSize(flexWM) += containerBP.BStartEnd(flexWM);
|
2015-01-23 21:25:58 +03:00
|
|
|
|
|
|
|
|
|
if (flexContainerAscent == nscoord_MIN) {
|
|
|
|
|
// Still don't have our baseline set -- this happens if we have no
|
|
|
|
|
// children (or if our children are huge enough that they have nscoord_MIN
|
|
|
|
|
// as their baseline... in which case, we'll use the wrong baseline, but no
|
|
|
|
|
// big deal)
|
|
|
|
|
NS_WARN_IF_FALSE(lines.getFirst()->IsEmpty(),
|
|
|
|
|
"Have flex items but didn't get an ascent - that's odd "
|
|
|
|
|
"(or there are just gigantic sizes involved)");
|
2015-04-17 20:41:23 +03:00
|
|
|
|
// Per spec, synthesize baseline from the flex container's content box
|
|
|
|
|
// (i.e. use block-end side of content-box)
|
|
|
|
|
// XXXdholbert This only makes sense if parent's writing mode is
|
|
|
|
|
// horizontal (& even then, really we should be using the BSize in terms
|
|
|
|
|
// of the parent's writing mode, not ours). Clean up in bug 1155322.
|
|
|
|
|
flexContainerAscent = desiredSizeInFlexWM.BSize(flexWM);
|
2015-01-23 21:25:58 +03:00
|
|
|
|
}
|
2015-04-17 20:41:23 +03:00
|
|
|
|
|
|
|
|
|
// XXXdholbert flexContainerAscent needs to be in terms of
|
|
|
|
|
// our parent's writing-mode here. See bug 1155322.
|
2015-01-23 21:25:58 +03:00
|
|
|
|
aDesiredSize.SetBlockStartAscent(flexContainerAscent);
|
|
|
|
|
|
2015-04-17 20:41:23 +03:00
|
|
|
|
// Now: If we're complete, add bottom border/padding to desired height (which
|
|
|
|
|
// we skipped via skipSides) -- unless that pushes us over available height,
|
|
|
|
|
// in which case we become incomplete (unless we already weren't asking for
|
|
|
|
|
// any height, in which case we stay complete to avoid looping forever).
|
2015-01-23 21:25:58 +03:00
|
|
|
|
// NOTE: If we're auto-height, we allow our bottom border/padding to push us
|
|
|
|
|
// over the available height without requesting a continuation, for
|
|
|
|
|
// consistency with the behavior of "display:block" elements.
|
|
|
|
|
if (NS_FRAME_IS_COMPLETE(aStatus)) {
|
2015-04-17 20:41:23 +03:00
|
|
|
|
nscoord desiredBSizeWithBEndBP =
|
|
|
|
|
desiredSizeInFlexWM.BSize(flexWM) + blockEndContainerBP;
|
|
|
|
|
|
|
|
|
|
if (aReflowState.AvailableBSize() == NS_UNCONSTRAINEDSIZE ||
|
|
|
|
|
desiredSizeInFlexWM.BSize(flexWM) == 0 ||
|
|
|
|
|
desiredBSizeWithBEndBP <= aReflowState.AvailableBSize() ||
|
|
|
|
|
aReflowState.ComputedBSize() == NS_INTRINSICSIZE) {
|
|
|
|
|
// Update desired height to include block-end border/padding
|
|
|
|
|
desiredSizeInFlexWM.BSize(flexWM) = desiredBSizeWithBEndBP;
|
2015-01-23 21:25:58 +03:00
|
|
|
|
} else {
|
|
|
|
|
// We couldn't fit bottom border/padding, so we'll need a continuation.
|
|
|
|
|
NS_FRAME_SET_INCOMPLETE(aStatus);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 20:41:23 +03:00
|
|
|
|
// Convert flex container's final desired size to parent's WM, for outparam.
|
|
|
|
|
aDesiredSize.SetSize(flexWM, desiredSizeInFlexWM);
|
|
|
|
|
|
2015-01-23 21:25:58 +03:00
|
|
|
|
// Overflow area = union(my overflow area, kids' overflow areas)
|
|
|
|
|
aDesiredSize.SetOverflowAreasToDesiredBounds();
|
2015-04-01 07:50:46 +03:00
|
|
|
|
for (nsIFrame* childFrame : mFrames) {
|
|
|
|
|
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, childFrame);
|
2015-01-23 21:25:58 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize,
|
|
|
|
|
aReflowState, aStatus);
|
|
|
|
|
|
|
|
|
|
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize)
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-24 01:15:11 +03:00
|
|
|
|
void
|
|
|
|
|
nsFlexContainerFrame::MoveFlexItemToFinalPosition(
|
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
|
|
|
|
const FlexItem& aItem,
|
|
|
|
|
LogicalPoint& aFramePos,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
const nsSize& aContainerSize)
|
2015-01-24 01:15:11 +03:00
|
|
|
|
{
|
|
|
|
|
WritingMode outerWM = aReflowState.GetWritingMode();
|
|
|
|
|
|
|
|
|
|
// If item is relpos, look up its offsets (cached from prev reflow)
|
|
|
|
|
LogicalMargin logicalOffsets(outerWM);
|
|
|
|
|
if (NS_STYLE_POSITION_RELATIVE == aItem.Frame()->StyleDisplay()->mPosition) {
|
|
|
|
|
FrameProperties props = aItem.Frame()->Properties();
|
|
|
|
|
nsMargin* cachedOffsets =
|
|
|
|
|
static_cast<nsMargin*>(props.Get(nsIFrame::ComputedOffsetProperty()));
|
|
|
|
|
MOZ_ASSERT(cachedOffsets,
|
|
|
|
|
"relpos previously-reflowed frame should've cached its offsets");
|
|
|
|
|
logicalOffsets = LogicalMargin(outerWM, *cachedOffsets);
|
|
|
|
|
}
|
|
|
|
|
nsHTMLReflowState::ApplyRelativePositioning(aItem.Frame(), outerWM,
|
|
|
|
|
logicalOffsets, &aFramePos,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
aContainerSize);
|
|
|
|
|
aItem.Frame()->SetPosition(outerWM, aFramePos, aContainerSize);
|
2015-01-24 01:15:11 +03:00
|
|
|
|
PositionChildViews(aItem.Frame());
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-23 21:25:58 +03:00
|
|
|
|
void
|
|
|
|
|
nsFlexContainerFrame::ReflowFlexItem(nsPresContext* aPresContext,
|
|
|
|
|
const FlexboxAxisTracker& aAxisTracker,
|
|
|
|
|
const nsHTMLReflowState& aReflowState,
|
2015-01-23 21:25:59 +03:00
|
|
|
|
const FlexItem& aItem,
|
|
|
|
|
LogicalPoint& aFramePos,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
const nsSize& aContainerSize)
|
2015-01-23 21:25:58 +03:00
|
|
|
|
{
|
2015-01-23 21:26:00 +03:00
|
|
|
|
WritingMode outerWM = aReflowState.GetWritingMode();
|
|
|
|
|
WritingMode wm = aItem.Frame()->GetWritingMode();
|
|
|
|
|
LogicalSize availSize = aReflowState.ComputedSize(wm);
|
|
|
|
|
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
|
|
|
|
|
nsHTMLReflowState childReflowState(aPresContext, aReflowState,
|
|
|
|
|
aItem.Frame(), availSize);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-01-23 21:26:00 +03:00
|
|
|
|
// Keep track of whether we've overriden the child's computed height
|
|
|
|
|
// and/or width, so we can set its resize flags accordingly.
|
|
|
|
|
bool didOverrideComputedWidth = false;
|
|
|
|
|
bool didOverrideComputedHeight = false;
|
2013-12-05 22:57:51 +04:00
|
|
|
|
|
2015-01-23 21:26:00 +03:00
|
|
|
|
// Override computed main-size
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsMainAxisHorizontal()) {
|
2015-01-23 21:26:00 +03:00
|
|
|
|
childReflowState.SetComputedWidth(aItem.GetMainSize());
|
|
|
|
|
didOverrideComputedWidth = true;
|
|
|
|
|
} else {
|
|
|
|
|
childReflowState.SetComputedHeight(aItem.GetMainSize());
|
|
|
|
|
didOverrideComputedHeight = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Override reflow state's computed cross-size, for stretched items.
|
|
|
|
|
if (aItem.IsStretched()) {
|
2015-11-03 17:18:06 +03:00
|
|
|
|
MOZ_ASSERT(aItem.GetAlignSelf() == NS_STYLE_ALIGN_STRETCH,
|
2015-01-23 21:26:00 +03:00
|
|
|
|
"stretched item w/o 'align-self: stretch'?");
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (aAxisTracker.IsCrossAxisHorizontal()) {
|
2015-01-23 21:26:00 +03:00
|
|
|
|
childReflowState.SetComputedWidth(aItem.GetCrossSize());
|
|
|
|
|
didOverrideComputedWidth = true;
|
|
|
|
|
} else {
|
|
|
|
|
// If this item's height is stretched, it's a relative height.
|
2015-06-18 09:33:50 +03:00
|
|
|
|
aItem.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
|
2015-01-23 21:26:00 +03:00
|
|
|
|
childReflowState.SetComputedHeight(aItem.GetCrossSize());
|
|
|
|
|
didOverrideComputedHeight = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// XXXdholbert Might need to actually set the correct margins in the
|
|
|
|
|
// reflow state at some point, so that they can be saved on the frame for
|
|
|
|
|
// UsedMarginProperty(). Maybe doesn't matter though...?
|
|
|
|
|
|
|
|
|
|
// If we're overriding the computed width or height, *and* we had an
|
|
|
|
|
// earlier "measuring" reflow, then this upcoming reflow needs to be
|
|
|
|
|
// treated as a resize.
|
|
|
|
|
if (aItem.HadMeasuringReflow()) {
|
|
|
|
|
if (didOverrideComputedWidth) {
|
|
|
|
|
// (This is somewhat redundant, since the reflow state already
|
|
|
|
|
// sets mHResize whenever our computed width has changed since the
|
|
|
|
|
// previous reflow. Still, it's nice for symmetry, and it may become
|
|
|
|
|
// necessary once we support orthogonal flows.)
|
|
|
|
|
childReflowState.SetHResize(true);
|
|
|
|
|
}
|
|
|
|
|
if (didOverrideComputedHeight) {
|
|
|
|
|
childReflowState.SetVResize(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// NOTE: Be very careful about doing anything else with childReflowState
|
|
|
|
|
// after this point, because some of its methods (e.g. SetComputedWidth)
|
|
|
|
|
// internally call InitResizeFlags and stomp on mVResize & mHResize.
|
|
|
|
|
|
|
|
|
|
nsHTMLReflowMetrics childDesiredSize(childReflowState);
|
|
|
|
|
nsReflowStatus childReflowStatus;
|
|
|
|
|
ReflowChild(aItem.Frame(), aPresContext,
|
|
|
|
|
childDesiredSize, childReflowState,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
outerWM, aFramePos, aContainerSize,
|
2015-01-23 21:26:00 +03:00
|
|
|
|
0, childReflowStatus);
|
|
|
|
|
|
|
|
|
|
// XXXdholbert Once we do pagination / splitting, we'll need to actually
|
|
|
|
|
// handle incomplete childReflowStatuses. But for now, we give our kids
|
|
|
|
|
// unconstrained available height, which means they should always
|
|
|
|
|
// complete.
|
|
|
|
|
MOZ_ASSERT(NS_FRAME_IS_COMPLETE(childReflowStatus),
|
|
|
|
|
"We gave flex item unconstrained available height, so it "
|
|
|
|
|
"should be complete");
|
|
|
|
|
|
2015-02-02 21:29:52 +03:00
|
|
|
|
LogicalMargin offsets =
|
|
|
|
|
childReflowState.ComputedLogicalOffsets().ConvertTo(outerWM, wm);
|
|
|
|
|
nsHTMLReflowState::ApplyRelativePositioning(aItem.Frame(), outerWM,
|
|
|
|
|
offsets, &aFramePos,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
aContainerSize);
|
2015-01-23 21:26:00 +03:00
|
|
|
|
|
|
|
|
|
FinishReflowChild(aItem.Frame(), aPresContext,
|
|
|
|
|
childDesiredSize, &childReflowState,
|
2015-07-16 12:07:57 +03:00
|
|
|
|
outerWM, aFramePos, aContainerSize, 0);
|
2015-01-23 21:26:00 +03:00
|
|
|
|
|
|
|
|
|
// Save the first child's ascent; it may establish container's baseline.
|
|
|
|
|
if (aItem.Frame() == mFrames.FirstChild()) {
|
|
|
|
|
aItem.SetAscent(childDesiredSize.BlockStartAscent());
|
|
|
|
|
}
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* virtual */ nscoord
|
2014-07-24 21:03:25 +04:00
|
|
|
|
nsFlexContainerFrame::GetMinISize(nsRenderingContext* aRenderingContext)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2014-02-13 11:47:01 +04:00
|
|
|
|
nscoord minWidth = 0;
|
|
|
|
|
DISPLAY_MIN_WIDTH(this, minWidth);
|
|
|
|
|
|
2015-03-27 22:06:03 +03:00
|
|
|
|
const nsStylePosition* stylePos = StylePosition();
|
|
|
|
|
const FlexboxAxisTracker axisTracker(stylePos, GetWritingMode());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-04-01 07:50:46 +03:00
|
|
|
|
for (nsIFrame* childFrame : mFrames) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord childMinWidth =
|
2015-04-01 07:50:46 +03:00
|
|
|
|
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
|
2014-07-24 21:03:26 +04:00
|
|
|
|
nsLayoutUtils::MIN_ISIZE);
|
2013-12-05 22:57:51 +04:00
|
|
|
|
// For a horizontal single-line flex container, the intrinsic min width is
|
|
|
|
|
// the sum of its items' min widths.
|
|
|
|
|
// For a vertical flex container, or for a multi-line horizontal flex
|
|
|
|
|
// container, the intrinsic min width is the max of its items' min widths.
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (axisTracker.IsMainAxisHorizontal() &&
|
2015-03-27 22:06:03 +03:00
|
|
|
|
NS_STYLE_FLEX_WRAP_NOWRAP == stylePos->mFlexWrap) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
minWidth += childMinWidth;
|
|
|
|
|
} else {
|
2013-01-15 16:22:03 +04:00
|
|
|
|
minWidth = std::max(minWidth, childMinWidth);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return minWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* virtual */ nscoord
|
2014-07-24 21:03:25 +04:00
|
|
|
|
nsFlexContainerFrame::GetPrefISize(nsRenderingContext* aRenderingContext)
|
2012-09-30 10:38:46 +04:00
|
|
|
|
{
|
2014-02-13 11:47:01 +04:00
|
|
|
|
nscoord prefWidth = 0;
|
|
|
|
|
DISPLAY_PREF_WIDTH(this, prefWidth);
|
|
|
|
|
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// XXXdholbert Optimization: We could cache our intrinsic widths like
|
|
|
|
|
// nsBlockFrame does (and return it early from this function if it's set).
|
|
|
|
|
// Whenever anything happens that might change it, set it to
|
2014-07-24 21:03:26 +04:00
|
|
|
|
// NS_INTRINSIC_WIDTH_UNKNOWN (like nsBlockFrame::MarkIntrinsicISizesDirty
|
2012-09-30 10:38:46 +04:00
|
|
|
|
// does)
|
2015-03-27 22:06:03 +03:00
|
|
|
|
const FlexboxAxisTracker axisTracker(StylePosition(), GetWritingMode());
|
2012-09-30 10:38:46 +04:00
|
|
|
|
|
2015-04-01 07:50:46 +03:00
|
|
|
|
for (nsIFrame* childFrame : mFrames) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
nscoord childPrefWidth =
|
2015-04-01 07:50:46 +03:00
|
|
|
|
nsLayoutUtils::IntrinsicForContainer(aRenderingContext, childFrame,
|
2014-07-24 21:03:26 +04:00
|
|
|
|
nsLayoutUtils::PREF_ISIZE);
|
2015-03-27 22:06:03 +03:00
|
|
|
|
if (axisTracker.IsMainAxisHorizontal()) {
|
2012-09-30 10:38:46 +04:00
|
|
|
|
prefWidth += childPrefWidth;
|
|
|
|
|
} else {
|
2013-01-15 16:22:03 +04:00
|
|
|
|
prefWidth = std::max(prefWidth, childPrefWidth);
|
2012-09-30 10:38:46 +04:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return prefWidth;
|
|
|
|
|
}
|