<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[277552] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/277552">277552</a></dd>
<dt>Author</dt> <dd>zalan@apple.com</dd>
<dt>Date</dt> <dd>2021-05-15 16:55:58 -0700 (Sat, 15 May 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>[LFC] Move inline formatting geometry to its own class
https://bugs.webkit.org/show_bug.cgi?id=225754

Reviewed by Antti Koivisto.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* layout/formattingContexts/inline/InlineFormattingContext.cpp:
(WebCore::Layout::InlineFormattingContext::geometry const):
* layout/formattingContexts/inline/InlineFormattingContext.h:
(WebCore::Layout::InlineFormattingContext::Geometry::Geometry): Deleted.
* layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp: Removed.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreSourcestxt">trunk/Source/WebCore/Sources.txt</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingContextcpp">trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp</a></li>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingContexth">trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingGeometrycpp">trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp</a></li>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingGeometryh">trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingContextGeometrycpp">trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (277551 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2021-05-15 23:54:52 UTC (rev 277551)
+++ trunk/Source/WebCore/ChangeLog      2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -1,5 +1,20 @@
</span><span class="cx"> 2021-05-15  Alan Bujtas  <zalan@apple.com>
</span><span class="cx"> 
</span><ins>+        [LFC] Move inline formatting geometry to its own class
+        https://bugs.webkit.org/show_bug.cgi?id=225754
+
+        Reviewed by Antti Koivisto.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * layout/formattingContexts/inline/InlineFormattingContext.cpp:
+        (WebCore::Layout::InlineFormattingContext::geometry const):
+        * layout/formattingContexts/inline/InlineFormattingContext.h:
+        (WebCore::Layout::InlineFormattingContext::Geometry::Geometry): Deleted.
+        * layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp: Removed.
+
+2021-05-15  Alan Bujtas  <zalan@apple.com>
+
</ins><span class="cx">         [LFC] Move flex formatting geometry to its own class
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=225755
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreSourcestxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/Sources.txt (277551 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/Sources.txt 2021-05-15 23:54:52 UTC (rev 277551)
+++ trunk/Source/WebCore/Sources.txt    2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -1534,7 +1534,7 @@
</span><span class="cx"> layout/floats/FloatingState.cpp
</span><span class="cx"> layout/formattingContexts/inline/InlineContentBreaker.cpp
</span><span class="cx"> layout/formattingContexts/inline/InlineFormattingContext.cpp
</span><del>-layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp
</del><ins>+layout/formattingContexts/inline/InlineFormattingGeometry.cpp
</ins><span class="cx"> layout/formattingContexts/inline/InlineFormattingQuirks.cpp
</span><span class="cx"> layout/formattingContexts/inline/InlineFormattingState.cpp
</span><span class="cx"> layout/formattingContexts/inline/InlineItem.cpp
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (277551 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj   2021-05-15 23:54:52 UTC (rev 277551)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj      2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -1334,6 +1334,7 @@
</span><span class="cx">          46F02A1A23737F8300106A64 /* EventLoop.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B0ABCA123679AB300B45085 /* EventLoop.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          46FCB6181A70820E00C5A21E /* DiagnosticLoggingKeys.h in Headers */ = {isa = PBXBuildFile; fileRef = CD37B37515C1A7E1006DC898 /* DiagnosticLoggingKeys.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          4786356526507A3800C5E2E0 /* BlockFormattingGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = 4786356426507A3700C5E2E0 /* BlockFormattingGeometry.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+               47C4D57D26508BCB00C7AB1F /* InlineFormattingGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = 47C4D57C26508BCA00C7AB1F /* InlineFormattingGeometry.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">           47F947DB26502F2F0087968C /* BlockFormattingQuirks.h in Headers */ = {isa = PBXBuildFile; fileRef = 47F947DA26502F2F0087968C /* BlockFormattingQuirks.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">          49291E4B134172C800E753DE /* ImageRenderingMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 49291E4A134172C800E753DE /* ImageRenderingMode.h */; };
</span><span class="cx">          493E5E0912D6420500020081 /* PlatformCALayerClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 493E5E0812D6420500020081 /* PlatformCALayerClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -8389,6 +8390,7 @@
</span><span class="cx">          46EFAF101E5FB9E100E7F34B /* LowPowerModeNotifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LowPowerModeNotifier.h; sourceTree = "<group>"; };
</span><span class="cx">          46F91BC91FCDD0FE001599C3 /* JSWorkerNavigatorCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWorkerNavigatorCustom.cpp; sourceTree = "<group>"; };
</span><span class="cx">          4786356426507A3700C5E2E0 /* BlockFormattingGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockFormattingGeometry.h; sourceTree = "<group>"; };
</span><ins>+               47C4D57C26508BCA00C7AB1F /* InlineFormattingGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineFormattingGeometry.h; sourceTree = "<group>"; };
</ins><span class="cx">           47F947DA26502F2F0087968C /* BlockFormattingQuirks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockFormattingQuirks.h; sourceTree = "<group>"; };
</span><span class="cx">          49291E4A134172C800E753DE /* ImageRenderingMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageRenderingMode.h; sourceTree = "<group>"; };
</span><span class="cx">          493E5E0812D6420500020081 /* PlatformCALayerClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformCALayerClient.h; sourceTree = "<group>"; };
</span><span class="lines">@@ -9964,7 +9966,7 @@
</span><span class="cx">          6F26BB6923343E5A002F2BEA /* LayoutContext.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutContext.cpp; sourceTree = "<group>"; };
</span><span class="cx">          6F26BB6B23343E5B002F2BEA /* LayoutContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LayoutContext.h; sourceTree = "<group>"; };
</span><span class="cx">          6F26EB46234004A5006906E2 /* InlineLineBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineLineBuilder.h; sourceTree = "<group>"; };
</span><del>-               6F35EFAF2187CBD50044E0F4 /* InlineFormattingContextGeometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineFormattingContextGeometry.cpp; sourceTree = "<group>"; };
</del><ins>+                6F35EFAF2187CBD50044E0F4 /* InlineFormattingGeometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineFormattingGeometry.cpp; sourceTree = "<group>"; };
</ins><span class="cx">           6F360E4E23999420001512A7 /* InlineSoftLineBreakItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineSoftLineBreakItem.h; sourceTree = "<group>"; };
</span><span class="cx">          6F3FBA962556E308003530FD /* LayoutIntegrationInlineContentBuilder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutIntegrationInlineContentBuilder.cpp; sourceTree = "<group>"; };
</span><span class="cx">          6F3FBA972556E312003530FD /* LayoutIntegrationInlineContentBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutIntegrationInlineContentBuilder.h; sourceTree = "<group>"; };
</span><span class="lines">@@ -18264,7 +18266,8 @@
</span><span class="cx">                          6FE198152178397C00446F08 /* InlineContentBreaker.h */,
</span><span class="cx">                          6F7CA3C9208C2B2E002F29AB /* InlineFormattingContext.cpp */,
</span><span class="cx">                          6F7CA3C8208C2B2E002F29AB /* InlineFormattingContext.h */,
</span><del>-                               6F35EFAF2187CBD50044E0F4 /* InlineFormattingContextGeometry.cpp */,
</del><ins>+                                6F35EFAF2187CBD50044E0F4 /* InlineFormattingGeometry.cpp */,
+                               47C4D57C26508BCA00C7AB1F /* InlineFormattingGeometry.h */,
</ins><span class="cx">                           6F10B08622B8568D0090E69C /* InlineFormattingQuirks.cpp */,
</span><span class="cx">                          6FE636E72647962900F0951E /* InlineFormattingQuirks.h */,
</span><span class="cx">                          115CFA7D208B8E10001E6991 /* InlineFormattingState.cpp */,
</span><span class="lines">@@ -32953,6 +32956,7 @@
</span><span class="cx">                          B57CB52E182A3EFC0079A647 /* InlineElementBox.h in Headers */,
</span><span class="cx">                          A8CFF5E30A155A05000A4234 /* InlineFlowBox.h in Headers */,
</span><span class="cx">                          6F7CA3CA208C2B2E002F29AB /* InlineFormattingContext.h in Headers */,
</span><ins>+                               47C4D57D26508BCB00C7AB1F /* InlineFormattingGeometry.h in Headers */,
</ins><span class="cx">                           6FE636E82647962900F0951E /* InlineFormattingQuirks.h in Headers */,
</span><span class="cx">                          115CFA7E208B8E10001E6991 /* InlineFormattingState.h in Headers */,
</span><span class="cx">                          6FE7CFA22177EEF2005B1573 /* InlineItem.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingContextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp (277551 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp        2021-05-15 23:54:52 UTC (rev 277551)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.cpp   2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include "FloatingContext.h"
</span><span class="cx"> #include "FontCascade.h"
</span><ins>+#include "InlineFormattingGeometry.h"
</ins><span class="cx"> #include "InlineFormattingQuirks.h"
</span><span class="cx"> #include "InlineFormattingState.h"
</span><span class="cx"> #include "InlineLineBox.h"
</span><span class="lines">@@ -606,6 +607,11 @@
</span><span class="cx">     // FIXME: This is also where we would delete inline items if their content changed.
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+InlineFormattingGeometry InlineFormattingContext::geometry() const
+{
+    return InlineFormattingGeometry(*this);
+}
+
</ins><span class="cx"> InlineFormattingQuirks InlineFormattingContext::quirks() const
</span><span class="cx"> {
</span><span class="cx">     return InlineFormattingQuirks(*this);
</span></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingContexth"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h (277551 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h  2021-05-15 23:54:52 UTC (rev 277551)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContext.h     2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> namespace Layout {
</span><span class="cx"> 
</span><ins>+class InlineFormattingGeometry;
</ins><span class="cx"> class InlineFormattingState;
</span><span class="cx"> class InlineFormattingQuirks;
</span><span class="cx"> class InvalidationState;
</span><span class="lines">@@ -58,23 +59,8 @@
</span><span class="cx"> private:
</span><span class="cx">     IntrinsicWidthConstraints computedIntrinsicWidthConstraints() override;
</span><span class="cx"> 
</span><del>-    class Geometry : public FormattingContext::Geometry {
-    public:
-        LineBox lineBoxForLineContent(const LineBuilder::LineContent&);
-        InlineLayoutUnit logicalTopForNextLine(const LineBuilder::LineContent&, InlineLayoutUnit previousLineLogicalBottom, const FloatingContext&) const;
</del><ins>+    InlineFormattingGeometry geometry() const;
</ins><span class="cx"> 
</span><del>-        ContentHeightAndMargin inlineBlockContentHeightAndMargin(const Box&, const HorizontalConstraints&, const OverriddenVerticalValues&) const;
-        ContentWidthAndMargin inlineBlockContentWidthAndMargin(const Box&, const HorizontalConstraints&, const OverriddenHorizontalValues&);
-
-    private:
-        friend class InlineFormattingContext;
-        Geometry(const InlineFormattingContext&);
-
-        const InlineFormattingContext& formattingContext() const { return downcast<InlineFormattingContext>(FormattingContext::Geometry::formattingContext()); }
-
-    };
-    InlineFormattingContext::Geometry geometry() const { return Geometry(*this); }
-
</del><span class="cx">     void lineLayout(InlineItems&, LineBuilder::InlineItemRange, const ConstraintsForInFlowContent&);
</span><span class="cx"> 
</span><span class="cx">     void computeIntrinsicWidthForFormattingRoot(const Box&);
</span><span class="lines">@@ -89,13 +75,8 @@
</span><span class="cx">     void invalidateFormattingState(const InvalidationState&);
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-inline InlineFormattingContext::Geometry::Geometry(const InlineFormattingContext& inlineFormattingContext)
-    : FormattingContext::Geometry(inlineFormattingContext)
-{
</del><span class="cx"> }
</span><del>-
</del><span class="cx"> }
</span><del>-}
</del><span class="cx"> 
</span><span class="cx"> SPECIALIZE_TYPE_TRAITS_LAYOUT_FORMATTING_CONTEXT(InlineFormattingContext, isInlineFormattingContext())
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingContextGeometrycpp"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp (277551 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp        2021-05-15 23:54:52 UTC (rev 277551)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp   2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -1,727 +0,0 @@
</span><del>-/*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "InlineFormattingContext.h"
-
-#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
-
-#include "FloatingContext.h"
-#include "FormattingContext.h"
-#include "InlineLineBox.h"
-#include "LayoutBox.h"
-#include "LayoutContainerBox.h"
-#include "LayoutReplacedBox.h"
-#include "LengthFunctions.h"
-
-namespace WebCore {
-namespace Layout {
-
-class LineBoxBuilder {
-public:
-    LineBoxBuilder(const InlineFormattingContext&);
-    LineBox build(const LineBuilder::LineContent&);
-
-private:
-    struct SimplifiedVerticalAlignment {
-        SimplifiedVerticalAlignment(const LineBox::InlineLevelBox& rootInlineBox);
-
-        static bool canUseSimplifiedAlignment(const LineBox::InlineLevelBox& rootInlineBox, const LineBox::InlineLevelBox&, Optional<const BoxGeometry> inlineLevelBoxGeometry);
-
-        void align(LineBox::InlineLevelBox&);
-
-        InlineLayoutUnit rootInlineBoxLogicalTop() const { return m_rootInlineBoxLogicalTop; }
-        InlineLayoutUnit lineBoxHeight() const { return m_lineBoxLogicalBottom - m_lineBoxLogicalTop; }
-
-        void setEnabled(bool enabled) { m_isEnabled = enabled; }
-        bool isEnabled() const { return m_isEnabled; }
-
-    private:
-        void adjust(const LineBox::InlineLevelBox&);
-
-        const LineBox::InlineLevelBox& m_rootInlineBox;
-        bool m_isEnabled { true };
-        InlineLayoutUnit m_lineBoxLogicalTop { 0 };
-        InlineLayoutUnit m_lineBoxLogicalBottom { 0 };
-        InlineLayoutUnit m_rootInlineBoxLogicalTop { 0 };
-    };
-
-    void setVerticalGeometryForInlineBox(LineBox::InlineLevelBox&) const;
-    void constructAndAlignInlineLevelBoxes(LineBox&, const Line::RunList&);
-    void computeLineBoxHeightAndAlignInlineLevelBoxesVertically(LineBox&);
-
-    const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
-    const Box& rootBox() const { return formattingContext().root(); }
-    LayoutState& layoutState() const { return formattingContext().layoutState(); }
-
-    bool isRootLayoutBox(const ContainerBox& containerBox) const { return &containerBox == &rootBox(); }
-
-private:
-    const InlineFormattingContext& m_inlineFormattingContext;
-};
-
-struct HangingTrailingWhitespaceContent {
-public:
-    void reset();
-
-    InlineLayoutUnit width() const { return m_width; }
-    bool isConditional() const { return m_isConditional; }
-
-    void setIsConditional() { m_isConditional = true; }
-    void expand(InlineLayoutUnit width) { m_width += width; }
-
-private:
-    bool m_isConditional { false };
-    InlineLayoutUnit m_width { 0 };
-};
-
-void HangingTrailingWhitespaceContent::reset()
-{
-    m_isConditional = false;
-    m_width =  0;
-}
-
-static HangingTrailingWhitespaceContent collectHangingTrailingWhitespaceContent(const Line::RunList& runs, bool isLastLineWithInlineContent)
-{
-    auto hangingContent = HangingTrailingWhitespaceContent { };
-    if (isLastLineWithInlineContent)
-        hangingContent.setIsConditional();
-    for (auto& run : WTF::makeReversedRange(runs)) {
-        if (run.isInlineBoxStart() || run.isInlineBoxEnd())
-            continue;
-        if (run.isLineBreak()) {
-            hangingContent.setIsConditional();
-            continue;
-        }
-        if (!run.hasTrailingWhitespace())
-            break;
-        // Check if we have a preserved or hung whitespace.
-        if (run.style().whiteSpace() != WhiteSpace::PreWrap)
-            break;
-        // This is either a normal or conditionally hanging trailing whitespace.
-        hangingContent.expand(run.trailingWhitespaceWidth());
-    }
-    return hangingContent;
-}
-
-static Optional<InlineLayoutUnit> horizontalAlignmentOffset(const Line::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, bool isLastLine)
-{
-    auto availableWidth = lineLogicalWidth - contentLogicalWidth;
-    auto hangingTrailingWhitespaceContent = collectHangingTrailingWhitespaceContent(runs, isLastLine);
-    availableWidth += hangingTrailingWhitespaceContent.width();
-    if (availableWidth <= 0)
-        return { };
-
-    auto computedHorizontalAlignment = [&] {
-        if (textAlign != TextAlignMode::Justify)
-            return textAlign;
-        // Text is justified according to the method specified by the text-justify property,
-        // in order to exactly fill the line box. Unless otherwise specified by text-align-last,
-        // the last line before a forced break or the end of the block is start-aligned.
-        if (isLastLine || (!runs.isEmpty() && runs.last().isLineBreak()))
-            return TextAlignMode::Start;
-        return TextAlignMode::Justify;
-    };
-
-    switch (computedHorizontalAlignment()) {
-    case TextAlignMode::Left:
-    case TextAlignMode::WebKitLeft:
-    case TextAlignMode::Start:
-        return { };
-    case TextAlignMode::Right:
-    case TextAlignMode::WebKitRight:
-    case TextAlignMode::End:
-        return availableWidth;
-    case TextAlignMode::Center:
-    case TextAlignMode::WebKitCenter:
-        return availableWidth / 2;
-    case TextAlignMode::Justify:
-        // TextAlignMode::Justify is a run alignment (and we only do inline box alignment here)
-        return { };
-    default:
-        ASSERT_NOT_IMPLEMENTED_YET();
-        return { };
-    }
-    ASSERT_NOT_REACHED();
-    return { };
-}
-
-LineBoxBuilder::LineBoxBuilder(const InlineFormattingContext& inlineFormattingContext)
-    : m_inlineFormattingContext(inlineFormattingContext)
-{
-}
-
-LineBox LineBoxBuilder::build(const LineBuilder::LineContent& lineContent)
-{
-    auto& runs = lineContent.runs;
-    auto lineLogicalWidth = lineContent.lineLogicalWidth;
-    auto contentLogicalWidth = lineContent.contentLogicalWidth;
-    auto horizontalAlignmentOffset = Layout::horizontalAlignmentOffset(runs, rootBox().style().textAlign(), lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent);
-    auto lineBox = LineBox { rootBox(), lineContent.logicalTopLeft, lineLogicalWidth, horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }), contentLogicalWidth, lineContent.nonSpanningInlineLevelBoxCount };
-    constructAndAlignInlineLevelBoxes(lineBox, runs);
-    return lineBox;
-}
-
-void LineBoxBuilder::setVerticalGeometryForInlineBox(LineBox::InlineLevelBox& inlineLevelBox) const
-{
-    ASSERT(inlineLevelBox.isInlineBox() || inlineLevelBox.isLineBreakBox());
-    auto& fontMetrics = inlineLevelBox.style().fontMetrics();
-    InlineLayoutUnit ascent = fontMetrics.ascent();
-    InlineLayoutUnit descent = fontMetrics.descent();
-    auto logicalHeight = ascent + descent;
-    // We need floor/ceil to match legacy layout integral positioning.
-    inlineLevelBox.setBaseline(floorf(ascent));
-    inlineLevelBox.setDescent(ceil(descent));
-    inlineLevelBox.setLogicalHeight(logicalHeight);
-
-    // FIXME: Adjust layout bounds with fallback font when applicable.
-    auto& style = inlineLevelBox.layoutBox().style();
-    auto lineHeight = style.lineHeight();
-    if (lineHeight.isNegative()) {
-        // If line-height computes to normal and either text-edge is leading or this is the root inline box,
-        // the font’s line gap metric may also be incorporated into A and D by adding half to each side as half-leading.
-        // https://www.w3.org/TR/css-inline-3/#inline-height
-        // Since text-edge is not supported yet and the initial value is leading, we should just apply it to
-        // all inline boxes.
-        auto halfLineGap = (fontMetrics.lineSpacing() - logicalHeight) / 2;
-        ascent += halfLineGap;
-        descent += halfLineGap;
-    } else {
-        InlineLayoutUnit lineHeight = style.computedLineHeight();
-        InlineLayoutUnit halfLeading = (lineHeight - (ascent + descent)) / 2;
-        ascent += halfLeading;
-        descent += halfLeading;
-    }
-    // We need floor/ceil to match legacy layout integral positioning.
-    inlineLevelBox.setLayoutBounds(LineBox::InlineLevelBox::LayoutBounds { floorf(ascent), ceil(descent) });
-}
-
-void LineBoxBuilder::constructAndAlignInlineLevelBoxes(LineBox& lineBox, const Line::RunList& runs)
-{
-    auto& rootInlineBox = lineBox.rootInlineBox();
-    setVerticalGeometryForInlineBox(rootInlineBox);
-
-    auto simplifiedVerticalAlignment = SimplifiedVerticalAlignment { rootInlineBox };
-    // FIXME: Add fast path support for line-height content.
-    simplifiedVerticalAlignment.setEnabled(layoutState().inStandardsMode() && rootBox().style().lineHeight().isNegative());
-
-    auto simplifiedAlignVerticallyIfApplicable = [&](auto& inlineLevelBox, Optional<const BoxGeometry> boxGeometry) {
-        if (!simplifiedVerticalAlignment.isEnabled())
-            return;
-        if (!SimplifiedVerticalAlignment::canUseSimplifiedAlignment(rootInlineBox, inlineLevelBox, boxGeometry)) {
-            simplifiedVerticalAlignment.setEnabled(false);
-            return;
-        }
-        simplifiedVerticalAlignment.align(inlineLevelBox);
-    };
-
-    auto createWrappedInlineBoxes = [&] {
-        if (runs.isEmpty())
-            return;
-        // An inline box may not necessarily start on the current line:
-        // <span id=outer>line break<br>this content's parent inline box('outer') <span id=inner>starts on the previous line</span></span>
-        // We need to make sure that there's an LineBox::InlineLevelBox for every inline box that's present on the current line.
-        // In nesting case we need to create LineBox::InlineLevelBoxes for the inline box ancestors.
-        // We only have to do it on the first run as any subsequent inline content is either at the same/higher nesting level or
-        // nested with a [inline box start] run.
-        auto& firstRun = runs[0];
-        auto& firstRunParentLayoutBox = firstRun.layoutBox().parent();
-        // If the parent is the formatting root, we can stop here. This is root inline box content, there's no nesting inline box from the previous line(s)
-        // unless the inline box closing is forced over to the current line.
-        // e.g.
-        // <span>normally the inline box closing forms a continuous content</span>
-        // <span>unless it's forced to the next line<br></span>
-        auto firstRunNeedsInlineBox = firstRun.isInlineBoxEnd();
-        if (!firstRunNeedsInlineBox && isRootLayoutBox(firstRunParentLayoutBox))
-            return;
-        Vector<const Box*> layoutBoxesWithoutInlineBoxes;
-        if (firstRunNeedsInlineBox)
-            layoutBoxesWithoutInlineBoxes.append(&firstRun.layoutBox());
-        auto* ancestor = &firstRunParentLayoutBox;
-        while (!isRootLayoutBox(*ancestor)) {
-            layoutBoxesWithoutInlineBoxes.append(ancestor);
-            ancestor = &ancestor->parent();
-        }
-        // Construct the missing LineBox::InlineBoxes starting with the topmost layout box.
-        for (auto* layoutBox : WTF::makeReversedRange(layoutBoxesWithoutInlineBoxes)) {
-            auto inlineBox = LineBox::InlineLevelBox::createInlineBox(*layoutBox, rootInlineBox.logicalLeft(), lineBox.contentLogicalWidth());
-            setVerticalGeometryForInlineBox(inlineBox);
-            simplifiedAlignVerticallyIfApplicable(inlineBox, { });
-            lineBox.addInlineLevelBox(WTFMove(inlineBox));
-        }
-    };
-    createWrappedInlineBoxes();
-
-    auto lineHasContent = false;
-    for (auto& run : runs) {
-        auto& layoutBox = run.layoutBox();
-        auto runHasContent = [&] () -> bool {
-            ASSERT(!lineHasContent);
-            if (run.isText() || run.isBox() || run.isSoftLineBreak() || run.isHardLineBreak())
-                return true;
-            auto& inlineBoxGeometry = formattingContext().geometryForBox(layoutBox);
-            // Even negative horizontal margin makes the line "contentful".
-            if (run.isInlineBoxStart())
-                return inlineBoxGeometry.marginStart() || inlineBoxGeometry.borderLeft() || inlineBoxGeometry.paddingLeft().valueOr(0_lu);
-            if (run.isInlineBoxEnd())
-                return inlineBoxGeometry.marginEnd() || inlineBoxGeometry.borderRight() || inlineBoxGeometry.paddingRight().valueOr(0_lu);
-            if (run.isWordBreakOpportunity())
-                return false;
-            ASSERT_NOT_REACHED();
-            return true;
-        };
-        lineHasContent = lineHasContent || runHasContent();
-        auto logicalLeft = rootInlineBox.logicalLeft() + run.logicalLeft();
-        if (run.isBox()) {
-            auto& inlineLevelBoxGeometry = formattingContext().geometryForBox(layoutBox);
-            auto marginBoxHeight = inlineLevelBoxGeometry.marginBoxHeight();
-            auto ascent = InlineLayoutUnit { };
-            if (layoutState().shouldNotSynthesizeInlineBlockBaseline()) {
-                // Integration codepath constructs replaced boxes for inline-block content.
-                ASSERT(layoutBox.isReplacedBox());
-                ascent = *downcast<ReplacedBox>(layoutBox).baseline();
-            } else if (layoutBox.isInlineBlockBox()) {
-                // The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or
-                // if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.
-                auto synthesizeBaseline = !layoutBox.establishesInlineFormattingContext() || !layoutBox.style().isOverflowVisible();
-                if (synthesizeBaseline)
-                    ascent = marginBoxHeight;
-                else {
-                    auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
-                    auto& lastLine = formattingState.lines().last();
-                    auto inlineBlockBaseline = lastLine.lineBoxLogicalRect().top() + lastLine.baseline();
-                    ascent = inlineLevelBoxGeometry.marginBefore() + inlineLevelBoxGeometry.borderTop() + inlineLevelBoxGeometry.paddingTop().valueOr(0) + inlineBlockBaseline;
-                }
-            } else if (layoutBox.isReplacedBox())
-                ascent = downcast<ReplacedBox>(layoutBox).baseline().valueOr(marginBoxHeight);
-            else
-                ascent = marginBoxHeight;
-            logicalLeft += std::max(0_lu, inlineLevelBoxGeometry.marginStart());
-            auto atomicInlineLevelBox = LineBox::InlineLevelBox::createAtomicInlineLevelBox(layoutBox, logicalLeft, { inlineLevelBoxGeometry.borderBoxWidth(), marginBoxHeight });
-            atomicInlineLevelBox.setBaseline(ascent);
-            atomicInlineLevelBox.setLayoutBounds(LineBox::InlineLevelBox::LayoutBounds { ascent, marginBoxHeight - ascent });
-            simplifiedAlignVerticallyIfApplicable(atomicInlineLevelBox, inlineLevelBoxGeometry);
-            lineBox.addInlineLevelBox(WTFMove(atomicInlineLevelBox));
-            continue;
-        }
-        if (run.isInlineBoxStart()) {
-            // At this point we don't know yet how wide this inline box is. Let's assume it's as long as the line is
-            // and adjust it later if we come across an inlineBoxEnd run (see below).
-            auto initialLogicalWidth = lineBox.contentLogicalWidth() - run.logicalLeft();
-            ASSERT(initialLogicalWidth >= 0);
-            // Inline box run is based on margin box. Let's convert it to border box.
-            auto marginStart = std::max(0_lu, formattingContext().geometryForBox(layoutBox).marginStart());
-            logicalLeft += marginStart;
-            initialLogicalWidth -= marginStart;
-            auto inlineBox = LineBox::InlineLevelBox::createInlineBox(layoutBox, logicalLeft, initialLogicalWidth);
-            setVerticalGeometryForInlineBox(inlineBox);
-            simplifiedAlignVerticallyIfApplicable(inlineBox, { });
-            lineBox.addInlineLevelBox(WTFMove(inlineBox));
-            continue;
-        }
-        if (run.isInlineBoxEnd()) {
-            // Adjust the logical width when the inline box closes on this line.
-            auto& inlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox);
-            ASSERT(inlineBox.isInlineBox());
-            // Inline box run is based on margin box. Let's convert it to border box.
-            auto marginEnd = std::max(0_lu, formattingContext().geometryForBox(layoutBox).marginEnd());
-            auto inlineBoxLogicalRight = logicalLeft + run.logicalWidth() - marginEnd;
-            inlineBox.setLogicalWidth(inlineBoxLogicalRight - inlineBox.logicalLeft());
-            simplifiedAlignVerticallyIfApplicable(inlineBox, { });
-            continue;
-        }
-        if (run.isText() || run.isSoftLineBreak()) {
-            // FIXME: Adjust non-empty inline box height when glyphs from the non-primary font stretch the box.
-            lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()).setHasContent();
-            continue;
-        }
-        if (run.isHardLineBreak()) {
-            auto lineBreakBox = LineBox::InlineLevelBox::createLineBreakBox(layoutBox, logicalLeft);
-            setVerticalGeometryForInlineBox(lineBreakBox);
-            simplifiedAlignVerticallyIfApplicable(lineBreakBox, { });
-            lineBox.addInlineLevelBox(WTFMove(lineBreakBox));
-            continue;
-        }
-        if (run.isWordBreakOpportunity()) {
-            lineBox.addInlineLevelBox(LineBox::InlineLevelBox::createGenericInlineLevelBox(layoutBox, logicalLeft));
-            continue;
-        }
-        ASSERT_NOT_REACHED();
-    }
-
-    lineBox.setHasContent(lineHasContent);
-    if (simplifiedVerticalAlignment.isEnabled() || !lineHasContent) {
-        // We should always be able to exercise the fast path when the line has no content at all, even in non-standards mode or with line-height set.
-        rootInlineBox.setLogicalTop(lineHasContent ? simplifiedVerticalAlignment.rootInlineBoxLogicalTop() : -rootInlineBox.baseline());
-        lineBox.setLogicalHeight(lineHasContent ? simplifiedVerticalAlignment.lineBoxHeight() : InlineLayoutUnit());
-    } else
-        computeLineBoxHeightAndAlignInlineLevelBoxesVertically(lineBox);
-}
-
-void LineBoxBuilder::computeLineBoxHeightAndAlignInlineLevelBoxesVertically(LineBox& lineBox)
-{
-    ASSERT(lineBox.hasContent());
-    // This function (partially) implements:
-    // 2.2. Layout Within Line Boxes
-    // https://www.w3.org/TR/css-inline-3/#line-layout
-    // 1. Compute the line box height using the layout bounds geometry. This height computation strictly uses layout bounds and not normal inline level box geometries.
-    // 2. Compute the baseline/logical top position of the root inline box. Aligned boxes push the root inline box around inside the line box.
-    // 3. Finally align the inline level boxes using (mostly) normal inline level box geometries.
-    auto quirks = formattingContext().quirks();
-    auto& rootInlineBox = lineBox.rootInlineBox();
-
-    auto computeLineBoxLogicalHeight = [&] {
-        // Line box height computation is based on the layout bounds of the inline boxes and not their logical (ascent/descent) dimensions.
-        struct AbsoluteTopAndBottom {
-            InlineLayoutUnit top { 0 };
-            InlineLayoutUnit bottom { 0 };
-        };
-        HashMap<const LineBox::InlineLevelBox*, AbsoluteTopAndBottom> inlineLevelBoxAbsoluteTopAndBottomMap;
-
-        auto minimumLogicalTop = Optional<InlineLayoutUnit> { };
-        auto maximumLogicalBottom = Optional<InlineLayoutUnit> { };
-        if (quirks.inlineLevelBoxAffectsLineBox(rootInlineBox, lineBox)) {
-            minimumLogicalTop = InlineLayoutUnit { };
-            maximumLogicalBottom = rootInlineBox.layoutBounds().height();
-            inlineLevelBoxAbsoluteTopAndBottomMap.add(&rootInlineBox, AbsoluteTopAndBottom { *minimumLogicalTop, *maximumLogicalBottom });
-        } else
-            inlineLevelBoxAbsoluteTopAndBottomMap.add(&rootInlineBox, AbsoluteTopAndBottom { });
-
-        Vector<LineBox::InlineLevelBox*> lineBoxRelativeInlineLevelBoxes;
-        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
-            auto& layoutBox = inlineLevelBox.layoutBox();
-            if (inlineLevelBox.hasLineBoxRelativeAlignment()) {
-                lineBoxRelativeInlineLevelBoxes.append(&inlineLevelBox);
-                continue;
-            }
-            auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent());
-            // Logical top is relative to the parent inline box's layout bounds.
-            // Note that this logical top is not the final logical top of the inline level box.
-            // This is the logical top in the context of the layout bounds geometry which may be very different from the inline box's normal geometry.
-            auto logicalTop = InlineLayoutUnit { };
-            switch (inlineLevelBox.verticalAlign()) {
-            case VerticalAlign::Baseline: {
-                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().ascent;
-                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
-                break;
-            }
-            case VerticalAlign::Middle: {
-                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().height() / 2 + parentInlineBox.style().fontMetrics().xHeight() / 2;
-                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
-                break;
-            }
-            case VerticalAlign::BaselineMiddle: {
-                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().height() / 2;
-                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
-                break;
-            }
-            case VerticalAlign::Length: {
-                auto& style = inlineLevelBox.style();
-                auto logicalTopOffsetFromParentBaseline = floatValueForLength(style.verticalAlignLength(), style.computedLineHeight()) + inlineLevelBox.layoutBounds().ascent;
-                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
-                break;
-            }
-            case VerticalAlign::TextTop: {
-                // Note that text-top aligns with the inline box's font metrics top (ascent) and not the layout bounds top.
-                logicalTop = parentInlineBox.layoutBounds().ascent - parentInlineBox.baseline();
-                break;
-            }
-            case VerticalAlign::TextBottom: {
-                // Note that text-bottom aligns with the inline box's font metrics bottom (descent) and not the layout bounds bottom.
-                auto parentInlineBoxLayoutBounds = parentInlineBox.layoutBounds();
-                auto parentInlineBoxLogicalBottom = parentInlineBoxLayoutBounds.height() - parentInlineBoxLayoutBounds.descent + parentInlineBox.descent().valueOr(InlineLayoutUnit());
-                logicalTop = parentInlineBoxLogicalBottom - inlineLevelBox.layoutBounds().height();
-                break;
-            }
-            default:
-                ASSERT_NOT_IMPLEMENTED_YET();
-                break;
-            }
-            auto parentInlineBoxAbsoluteTopAndBottom = inlineLevelBoxAbsoluteTopAndBottomMap.get(&parentInlineBox);
-            auto absoluteLogicalTop = parentInlineBoxAbsoluteTopAndBottom.top + logicalTop;
-            auto absoluteLogicalBottom = absoluteLogicalTop + inlineLevelBox.layoutBounds().height();
-            inlineLevelBoxAbsoluteTopAndBottomMap.add(&inlineLevelBox, AbsoluteTopAndBottom { absoluteLogicalTop, absoluteLogicalBottom });
-            // Stretch the min/max absolute values if applicable.
-            if (quirks.inlineLevelBoxAffectsLineBox(inlineLevelBox, lineBox)) {
-                minimumLogicalTop = std::min(minimumLogicalTop.valueOr(absoluteLogicalTop), absoluteLogicalTop);
-                maximumLogicalBottom = std::max(maximumLogicalBottom.valueOr(absoluteLogicalBottom), absoluteLogicalBottom);
-            }
-        }
-        // The line box height computation is as follows:
-        // 1. Stretch the line box with the non-line-box relative aligned inline box absolute top and bottom values.
-        // 2. Check if the line box relative aligned inline boxes (top, bottom etc) have enough room and stretch the line box further if needed.
-        auto lineBoxLogicalHeight = maximumLogicalBottom.valueOr(InlineLayoutUnit()) - minimumLogicalTop.valueOr(InlineLayoutUnit());
-        for (auto* lineBoxRelativeInlineLevelBox : lineBoxRelativeInlineLevelBoxes) {
-            if (!quirks.inlineLevelBoxAffectsLineBox(*lineBoxRelativeInlineLevelBox, lineBox))
-                continue;
-            lineBoxLogicalHeight = std::max(lineBoxLogicalHeight, lineBoxRelativeInlineLevelBox->layoutBounds().height());
-        }
-        lineBox.setLogicalHeight(lineBoxLogicalHeight);
-    };
-    computeLineBoxLogicalHeight();
-
-    auto computeRootInlineBoxVerticalPosition = [&] {
-        HashMap<const LineBox::InlineLevelBox*, InlineLayoutUnit> inlineLevelBoxAbsoluteBaselineOffsetMap;
-        inlineLevelBoxAbsoluteBaselineOffsetMap.add(&rootInlineBox, InlineLayoutUnit { });
-
-        auto maximumTopOffsetFromRootInlineBoxBaseline = Optional<InlineLayoutUnit> { };
-        if (quirks.inlineLevelBoxAffectsLineBox(rootInlineBox, lineBox))
-            maximumTopOffsetFromRootInlineBoxBaseline = rootInlineBox.layoutBounds().ascent;
-
-        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
-            auto absoluteBaselineOffset = InlineLayoutUnit { };
-            if (!inlineLevelBox.hasLineBoxRelativeAlignment()) {
-                auto& layoutBox = inlineLevelBox.layoutBox();
-                auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent());
-                auto baselineOffsetFromParentBaseline = InlineLayoutUnit { };
-
-                switch (inlineLevelBox.verticalAlign()) {
-                case VerticalAlign::Baseline:
-                    baselineOffsetFromParentBaseline = { };
-                    break;
-                case VerticalAlign::Middle: {
-                    auto logicalTopOffsetFromParentBaseline = (inlineLevelBox.layoutBounds().height() / 2 + parentInlineBox.style().fontMetrics().xHeight() / 2);
-                    baselineOffsetFromParentBaseline = logicalTopOffsetFromParentBaseline - inlineLevelBox.layoutBounds().ascent;
-                    break;
-                }
-                case VerticalAlign::BaselineMiddle: {
-                    auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().height() / 2;
-                    baselineOffsetFromParentBaseline = logicalTopOffsetFromParentBaseline - inlineLevelBox.layoutBounds().ascent;
-                    break;
-                }
-                case VerticalAlign::Length: {
-                    auto& style = inlineLevelBox.style();
-                    auto verticalAlignOffset = floatValueForLength(style.verticalAlignLength(), style.computedLineHeight());
-                    auto logicalTopOffsetFromParentBaseline = verticalAlignOffset + inlineLevelBox.baseline();
-                    baselineOffsetFromParentBaseline = logicalTopOffsetFromParentBaseline - inlineLevelBox.baseline();
-                    break;
-                }
-                case VerticalAlign::TextTop:
-                    baselineOffsetFromParentBaseline = parentInlineBox.baseline() - inlineLevelBox.layoutBounds().ascent;
-                    break;
-                case VerticalAlign::TextBottom:
-                    baselineOffsetFromParentBaseline = inlineLevelBox.layoutBounds().descent - *parentInlineBox.descent();
-                    break;
-                default:
-                    ASSERT_NOT_IMPLEMENTED_YET();
-                    break;
-                }
-                absoluteBaselineOffset = inlineLevelBoxAbsoluteBaselineOffsetMap.get(&parentInlineBox) + baselineOffsetFromParentBaseline;
-            } else {
-                switch (inlineLevelBox.verticalAlign()) {
-                case VerticalAlign::Top: {
-                    absoluteBaselineOffset = rootInlineBox.layoutBounds().ascent - inlineLevelBox.layoutBounds().ascent;
-                    break;
-                }
-                case VerticalAlign::Bottom: {
-                    absoluteBaselineOffset = inlineLevelBox.layoutBounds().descent - rootInlineBox.layoutBounds().descent;
-                    break;
-                }
-                default:
-                    ASSERT_NOT_IMPLEMENTED_YET();
-                    break;
-                }
-            }
-            inlineLevelBoxAbsoluteBaselineOffsetMap.add(&inlineLevelBox, absoluteBaselineOffset);
-            auto affectsRootInlineBoxVerticalPosition = quirks.inlineLevelBoxAffectsLineBox(inlineLevelBox, lineBox);
-            if (affectsRootInlineBoxVerticalPosition) {
-                auto topOffsetFromRootInlineBoxBaseline = absoluteBaselineOffset + inlineLevelBox.layoutBounds().ascent;
-                if (maximumTopOffsetFromRootInlineBoxBaseline)
-                    maximumTopOffsetFromRootInlineBoxBaseline = std::max(*maximumTopOffsetFromRootInlineBoxBaseline, topOffsetFromRootInlineBoxBaseline);
-                else {
-                    // We are is quirk mode and the root inline box has no content. The root inline box's baseline is anchored at 0.
-                    // However negative ascent (e.g negative top margin) can "push" the root inline box upwards and have a negative value.
-                    maximumTopOffsetFromRootInlineBoxBaseline = inlineLevelBox.layoutBounds().ascent >= 0
-                        ? std::max(0.0f, topOffsetFromRootInlineBoxBaseline)
-                        : topOffsetFromRootInlineBoxBaseline;
-                }
-            }
-        }
-        auto rootInlineBoxLogicalTop = maximumTopOffsetFromRootInlineBoxBaseline.valueOr(0.f) - rootInlineBox.baseline();
-        rootInlineBox.setLogicalTop(rootInlineBoxLogicalTop);
-    };
-    computeRootInlineBoxVerticalPosition();
-
-    auto alignInlineLevelBoxes = [&] {
-        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
-            auto& layoutBox = inlineLevelBox.layoutBox();
-            auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent());
-            auto logicalTop = InlineLayoutUnit { };
-            switch (inlineLevelBox.verticalAlign()) {
-            case VerticalAlign::Baseline:
-                logicalTop = parentInlineBox.baseline() - inlineLevelBox.baseline();
-                break;
-            case VerticalAlign::Middle: {
-                auto logicalTopOffsetFromParentBaseline = (inlineLevelBox.logicalHeight() / 2 + parentInlineBox.style().fontMetrics().xHeight() / 2);
-                logicalTop = parentInlineBox.baseline() - logicalTopOffsetFromParentBaseline;
-                break;
-            }
-            case VerticalAlign::BaselineMiddle: {
-                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.logicalHeight() / 2;
-                logicalTop = parentInlineBox.baseline() - logicalTopOffsetFromParentBaseline;
-                break;
-            }
-            case VerticalAlign::Length: {
-                auto& style = inlineLevelBox.style();
-                auto verticalAlignOffset = floatValueForLength(style.verticalAlignLength(), style.computedLineHeight());
-                auto logicalTopOffsetFromParentBaseline = verticalAlignOffset + inlineLevelBox.baseline();
-                logicalTop = parentInlineBox.baseline() - logicalTopOffsetFromParentBaseline;
-                break;
-            }
-            // Note that (text)top/bottom align their layout bounds.
-            case VerticalAlign::TextTop:
-                logicalTop = inlineLevelBox.layoutBounds().ascent - inlineLevelBox.baseline();
-                break;
-            case VerticalAlign::TextBottom:
-                logicalTop = parentInlineBox.logicalHeight() - inlineLevelBox.layoutBounds().descent - inlineLevelBox.baseline();
-                break;
-            case VerticalAlign::Top:
-                // Note that this logical top is not relative to the parent inline box.
-                logicalTop = inlineLevelBox.layoutBounds().ascent - inlineLevelBox.baseline();
-                break;
-            case VerticalAlign::Bottom:
-                // Note that this logical top is not relative to the parent inline box.
-                logicalTop = lineBox.logicalHeight() - inlineLevelBox.layoutBounds().descent - inlineLevelBox.baseline();
-                break;
-            default:
-                ASSERT_NOT_IMPLEMENTED_YET();
-                break;
-            }
-            inlineLevelBox.setLogicalTop(logicalTop);
-        }
-    };
-    alignInlineLevelBoxes();
-}
-
-LineBoxBuilder::SimplifiedVerticalAlignment::SimplifiedVerticalAlignment(const LineBox::InlineLevelBox& rootInlineBox)
-    : m_rootInlineBox(rootInlineBox)
-{
-    adjust(rootInlineBox);
-}
-
-bool LineBoxBuilder::SimplifiedVerticalAlignment::canUseSimplifiedAlignment(const LineBox::InlineLevelBox& rootInlineBox, const LineBox::InlineLevelBox& inlineLevelBox, Optional<const BoxGeometry> inlineLevelBoxGeometry)
-{
-    if (inlineLevelBox.isAtomicInlineLevelBox()) {
-        ASSERT(inlineLevelBoxGeometry);
-        // Baseline aligned, non-stretchy direct children are considered to be simple for now.
-        auto& layoutBox = inlineLevelBox.layoutBox();
-        return &layoutBox.parent() == &rootInlineBox.layoutBox()
-            && layoutBox.style().verticalAlign() == VerticalAlign::Baseline
-            && !inlineLevelBoxGeometry->marginBefore()
-            && !inlineLevelBoxGeometry->marginAfter()
-            && inlineLevelBoxGeometry->marginBoxHeight() <= rootInlineBox.baseline();
-    }
-    if (inlineLevelBox.isLineBreakBox()) {
-        // Baseline aligned, non-stretchy line breaks e.g. <div><span><br></span></div> but not <div><span style="font-size: 100px;"><br></span></div>.
-        return inlineLevelBox.layoutBox().style().verticalAlign() == VerticalAlign::Baseline && inlineLevelBox.baseline() <= rootInlineBox.baseline();
-    }
-    if (inlineLevelBox.isInlineBox()) {
-        // Baseline aligned, non-stretchy inline boxes e.g. <div><span></span></div> but not <div><span style="font-size: 100px;"></span></div>.
-        return inlineLevelBox.layoutBox().style().verticalAlign() == VerticalAlign::Baseline && inlineLevelBox.layoutBounds() == rootInlineBox.layoutBounds();
-    }
-    return false;
-}
-
-void LineBoxBuilder::SimplifiedVerticalAlignment::align(LineBox::InlineLevelBox& inlineLevelBox)
-{
-    if (inlineLevelBox.isAtomicInlineLevelBox() || inlineLevelBox.isLineBreakBox() || inlineLevelBox.isInlineBox()) {
-        // Only baseline alignment for now.
-        inlineLevelBox.setLogicalTop(m_rootInlineBox.baseline() - inlineLevelBox.baseline());
-        adjust(inlineLevelBox);
-        return;
-    }
-    ASSERT_NOT_IMPLEMENTED_YET();
-}
-
-void LineBoxBuilder::SimplifiedVerticalAlignment::adjust(const LineBox::InlineLevelBox& inlineLevelBox)
-{
-    auto layoutBoundsLogicalTop = m_rootInlineBox.layoutBounds().ascent - inlineLevelBox.layoutBounds().ascent;
-    m_lineBoxLogicalTop = std::min(m_lineBoxLogicalTop, layoutBoundsLogicalTop);
-    m_lineBoxLogicalBottom = std::max(m_lineBoxLogicalBottom, layoutBoundsLogicalTop + inlineLevelBox.layoutBounds().height());
-    m_rootInlineBoxLogicalTop = std::max(m_rootInlineBoxLogicalTop, inlineLevelBox.layoutBounds().ascent - m_rootInlineBox.baseline());
-}
-
-LineBox InlineFormattingContext::Geometry::lineBoxForLineContent(const LineBuilder::LineContent& lineContent)
-{
-    return LineBoxBuilder(formattingContext()).build(lineContent);
-}
-
-InlineLayoutUnit InlineFormattingContext::Geometry::logicalTopForNextLine(const LineBuilder::LineContent& lineContent, InlineLayoutUnit previousLineLogicalBottom, const FloatingContext& floatingContext) const
-{
-    // Normally the next line's logical top is the previous line's logical bottom, but when the line ends
-    // with the clear property set, the next line needs to clear the existing floats.
-    if (lineContent.runs.isEmpty())
-        return previousLineLogicalBottom;
-    auto& lastRunLayoutBox = lineContent.runs.last().layoutBox(); 
-    if (lastRunLayoutBox.style().clear() == Clear::None)
-        return previousLineLogicalBottom;
-    auto positionWithClearance = floatingContext.verticalPositionWithClearance(lastRunLayoutBox);
-    if (!positionWithClearance)
-        return previousLineLogicalBottom;
-    return std::max(previousLineLogicalBottom, InlineLayoutUnit(positionWithClearance->position));
-}
-
-ContentWidthAndMargin InlineFormattingContext::Geometry::inlineBlockContentWidthAndMargin(const Box& formattingContextRoot, const HorizontalConstraints& horizontalConstraints, const OverriddenHorizontalValues& overriddenHorizontalValues)
-{
-    ASSERT(formattingContextRoot.isInFlow());
-
-    // 10.3.10 'Inline-block', replaced elements in normal flow
-
-    // Exactly as inline replaced elements.
-    if (formattingContextRoot.isReplacedBox())
-        return inlineReplacedContentWidthAndMargin(downcast<ReplacedBox>(formattingContextRoot), horizontalConstraints, { }, overriddenHorizontalValues);
-
-    // 10.3.9 'Inline-block', non-replaced elements in normal flow
-
-    // If 'width' is 'auto', the used value is the shrink-to-fit width as for floating elements.
-    // A computed value of 'auto' for 'margin-left' or 'margin-right' becomes a used value of '0'.
-    // #1
-    auto width = computedValue(formattingContextRoot.style().logicalWidth(), horizontalConstraints.logicalWidth);
-    if (!width)
-        width = shrinkToFitWidth(formattingContextRoot, horizontalConstraints.logicalWidth);
-
-    // #2
-    auto computedHorizontalMargin = Geometry::computedHorizontalMargin(formattingContextRoot, horizontalConstraints);
-
-    return ContentWidthAndMargin { *width, { computedHorizontalMargin.start.valueOr(0_lu), computedHorizontalMargin.end.valueOr(0_lu) } };
-}
-
-ContentHeightAndMargin InlineFormattingContext::Geometry::inlineBlockContentHeightAndMargin(const Box& layoutBox, const HorizontalConstraints& horizontalConstraints, const OverriddenVerticalValues& overriddenVerticalValues) const
-{
-    ASSERT(layoutBox.isInFlow());
-
-    // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
-    if (layoutBox.isReplacedBox())
-        return inlineReplacedContentHeightAndMargin(downcast<ReplacedBox>(layoutBox), horizontalConstraints, { }, overriddenVerticalValues);
-
-    // 10.6.6 Complicated cases
-    // - 'Inline-block', non-replaced elements.
-    return complicatedCases(layoutBox, horizontalConstraints, overriddenVerticalValues);
-}
-
-}
-}
-
-#endif
</del></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingGeometrycppfromrev277551trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingContextGeometrycpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp (from rev 277551, trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingContextGeometry.cpp) (0 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp                               (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.cpp  2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -0,0 +1,732 @@
</span><ins>+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InlineFormattingGeometry.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FloatingContext.h"
+#include "FormattingContext.h"
+#include "InlineLineBox.h"
+#include "LayoutBox.h"
+#include "LayoutContainerBox.h"
+#include "LayoutReplacedBox.h"
+#include "LengthFunctions.h"
+
+namespace WebCore {
+namespace Layout {
+
+class LineBoxBuilder {
+public:
+    LineBoxBuilder(const InlineFormattingContext&);
+    LineBox build(const LineBuilder::LineContent&);
+
+private:
+    struct SimplifiedVerticalAlignment {
+        SimplifiedVerticalAlignment(const LineBox::InlineLevelBox& rootInlineBox);
+
+        static bool canUseSimplifiedAlignment(const LineBox::InlineLevelBox& rootInlineBox, const LineBox::InlineLevelBox&, Optional<const BoxGeometry> inlineLevelBoxGeometry);
+
+        void align(LineBox::InlineLevelBox&);
+
+        InlineLayoutUnit rootInlineBoxLogicalTop() const { return m_rootInlineBoxLogicalTop; }
+        InlineLayoutUnit lineBoxHeight() const { return m_lineBoxLogicalBottom - m_lineBoxLogicalTop; }
+
+        void setEnabled(bool enabled) { m_isEnabled = enabled; }
+        bool isEnabled() const { return m_isEnabled; }
+
+    private:
+        void adjust(const LineBox::InlineLevelBox&);
+
+        const LineBox::InlineLevelBox& m_rootInlineBox;
+        bool m_isEnabled { true };
+        InlineLayoutUnit m_lineBoxLogicalTop { 0 };
+        InlineLayoutUnit m_lineBoxLogicalBottom { 0 };
+        InlineLayoutUnit m_rootInlineBoxLogicalTop { 0 };
+    };
+
+    void setVerticalGeometryForInlineBox(LineBox::InlineLevelBox&) const;
+    void constructAndAlignInlineLevelBoxes(LineBox&, const Line::RunList&);
+    void computeLineBoxHeightAndAlignInlineLevelBoxesVertically(LineBox&);
+
+    const InlineFormattingContext& formattingContext() const { return m_inlineFormattingContext; }
+    const Box& rootBox() const { return formattingContext().root(); }
+    LayoutState& layoutState() const { return formattingContext().layoutState(); }
+
+    bool isRootLayoutBox(const ContainerBox& containerBox) const { return &containerBox == &rootBox(); }
+
+private:
+    const InlineFormattingContext& m_inlineFormattingContext;
+};
+
+struct HangingTrailingWhitespaceContent {
+public:
+    void reset();
+
+    InlineLayoutUnit width() const { return m_width; }
+    bool isConditional() const { return m_isConditional; }
+
+    void setIsConditional() { m_isConditional = true; }
+    void expand(InlineLayoutUnit width) { m_width += width; }
+
+private:
+    bool m_isConditional { false };
+    InlineLayoutUnit m_width { 0 };
+};
+
+void HangingTrailingWhitespaceContent::reset()
+{
+    m_isConditional = false;
+    m_width =  0;
+}
+
+static HangingTrailingWhitespaceContent collectHangingTrailingWhitespaceContent(const Line::RunList& runs, bool isLastLineWithInlineContent)
+{
+    auto hangingContent = HangingTrailingWhitespaceContent { };
+    if (isLastLineWithInlineContent)
+        hangingContent.setIsConditional();
+    for (auto& run : WTF::makeReversedRange(runs)) {
+        if (run.isInlineBoxStart() || run.isInlineBoxEnd())
+            continue;
+        if (run.isLineBreak()) {
+            hangingContent.setIsConditional();
+            continue;
+        }
+        if (!run.hasTrailingWhitespace())
+            break;
+        // Check if we have a preserved or hung whitespace.
+        if (run.style().whiteSpace() != WhiteSpace::PreWrap)
+            break;
+        // This is either a normal or conditionally hanging trailing whitespace.
+        hangingContent.expand(run.trailingWhitespaceWidth());
+    }
+    return hangingContent;
+}
+
+static Optional<InlineLayoutUnit> horizontalAlignmentOffset(const Line::RunList& runs, TextAlignMode textAlign, InlineLayoutUnit lineLogicalWidth, InlineLayoutUnit contentLogicalWidth, bool isLastLine)
+{
+    auto availableWidth = lineLogicalWidth - contentLogicalWidth;
+    auto hangingTrailingWhitespaceContent = collectHangingTrailingWhitespaceContent(runs, isLastLine);
+    availableWidth += hangingTrailingWhitespaceContent.width();
+    if (availableWidth <= 0)
+        return { };
+
+    auto computedHorizontalAlignment = [&] {
+        if (textAlign != TextAlignMode::Justify)
+            return textAlign;
+        // Text is justified according to the method specified by the text-justify property,
+        // in order to exactly fill the line box. Unless otherwise specified by text-align-last,
+        // the last line before a forced break or the end of the block is start-aligned.
+        if (isLastLine || (!runs.isEmpty() && runs.last().isLineBreak()))
+            return TextAlignMode::Start;
+        return TextAlignMode::Justify;
+    };
+
+    switch (computedHorizontalAlignment()) {
+    case TextAlignMode::Left:
+    case TextAlignMode::WebKitLeft:
+    case TextAlignMode::Start:
+        return { };
+    case TextAlignMode::Right:
+    case TextAlignMode::WebKitRight:
+    case TextAlignMode::End:
+        return availableWidth;
+    case TextAlignMode::Center:
+    case TextAlignMode::WebKitCenter:
+        return availableWidth / 2;
+    case TextAlignMode::Justify:
+        // TextAlignMode::Justify is a run alignment (and we only do inline box alignment here)
+        return { };
+    default:
+        ASSERT_NOT_IMPLEMENTED_YET();
+        return { };
+    }
+    ASSERT_NOT_REACHED();
+    return { };
+}
+
+LineBoxBuilder::LineBoxBuilder(const InlineFormattingContext& inlineFormattingContext)
+    : m_inlineFormattingContext(inlineFormattingContext)
+{
+}
+
+LineBox LineBoxBuilder::build(const LineBuilder::LineContent& lineContent)
+{
+    auto& runs = lineContent.runs;
+    auto lineLogicalWidth = lineContent.lineLogicalWidth;
+    auto contentLogicalWidth = lineContent.contentLogicalWidth;
+    auto horizontalAlignmentOffset = Layout::horizontalAlignmentOffset(runs, rootBox().style().textAlign(), lineLogicalWidth, contentLogicalWidth, lineContent.isLastLineWithInlineContent);
+    auto lineBox = LineBox { rootBox(), lineContent.logicalTopLeft, lineLogicalWidth, horizontalAlignmentOffset.valueOr(InlineLayoutUnit { }), contentLogicalWidth, lineContent.nonSpanningInlineLevelBoxCount };
+    constructAndAlignInlineLevelBoxes(lineBox, runs);
+    return lineBox;
+}
+
+void LineBoxBuilder::setVerticalGeometryForInlineBox(LineBox::InlineLevelBox& inlineLevelBox) const
+{
+    ASSERT(inlineLevelBox.isInlineBox() || inlineLevelBox.isLineBreakBox());
+    auto& fontMetrics = inlineLevelBox.style().fontMetrics();
+    InlineLayoutUnit ascent = fontMetrics.ascent();
+    InlineLayoutUnit descent = fontMetrics.descent();
+    auto logicalHeight = ascent + descent;
+    // We need floor/ceil to match legacy layout integral positioning.
+    inlineLevelBox.setBaseline(floorf(ascent));
+    inlineLevelBox.setDescent(ceil(descent));
+    inlineLevelBox.setLogicalHeight(logicalHeight);
+
+    // FIXME: Adjust layout bounds with fallback font when applicable.
+    auto& style = inlineLevelBox.layoutBox().style();
+    auto lineHeight = style.lineHeight();
+    if (lineHeight.isNegative()) {
+        // If line-height computes to normal and either text-edge is leading or this is the root inline box,
+        // the font’s line gap metric may also be incorporated into A and D by adding half to each side as half-leading.
+        // https://www.w3.org/TR/css-inline-3/#inline-height
+        // Since text-edge is not supported yet and the initial value is leading, we should just apply it to
+        // all inline boxes.
+        auto halfLineGap = (fontMetrics.lineSpacing() - logicalHeight) / 2;
+        ascent += halfLineGap;
+        descent += halfLineGap;
+    } else {
+        InlineLayoutUnit lineHeight = style.computedLineHeight();
+        InlineLayoutUnit halfLeading = (lineHeight - (ascent + descent)) / 2;
+        ascent += halfLeading;
+        descent += halfLeading;
+    }
+    // We need floor/ceil to match legacy layout integral positioning.
+    inlineLevelBox.setLayoutBounds(LineBox::InlineLevelBox::LayoutBounds { floorf(ascent), ceil(descent) });
+}
+
+void LineBoxBuilder::constructAndAlignInlineLevelBoxes(LineBox& lineBox, const Line::RunList& runs)
+{
+    auto& rootInlineBox = lineBox.rootInlineBox();
+    setVerticalGeometryForInlineBox(rootInlineBox);
+
+    auto simplifiedVerticalAlignment = SimplifiedVerticalAlignment { rootInlineBox };
+    // FIXME: Add fast path support for line-height content.
+    simplifiedVerticalAlignment.setEnabled(layoutState().inStandardsMode() && rootBox().style().lineHeight().isNegative());
+
+    auto simplifiedAlignVerticallyIfApplicable = [&](auto& inlineLevelBox, Optional<const BoxGeometry> boxGeometry) {
+        if (!simplifiedVerticalAlignment.isEnabled())
+            return;
+        if (!SimplifiedVerticalAlignment::canUseSimplifiedAlignment(rootInlineBox, inlineLevelBox, boxGeometry)) {
+            simplifiedVerticalAlignment.setEnabled(false);
+            return;
+        }
+        simplifiedVerticalAlignment.align(inlineLevelBox);
+    };
+
+    auto createWrappedInlineBoxes = [&] {
+        if (runs.isEmpty())
+            return;
+        // An inline box may not necessarily start on the current line:
+        // <span id=outer>line break<br>this content's parent inline box('outer') <span id=inner>starts on the previous line</span></span>
+        // We need to make sure that there's an LineBox::InlineLevelBox for every inline box that's present on the current line.
+        // In nesting case we need to create LineBox::InlineLevelBoxes for the inline box ancestors.
+        // We only have to do it on the first run as any subsequent inline content is either at the same/higher nesting level or
+        // nested with a [inline box start] run.
+        auto& firstRun = runs[0];
+        auto& firstRunParentLayoutBox = firstRun.layoutBox().parent();
+        // If the parent is the formatting root, we can stop here. This is root inline box content, there's no nesting inline box from the previous line(s)
+        // unless the inline box closing is forced over to the current line.
+        // e.g.
+        // <span>normally the inline box closing forms a continuous content</span>
+        // <span>unless it's forced to the next line<br></span>
+        auto firstRunNeedsInlineBox = firstRun.isInlineBoxEnd();
+        if (!firstRunNeedsInlineBox && isRootLayoutBox(firstRunParentLayoutBox))
+            return;
+        Vector<const Box*> layoutBoxesWithoutInlineBoxes;
+        if (firstRunNeedsInlineBox)
+            layoutBoxesWithoutInlineBoxes.append(&firstRun.layoutBox());
+        auto* ancestor = &firstRunParentLayoutBox;
+        while (!isRootLayoutBox(*ancestor)) {
+            layoutBoxesWithoutInlineBoxes.append(ancestor);
+            ancestor = &ancestor->parent();
+        }
+        // Construct the missing LineBox::InlineBoxes starting with the topmost layout box.
+        for (auto* layoutBox : WTF::makeReversedRange(layoutBoxesWithoutInlineBoxes)) {
+            auto inlineBox = LineBox::InlineLevelBox::createInlineBox(*layoutBox, rootInlineBox.logicalLeft(), lineBox.contentLogicalWidth());
+            setVerticalGeometryForInlineBox(inlineBox);
+            simplifiedAlignVerticallyIfApplicable(inlineBox, { });
+            lineBox.addInlineLevelBox(WTFMove(inlineBox));
+        }
+    };
+    createWrappedInlineBoxes();
+
+    auto lineHasContent = false;
+    for (auto& run : runs) {
+        auto& layoutBox = run.layoutBox();
+        auto runHasContent = [&] () -> bool {
+            ASSERT(!lineHasContent);
+            if (run.isText() || run.isBox() || run.isSoftLineBreak() || run.isHardLineBreak())
+                return true;
+            auto& inlineBoxGeometry = formattingContext().geometryForBox(layoutBox);
+            // Even negative horizontal margin makes the line "contentful".
+            if (run.isInlineBoxStart())
+                return inlineBoxGeometry.marginStart() || inlineBoxGeometry.borderLeft() || inlineBoxGeometry.paddingLeft().valueOr(0_lu);
+            if (run.isInlineBoxEnd())
+                return inlineBoxGeometry.marginEnd() || inlineBoxGeometry.borderRight() || inlineBoxGeometry.paddingRight().valueOr(0_lu);
+            if (run.isWordBreakOpportunity())
+                return false;
+            ASSERT_NOT_REACHED();
+            return true;
+        };
+        lineHasContent = lineHasContent || runHasContent();
+        auto logicalLeft = rootInlineBox.logicalLeft() + run.logicalLeft();
+        if (run.isBox()) {
+            auto& inlineLevelBoxGeometry = formattingContext().geometryForBox(layoutBox);
+            auto marginBoxHeight = inlineLevelBoxGeometry.marginBoxHeight();
+            auto ascent = InlineLayoutUnit { };
+            if (layoutState().shouldNotSynthesizeInlineBlockBaseline()) {
+                // Integration codepath constructs replaced boxes for inline-block content.
+                ASSERT(layoutBox.isReplacedBox());
+                ascent = *downcast<ReplacedBox>(layoutBox).baseline();
+            } else if (layoutBox.isInlineBlockBox()) {
+                // The baseline of an 'inline-block' is the baseline of its last line box in the normal flow, unless it has either no in-flow line boxes or
+                // if its 'overflow' property has a computed value other than 'visible', in which case the baseline is the bottom margin edge.
+                auto synthesizeBaseline = !layoutBox.establishesInlineFormattingContext() || !layoutBox.style().isOverflowVisible();
+                if (synthesizeBaseline)
+                    ascent = marginBoxHeight;
+                else {
+                    auto& formattingState = layoutState().establishedInlineFormattingState(downcast<ContainerBox>(layoutBox));
+                    auto& lastLine = formattingState.lines().last();
+                    auto inlineBlockBaseline = lastLine.lineBoxLogicalRect().top() + lastLine.baseline();
+                    ascent = inlineLevelBoxGeometry.marginBefore() + inlineLevelBoxGeometry.borderTop() + inlineLevelBoxGeometry.paddingTop().valueOr(0) + inlineBlockBaseline;
+                }
+            } else if (layoutBox.isReplacedBox())
+                ascent = downcast<ReplacedBox>(layoutBox).baseline().valueOr(marginBoxHeight);
+            else
+                ascent = marginBoxHeight;
+            logicalLeft += std::max(0_lu, inlineLevelBoxGeometry.marginStart());
+            auto atomicInlineLevelBox = LineBox::InlineLevelBox::createAtomicInlineLevelBox(layoutBox, logicalLeft, { inlineLevelBoxGeometry.borderBoxWidth(), marginBoxHeight });
+            atomicInlineLevelBox.setBaseline(ascent);
+            atomicInlineLevelBox.setLayoutBounds(LineBox::InlineLevelBox::LayoutBounds { ascent, marginBoxHeight - ascent });
+            simplifiedAlignVerticallyIfApplicable(atomicInlineLevelBox, inlineLevelBoxGeometry);
+            lineBox.addInlineLevelBox(WTFMove(atomicInlineLevelBox));
+            continue;
+        }
+        if (run.isInlineBoxStart()) {
+            // At this point we don't know yet how wide this inline box is. Let's assume it's as long as the line is
+            // and adjust it later if we come across an inlineBoxEnd run (see below).
+            auto initialLogicalWidth = lineBox.contentLogicalWidth() - run.logicalLeft();
+            ASSERT(initialLogicalWidth >= 0);
+            // Inline box run is based on margin box. Let's convert it to border box.
+            auto marginStart = std::max(0_lu, formattingContext().geometryForBox(layoutBox).marginStart());
+            logicalLeft += marginStart;
+            initialLogicalWidth -= marginStart;
+            auto inlineBox = LineBox::InlineLevelBox::createInlineBox(layoutBox, logicalLeft, initialLogicalWidth);
+            setVerticalGeometryForInlineBox(inlineBox);
+            simplifiedAlignVerticallyIfApplicable(inlineBox, { });
+            lineBox.addInlineLevelBox(WTFMove(inlineBox));
+            continue;
+        }
+        if (run.isInlineBoxEnd()) {
+            // Adjust the logical width when the inline box closes on this line.
+            auto& inlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox);
+            ASSERT(inlineBox.isInlineBox());
+            // Inline box run is based on margin box. Let's convert it to border box.
+            auto marginEnd = std::max(0_lu, formattingContext().geometryForBox(layoutBox).marginEnd());
+            auto inlineBoxLogicalRight = logicalLeft + run.logicalWidth() - marginEnd;
+            inlineBox.setLogicalWidth(inlineBoxLogicalRight - inlineBox.logicalLeft());
+            simplifiedAlignVerticallyIfApplicable(inlineBox, { });
+            continue;
+        }
+        if (run.isText() || run.isSoftLineBreak()) {
+            // FIXME: Adjust non-empty inline box height when glyphs from the non-primary font stretch the box.
+            lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent()).setHasContent();
+            continue;
+        }
+        if (run.isHardLineBreak()) {
+            auto lineBreakBox = LineBox::InlineLevelBox::createLineBreakBox(layoutBox, logicalLeft);
+            setVerticalGeometryForInlineBox(lineBreakBox);
+            simplifiedAlignVerticallyIfApplicable(lineBreakBox, { });
+            lineBox.addInlineLevelBox(WTFMove(lineBreakBox));
+            continue;
+        }
+        if (run.isWordBreakOpportunity()) {
+            lineBox.addInlineLevelBox(LineBox::InlineLevelBox::createGenericInlineLevelBox(layoutBox, logicalLeft));
+            continue;
+        }
+        ASSERT_NOT_REACHED();
+    }
+
+    lineBox.setHasContent(lineHasContent);
+    if (simplifiedVerticalAlignment.isEnabled() || !lineHasContent) {
+        // We should always be able to exercise the fast path when the line has no content at all, even in non-standards mode or with line-height set.
+        rootInlineBox.setLogicalTop(lineHasContent ? simplifiedVerticalAlignment.rootInlineBoxLogicalTop() : -rootInlineBox.baseline());
+        lineBox.setLogicalHeight(lineHasContent ? simplifiedVerticalAlignment.lineBoxHeight() : InlineLayoutUnit());
+    } else
+        computeLineBoxHeightAndAlignInlineLevelBoxesVertically(lineBox);
+}
+
+void LineBoxBuilder::computeLineBoxHeightAndAlignInlineLevelBoxesVertically(LineBox& lineBox)
+{
+    ASSERT(lineBox.hasContent());
+    // This function (partially) implements:
+    // 2.2. Layout Within Line Boxes
+    // https://www.w3.org/TR/css-inline-3/#line-layout
+    // 1. Compute the line box height using the layout bounds geometry. This height computation strictly uses layout bounds and not normal inline level box geometries.
+    // 2. Compute the baseline/logical top position of the root inline box. Aligned boxes push the root inline box around inside the line box.
+    // 3. Finally align the inline level boxes using (mostly) normal inline level box geometries.
+    auto quirks = formattingContext().quirks();
+    auto& rootInlineBox = lineBox.rootInlineBox();
+
+    auto computeLineBoxLogicalHeight = [&] {
+        // Line box height computation is based on the layout bounds of the inline boxes and not their logical (ascent/descent) dimensions.
+        struct AbsoluteTopAndBottom {
+            InlineLayoutUnit top { 0 };
+            InlineLayoutUnit bottom { 0 };
+        };
+        HashMap<const LineBox::InlineLevelBox*, AbsoluteTopAndBottom> inlineLevelBoxAbsoluteTopAndBottomMap;
+
+        auto minimumLogicalTop = Optional<InlineLayoutUnit> { };
+        auto maximumLogicalBottom = Optional<InlineLayoutUnit> { };
+        if (quirks.inlineLevelBoxAffectsLineBox(rootInlineBox, lineBox)) {
+            minimumLogicalTop = InlineLayoutUnit { };
+            maximumLogicalBottom = rootInlineBox.layoutBounds().height();
+            inlineLevelBoxAbsoluteTopAndBottomMap.add(&rootInlineBox, AbsoluteTopAndBottom { *minimumLogicalTop, *maximumLogicalBottom });
+        } else
+            inlineLevelBoxAbsoluteTopAndBottomMap.add(&rootInlineBox, AbsoluteTopAndBottom { });
+
+        Vector<LineBox::InlineLevelBox*> lineBoxRelativeInlineLevelBoxes;
+        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
+            auto& layoutBox = inlineLevelBox.layoutBox();
+            if (inlineLevelBox.hasLineBoxRelativeAlignment()) {
+                lineBoxRelativeInlineLevelBoxes.append(&inlineLevelBox);
+                continue;
+            }
+            auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent());
+            // Logical top is relative to the parent inline box's layout bounds.
+            // Note that this logical top is not the final logical top of the inline level box.
+            // This is the logical top in the context of the layout bounds geometry which may be very different from the inline box's normal geometry.
+            auto logicalTop = InlineLayoutUnit { };
+            switch (inlineLevelBox.verticalAlign()) {
+            case VerticalAlign::Baseline: {
+                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().ascent;
+                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
+                break;
+            }
+            case VerticalAlign::Middle: {
+                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().height() / 2 + parentInlineBox.style().fontMetrics().xHeight() / 2;
+                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
+                break;
+            }
+            case VerticalAlign::BaselineMiddle: {
+                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().height() / 2;
+                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
+                break;
+            }
+            case VerticalAlign::Length: {
+                auto& style = inlineLevelBox.style();
+                auto logicalTopOffsetFromParentBaseline = floatValueForLength(style.verticalAlignLength(), style.computedLineHeight()) + inlineLevelBox.layoutBounds().ascent;
+                logicalTop = parentInlineBox.layoutBounds().ascent - logicalTopOffsetFromParentBaseline;
+                break;
+            }
+            case VerticalAlign::TextTop: {
+                // Note that text-top aligns with the inline box's font metrics top (ascent) and not the layout bounds top.
+                logicalTop = parentInlineBox.layoutBounds().ascent - parentInlineBox.baseline();
+                break;
+            }
+            case VerticalAlign::TextBottom: {
+                // Note that text-bottom aligns with the inline box's font metrics bottom (descent) and not the layout bounds bottom.
+                auto parentInlineBoxLayoutBounds = parentInlineBox.layoutBounds();
+                auto parentInlineBoxLogicalBottom = parentInlineBoxLayoutBounds.height() - parentInlineBoxLayoutBounds.descent + parentInlineBox.descent().valueOr(InlineLayoutUnit());
+                logicalTop = parentInlineBoxLogicalBottom - inlineLevelBox.layoutBounds().height();
+                break;
+            }
+            default:
+                ASSERT_NOT_IMPLEMENTED_YET();
+                break;
+            }
+            auto parentInlineBoxAbsoluteTopAndBottom = inlineLevelBoxAbsoluteTopAndBottomMap.get(&parentInlineBox);
+            auto absoluteLogicalTop = parentInlineBoxAbsoluteTopAndBottom.top + logicalTop;
+            auto absoluteLogicalBottom = absoluteLogicalTop + inlineLevelBox.layoutBounds().height();
+            inlineLevelBoxAbsoluteTopAndBottomMap.add(&inlineLevelBox, AbsoluteTopAndBottom { absoluteLogicalTop, absoluteLogicalBottom });
+            // Stretch the min/max absolute values if applicable.
+            if (quirks.inlineLevelBoxAffectsLineBox(inlineLevelBox, lineBox)) {
+                minimumLogicalTop = std::min(minimumLogicalTop.valueOr(absoluteLogicalTop), absoluteLogicalTop);
+                maximumLogicalBottom = std::max(maximumLogicalBottom.valueOr(absoluteLogicalBottom), absoluteLogicalBottom);
+            }
+        }
+        // The line box height computation is as follows:
+        // 1. Stretch the line box with the non-line-box relative aligned inline box absolute top and bottom values.
+        // 2. Check if the line box relative aligned inline boxes (top, bottom etc) have enough room and stretch the line box further if needed.
+        auto lineBoxLogicalHeight = maximumLogicalBottom.valueOr(InlineLayoutUnit()) - minimumLogicalTop.valueOr(InlineLayoutUnit());
+        for (auto* lineBoxRelativeInlineLevelBox : lineBoxRelativeInlineLevelBoxes) {
+            if (!quirks.inlineLevelBoxAffectsLineBox(*lineBoxRelativeInlineLevelBox, lineBox))
+                continue;
+            lineBoxLogicalHeight = std::max(lineBoxLogicalHeight, lineBoxRelativeInlineLevelBox->layoutBounds().height());
+        }
+        lineBox.setLogicalHeight(lineBoxLogicalHeight);
+    };
+    computeLineBoxLogicalHeight();
+
+    auto computeRootInlineBoxVerticalPosition = [&] {
+        HashMap<const LineBox::InlineLevelBox*, InlineLayoutUnit> inlineLevelBoxAbsoluteBaselineOffsetMap;
+        inlineLevelBoxAbsoluteBaselineOffsetMap.add(&rootInlineBox, InlineLayoutUnit { });
+
+        auto maximumTopOffsetFromRootInlineBoxBaseline = Optional<InlineLayoutUnit> { };
+        if (quirks.inlineLevelBoxAffectsLineBox(rootInlineBox, lineBox))
+            maximumTopOffsetFromRootInlineBoxBaseline = rootInlineBox.layoutBounds().ascent;
+
+        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
+            auto absoluteBaselineOffset = InlineLayoutUnit { };
+            if (!inlineLevelBox.hasLineBoxRelativeAlignment()) {
+                auto& layoutBox = inlineLevelBox.layoutBox();
+                auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent());
+                auto baselineOffsetFromParentBaseline = InlineLayoutUnit { };
+
+                switch (inlineLevelBox.verticalAlign()) {
+                case VerticalAlign::Baseline:
+                    baselineOffsetFromParentBaseline = { };
+                    break;
+                case VerticalAlign::Middle: {
+                    auto logicalTopOffsetFromParentBaseline = (inlineLevelBox.layoutBounds().height() / 2 + parentInlineBox.style().fontMetrics().xHeight() / 2);
+                    baselineOffsetFromParentBaseline = logicalTopOffsetFromParentBaseline - inlineLevelBox.layoutBounds().ascent;
+                    break;
+                }
+                case VerticalAlign::BaselineMiddle: {
+                    auto logicalTopOffsetFromParentBaseline = inlineLevelBox.layoutBounds().height() / 2;
+                    baselineOffsetFromParentBaseline = logicalTopOffsetFromParentBaseline - inlineLevelBox.layoutBounds().ascent;
+                    break;
+                }
+                case VerticalAlign::Length: {
+                    auto& style = inlineLevelBox.style();
+                    auto verticalAlignOffset = floatValueForLength(style.verticalAlignLength(), style.computedLineHeight());
+                    auto logicalTopOffsetFromParentBaseline = verticalAlignOffset + inlineLevelBox.baseline();
+                    baselineOffsetFromParentBaseline = logicalTopOffsetFromParentBaseline - inlineLevelBox.baseline();
+                    break;
+                }
+                case VerticalAlign::TextTop:
+                    baselineOffsetFromParentBaseline = parentInlineBox.baseline() - inlineLevelBox.layoutBounds().ascent;
+                    break;
+                case VerticalAlign::TextBottom:
+                    baselineOffsetFromParentBaseline = inlineLevelBox.layoutBounds().descent - *parentInlineBox.descent();
+                    break;
+                default:
+                    ASSERT_NOT_IMPLEMENTED_YET();
+                    break;
+                }
+                absoluteBaselineOffset = inlineLevelBoxAbsoluteBaselineOffsetMap.get(&parentInlineBox) + baselineOffsetFromParentBaseline;
+            } else {
+                switch (inlineLevelBox.verticalAlign()) {
+                case VerticalAlign::Top: {
+                    absoluteBaselineOffset = rootInlineBox.layoutBounds().ascent - inlineLevelBox.layoutBounds().ascent;
+                    break;
+                }
+                case VerticalAlign::Bottom: {
+                    absoluteBaselineOffset = inlineLevelBox.layoutBounds().descent - rootInlineBox.layoutBounds().descent;
+                    break;
+                }
+                default:
+                    ASSERT_NOT_IMPLEMENTED_YET();
+                    break;
+                }
+            }
+            inlineLevelBoxAbsoluteBaselineOffsetMap.add(&inlineLevelBox, absoluteBaselineOffset);
+            auto affectsRootInlineBoxVerticalPosition = quirks.inlineLevelBoxAffectsLineBox(inlineLevelBox, lineBox);
+            if (affectsRootInlineBoxVerticalPosition) {
+                auto topOffsetFromRootInlineBoxBaseline = absoluteBaselineOffset + inlineLevelBox.layoutBounds().ascent;
+                if (maximumTopOffsetFromRootInlineBoxBaseline)
+                    maximumTopOffsetFromRootInlineBoxBaseline = std::max(*maximumTopOffsetFromRootInlineBoxBaseline, topOffsetFromRootInlineBoxBaseline);
+                else {
+                    // We are is quirk mode and the root inline box has no content. The root inline box's baseline is anchored at 0.
+                    // However negative ascent (e.g negative top margin) can "push" the root inline box upwards and have a negative value.
+                    maximumTopOffsetFromRootInlineBoxBaseline = inlineLevelBox.layoutBounds().ascent >= 0
+                        ? std::max(0.0f, topOffsetFromRootInlineBoxBaseline)
+                        : topOffsetFromRootInlineBoxBaseline;
+                }
+            }
+        }
+        auto rootInlineBoxLogicalTop = maximumTopOffsetFromRootInlineBoxBaseline.valueOr(0.f) - rootInlineBox.baseline();
+        rootInlineBox.setLogicalTop(rootInlineBoxLogicalTop);
+    };
+    computeRootInlineBoxVerticalPosition();
+
+    auto alignInlineLevelBoxes = [&] {
+        for (auto& inlineLevelBox : lineBox.nonRootInlineLevelBoxes()) {
+            auto& layoutBox = inlineLevelBox.layoutBox();
+            auto& parentInlineBox = lineBox.inlineLevelBoxForLayoutBox(layoutBox.parent());
+            auto logicalTop = InlineLayoutUnit { };
+            switch (inlineLevelBox.verticalAlign()) {
+            case VerticalAlign::Baseline:
+                logicalTop = parentInlineBox.baseline() - inlineLevelBox.baseline();
+                break;
+            case VerticalAlign::Middle: {
+                auto logicalTopOffsetFromParentBaseline = (inlineLevelBox.logicalHeight() / 2 + parentInlineBox.style().fontMetrics().xHeight() / 2);
+                logicalTop = parentInlineBox.baseline() - logicalTopOffsetFromParentBaseline;
+                break;
+            }
+            case VerticalAlign::BaselineMiddle: {
+                auto logicalTopOffsetFromParentBaseline = inlineLevelBox.logicalHeight() / 2;
+                logicalTop = parentInlineBox.baseline() - logicalTopOffsetFromParentBaseline;
+                break;
+            }
+            case VerticalAlign::Length: {
+                auto& style = inlineLevelBox.style();
+                auto verticalAlignOffset = floatValueForLength(style.verticalAlignLength(), style.computedLineHeight());
+                auto logicalTopOffsetFromParentBaseline = verticalAlignOffset + inlineLevelBox.baseline();
+                logicalTop = parentInlineBox.baseline() - logicalTopOffsetFromParentBaseline;
+                break;
+            }
+            // Note that (text)top/bottom align their layout bounds.
+            case VerticalAlign::TextTop:
+                logicalTop = inlineLevelBox.layoutBounds().ascent - inlineLevelBox.baseline();
+                break;
+            case VerticalAlign::TextBottom:
+                logicalTop = parentInlineBox.logicalHeight() - inlineLevelBox.layoutBounds().descent - inlineLevelBox.baseline();
+                break;
+            case VerticalAlign::Top:
+                // Note that this logical top is not relative to the parent inline box.
+                logicalTop = inlineLevelBox.layoutBounds().ascent - inlineLevelBox.baseline();
+                break;
+            case VerticalAlign::Bottom:
+                // Note that this logical top is not relative to the parent inline box.
+                logicalTop = lineBox.logicalHeight() - inlineLevelBox.layoutBounds().descent - inlineLevelBox.baseline();
+                break;
+            default:
+                ASSERT_NOT_IMPLEMENTED_YET();
+                break;
+            }
+            inlineLevelBox.setLogicalTop(logicalTop);
+        }
+    };
+    alignInlineLevelBoxes();
+}
+
+LineBoxBuilder::SimplifiedVerticalAlignment::SimplifiedVerticalAlignment(const LineBox::InlineLevelBox& rootInlineBox)
+    : m_rootInlineBox(rootInlineBox)
+{
+    adjust(rootInlineBox);
+}
+
+bool LineBoxBuilder::SimplifiedVerticalAlignment::canUseSimplifiedAlignment(const LineBox::InlineLevelBox& rootInlineBox, const LineBox::InlineLevelBox& inlineLevelBox, Optional<const BoxGeometry> inlineLevelBoxGeometry)
+{
+    if (inlineLevelBox.isAtomicInlineLevelBox()) {
+        ASSERT(inlineLevelBoxGeometry);
+        // Baseline aligned, non-stretchy direct children are considered to be simple for now.
+        auto& layoutBox = inlineLevelBox.layoutBox();
+        return &layoutBox.parent() == &rootInlineBox.layoutBox()
+            && layoutBox.style().verticalAlign() == VerticalAlign::Baseline
+            && !inlineLevelBoxGeometry->marginBefore()
+            && !inlineLevelBoxGeometry->marginAfter()
+            && inlineLevelBoxGeometry->marginBoxHeight() <= rootInlineBox.baseline();
+    }
+    if (inlineLevelBox.isLineBreakBox()) {
+        // Baseline aligned, non-stretchy line breaks e.g. <div><span><br></span></div> but not <div><span style="font-size: 100px;"><br></span></div>.
+        return inlineLevelBox.layoutBox().style().verticalAlign() == VerticalAlign::Baseline && inlineLevelBox.baseline() <= rootInlineBox.baseline();
+    }
+    if (inlineLevelBox.isInlineBox()) {
+        // Baseline aligned, non-stretchy inline boxes e.g. <div><span></span></div> but not <div><span style="font-size: 100px;"></span></div>.
+        return inlineLevelBox.layoutBox().style().verticalAlign() == VerticalAlign::Baseline && inlineLevelBox.layoutBounds() == rootInlineBox.layoutBounds();
+    }
+    return false;
+}
+
+void LineBoxBuilder::SimplifiedVerticalAlignment::align(LineBox::InlineLevelBox& inlineLevelBox)
+{
+    if (inlineLevelBox.isAtomicInlineLevelBox() || inlineLevelBox.isLineBreakBox() || inlineLevelBox.isInlineBox()) {
+        // Only baseline alignment for now.
+        inlineLevelBox.setLogicalTop(m_rootInlineBox.baseline() - inlineLevelBox.baseline());
+        adjust(inlineLevelBox);
+        return;
+    }
+    ASSERT_NOT_IMPLEMENTED_YET();
+}
+
+void LineBoxBuilder::SimplifiedVerticalAlignment::adjust(const LineBox::InlineLevelBox& inlineLevelBox)
+{
+    auto layoutBoundsLogicalTop = m_rootInlineBox.layoutBounds().ascent - inlineLevelBox.layoutBounds().ascent;
+    m_lineBoxLogicalTop = std::min(m_lineBoxLogicalTop, layoutBoundsLogicalTop);
+    m_lineBoxLogicalBottom = std::max(m_lineBoxLogicalBottom, layoutBoundsLogicalTop + inlineLevelBox.layoutBounds().height());
+    m_rootInlineBoxLogicalTop = std::max(m_rootInlineBoxLogicalTop, inlineLevelBox.layoutBounds().ascent - m_rootInlineBox.baseline());
+}
+
+InlineFormattingGeometry::InlineFormattingGeometry(const InlineFormattingContext& inlineFormattingContext)
+    : FormattingContext::Geometry(inlineFormattingContext)
+{
+}
+
+LineBox InlineFormattingGeometry::lineBoxForLineContent(const LineBuilder::LineContent& lineContent)
+{
+    return LineBoxBuilder(formattingContext()).build(lineContent);
+}
+
+InlineLayoutUnit InlineFormattingGeometry::logicalTopForNextLine(const LineBuilder::LineContent& lineContent, InlineLayoutUnit previousLineLogicalBottom, const FloatingContext& floatingContext) const
+{
+    // Normally the next line's logical top is the previous line's logical bottom, but when the line ends
+    // with the clear property set, the next line needs to clear the existing floats.
+    if (lineContent.runs.isEmpty())
+        return previousLineLogicalBottom;
+    auto& lastRunLayoutBox = lineContent.runs.last().layoutBox(); 
+    if (lastRunLayoutBox.style().clear() == Clear::None)
+        return previousLineLogicalBottom;
+    auto positionWithClearance = floatingContext.verticalPositionWithClearance(lastRunLayoutBox);
+    if (!positionWithClearance)
+        return previousLineLogicalBottom;
+    return std::max(previousLineLogicalBottom, InlineLayoutUnit(positionWithClearance->position));
+}
+
+ContentWidthAndMargin InlineFormattingGeometry::inlineBlockContentWidthAndMargin(const Box& formattingContextRoot, const HorizontalConstraints& horizontalConstraints, const OverriddenHorizontalValues& overriddenHorizontalValues)
+{
+    ASSERT(formattingContextRoot.isInFlow());
+
+    // 10.3.10 'Inline-block', replaced elements in normal flow
+
+    // Exactly as inline replaced elements.
+    if (formattingContextRoot.isReplacedBox())
+        return inlineReplacedContentWidthAndMargin(downcast<ReplacedBox>(formattingContextRoot), horizontalConstraints, { }, overriddenHorizontalValues);
+
+    // 10.3.9 'Inline-block', non-replaced elements in normal flow
+
+    // If 'width' is 'auto', the used value is the shrink-to-fit width as for floating elements.
+    // A computed value of 'auto' for 'margin-left' or 'margin-right' becomes a used value of '0'.
+    // #1
+    auto width = computedValue(formattingContextRoot.style().logicalWidth(), horizontalConstraints.logicalWidth);
+    if (!width)
+        width = shrinkToFitWidth(formattingContextRoot, horizontalConstraints.logicalWidth);
+
+    // #2
+    auto computedHorizontalMargin = Geometry::computedHorizontalMargin(formattingContextRoot, horizontalConstraints);
+
+    return ContentWidthAndMargin { *width, { computedHorizontalMargin.start.valueOr(0_lu), computedHorizontalMargin.end.valueOr(0_lu) } };
+}
+
+ContentHeightAndMargin InlineFormattingGeometry::inlineBlockContentHeightAndMargin(const Box& layoutBox, const HorizontalConstraints& horizontalConstraints, const OverriddenVerticalValues& overriddenVerticalValues) const
+{
+    ASSERT(layoutBox.isInFlow());
+
+    // 10.6.2 Inline replaced elements, block-level replaced elements in normal flow, 'inline-block' replaced elements in normal flow and floating replaced elements
+    if (layoutBox.isReplacedBox())
+        return inlineReplacedContentHeightAndMargin(downcast<ReplacedBox>(layoutBox), horizontalConstraints, { }, overriddenVerticalValues);
+
+    // 10.6.6 Complicated cases
+    // - 'Inline-block', non-replaced elements.
+    return complicatedCases(layoutBox, horizontalConstraints, overriddenVerticalValues);
+}
+
+}
+}
+
+#endif
</ins></span></pre></div>
<a id="trunkSourceWebCorelayoutformattingContextsinlineInlineFormattingGeometryh"></a>
<div class="addfile"><h4>Added: trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h (0 => 277552)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h                         (rev 0)
+++ trunk/Source/WebCore/layout/formattingContexts/inline/InlineFormattingGeometry.h    2021-05-15 23:55:58 UTC (rev 277552)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FormattingContext.h"
+
+namespace WebCore {
+namespace Layout {
+
+class InlineFormattingGeometry : public FormattingContext::Geometry {
+public:
+    LineBox lineBoxForLineContent(const LineBuilder::LineContent&);
+    InlineLayoutUnit logicalTopForNextLine(const LineBuilder::LineContent&, InlineLayoutUnit previousLineLogicalBottom, const FloatingContext&) const;
+
+    ContentHeightAndMargin inlineBlockContentHeightAndMargin(const Box&, const HorizontalConstraints&, const OverriddenVerticalValues&) const;
+    ContentWidthAndMargin inlineBlockContentWidthAndMargin(const Box&, const HorizontalConstraints&, const OverriddenHorizontalValues&);
+
+private:
+    friend class InlineFormattingContext;
+    InlineFormattingGeometry(const InlineFormattingContext&);
+
+    const InlineFormattingContext& formattingContext() const { return downcast<InlineFormattingContext>(FormattingContext::Geometry::formattingContext()); }
+
+};
+
+}
+}
+
+#endif
</ins></span></pre>
</div>
</div>

</body>
</html>