Index: third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp |
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp |
index f735ab00a391df20b08aabec6cc348f1ae456e59..f589bc10dd9940647f92964093bf09969095937d 100644 |
--- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp |
+++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp |
@@ -42,6 +42,11 @@ |
namespace blink { |
+static bool hasAspectRatio(const LayoutBox& child) |
+{ |
+ return child.isImage() || child.isCanvas() || child.isVideo(); |
+} |
+ |
struct LayoutFlexibleBox::LineContext { |
LineContext(LayoutUnit crossAxisOffset, LayoutUnit crossAxisExtent, size_t numberOfChildren, LayoutUnit maxAscent) |
: crossAxisOffset(crossAxisOffset) |
@@ -452,7 +457,7 @@ LayoutUnit LayoutFlexibleBox::computeMainAxisExtentForChild(const LayoutBox& chi |
// computeLogicalWidth always re-computes the intrinsic widths. However, when our logical width is auto, |
// we can just use our cached value. So let's do that here. (Compare code in LayoutBlock::computePreferredLogicalWidths) |
LayoutUnit borderAndPadding = child.borderAndPaddingLogicalWidth(); |
- if (child.styleRef().logicalWidth().isAuto()) { |
+ if (child.styleRef().logicalWidth().isAuto() && !hasAspectRatio(child)) { |
if (size.type() == MinContent) |
return child.minPreferredLogicalWidth() - borderAndPadding; |
if (size.type() == MaxContent) |
@@ -625,6 +630,44 @@ LayoutPoint LayoutFlexibleBox::flowAwareLocationForChild(const LayoutBox& child) |
return isHorizontalFlow() ? child.location() : child.location().transposedPoint(); |
} |
+bool LayoutFlexibleBox::useChildAspectRatio(const LayoutBox& child) const |
+{ |
+ if (!hasAspectRatio(child)) |
+ return false; |
+ if (child.intrinsicSize().height() == 0) { |
+ // We can't compute a ratio in this case. |
+ return false; |
+ } |
+ Length crossSize; |
+ if (isHorizontalFlow()) |
+ crossSize = child.styleRef().height(); |
+ else |
+ crossSize = child.styleRef().width(); |
+ return crossAxisLengthIsDefinite(child, crossSize); |
+} |
+ |
+LayoutUnit LayoutFlexibleBox::computeMainSizeFromAspectRatioUsing(const LayoutBox& child, Length crossSizeLength) const |
+{ |
+ ASSERT(hasAspectRatio(child)); |
+ ASSERT(child.intrinsicSize().height() != 0); |
+ |
+ LayoutUnit crossSize; |
+ if (crossSizeLength.isFixed()) { |
+ crossSize = crossSizeLength.value(); |
+ } else { |
+ ASSERT(crossSizeLength.hasPercent()); |
+ crossSize = hasOrthogonalFlow(child) ? |
+ adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(crossSizeLength, contentWidth())) : |
+ child.computePercentageLogicalHeight(crossSizeLength); |
+ } |
+ |
+ const LayoutSize& childIntrinsicSize = child.intrinsicSize(); |
+ double ratio = childIntrinsicSize.width().toFloat() / childIntrinsicSize.height().toFloat(); |
+ if (isHorizontalFlow()) |
+ return crossSize * ratio; |
+ return crossSize / ratio; |
+} |
+ |
void LayoutFlexibleBox::setFlowAwareLocationForChild(LayoutBox& child, const LayoutPoint& location) |
{ |
if (isHorizontalFlow()) |
@@ -650,6 +693,20 @@ bool LayoutFlexibleBox::mainAxisLengthIsDefinite(const LayoutBox& child, const L |
return true; |
} |
+bool LayoutFlexibleBox::crossAxisLengthIsDefinite(const LayoutBox& child, const Length& length) const |
+{ |
+ if (length.isAuto()) |
+ return false; |
+ if (length.hasPercent()) { |
+ return hasOrthogonalFlow(child) ? |
+ hasDefiniteLogicalWidth() : |
+ child.computePercentageLogicalHeight(length) != -1; |
+ } |
+ // TODO(cbiesinger): Eventually we should support other types of sizes here. Requires updating |
+ // computeMainSizeFromAspectRatioUsing. |
+ return length.isFixed(); |
+} |
+ |
bool LayoutFlexibleBox::childFlexBaseSizeRequiresLayout(const LayoutBox& child) const |
{ |
return !mainAxisLengthIsDefinite(child, flexBasisForChild(child)) && ( |
@@ -919,6 +976,8 @@ LayoutUnit LayoutFlexibleBox::adjustChildSizeForMinAndMax(const LayoutBox& child |
// css-flexbox section 4.5 |
LayoutUnit contentSize = computeMainAxisExtentForChild(child, MinSize, Length(MinContent)); |
ASSERT(contentSize >= 0); |
+ if (hasAspectRatio(child) && child.intrinsicSize().height() > 0) |
+ contentSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, contentSize); |
if (maxExtent != -1 && contentSize > maxExtent) |
contentSize = maxExtent; |
@@ -929,15 +988,38 @@ LayoutUnit LayoutFlexibleBox::adjustChildSizeForMinAndMax(const LayoutBox& child |
LayoutUnit specifiedSize = maxExtent != -1 ? std::min(resolvedMainSize, maxExtent) : resolvedMainSize; |
minExtent = std::min(specifiedSize, contentSize); |
+ } else if (useChildAspectRatio(child)) { |
+ Length crossSizeLength = isHorizontalFlow() ? child.styleRef().height() : child.styleRef().width(); |
+ LayoutUnit transferredSize = computeMainSizeFromAspectRatioUsing(child, crossSizeLength); |
+ transferredSize = adjustChildSizeForAspectRatioCrossAxisMinAndMax(child, transferredSize); |
+ minExtent = std::min(transferredSize, contentSize); |
} else { |
minExtent = contentSize; |
} |
- // TODO(cbiesinger): Implement aspect ratio handling (here, transferred size) - crbug.com/249112 |
} |
ASSERT(minExtent >= 0); |
return std::max(childSize, minExtent); |
} |
+LayoutUnit LayoutFlexibleBox::adjustChildSizeForAspectRatioCrossAxisMinAndMax(const LayoutBox& child, LayoutUnit childSize) |
+{ |
+ Length crossMin = isHorizontalFlow() ? child.style()->minHeight() : child.style()->minWidth(); |
+ Length crossMax = isHorizontalFlow() ? child.style()->maxHeight() : child.style()->maxWidth(); |
+ |
+ |
+ if (crossAxisLengthIsDefinite(child, crossMax)) { |
+ LayoutUnit maxValue = computeMainSizeFromAspectRatioUsing(child, crossMax); |
+ childSize = std::min(maxValue, childSize); |
+ } |
+ |
+ if (crossAxisLengthIsDefinite(child, crossMin)) { |
+ LayoutUnit minValue = computeMainSizeFromAspectRatioUsing(child, crossMin); |
+ childSize = std::max(minValue, childSize); |
+ } |
+ |
+ return childSize; |
+} |
+ |
bool LayoutFlexibleBox::computeNextFlexLine(OrderedFlexItemList& orderedChildren, LayoutUnit& sumFlexBaseSize, double& totalFlexGrow, double& totalFlexShrink, double& totalWeightedFlexShrink, LayoutUnit& sumHypotheticalMainSize, bool relayoutChildren) |
{ |
orderedChildren.clear(); |
@@ -1177,6 +1259,7 @@ bool LayoutFlexibleBox::needToStretchChildLogicalHeight(const LayoutBox& child) |
if (isHorizontalFlow() != child.styleRef().isHorizontalWritingMode()) |
return false; |
+ // TODO(cbiesinger): what about indefinite percentage heights? |
return isHorizontalFlow() ? child.styleRef().height().isAuto() : child.styleRef().width().isAuto(); |
} |
@@ -1206,6 +1289,7 @@ EOverflow LayoutFlexibleBox::crossAxisOverflowForChild(const LayoutBox& child) c |
return child.styleRef().overflowY(); |
return child.styleRef().overflowX(); |
} |
+ |
void LayoutFlexibleBox::layoutAndPlaceChildren(LayoutUnit& crossAxisOffset, const OrderedFlexItemList& children, const Vector<LayoutUnit, 16>& childSizes, LayoutUnit availableFreeSpace, bool relayoutChildren, SubtreeLayoutScope& layoutScope, Vector<LineContext>& lineContexts) |
{ |
ASSERT(childSizes.size() == children.size()); |