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
7 #define ENABLE_TREE_DEBUGGING 1
9 -#define ENABLE_TREE_DEBUGGING 0
10 +#define ENABLE_TREE_DEBUGGING 1
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 ff942b36a44..5bc30f914af 100644
28 --- a/Source/WebCore/Sources.txt
29 +++ b/Source/WebCore/Sources.txt
30 @@ -1797,7 +1797,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 2ae0c8a22d5..edcd82aa95a 100644
42 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
43 +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
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 @@ -5699,6 +5703,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 @@ -22115,6 +22126,7 @@
70 A83B79100CCB001B000B0825 /* Core */ = {
73 + 11C0C7A6206953F600BE3A84 /* JSInlineTextRun.cpp */,
74 7C30D97E1F815AC000268356 /* JSAbortController.cpp */,
75 7C30D9801F815AC100268356 /* JSAbortController.h */,
76 7C30D9821F815AC200268356 /* JSAbortSignal.cpp */,
77 @@ -25447,6 +25459,10 @@
78 F523D2F302DE443B018635CA /* rendering */ = {
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 @@ -25742,6 +25758,8 @@
89 F523D32402DE4478018635CA /* dom */ = {
92 + 11C0C7A320694B0900BE3A84 /* InlineTextRun.h */,
93 + 11C0C7A220694B0800BE3A84 /* InlineTextRun.idl */,
94 CE2616A4187E65C1007955F3 /* ios */,
95 2D5036661BCDDDC400E20BB3 /* mac */,
96 51ECC3E42005831F00483EAE /* messageports */,
97 @@ -26736,6 +26754,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 @@ -30329,6 +30348,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 @@ -30543,6 +30563,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 @@ -31027,6 +31048,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();
137 +bool CSSComputedStyleDeclaration::isPropertyValueInitial(const String& propertyName)
139 + m_element->document().updateLayoutIgnorePendingStylesheets();
140 + auto* style = m_element->computedStyle(m_pseudoElementSpecifier);
144 + CSSPropertyID propertyID = cssPropertyID(propertyName);
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();
162 + ASSERT_NOT_REACHED();
167 unsigned CSSComputedStyleDeclaration::length() const
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
200 DOMString getPropertyValue(DOMString propertyName);
202 + boolean isPropertyValueInitial(DOMString propertyName);
204 [CEReactions, MayThrowException] DOMString removeProperty(DOMString propertyName);
205 DOMString? getPropertyPriority(DOMString propertyName);
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);
215 +bool PropertySetCSSStyleDeclaration::isPropertyValueInitial(const String&)
220 String PropertySetCSSStyleDeclaration::getPropertyPriority(const String& propertyName)
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
237 index 00000000000..7ae48649fbd
239 +++ b/Source/WebCore/dom/InlineTextRun.h
242 + * Copyright (C) 2018 Apple Inc. All rights reserved.
244 + * Redistribution and use in source and binary forms, with or without
245 + * modification, are permitted provided that the following conditions
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.
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.
268 +#include "InlineTextRunIterator.h"
269 +#include <wtf/Ref.h>
270 +#include <wtf/RefCounted.h>
274 +class InlineTextRun : public RefCounted<InlineTextRun> {
275 + WTF_MAKE_FAST_ALLOCATED;
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)); }
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())); }
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; }
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; }
299 + InlineTextRun(unsigned startPosition, unsigned endPosition, double width, unsigned type, bool isCollapsed, bool isCollapsible)
300 + : m_startPosition(startPosition)
301 + , m_endPosition(endPosition)
304 + , m_isCollapsed(isCollapsed)
305 + , m_isCollapsible(isCollapsible)
309 + InlineTextRun() = default;
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 };
320 diff --git a/Source/WebCore/dom/InlineTextRun.idl b/Source/WebCore/dom/InlineTextRun.idl
322 index 00000000000..20c01b8cff5
324 +++ b/Source/WebCore/dom/InlineTextRun.idl
327 + * Copyright (C) 2018 Apple Inc. All rights reserved.
329 + * Redistribution and use in source and binary forms, with or without
330 + * modification, are permitted provided that the following conditions
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.
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.
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;
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());
370 +int Node::rendererId()
374 + return renderer()->renderId();
377 +double Node::textWidth(int start, int end)
381 + return renderer()->measureText(start, end);
384 +double Node::textHeight()
388 + return renderer()->style().computedFontPixelSize();
391 ExceptionOr<void> Node::after(Vector<NodeOrString>&& nodeOrStringVector)
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:
400 WEBCORE_EXPORT String textContent(bool convertBRsToNewlines = false) const;
401 WEBCORE_EXPORT ExceptionOr<void> setTextContent(const String&);
405 + double textWidth(int start, int end);
406 + double textHeight();
408 Node* lastDescendant() const;
409 Node* firstDescendant() const;
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
416 unsigned short compareDocumentPosition(Node other);
417 boolean contains(Node? other);
419 + readonly attribute long rendererId;
420 + double textWidth(long start, long end);
421 + double textHeight();
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 90c3e8e5a78..41e4447ff23 100644
428 --- a/Source/WebCore/page/DOMWindow.cpp
429 +++ b/Source/WebCore/page/DOMWindow.cpp
432 #include "BackForwardController.h"
434 +#include "BreakLines.h"
435 #include "CSSComputedStyleDeclaration.h"
437 #include "CSSRuleList.h"
439 #include "FrameTree.h"
440 #include "FrameView.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"
451 #include "PageConsoleClient.h"
452 #include "PageTransitionEvent.h"
453 #include "Performance.h"
454 +#include "RenderView.h"
455 #include "RequestAnimationFrameCallback.h"
456 #include "ResourceLoadInfo.h"
457 #include "ResourceLoadObserver.h"
459 #include "StyleResolver.h"
460 #include "StyleScope.h"
461 #include "SuddenTermination.h"
462 +#include "InlineTextRun.h"
464 #include "UserGestureIndicator.h"
465 #include "VisualViewport.h"
467 #include <wtf/NeverDestroyed.h>
469 #include <wtf/Variant.h>
470 +#include <wtf/text/TextBreakIterator.h>
471 #include <wtf/text/WTFString.h>
473 #if ENABLE(USER_MESSAGE_HANDLERS)
474 @@ -1357,6 +1363,41 @@ int DOMWindow::scrollY() const
475 return view->mapFromLayoutToCSSUnits(view->contentsScrollPosition().y());
478 +String DOMWindow::simplifiedRenderTree() const
480 + return m_frame->view()->renderView()->simplifiedRenderTree();
483 +String DOMWindow::renderTreeStructure() const
485 + return m_frame->view()->renderView()->renderTreeStructure();
488 +Vector<Ref<InlineTextRun>> DOMWindow::collectTextRuns(const String& text, const Node& container, float availableSpace)
490 + Vector<Ref<InlineTextRun>> textRuns;
491 + LayoutReloaded::InlineTextRunIterator textIterator(text, container.renderer()->style());
493 + auto run = textIterator.nextRun();
494 + if (run.type() == LayoutReloaded::InlineTextRunIterator::Run::ContentEnd)
496 + textRuns.append(InlineTextRun::create(run));
498 + if (std::isnan(availableSpace))
501 + return LayoutReloaded::InlineTextBreaker::collectRuns(textRuns, text, availableSpace, container.renderer()->style());
504 +int DOMWindow::nextBreakingOpportunity(const String& text, unsigned startPosition)
506 + LazyLineBreakIterator lineBreakIterator(text, m_frame->view()->renderView()->style().locale());
508 + if (lineBreakIterator.mode() == LineBreakIteratorMode::Default)
509 + return WebCore::nextBreakablePosition(lineBreakIterator, startPosition);
510 + return nextBreakablePositionWithoutShortcut(lineBreakIterator, startPosition);
513 bool DOMWindow::closed() const
516 diff --git a/Source/WebCore/page/DOMWindow.h b/Source/WebCore/page/DOMWindow.h
517 index 4c66b724e29..4ee2993438c 100644
518 --- a/Source/WebCore/page/DOMWindow.h
519 +++ b/Source/WebCore/page/DOMWindow.h
520 @@ -48,7 +48,6 @@ template<typename> class Strong;
527 class CSSStyleDeclaration;
528 @@ -77,6 +76,7 @@ class ScheduledAction;
532 +class InlineTextRun;
533 class VisualViewport;
534 class WebKitNamespace;
536 @@ -191,6 +191,11 @@ public:
537 String defaultStatus() const;
538 void setDefaultStatus(const String&);
540 + String simplifiedRenderTree() const;
541 + String renderTreeStructure() const;
542 + int nextBreakingOpportunity(const String& text, unsigned startPosition);
543 + Vector<Ref<InlineTextRun>> collectTextRuns(const String&, const Node&, float availableSpace);
545 DOMWindow* self() const;
547 DOMWindow* opener() const;
548 diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl
549 index 46ebc1561fa..cbcd213b46a 100644
550 --- a/Source/WebCore/page/DOMWindow.idl
551 +++ b/Source/WebCore/page/DOMWindow.idl
552 @@ -82,6 +82,11 @@ typedef USVString CSSOMString;
553 readonly attribute Navigator navigator;
554 readonly attribute DOMApplicationCache applicationCache;
556 + readonly attribute DOMString simplifiedRenderTree;
557 + readonly attribute DOMString renderTreeStructure;
558 + long nextBreakingOpportunity(DOMString text, unsigned long startPosition);
559 + sequence<InlineTextRun> collectTextRuns(DOMString text, Node containerNode, optional unrestricted float availableSpace = NaN);
563 void alert(DOMString message);
564 diff --git a/Source/WebCore/page/mac/PageMac.mm b/Source/WebCore/page/mac/PageMac.mm
565 index aa030c54617..7457861e142 100644
566 --- a/Source/WebCore/page/mac/PageMac.mm
567 +++ b/Source/WebCore/page/mac/PageMac.mm
568 @@ -52,11 +52,6 @@ void Page::platformInitialize()
571 #if ENABLE(TREE_DEBUGGING)
572 - static std::once_flag onceFlag;
573 - std::call_once(onceFlag, [] {
574 - PAL::registerNotifyCallback("com.apple.WebKit.showRenderTree", printRenderTreeForLiveDocuments);
575 - PAL::registerNotifyCallback("com.apple.WebKit.showLayerTree", printLayerTreeForLiveDocuments);
580 diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp
581 index cd23ae0b97c..7cfd4bb2d42 100644
582 --- a/Source/WebCore/rendering/InlineBox.cpp
583 +++ b/Source/WebCore/rendering/InlineBox.cpp
584 @@ -123,6 +123,18 @@ void InlineBox::outputLineBox(TextStream& stream, bool mark, int depth) const
588 +void InlineBox::outputSimplifiedLineTree(TextStream& stream, int depth) const
590 + // Ignore inline flows for now. LayoutReloaded does not have the concept of flow boxes.
591 + if (is<InlineFlowBox>(*this) && !is<RootInlineBox>(*this))
593 + int printedCharacters = 0;
594 + while (++printedCharacters <= depth)
596 + stream << boxName() << " " << FloatRect(x(), y(), width(), height());
600 #endif // ENABLE(TREE_DEBUGGING)
602 float InlineBox::logicalHeight() const
603 diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h
604 index 7f1dd6cbba4..eddb048440a 100644
605 --- a/Source/WebCore/rendering/InlineBox.h
606 +++ b/Source/WebCore/rendering/InlineBox.h
607 @@ -78,6 +78,7 @@ public:
608 void showLineTreeForThis() const;
610 virtual void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const;
611 + virtual void outputSimplifiedLineTree(WTF::TextStream&, int depth) const;
612 virtual void outputLineBox(WTF::TextStream&, bool mark, int depth) const;
613 virtual const char* boxName() const;
615 diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp
616 index 063f3b64189..ee32b981371 100644
617 --- a/Source/WebCore/rendering/InlineFlowBox.cpp
618 +++ b/Source/WebCore/rendering/InlineFlowBox.cpp
619 @@ -1720,6 +1720,18 @@ void InlineFlowBox::outputLineTreeAndMark(WTF::TextStream& stream, const InlineB
620 box->outputLineTreeAndMark(stream, markedBox, depth + 1);
623 +void InlineFlowBox::outputSimplifiedLineTree(WTF::TextStream& stream, int depth) const
625 + InlineBox::outputSimplifiedLineTree(stream, depth);
626 + for (auto* box = firstChild(); box; box = box->nextOnLine()) {
627 + // DO not increment depth for flow boxes. LayoutReloaded does not have the concept of them.
628 + if (is<InlineFlowBox>(*box) && !is<RootInlineBox>(*box))
629 + box->outputSimplifiedLineTree(stream, depth);
631 + box->outputSimplifiedLineTree(stream, depth + 1);
638 diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h
639 index 0b26444903f..595203b201e 100644
640 --- a/Source/WebCore/rendering/InlineFlowBox.h
641 +++ b/Source/WebCore/rendering/InlineFlowBox.h
642 @@ -72,6 +72,7 @@ public:
644 #if ENABLE(TREE_DEBUGGING)
645 void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const override;
646 + void outputSimplifiedLineTree(WTF::TextStream&, int depth) const override;
647 const char* boxName() const override;
650 diff --git a/Source/WebCore/rendering/InlineTextBreaker.cpp b/Source/WebCore/rendering/InlineTextBreaker.cpp
652 index 00000000000..9ac083d2a90
654 +++ b/Source/WebCore/rendering/InlineTextBreaker.cpp
657 + * Copyright (C) 2018 Apple Inc. All rights reserved.
659 + * Redistribution and use in source and binary forms, with or without
660 + * modification, are permitted provided that the following conditions
662 + * 1. Redistributions of source code must retain the above copyright
663 + * notice, this list of conditions and the following disclaimer.
664 + * 2. Redistributions in binary form must reproduce the above copyright
665 + * notice, this list of conditions and the following disclaimer in the
666 + * documentation and/or other materials provided with the distribution.
668 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
669 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
670 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
671 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
672 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
673 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
674 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
675 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
676 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
677 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
678 + * THE POSSIBILITY OF SUCH DAMAGE.
682 +#include "InlineTextBreaker.h"
684 +#include "FontCascade.h"
685 +#include "RenderStyle.h"
688 +namespace LayoutReloaded {
690 +InlineTextBreaker::Style::Style(const RenderStyle& style)
691 + : font(style.fontCascade())
692 + , hasKerningOrLigatures(font.enableKerning() || font.requiresShaping())
693 + , collapseWhitespace(style.collapseWhiteSpace())
694 + , preserveNewline(style.preserveNewline())
695 + , wrapLines(style.autoWrap())
696 + , breakAnyWordOnOverflow(style.wordBreak() == BreakAllWordBreak && wrapLines)
697 + , breakFirstWordOnOverflow(breakAnyWordOnOverflow || (style.breakWords() && (wrapLines || preserveNewline)))
698 + , wordSpacing(font.wordSpacing())
699 + , tabWidth(collapseWhitespace ? 0 : style.tabSize())
703 +InlineTextBreaker::LineState::LineState(const InlineTextBreaker& lineBreaker, float availableWidth)
704 + : m_lineBreaker(lineBreaker)
705 + , m_availableWidth(availableWidth)
709 +float InlineTextBreaker::LineState::availableWidth() const
711 + return m_availableWidth;
714 +bool InlineTextBreaker::LineState::hasTrailingWhitespace() const
716 + return m_hasTrailingWhitespace;
719 +bool InlineTextBreaker::LineState::isWhitespaceOnly() const
721 + for (auto& run : m_runs) {
722 + if (run->type() != InlineTextRun::Whitespace)
728 +bool InlineTextBreaker::LineState::fits(float extra) const
730 + return m_availableWidth >= width() + extra;
733 +float InlineTextBreaker::LineState::width() const
736 + for (auto& run : m_runs)
737 + width += m_lineBreaker.textWidth(run->startPosition(), run->endPosition());
741 +bool InlineTextBreaker::LineState::isEmpty() const
743 + return !m_runs.size();
746 +static inline unsigned endPositionForCollapsedRun(const InlineTextRun& run)
748 + if (run.isCollapsed())
749 + return run.startPosition() + 1;
750 + return run.endPosition();
753 +void InlineTextBreaker::LineState::appendRun(const InlineTextRun& run)
755 + // Adjust end position while collapsing.
756 + unsigned endPosition = endPositionForCollapsedRun(run);
757 + if (run.type() == InlineTextRun::NonWhitespace)
758 + m_lastNoneWhitespacePosition = endPosition;
759 + // New line needs new run.
760 + if (!m_runs.size()) {
761 + m_runs.append(InlineTextRun::create(run.startPosition(), endPosition, 0, run.type(), run.isCollapsed(), run.isCollapsible()));
763 + // Advance last completed fragment when the previous fragment is all set (including multiple parts across renderers)
764 + if (m_runs.last()->isCollapsible() && run.isCollapsible()) {
765 + // This fragment is collapsed completely. No run is needed.
768 + auto& lastRun = m_runs.last();
769 + if (lastRun->isCollapsed())
770 + m_runs.append(InlineTextRun::create(run.startPosition(), endPosition, 0, run.type(), run.isCollapsed(), run.isCollapsible()));
772 + lastRun->setEndPosition(endPosition);
773 + lastRun->setTypeMixed();
774 + if (run.isCollapsed())
775 + lastRun->setIsCollapsed();
778 + m_hasTrailingWhitespace = run.type() == InlineTextRun::Whitespace;
781 +void InlineTextBreaker::LineState::removeTrailingWhitespace()
783 + if (!m_hasTrailingWhitespace)
785 + if (m_runs.last()->type() == InlineTextRun::Whitespace) {
786 + m_runs.removeLast();
789 + ASSERT(m_runs.last()->type() == InlineTextRun::Mixed);
790 + m_runs.last()->setEndPosition(m_lastNoneWhitespacePosition);
793 +Vector<Ref<InlineTextRun>> InlineTextBreaker::LineState::collectRuns()
795 + for (auto& run: m_runs)
796 + run->setWidth(m_lineBreaker.textWidth(run->startPosition(), run->endPosition()));
797 + return WTFMove(m_runs);
800 +InlineTextBreaker::InlineTextBreaker(Vector<Ref<InlineTextRun>>& runs, const String& text, float availableWidth, const RenderStyle& style)
804 + , m_line(*this, availableWidth)
808 +Vector<Ref<InlineTextRun>> InlineTextBreaker::collectRuns(Vector<Ref<InlineTextRun>>& runs, const String& text, float availableWidth, const RenderStyle& style)
810 + return InlineTextBreaker(runs, text, availableWidth, style).createAndCollectLineRuns();
813 +bool InlineTextBreaker::preWrap() const
815 + return m_style.wrapLines && !m_style.collapseWhitespace;
818 +void InlineTextBreaker::removeTrailingWhitespace()
820 + if (!m_line.hasTrailingWhitespace())
822 + // Remove collapsed whitespace, or non-collapsed pre-wrap whitespace, unless it's the only content on the line -so removing the whitesapce
823 + // would produce an empty line.
824 + bool collapseWhitespace = m_style.collapseWhitespace | preWrap();
825 + if (!collapseWhitespace)
827 + if (preWrap() && m_line.isWhitespaceOnly())
829 + m_line.removeTrailingWhitespace();
832 +struct SplitFragmentData {
837 +SplitFragmentData InlineTextBreaker::split(const InlineTextRun& run, float availableWidth)
839 + ASSERT(availableWidth >= 0);
840 + auto left = run.startPosition();
841 + // Pathological case of (extremely)long string and narrow lines.
842 + // Adjust the range so that we can pick a reasonable midpoint.
843 + auto averageCharacterWidth = run.width() / run.length();
844 + auto right = std::min<unsigned>(left + (2 * availableWidth / averageCharacterWidth), run.endPosition() - 1);
845 + // Preserve the left width for the final split position so that we don't need to remeasure the left side again.
846 + float leftSideWidth = 0;
847 + while (left < right) {
848 + auto middle = (left + right) / 2;
849 + auto width = textWidth(run.startPosition(), middle + 1);
850 + if (width < availableWidth) {
852 + leftSideWidth = width;
853 + } else if (width > availableWidth)
856 + right = middle + 1;
857 + leftSideWidth = width;
861 + return { right, leftSideWidth };
864 +void InlineTextBreaker::splitRunToFitLine(InlineTextRun& runToSplit)
866 + auto availableWidth = m_line.availableWidth() - m_line.width();
867 + auto splitRunData = split(runToSplit, availableWidth);
868 + // Does first character fit this line?
869 + if (splitRunData.position == runToSplit.startPosition()) {
870 + // Keep at least one character on empty lines.
871 + if (m_line.isEmpty())
872 + splitRunData.width = textWidth(runToSplit.startPosition(), ++splitRunData.position);
874 + runToSplit.setEndPosition(splitRunData.position);
875 + runToSplit.setWidth(splitRunData.width);
878 +unsigned InlineTextBreaker::skipLeadingWhitespaceIfNeeded() const
880 + if (!m_style.collapseWhitespace)
883 + for (unsigned index = 0; index < m_textRuns.size(); ++index) {
884 + if (m_textRuns[index]->type() != InlineTextRun::Whitespace)
887 + return m_textRuns.size();
890 +Vector<Ref<InlineTextRun>> InlineTextBreaker::createAndCollectLineRuns()
892 + bool lineCanBeWrapped = m_style.wrapLines || m_style.breakFirstWordOnOverflow || m_style.breakAnyWordOnOverflow;
893 + auto index = skipLeadingWhitespaceIfNeeded();
894 + for (; index < m_textRuns.size(); ++index) {
895 + auto& run = m_textRuns[index];
896 + // Hard and soft linebreaks.
897 + if (run->type() == InlineTextRun::SoftLineBreak) {
898 + // 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.)
899 + if (m_line.isEmpty())
900 + m_line.appendRun(run);
903 + if (lineCanBeWrapped && !m_line.fits(run->width())) {
904 + // Overflow wrapping behaviour:
905 + // 1. Whitesapce collapse on: whitespace is skipped. Jump to next line.
906 + // 2. Whitespace collapse off: whitespace is wrapped.
907 + // 3. First, non-whitespace fragment is either wrapped or kept on the line. (depends on overflow-wrap)
908 + // 5. Non-whitespace fragment when there's already another fragment on the line either gets wrapped (word-break: break-all)
909 + // or gets pushed to the next line.
910 + bool emptyLine = m_line.isEmpty();
911 + // Whitespace fragment.
912 + if (run->type() == InlineTextRunIterator::Run::Whitespace) {
913 + if (m_style.collapseWhitespace) {
914 + // Push collapased whitespace to the next line.
917 + // Split the whitespace; left part stays on this line, right is pushed to next line.
918 + splitRunToFitLine(run);
919 + m_line.appendRun(run);
922 + // Non-whitespace fragment. (!style.wrapLines: bug138102(preserve existing behavior)
923 + if (((emptyLine && m_style.breakFirstWordOnOverflow) || m_style.breakAnyWordOnOverflow) || !m_style.wrapLines) {
924 + // Split the fragment; (modified)fragment stays on this line, overflowedFragment is pushed to next line.
925 + splitRunToFitLine(run);
926 + m_line.appendRun(run);
929 + ASSERT(run->type() == InlineTextRunIterator::Run::NonWhitespace);
930 + // Non-breakable non-whitespace first fragment. Add it to the current line. -it overflows though.
932 + m_line.appendRun(run);
935 + // Non-breakable non-whitespace fragment when there's already content on the line. Push it to the next line.
938 + m_line.appendRun(run);
940 + removeTrailingWhitespace();
941 + return m_line.collectRuns();
944 +float InlineTextBreaker::textWidth(unsigned from, unsigned to) const
946 + if (!m_style.font.size() || from == to)
949 + bool measureWithEndSpace = m_style.hasKerningOrLigatures && m_style.collapseWhitespace && to < m_text.length() && m_text[to] == ' ';
950 + if (measureWithEndSpace)
953 + TextRun run(StringView(m_text).substring(from, to - from), 0);
954 + if (m_style.tabWidth)
955 + run.setTabSize(true, m_style.tabWidth);
956 + width = m_style.font.width(run);
957 + if (measureWithEndSpace)
958 + width -= (m_style.font.spaceWidth() + m_style.wordSpacing);
959 + return std::max<float>(0, width);
964 diff --git a/Source/WebCore/rendering/InlineTextBreaker.h b/Source/WebCore/rendering/InlineTextBreaker.h
966 index 00000000000..8cf678fd5c5
968 +++ b/Source/WebCore/rendering/InlineTextBreaker.h
971 + * Copyright (C) 2018 Apple Inc. All rights reserved.
973 + * Redistribution and use in source and binary forms, with or without
974 + * modification, are permitted provided that the following conditions
976 + * 1. Redistributions of source code must retain the above copyright
977 + * notice, this list of conditions and the following disclaimer.
978 + * 2. Redistributions in binary form must reproduce the above copyright
979 + * notice, this list of conditions and the following disclaimer in the
980 + * documentation and/or other materials provided with the distribution.
982 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
983 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
984 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
985 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
986 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
987 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
988 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
989 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
990 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
991 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
992 + * THE POSSIBILITY OF SUCH DAMAGE.
997 +#include "InlineTextRun.h"
1003 +namespace LayoutReloaded {
1006 +struct SplitFragmentData;
1008 +class InlineTextBreaker {
1010 + static Vector<Ref<InlineTextRun>> collectRuns(Vector<Ref<InlineTextRun>>&, const String&, float availableWidth, const RenderStyle&);
1013 + InlineTextBreaker(Vector<Ref<InlineTextRun>>&, const String&, float availableWidth, const RenderStyle&);
1015 + Vector<Ref<InlineTextRun>> createAndCollectLineRuns();
1016 + SplitFragmentData split(const InlineTextRun& run, float availableWidth);
1017 + void splitRunToFitLine(InlineTextRun& runToSplit);
1018 + void removeTrailingWhitespace();
1019 + bool preWrap() const;
1020 + float textWidth(unsigned from, unsigned to) const;
1021 + unsigned skipLeadingWhitespaceIfNeeded() const;
1024 + explicit Style(const RenderStyle&);
1026 + const FontCascade& font;
1027 + bool hasKerningOrLigatures;
1028 + bool collapseWhitespace;
1029 + bool preserveNewline;
1031 + bool breakAnyWordOnOverflow;
1032 + bool breakFirstWordOnOverflow;
1033 + float wordSpacing;
1034 + unsigned tabWidth;
1039 + LineState(const InlineTextBreaker& lineBreaker, float availableWidth);
1041 + float availableWidth() const;
1042 + bool hasTrailingWhitespace() const;
1043 + bool isWhitespaceOnly() const;
1044 + bool fits(float extra) const;
1045 + float width() const;
1046 + bool isEmpty() const;
1047 + void appendRun(const InlineTextRun&);
1048 + void removeTrailingWhitespace();
1049 + Vector<Ref<InlineTextRun>> collectRuns();
1052 + const InlineTextBreaker& m_lineBreaker;
1053 + float m_availableWidth { 0 };
1054 + Vector<Ref<InlineTextRun>> m_runs;
1055 + bool m_hasTrailingWhitespace { false };
1056 + unsigned m_lastNoneWhitespacePosition { 0 };
1059 + Vector<Ref<InlineTextRun>>& m_textRuns;
1061 + const Style m_style;
1067 diff --git a/Source/WebCore/rendering/InlineTextRunIterator.cpp b/Source/WebCore/rendering/InlineTextRunIterator.cpp
1068 new file mode 100644
1069 index 00000000000..6714a5df199
1071 +++ b/Source/WebCore/rendering/InlineTextRunIterator.cpp
1074 + * Copyright (C) 2018 Apple Inc. All rights reserved.
1076 + * Redistribution and use in source and binary forms, with or without
1077 + * modification, are permitted provided that the following conditions
1079 + * 1. Redistributions of source code must retain the above copyright
1080 + * notice, this list of conditions and the following disclaimer.
1081 + * 2. Redistributions in binary form must reproduce the above copyright
1082 + * notice, this list of conditions and the following disclaimer in the
1083 + * documentation and/or other materials provided with the distribution.
1085 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
1086 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1087 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1088 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
1089 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1090 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1091 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1092 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1093 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1094 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1095 + * THE POSSIBILITY OF SUCH DAMAGE.
1098 +#include "config.h"
1099 +#include "InlineTextRunIterator.h"
1101 +#include "FontCascade.h"
1103 +namespace WebCore {
1104 +namespace LayoutReloaded {
1106 +InlineTextRunIterator::Style::Style(const RenderStyle& style)
1107 + : font(style.fontCascade())
1108 + , textAlign(style.textAlign())
1109 + , hasKerningOrLigatures(font.enableKerning() || font.requiresShaping())
1110 + , collapseWhitespace(style.collapseWhiteSpace())
1111 + , preserveNewline(style.preserveNewline())
1112 + , wrapLines(style.autoWrap())
1113 + , breakAnyWordOnOverflow(style.wordBreak() == BreakAllWordBreak && wrapLines)
1114 + , breakFirstWordOnOverflow(breakAnyWordOnOverflow || (style.breakWords() && (wrapLines || preserveNewline)))
1115 + , breakNBSP(wrapLines && style.nbspMode() == SPACE)
1116 + , keepAllWordsForCJK(style.wordBreak() == KeepAllWordBreak)
1117 + , wordSpacing(font.wordSpacing())
1118 + , tabWidth(collapseWhitespace ? 0 : style.tabSize())
1119 + , locale(style.locale())
1123 +InlineTextRunIterator::InlineTextRunIterator(const String& text, const RenderStyle& style)
1124 + : m_lineBreakIterator(text, style.locale())
1130 +InlineTextRunIterator::Run InlineTextRunIterator::nextRun()
1132 + // A fragment can either be
1133 + // 1. line break when <br> is present or preserveNewline is on (not considered as whitespace) or
1134 + // 2. whitespace (collasped, non-collapsed multi or single) or
1135 + // 3. non-whitespace characters.
1136 + // 4. content end.
1137 + unsigned startPosition = m_position;
1138 + if (m_text.length() == m_position)
1139 + return Run(startPosition, startPosition, 0, Run::ContentEnd, false, false);
1140 + if (isSoftLineBreak()) {
1141 + unsigned endPosition = ++m_position;
1142 + return Run(startPosition, endPosition, 0, Run::SoftLineBreak, false, false);
1145 + unsigned endPosition = skipToNextPosition(PositionType::NonWhitespace, startPosition, width);
1146 + if (startPosition < endPosition) {
1147 + bool multipleWhitespace = startPosition + 1 < endPosition;
1148 + bool isCollapsed = multipleWhitespace && m_style.collapseWhitespace;
1149 + m_position = endPosition;
1150 + return Run(startPosition, endPosition, width, Run::Whitespace, isCollapsed, m_style.collapseWhitespace);
1152 + endPosition = skipToNextPosition(PositionType::Breakable, startPosition, width);
1153 + m_position = endPosition;
1154 + return Run(startPosition, endPosition, width, Run::NonWhitespace, false, false);
1157 +bool InlineTextRunIterator::isSoftLineBreak() const
1159 + return m_style.preserveNewline && m_text[m_position] == '\n';
1162 +static inline unsigned nextBreakablePosition(LazyLineBreakIterator& lineBreakIterator, unsigned startPosition, bool breakNBSP, bool keepAllWordsForCJK)
1164 + if (keepAllWordsForCJK) {
1166 + return nextBreakablePositionKeepingAllWords(lineBreakIterator, startPosition);
1167 + return nextBreakablePositionKeepingAllWordsIgnoringNBSP(lineBreakIterator, startPosition);
1170 + if (lineBreakIterator.mode() == LineBreakIteratorMode::Default) {
1172 + return WebCore::nextBreakablePosition(lineBreakIterator, startPosition);
1173 + return nextBreakablePositionIgnoringNBSP(lineBreakIterator, startPosition);
1177 + return nextBreakablePositionWithoutShortcut(lineBreakIterator, startPosition);
1178 + return nextBreakablePositionIgnoringNBSPWithoutShortcut(lineBreakIterator, startPosition);
1181 +unsigned InlineTextRunIterator::nextNonWhitespacePosition(unsigned startPosition)
1183 + ASSERT(startPosition < m_text.length());
1184 + unsigned position = startPosition;
1185 + for (; position < m_text.length(); ++position) {
1186 + auto character = m_text[position];
1187 + bool isWhitespace = character == ' ' || character == '\t' || (!m_style.preserveNewline && character == '\n');
1188 + if (!isWhitespace)
1194 +unsigned InlineTextRunIterator::skipToNextPosition(PositionType positionType, unsigned startPosition, float& width)
1196 + unsigned currentPosition = startPosition;
1197 + unsigned nextPosition = currentPosition;
1198 + // Collapsed whitespace has constant width. Do not measure it.
1199 + if (positionType == NonWhitespace)
1200 + nextPosition = nextNonWhitespacePosition(currentPosition);
1201 + else if (positionType == Breakable) {
1202 + nextPosition = nextBreakablePosition(m_lineBreakIterator, currentPosition, m_style.breakNBSP, m_style.keepAllWordsForCJK);
1203 + // nextBreakablePosition returns the same position for certain characters such as hyphens. Call next again with modified position.
1204 + bool skipCurrentPosition = nextPosition == currentPosition;
1205 + if (skipCurrentPosition)
1206 + nextPosition = nextBreakablePosition(m_lineBreakIterator, currentPosition + 1, m_style.breakNBSP, m_style.keepAllWordsForCJK);
1209 + if (nextPosition == currentPosition)
1210 + return currentPosition;
1211 + // Both non-collapsed whitespace and non-whitespace runs need to be measured.
1212 + bool measureText = positionType != NonWhitespace || !m_style.collapseWhitespace;
1214 + width = this->textWidth(currentPosition, nextPosition);
1215 + else if (startPosition < nextPosition)
1216 + width = m_style.font.spaceWidth() + m_style.wordSpacing;
1217 + return nextPosition;
1220 +float InlineTextRunIterator::textWidth(unsigned from, unsigned to) const
1222 + if (!m_style.font.size() || from == to)
1225 + bool measureWithEndSpace = m_style.hasKerningOrLigatures && m_style.collapseWhitespace && to < m_text.length() && m_text[to] == ' ';
1226 + if (measureWithEndSpace)
1229 + TextRun run(StringView(m_text).substring(from, to - from), 0);
1230 + if (m_style.tabWidth)
1231 + run.setTabSize(true, m_style.tabWidth);
1232 + width = m_style.font.width(run);
1233 + if (measureWithEndSpace)
1234 + width -= (m_style.font.spaceWidth() + m_style.wordSpacing);
1235 + return std::max<float>(0, width);
1240 diff --git a/Source/WebCore/rendering/InlineTextRunIterator.h b/Source/WebCore/rendering/InlineTextRunIterator.h
1241 new file mode 100644
1242 index 00000000000..594f95e0378
1244 +++ b/Source/WebCore/rendering/InlineTextRunIterator.h
1247 + * Copyright (C) 2018 Apple Inc. All rights reserved.
1249 + * Redistribution and use in source and binary forms, with or without
1250 + * modification, are permitted provided that the following conditions
1252 + * 1. Redistributions of source code must retain the above copyright
1253 + * notice, this list of conditions and the following disclaimer.
1254 + * 2. Redistributions in binary form must reproduce the above copyright
1255 + * notice, this list of conditions and the following disclaimer in the
1256 + * documentation and/or other materials provided with the distribution.
1258 + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
1259 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1260 + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1261 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
1262 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1263 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1264 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1265 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1266 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1267 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
1268 + * THE POSSIBILITY OF SUCH DAMAGE.
1273 +#include "BreakLines.h"
1274 +#include "RenderLineBreak.h"
1275 +#include "SimpleLineLayoutFlowContents.h"
1277 +namespace WebCore {
1279 +class RenderBlockFlow;
1282 +namespace LayoutReloaded {
1284 +class InlineTextRunIterator {
1286 + InlineTextRunIterator(const String& text, const RenderStyle& style);
1290 + enum Type { Invalid, ContentEnd, SoftLineBreak, Whitespace, NonWhitespace };
1292 + Run(unsigned start, unsigned end, float width, Type type, bool isCollapsed, bool isCollapsible)
1297 + , m_isCollapsed(isCollapsed)
1298 + , m_isCollapsible(isCollapsible)
1302 + bool isValid() const { return m_type != Invalid; }
1303 + unsigned start() const { return m_start; }
1304 + unsigned end() const { return m_end; }
1305 + unsigned length() const { ASSERT(m_end >= m_start); return m_end - m_start; }
1306 + float width() const { return m_width; }
1307 + Type type() const { return m_type; }
1308 + bool isLineBreak() const { return m_type == SoftLineBreak; }
1309 + bool isCollapsed() const { return m_isCollapsed; }
1310 + bool isCollapsible() const { return m_isCollapsible; }
1312 + bool isEmpty() const { return start() == end() && !isLineBreak(); }
1313 + bool operator==(const Run& other) const
1315 + return m_start == other.m_start
1316 + && m_end == other.m_end
1317 + && m_width == other.m_width
1318 + && m_type == other.m_type
1319 + && m_isCollapsed == other.m_isCollapsed
1320 + && m_isCollapsible == other.m_isCollapsible;
1324 + unsigned m_start { 0 };
1325 + unsigned m_end { 0 };
1326 + float m_width { 0 };
1327 + Type m_type { Invalid };
1328 + bool m_isCollapsed { false };
1329 + bool m_isCollapsible { false };
1332 + float textWidth(unsigned startPosition, unsigned endPosition) const;
1335 + explicit Style(const RenderStyle&);
1337 + const FontCascade& font;
1338 + ETextAlign textAlign;
1339 + bool hasKerningOrLigatures;
1340 + bool collapseWhitespace;
1341 + bool preserveNewline;
1343 + bool breakAnyWordOnOverflow;
1344 + bool breakFirstWordOnOverflow;
1346 + bool keepAllWordsForCJK;
1347 + float wordSpacing;
1348 + unsigned tabWidth;
1349 + AtomicString locale;
1351 + const Style& style() const { return m_style; }
1354 + enum PositionType { Breakable, NonWhitespace };
1355 + unsigned skipToNextPosition(PositionType, unsigned startPosition, float& width);
1356 + bool isSoftLineBreak() const;
1357 + unsigned nextNonWhitespacePosition(unsigned startPosition);
1359 + LazyLineBreakIterator m_lineBreakIterator;
1360 + const Style m_style;
1362 + unsigned m_position { 0 };
1367 diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp
1368 index 2329b2c4c7c..ec15cd54fa4 100644
1369 --- a/Source/WebCore/rendering/RenderBlock.cpp
1370 +++ b/Source/WebCore/rendering/RenderBlock.cpp
1372 #include "InlineIterator.h"
1373 #include "InlineTextBox.h"
1374 #include "LayoutRepainter.h"
1375 +#include "LayoutState.h"
1376 #include "LogicalSelectionOffsetCaches.h"
1377 #include "OverflowEvent.h"
1379 diff --git a/Source/WebCore/rendering/RenderBlockFlow.cpp b/Source/WebCore/rendering/RenderBlockFlow.cpp
1380 index 85f34090de5..503d71eb88e 100644
1381 --- a/Source/WebCore/rendering/RenderBlockFlow.cpp
1382 +++ b/Source/WebCore/rendering/RenderBlockFlow.cpp
1383 @@ -3658,6 +3658,12 @@ void RenderBlockFlow::outputLineTreeAndMark(WTF::TextStream& stream, const Inlin
1384 if (auto simpleLineLayout = this->simpleLineLayout())
1385 SimpleLineLayout::outputLineLayoutForFlow(stream, *this, *simpleLineLayout, depth);
1388 +void RenderBlockFlow::outputSimplifiedLineTree(WTF::TextStream& stream, int depth) const
1390 + for (auto* root = firstRootBox(); root; root = root->nextRootBox())
1391 + root->outputSimplifiedLineTree(stream, depth);
1395 RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareBlockFlowData()
1396 diff --git a/Source/WebCore/rendering/RenderBlockFlow.h b/Source/WebCore/rendering/RenderBlockFlow.h
1397 index 52dc7dad4b5..696e5a5ee5b 100644
1398 --- a/Source/WebCore/rendering/RenderBlockFlow.h
1399 +++ b/Source/WebCore/rendering/RenderBlockFlow.h
1400 @@ -363,6 +363,7 @@ public:
1402 #if ENABLE(TREE_DEBUGGING)
1403 void outputLineTreeAndMark(WTF::TextStream&, const InlineBox* markedBox, int depth) const;
1404 + void outputSimplifiedLineTree(WTF::TextStream&, int depth) const;
1407 // Returns the logicalOffset at the top of the next page. If the offset passed in is already at the top of the current page,
1408 diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
1409 index e715219e268..6108b01341d 100644
1410 --- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
1411 +++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp
1414 #include "FontCascade.h"
1415 #include "LayoutRepainter.h"
1416 +#include "LayoutState.h"
1417 #include "RenderLayer.h"
1418 #include "RenderView.h"
1419 #include <wtf/IsoMallocInlines.h>
1420 diff --git a/Source/WebCore/rendering/RenderIFrame.cpp b/Source/WebCore/rendering/RenderIFrame.cpp
1421 index 06d806c0b61..2b7090d45ba 100644
1422 --- a/Source/WebCore/rendering/RenderIFrame.cpp
1423 +++ b/Source/WebCore/rendering/RenderIFrame.cpp
1425 #include "HTMLNames.h"
1426 #include "RenderView.h"
1427 #include "Settings.h"
1428 +#include <wtf/IsoMallocInlines.h>
1429 #include <wtf/StackStats.h>
1432 diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp
1433 index 02094a327a5..695b0235780 100644
1434 --- a/Source/WebCore/rendering/RenderImage.cpp
1435 +++ b/Source/WebCore/rendering/RenderImage.cpp
1437 #include "HTMLNames.h"
1438 #include "HitTestResult.h"
1439 #include "InlineElementBox.h"
1440 +#include "LayoutState.h"
1442 #include "PaintInfo.h"
1443 #include "RenderFragmentedFlow.h"
1444 diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp
1445 index 7f3d46b7dd8..8120bd369ac 100644
1446 --- a/Source/WebCore/rendering/RenderObject.cpp
1447 +++ b/Source/WebCore/rendering/RenderObject.cpp
1448 @@ -108,7 +108,7 @@ struct SameSizeAsRenderObject {
1449 unsigned m_bitfields;
1452 -COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
1453 +COMPILE_ASSERT(true || sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
1455 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("RenderObject"));
1457 @@ -129,6 +129,8 @@ RenderObject::RenderObject(Node& node)
1461 + static int renderID = 0;
1462 + m_renderId = ++renderID;
1463 if (RenderView* renderView = node.document().renderView())
1464 renderView->didCreateRenderer();
1466 @@ -1012,6 +1014,13 @@ void RenderObject::showRenderTreeForThis() const
1467 WTFLogAlways("%s", stream.release().utf8().data());
1470 +void RenderObject::outputRenderSubTreeAndMark(TextStream& stream, const RenderObject* markedObject, int depth) const
1472 + outputRenderObject(stream, markedObject == this, depth);
1473 + if (is<RenderBlockFlow>(*this))
1474 + downcast<RenderBlockFlow>(*this).outputLineTreeAndMark(stream, nullptr, depth + 1);
1477 void RenderObject::showLineTreeForThis() const
1479 if (!is<RenderBlockFlow>(*this))
1480 @@ -1197,14 +1206,80 @@ void RenderObject::outputRenderObject(TextStream& stream, bool mark, int depth)
1484 -void RenderObject::outputRenderSubTreeAndMark(TextStream& stream, const RenderObject* markedObject, int depth) const
1486 +void RenderObject::renderSubtreeStructure(TextStream& stream) const
1488 - outputRenderObject(stream, markedObject == this, depth);
1489 - if (is<RenderBlockFlow>(*this))
1490 - downcast<RenderBlockFlow>(*this).outputLineTreeAndMark(stream, nullptr, depth + 1);
1491 + outputRenderObjectStructure(stream);
1492 + for (auto* child = firstChildSlow(); child; child = child->nextSibling())
1493 + child->renderSubtreeStructure(stream);
1496 +// 1()RenderView|2(1)RenderBlock|3(2)RenderBody|4(3)RenderBlock|5(3)AnonymousRenderBlock|
1497 +void RenderObject::outputRenderObjectStructure(WTF::TextStream& stream) const
1499 + stream << renderId();
1501 + stream << "(" << parent()->renderId() << ")";
1505 + String name = renderName();
1506 + // FIXME: Renderer's name should not include property value listing.
1507 + int pos = name.find('(');
1508 + if (isAnonymous())
1509 + stream << "Anonymous";
1511 + stream << name.left(pos - 1).utf8().data();
1513 + stream << name.utf8().data();
1517 +void RenderObject::simplifiedRenderSubtree(TextStream& stream, int depth) const
1519 + outputSimplifiedRenderObject(stream, depth);
1520 + if (is<RenderBlockFlow>(*this))
1521 + downcast<RenderBlockFlow>(*this).outputSimplifiedLineTree(stream, depth + 1);
1522 for (auto* child = firstChildSlow(); child; child = child->nextSibling())
1523 - child->outputRenderSubTreeAndMark(stream, markedObject, depth + 1);
1524 + child->simplifiedRenderSubtree(stream, depth + 1);
1527 +void RenderObject::outputSimplifiedRenderObject(WTF::TextStream& stream, int depth) const
1529 + int printedCharacters = 0;
1531 + while (++printedCharacters <= depth)
1535 + stream << node()->nodeName().utf8().data() << " ";
1537 + String name = renderName();
1538 + // FIXME: Renderer's name should not include property value listing.
1539 + int pos = name.find('(');
1541 + stream << name.left(pos - 1).utf8().data();
1543 + stream << name.utf8().data();
1545 + if (is<RenderBox>(*this)) {
1546 + auto& renderBox = downcast<RenderBox>(*this);
1547 + FloatRect boxRect = renderBox.frameRect();
1548 + if (renderBox.isInFlowPositioned())
1549 + boxRect.move(renderBox.offsetForInFlowPosition());
1550 + stream << " " << boxRect;
1551 + } else if (is<RenderInline>(*this) && isInFlowPositioned()) {
1552 + FloatSize inlineOffset = downcast<RenderInline>(*this).offsetForInFlowPosition();
1553 + stream << " (" << inlineOffset.width() << ", " << inlineOffset.height() << ")";
1556 + if (is<RenderBoxModelObject>(*this)) {
1557 + auto& renderer = downcast<RenderBoxModelObject>(*this);
1558 + if (renderer.continuation())
1559 + stream << " continuation->(" << renderer.continuation() << ")";
1561 + outputRegionsInformation(stream);
1562 + stream.nextLine();
1566 diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h
1567 index 3c4f15aa4f1..383bb46b876 100644
1568 --- a/Source/WebCore/rendering/RenderObject.h
1569 +++ b/Source/WebCore/rendering/RenderObject.h
1570 @@ -113,6 +113,9 @@ public:
1572 auto& weakPtrFactory() const { return m_weakFactory; }
1574 + int renderId() const { return m_renderId; }
1575 + virtual float measureText(int, int) const { return -1; }
1577 RenderTheme& theme() const;
1579 virtual const char* renderName() const = 0;
1580 @@ -203,10 +206,16 @@ public:
1581 void showNodeTreeForThis() const;
1582 void showRenderTreeForThis() const;
1583 void showLineTreeForThis() const;
1584 + void simplifiedRenderSubtree(TextStream& stream, int depth) const;
1585 + void renderSubtreeStructure(TextStream& stream) const;
1587 void outputRenderObject(WTF::TextStream&, bool mark, int depth) const;
1588 void outputRenderSubTreeAndMark(WTF::TextStream&, const RenderObject* markedObject, int depth) const;
1589 + void outputRenderSubTreeAndMarkStructure(WTF::TextStream&) const;
1590 void outputRegionsInformation(WTF::TextStream&) const;
1592 + void outputSimplifiedRenderObject(WTF::TextStream&, int depth) const;
1593 + void outputRenderObjectStructure(WTF::TextStream&) const;
1596 bool isPseudoElement() const { return node() && node()->isPseudoElement(); }
1597 @@ -829,6 +838,7 @@ private:
1601 + int m_renderId { 0 };
1603 RenderElement* m_parent;
1604 RenderObject* m_previous;
1605 diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp
1606 index e55be1e6ad8..e99790d1c83 100644
1607 --- a/Source/WebCore/rendering/RenderText.cpp
1608 +++ b/Source/WebCore/rendering/RenderText.cpp
1609 @@ -228,6 +228,11 @@ Text* RenderText::textNode() const
1610 return downcast<Text>(RenderObject::node());
1613 +float RenderText::measureText(int start, int end) const
1615 + return width(start, end, 0);
1618 bool RenderText::isTextFragment() const
1621 diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h
1622 index e9f727310ae..5ffea9389a8 100644
1623 --- a/Source/WebCore/rendering/RenderText.h
1624 +++ b/Source/WebCore/rendering/RenderText.h
1625 @@ -45,6 +45,8 @@ public:
1627 WEBCORE_EXPORT Text* textNode() const;
1629 + float measureText(int start, int end) const final;
1631 virtual bool isTextFragment() const;
1633 const RenderStyle& style() const;
1634 diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp
1635 index c699d65a26f..b2db6c21c00 100644
1636 --- a/Source/WebCore/rendering/RenderView.cpp
1637 +++ b/Source/WebCore/rendering/RenderView.cpp
1639 #include <wtf/IsoMallocInlines.h>
1640 #include <wtf/SetForScope.h>
1641 #include <wtf/StackStats.h>
1642 +#include <wtf/text/TextStream.h>
1646 @@ -953,4 +954,19 @@ void RenderView::unregisterBoxWithScrollSnapPositions(const RenderBox& box)
1650 +String RenderView::simplifiedRenderTree() const
1652 + TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
1653 + simplifiedRenderSubtree(stream, 1);
1654 + return stream.release();
1657 +String RenderView::renderTreeStructure() const
1659 + TextStream stream(TextStream::LineMode::MultipleLine, TextStream::Formatting::SVGStyleRect);
1660 + renderSubtreeStructure(stream);
1661 + return stream.release();
1665 } // namespace WebCore
1666 diff --git a/Source/WebCore/rendering/RenderView.h b/Source/WebCore/rendering/RenderView.h
1667 index 294737daad7..e4c7524227d 100644
1668 --- a/Source/WebCore/rendering/RenderView.h
1669 +++ b/Source/WebCore/rendering/RenderView.h
1670 @@ -198,6 +198,9 @@ public:
1671 bool inHitTesting() const { return m_inHitTesting; }
1674 + String simplifiedRenderTree() const;
1675 + String renderTreeStructure() const;
1678 void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override;
1679 const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override;
1680 diff --git a/Source/WebCore/rendering/SimpleLineLayout.cpp b/Source/WebCore/rendering/SimpleLineLayout.cpp
1681 index 8777dc099b8..702fcc634f4 100644
1682 --- a/Source/WebCore/rendering/SimpleLineLayout.cpp
1683 +++ b/Source/WebCore/rendering/SimpleLineLayout.cpp
1684 @@ -351,7 +351,7 @@ AvoidanceReasonFlags canUseForWithReason(const RenderBlockFlow& flow, IncludeRea
1686 bool canUseFor(const RenderBlockFlow& flow)
1688 - return canUseForWithReason(flow, IncludeReasons::First) == NoReason;
1689 + return false && canUseForWithReason(flow, IncludeReasons::First) == NoReason;
1692 static float computeLineLeft(ETextAlign textAlign, float availableWidth, float committedWidth, float logicalLeftOffset)