Expand IntrinsicSizingInfo for SVG

Add fields to IntrinsicSizingInfo specifying whether the intrinsic
width and height are specified or not. For SVGs there is a distinction
between missing width/height and setting width/height to 0. There is
code in LayoutReplaced that has specific hooks into the SVG code to
make this distinction. By having separate fields in
IntrinsicSizingInfo this entanglement can be broken.

BUG=585467

Review URL: https://codereview.chromium.org/1679743006

Cr-Commit-Position: refs/heads/master@{#374909}
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index cc651c30..eee5c67d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -4720,4 +4720,11 @@
     }
 }
 
+void LayoutBox::IntrinsicSizingInfo::transpose()
+{
+    size = size.transposedSize();
+    aspectRatio = aspectRatio ? 1 / aspectRatio : 0;
+    std::swap(hasWidth, hasHeight);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index c76c483e..62727dde 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -826,10 +826,14 @@
 
     struct IntrinsicSizingInfo {
         STACK_ALLOCATED();
-        IntrinsicSizingInfo() : aspectRatio(0) {}
+        IntrinsicSizingInfo() : aspectRatio(0), hasWidth(true), hasHeight(true) {}
 
         FloatSize size;
         double aspectRatio;
+        bool hasWidth;
+        bool hasHeight;
+
+        void transpose();
     };
 
     // Computes the logical intrinsic sizing information.
diff --git a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
index 6d91582..9927165b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutReplaced.cpp
@@ -33,7 +33,6 @@
 #include "core/paint/PaintInfo.h"
 #include "core/paint/PaintLayer.h"
 #include "core/paint/ReplacedPainter.h"
-#include "core/svg/SVGSVGElement.h"
 #include "platform/LengthFunctions.h"
 
 namespace blink {
@@ -163,11 +162,8 @@
         if (intrinsicSizingInfo.aspectRatio && !intrinsicSizingInfo.size.isEmpty())
             m_intrinsicSize = LayoutSize(intrinsicSizingInfo.size);
 
-        if (!isHorizontalWritingMode()) {
-            if (intrinsicSizingInfo.aspectRatio)
-                intrinsicSizingInfo.aspectRatio = 1 / intrinsicSizingInfo.aspectRatio;
-            intrinsicSizingInfo.size = intrinsicSizingInfo.size.transposedSize();
-        }
+        if (!isHorizontalWritingMode())
+            intrinsicSizingInfo.transpose();
     } else {
         computeIntrinsicSizingInfo(intrinsicSizingInfo);
         if (intrinsicSizingInfo.aspectRatio && !intrinsicSizingInfo.size.isEmpty())
@@ -544,28 +540,6 @@
     intrinsicSizingInfo.aspectRatio = intrinsicSizingInfo.size.width() / intrinsicSizingInfo.size.height();
 }
 
-static bool hasIntrinsicWidthForLayoutBox(LayoutBox* layoutObject)
-{
-    if (layoutObject && layoutObject->isSVGRoot()) {
-        SVGSVGElement* svg = toSVGSVGElement(layoutObject->node());
-        ASSERT(svg);
-        return svg->hasIntrinsicWidth();
-    }
-
-    return false;
-}
-
-static bool hasIntrinsicHeightForLayoutBox(LayoutBox* layoutObject)
-{
-    if (layoutObject && layoutObject->isSVGRoot()) {
-        SVGSVGElement* svg = toSVGSVGElement(layoutObject->node());
-        ASSERT(svg);
-        return svg->hasIntrinsicHeight();
-    }
-
-    return false;
-}
-
 LayoutUnit LayoutReplaced::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
 {
     if (style()->logicalWidth().isSpecified() || style()->logicalWidth().isIntrinsic())
@@ -580,21 +554,16 @@
 
     if (style()->logicalWidth().isAuto()) {
         bool computedHeightIsAuto = hasAutoHeightOrContainingBlockWithAutoHeight();
-        // TODO(shanmuga.m@samsung.com): hasIntrinsicWidth/Height information should be obtained
-        // from LayoutBox::computeIntrinsicSizingInfo().
-        bool hasIntrinsicWidth = constrainedSize.width() > 0 || hasIntrinsicWidthForLayoutBox(contentLayoutObject);
 
         // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic width, then that intrinsic width is the used value of 'width'.
-        if (computedHeightIsAuto && hasIntrinsicWidth)
+        if (computedHeightIsAuto && intrinsicSizingInfo.hasWidth)
             return computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit(constrainedSize.width()), shouldComputePreferred);
 
-        bool hasIntrinsicHeight = constrainedSize.height() > 0 || hasIntrinsicHeightForLayoutBox(contentLayoutObject);
-
         if (intrinsicSizingInfo.aspectRatio) {
             // If 'height' and 'width' both have computed values of 'auto' and the element has no intrinsic width, but does have an intrinsic height and intrinsic ratio;
             // or if 'width' has a computed value of 'auto', 'height' has some other computed value, and the element does have an intrinsic ratio; then the used value
             // of 'width' is: (used height) * (intrinsic ratio)
-            if (intrinsicSizingInfo.aspectRatio && ((computedHeightIsAuto && !hasIntrinsicWidth && hasIntrinsicHeight) || !computedHeightIsAuto)) {
+            if ((computedHeightIsAuto && !intrinsicSizingInfo.hasWidth && intrinsicSizingInfo.hasHeight) || !computedHeightIsAuto) {
                 LayoutUnit logicalHeight = computeReplacedLogicalHeight();
                 return computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit(logicalHeight * intrinsicSizingInfo.aspectRatio), shouldComputePreferred);
             }
@@ -602,7 +571,7 @@
             // If 'height' and 'width' both have computed values of 'auto' and the element has an intrinsic ratio but no intrinsic height or width, then the used value of
             // 'width' is undefined in CSS 2.1. However, it is suggested that, if the containing block's width does not itself depend on the replaced element's width, then
             // the used value of 'width' is calculated from the constraint equation used for block-level, non-replaced elements in normal flow.
-            if (computedHeightIsAuto && !hasIntrinsicWidth && !hasIntrinsicHeight) {
+            if (computedHeightIsAuto && !intrinsicSizingInfo.hasWidth && !intrinsicSizingInfo.hasHeight) {
                 if (shouldComputePreferred == ComputePreferred)
                     return computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit(), ComputePreferred);
                 // The aforementioned 'constraint equation' used for block-level, non-replaced elements in normal flow:
@@ -618,7 +587,7 @@
         }
 
         // Otherwise, if 'width' has a computed value of 'auto', and the element has an intrinsic width, then that intrinsic width is the used value of 'width'.
-        if (hasIntrinsicWidth)
+        if (intrinsicSizingInfo.hasWidth)
             return computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit(constrainedSize.width()), shouldComputePreferred);
 
         // Otherwise, if 'width' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'width' becomes 300px. If 300px is too
@@ -645,12 +614,9 @@
     FloatSize constrainedSize = constrainIntrinsicSizeToMinMax(intrinsicSizingInfo);
 
     bool widthIsAuto = style()->logicalWidth().isAuto();
-    // TODO(shanmuga.m@samsung.com): hasIntrinsicWidth/Height information should be obtained
-    // from LayoutBox::computeIntrinsicSizingInfo().
-    bool hasIntrinsicHeight = constrainedSize.height() > 0 || hasIntrinsicHeightForLayoutBox(contentLayoutObject);
 
     // If 'height' and 'width' both have computed values of 'auto' and the element also has an intrinsic height, then that intrinsic height is the used value of 'height'.
-    if (widthIsAuto && hasIntrinsicHeight)
+    if (widthIsAuto && intrinsicSizingInfo.hasHeight)
         return computeReplacedLogicalHeightRespectingMinMaxHeight(constrainedSize.height());
 
     // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic ratio then the used value of 'height' is:
@@ -659,7 +625,7 @@
         return computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit(availableLogicalWidth() / intrinsicSizingInfo.aspectRatio));
 
     // Otherwise, if 'height' has a computed value of 'auto', and the element has an intrinsic height, then that intrinsic height is the used value of 'height'.
-    if (hasIntrinsicHeight)
+    if (intrinsicSizingInfo.hasHeight)
         return computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit(constrainedSize.height()));
 
     // Otherwise, if 'height' has a computed value of 'auto', but none of the conditions above are met, then the used value of 'height' must be set to the height
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
index 840ffc7..6a16ef6e 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.cpp
@@ -39,6 +39,15 @@
 
 namespace blink {
 
+namespace {
+
+FloatSize calculateIntrinsicSize(const SVGSVGElement& svg)
+{
+    return FloatSize(floatValueForLength(svg.intrinsicWidth(), 0), floatValueForLength(svg.intrinsicHeight(), 0));
+}
+
+} // namespace
+
 LayoutSVGRoot::LayoutSVGRoot(SVGElement* node)
     : LayoutReplaced(node)
     , m_objectBoundingBoxValid(false)
@@ -48,10 +57,13 @@
     , m_hasNonIsolatedBlendingDescendants(false)
     , m_hasNonIsolatedBlendingDescendantsDirty(false)
 {
-    LayoutSize intrinsicSize(calculateIntrinsicSize());
-    if (!intrinsicSize.width())
+    SVGSVGElement* svg = toSVGSVGElement(node);
+    ASSERT(svg);
+
+    LayoutSize intrinsicSize(calculateIntrinsicSize(*svg));
+    if (!svg->hasIntrinsicWidth())
         intrinsicSize.setWidth(LayoutUnit(defaultWidth));
-    if (!intrinsicSize.height())
+    if (!svg->hasIntrinsicHeight())
         intrinsicSize.setHeight(LayoutUnit(defaultHeight));
     setIntrinsicSize(intrinsicSize);
 }
@@ -60,36 +72,29 @@
 {
 }
 
-FloatSize LayoutSVGRoot::calculateIntrinsicSize() const
-{
-    SVGSVGElement* svg = toSVGSVGElement(node());
-    ASSERT(svg);
-
-    return FloatSize(floatValueForLength(svg->intrinsicWidth(), 0), floatValueForLength(svg->intrinsicHeight(), 0));
-}
-
 void LayoutSVGRoot::computeIntrinsicSizingInfo(IntrinsicSizingInfo& intrinsicSizingInfo) const
 {
     // https://www.w3.org/TR/SVG/coords.html#IntrinsicSizing
-    intrinsicSizingInfo.size = calculateIntrinsicSize();
 
-    if (!isHorizontalWritingMode())
-        intrinsicSizingInfo.size = intrinsicSizingInfo.size.transposedSize();
+    SVGSVGElement* svg = toSVGSVGElement(node());
+    ASSERT(svg);
+
+    intrinsicSizingInfo.size = calculateIntrinsicSize(*svg);
+    intrinsicSizingInfo.hasWidth = svg->hasIntrinsicWidth();
+    intrinsicSizingInfo.hasHeight = svg->hasIntrinsicHeight();
 
     if (!intrinsicSizingInfo.size.isEmpty()) {
         intrinsicSizingInfo.aspectRatio = intrinsicSizingInfo.size.width() / static_cast<double>(intrinsicSizingInfo.size.height());
     } else {
-        SVGSVGElement* svg = toSVGSVGElement(node());
-        ASSERT(svg);
-
         FloatSize viewBoxSize = svg->viewBox()->currentValue()->value().size();
         if (!viewBoxSize.isEmpty()) {
             // The viewBox can only yield an intrinsic ratio, not an intrinsic size.
             intrinsicSizingInfo.aspectRatio = viewBoxSize.width() / static_cast<double>(viewBoxSize.height());
-            if (!isHorizontalWritingMode())
-                intrinsicSizingInfo.aspectRatio = 1 / intrinsicSizingInfo.aspectRatio;
         }
     }
+
+    if (!isHorizontalWritingMode())
+        intrinsicSizingInfo.transpose();
 }
 
 bool LayoutSVGRoot::isEmbeddedThroughSVGImage() const
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
index 1b56163..4f3d5f5 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGRoot.h
@@ -114,8 +114,6 @@
     void updateCachedBoundaries();
     void buildLocalToBorderBoxTransform();
 
-    FloatSize calculateIntrinsicSize() const;
-
     LayoutObjectChildList m_children;
     IntSize m_containerSize;
     FloatRect m_objectBoundingBox;