[LFC] Remove PointInContainingBlock and PositionInContainingBlock
[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 "Textutil.h"
42 #include <wtf/IsoMallocInlines.h>
43 #include <wtf/text/TextStream.h>
44
45 namespace WebCore {
46 namespace Layout {
47
48 WTF_MAKE_ISO_ALLOCATED_IMPL(InlineFormattingContext);
49
50 InlineFormattingContext::InlineFormattingContext(const Box& formattingContextRoot, FormattingState& formattingState)
51     : FormattingContext(formattingContextRoot, formattingState)
52 {
53 }
54
55 void InlineFormattingContext::layout() const
56 {
57     if (!is<Container>(root()))
58         return;
59
60     LOG_WITH_STREAM(FormattingContextLayout, stream << "[Start] -> inline formatting context -> formatting root(" << &root() << ")");
61
62     InlineRunProvider inlineRunProvider;
63     collectInlineContent(inlineRunProvider);
64     // Compute width/height for non-text content.
65     for (auto& inlineRun : inlineRunProvider.runs()) {
66         if (inlineRun.isText())
67             continue;
68
69         auto& layoutBox = inlineRun.inlineItem().layoutBox();
70         if (layoutBox.establishesFormattingContext()) {
71             layoutFormattingContextRoot(layoutBox);
72             continue;
73         }
74         computeWidthAndHeightForReplacedInlineBox(layoutBox);
75     }
76
77     layoutInlineContent(inlineRunProvider);
78     LOG_WITH_STREAM(FormattingContextLayout, stream << "[End] -> inline formatting context -> formatting root(" << &root() << ")");
79 }
80
81 static bool isTrimmableContent(const InlineLineBreaker::Run& run)
82 {
83     return run.content.isWhitespace() && run.content.style().collapseWhiteSpace();
84 }
85
86 void InlineFormattingContext::initializeNewLine(Line& line) const
87 {
88     auto& formattingRoot = downcast<Container>(root());
89     auto& formattingRootDisplayBox = layoutState().displayBoxForLayoutBox(formattingRoot);
90
91     auto lineLogicalLeft = formattingRootDisplayBox.contentBoxLeft();
92     auto lineLogicalTop = line.isFirstLine() ? formattingRootDisplayBox.contentBoxTop() : line.logicalBottom();
93     auto availableWidth = formattingRootDisplayBox.contentBoxWidth();
94
95     // Check for intruding floats and adjust logical left/available width for this line accordingly.
96     auto& floatingState = formattingState().floatingState();
97     if (!floatingState.isEmpty()) {
98         auto floatConstraints = floatingState.constraints({ lineLogicalTop }, formattingRoot);
99         // Check if these constraints actually put limitation on the line.
100         if (floatConstraints.left && *floatConstraints.left <= formattingRootDisplayBox.contentBoxLeft())
101             floatConstraints.left = { };
102
103         if (floatConstraints.right && *floatConstraints.right >= formattingRootDisplayBox.contentBoxRight())
104             floatConstraints.right = { };
105
106         if (floatConstraints.left && floatConstraints.right) {
107             ASSERT(*floatConstraints.left < *floatConstraints.right);
108             availableWidth = *floatConstraints.right - *floatConstraints.left;
109             lineLogicalLeft = *floatConstraints.left;
110         } else if (floatConstraints.left) {
111             ASSERT(*floatConstraints.left > lineLogicalLeft);
112             availableWidth -= (*floatConstraints.left - lineLogicalLeft);
113             lineLogicalLeft = *floatConstraints.left;
114         } else if (floatConstraints.right) {
115             ASSERT(*floatConstraints.right > lineLogicalLeft);
116             availableWidth = *floatConstraints.right - lineLogicalLeft;
117         }
118     }
119
120     line.init({ lineLogicalLeft, lineLogicalTop }, availableWidth, formattingRoot.style().computedLineHeight());
121 }
122
123 void InlineFormattingContext::splitInlineRunIfNeeded(const InlineRun& inlineRun, InlineRuns& splitRuns) const
124 {
125     ASSERT(inlineRun.textContext());
126     ASSERT(inlineRun.overlapsMultipleInlineItems());
127     // In certain cases, a run can overlap multiple inline elements like this:
128     // <span>normal text content</span><span style="position: relative; left: 10px;">but this one needs a dedicated run</span><span>end of text</span>
129     // The content above generates one long run <normal text contentbut this one needs dedicated runend of text>
130     // 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.
131
132     // 1. Start with the first inline item (element) and travers the list until
133     // 2. either find an inline item that needs a dedicated run or we reach the end of the run
134     // 3. Create dedicate inline runs.
135     auto& inlineContent = inlineFormattingState().inlineContent();
136     auto contentStart = inlineRun.logicalLeft();
137     auto startPosition = inlineRun.textContext()->start();
138     auto remaningLength = inlineRun.textContext()->length();
139
140     struct Uncommitted {
141         const InlineItem* firstInlineItem { nullptr };
142         const InlineItem* lastInlineItem { nullptr };
143         unsigned length { 0 };
144     };
145     std::optional<Uncommitted> uncommitted;
146
147     auto commit = [&] {
148         if (!uncommitted)
149             return;
150
151         contentStart += uncommitted->firstInlineItem->nonBreakableStart();
152
153         auto runWidth = Geometry::runWidth(inlineContent, *uncommitted->firstInlineItem, startPosition, uncommitted->length, contentStart);
154         auto run = InlineRun { { inlineRun.logicalTop(), contentStart, runWidth, inlineRun.logicalHeight() }, *uncommitted->firstInlineItem };
155         run.setTextContext({ startPosition, uncommitted->length });
156         splitRuns.append(run);
157
158         contentStart += runWidth + uncommitted->lastInlineItem->nonBreakableEnd();
159         remaningLength -= uncommitted->length;
160
161         startPosition = 0;
162         uncommitted = { };
163     };
164
165     for (auto iterator = inlineContent.find(const_cast<InlineItem*>(&inlineRun.inlineItem())); iterator != inlineContent.end() && remaningLength > 0; ++iterator) {
166         auto& inlineItem = **iterator;
167
168         // Skip all non-inflow boxes (floats, out-of-flow positioned elements). They don't participate in the inline run context.
169         if (!inlineItem.layoutBox().isInFlow())
170             continue;
171
172         auto currentLength = [&] {
173             return std::min(remaningLength, inlineItem.textContent().length() - startPosition);
174         };
175
176         // 1. 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.
177         // 2. Break at the beginning of the inline element -> commit what we've got so far. Current element becomes the first uncommitted.
178         // 3. Break at the end of the inline element -> commit what we've got so far including the current element.
179         // 4. Inline element does not require run breaking -> add current inline element to uncommitted. Jump to the next element.
180         auto detachingRules = inlineItem.detachingRules();
181
182         // #1
183         if (detachingRules.containsAll({ InlineItem::DetachingRule::BreakAtStart, InlineItem::DetachingRule::BreakAtEnd })) {
184             commit();
185             uncommitted = Uncommitted { &inlineItem, &inlineItem, currentLength() };
186             commit();
187             continue;
188         }
189
190         // #2
191         if (detachingRules.contains(InlineItem::DetachingRule::BreakAtStart))
192             commit();
193
194         // Add current inline item to uncommitted.
195         // #3 and #4
196         if (!uncommitted)
197             uncommitted = Uncommitted { &inlineItem, &inlineItem, 0 };
198         uncommitted->length += currentLength();
199         uncommitted->lastInlineItem = &inlineItem;
200
201         // #3
202         if (detachingRules.contains(InlineItem::DetachingRule::BreakAtEnd))
203             commit();
204     }
205     // Either all inline elements needed dedicated runs or neither of them.
206     if (!remaningLength || remaningLength == inlineRun.textContext()->length())
207         return;
208
209     commit();
210 }
211
212 void InlineFormattingContext::createFinalRuns(Line& line) const
213 {
214     auto& inlineFormattingState = this->inlineFormattingState();
215     for (auto& inlineRun : line.runs()) {
216         if (inlineRun.overlapsMultipleInlineItems()) {
217             InlineRuns splitRuns;
218             splitInlineRunIfNeeded(inlineRun, splitRuns);
219             for (auto& splitRun : splitRuns)
220                 inlineFormattingState.appendInlineRun(splitRun);
221
222             if (!splitRuns.isEmpty())
223                 continue;
224         }
225
226         auto finalRun = [&] {
227             auto& inlineItem = inlineRun.inlineItem();
228             if (inlineItem.detachingRules().isEmpty())
229                 return inlineRun;
230
231             InlineRun adjustedRun = inlineRun;
232             auto width = inlineRun.logicalWidth() - inlineItem.nonBreakableStart() - inlineItem.nonBreakableEnd();
233             adjustedRun.setLogicalLeft(inlineRun.logicalLeft() + inlineItem.nonBreakableStart());
234             adjustedRun.setLogicalWidth(width);
235             return adjustedRun;
236         };
237
238         inlineFormattingState.appendInlineRun(finalRun());
239     }
240 }
241
242 void InlineFormattingContext::postProcessInlineRuns(Line& line, IsLastLine isLastLine) const
243 {
244     Geometry::alignRuns(root().style().textAlign(), line, isLastLine);
245     auto firstRunIndex = inlineFormattingState().inlineRuns().size();
246     createFinalRuns(line);
247
248     placeInFlowPositionedChildren(firstRunIndex);
249 }
250
251 void InlineFormattingContext::closeLine(Line& line, IsLastLine isLastLine) const
252 {
253     line.close();
254     if (!line.hasContent())
255         return;
256
257     postProcessInlineRuns(line, isLastLine);
258 }
259
260 void InlineFormattingContext::appendContentToLine(Line& line, const InlineRunProvider::Run& run, const LayoutSize& runSize) const
261 {
262     auto lastRunType = line.lastRunType();
263     line.appendContent(run, runSize);
264
265     if (root().style().textAlign() == TextAlignMode::Justify)
266         Geometry::computeExpansionOpportunities(line, run, lastRunType.value_or(InlineRunProvider::Run::Type::NonWhitespace));
267 }
268
269 void InlineFormattingContext::layoutInlineContent(const InlineRunProvider& inlineRunProvider) const
270 {
271     auto& layoutState = this->layoutState();
272     auto& inlineFormattingState = this->inlineFormattingState();
273     auto floatingContext = FloatingContext { inlineFormattingState.floatingState() };
274
275     Line line;
276     initializeNewLine(line);
277
278     InlineLineBreaker lineBreaker(layoutState, inlineFormattingState.inlineContent(), inlineRunProvider.runs());
279     while (auto run = lineBreaker.nextRun(line.contentLogicalRight(), line.availableWidth(), !line.hasContent())) {
280         auto isFirstRun = run->position == InlineLineBreaker::Run::Position::LineBegin;
281         auto isLastRun = run->position == InlineLineBreaker::Run::Position::LineEnd;
282         auto generatesInlineRun = true;
283
284         // Position float and adjust the runs on line.
285         if (run->content.isFloat()) {
286             auto& floatBox = run->content.inlineItem().layoutBox();
287             computeFloatPosition(floatingContext, line, floatBox);
288             inlineFormattingState.floatingState().append(floatBox);
289
290             auto floatBoxWidth = layoutState.displayBoxForLayoutBox(floatBox).width();
291             // Shrink availble space for current line and move existing inline runs.
292             floatBox.isLeftFloatingPositioned() ? line.adjustLogicalLeft(floatBoxWidth) : line.adjustLogicalRight(floatBoxWidth);
293
294             generatesInlineRun = false;
295         }
296
297         // 1. Initialize new line if needed.
298         // 2. Append inline run unless it is skipped.
299         // 3. Close current line if needed.
300         if (isFirstRun) {
301             // When the first run does not generate an actual inline run, the next run comes in first-run as well.
302             // No need to spend time on closing/initializing.
303             // Skip leading whitespace.
304             if (!generatesInlineRun || isTrimmableContent(*run))
305                 continue;
306
307             if (line.hasContent()) {
308                 // Previous run ended up being at the line end. Adjust the line accordingly.
309                 if (!line.isClosed())
310                     closeLine(line, IsLastLine::No);
311                 initializeNewLine(line);
312             }
313          }
314
315         if (generatesInlineRun) {
316             auto width = run->width;
317             auto height = run->content.isText() ? LayoutUnit(root().style().computedLineHeight()) : layoutState.displayBoxForLayoutBox(run->content.inlineItem().layoutBox()).height(); 
318             appendContentToLine(line, run->content, { width, height });
319         }
320
321         if (isLastRun)
322             closeLine(line, IsLastLine::No);
323     }
324
325     closeLine(line, IsLastLine::Yes);
326 }
327
328 void InlineFormattingContext::computeWidthAndMargin(const Box& layoutBox) const
329 {
330     auto& layoutState = this->layoutState();
331
332     WidthAndMargin widthAndMargin;
333     if (layoutBox.isFloatingPositioned())
334         widthAndMargin = Geometry::floatingWidthAndMargin(layoutState, layoutBox);
335     else if (layoutBox.isInlineBlockBox())
336         widthAndMargin = Geometry::inlineBlockWidthAndMargin(layoutState, layoutBox);
337     else if (layoutBox.replaced())
338         widthAndMargin = Geometry::inlineReplacedWidthAndMargin(layoutState, layoutBox);
339     else
340         ASSERT_NOT_REACHED();
341
342     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
343     displayBox.setContentBoxWidth(widthAndMargin.width);
344     displayBox.setHorizontalMargin(widthAndMargin.margin);
345     displayBox.setHorizontalNonComputedMargin(widthAndMargin.nonComputedMargin);
346 }
347
348 void InlineFormattingContext::computeHeightAndMargin(const Box& layoutBox) const
349 {
350     auto& layoutState = this->layoutState();
351
352     HeightAndMargin heightAndMargin;
353     if (layoutBox.isFloatingPositioned())
354         heightAndMargin = Geometry::floatingHeightAndMargin(layoutState, layoutBox);
355     else if (layoutBox.isInlineBlockBox())
356         heightAndMargin = Geometry::inlineBlockHeightAndMargin(layoutState, layoutBox);
357     else if (layoutBox.replaced())
358         heightAndMargin = Geometry::inlineReplacedHeightAndMargin(layoutState, layoutBox);
359     else
360         ASSERT_NOT_REACHED();
361
362     auto& displayBox = layoutState.displayBoxForLayoutBox(layoutBox);
363     displayBox.setContentBoxHeight(heightAndMargin.height);
364     displayBox.setVerticalNonCollapsedMargin(heightAndMargin.margin);
365     displayBox.setVerticalMargin(heightAndMargin.collapsedMargin.value_or(heightAndMargin.margin));
366 }
367
368 void InlineFormattingContext::layoutFormattingContextRoot(const Box& root) const
369 {
370     ASSERT(root.isFloatingPositioned() || root.isInlineBlockBox());
371
372     computeBorderAndPadding(root);
373     computeWidthAndMargin(root);
374     // Swich over to the new formatting context (the one that the root creates).
375     auto formattingContext = layoutState().createFormattingStateForFormattingRootIfNeeded(root).formattingContext(root);
376     formattingContext->layout();
377     // Come back and finalize the root's height and margin.
378     computeHeightAndMargin(root);
379     // Now that we computed the root's height, we can go back and layout the out-of-flow descedants (if any).
380     formattingContext->layoutOutOfFlowDescendants(root);
381 }
382
383 void InlineFormattingContext::computeWidthAndHeightForReplacedInlineBox(const Box& layoutBox) const
384 {
385     ASSERT(!layoutBox.isContainer());
386     ASSERT(!layoutBox.establishesFormattingContext());
387     ASSERT(layoutBox.replaced());
388
389     computeBorderAndPadding(layoutBox);
390     computeWidthAndMargin(layoutBox);
391     computeHeightAndMargin(layoutBox);
392 }
393
394 void InlineFormattingContext::computeFloatPosition(const FloatingContext& floatingContext, Line& line, const Box& floatBox) const
395 {
396     auto& layoutState = this->layoutState();
397     ASSERT(layoutState.hasDisplayBox(floatBox));
398     auto& displayBox = layoutState.displayBoxForLayoutBox(floatBox);
399
400     // Set static position first.
401     displayBox.setTopLeft({ line.contentLogicalRight(), line.logicalTop() });
402     // Float it.
403     displayBox.setTopLeft(floatingContext.positionForFloat(floatBox));
404 }
405
406 void InlineFormattingContext::placeInFlowPositionedChildren(unsigned fistRunIndex) const
407 {
408     auto& inlineRuns = inlineFormattingState().inlineRuns();
409     for (auto runIndex = fistRunIndex; runIndex < inlineRuns.size(); ++runIndex) {
410         auto& inlineRun = inlineRuns[runIndex];
411
412         auto positionOffset = [&](auto& layoutBox) {
413             // FIXME: Need to figure out whether in-flow offset should stick. This might very well be temporary.
414             std::optional<LayoutSize> offset;
415             for (auto* box = &layoutBox; box != &root(); box = box->parent()) {
416                 if (!box->isInFlowPositioned())
417                     continue;
418                 offset = offset.value_or(LayoutSize()) + Geometry::inFlowPositionedPositionOffset(layoutState(), *box);
419             }
420             return offset;
421         };
422
423         if (auto offset = positionOffset(inlineRun.inlineItem().layoutBox())) {
424             inlineRun.moveVertically(offset->height());
425             inlineRun.moveHorizontally(offset->width());
426         }
427     }
428 }
429
430 void InlineFormattingContext::collectInlineContentForSubtree(const Box& root, InlineRunProvider& inlineRunProvider) const
431 {
432     // Collect inline content recursively and set breaking rules for the inline elements (for paddings, margins, positioned element etc).
433     auto& inlineFormattingState = this->inlineFormattingState();
434
435     auto createAndAppendInlineItem = [&] {
436         auto inlineItem = std::make_unique<InlineItem>(root);
437         inlineRunProvider.append(*inlineItem);
438         inlineFormattingState.inlineContent().add(WTFMove(inlineItem));
439     };
440
441     if (root.establishesFormattingContext() && &root != &(this->root())) {
442         createAndAppendInlineItem();
443         auto& inlineRun = *inlineFormattingState.inlineContent().last();
444
445         auto horizontalMargins = Geometry::computedNonCollapsedHorizontalMarginValue(layoutState(), root);
446         inlineRun.addDetachingRule({ InlineItem::DetachingRule::BreakAtStart, InlineItem::DetachingRule::BreakAtEnd });
447         inlineRun.addNonBreakableStart(horizontalMargins.left);
448         inlineRun.addNonBreakableEnd(horizontalMargins.right);
449         // Skip formatting root subtree. They are not part of this inline formatting context.
450         return;
451     }
452
453     if (!is<Container>(root)) {
454         createAndAppendInlineItem();
455         return;
456     }
457
458     auto* lastInlineBoxBeforeContainer = inlineFormattingState.lastInlineItem();
459     auto* child = downcast<Container>(root).firstInFlowOrFloatingChild();
460     while (child) {
461         collectInlineContentForSubtree(*child, inlineRunProvider);
462         child = child->nextInFlowOrFloatingSibling();
463     }
464
465     // FIXME: Revisit this when we figured out how inline boxes fit the display tree.
466     auto padding = Geometry::computedPadding(layoutState(), root);
467     auto border = Geometry::computedBorder(layoutState(), root);
468     auto horizontalMargins = Geometry::computedNonCollapsedHorizontalMarginValue(layoutState(), root);
469     // Setup breaking boundaries for this subtree.
470     auto* lastDescendantInlineBox = inlineFormattingState.lastInlineItem();
471     // Empty container?
472     if (lastInlineBoxBeforeContainer == lastDescendantInlineBox)
473         return;
474
475     auto rootBreaksAtStart = [&] {
476         if (&root == &(this->root()))
477             return false;
478         return (padding && padding->horizontal.left) || border.horizontal.left || horizontalMargins.left || root.isPositioned();
479     };
480
481     auto rootBreaksAtEnd = [&] {
482         if (&root == &(this->root()))
483             return false;
484         return (padding && padding->horizontal.right) || border.horizontal.right || horizontalMargins.right || root.isPositioned();
485     };
486
487     if (rootBreaksAtStart()) {
488         InlineItem* firstDescendantInlineBox = nullptr;
489         auto& inlineContent = inlineFormattingState.inlineContent();
490
491         if (lastInlineBoxBeforeContainer) {
492             auto iterator = inlineContent.find(lastInlineBoxBeforeContainer);
493             firstDescendantInlineBox = (*++iterator).get();
494         } else
495             firstDescendantInlineBox = inlineContent.first().get();
496
497         ASSERT(firstDescendantInlineBox);
498         firstDescendantInlineBox->addDetachingRule(InlineItem::DetachingRule::BreakAtStart);
499         auto startOffset = border.horizontal.left + horizontalMargins.left;
500         if (padding)
501             startOffset += padding->horizontal.left;
502         firstDescendantInlineBox->addNonBreakableStart(startOffset);
503     }
504
505     if (rootBreaksAtEnd()) {
506         lastDescendantInlineBox->addDetachingRule(InlineItem::DetachingRule::BreakAtEnd);
507         auto endOffset = border.horizontal.right + horizontalMargins.right;
508         if (padding)
509             endOffset += padding->horizontal.right;
510         lastDescendantInlineBox->addNonBreakableEnd(endOffset);
511     }
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