[LFC][IFC] Move detaching rules from InlineFormattingState to InlineItem
[WebKit-https.git] / Source / WebCore / layout / inlineformatting / InlineFormattingContext.cpp
1 /*
2  * Copyright (C) 2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "InlineFormattingContext.h"
28
29 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
30
31 #include "FloatingState.h"
32 #include "InlineFormattingState.h"
33 #include "InlineLineBreaker.h"
34 #include "InlineRunProvider.h"
35 #include "LayoutBox.h"
36 #include "LayoutContainer.h"
37 #include "LayoutFormattingState.h"
38 #include "LayoutInlineBox.h"
39 #include "LayoutInlineContainer.h"
40 #include "Logging.h"
41 #include <wtf/IsoMallocInlines.h>
42 #include <wtf/text/TextStream.h>
43
44 namespace WebCore {
45 namespace Layout {
46
47 WTF_MAKE_ISO_ALLOCATED_IMPL(InlineFormattingContext);
48
49 InlineFormattingContext::InlineFormattingContext(const Box& formattingContextRoot, FormattingState& formattingState)
50     : FormattingContext(formattingContextRoot, formattingState)
51 {
52 }
53
54 void InlineFormattingContext::layout() const
55 {
56     if (!is<Container>(root()))
57         return;
58
59     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Start] -> inline formatting context -> formatting root(" << &root() << ")");
60
61     InlineRunProvider inlineRunProvider;
62     collectInlineContent(inlineRunProvider);
63     // Compute width/height for non-text content.
64     for (auto& inlineRun : inlineRunProvider.runs()) {
65         if (inlineRun.isText())
66             continue;
67
68         auto& layoutBox = inlineRun.inlineItem().layoutBox();
69         if (layoutBox.establishesFormattingContext()) {
70             layoutFormattingContextRoot(layoutBox);
71             continue;
72         }
73         computeWidthAndHeightForReplacedInlineBox(layoutBox);
74     }
75
76     layoutInlineContent(inlineRunProvider);
77     LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> inline formatting context -> formatting root(" << &root() << ")");
78 }
79
80 static bool isTrimmableContent(const InlineLineBreaker::Run& run)
81 {
82     return run.content.isWhitespace() && run.content.style().collapseWhiteSpace();
83 }
84
85 void InlineFormattingContext::initializeNewLine(Line& line) const
86 {
87     auto& formattingRoot = downcast<Container>(root());
88     auto& formattingRootDisplayBox = layoutState().displayBoxForLayoutBox(formattingRoot);
89
90     auto lineLogicalLeft = formattingRootDisplayBox.contentBoxLeft();
91     auto lineLogicalTop = line.isFirstLine() ? formattingRootDisplayBox.contentBoxTop() : line.logicalBottom();
92     auto availableWidth = formattingRootDisplayBox.contentBoxWidth();
93
94     // Check for intruding floats and adjust logical left/available width for this line accordingly.
95     auto& floatingState = formattingState().floatingState();
96     if (!floatingState.isEmpty()) {
97         auto floatConstraints = floatingState.constraints(lineLogicalTop, formattingRoot);
98         // Check if these constraints actually put limitation on the line.
99         if (floatConstraints.left && *floatConstraints.left <= formattingRootDisplayBox.contentBoxLeft())
100             floatConstraints.left = { };
101
102         if (floatConstraints.right && *floatConstraints.right >= formattingRootDisplayBox.contentBoxRight())
103             floatConstraints.right = { };
104
105         if (floatConstraints.left && floatConstraints.right) {
106             ASSERT(*floatConstraints.left < *floatConstraints.right);
107             availableWidth = *floatConstraints.right - *floatConstraints.left;
108             lineLogicalLeft = *floatConstraints.left;
109         } else if (floatConstraints.left) {
110             ASSERT(*floatConstraints.left > lineLogicalLeft);
111             availableWidth -= (*floatConstraints.left - lineLogicalLeft);
112             lineLogicalLeft = *floatConstraints.left;
113         } else if (floatConstraints.right) {
114             ASSERT(*floatConstraints.right > lineLogicalLeft);
115             availableWidth = *floatConstraints.right - lineLogicalLeft;
116         }
117     }
118
119     Display::Box::Rect logicalRect;
120     logicalRect.setTop(lineLogicalTop);
121     logicalRect.setLeft(lineLogicalLeft);
122     logicalRect.setWidth(availableWidth);
123     logicalRect.setHeight(formattingRoot.style().computedLineHeight());
124
125     line.init(logicalRect);
126 }
127
128 void InlineFormattingContext::splitInlineRunIfNeeded(const InlineRun& inlineRun, InlineRuns& splitRuns) const
129 {
130     if (!inlineRun.overlapsMultipleInlineItems())
131         return;
132
133     ASSERT(inlineRun.textContext());
134     // In certain cases, a run can overlap multiple inline elements like this:
135     // <span>normal text content</span><span style="position: relative; left: 10px;">but this one needs a dedicated run</span><span>end of text</span>
136     // The content above generates one long run <normal text contentbut this one needs dedicated runend of text>
137     // However, since the middle run is positioned, it needs to be moved independently from the rest of the content, hence it needs a dedicated inline run.
138
139     // 1. Start with the first inline item (element) and travers the list until
140     // 2. either find an inline item that needs a dedicated run or we reach the end of the run
141     // 3. Create dedicate inline runs.
142     auto& inlineContent = inlineFormattingState().inlineContent();
143     auto textUtil = TextUtil { inlineContent };
144
145     auto split=[&](const auto& inlineItem, auto startPosition, auto length, auto contentStart) {
146         auto width = textUtil.width(inlineItem, startPosition, length, contentStart);
147
148         auto run = InlineRun { { inlineRun.logicalTop(), contentStart, width, inlineRun.height() }, inlineItem };
149         run.setTextContext({ startPosition, length });
150         splitRuns.append(run);
151         return contentStart + width;
152     };
153
154     auto contentStart = inlineRun.logicalLeft();
155     auto startPosition = inlineRun.textContext()->start();
156     auto remaningLength = inlineRun.textContext()->length();
157
158     unsigned uncommittedLength = 0;
159     InlineItem* firstUncommittedInlineItem = nullptr;
160     for (auto iterator = inlineContent.find<const InlineItem&, InlineItemHashTranslator>(inlineRun.inlineItem()); iterator != inlineContent.end() && remaningLength > 0; ++iterator) {
161         auto& inlineItem = **iterator;
162
163         // Skip all non-inflow boxes (floats, out-of-flow positioned elements). They don't participate in the inline run context.
164         if (!inlineItem.layoutBox().isInFlow())
165             continue;
166
167         auto currentLength = [&] {
168             return std::min(remaningLength, inlineItem.textContent().length() - startPosition);
169         };
170
171         // 1. Inline element does not require run breaking -> add current inline element to uncommitted. Jump to the next element.
172         // 2. Break at the beginning of the inline element -> commit what we've got so far. Current element becomes the first uncommitted.
173         // 3. Break at the end of the inline element -> commit what we've got so far including the current element.
174         // 4. Break before/after -> requires dedicated run -> commit what we've got so far and also commit the current inline element as a separate inline run.
175         auto detachingRules = inlineItem.detachingRules();
176
177         // #1
178         if (detachingRules.isEmpty()) {
179             uncommittedLength += currentLength();
180             firstUncommittedInlineItem = !firstUncommittedInlineItem ? &inlineItem : firstUncommittedInlineItem;
181             continue;
182         }
183
184         auto commit = [&] {
185             if (!firstUncommittedInlineItem)
186                 return;
187
188             contentStart = split(*firstUncommittedInlineItem, startPosition, uncommittedLength, contentStart);
189
190             remaningLength -= uncommittedLength;
191             startPosition = 0;
192             uncommittedLength = 0;
193             firstUncommittedInlineItem = nullptr;
194         };
195
196         // #2
197         if (detachingRules == InlineItem::DetachingRule::BreakAtStart) {
198             commit();
199             firstUncommittedInlineItem = &inlineItem;
200             uncommittedLength = currentLength();
201             continue;
202         }
203
204         // #3
205         if (detachingRules == InlineItem::DetachingRule::BreakAtEnd) {
206             ASSERT(firstUncommittedInlineItem);
207             uncommittedLength += currentLength();
208             commit();
209             continue;
210         }
211
212         // #4
213         commit();
214         firstUncommittedInlineItem = &inlineItem;
215         uncommittedLength = currentLength();
216         commit();
217     }
218
219     // Either all inline elements needed dedicated runs or neither of them.
220     if (!remaningLength || remaningLength == inlineRun.textContext()->length())
221         return;
222
223     ASSERT(remaningLength == uncommittedLength);
224     split(*firstUncommittedInlineItem, startPosition, uncommittedLength, contentStart);
225 }
226
227 InlineFormattingContext::Line::RunRange InlineFormattingContext::splitInlineRunsIfNeeded(Line::RunRange runRange) const
228 {
229     auto& inlineRuns = inlineFormattingState().inlineRuns();
230     ASSERT(*runRange.lastRunIndex < inlineRuns.size());
231
232     auto runIndex = *runRange.firstRunIndex;
233     auto& lastInlineRun = inlineRuns[*runRange.lastRunIndex];
234     while (runIndex < inlineRuns.size()) {
235         auto& inlineRun = inlineRuns[runIndex];
236         auto isLastRunInRange = &inlineRun == &lastInlineRun;
237
238         InlineRuns splitRuns;
239         splitInlineRunIfNeeded(inlineRun, splitRuns);
240         if (!splitRuns.isEmpty()) {
241             ASSERT(splitRuns.size() > 1);
242             // Replace the continous run with new ones.
243             // Reuse the original one.
244             auto& firstRun = splitRuns.first();
245             inlineRun.setWidth(firstRun.width());
246             inlineRun.textContext()->setLength(firstRun.textContext()->length());
247             splitRuns.remove(0);
248             // Insert the rest.
249             for (auto& splitRun : splitRuns)
250                 inlineRuns.insert(++runIndex, splitRun);
251         }
252
253         if (isLastRunInRange)
254             break;
255
256         ++runIndex;
257     }
258
259     return { runRange.firstRunIndex, runIndex };
260 }
261
262 void InlineFormattingContext::postProcessInlineRuns(Line& line, IsLastLine isLastLine, Line::RunRange runRange) const
263 {
264     auto& inlineFormattingState = this->inlineFormattingState();
265     Geometry::alignRuns(inlineFormattingState, root().style().textAlign(), line, runRange, isLastLine);
266     runRange = splitInlineRunsIfNeeded(runRange);
267     placeInFlowPositionedChildren(runRange);
268 }
269
270 void InlineFormattingContext::closeLine(Line& line, IsLastLine isLastLine) const
271 {
272     auto runRange = line.close();
273     ASSERT(!runRange.firstRunIndex || runRange.lastRunIndex);
274
275     if (!runRange.firstRunIndex)
276         return;
277
278     postProcessInlineRuns(line, isLastLine, runRange);
279 }
280
281 void InlineFormattingContext::appendContentToLine(Line& line, const InlineLineBreaker::Run& run) const
282 {
283     auto lastRunType = line.lastRunType();
284     line.appendContent(run);
285
286     if (root().style().textAlign() == TextAlignMode::Justify)
287         Geometry::computeExpansionOpportunities(inlineFormattingState(), run.content, lastRunType.value_or(InlineRunProvider::Run::Type::NonWhitespace));
288 }
289
290 void InlineFormattingContext::layoutInlineContent(const InlineRunProvider& inlineRunProvider) const
291 {
292     auto& layoutState = this->layoutState();
293     auto& inlineFormattingState = this->inlineFormattingState();
294     auto floatingContext = FloatingContext { inlineFormattingState.floatingState() };
295
296     Line line(inlineFormattingState);
297     initializeNewLine(line);
298
299     InlineLineBreaker lineBreaker(layoutState, inlineFormattingState.inlineContent(), inlineRunProvider.runs());
300     while (auto run = lineBreaker.nextRun(line.contentLogicalRight(), line.availableWidth(), !line.hasContent())) {
301         auto isFirstRun = run->position == InlineLineBreaker::Run::Position::LineBegin;
302         auto isLastRun = run->position == InlineLineBreaker::Run::Position::LineEnd;
303         auto generatesInlineRun = true;
304
305         // Position float and adjust the runs on line.
306         if (run->content.isFloat()) {
307             auto& floatBox = run->content.inlineItem().layoutBox();
308             computeFloatPosition(floatingContext, line, floatBox);
309             inlineFormattingState.floatingState().append(floatBox);
310
311             auto floatBoxWidth = layoutState.displayBoxForLayoutBox(floatBox).width();
312             // Shrink availble space for current line and move existing inline runs.
313             floatBox.isLeftFloatingPositioned() ? line.adjustLogicalLeft(floatBoxWidth) : line.adjustLogicalRight(floatBoxWidth);
314
315             generatesInlineRun = false;
316         }
317
318         // 1. Initialize new line if needed.
319         // 2. Append inline run unless it is skipped.
320         // 3. Close current line if needed.
321         if (isFirstRun) {
322             // When the first run does not generate an actual inline run, the next run comes in first-run as well.
323             // No need to spend time on closing/initializing.
324             // Skip leading whitespace.
325             if (!generatesInlineRun || isTrimmableContent(*run))
326                 continue;
327
328             if (line.hasContent()) {
329                 // Previous run ended up being at the line end. Adjust the line accordingly.
330                 if (!line.isClosed())
331                     closeLine(line, IsLastLine::No);
332                 initializeNewLine(line);
333             }
334          }
335
336         if (generatesInlineRun)
337             appendContentToLine(line, *run);
338
339         if (isLastRun)
340             closeLine(line, IsLastLine::No);
341     }
342
343     closeLine(line, IsLastLine::Yes);
344 }
345
346 void InlineFormattingContext::computeWidthAndMargin(const Box& layoutBox) const
347 {
348     auto& layoutState = this->layoutState();
349
350     WidthAndMargin widthAndMargin;
351     if (layoutBox.isFloatingPositioned())
352         widthAndMargin = Geometry::floatingWidthAndMargin(layoutState, layoutBox);
353     else if (layoutBox.isInlineBlockBox())
354         widthAndMargin = Geometry::inlineBlockWidthAndMargin(layoutState, layoutBox);
355     else if (layoutBox.replaced())
356         widthAndMargin = Geometry::inlineReplacedWidthAndMargin(layoutState, layoutBox);
357     else
358         ASSERT_NOT_REACHED();
359
360     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
361     displayBox.setContentBoxWidth(widthAndMargin.width);
362     displayBox.setHorizontalMargin(widthAndMargin.margin);
363     displayBox.setHorizontalNonComputedMargin(widthAndMargin.nonComputedMargin);
364 }
365
366 void InlineFormattingContext::computeHeightAndMargin(const Box& layoutBox) const
367 {
368     auto& layoutState = this->layoutState();
369
370     HeightAndMargin heightAndMargin;
371     if (layoutBox.isFloatingPositioned())
372         heightAndMargin = Geometry::floatingHeightAndMargin(layoutState, layoutBox);
373     else if (layoutBox.isInlineBlockBox())
374         heightAndMargin = Geometry::inlineBlockHeightAndMargin(layoutState, layoutBox);
375     else if (layoutBox.replaced())
376         heightAndMargin = Geometry::inlineReplacedHeightAndMargin(layoutState, layoutBox);
377     else
378         ASSERT_NOT_REACHED();
379
380     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
381     displayBox.setContentBoxHeight(heightAndMargin.height);
382     displayBox.setVerticalNonCollapsedMargin(heightAndMargin.margin);
383     displayBox.setVerticalMargin(heightAndMargin.collapsedMargin.value_or(heightAndMargin.margin));
384 }
385
386 void InlineFormattingContext::layoutFormattingContextRoot(const Box& root) const
387 {
388     ASSERT(root.isFloatingPositioned() || root.isInlineBlockBox());
389
390     computeBorderAndPadding(root);
391     computeWidthAndMargin(root);
392     // Swich over to the new formatting context (the one that the root creates).
393     auto formattingContext = layoutState().createFormattingStateForFormattingRootIfNeeded(root).formattingContext(root);
394     formattingContext->layout();
395     // Come back and finalize the root's height and margin.
396     computeHeightAndMargin(root);
397     // Now that we computed the root's height, we can go back and layout the out-of-flow descedants (if any).
398     formattingContext->layoutOutOfFlowDescendants(root);
399 }
400
401 void InlineFormattingContext::computeWidthAndHeightForReplacedInlineBox(const Box& layoutBox) const
402 {
403     ASSERT(!layoutBox.isContainer());
404     ASSERT(!layoutBox.establishesFormattingContext());
405     ASSERT(layoutBox.replaced());
406
407     computeBorderAndPadding(layoutBox);
408     computeWidthAndMargin(layoutBox);
409     computeHeightAndMargin(layoutBox);
410 }
411
412 void InlineFormattingContext::computeFloatPosition(const FloatingContext& floatingContext, Line& line, const Box& floatBox) const
413 {
414     auto& layoutState = this->layoutState();
415     ASSERT(layoutState.hasDisplayBox(floatBox));
416     auto& displayBox = layoutState.displayBoxForLayoutBox(floatBox);
417
418     // Set static position first.
419     displayBox.setTopLeft({ line.contentLogicalRight(), line.logicalTop() });
420     // Float it.
421     displayBox.setTopLeft(floatingContext.positionForFloat(floatBox));
422 }
423
424 void InlineFormattingContext::placeInFlowPositionedChildren(Line::RunRange runRange) const
425 {
426     auto& inlineRuns = inlineFormattingState().inlineRuns();
427     ASSERT(*runRange.lastRunIndex < inlineRuns.size());
428
429     for (auto runIndex = *runRange.firstRunIndex; runIndex <= *runRange.lastRunIndex; ++runIndex) {
430         auto& inlineRun = inlineRuns[runIndex];
431
432         auto positionOffset = [&](auto& layoutBox) {
433             // FIXME: Need to figure out whether in-flow offset should stick. This might very well be temporary.
434             std::optional<LayoutSize> offset;
435             for (auto* box = &layoutBox; box != &root(); box = box->parent()) {
436                 if (!box->isInFlowPositioned())
437                     continue;
438                 offset = offset.value_or(LayoutSize()) + Geometry::inFlowPositionedPositionOffset(layoutState(), *box);
439             }
440             return offset;
441         };
442
443         if (auto offset = positionOffset(inlineRun.inlineItem().layoutBox())) {
444             inlineRun.moveVertically(offset->height());
445             inlineRun.moveHorizontally(offset->width());
446         }
447     }
448 }
449
450 void InlineFormattingContext::collectInlineContentForSubtree(const Box& root, InlineRunProvider& inlineRunProvider) const
451 {
452     // Collect inline content recursively and set breaking rules for the inline elements (for paddings, margins, positioned element etc).
453     auto& inlineFormattingState = this->inlineFormattingState();
454
455     auto createAndAppendInlineItem = [&] {
456         auto inlineItem = std::make_unique<InlineItem>(root);
457         inlineRunProvider.append(*inlineItem);
458         inlineFormattingState.inlineContent().add(WTFMove(inlineItem));
459     };
460
461     if (root.establishesFormattingContext() && &root != &(this->root())) {
462         createAndAppendInlineItem();
463         inlineFormattingState.inlineContent().last()->addDetachingRule({ InlineItem::DetachingRule::BreakAtStart, InlineItem::DetachingRule::BreakAtEnd });
464         // Skip formatting root subtree. They are not part of this inline formatting context.
465         return;
466     }
467
468     if (!is<Container>(root)) {
469         createAndAppendInlineItem();
470         return;
471     }
472
473     auto* lastInlineBoxBeforeContainer = inlineFormattingState.lastInlineItem();
474     auto* child = downcast<Container>(root).firstInFlowOrFloatingChild();
475     while (child) {
476         collectInlineContentForSubtree(*child, inlineRunProvider);
477         child = child->nextInFlowOrFloatingSibling();
478     }
479
480     // Setup breaking boundaries for this subtree.
481     auto* lastDescendantInlineBox = inlineFormattingState.lastInlineItem();
482     // Empty container?
483     if (lastInlineBoxBeforeContainer == lastDescendantInlineBox)
484         return;
485
486     auto rootBreaksAtStart = [&] {
487         // FIXME: add padding-inline-start, margin-inline-start etc.
488         return root.isPositioned();
489     };
490
491     auto rootBreaksAtEnd = [&] {
492         // FIXME: add padding-inline-end, margin-inline-end etc.
493         return root.isPositioned();
494     };
495
496     if (rootBreaksAtStart()) {
497         InlineItem* firstDescendantInlineBox = nullptr;
498         auto& inlineContent = inlineFormattingState.inlineContent();
499
500         if (lastInlineBoxBeforeContainer) {
501             auto iterator = inlineContent.find<const InlineItem&, InlineItemHashTranslator>(*lastInlineBoxBeforeContainer);
502             firstDescendantInlineBox = (*++iterator).get();
503         } else
504             firstDescendantInlineBox = inlineContent.first().get();
505
506         ASSERT(firstDescendantInlineBox);
507         firstDescendantInlineBox->addDetachingRule(InlineItem::DetachingRule::BreakAtStart);
508     }
509
510     if (rootBreaksAtEnd())
511         lastDescendantInlineBox->addDetachingRule(InlineItem::DetachingRule::BreakAtEnd);
512 }
513
514 void InlineFormattingContext::collectInlineContent(InlineRunProvider& inlineRunProvider) const
515 {
516     collectInlineContentForSubtree(root(), inlineRunProvider);
517 }
518
519 FormattingContext::InstrinsicWidthConstraints InlineFormattingContext::instrinsicWidthConstraints() const
520 {
521     auto& formattingStateForRoot = layoutState().formattingStateForBox(root());
522     if (auto instrinsicWidthConstraints = formattingStateForRoot.instrinsicWidthConstraints(root()))
523         return *instrinsicWidthConstraints;
524
525     auto& inlineFormattingState = this->inlineFormattingState();
526     InlineRunProvider inlineRunProvider;
527     collectInlineContent(inlineRunProvider);
528
529     // Compute width for non-text content.
530     for (auto& inlineRun : inlineRunProvider.runs()) {
531         if (inlineRun.isText())
532             continue;
533
534         computeWidthAndMargin(inlineRun.inlineItem().layoutBox());
535     }
536
537     auto maximumLineWidth = [&](auto availableWidth) {
538         LayoutUnit maxContentLogicalRight;
539         InlineLineBreaker lineBreaker(layoutState(), inlineFormattingState.inlineContent(), inlineRunProvider.runs());
540         LayoutUnit lineLogicalRight;
541         while (auto run = lineBreaker.nextRun(lineLogicalRight, availableWidth, !lineLogicalRight)) {
542             if (run->position == InlineLineBreaker::Run::Position::LineBegin)
543                 lineLogicalRight = 0;
544             lineLogicalRight += run->width;
545
546             maxContentLogicalRight = std::max(maxContentLogicalRight, lineLogicalRight);
547         }
548         return maxContentLogicalRight;
549     };
550
551     auto instrinsicWidthConstraints = FormattingContext::InstrinsicWidthConstraints { maximumLineWidth(0), maximumLineWidth(LayoutUnit::max()) };
552     formattingStateForRoot.setInstrinsicWidthConstraints(root(), instrinsicWidthConstraints);
553     return instrinsicWidthConstraints;
554 }
555
556 }
557 }
558
559 #endif