Missing from r237549
[WebKit-https.git] / Tools / LayoutReloaded / misc / LayoutReloadedWebKit.patch
1 diff --git a/Source/WTF/wtf/Platform.h b/Source/WTF/wtf/Platform.h
2 index 290f6de219b..f7411e2dfb4 100644
3 --- a/Source/WTF/wtf/Platform.h
4 +++ b/Source/WTF/wtf/Platform.h
5 @@ -1120,7 +1120,7 @@
6  #if !defined(NDEBUG)
7  #define ENABLE_TREE_DEBUGGING 1
8  #else
9 -#define ENABLE_TREE_DEBUGGING 0
10 +#define ENABLE_TREE_DEBUGGING 1
11  #endif
12  #endif
13  
14 diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make
15 index f5d0e5d2c3e..3945090acf3 100644
16 --- a/Source/WebCore/DerivedSources.make
17 +++ b/Source/WebCore/DerivedSources.make
18 @@ -532,6 +532,7 @@ JS_BINDING_IDLS = \
19      $(WebCore)/dom/TextDecoder.idl \
20      $(WebCore)/dom/TextEncoder.idl \
21      $(WebCore)/dom/TextEvent.idl \
22 +    $(WebCore)/dom/InlineTextRun.idl \
23      $(WebCore)/dom/TransitionEvent.idl \
24      $(WebCore)/dom/TreeWalker.idl \
25      $(WebCore)/dom/UIEvent.idl \
26 diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt
27 index a461719e2dd..2d48c60758b 100644
28 --- a/Source/WebCore/Sources.txt
29 +++ b/Source/WebCore/Sources.txt
30 @@ -1802,7 +1802,9 @@ rendering/InlineBox.cpp
31  rendering/InlineElementBox.cpp
32  rendering/InlineFlowBox.cpp
33  rendering/InlineIterator.cpp
34 +rendering/InlineTextBreaker.cpp
35  rendering/InlineTextBox.cpp
36 +rendering/InlineTextRunIterator.cpp
37  rendering/LayoutDisallowedScope.cpp
38  rendering/LayoutRepainter.cpp
39  rendering/LayoutState.cpp
40 diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
41 index a6a138060f6..91fb8a5cd04 100644
42 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
43 +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
44 @@ -396,6 +396,10 @@
45                 1193408A1FEB355D00935F1E /* RenderTreeBuilderRuby.h in Headers */ = {isa = PBXBuildFile; fileRef = 119340881FEB355D00935F1E /* RenderTreeBuilderRuby.h */; };
46                 119340971FED715500935F1E /* RenderTreeBuilderFormControls.h in Headers */ = {isa = PBXBuildFile; fileRef = 119340951FED715500935F1E /* RenderTreeBuilderFormControls.h */; };
47                 119340A31FEE024000935F1E /* RenderTreeBuilderBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 119340A11FEE024000935F1E /* RenderTreeBuilderBlock.h */; };
48 +               11C0C79E20694AE100BE3A84 /* InlineTextRunIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 11C0C79920694ADE00BE3A84 /* InlineTextRunIterator.h */; };
49 +               11C0C7A020694AE100BE3A84 /* InlineTextBreaker.h in Headers */ = {isa = PBXBuildFile; fileRef = 11C0C79C20694AE000BE3A84 /* InlineTextBreaker.h */; };
50 +               11C0C7A520694B0A00BE3A84 /* InlineTextRun.h in Headers */ = {isa = PBXBuildFile; fileRef = 11C0C7A320694B0900BE3A84 /* InlineTextRun.h */; };
51 +               11C0C7A7206953F700BE3A84 /* JSInlineTextRun.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 11C0C7A6206953F600BE3A84 /* JSInlineTextRun.cpp */; };
52                 11CB2789203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h in Headers */ = {isa = PBXBuildFile; fileRef = 11CB2787203BA570004A1DC9 /* RenderTreeBuilderFullScreen.h */; };
53                 11E067EE1E6246E500162D16 /* SimpleLineLayoutCoverage.h in Headers */ = {isa = PBXBuildFile; fileRef = 11E067ED1E6246E500162D16 /* SimpleLineLayoutCoverage.h */; settings = {ATTRIBUTES = (Private, ); }; };
54                 1400D7A817136EA70077CE05 /* ScriptWrappableInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 1400D7A717136EA70077CE05 /* ScriptWrappableInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
55 @@ -5706,6 +5710,13 @@
56                 119340951FED715500935F1E /* RenderTreeBuilderFormControls.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderFormControls.h; sourceTree = "<group>"; };
57                 119340A01FEE024000935F1E /* RenderTreeBuilderBlock.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTreeBuilderBlock.cpp; sourceTree = "<group>"; };
58                 119340A11FEE024000935F1E /* RenderTreeBuilderBlock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderBlock.h; sourceTree = "<group>"; };
59 +               11C0C79920694ADE00BE3A84 /* InlineTextRunIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineTextRunIterator.h; sourceTree = "<group>"; };
60 +               11C0C79B20694ADF00BE3A84 /* InlineTextBreaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineTextBreaker.cpp; sourceTree = "<group>"; };
61 +               11C0C79C20694AE000BE3A84 /* InlineTextBreaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineTextBreaker.h; sourceTree = "<group>"; };
62 +               11C0C79D20694AE000BE3A84 /* InlineTextRunIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InlineTextRunIterator.cpp; sourceTree = "<group>"; };
63 +               11C0C7A220694B0800BE3A84 /* InlineTextRun.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = InlineTextRun.idl; sourceTree = "<group>"; };
64 +               11C0C7A320694B0900BE3A84 /* InlineTextRun.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InlineTextRun.h; sourceTree = "<group>"; };
65 +               11C0C7A6206953F600BE3A84 /* JSInlineTextRun.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSInlineTextRun.cpp; path = JSInlineTextRun.cpp; sourceTree = "<group>"; };
66                 11C5F1162003E7750001AE60 /* RenderTreeBuilderInline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderTreeBuilderInline.cpp; sourceTree = "<group>"; };
67                 11C5F1182003E7760001AE60 /* RenderTreeBuilderInline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderInline.h; sourceTree = "<group>"; };
68                 11C5F11D2003F69E0001AE60 /* RenderTreeBuilderBlockFlow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderTreeBuilderBlockFlow.h; sourceTree = "<group>"; };
69 @@ -22145,6 +22156,7 @@
70                 A83B79100CCB001B000B0825 /* Core */ = {
71                         isa = PBXGroup;
72                         children = (
73 +                               11C0C7A6206953F600BE3A84 /* JSInlineTextRun.cpp */,
74                                 7C30D97E1F815AC000268356 /* JSAbortController.cpp */,
75                                 7C30D9801F815AC100268356 /* JSAbortController.h */,
76                                 7C30D9821F815AC200268356 /* JSAbortSignal.cpp */,
77 @@ -25479,6 +25491,10 @@
78                 F523D2F302DE443B018635CA /* rendering */ = {
79                         isa = PBXGroup;
80                         children = (
81 +                               11C0C79B20694ADF00BE3A84 /* InlineTextBreaker.cpp */,
82 +                               11C0C79C20694AE000BE3A84 /* InlineTextBreaker.h */,
83 +                               11C0C79D20694AE000BE3A84 /* InlineTextRunIterator.cpp */,
84 +                               11C0C79920694ADE00BE3A84 /* InlineTextRunIterator.h */,
85                                 FFB698C81832F10B00158A31 /* line */,
86                                 439046C212DA25CE00AF80A2 /* mathml */,
87                                 FD08A879175D3926002CD360 /* shapes */,
88 @@ -25775,6 +25791,8 @@
89                 F523D32402DE4478018635CA /* dom */ = {
90                         isa = PBXGroup;
91                         children = (
92 +                               11C0C7A320694B0900BE3A84 /* InlineTextRun.h */,
93 +                               11C0C7A220694B0800BE3A84 /* InlineTextRun.idl */,
94                                 CE2616A4187E65C1007955F3 /* ios */,
95                                 2D5036661BCDDDC400E20BB3 /* mac */,
96                                 51ECC3E42005831F00483EAE /* messageports */,
97 @@ -26771,6 +26789,7 @@
98                                 31DCD29D1AB4FBDE0072E817 /* AnimationTrigger.h in Headers */,
99                                 0F580FAF149800D400FB5BD8 /* AnimationUtilities.h in Headers */,
100                                 93309DD7099E64920056E581 /* AppendNodeCommand.h in Headers */,
101 +                               11C0C7A520694B0A00BE3A84 /* InlineTextRun.h in Headers */,
102                                 A1DF5A941F7EC4320058A477 /* ApplePayContactField.h in Headers */,
103                                 A12C59EE2035FC9B0012236B /* ApplePayError.h in Headers */,
104                                 7C6579E31E00827000E3A27A /* ApplePayLineItem.h in Headers */,
105 @@ -30369,6 +30388,7 @@
106                                 4945BFD413CF809000CC3B38 /* TransformState.h in Headers */,
107                                 E17B491616A9B094001C8839 /* TransitionEvent.h in Headers */,
108                                 49E911D20EF86D47009D0CAF /* TranslateTransformOperation.h in Headers */,
109 +                               11C0C7A020694AE100BE3A84 /* InlineTextBreaker.h in Headers */,
110                                 854FE7370A2297BE0058D7AD /* Traversal.h in Headers */,
111                                 37FD4298118368460093C029 /* TreeDepthLimit.h in Headers */,
112                                 14D64B5D134A5B6B00E58FDA /* TreeScope.h in Headers */,
113 @@ -30583,6 +30603,7 @@
114                                 97AABD1E14FA09D5007457AE /* WebSocketChannel.h in Headers */,
115                                 97AABD1F14FA09D5007457AE /* WebSocketChannelClient.h in Headers */,
116                                 4A38BF5114FE1C0900612512 /* WebSocketDeflateFramer.h in Headers */,
117 +                               11C0C79E20694AE100BE3A84 /* InlineTextRunIterator.h in Headers */,
118                                 97AABD2114FA09D5007457AE /* WebSocketDeflater.h in Headers */,
119                                 97AABD2314FA09D5007457AE /* WebSocketExtensionDispatcher.h in Headers */,
120                                 4A5A2ADC161E7E00005889DD /* WebSocketExtensionParser.h in Headers */,
121 @@ -31067,6 +31088,7 @@
122                                 0719427F1D088F21002AA51D /* AVFoundationMIMETypeCache.mm in Sources */,
123                                 070363E5181A1CDC00C074A5 /* AVMediaCaptureSource.mm in Sources */,
124                                 CD336F6117F9F64700DDDCD0 /* AVTrackPrivateAVFObjCImpl.mm in Sources */,
125 +                               11C0C7A7206953F700BE3A84 /* JSInlineTextRun.cpp in Sources */,
126                                 070363E7181A1CDC00C074A5 /* AVVideoCaptureSource.mm in Sources */,
127                                 7A45032F18DB717200377B34 /* BufferedLineReader.cpp in Sources */,
128                                 0753860214489E9800B78452 /* CachedTextTrack.cpp in Sources */,
129 diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp
130 index 923ab54d4f2..12004b5afbe 100644
131 --- a/Source/WebCore/css/CSSComputedStyleDeclaration.cpp
132 +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.cpp
133 @@ -4113,6 +4113,36 @@ String CSSComputedStyleDeclaration::getPropertyValue(CSSPropertyID propertyID) c
134      return value->cssText();
135  }
136  
137 +bool CSSComputedStyleDeclaration::isPropertyValueInitial(const String& propertyName)
138 +{
139 +    m_element->document().updateLayoutIgnorePendingStylesheets();
140 +    auto* style = m_element->computedStyle(m_pseudoElementSpecifier);
141 +    if (!style)
142 +        return true;
143 +
144 +    CSSPropertyID propertyID = cssPropertyID(propertyName);
145 +    if (!propertyID)
146 +        return true;
147 +
148 +    switch (propertyID) {
149 +    case CSSPropertyLeft:
150 +        return style->left().isAuto();
151 +    case CSSPropertyRight:
152 +        return style->right().isAuto();
153 +    case CSSPropertyTop:
154 +        return style->top().isAuto();
155 +    case CSSPropertyBottom:
156 +        return style->bottom().isAuto();
157 +    case CSSPropertyWidth:
158 +        return style->width().isAuto();
159 +    case CSSPropertyHeight:
160 +        return style->height().isAuto();
161 +    default:
162 +        ASSERT_NOT_REACHED();
163 +    }
164 +    return false;
165 +}
166 +
167  unsigned CSSComputedStyleDeclaration::length() const
168  {
169      updateStyleIfNeededForProperty(m_element.get(), CSSPropertyCustom);
170 diff --git a/Source/WebCore/css/CSSComputedStyleDeclaration.h b/Source/WebCore/css/CSSComputedStyleDeclaration.h
171 index 39ae6c30d7e..a3b6f4697bd 100644
172 --- a/Source/WebCore/css/CSSComputedStyleDeclaration.h
173 +++ b/Source/WebCore/css/CSSComputedStyleDeclaration.h
174 @@ -123,6 +123,7 @@ private:
175      String item(unsigned index) const final;
176      RefPtr<DeprecatedCSSOMValue> getPropertyCSSValue(const String& propertyName) final;
177      String getPropertyValue(const String& propertyName) final;
178 +    bool isPropertyValueInitial(const String& propertyName) final;
179      String getPropertyPriority(const String& propertyName) final;
180      String getPropertyShorthand(const String& propertyName) final;
181      bool isPropertyImplicit(const String& propertyName) final;
182 diff --git a/Source/WebCore/css/CSSStyleDeclaration.h b/Source/WebCore/css/CSSStyleDeclaration.h
183 index b18c9ce3274..4dfb6b936f8 100644
184 --- a/Source/WebCore/css/CSSStyleDeclaration.h
185 +++ b/Source/WebCore/css/CSSStyleDeclaration.h
186 @@ -54,6 +54,7 @@ public:
187      virtual String item(unsigned index) const = 0;
188      virtual RefPtr<DeprecatedCSSOMValue> getPropertyCSSValue(const String& propertyName) = 0;
189      virtual String getPropertyValue(const String& propertyName) = 0;
190 +    virtual bool isPropertyValueInitial(const String& propertyName) = 0;
191      virtual String getPropertyPriority(const String& propertyName) = 0;
192      virtual String getPropertyShorthand(const String& propertyName) = 0;
193      virtual bool isPropertyImplicit(const String& propertyName) = 0;
194 diff --git a/Source/WebCore/css/CSSStyleDeclaration.idl b/Source/WebCore/css/CSSStyleDeclaration.idl
195 index 035cb6245d9..c622313db3b 100644
196 --- a/Source/WebCore/css/CSSStyleDeclaration.idl
197 +++ b/Source/WebCore/css/CSSStyleDeclaration.idl
198 @@ -30,6 +30,8 @@
199  
200      DOMString getPropertyValue(DOMString propertyName);
201  
202 +    boolean isPropertyValueInitial(DOMString propertyName);
203 +
204      [CEReactions, MayThrowException] DOMString removeProperty(DOMString propertyName);
205      DOMString? getPropertyPriority(DOMString propertyName);
206  
207 diff --git a/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp b/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp
208 index 084cbca04ec..4fc589226cf 100644
209 --- a/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp
210 +++ b/Source/WebCore/css/PropertySetCSSStyleDeclaration.cpp
211 @@ -196,6 +196,11 @@ String PropertySetCSSStyleDeclaration::getPropertyValue(const String& propertyNa
212      return getPropertyValueInternal(propertyID);
213  }
214  
215 +bool PropertySetCSSStyleDeclaration::isPropertyValueInitial(const String&)
216 +{
217 +    return false;
218 +}
219 +
220  String PropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
221  {
222      if (isCustomPropertyName(propertyName))
223 diff --git a/Source/WebCore/css/PropertySetCSSStyleDeclaration.h b/Source/WebCore/css/PropertySetCSSStyleDeclaration.h
224 index 04196405ddf..59981205cae 100644
225 --- a/Source/WebCore/css/PropertySetCSSStyleDeclaration.h
226 +++ b/Source/WebCore/css/PropertySetCSSStyleDeclaration.h
227 @@ -68,6 +68,7 @@ private:
228      String item(unsigned index) const final;
229      RefPtr<DeprecatedCSSOMValue> getPropertyCSSValue(const String& propertyName) final;
230      String getPropertyValue(const String& propertyName) final;
231 +    bool isPropertyValueInitial(const String& propertyName) final;
232      String getPropertyPriority(const String& propertyName) final;
233      String getPropertyShorthand(const String& propertyName) final;
234      bool isPropertyImplicit(const String& propertyName) final;
235 diff --git a/Source/WebCore/dom/InlineTextRun.h b/Source/WebCore/dom/InlineTextRun.h
236 new file mode 100644
237 index 00000000000..7ae48649fbd
238 --- /dev/null
239 +++ b/Source/WebCore/dom/InlineTextRun.h
240 @@ -0,0 +1,79 @@
241 +/*
242 + * Copyright (C) 2018 Apple Inc. All rights reserved.
243 + *
244 + * Redistribution and use in source and binary forms, with or without
245 + * modification, are permitted provided that the following conditions
246 + * are met:
247 + * 1. Redistributions of source code must retain the above copyright
248 + *    notice, this list of conditions and the following disclaimer.
249 + * 2. Redistributions in binary form must reproduce the above copyright
250 + *    notice, this list of conditions and the following disclaimer in the
251 + *    documentation and/or other materials provided with the distribution.
252 + *
253 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
254 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
255 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
256 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
257 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
260 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
261 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
263 + * THE POSSIBILITY OF SUCH DAMAGE.
264 + */
265 +
266 +#pragma once
267 +
268 +#include "InlineTextRunIterator.h"
269 +#include <wtf/Ref.h>
270 +#include <wtf/RefCounted.h>
271 +
272 +namespace WebCore {
273 +
274 +class InlineTextRun : public RefCounted<InlineTextRun> {
275 +    WTF_MAKE_FAST_ALLOCATED;
276 +public:
277 +    static Ref<InlineTextRun> create(unsigned startPosition, unsigned endPosition, double width, unsigned type, bool isCollapsed, bool isCollapsible)
278 +        { return adoptRef(*new InlineTextRun(startPosition, endPosition, width, type, isCollapsed, isCollapsible)); }
279 +
280 +    static Ref<InlineTextRun> create(const LayoutReloaded::InlineTextRunIterator::Run& run)
281 +        { return adoptRef(*new InlineTextRun(run.start(), run.end(), run.width(), run.type(), run.isCollapsed(), run.isCollapsible())); }
282 +
283 +    enum Type { Invalid, ContentEnd, SoftLineBreak, Whitespace, NonWhitespace, Mixed };
284 +    void setStartPosition(unsigned position) { m_startPosition = position; }
285 +    void setEndPosition(unsigned position) { m_endPosition = position; }
286 +    void setWidth(double width) { m_width = width; }
287 +    void setTypeMixed() { m_type = InlineTextRun::Mixed; }
288 +    void setIsCollapsed() { m_isCollapsed = true; }
289 +
290 +    unsigned startPosition() const { return m_startPosition; }
291 +    unsigned endPosition() const { return m_endPosition; }
292 +    double width() const { return m_width; }
293 +    unsigned type() const { return m_type; }
294 +    unsigned length() const { return endPosition() - startPosition(); }
295 +    bool isCollapsed() const { return m_isCollapsed; }
296 +    bool isCollapsible() const { return m_isCollapsible; }
297 +
298 +protected:
299 +    InlineTextRun(unsigned startPosition, unsigned endPosition, double width, unsigned type, bool isCollapsed, bool isCollapsible)
300 +        : m_startPosition(startPosition)
301 +        , m_endPosition(endPosition)
302 +        , m_width(width)
303 +        , m_type(type)
304 +        , m_isCollapsed(isCollapsed)
305 +        , m_isCollapsible(isCollapsible)
306 +    {
307 +    }
308 +
309 +    InlineTextRun() = default;
310 +
311 +    unsigned m_startPosition { 0 };
312 +    unsigned m_endPosition { 0 };
313 +    double m_width { 0 };
314 +    unsigned m_type { 0 };
315 +    bool m_isCollapsed { false };
316 +    bool m_isCollapsible { false };
317 +};
318 +
319 +}
320 diff --git a/Source/WebCore/dom/InlineTextRun.idl b/Source/WebCore/dom/InlineTextRun.idl
321 new file mode 100644
322 index 00000000000..20c01b8cff5
323 --- /dev/null
324 +++ b/Source/WebCore/dom/InlineTextRun.idl
325 @@ -0,0 +1,36 @@
326 +/*
327 + * Copyright (C) 2018 Apple Inc. All rights reserved.
328 + *
329 + * Redistribution and use in source and binary forms, with or without
330 + * modification, are permitted provided that the following conditions
331 + * are met:
332 + * 1. Redistributions of source code must retain the above copyright
333 + *    notice, this list of conditions and the following disclaimer.
334 + * 2. Redistributions in binary form must reproduce the above copyright
335 + *    notice, this list of conditions and the following disclaimer in the
336 + *    documentation and/or other materials provided with the distribution.
337 + *
338 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
339 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
340 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
341 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
342 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
343 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
344 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
345 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
346 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
347 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
348 + * THE POSSIBILITY OF SUCH DAMAGE.
349 + */
350 +
351 +[
352 +    NoInterfaceObject,
353 +    ImplementationLacksVTable,
354 +] interface InlineTextRun {
355 +    readonly attribute long startPosition;
356 +    readonly attribute long endPosition;
357 +    readonly attribute double width;
358 +    readonly attribute long type;
359 +    readonly attribute boolean isCollapsed;
360 +    readonly attribute boolean isCollapsible;
361 +};
362 diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp
363 index 4b1e8725795..cae6e476cad 100644
364 --- a/Source/WebCore/dom/Node.cpp
365 +++ b/Source/WebCore/dom/Node.cpp
366 @@ -517,6 +517,27 @@ ExceptionOr<void> Node::before(Vector<NodeOrString>&& nodeOrStringVector)
367      return parent->insertBefore(*node, viablePreviousSibling.get());
368  }
369  
370 +int Node::rendererId()
371 +{
372 +    if (!renderer())
373 +        return 0;
374 +    return renderer()->renderId();
375 +}
376 +
377 +double Node::textWidth(int start, int end)
378 +{
379 +    if (!renderer())
380 +        return 0;
381 +    return renderer()->measureText(start, end);
382 +}
383 +
384 +double Node::textHeight()
385 +{
386 +    if (!renderer())
387 +        return 0;
388 +    return renderer()->style().computedFontPixelSize();
389 +}
390 +
391  ExceptionOr<void> Node::after(Vector<NodeOrString>&& nodeOrStringVector)
392  {
393      RefPtr<ContainerNode> parent = parentNode();
394 diff --git a/Source/WebCore/dom/Node.h b/Source/WebCore/dom/Node.h
395 index 7f176126c7a..1b7a19e07f0 100644
396 --- a/Source/WebCore/dom/Node.h
397 +++ b/Source/WebCore/dom/Node.h
398 @@ -179,7 +179,11 @@ public:
399  
400      WEBCORE_EXPORT String textContent(bool convertBRsToNewlines = false) const;
401      WEBCORE_EXPORT ExceptionOr<void> setTextContent(const String&);
402 -    
403 +
404 +    int rendererId();
405 +    double textWidth(int start, int end);
406 +    double textHeight();
407 +
408      Node* lastDescendant() const;
409      Node* firstDescendant() const;
410  
411 diff --git a/Source/WebCore/dom/Node.idl b/Source/WebCore/dom/Node.idl
412 index 25177a8cd43..294307dc815 100644
413 --- a/Source/WebCore/dom/Node.idl
414 +++ b/Source/WebCore/dom/Node.idl
415 @@ -73,6 +73,10 @@
416      unsigned short compareDocumentPosition(Node other);
417      boolean contains(Node? other);
418  
419 +    readonly attribute long rendererId;
420 +    double textWidth(long start, long end);
421 +    double textHeight();
422 +
423      DOMString? lookupPrefix(DOMString? namespaceURI);
424      DOMString? lookupNamespaceURI(DOMString? prefix);
425      boolean isDefaultNamespace(DOMString? namespaceURI);
426 diff --git a/Source/WebCore/page/DOMWindow.cpp b/Source/WebCore/page/DOMWindow.cpp
427 index 0210b08a182..4d3a54691a9 100644
428 --- a/Source/WebCore/page/DOMWindow.cpp
429 +++ b/Source/WebCore/page/DOMWindow.cpp
430 @@ -29,6 +29,7 @@
431  
432  #include "BackForwardController.h"
433  #include "BarProp.h"
434 +#include "BreakLines.h"
435  #include "CSSComputedStyleDeclaration.h"
436  #include "CSSRule.h"
437  #include "CSSRuleList.h"
438 @@ -64,9 +65,11 @@
439  #include "FrameTree.h"
440  #include "FrameView.h"
441  #include "History.h"
442 +#include "InlineTextRunIterator.h"
443  #include "InspectorInstrumentation.h"
444  #include "JSDOMWindowBase.h"
445  #include "JSMainThreadExecState.h"
446 +#include "InlineTextBreaker.h"
447  #include "Location.h"
448  #include "MediaQueryList.h"
449  #include "MediaQueryMatcher.h"
450 @@ -78,6 +81,8 @@
451  #include "PageConsoleClient.h"
452  #include "PageTransitionEvent.h"
453  #include "Performance.h"
454 +#include "RenderChildIterator.h"
455 +#include "RenderView.h"
456  #include "RequestAnimationFrameCallback.h"
457  #include "ResourceLoadInfo.h"
458  #include "ResourceLoadObserver.h"
459 @@ -100,6 +105,7 @@
460  #include "StyleResolver.h"
461  #include "StyleScope.h"
462  #include "SuddenTermination.h"
463 +#include "InlineTextRun.h"
464  #include "URL.h"
465  #include "UserGestureIndicator.h"
466  #include "VisualViewport.h"
467 @@ -116,6 +122,7 @@
468  #include <wtf/NeverDestroyed.h>
469  #include <wtf/Ref.h>
470  #include <wtf/Variant.h>
471 +#include <wtf/text/TextBreakIterator.h>
472  #include <wtf/text/WTFString.h>
473  
474  #if ENABLE(USER_MESSAGE_HANDLERS)
475 @@ -1358,6 +1365,72 @@ int DOMWindow::scrollY() const
476      return view->mapFromLayoutToCSSUnits(view->contentsScrollPosition().y());
477  }
478  
479 +String DOMWindow::simplifiedRenderTree() const
480 +{
481 +    return m_frame->view()->renderView()->simplifiedRenderTree();
482 +}
483 +
484 +String DOMWindow::renderTreeStructure() const
485 +{
486 +    return m_frame->view()->renderView()->renderTreeStructure();
487 +}
488 +
489 +static bool hasDirtyChild(RenderElement& parent)
490 +{
491 +    for (auto& child : childrenOfType<RenderElement>(parent)) {
492 +        if (child.needsLayout())
493 +            return true;
494 +    }
495 +    return false;
496 +}
497 +
498 +static void collectDirtyRenderers(RenderElement& container, Vector<long>& dirtyRenderers)
499 +{
500 +    // Collect the leaf marks only -would be cheating othewise.
501 +    for (auto& child : childrenOfType<RenderElement>(container)) {
502 +        if (!child.needsLayout())
503 +            continue;
504 +        if (!hasDirtyChild(child))
505 +            dirtyRenderers.append(child.renderId());
506 +        else
507 +            collectDirtyRenderers(child, dirtyRenderers);
508 +    }
509 +}
510 +
511 +Vector<long> DOMWindow::collectRenderersWithNeedsLayout()
512 +{
513 +    Vector<long> dirtyRenderers;
514 +    auto* renderView = m_frame->view()->renderView();
515 +    m_frame->document()->updateStyleIfNeeded();
516 +    collectDirtyRenderers(*renderView, dirtyRenderers);
517 +    return dirtyRenderers;
518 +}
519 +
520 +Vector<Ref<InlineTextRun>> DOMWindow::collectTextRuns(const String& text, const Node& container, float availableSpace)
521 +{
522 +    Vector<Ref<InlineTextRun>> textRuns;
523 +    LayoutReloaded::InlineTextRunIterator textIterator(text, container.renderer()->style());
524 +    while (true) {
525 +        auto run = textIterator.nextRun();
526 +        if (run.type() == LayoutReloaded::InlineTextRunIterator::Run::ContentEnd)
527 +            break;
528 +        textRuns.append(InlineTextRun::create(run));
529 +    }
530 +    if (std::isnan(availableSpace))
531 +        return textRuns;
532 +
533 +    return LayoutReloaded::InlineTextBreaker::collectRuns(textRuns, text, availableSpace, container.renderer()->style());
534 +}
535 +
536 +int DOMWindow::nextBreakingOpportunity(const String& text, unsigned startPosition)
537 +{
538 +    LazyLineBreakIterator lineBreakIterator(text, m_frame->view()->renderView()->style().locale());
539 +
540 +    if (lineBreakIterator.mode() == LineBreakIteratorMode::Default)
541 +            return WebCore::nextBreakablePosition(lineBreakIterator, startPosition);
542 +    return nextBreakablePositionWithoutShortcut(lineBreakIterator, startPosition);
543 +}
544 +
545  bool DOMWindow::closed() const
546  {
547      return !m_frame;
548 diff --git a/Source/WebCore/page/DOMWindow.h b/Source/WebCore/page/DOMWindow.h
549 index 499a558d2ee..be60b3aaf79 100644
550 --- a/Source/WebCore/page/DOMWindow.h
551 +++ b/Source/WebCore/page/DOMWindow.h
552 @@ -49,7 +49,6 @@ template<typename> class Strong;
553  }
554  
555  namespace WebCore {
556 -
557  class BarProp;
558  class CSSRuleList;
559  class CSSStyleDeclaration;
560 @@ -78,6 +77,7 @@ class ScheduledAction;
561  class Screen;
562  class Storage;
563  class StyleMedia;
564 +class InlineTextRun;
565  class VisualViewport;
566  class WebKitNamespace;
567  class WebKitPoint;
568 @@ -192,6 +192,12 @@ public:
569      String defaultStatus() const;
570      void setDefaultStatus(const String&);
571  
572 +    String simplifiedRenderTree() const;
573 +    String renderTreeStructure() const;
574 +    Vector<long> collectRenderersWithNeedsLayout();
575 +    int nextBreakingOpportunity(const String& text, unsigned startPosition);
576 +    Vector<Ref<InlineTextRun>> collectTextRuns(const String&, const Node&, float availableSpace);
577 +
578      DOMWindow* self() const;
579  
580      DOMWindow* opener() const;
581 diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl
582 index 46ebc1561fa..bd35d3f2155 100644
583 --- a/Source/WebCore/page/DOMWindow.idl
584 +++ b/Source/WebCore/page/DOMWindow.idl
585 @@ -82,6 +82,12 @@ typedef USVString CSSOMString;
586      readonly attribute Navigator navigator;
587      readonly attribute DOMApplicationCache applicationCache;
588  
589 +    readonly attribute DOMString simplifiedRenderTree;
590 +    readonly attribute DOMString renderTreeStructure;
591 +    sequence<long> collectRenderersWithNeedsLayout();
592 +    long nextBreakingOpportunity(DOMString text, unsigned long startPosition);
593 +    sequence<InlineTextRun> collectTextRuns(DOMString text, Node containerNode, optional unrestricted float availableSpace = NaN);
594 +
595      // User prompts.
596      void alert();
597      void alert(DOMString message);
598 diff --git a/Source/WebCore/page/mac/PageMac.mm b/Source/WebCore/page/mac/PageMac.mm
599 index aa030c54617..7457861e142 100644
600 --- a/Source/WebCore/page/mac/PageMac.mm
601 +++ b/Source/WebCore/page/mac/PageMac.mm
602 @@ -52,11 +52,6 @@ void Page::platformInitialize()
603  #endif
604  
605  #if ENABLE(TREE_DEBUGGING)
606 -    static std::once_flag onceFlag;
607 -    std::call_once(onceFlag, [] {
608 -        PAL::registerNotifyCallback("com.apple.WebKit.showRenderTree", printRenderTreeForLiveDocuments);
609 -        PAL::registerNotifyCallback("com.apple.WebKit.showLayerTree", printLayerTreeForLiveDocuments);
610 -    });
611  #endif
612  }
613  
614 diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp
615 index cd23ae0b97c..7cfd4bb2d42 100644
616 --- a/Source/WebCore/rendering/InlineBox.cpp
617 +++ b/Source/WebCore/rendering/InlineBox.cpp
618 @@ -123,6 +123,18 @@ void InlineBox::outputLineBox(TextStream& stream, bool mark, int depth) const
619      stream.nextLine();
620  }
621  
622 +void InlineBox::outputSimplifiedLineTree(TextStream& stream, int depth) const
623 +{
624 +    // Ignore inline flows for now. LayoutReloaded does not have the concept of flow boxes.
625 +    if (is<InlineFlowBox>(*this) && !is<RootInlineBox>(*this))
626 +        return;
627 +    int printedCharacters = 0;
628 +    while (++printedCharacters <= depth)
629 +        stream << " ";
630 +    stream << boxName() << " " << FloatRect(x(), y(), width(), height());
631 +    stream.nextLine();
632 +}
633 +
634  #endif // ENABLE(TREE_DEBUGGING)
635  
636  float InlineBox::logicalHeight() const
637 diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h
638 index 7f1dd6cbba4..eddb048440a 100644
639 --- a/Source/WebCore/rendering/InlineBox.h
640 +++ b/Source/WebCore/rendering/InlineBox.h
641 @@ -78,6 +78,7 @@ public:
642      void showLineTreeForThis() const;
643      
644      virtual void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const;
645 +    virtual void outputSimplifiedLineTree(WTF::TextStream&, int depth) const;
646      virtual void outputLineBox(WTF::TextStream&, bool mark, int depth) const;
647      virtual const char* boxName() const;
648  #endif
649 diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp
650 index 063f3b64189..ee32b981371 100644
651 --- a/Source/WebCore/rendering/InlineFlowBox.cpp
652 +++ b/Source/WebCore/rendering/InlineFlowBox.cpp
653 @@ -1720,6 +1720,18 @@ void InlineFlowBox::outputLineTreeAndMark(WTF::TextStream& stream, const InlineB
654          box->outputLineTreeAndMark(stream, markedBox, depth + 1);
655  }
656  
657 +void InlineFlowBox::outputSimplifiedLineTree(WTF::TextStream& stream, int depth) const
658 +{
659 +    InlineBox::outputSimplifiedLineTree(stream, depth);
660 +    for (auto* box = firstChild(); box; box = box->nextOnLine()) {
661 +        // DO not increment depth for flow boxes. LayoutReloaded does not have the concept of them.
662 +        if (is<InlineFlowBox>(*box) && !is<RootInlineBox>(*box))
663 +            box->outputSimplifiedLineTree(stream, depth);
664 +        else
665 +            box->outputSimplifiedLineTree(stream, depth + 1);
666 +    }
667 +}
668 +
669  #endif
670  
671  #ifndef NDEBUG
672 diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h
673 index 0b26444903f..595203b201e 100644
674 --- a/Source/WebCore/rendering/InlineFlowBox.h
675 +++ b/Source/WebCore/rendering/InlineFlowBox.h
676 @@ -72,6 +72,7 @@ public:
677  
678  #if ENABLE(TREE_DEBUGGING)
679      void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const override;
680 +    void outputSimplifiedLineTree(WTF::TextStream&, int depth) const override;
681      const char* boxName() const override;
682  #endif
683  
684 diff --git a/Source/WebCore/rendering/InlineTextBreaker.cpp b/Source/WebCore/rendering/InlineTextBreaker.cpp
685 new file mode 100644
686 index 00000000000..9ac083d2a90
687 --- /dev/null
688 +++ b/Source/WebCore/rendering/InlineTextBreaker.cpp
689 @@ -0,0 +1,308 @@
690 +/*
691 + * Copyright (C) 2018 Apple Inc. All rights reserved.
692 + *
693 + * Redistribution and use in source and binary forms, with or without
694 + * modification, are permitted provided that the following conditions
695 + * are met:
696 + * 1. Redistributions of source code must retain the above copyright
697 + *    notice, this list of conditions and the following disclaimer.
698 + * 2. Redistributions in binary form must reproduce the above copyright
699 + *    notice, this list of conditions and the following disclaimer in the
700 + *    documentation and/or other materials provided with the distribution.
701 + *
702 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
703 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
704 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
705 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
706 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
707 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
708 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
709 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
710 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
711 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
712 + * THE POSSIBILITY OF SUCH DAMAGE.
713 + */
714 +
715 +#include "config.h"
716 +#include "InlineTextBreaker.h"
717 +
718 +#include "FontCascade.h"
719 +#include "RenderStyle.h"
720 +
721 +namespace WebCore {
722 +namespace LayoutReloaded {
723 +
724 +InlineTextBreaker::Style::Style(const RenderStyle& style)
725 +    : font(style.fontCascade())
726 +    , hasKerningOrLigatures(font.enableKerning() || font.requiresShaping())
727 +    , collapseWhitespace(style.collapseWhiteSpace())
728 +    , preserveNewline(style.preserveNewline())
729 +    , wrapLines(style.autoWrap())
730 +    , breakAnyWordOnOverflow(style.wordBreak() == BreakAllWordBreak && wrapLines)
731 +    , breakFirstWordOnOverflow(breakAnyWordOnOverflow || (style.breakWords() && (wrapLines || preserveNewline)))
732 +    , wordSpacing(font.wordSpacing())
733 +    , tabWidth(collapseWhitespace ? 0 : style.tabSize())
734 +{
735 +}
736 +
737 +InlineTextBreaker::LineState::LineState(const InlineTextBreaker& lineBreaker, float availableWidth)
738 +    : m_lineBreaker(lineBreaker)
739 +    , m_availableWidth(availableWidth)
740 +{
741 +}
742 +
743 +float InlineTextBreaker::LineState::availableWidth() const
744 +{
745 +    return m_availableWidth;
746 +}
747 +
748 +bool InlineTextBreaker::LineState::hasTrailingWhitespace() const
749 +{
750 +    return m_hasTrailingWhitespace;
751 +}
752 +
753 +bool InlineTextBreaker::LineState::isWhitespaceOnly() const
754 +{
755 +    for (auto& run : m_runs) {
756 +        if (run->type() != InlineTextRun::Whitespace)
757 +            return false;
758 +    }
759 +    return true;
760 +}
761 +
762 +bool InlineTextBreaker::LineState::fits(float extra) const
763 +{
764 +    return m_availableWidth >= width() + extra;
765 +}
766 +
767 +float InlineTextBreaker::LineState::width() const
768 +{
769 +    float width = 0;
770 +    for (auto& run : m_runs)
771 +        width += m_lineBreaker.textWidth(run->startPosition(), run->endPosition());
772 +    return width;
773 +}
774 +
775 +bool InlineTextBreaker::LineState::isEmpty() const
776 +{
777 +    return !m_runs.size();
778 +}
779 +
780 +static inline unsigned endPositionForCollapsedRun(const InlineTextRun& run)
781 +{
782 +    if (run.isCollapsed())
783 +        return run.startPosition() + 1;
784 +    return run.endPosition();
785 +}
786 +
787 +void InlineTextBreaker::LineState::appendRun(const InlineTextRun& run)
788 +{
789 +    // Adjust end position while collapsing.
790 +    unsigned endPosition = endPositionForCollapsedRun(run);
791 +    if (run.type() == InlineTextRun::NonWhitespace)
792 +        m_lastNoneWhitespacePosition = endPosition;
793 +    // New line needs new run.
794 +    if (!m_runs.size()) {
795 +        m_runs.append(InlineTextRun::create(run.startPosition(), endPosition, 0, run.type(), run.isCollapsed(), run.isCollapsible()));
796 +    } else {
797 +        // Advance last completed fragment when the previous fragment is all set (including multiple parts across renderers)
798 +        if (m_runs.last()->isCollapsible() && run.isCollapsible()) {
799 +            // This fragment is collapsed completely. No run is needed.
800 +            return;
801 +        }
802 +        auto& lastRun = m_runs.last();
803 +        if (lastRun->isCollapsed())
804 +            m_runs.append(InlineTextRun::create(run.startPosition(), endPosition, 0, run.type(), run.isCollapsed(), run.isCollapsible()));
805 +        else {
806 +            lastRun->setEndPosition(endPosition);
807 +            lastRun->setTypeMixed();
808 +            if (run.isCollapsed())
809 +                lastRun->setIsCollapsed();
810 +        }
811 +    }
812 +    m_hasTrailingWhitespace = run.type() == InlineTextRun::Whitespace;
813 +}
814 +
815 +void InlineTextBreaker::LineState::removeTrailingWhitespace()
816 +{
817 +    if (!m_hasTrailingWhitespace)
818 +        return;
819 +    if (m_runs.last()->type() == InlineTextRun::Whitespace) {
820 +        m_runs.removeLast();
821 +        return;
822 +    }
823 +    ASSERT(m_runs.last()->type() == InlineTextRun::Mixed);
824 +    m_runs.last()->setEndPosition(m_lastNoneWhitespacePosition);
825 +}
826 +
827 +Vector<Ref<InlineTextRun>> InlineTextBreaker::LineState::collectRuns()
828 +{
829 +    for (auto& run: m_runs)
830 +        run->setWidth(m_lineBreaker.textWidth(run->startPosition(), run->endPosition()));
831 +    return WTFMove(m_runs);
832 +}
833 +
834 +InlineTextBreaker::InlineTextBreaker(Vector<Ref<InlineTextRun>>& runs, const String& text, float availableWidth, const RenderStyle& style)
835 +    : m_textRuns(runs)
836 +    , m_text(text)
837 +    , m_style(style)
838 +    , m_line(*this, availableWidth)
839 +{
840 +}
841 +
842 +Vector<Ref<InlineTextRun>> InlineTextBreaker::collectRuns(Vector<Ref<InlineTextRun>>& runs, const String& text, float availableWidth, const RenderStyle& style)
843 +{
844 +    return InlineTextBreaker(runs, text, availableWidth, style).createAndCollectLineRuns();
845 +}
846 +
847 +bool InlineTextBreaker::preWrap() const
848 +{
849 +    return m_style.wrapLines && !m_style.collapseWhitespace;
850 +}
851 +
852 +void InlineTextBreaker::removeTrailingWhitespace()
853 +{
854 +    if (!m_line.hasTrailingWhitespace())
855 +        return;
856 +    // Remove collapsed whitespace, or non-collapsed pre-wrap whitespace, unless it's the only content on the line -so removing the whitesapce
857 +    // would produce an empty line.
858 +    bool collapseWhitespace = m_style.collapseWhitespace | preWrap();
859 +    if (!collapseWhitespace)
860 +        return;
861 +    if (preWrap() && m_line.isWhitespaceOnly())
862 +        return;
863 +    m_line.removeTrailingWhitespace();
864 +}
865 +
866 +struct SplitFragmentData {
867 +    unsigned position;
868 +    float width;
869 +};
870 +
871 +SplitFragmentData InlineTextBreaker::split(const InlineTextRun& run, float availableWidth)
872 +{
873 +    ASSERT(availableWidth >= 0);
874 +    auto left = run.startPosition();
875 +    // Pathological case of (extremely)long string and narrow lines.
876 +    // Adjust the range so that we can pick a reasonable midpoint.
877 +    auto averageCharacterWidth = run.width() / run.length();
878 +    auto right = std::min<unsigned>(left + (2 * availableWidth / averageCharacterWidth), run.endPosition() - 1);
879 +    // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
880 +    float leftSideWidth = 0;
881 +    while (left < right) {
882 +        auto middle = (left + right) / 2;
883 +        auto width = textWidth(run.startPosition(), middle + 1);
884 +        if (width < availableWidth) {
885 +            left = middle + 1;
886 +            leftSideWidth = width;
887 +        } else if (width > availableWidth)
888 +            right = middle;
889 +        else {
890 +            right = middle + 1;
891 +            leftSideWidth = width;
892 +            break;
893 +        }
894 +    }
895 +    return { right, leftSideWidth };
896 +}
897 +
898 +void InlineTextBreaker::splitRunToFitLine(InlineTextRun& runToSplit)
899 +{
900 +    auto availableWidth = m_line.availableWidth() - m_line.width();
901 +    auto splitRunData = split(runToSplit, availableWidth);
902 +    // Does first character fit this line?
903 +    if (splitRunData.position == runToSplit.startPosition()) {
904 +        // Keep at least one character on empty lines.
905 +        if (m_line.isEmpty())
906 +            splitRunData.width = textWidth(runToSplit.startPosition(), ++splitRunData.position);
907 +    }
908 +    runToSplit.setEndPosition(splitRunData.position);
909 +    runToSplit.setWidth(splitRunData.width);
910 +}
911 +
912 +unsigned InlineTextBreaker::skipLeadingWhitespaceIfNeeded() const
913 +{
914 +    if (!m_style.collapseWhitespace)
915 +        return 0;
916 +
917 +    for (unsigned index = 0; index < m_textRuns.size(); ++index) {
918 +        if (m_textRuns[index]->type() != InlineTextRun::Whitespace)
919 +            return index;
920 +    }
921 +    return m_textRuns.size();
922 +}
923 +
924 +Vector<Ref<InlineTextRun>> InlineTextBreaker::createAndCollectLineRuns()
925 +{
926 +    bool lineCanBeWrapped = m_style.wrapLines || m_style.breakFirstWordOnOverflow || m_style.breakAnyWordOnOverflow;
927 +    auto index = skipLeadingWhitespaceIfNeeded();
928 +    for (; index < m_textRuns.size(); ++index) {
929 +        auto& run = m_textRuns[index];
930 +        // Hard and soft linebreaks.
931 +        if (run->type() == InlineTextRun::SoftLineBreak) {
932 +            // Add the new line fragment only if there's nothing on the line. (otherwise the extra new line character would show up at the end of the content.)
933 +            if (m_line.isEmpty())
934 +                m_line.appendRun(run);
935 +            break;
936 +        }
937 +        if (lineCanBeWrapped && !m_line.fits(run->width())) {
938 +            // Overflow wrapping behaviour:
939 +            // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
940 +            // 2. Whitespace collapse off: whitespace is wrapped.
941 +            // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
942 +            // 5. Non-whitespace fragment when there's already another fragment on the line either gets wrapped (word-break: break-all)
943 +            // or gets pushed to the next line.
944 +            bool emptyLine = m_line.isEmpty();
945 +            // Whitespace fragment.
946 +            if (run->type() == InlineTextRunIterator::Run::Whitespace) {
947 +                if (m_style.collapseWhitespace) {
948 +                    // Push collapased whitespace to the next line.
949 +                    break;
950 +                }
951 +                // Split the whitespace; left part stays on this line, right is pushed to next line.
952 +                splitRunToFitLine(run);
953 +                m_line.appendRun(run);
954 +                break;
955 +            }
956 +            // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
957 +            if (((emptyLine && m_style.breakFirstWordOnOverflow) || m_style.breakAnyWordOnOverflow) || !m_style.wrapLines) {
958 +                // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
959 +                splitRunToFitLine(run);
960 +                m_line.appendRun(run);
961 +                break;
962 +            }
963 +            ASSERT(run->type() == InlineTextRunIterator::Run::NonWhitespace);
964 +            // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
965 +            if (emptyLine) {
966 +                m_line.appendRun(run);
967 +                break;
968 +            }
969 +            // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
970 +            break;
971 +        }
972 +        m_line.appendRun(run);
973 +    }
974 +    removeTrailingWhitespace();
975 +    return m_line.collectRuns();
976 +}
977 +
978 +float InlineTextBreaker::textWidth(unsigned from, unsigned to) const
979 +{
980 +    if (!m_style.font.size() || from == to)
981 +        return 0;
982 +
983 +    bool measureWithEndSpace = m_style.hasKerningOrLigatures && m_style.collapseWhitespace && to < m_text.length() && m_text[to] == ' ';
984 +    if (measureWithEndSpace)
985 +        ++to;
986 +    float width = 0;
987 +    TextRun run(StringView(m_text).substring(from, to - from), 0);
988 +    if (m_style.tabWidth)
989 +        run.setTabSize(true, m_style.tabWidth);
990 +    width = m_style.font.width(run);
991 +    if (measureWithEndSpace)
992 +        width -= (m_style.font.spaceWidth() + m_style.wordSpacing);
993 +    return std::max<float>(0, width);
994 +}
995 +
996 +}
997 +}
998 diff --git a/Source/WebCore/rendering/InlineTextBreaker.h b/Source/WebCore/rendering/InlineTextBreaker.h
999 new file mode 100644
1000 index 00000000000..8cf678fd5c5
1001 --- /dev/null
1002 +++ b/Source/WebCore/rendering/InlineTextBreaker.h
1003 @@ -0,0 +1,97 @@
1004 +/*
1005 + * Copyright (C) 2018 Apple Inc. All rights reserved.
1006 + *
1007 + * Redistribution and use in source and binary forms, with or without
1008 + * modification, are permitted provided that the following conditions
1009 + * are met:
1010 + * 1. Redistributions of source code must retain the above copyright
1011 + *    notice, this list of conditions and the following disclaimer.
1012 + * 2. Redistributions in binary form must reproduce the above copyright
1013 + *    notice, this list of conditions and the following disclaimer in the
1014 + *    documentation and/or other materials provided with the distribution.
1015 + *
1016 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
1017 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1018 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1019 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
1020 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1021 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1022 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1023 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1024 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1025 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1026 + * THE POSSIBILITY OF SUCH DAMAGE.
1027 + */
1028 +
1029 +#pragma once
1030 +
1031 +#include "InlineTextRun.h"
1032 +
1033 +namespace WebCore {
1034 +
1035 +class FontCascade;
1036 +
1037 +namespace LayoutReloaded {
1038 +
1039 +class LineState;
1040 +struct SplitFragmentData;
1041 +
1042 +class InlineTextBreaker {
1043 +public:
1044 +    static Vector<Ref<InlineTextRun>> collectRuns(Vector<Ref<InlineTextRun>>&, const String&, float availableWidth, const RenderStyle&);
1045 +
1046 +private:
1047 +    InlineTextBreaker(Vector<Ref<InlineTextRun>>&, const String&, float availableWidth, const RenderStyle&);
1048 +
1049 +    Vector<Ref<InlineTextRun>> createAndCollectLineRuns();
1050 +    SplitFragmentData split(const InlineTextRun& run, float availableWidth);
1051 +    void splitRunToFitLine(InlineTextRun& runToSplit);
1052 +    void removeTrailingWhitespace();
1053 +    bool preWrap() const;
1054 +    float textWidth(unsigned from, unsigned to) const;
1055 +    unsigned skipLeadingWhitespaceIfNeeded() const;
1056 +
1057 +    struct Style {
1058 +        explicit Style(const RenderStyle&);
1059 +
1060 +        const FontCascade& font;
1061 +        bool hasKerningOrLigatures;
1062 +        bool collapseWhitespace;
1063 +        bool preserveNewline;
1064 +        bool wrapLines;
1065 +        bool breakAnyWordOnOverflow;
1066 +        bool breakFirstWordOnOverflow;
1067 +        float wordSpacing;
1068 +        unsigned tabWidth;
1069 +    };
1070 +
1071 +    class LineState {
1072 +    public:
1073 +        LineState(const InlineTextBreaker& lineBreaker, float availableWidth);
1074 +
1075 +        float availableWidth() const;
1076 +        bool hasTrailingWhitespace() const;
1077 +        bool isWhitespaceOnly() const;
1078 +        bool fits(float extra) const;
1079 +        float width() const;
1080 +        bool isEmpty() const;
1081 +        void appendRun(const InlineTextRun&);
1082 +        void removeTrailingWhitespace();
1083 +        Vector<Ref<InlineTextRun>> collectRuns();
1084 +
1085 +    private:
1086 +        const InlineTextBreaker& m_lineBreaker;
1087 +        float m_availableWidth { 0 };
1088 +        Vector<Ref<InlineTextRun>> m_runs;
1089 +        bool m_hasTrailingWhitespace { false };
1090 +        unsigned m_lastNoneWhitespacePosition { 0 };
1091 +    };
1092 +
1093 +    Vector<Ref<InlineTextRun>>& m_textRuns;
1094 +    String m_text;
1095 +    const Style m_style;
1096 +    LineState m_line;
1097 +};
1098 +
1099 +}
1100 +}
1101 diff --git a/Source/WebCore/rendering/InlineTextRunIterator.cpp b/Source/WebCore/rendering/InlineTextRunIterator.cpp
1102 new file mode 100644
1103 index 00000000000..6714a5df199
1104 --- /dev/null
1105 +++ b/Source/WebCore/rendering/InlineTextRunIterator.cpp
1106 @@ -0,0 +1,167 @@
1107 +/*
1108 + * Copyright (C) 2018 Apple Inc. All rights reserved.
1109 + *
1110 + * Redistribution and use in source and binary forms, with or without
1111 + * modification, are permitted provided that the following conditions
1112 + * are met:
1113 + * 1. Redistributions of source code must retain the above copyright
1114 + *    notice, this list of conditions and the following disclaimer.
1115 + * 2. Redistributions in binary form must reproduce the above copyright
1116 + *    notice, this list of conditions and the following disclaimer in the
1117 + *    documentation and/or other materials provided with the distribution.
1118 + *
1119 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
1120 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1121 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1122 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
1123 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1124 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1125 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1126 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1127 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1128 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1129 + * THE POSSIBILITY OF SUCH DAMAGE.
1130 + */
1131 +
1132 +#include "config.h"
1133 +#include "InlineTextRunIterator.h"
1134 +
1135 +#include "FontCascade.h"
1136 +
1137 +namespace WebCore {
1138 +namespace LayoutReloaded {
1139 +
1140 +InlineTextRunIterator::Style::Style(const RenderStyle& style)
1141 +    : font(style.fontCascade())
1142 +    , textAlign(style.textAlign())
1143 +    , hasKerningOrLigatures(font.enableKerning() || font.requiresShaping())
1144 +    , collapseWhitespace(style.collapseWhiteSpace())
1145 +    , preserveNewline(style.preserveNewline())
1146 +    , wrapLines(style.autoWrap())
1147 +    , breakAnyWordOnOverflow(style.wordBreak() == BreakAllWordBreak && wrapLines)
1148 +    , breakFirstWordOnOverflow(breakAnyWordOnOverflow || (style.breakWords() && (wrapLines || preserveNewline)))
1149 +    , breakNBSP(wrapLines && style.nbspMode() == SPACE)
1150 +    , keepAllWordsForCJK(style.wordBreak() == KeepAllWordBreak)
1151 +    , wordSpacing(font.wordSpacing())
1152 +    , tabWidth(collapseWhitespace ? 0 : style.tabSize())
1153 +    , locale(style.locale())
1154 +{
1155 +}
1156 +
1157 +InlineTextRunIterator::InlineTextRunIterator(const String& text, const RenderStyle& style)
1158 +    : m_lineBreakIterator(text, style.locale())
1159 +    , m_style(style)
1160 +    , m_text(text)
1161 +{
1162 +}
1163 +
1164 +InlineTextRunIterator::Run InlineTextRunIterator::nextRun()
1165 +{
1166 +    // A fragment can either be
1167 +    // 1. line break when <br> is present or preserveNewline is on (not considered as whitespace) or
1168 +    // 2. whitespace (collasped, non-collapsed multi or single) or
1169 +    // 3. non-whitespace characters.
1170 +    // 4. content end.
1171 +    unsigned startPosition = m_position;
1172 +    if (m_text.length() == m_position)
1173 +        return Run(startPosition, startPosition, 0, Run::ContentEnd, false, false);
1174 +    if (isSoftLineBreak()) {
1175 +        unsigned endPosition = ++m_position;
1176 +        return Run(startPosition, endPosition, 0, Run::SoftLineBreak, false, false);
1177 +    }
1178 +    float width = 0;
1179 +    unsigned endPosition = skipToNextPosition(PositionType::NonWhitespace, startPosition, width);
1180 +    if (startPosition < endPosition) {
1181 +        bool multipleWhitespace = startPosition + 1 < endPosition;
1182 +        bool isCollapsed = multipleWhitespace && m_style.collapseWhitespace;
1183 +        m_position = endPosition;
1184 +        return Run(startPosition, endPosition, width, Run::Whitespace, isCollapsed, m_style.collapseWhitespace);
1185 +    }
1186 +    endPosition = skipToNextPosition(PositionType::Breakable, startPosition, width);
1187 +    m_position = endPosition;
1188 +    return Run(startPosition, endPosition, width, Run::NonWhitespace, false, false);
1189 +}
1190 +
1191 +bool InlineTextRunIterator::isSoftLineBreak() const
1192 +{
1193 +    return m_style.preserveNewline && m_text[m_position] == '\n';
1194 +}
1195 +
1196 +static inline unsigned nextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, unsigned startPosition, bool breakNBSP, bool keepAllWordsForCJK)
1197 +{
1198 +    if (keepAllWordsForCJK) {
1199 +        if (breakNBSP)
1200 +            return nextBreakablePositionKeepingAllWords(lineBreakIterator, startPosition);
1201 +        return nextBreakablePositionKeepingAllWordsIgnoringNBSP(lineBreakIterator, startPosition);
1202 +    }
1203 +
1204 +    if (lineBreakIterator.mode() == LineBreakIteratorMode::Default) {
1205 +        if (breakNBSP)
1206 +            return WebCore::nextBreakablePosition(lineBreakIterator, startPosition);
1207 +        return nextBreakablePositionIgnoringNBSP(lineBreakIterator, startPosition);
1208 +    }
1209 +
1210 +    if (breakNBSP)
1211 +        return nextBreakablePositionWithoutShortcut(lineBreakIterator, startPosition);
1212 +    return nextBreakablePositionIgnoringNBSPWithoutShortcut(lineBreakIterator, startPosition);
1213 +}
1214 +
1215 +unsigned InlineTextRunIterator::nextNonWhitespacePosition(unsigned startPosition)
1216 +{
1217 +    ASSERT(startPosition < m_text.length());
1218 +    unsigned position = startPosition;
1219 +    for (; position < m_text.length(); ++position) {
1220 +        auto character = m_text[position];
1221 +        bool isWhitespace = character == ' ' || character == '\t' || (!m_style.preserveNewline && character == '\n');
1222 +        if (!isWhitespace)
1223 +            return position;
1224 +    }
1225 +    return position;
1226 +}
1227 +
1228 +unsigned InlineTextRunIterator::skipToNextPosition(PositionType positionType, unsigned startPosition, float& width)
1229 +{
1230 +    unsigned currentPosition = startPosition;
1231 +    unsigned nextPosition = currentPosition;
1232 +    // Collapsed whitespace has constant width. Do not measure it.
1233 +    if (positionType == NonWhitespace)
1234 +        nextPosition = nextNonWhitespacePosition(currentPosition);
1235 +    else if (positionType == Breakable) {
1236 +        nextPosition = nextBreakablePosition(m_lineBreakIterator, currentPosition, m_style.breakNBSP, m_style.keepAllWordsForCJK);
1237 +        // nextBreakablePosition returns the same position for certain characters such as hyphens. Call next again with modified position.
1238 +        bool skipCurrentPosition = nextPosition == currentPosition;
1239 +        if (skipCurrentPosition)
1240 +            nextPosition = nextBreakablePosition(m_lineBreakIterator, currentPosition + 1, m_style.breakNBSP, m_style.keepAllWordsForCJK);
1241 +    }
1242 +    width = 0;
1243 +    if (nextPosition == currentPosition)
1244 +        return currentPosition;
1245 +    // Both non-collapsed whitespace and non-whitespace runs need to be measured.
1246 +    bool measureText = positionType != NonWhitespace || !m_style.collapseWhitespace;
1247 +    if (measureText)
1248 +        width = this->textWidth(currentPosition, nextPosition);
1249 +    else if (startPosition < nextPosition)
1250 +        width = m_style.font.spaceWidth() + m_style.wordSpacing;
1251 +    return nextPosition;
1252 +}
1253 +
1254 +float InlineTextRunIterator::textWidth(unsigned from, unsigned to) const
1255 +{
1256 +    if (!m_style.font.size() || from == to)
1257 +        return 0;
1258 +
1259 +    bool measureWithEndSpace = m_style.hasKerningOrLigatures && m_style.collapseWhitespace && to < m_text.length() && m_text[to] == ' ';
1260 +    if (measureWithEndSpace)
1261 +        ++to;
1262 +    float width = 0;
1263 +    TextRun run(StringView(m_text).substring(from, to - from), 0);
1264 +    if (m_style.tabWidth)
1265 +        run.setTabSize(true, m_style.tabWidth);
1266 +    width = m_style.font.width(run);
1267 +    if (measureWithEndSpace)
1268 +        width -= (m_style.font.spaceWidth() + m_style.wordSpacing);
1269 +    return std::max<float>(0, width);
1270 +}
1271 +
1272 +}
1273 +}
1274 diff --git a/Source/WebCore/rendering/InlineTextRunIterator.h b/Source/WebCore/rendering/InlineTextRunIterator.h
1275 new file mode 100644
1276 index 00000000000..594f95e0378
1277 --- /dev/null
1278 +++ b/Source/WebCore/rendering/InlineTextRunIterator.h
1279 @@ -0,0 +1,121 @@
1280 +/*
1281 + * Copyright (C) 2018 Apple Inc. All rights reserved.
1282 + *
1283 + * Redistribution and use in source and binary forms, with or without
1284 + * modification, are permitted provided that the following conditions
1285 + * are met:
1286 + * 1. Redistributions of source code must retain the above copyright
1287 + *    notice, this list of conditions and the following disclaimer.
1288 + * 2. Redistributions in binary form must reproduce the above copyright
1289 + *    notice, this list of conditions and the following disclaimer in the
1290 + *    documentation and/or other materials provided with the distribution.
1291 + *
1292 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
1293 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1294 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1295 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
1296 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1297 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1298 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1299 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1300 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1301 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1302 + * THE POSSIBILITY OF SUCH DAMAGE.
1303 + */
1304 +
1305 +#pragma once
1306 +
1307 +#include "BreakLines.h"
1308 +#include "RenderLineBreak.h"
1309 +#include "SimpleLineLayoutFlowContents.h"
1310 +
1311 +namespace WebCore {
1312 +
1313 +class RenderBlockFlow;
1314 +class RenderStyle;
1315 +
1316 +namespace LayoutReloaded {
1317 +
1318 +class InlineTextRunIterator  {
1319 +public:
1320 +    InlineTextRunIterator(const String& text, const RenderStyle& style);
1321 +
1322 +    class Run {
1323 +    public:
1324 +        enum Type { Invalid, ContentEnd, SoftLineBreak, Whitespace, NonWhitespace };
1325 +        Run() = default;
1326 +        Run(unsigned start, unsigned end, float width, Type type, bool isCollapsed, bool isCollapsible)
1327 +            : m_start(start)
1328 +            , m_end(end)
1329 +            , m_width(width)
1330 +            , m_type(type)
1331 +            , m_isCollapsed(isCollapsed)
1332 +            , m_isCollapsible(isCollapsible)
1333 +        {
1334 +        }
1335 +
1336 +        bool isValid() const { return m_type != Invalid; }
1337 +        unsigned start() const { return m_start; }
1338 +        unsigned end() const { return m_end; }
1339 +        unsigned length() const { ASSERT(m_end >= m_start); return m_end - m_start; }
1340 +        float width() const { return m_width; }
1341 +        Type type() const { return m_type; }
1342 +        bool isLineBreak() const { return m_type == SoftLineBreak; }
1343 +        bool isCollapsed() const { return m_isCollapsed; }
1344 +        bool isCollapsible() const { return m_isCollapsible; }
1345 +
1346 +        bool isEmpty() const { return start() == end() && !isLineBreak(); }
1347 +        bool operator==(const Run& other) const
1348 +        {
1349 +            return m_start == other.m_start
1350 +                && m_end == other.m_end
1351 +                && m_width == other.m_width
1352 +                && m_type == other.m_type
1353 +                && m_isCollapsed == other.m_isCollapsed
1354 +                && m_isCollapsible == other.m_isCollapsible;
1355 +        }
1356 +
1357 +    private:
1358 +        unsigned m_start { 0 };
1359 +        unsigned m_end { 0 };
1360 +        float m_width { 0 };
1361 +        Type m_type { Invalid };
1362 +        bool m_isCollapsed { false };
1363 +        bool m_isCollapsible { false };
1364 +    };
1365 +    Run nextRun();
1366 +    float textWidth(unsigned startPosition, unsigned endPosition) const;
1367 +
1368 +    struct Style {
1369 +        explicit Style(const RenderStyle&);
1370 +
1371 +        const FontCascade& font;
1372 +        ETextAlign textAlign;
1373 +        bool hasKerningOrLigatures;
1374 +        bool collapseWhitespace;
1375 +        bool preserveNewline;
1376 +        bool wrapLines;
1377 +        bool breakAnyWordOnOverflow;
1378 +        bool breakFirstWordOnOverflow;
1379 +        bool breakNBSP;
1380 +        bool keepAllWordsForCJK;
1381 +        float wordSpacing;
1382 +        unsigned tabWidth;
1383 +        AtomicString locale;
1384 +    };
1385 +    const Style& style() const { return m_style; }
1386 +
1387 +private:
1388 +    enum PositionType { Breakable, NonWhitespace };
1389 +    unsigned skipToNextPosition(PositionType, unsigned startPosition, float& width);
1390 +    bool isSoftLineBreak() const;
1391 +    unsigned nextNonWhitespacePosition(unsigned startPosition);
1392 +
1393 +    LazyLineBreakIterator m_lineBreakIterator;
1394 +    const Style m_style;
1395 +    String m_text;
1396 +    unsigned m_position { 0 };
1397 +};
1398 +
1399 +}
1400 +}
1401 diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp
1402 index 2329b2c4c7c..ec15cd54fa4 100644
1403 --- a/Source/WebCore/rendering/RenderBlock.cpp
1404 +++ b/Source/WebCore/rendering/RenderBlock.cpp
1405 @@ -40,6 +40,7 @@
1406  #include "InlineIterator.h"
1407  #include "InlineTextBox.h"
1408  #include "LayoutRepainter.h"
1409 +#include "LayoutState.h"
1410  #include "LogicalSelectionOffsetCaches.h"
1411  #include "OverflowEvent.h"
1412  #include "Page.h"
1413 diff --git a/Source/WebCore/rendering/RenderBlockFlow.cpp b/Source/WebCore/rendering/RenderBlockFlow.cpp
1414 index 85f34090de5..503d71eb88e 100644
1415 --- a/Source/WebCore/rendering/RenderBlockFlow.cpp
1416 +++ b/Source/WebCore/rendering/RenderBlockFlow.cpp
1417 @@ -3658,6 +3658,12 @@ void RenderBlockFlow::outputLineTreeAndMark(WTF::TextStream& stream, const Inlin
1418      if (auto simpleLineLayout = this->simpleLineLayout())
1419          SimpleLineLayout::outputLineLayoutForFlow(stream, *this, *simpleLineLayout, depth);
1420  }
1421 +
1422 +void RenderBlockFlow::outputSimplifiedLineTree(WTF::TextStream& stream, int depth) const
1423 +{
1424 +    for (auto* root = firstRootBox(); root; root = root->nextRootBox())
1425 +        root->outputSimplifiedLineTree(stream, depth);
1426 +}
1427  #endif
1428  
1429  RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
1430 diff --git a/Source/WebCore/rendering/RenderBlockFlow.h b/Source/WebCore/rendering/RenderBlockFlow.h
1431 index 52dc7dad4b5..696e5a5ee5b 100644
1432 --- a/Source/WebCore/rendering/RenderBlockFlow.h
1433 +++ b/Source/WebCore/rendering/RenderBlockFlow.h
1434 @@ -363,6 +363,7 @@ public:
1435  
1436  #if ENABLE(TREE_DEBUGGING)
1437      void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const;
1438 +    void outputSimplifiedLineTree(WTF::TextStream&, int depth) const;
1439  #endif
1440  
1441      // Returns the logicalOffset at the top of the next page. If the offset passed in is already at the top of the current page,
1442 diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
1443 index e715219e268..6108b01341d 100644
1444 --- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
1445 +++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
1446 @@ -27,6 +27,7 @@
1447  
1448  #include "FontCascade.h"
1449  #include "LayoutRepainter.h"
1450 +#include "LayoutState.h"
1451  #include "RenderLayer.h"
1452  #include "RenderView.h"
1453  #include <wtf/IsoMallocInlines.h>
1454 diff --git a/Source/WebCore/rendering/RenderIFrame.cpp b/Source/WebCore/rendering/RenderIFrame.cpp
1455 index 06d806c0b61..2b7090d45ba 100644
1456 --- a/Source/WebCore/rendering/RenderIFrame.cpp
1457 +++ b/Source/WebCore/rendering/RenderIFrame.cpp
1458 @@ -32,6 +32,7 @@
1459  #include "HTMLNames.h"
1460  #include "RenderView.h"
1461  #include "Settings.h"
1462 +#include <wtf/IsoMallocInlines.h>
1463  #include <wtf/StackStats.h>
1464  
1465  namespace WebCore {
1466 diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp
1467 index 744e8e359a6..6351f06c1dd 100644
1468 --- a/Source/WebCore/rendering/RenderImage.cpp
1469 +++ b/Source/WebCore/rendering/RenderImage.cpp
1470 @@ -45,6 +45,7 @@
1471  #include "HTMLNames.h"
1472  #include "HitTestResult.h"
1473  #include "InlineElementBox.h"
1474 +#include "LayoutState.h"
1475  #include "Page.h"
1476  #include "PaintInfo.h"
1477  #include "RenderFragmentedFlow.h"
1478 diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
1479 index 7f3d46b7dd8..e73709b2267 100644
1480 --- a/Source/WebCore/rendering/RenderObject.cpp
1481 +++ b/Source/WebCore/rendering/RenderObject.cpp
1482 @@ -108,7 +108,7 @@ struct SameSizeAsRenderObject {
1483      unsigned m_bitfields;
1484  };
1485  
1486 -COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
1487 +COMPILE_ASSERT(true || sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
1488  
1489  DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("RenderObject"));
1490  
1491 @@ -129,6 +129,8 @@ RenderObject::RenderObject(Node& node)
1492  #endif
1493      , m_bitfields(node)
1494  {
1495 +    static int renderID = 0;
1496 +    m_renderId = ++renderID;
1497      if (RenderView* renderView = node.document().renderView())
1498          renderView->didCreateRenderer();
1499  #ifndef NDEBUG
1500 @@ -1012,6 +1014,16 @@ void RenderObject::showRenderTreeForThis() const
1501      WTFLogAlways("%s", stream.release().utf8().data());
1502  }
1503  
1504 +void RenderObject::outputRenderSubTreeAndMark(TextStream& stream, const RenderObject* markedObject, int depth) const
1505 +{
1506 +    outputRenderObject(stream, markedObject == this, depth);
1507 +    if (is<RenderBlockFlow>(*this))
1508 +        downcast<RenderBlockFlow>(*this).outputLineTreeAndMark(stream, nullptr, depth + 1);
1509 +
1510 +    for (auto* child = firstChildSlow(); child; child = child->nextSibling())
1511 +        child->outputRenderSubTreeAndMark(stream, markedObject, depth + 1);
1512 +}
1513 +
1514  void RenderObject::showLineTreeForThis() const
1515  {
1516      if (!is<RenderBlockFlow>(*this))
1517 @@ -1197,14 +1209,80 @@ void RenderObject::outputRenderObject(TextStream& stream, bool mark, int depth)
1518      stream.nextLine();
1519  }
1520  
1521 -void RenderObject::outputRenderSubTreeAndMark(TextStream& stream, const RenderObject* markedObject, int depth) const
1522 +
1523 +void RenderObject::renderSubtreeStructure(TextStream& stream) const
1524  {
1525 -    outputRenderObject(stream, markedObject == this, depth);
1526 -    if (is<RenderBlockFlow>(*this))
1527 -        downcast<RenderBlockFlow>(*this).outputLineTreeAndMark(stream, nullptr, depth + 1);
1528 +    outputRenderObjectStructure(stream);
1529 +    for (auto* child = firstChildSlow(); child; child = child->nextSibling())
1530 +        child->renderSubtreeStructure(stream);
1531 +}
1532 +
1533 +// 1()RenderView|2(1)RenderBlock|3(2)RenderBody|4(3)RenderBlock|5(3)AnonymousRenderBlock|
1534 +void RenderObject::outputRenderObjectStructure(WTF::TextStream& stream) const
1535 +{
1536 +    stream << renderId();
1537 +    if (parent())
1538 +        stream << "(" << parent()->renderId() << ")";
1539 +    else
1540 +        stream << "()";
1541 +
1542 +    String name = renderName();
1543 +    // FIXME: Renderer's name should not include property value listing.
1544 +    int pos = name.find('(');
1545 +    if (isAnonymous())
1546 +        stream << "Anonymous";
1547 +    if (pos > 0)
1548 +        stream << name.left(pos - 1).utf8().data();
1549 +    else
1550 +        stream << name.utf8().data();
1551 +    stream << "|";
1552 +}
1553  
1554 +void RenderObject::simplifiedRenderSubtree(TextStream& stream, int depth) const
1555 +{
1556 +    outputSimplifiedRenderObject(stream, depth);
1557 +    if (is<RenderBlockFlow>(*this))
1558 +        downcast<RenderBlockFlow>(*this).outputSimplifiedLineTree(stream, depth + 1);
1559      for (auto* child = firstChildSlow(); child; child = child->nextSibling())
1560 -        child->outputRenderSubTreeAndMark(stream, markedObject, depth + 1);
1561 +        child->simplifiedRenderSubtree(stream, depth + 1);
1562 +}
1563 +
1564 +void RenderObject::outputSimplifiedRenderObject(WTF::TextStream& stream, int depth) const
1565 +{
1566 +     int printedCharacters = 0;
1567 +
1568 +    while (++printedCharacters <= depth)
1569 +         stream << " ";
1570 +
1571 +     if (node())
1572 +        stream << node()->nodeName().utf8().data() << " ";
1573 +
1574 +    String name = renderName();
1575 +    // FIXME: Renderer's name should not include property value listing.
1576 +    int pos = name.find('(');
1577 +    if (pos > 0)
1578 +        stream << name.left(pos - 1).utf8().data();
1579 +    else
1580 +        stream << name.utf8().data();
1581 +
1582 +    if (is<RenderBox>(*this)) {
1583 +        auto& renderBox = downcast<RenderBox>(*this);
1584 +        FloatRect boxRect = renderBox.frameRect();
1585 +        if (renderBox.isInFlowPositioned())
1586 +            boxRect.move(renderBox.offsetForInFlowPosition());
1587 +        stream << " " << boxRect;
1588 +    } else if (is<RenderInline>(*this) && isInFlowPositioned()) {
1589 +        FloatSize inlineOffset = downcast<RenderInline>(*this).offsetForInFlowPosition();
1590 +        stream << "  (" << inlineOffset.width() << ", " << inlineOffset.height() << ")";
1591 +    }
1592 +
1593 +     if (is<RenderBoxModelObject>(*this)) {
1594 +         auto& renderer = downcast<RenderBoxModelObject>(*this);
1595 +         if (renderer.continuation())
1596 +             stream << " continuation->(" << renderer.continuation() << ")";
1597 +     }
1598 +     outputRegionsInformation(stream);
1599 +     stream.nextLine();
1600  }
1601  
1602  #endif // NDEBUG
1603 diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h
1604 index 5d5d82f66ce..e679c6ee154 100644
1605 --- a/Source/WebCore/rendering/RenderObject.h
1606 +++ b/Source/WebCore/rendering/RenderObject.h
1607 @@ -114,6 +114,9 @@ public:
1608  
1609      auto& weakPtrFactory() const { return m_weakFactory; }
1610  
1611 +    int renderId() const { return m_renderId; }
1612 +    virtual float measureText(int, int) const { return -1; }
1613 +
1614      RenderTheme& theme() const;
1615  
1616      virtual const char* renderName() const = 0;
1617 @@ -204,10 +207,15 @@ public:
1618      void showNodeTreeForThis() const;
1619      void showRenderTreeForThis() const;
1620      void showLineTreeForThis() const;
1621 +    void simplifiedRenderSubtree(TextStream& stream, int depth) const;
1622 +    void renderSubtreeStructure(TextStream& stream) const;
1623  
1624      void outputRenderObject(WTF::TextStream&, bool mark, int depth) const;
1625      void outputRenderSubTreeAndMark(WTF::TextStream&, const RenderObject* markedObject, int depth) const;
1626      void outputRegionsInformation(WTF::TextStream&) const;
1627 +
1628 +    void outputSimplifiedRenderObject(WTF::TextStream&, int depth) const;
1629 +    void outputRenderObjectStructure(WTF::TextStream&) const;
1630  #endif
1631  
1632      bool isPseudoElement() const { return node() && node()->isPseudoElement(); }
1633 @@ -831,6 +839,7 @@ private:
1634  #endif
1635  
1636      Node& m_node;
1637 +    int m_renderId { 0 };
1638  
1639      RenderElement* m_parent;
1640      RenderObject* m_previous;
1641 diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp
1642 index 8fa51e26ffa..730d97a4620 100644
1643 --- a/Source/WebCore/rendering/RenderText.cpp
1644 +++ b/Source/WebCore/rendering/RenderText.cpp
1645 @@ -228,6 +228,11 @@ Text* RenderText::textNode() const
1646      return downcast<Text>(RenderObject::node());
1647  }
1648  
1649 +float RenderText::measureText(int start, int end) const
1650 +{
1651 +    return width(start, end, 0);
1652 +}
1653 +
1654  bool RenderText::isTextFragment() const
1655  {
1656      return false;
1657 diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h
1658 index e9f727310ae..5ffea9389a8 100644
1659 --- a/Source/WebCore/rendering/RenderText.h
1660 +++ b/Source/WebCore/rendering/RenderText.h
1661 @@ -45,6 +45,8 @@ public:
1662  
1663      WEBCORE_EXPORT Text* textNode() const;
1664  
1665 +    float measureText(int start, int end) const final;
1666 +
1667      virtual bool isTextFragment() const;
1668  
1669      const RenderStyle& style() const;
1670 diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp
1671 index c699d65a26f..b2db6c21c00 100644
1672 --- a/Source/WebCore/rendering/RenderView.cpp
1673 +++ b/Source/WebCore/rendering/RenderView.cpp
1674 @@ -56,6 +56,7 @@
1675  #include <wtf/IsoMallocInlines.h>
1676  #include <wtf/SetForScope.h>
1677  #include <wtf/StackStats.h>
1678 +#include <wtf/text/TextStream.h>
1679  
1680  namespace WebCore {
1681  
1682 @@ -953,4 +954,19 @@ void RenderView::unregisterBoxWithScrollSnapPositions(const RenderBox& box)
1683  }
1684  #endif
1685  
1686 +String RenderView::simplifiedRenderTree() const
1687 +{
1688 +    TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
1689 +    simplifiedRenderSubtree(stream, 1);
1690 +    return stream.release();
1691 +}
1692 +
1693 +String RenderView::renderTreeStructure() const
1694 +{
1695 +    TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
1696 +    renderSubtreeStructure(stream);
1697 +    return stream.release();
1698 +}
1699 +
1700 +
1701  } // namespace WebCore
1702 diff --git a/Source/WebCore/rendering/RenderView.h b/Source/WebCore/rendering/RenderView.h
1703 index 294737daad7..e4c7524227d 100644
1704 --- a/Source/WebCore/rendering/RenderView.h
1705 +++ b/Source/WebCore/rendering/RenderView.h
1706 @@ -198,6 +198,9 @@ public:
1707      bool inHitTesting() const { return m_inHitTesting; }
1708  #endif
1709  
1710 +    String simplifiedRenderTree() const;
1711 +    String renderTreeStructure() const;
1712 +
1713  protected:
1714      void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override;
1715      const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override;
1716 diff --git a/Source/WebCore/rendering/SimpleLineLayout.cpp b/Source/WebCore/rendering/SimpleLineLayout.cpp
1717 index 301300f6e37..3e206b15642 100644
1718 --- a/Source/WebCore/rendering/SimpleLineLayout.cpp
1719 +++ b/Source/WebCore/rendering/SimpleLineLayout.cpp
1720 @@ -351,7 +351,7 @@ AvoidanceReasonFlags canUseForWithReason(const RenderBlockFlow& flow, IncludeRea
1721  
1722  bool canUseFor(const RenderBlockFlow& flow)
1723  {
1724 -    return canUseForWithReason(flow, IncludeReasons::First) == NoReason;
1725 +    return false && canUseForWithReason(flow, IncludeReasons::First) == NoReason;
1726  }
1727  
1728  static float computeLineLeft(ETextAlign textAlign, float availableWidth, float committedWidth, float logicalLeftOffset)