summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/RenderBlockLineLayout.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/WebCore/rendering/RenderBlockLineLayout.cpp
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/WebCore/rendering/RenderBlockLineLayout.cpp')
-rw-r--r--Source/WebCore/rendering/RenderBlockLineLayout.cpp1221
1 files changed, 585 insertions, 636 deletions
diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
index 451de09c9..3e546abec 100644
--- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp
+++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp
@@ -26,22 +26,18 @@
#include "AXObjectCache.h"
#include "BidiResolver.h"
-#include "BreakingContext.h"
+#include "BreakingContextInlineHeaders.h"
#include "FloatingObjects.h"
#include "InlineElementBox.h"
#include "InlineIterator.h"
#include "InlineTextBox.h"
-#include "InlineTextBoxStyle.h"
#include "LineLayoutState.h"
#include "Logging.h"
#include "RenderBlockFlow.h"
#include "RenderFlowThread.h"
#include "RenderLineBreak.h"
#include "RenderRegion.h"
-#include "RenderRubyBase.h"
-#include "RenderRubyText.h"
#include "RenderView.h"
-#include "SVGRootInlineBox.h"
#include "Settings.h"
#include "SimpleLineLayoutFunctions.h"
#include "TrailingFloatsRootInlineBox.h"
@@ -49,6 +45,10 @@
#include <wtf/RefCountedLeakCounter.h>
#include <wtf/StdLibExtras.h>
+#if ENABLE(SVG)
+#include "SVGRootInlineBox.h"
+#endif
+
namespace WebCore {
static void determineDirectionality(TextDirection& dir, InlineIterator iter)
@@ -71,12 +71,13 @@ static void determineDirectionality(TextDirection& dir, InlineIterator iter)
}
}
-inline BidiRun* createRun(int start, int end, RenderObject& obj, InlineBidiResolver& resolver)
+inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
{
- return new BidiRun(start, end, obj, resolver.context(), resolver.dir());
+ ASSERT(obj);
+ return new BidiRun(start, end, *obj, resolver.context(), resolver.dir());
}
-void RenderBlockFlow::appendRunsForObject(BidiRunList<BidiRun>* runs, int start, int end, RenderObject& obj, InlineBidiResolver& resolver)
+void RenderBlockFlow::appendRunsForObject(BidiRunList<BidiRun>& runs, int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
{
if (start > end || shouldSkipCreatingRunsForObject(obj))
return;
@@ -87,34 +88,33 @@ void RenderBlockFlow::appendRunsForObject(BidiRunList<BidiRun>* runs, int start,
if (haveNextMidpoint)
nextMidpoint = lineMidpointState.midpoints()[lineMidpointState.currentMidpoint()];
if (lineMidpointState.betweenMidpoints()) {
- if (!haveNextMidpoint || (&obj != nextMidpoint.renderer()))
+ if (!(haveNextMidpoint && nextMidpoint.renderer() == obj))
return;
// This is a new start point. Stop ignoring objects and
// adjust our start.
+ lineMidpointState.setBetweenMidpoints(false);
start = nextMidpoint.offset();
lineMidpointState.incrementCurrentMidpoint();
- if (start < end) {
- appendRunsForObject(runs, start, end, obj, resolver);
- return;
- }
+ if (start < end)
+ return appendRunsForObject(runs, start, end, obj, resolver);
} else {
- if (!haveNextMidpoint || (&obj != nextMidpoint.renderer())) {
- if (runs)
- runs->addRun(createRun(start, end, obj, resolver));
+ if (!haveNextMidpoint || (obj != nextMidpoint.renderer())) {
+ runs.addRun(createRun(start, end, obj, resolver));
return;
}
- // An end midpoint has been encountered within our object. We need to append a run with our endpoint.
+ // An end midpoint has been encountered within our object. We
+ // need to go ahead and append a run with our endpoint.
if (static_cast<int>(nextMidpoint.offset() + 1) <= end) {
+ lineMidpointState.setBetweenMidpoints(true);
lineMidpointState.incrementCurrentMidpoint();
- // The end of the line is before the object we're inspecting. Skip everything and return
- if (nextMidpoint.refersToEndOfPreviousNode())
- return;
- if (static_cast<int>(nextMidpoint.offset() + 1) > start && runs)
- runs->addRun(createRun(start, nextMidpoint.offset() + 1, obj, resolver));
- appendRunsForObject(runs, nextMidpoint.offset() + 1, end, obj, resolver);
- } else if (runs)
- runs->addRun(createRun(start, end, obj, resolver));
+ if (nextMidpoint.offset() != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
+ if (static_cast<int>(nextMidpoint.offset() + 1) > start)
+ runs.addRun(createRun(start, nextMidpoint.offset() + 1, obj, resolver));
+ return appendRunsForObject(runs, nextMidpoint.offset() + 1, end, obj, resolver);
+ }
+ } else
+ runs.addRun(createRun(start, end, obj, resolver));
}
}
@@ -127,7 +127,7 @@ RootInlineBox* RenderBlockFlow::createAndAppendRootInlineBox()
{
auto newRootBox = createRootInlineBox();
RootInlineBox* rootBox = newRootBox.get();
- m_lineBoxes.appendLineBox(WTFMove(newRootBox));
+ m_lineBoxes.appendLineBox(std::move(newRootBox));
if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && firstRootBox() == rootBox) {
if (AXObjectCache* cache = document().existingAXObjectCache())
@@ -137,41 +137,41 @@ RootInlineBox* RenderBlockFlow::createAndAppendRootInlineBox()
return rootBox;
}
-static inline InlineBox* createInlineBoxForRenderer(RenderObject* renderer, bool isRootLineBox, bool isOnlyRun = false)
+static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
{
if (isRootLineBox)
- return downcast<RenderBlockFlow>(*renderer).createAndAppendRootInlineBox();
+ return toRenderBlockFlow(obj)->createAndAppendRootInlineBox();
- if (is<RenderText>(*renderer))
- return downcast<RenderText>(*renderer).createInlineTextBox();
+ if (obj->isText())
+ return toRenderText(obj)->createInlineTextBox();
- if (is<RenderBox>(*renderer)) {
+ if (obj->isBox()) {
// FIXME: This is terrible. This branch returns an *owned* pointer!
- return downcast<RenderBox>(*renderer).createInlineBox().release();
+ return toRenderBox(obj)->createInlineBox().release();
}
- if (is<RenderLineBreak>(*renderer)) {
+ if (obj->isLineBreak()) {
// FIXME: This is terrible. This branch returns an *owned* pointer!
- auto inlineBox = downcast<RenderLineBreak>(*renderer).createInlineBox().release();
+ auto inlineBox = toRenderLineBreak(obj)->createInlineBox().release();
// We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
// (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
- inlineBox->setBehavesLikeText(isOnlyRun || renderer->document().inNoQuirksMode() || renderer->isLineBreakOpportunity());
+ inlineBox->setBehavesLikeText(isOnlyRun || obj->document().inNoQuirksMode() || obj->isLineBreakOpportunity());
return inlineBox;
}
- return downcast<RenderInline>(*renderer).createAndAppendInlineFlowBox();
+ return toRenderInline(obj)->createAndAppendInlineFlowBox();
}
static inline void dirtyLineBoxesForRenderer(RenderObject& renderer, bool fullLayout)
{
- if (is<RenderText>(renderer)) {
- RenderText& renderText = downcast<RenderText>(renderer);
+ if (renderer.isText()) {
+ RenderText& renderText = toRenderText(renderer);
updateCounterIfNeeded(renderText);
renderText.dirtyLineBoxes(fullLayout);
- } else if (is<RenderLineBreak>(renderer))
- downcast<RenderLineBreak>(renderer).dirtyLineBoxes(fullLayout);
+ } else if (renderer.isLineBreak())
+ toRenderLineBreak(renderer).dirtyLineBoxes(fullLayout);
else
- downcast<RenderInline>(renderer).dirtyLineBoxes(fullLayout);
+ toRenderInline(renderer).dirtyLineBoxes(fullLayout);
}
static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
@@ -184,21 +184,21 @@ static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
return false;
}
-InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox)
+InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox, bool startNewSegment)
{
// See if we have an unconstructed line box for this object that is also
// the last item on the line.
unsigned lineDepth = 1;
- InlineFlowBox* parentBox = nullptr;
- InlineFlowBox* result = nullptr;
+ InlineFlowBox* parentBox = 0;
+ InlineFlowBox* result = 0;
bool hasDefaultLineBoxContain = style().lineBoxContain() == RenderStyle::initialLineBoxContain();
do {
- ASSERT_WITH_SECURITY_IMPLICATION(is<RenderInline>(*obj) || obj == this);
+ ASSERT_WITH_SECURITY_IMPLICATION(obj->isRenderInline() || obj == this);
- RenderInline* inlineFlow = obj != this ? downcast<RenderInline>(obj) : nullptr;
+ RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
// Get the last box we made for this render object.
- parentBox = inlineFlow ? inlineFlow->lastLineBox() : downcast<RenderBlockFlow>(*obj).lastRootBox();
+ parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlockFlow(obj)->lastRootBox();
// If this box or its ancestor is constructed then it is from a previous line, and we need
// to make a new box for our line. If this box or its ancestor is unconstructed but it has
@@ -207,12 +207,14 @@ InlineFlowBox* RenderBlockFlow::createLineBoxes(RenderObject* obj, const LineInf
// the same line (this can happen with very fancy language mixtures).
bool constructedNewBox = false;
bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
- bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
+ bool mustCreateBoxesToRoot = startNewSegment && !(parentBox && parentBox->isRootInlineBox());
+ bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox) && !mustCreateBoxesToRoot;
if (allowedToConstructNewBox && !canUseExistingParentBox) {
// We need to make a new box for this render object. Once
// made, we need to place it at the end of the current line.
InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
- parentBox = downcast<InlineFlowBox>(newBox);
+ ASSERT_WITH_SECURITY_IMPLICATION(newBox->isInlineFlowBox());
+ parentBox = toInlineFlowBox(newBox);
parentBox->setIsFirstLine(lineInfo.isFirstLine());
parentBox->setIsHorizontal(isHorizontalWritingMode());
if (!hasDefaultLineBoxContain)
@@ -262,10 +264,10 @@ static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns)
if (!run)
return true;
unsigned pos = run->stop();
- const RenderObject& renderer = run->renderer();
- if (!is<RenderText>(renderer))
+ const RenderObject& r = run->renderer();
+ if (!r.isText())
return false;
- const RenderText& renderText = downcast<RenderText>(renderer);
+ const RenderText& renderText = toRenderText(r);
unsigned length = renderText.textLength();
if (pos >= length)
return true;
@@ -282,7 +284,6 @@ RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, co
bool rootHasSelectedChildren = false;
InlineFlowBox* parentBox = 0;
int runCount = bidiRuns.runCount() - lineInfo.runsFromLeadingWhitespace();
-
for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
// Create a box for our object.
bool isOnlyRun = (runCount == 1);
@@ -293,20 +294,24 @@ RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, co
continue;
InlineBox* box = createInlineBoxForRenderer(&r->renderer(), false, isOnlyRun);
- r->setBox(box);
+ r->setBox(*box);
if (!rootHasSelectedChildren && box->renderer().selectionState() != RenderObject::SelectionNone)
rootHasSelectedChildren = true;
-
+
// If we have no parent box yet, or if the run is not simply a sibling,
// then we need to construct inline boxes as necessary to properly enclose the
// run's inline box. Segments can only be siblings at the root level, as
// they are positioned separately.
- if (!parentBox || &parentBox->renderer() != r->renderer().parent()) {
+#if ENABLE(CSS_SHAPES)
+ bool runStartsSegment = r->m_startsSegment;
+#else
+ bool runStartsSegment = false;
+#endif
+ if (!parentBox || &parentBox->renderer() != r->renderer().parent() || runStartsSegment)
// Create new inline boxes all the way back to the appropriate insertion point.
- RenderObject* parentToUse = r->renderer().parent();
- parentBox = createLineBoxes(parentToUse, lineInfo, box);
- } else {
+ parentBox = createLineBoxes(r->renderer().parent(), lineInfo, box, runStartsSegment);
+ else {
// Append the inline box to this line.
parentBox->addToLine(box);
}
@@ -314,13 +319,13 @@ RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, co
bool visuallyOrdered = r->renderer().style().rtlOrdering() == VisualOrder;
box->setBidiLevel(r->level());
- if (is<InlineTextBox>(*box)) {
- auto& textBox = downcast<InlineTextBox>(*box);
- textBox.setStart(r->m_start);
- textBox.setLen(r->m_stop - r->m_start);
- textBox.setDirOverride(r->dirOverride(visuallyOrdered));
+ if (box->isInlineTextBox()) {
+ InlineTextBox* text = toInlineTextBox(box);
+ text->setStart(r->m_start);
+ text->setLen(r->m_stop - r->m_start);
+ text->setDirOverride(r->dirOverride(visuallyOrdered));
if (r->m_hasHyphen)
- textBox.setHasHyphen(true);
+ text->setHasHyphen(true);
}
}
@@ -350,12 +355,6 @@ RootInlineBox* RenderBlockFlow::constructLine(BidiRunList<BidiRun>& bidiRuns, co
ETextAlign RenderBlockFlow::textAlignmentForLine(bool endsWithSoftBreak) const
{
ETextAlign alignment = style().textAlign();
-#if ENABLE(CSS3_TEXT)
- TextJustify textJustify = style().textJustify();
- if (alignment == JUSTIFY && textJustify == TextJustifyNone)
- return style().direction() == LTR ? LEFT : RIGHT;
-#endif
-
if (endsWithSoftBreak)
return alignment;
@@ -380,7 +379,7 @@ ETextAlign RenderBlockFlow::textAlignmentForLine(bool endsWithSoftBreak) const
case TextAlignLastJustify:
return JUSTIFY;
case TextAlignLastAuto:
- if (textJustify == TextJustifyDistribute)
+ if (style().textJustify() == TextJustifyDistribute)
return JUSTIFY;
return TASTART;
}
@@ -414,7 +413,8 @@ static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection,
totalLogicalWidth -= trailingSpaceRun->box()->logicalWidth();
trailingSpaceRun->box()->setLogicalWidth(0);
}
- logicalLeft += std::max(0.f, availableLogicalWidth - totalLogicalWidth);
+ if (totalLogicalWidth < availableLogicalWidth)
+ logicalLeft += availableLogicalWidth - totalLogicalWidth;
return;
}
@@ -441,8 +441,8 @@ static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection,
void RenderBlockFlow::setMarginsForRubyRun(BidiRun* run, RenderRubyRun& renderer, RenderObject* previousObject, const LineInfo& lineInfo)
{
- float startOverhang;
- float endOverhang;
+ int startOverhang;
+ int endOverhang;
RenderObject* nextObject = 0;
for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) {
if (!runWithNextObject->renderer().isOutOfFlowPositioned() && !runWithNextObject->box()->isLineBreak()) {
@@ -455,13 +455,13 @@ void RenderBlockFlow::setMarginsForRubyRun(BidiRun* run, RenderRubyRun& renderer
setMarginEndForChild(renderer, -endOverhang);
}
-static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText& renderer, float xPos, const LineInfo& lineInfo,
+static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMeasurements& wordMeasurements)
{
- HashSet<const Font*> fallbackFonts;
+ HashSet<const SimpleFontData*> fallbackFonts;
GlyphOverflow glyphOverflow;
- const FontCascade& font = lineStyle(*renderer.parent(), lineInfo).fontCascade();
+ const Font& font = lineStyle(*renderer->parent(), lineInfo).font();
// Always compute glyph overflow if the block's line-box-contain value is "glyphs".
if (lineBox->fitsToGlyphs()) {
// If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
@@ -477,13 +477,13 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru
}
LayoutUnit hyphenWidth = 0;
- if (downcast<InlineTextBox>(*run->box()).hasHyphen())
+ if (toInlineTextBox(run->box())->hasHyphen())
hyphenWidth = measureHyphenWidth(renderer, font, &fallbackFonts);
float measuredWidth = 0;
- bool kerningIsEnabled = font.enableKerning();
- bool canUseSimpleFontCodePath = renderer.canUseSimpleFontCodePath();
+ bool kerningIsEnabled = font.typesettingFeatures() & Kerning;
+ bool canUseSimpleFontCodePath = renderer->canUseSimpleFontCodePath();
// Since we don't cache glyph overflows, we need to re-measure the run if
// the style is linebox-contain: glyph.
@@ -494,23 +494,23 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru
WordMeasurement& wordMeasurement = wordMeasurements[i];
if (wordMeasurement.width <= 0 || wordMeasurement.startOffset == wordMeasurement.endOffset)
continue;
- if (wordMeasurement.renderer != &renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
+ if (wordMeasurement.renderer != renderer || wordMeasurement.startOffset != lastEndOffset || wordMeasurement.endOffset > run->m_stop)
continue;
lastEndOffset = wordMeasurement.endOffset;
if (kerningIsEnabled && lastEndOffset == run->m_stop) {
int wordLength = lastEndOffset - wordMeasurement.startOffset;
GlyphOverflow overflow;
- measuredWidth += renderer.width(wordMeasurement.startOffset, wordLength, xPos + measuredWidth, lineInfo.isFirstLine(),
+ measuredWidth += renderer->width(wordMeasurement.startOffset, wordLength, xPos + measuredWidth, lineInfo.isFirstLine(),
&wordMeasurement.fallbackFonts, &overflow);
- UChar c = renderer.characterAt(wordMeasurement.startOffset);
+ UChar c = renderer->characterAt(wordMeasurement.startOffset);
if (i > 0 && wordLength == 1 && (c == ' ' || c == '\t'))
- measuredWidth += renderer.style().fontCascade().wordSpacing();
+ measuredWidth += renderer->style().font().wordSpacing();
} else
measuredWidth += wordMeasurement.width;
if (!wordMeasurement.fallbackFonts.isEmpty()) {
- HashSet<const Font*>::const_iterator end = wordMeasurement.fallbackFonts.end();
- for (HashSet<const Font*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it)
+ HashSet<const SimpleFontData*>::const_iterator end = wordMeasurement.fallbackFonts.end();
+ for (HashSet<const SimpleFontData*>::const_iterator it = wordMeasurement.fallbackFonts.begin(); it != end; ++it)
fallbackFonts.add(*it);
}
}
@@ -522,114 +522,60 @@ static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* ru
}
if (!measuredWidth)
- measuredWidth = renderer.width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
+ measuredWidth = renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow);
run->box()->setLogicalWidth(measuredWidth + hyphenWidth);
if (!fallbackFonts.isEmpty()) {
ASSERT(run->box()->behavesLikeText());
- GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(downcast<InlineTextBox>(run->box()), std::make_pair(Vector<const Font*>(), GlyphOverflow())).iterator;
+ GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->box()), std::make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator;
ASSERT(it->value.first.isEmpty());
copyToVector(fallbackFonts, it->value.first);
run->box()->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
}
-
- // Include text decoration visual overflow as part of the glyph overflow.
- if (renderer.style().textDecorationsInEffect() != TextDecorationNone)
- glyphOverflow.extendTo(visualOverflowForDecorations(run->box()->lineStyle(), downcast<InlineTextBox>(run->box())));
-
- if (!glyphOverflow.isEmpty()) {
+ if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) {
ASSERT(run->box()->behavesLikeText());
- GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(downcast<InlineTextBox>(run->box()), std::make_pair(Vector<const Font*>(), GlyphOverflow())).iterator;
+ GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(toInlineTextBox(run->box()), std::make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).iterator;
it->value.second = glyphOverflow;
run->box()->clearKnownToHaveNoOverflow();
}
}
-void RenderBlockFlow::updateRubyForJustifiedText(RenderRubyRun& rubyRun, BidiRun& r, const Vector<unsigned, 16>& expansionOpportunities, unsigned& expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth, size_t& i)
-{
- if (!rubyRun.rubyBase() || !rubyRun.rubyBase()->firstRootBox() || rubyRun.rubyBase()->firstRootBox()->nextRootBox() || !r.renderer().style().collapseWhiteSpace())
- return;
-
- auto& rubyBase = *rubyRun.rubyBase();
- auto& rootBox = *rubyBase.firstRootBox();
-
- float totalExpansion = 0;
- unsigned totalOpportunitiesInRun = 0;
- for (auto* leafChild = rootBox.firstLeafChild(); leafChild; leafChild = leafChild->nextLeafChild()) {
- if (!leafChild->isInlineTextBox())
- continue;
-
- unsigned opportunitiesInRun = expansionOpportunities[i++];
- ASSERT(opportunitiesInRun <= expansionOpportunityCount);
- auto expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
- totalExpansion += expansion;
- totalOpportunitiesInRun += opportunitiesInRun;
- }
-
- ASSERT(!rubyRun.hasOverrideLogicalContentWidth());
- float newBaseWidth = rubyRun.logicalWidth() + totalExpansion + marginStartForChild(rubyRun) + marginEndForChild(rubyRun);
- float newRubyRunWidth = rubyRun.logicalWidth() + totalExpansion;
- rubyBase.setInitialOffset((newRubyRunWidth - newBaseWidth) / 2);
- rubyRun.setOverrideLogicalContentWidth(newRubyRunWidth);
- rubyRun.setNeedsLayout(MarkOnlyThis);
- rootBox.markDirty();
- if (RenderRubyText* rubyText = rubyRun.rubyText()) {
- if (RootInlineBox* textRootBox = rubyText->firstRootBox())
- textRootBox->markDirty();
- }
- rubyRun.layoutBlock(true);
- rubyRun.clearOverrideLogicalContentWidth();
- r.box()->setExpansion(newRubyRunWidth - r.box()->logicalWidth());
-
- // This relayout caused the size of the RenderRubyText and the RenderRubyBase to change, dependent on the line's current expansion. Next time we relayout the
- // RenderRubyRun, make sure that we relayout the RenderRubyBase and RenderRubyText as well.
- rubyBase.setNeedsLayout(MarkOnlyThis);
- if (RenderRubyText* rubyText = rubyRun.rubyText())
- rubyText->setNeedsLayout(MarkOnlyThis);
-
- totalLogicalWidth += totalExpansion;
- expansionOpportunityCount -= totalOpportunitiesInRun;
-}
-
-void RenderBlockFlow::computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, const Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float totalLogicalWidth, float availableLogicalWidth)
+static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth)
{
if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth)
return;
size_t i = 0;
- for (BidiRun* run = firstRun; run; run = run->next()) {
- if (!run->box() || run == trailingSpaceRun)
+ for (BidiRun* r = firstRun; r; r = r->next()) {
+#if ENABLE(CSS_SHAPES)
+ // This method is called once per segment, do not move past the current segment.
+ if (r->m_startsSegment)
+ break;
+#endif
+ if (!r->box() || r == trailingSpaceRun)
continue;
- if (is<RenderText>(run->renderer())) {
+ if (r->renderer().isText()) {
unsigned opportunitiesInRun = expansionOpportunities[i++];
ASSERT(opportunitiesInRun <= expansionOpportunityCount);
// Only justify text if whitespace is collapsed.
- if (run->renderer().style().collapseWhiteSpace()) {
- InlineTextBox& textBox = downcast<InlineTextBox>(*run->box());
- float expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
- textBox.setExpansion(expansion);
+ if (r->renderer().style().collapseWhiteSpace()) {
+ InlineTextBox* textBox = toInlineTextBox(r->box());
+ int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
+ textBox->setExpansion(expansion);
totalLogicalWidth += expansion;
}
expansionOpportunityCount -= opportunitiesInRun;
- } else if (is<RenderRubyRun>(run->renderer()))
- updateRubyForJustifiedText(downcast<RenderRubyRun>(run->renderer()), *run, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth, i);
-
- if (!expansionOpportunityCount)
- break;
+ if (!expansionOpportunityCount)
+ break;
+ }
}
}
-void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, const RootInlineBox* rootInlineBox, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, int expansionOpportunityCount)
+void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float& availableLogicalWidth, int expansionOpportunityCount)
{
- TextDirection direction;
- if (rootInlineBox && style().unicodeBidi() == Plaintext)
- direction = rootInlineBox->direction();
- else
- direction = style().direction();
-
// Armed with the total width of the line (without justification),
// we now examine our text-align property in order to determine where to position the
// objects horizontally. The total width of the line can be increased if we end up
@@ -658,13 +604,13 @@ void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign
}
FALLTHROUGH;
case TASTART:
- if (direction == LTR)
+ if (style().isLeftToRightDirection())
updateLogicalWidthForLeftAlignedBlock(style().isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
else
updateLogicalWidthForRightAlignedBlock(style().isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
break;
case TAEND:
- if (direction == LTR)
+ if (style().isLeftToRightDirection())
updateLogicalWidthForRightAlignedBlock(style().isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
else
updateLogicalWidthForLeftAlignedBlock(style().isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
@@ -672,17 +618,11 @@ void RenderBlockFlow::updateLogicalWidthForAlignment(const ETextAlign& textAlign
}
}
-static void updateLogicalInlinePositions(RenderBlockFlow& block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine,
- IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight, RootInlineBox* rootBox)
+static void updateLogicalInlinePositions(RenderBlockFlow& block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
{
LayoutUnit lineLogicalHeight = block.minLineHeightForReplacedRenderer(firstLine, boxLogicalHeight);
- if (rootBox->hasAnonymousInlineBlock()) {
- lineLogicalLeft = block.logicalLeftOffsetForContent(block.logicalHeight());
- lineLogicalRight = block.logicalRightOffsetForContent(block.logicalHeight());
- } else {
- lineLogicalLeft = block.logicalLeftOffsetForLine(block.logicalHeight(), shouldIndentText, lineLogicalHeight);
- lineLogicalRight = block.logicalRightOffsetForLine(block.logicalHeight(), shouldIndentText, lineLogicalHeight);
- }
+ lineLogicalLeft = block.pixelSnappedLogicalLeftOffsetForLine(block.logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
+ lineLogicalRight = block.pixelSnappedLogicalRightOffsetForLine(block.logicalHeight(), shouldIndentText == IndentText, lineLogicalHeight);
availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
}
@@ -700,110 +640,50 @@ void RenderBlockFlow::computeInlineDirectionPositionsForLine(RootInlineBox* line
float lineLogicalLeft;
float lineLogicalRight;
float availableLogicalWidth;
- updateLogicalInlinePositions(*this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0, lineBox);
+ updateLogicalInlinePositions(*this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, 0);
bool needsWordSpacing;
+#if ENABLE(CSS_SHAPES)
+ ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
+ if (shapeInsideInfo && shapeInsideInfo->hasSegments()) {
+ BidiRun* segmentStart = firstRun;
+ const SegmentList& segments = shapeInsideInfo->segments();
+ float logicalLeft = std::max<float>(roundToInt(segments[0].logicalLeft), lineLogicalLeft);
+ float logicalRight = std::min<float>(floorToInt(segments[0].logicalRight), lineLogicalRight);
+ float startLogicalLeft = logicalLeft;
+ float endLogicalRight = logicalLeft;
+ float minLogicalLeft = logicalLeft;
+ float maxLogicalRight = logicalLeft;
+ lineBox->beginPlacingBoxRangesInInlineDirection(logicalLeft);
+ for (size_t i = 0; i < segments.size(); i++) {
+ if (i) {
+ logicalLeft = std::max<float>(roundToInt(segments[i].logicalLeft), lineLogicalLeft);
+ logicalRight = std::min<float>(floorToInt(segments[i].logicalRight), lineLogicalRight);
+ }
+ availableLogicalWidth = logicalRight - logicalLeft;
+ BidiRun* newSegmentStart = computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, logicalLeft, availableLogicalWidth, segmentStart, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
+ needsWordSpacing = false;
+ endLogicalRight = lineBox->placeBoxRangeInInlineDirection(segmentStart->box(), newSegmentStart ? newSegmentStart->box() : 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap);
+ if (!newSegmentStart || !newSegmentStart->next())
+ break;
+ ASSERT(newSegmentStart->m_startsSegment);
+ // Discard the empty segment start marker bidi runs
+ segmentStart = newSegmentStart->next();
+ }
+ lineBox->endPlacingBoxRangesInInlineDirection(startLogicalLeft, endLogicalRight, minLogicalLeft, maxLogicalRight);
+ return;
+ }
+#endif
if (firstRun && firstRun->renderer().isReplaced()) {
- RenderBox& renderBox = downcast<RenderBox>(firstRun->renderer());
- updateLogicalInlinePositions(*this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox.logicalHeight(), lineBox);
+ RenderBox& renderBox = toRenderBox(firstRun->renderer());
+ updateLogicalInlinePositions(*this, lineLogicalLeft, lineLogicalRight, availableLogicalWidth, isFirstLine, shouldIndentText, renderBox.logicalHeight());
}
computeInlineDirectionPositionsForSegment(lineBox, lineInfo, textAlign, lineLogicalLeft, availableLogicalWidth, firstRun, trailingSpaceRun, textBoxDataMap, verticalPositionCache, wordMeasurements);
// The widths of all runs are now known. We can now place every inline box (and
// compute accurate widths for the inline flow boxes).
needsWordSpacing = false;
- lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing);
-}
-
-static inline ExpansionBehavior expansionBehaviorForInlineTextBox(RenderBlockFlow& block, InlineTextBox& textBox, BidiRun* previousRun, BidiRun* nextRun, ETextAlign textAlign, bool isAfterExpansion)
-{
- // Tatechuyoko is modeled as the Object Replacement Character (U+FFFC), which can never have expansion opportunities inside nor intrinsically adjacent to it.
- if (textBox.renderer().style().textCombine() == TextCombineHorizontal)
- return ForbidLeadingExpansion | ForbidTrailingExpansion;
-
- ExpansionBehavior result = 0;
- bool setLeadingExpansion = false;
- bool setTrailingExpansion = false;
- if (textAlign == JUSTIFY) {
- // If the next box is ruby, and we're justifying, and the first box in the ruby base has a leading expansion, and we are a text box, then force a trailing expansion.
- if (nextRun && is<RenderRubyRun>(nextRun->renderer()) && downcast<RenderRubyRun>(nextRun->renderer()).rubyBase() && nextRun->renderer().style().collapseWhiteSpace()) {
- auto& rubyBase = *downcast<RenderRubyRun>(nextRun->renderer()).rubyBase();
- if (rubyBase.firstRootBox() && !rubyBase.firstRootBox()->nextRootBox()) {
- if (auto* leafChild = rubyBase.firstRootBox()->firstLeafChild()) {
- if (is<InlineTextBox>(*leafChild)) {
- // FIXME: This leadingExpansionOpportunity doesn't actually work because it doesn't perform the UBA
- if (FontCascade::leadingExpansionOpportunity(downcast<RenderText>(leafChild->renderer()).stringView(), leafChild->direction())) {
- setTrailingExpansion = true;
- result |= ForceTrailingExpansion;
- }
- }
- }
- }
- }
- // Same thing, except if we're following a ruby
- if (previousRun && is<RenderRubyRun>(previousRun->renderer()) && downcast<RenderRubyRun>(previousRun->renderer()).rubyBase() && previousRun->renderer().style().collapseWhiteSpace()) {
- auto& rubyBase = *downcast<RenderRubyRun>(previousRun->renderer()).rubyBase();
- if (rubyBase.firstRootBox() && !rubyBase.firstRootBox()->nextRootBox()) {
- if (auto* leafChild = rubyBase.firstRootBox()->lastLeafChild()) {
- if (is<InlineTextBox>(*leafChild)) {
- // FIXME: This leadingExpansionOpportunity doesn't actually work because it doesn't perform the UBA
- if (FontCascade::trailingExpansionOpportunity(downcast<RenderText>(leafChild->renderer()).stringView(), leafChild->direction())) {
- setLeadingExpansion = true;
- result |= ForceLeadingExpansion;
- }
- }
- }
- }
- }
- // If we're the first box inside a ruby base, forbid a leading expansion, and vice-versa
- if (is<RenderRubyBase>(block)) {
- RenderRubyBase& rubyBase = downcast<RenderRubyBase>(block);
- if (&textBox == rubyBase.firstRootBox()->firstLeafChild()) {
- setLeadingExpansion = true;
- result |= ForbidLeadingExpansion;
- } if (&textBox == rubyBase.firstRootBox()->lastLeafChild()) {
- setTrailingExpansion = true;
- result |= ForbidTrailingExpansion;
- }
- }
- }
- if (!setLeadingExpansion)
- result |= isAfterExpansion ? ForbidLeadingExpansion : AllowLeadingExpansion;
- if (!setTrailingExpansion)
- result |= AllowTrailingExpansion;
- return result;
-}
-
-static inline void applyExpansionBehavior(InlineTextBox& textBox, ExpansionBehavior expansionBehavior)
-{
- switch (expansionBehavior & LeadingExpansionMask) {
- case ForceLeadingExpansion:
- textBox.setForceLeadingExpansion();
- break;
- case ForbidLeadingExpansion:
- textBox.setCanHaveLeadingExpansion(false);
- break;
- case AllowLeadingExpansion:
- textBox.setCanHaveLeadingExpansion(true);
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
- switch (expansionBehavior & TrailingExpansionMask) {
- case ForceTrailingExpansion:
- textBox.setForceTrailingExpansion();
- break;
- case ForbidTrailingExpansion:
- textBox.setCanHaveTrailingExpansion(false);
- break;
- case AllowTrailingExpansion:
- textBox.setCanHaveTrailingExpansion(true);
- break;
- default:
- ASSERT_NOT_REACHED();
- break;
- }
+ lineBox->placeBoxesInInlineDirection(lineLogicalLeft, needsWordSpacing, textBoxDataMap);
}
BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBox* lineBox, const LineInfo& lineInfo, ETextAlign textAlign, float& logicalLeft,
@@ -813,72 +693,56 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo
bool needsWordSpacing = false;
float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
unsigned expansionOpportunityCount = 0;
- bool isAfterExpansion = is<RenderRubyBase>(*this) ? downcast<RenderRubyBase>(*this).isAfterExpansion() : true;
+ bool isAfterExpansion = true;
Vector<unsigned, 16> expansionOpportunities;
-
- BidiRun* run = firstRun;
- BidiRun* previousRun = nullptr;
- for (; run; run = run->next()) {
- if (!run->box() || run->renderer().isOutOfFlowPositioned() || run->box()->isLineBreak()) {
+ RenderObject* previousObject = 0;
+
+ BidiRun* r = firstRun;
+ for (; r; r = r->next()) {
+#if ENABLE(CSS_SHAPES)
+ // Once we have reached the start of the next segment, we have finished
+ // computing the positions for this segment's contents.
+ if (r->m_startsSegment)
+ break;
+#endif
+ if (!r->box() || r->renderer().isOutOfFlowPositioned() || r->box()->isLineBreak())
continue; // Positioned objects are only participating to figure out their
// correct static x position. They have no effect on the width.
// Similarly, line break boxes have no effect on the width.
- }
- if (is<RenderText>(run->renderer())) {
- auto& renderText = downcast<RenderText>(run->renderer());
- auto& textBox = downcast<InlineTextBox>(*run->box());
- if (textAlign == JUSTIFY && run != trailingSpaceRun) {
- ExpansionBehavior expansionBehavior = expansionBehaviorForInlineTextBox(*this, textBox, previousRun, run->next(), textAlign, isAfterExpansion);
- applyExpansionBehavior(textBox, expansionBehavior);
+ if (r->renderer().isText()) {
+ RenderText& rt = toRenderText(r->renderer());
+ if (textAlign == JUSTIFY && r != trailingSpaceRun) {
+ if (!isAfterExpansion)
+ toInlineTextBox(r->box())->setCanHaveLeadingExpansion(true);
unsigned opportunitiesInRun;
- std::tie(opportunitiesInRun, isAfterExpansion) = FontCascade::expansionOpportunityCount(renderText.stringView(run->m_start, run->m_stop), run->box()->direction(), expansionBehavior);
+ if (rt.is8Bit())
+ opportunitiesInRun = Font::expansionOpportunityCount(rt.characters8() + r->m_start, r->m_stop - r->m_start, r->box()->direction(), isAfterExpansion);
+ else
+ opportunitiesInRun = Font::expansionOpportunityCount(rt.characters16() + r->m_start, r->m_stop - r->m_start, r->box()->direction(), isAfterExpansion);
expansionOpportunities.append(opportunitiesInRun);
expansionOpportunityCount += opportunitiesInRun;
}
- if (int length = renderText.textLength()) {
- if (!run->m_start && needsWordSpacing && isSpaceOrNewline(renderText.characterAt(run->m_start)))
- totalLogicalWidth += lineStyle(*renderText.parent(), lineInfo).fontCascade().wordSpacing();
- needsWordSpacing = !isSpaceOrNewline(renderText.characterAt(run->m_stop - 1)) && run->m_stop == length;
+ if (int length = rt.textLength()) {
+ if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt.characterAt(r->m_start)))
+ totalLogicalWidth += lineStyle(*rt.parent(), lineInfo).font().wordSpacing();
+ needsWordSpacing = !isSpaceOrNewline(rt.characterAt(r->m_stop - 1)) && r->m_stop == length;
}
- setLogicalWidthForTextRun(lineBox, run, renderText, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
+ setLogicalWidthForTextRun(lineBox, r, &rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache, wordMeasurements);
} else {
- bool encounteredJustifiedRuby = false;
- if (is<RenderRubyRun>(run->renderer()) && textAlign == JUSTIFY && run != trailingSpaceRun && downcast<RenderRubyRun>(run->renderer()).rubyBase()) {
- auto* rubyBase = downcast<RenderRubyRun>(run->renderer()).rubyBase();
- if (rubyBase->firstRootBox() && !rubyBase->firstRootBox()->nextRootBox() && run->renderer().style().collapseWhiteSpace()) {
- rubyBase->setIsAfterExpansion(isAfterExpansion);
- for (auto* leafChild = rubyBase->firstRootBox()->firstLeafChild(); leafChild; leafChild = leafChild->nextLeafChild()) {
- if (!is<InlineTextBox>(*leafChild))
- continue;
- auto& textBox = downcast<InlineTextBox>(*leafChild);
- encounteredJustifiedRuby = true;
- auto& renderText = downcast<RenderText>(leafChild->renderer());
- ExpansionBehavior expansionBehavior = expansionBehaviorForInlineTextBox(*rubyBase, textBox, nullptr, nullptr, textAlign, isAfterExpansion);
- applyExpansionBehavior(textBox, expansionBehavior);
- unsigned opportunitiesInRun;
- std::tie(opportunitiesInRun, isAfterExpansion) = FontCascade::expansionOpportunityCount(renderText.stringView(), leafChild->direction(), expansionBehavior);
- expansionOpportunities.append(opportunitiesInRun);
- expansionOpportunityCount += opportunitiesInRun;
- }
- }
- }
-
- if (!encounteredJustifiedRuby)
- isAfterExpansion = false;
-
- if (!is<RenderInline>(run->renderer())) {
- auto& renderBox = downcast<RenderBox>(run->renderer());
- if (is<RenderRubyRun>(renderBox))
- setMarginsForRubyRun(run, downcast<RenderRubyRun>(renderBox), previousRun ? &previousRun->renderer() : nullptr, lineInfo);
- run->box()->setLogicalWidth(logicalWidthForChild(renderBox));
+ isAfterExpansion = false;
+ if (!r->renderer().isRenderInline()) {
+ RenderBox& renderBox = toRenderBox(r->renderer());
+ if (renderBox.isRubyRun())
+ setMarginsForRubyRun(r, toRenderRubyRun(renderBox), previousObject, lineInfo);
+ r->box()->setLogicalWidth(logicalWidthForChild(renderBox));
totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
}
}
- totalLogicalWidth += run->box()->logicalWidth();
- previousRun = run;
+ totalLogicalWidth += r->box()->logicalWidth();
+ previousObject = &r->renderer();
}
if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
@@ -886,43 +750,11 @@ BidiRun* RenderBlockFlow::computeInlineDirectionPositionsForSegment(RootInlineBo
expansionOpportunityCount--;
}
- if (is<RenderRubyBase>(*this) && !expansionOpportunityCount)
- textAlign = CENTER;
-
- updateLogicalWidthForAlignment(textAlign, lineBox, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
+ updateLogicalWidthForAlignment(textAlign, trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth, expansionOpportunityCount);
computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
- return run;
-}
-
-void RenderBlockFlow::removeInlineBox(BidiRun& run, const RootInlineBox& rootLineBox) const
-{
- auto* inlineBox = run.box();
-#if !ASSERT_DISABLED
- auto* inlineParent = inlineBox->parent();
- while (inlineParent && inlineParent != &rootLineBox) {
- ASSERT(!inlineParent->isDirty());
- inlineParent = inlineParent->parent();
- }
- ASSERT(!rootLineBox.isDirty());
-#endif
- auto* parent = inlineBox->parent();
- inlineBox->removeFromParent();
-
- auto& renderer = run.renderer();
- if (is<RenderText>(renderer))
- downcast<RenderText>(renderer).removeTextBox(downcast<InlineTextBox>(*inlineBox));
- delete inlineBox;
- run.setBox(nullptr);
- // removeFromParent() unnecessarily dirties the ancestor subtree.
- auto* ancestor = parent;
- while (ancestor) {
- ancestor->markDirty(false);
- if (ancestor == &rootLineBox)
- break;
- ancestor = ancestor->parent();
- }
+ return r;
}
void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
@@ -931,33 +763,30 @@ void RenderBlockFlow::computeBlockDirectionPositionsForLine(RootInlineBox* lineB
setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
// Now make sure we place replaced render objects correctly.
- for (auto* run = firstRun; run; run = run->next()) {
- ASSERT(run->box());
- if (!run->box())
+ for (BidiRun* r = firstRun; r; r = r->next()) {
+ ASSERT(r->box());
+ if (!r->box())
continue; // Skip runs with no line boxes.
+ InlineBox& box = *r->box();
+
// Align positioned boxes with the top of the line box. This is
// a reasonable approximation of an appropriate y position.
- auto& renderer = run->renderer();
- if (renderer.isOutOfFlowPositioned())
- run->box()->setLogicalTop(logicalHeight());
+ if (r->renderer().isOutOfFlowPositioned())
+ box.setLogicalTop(logicalHeight());
// Position is used to properly position both replaced elements and
// to update the static normal flow x/y of positioned elements.
- bool inlineBoxIsRedundant = false;
- if (is<RenderText>(renderer)) {
- auto& inlineTextBox = downcast<InlineTextBox>(*run->box());
- downcast<RenderText>(renderer).positionLineBox(inlineTextBox);
- inlineBoxIsRedundant = !inlineTextBox.len();
- } else if (is<RenderBox>(renderer)) {
- downcast<RenderBox>(renderer).positionLineBox(downcast<InlineElementBox>(*run->box()));
- inlineBoxIsRedundant = renderer.isOutOfFlowPositioned();
- } else if (is<RenderLineBreak>(renderer))
- downcast<RenderLineBreak>(renderer).replaceInlineBoxWrapper(downcast<InlineElementBox>(*run->box()));
- // Check if we need to keep this box on the line at all.
- if (inlineBoxIsRedundant)
- removeInlineBox(*run, *lineBox);
- }
+ if (r->renderer().isText())
+ toRenderText(r->renderer()).positionLineBox(toInlineTextBox(box));
+ else if (r->renderer().isBox())
+ toRenderBox(r->renderer()).positionLineBox(toInlineElementBox(box));
+ else if (r->renderer().isLineBreak())
+ toRenderLineBreak(r->renderer()).replaceInlineBoxWrapper(toInlineElementBox(box));
+ }
+ // Positioned objects and zero-length text nodes destroy their boxes in
+ // position(), which unnecessarily dirties the line.
+ lineBox->markDirty(false);
}
static inline bool isCollapsibleSpace(UChar character, const RenderText& renderer)
@@ -990,14 +819,14 @@ inline BidiRun* RenderBlockFlow::handleTrailingSpaces(BidiRunList<BidiRun>& bidi
if (!bidiRuns.runCount()
|| !bidiRuns.logicallyLastRun()->renderer().style().breakOnlyAfterWhiteSpace()
|| !bidiRuns.logicallyLastRun()->renderer().style().autoWrap())
- return nullptr;
+ return 0;
BidiRun* trailingSpaceRun = bidiRuns.logicallyLastRun();
const RenderObject& lastObject = trailingSpaceRun->renderer();
- if (!is<RenderText>(lastObject))
- return nullptr;
+ if (!lastObject.isText())
+ return 0;
- const RenderText& lastText = downcast<RenderText>(lastObject);
+ const RenderText& lastText = toRenderText(lastObject);
int firstSpace;
if (lastText.is8Bit())
firstSpace = findFirstTrailingSpace(lastText, lastText.characters8(), trailingSpaceRun->start(), trailingSpaceRun->stop());
@@ -1005,7 +834,7 @@ inline BidiRun* RenderBlockFlow::handleTrailingSpaces(BidiRunList<BidiRun>& bidi
firstSpace = findFirstTrailingSpace(lastText, lastText.characters16(), trailingSpaceRun->start(), trailingSpaceRun->stop());
if (firstSpace == trailingSpaceRun->stop())
- return nullptr;
+ return 0;
TextDirection direction = style().direction();
bool shouldReorder = trailingSpaceRun != (direction == LTR ? bidiRuns.lastRun() : bidiRuns.firstRun());
@@ -1038,30 +867,20 @@ inline BidiRun* RenderBlockFlow::handleTrailingSpaces(BidiRunList<BidiRun>& bidi
void RenderBlockFlow::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
{
- ASSERT_WITH_SECURITY_IMPLICATION(!floatingObject->originatingLine());
+ ASSERT(!floatingObject->originatingLine());
floatingObject->setOriginatingLine(lastRootBox());
lastRootBox()->appendFloat(floatingObject->renderer());
}
-static inline void notifyResolverToResumeInIsolate(InlineBidiResolver& resolver, RenderObject* root, RenderObject* startObject)
+static inline void setUpResolverToResumeInIsolate(InlineBidiResolver& resolver, RenderObject* root, RenderObject* startObject)
{
if (root != startObject) {
RenderObject* parent = startObject->parent();
- notifyResolverToResumeInIsolate(resolver, root, parent);
+ setUpResolverToResumeInIsolate(resolver, root, parent);
notifyObserverEnteredObject(&resolver, startObject);
}
}
-static inline void setUpResolverToResumeInIsolate(InlineBidiResolver& resolver, InlineBidiResolver& topResolver, BidiRun& isolatedRun, RenderObject* root, RenderObject* startObject)
-{
- // Set up m_midpointState
- resolver.midpointState() = topResolver.midpointState();
- resolver.midpointState().setCurrentMidpoint(topResolver.midpointForIsolatedRun(isolatedRun));
-
- // Set up m_nestedIsolateCount
- notifyResolverToResumeInIsolate(resolver, root, startObject);
-}
-
// FIXME: BidiResolver should have this logic.
static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfRuns, VisualDirectionOverride override, bool previousLineBrokeCleanly)
{
@@ -1074,37 +893,36 @@ static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver,
while (!topResolver.isolatedRuns().isEmpty()) {
// It does not matter which order we resolve the runs as long as we resolve them all.
- auto isolatedRun = WTFMove(topResolver.isolatedRuns().last());
+ BidiRun* isolatedRun = topResolver.isolatedRuns().last();
topResolver.isolatedRuns().removeLast();
- currentRoot = &isolatedRun.root;
- RenderObject& startObject = isolatedRun.object;
+ RenderObject& startObject = isolatedRun->renderer();
// Only inlines make sense with unicode-bidi: isolate (blocks are already isolated).
// FIXME: Because enterIsolate is not passed a RenderObject, we have to crawl up the
// tree to see which parent inline is the isolate. We could change enterIsolate
// to take a RenderObject and do this logic there, but that would be a layering
// violation for BidiResolver (which knows nothing about RenderObject).
- RenderInline* isolatedInline = downcast<RenderInline>(highestContainingIsolateWithinRoot(startObject, currentRoot));
+ RenderInline* isolatedInline = toRenderInline(highestContainingIsolateWithinRoot(startObject, currentRoot));
ASSERT(isolatedInline);
InlineBidiResolver isolatedResolver;
EUnicodeBidi unicodeBidi = isolatedInline->style().unicodeBidi();
TextDirection direction;
if (unicodeBidi == Plaintext)
- determineDirectionality(direction, InlineIterator(isolatedInline, &isolatedRun.object, 0));
+ determineDirectionality(direction, InlineIterator(isolatedInline, &isolatedRun->renderer(), 0));
else {
ASSERT(unicodeBidi == Isolate || unicodeBidi == IsolateOverride);
direction = isolatedInline->style().direction();
}
isolatedResolver.setStatus(BidiStatus(direction, isOverride(unicodeBidi)));
- setUpResolverToResumeInIsolate(isolatedResolver, topResolver, isolatedRun.runToReplace, isolatedInline, &startObject);
+ setUpResolverToResumeInIsolate(isolatedResolver, isolatedInline, &startObject);
// The starting position is the beginning of the first run within the isolate that was identified
// during the earlier call to createBidiRunsForLine. This can be but is not necessarily the
// first run within the isolate.
- InlineIterator iter = InlineIterator(isolatedInline, &startObject, isolatedRun.position);
+ InlineIterator iter = InlineIterator(isolatedInline, &startObject, isolatedRun->m_start);
isolatedResolver.setPositionIgnoringNestedIsolates(iter);
// We stop at the next end of line; we may re-enter this isolate in the next call to constructBidiRuns().
@@ -1116,36 +934,74 @@ static inline void constructBidiRunsForSegment(InlineBidiResolver& topResolver,
// itself to be turned into an InlineBox. We can't remove it here without potentially losing track of
// the logically last run.
if (isolatedResolver.runs().runCount())
- bidiRuns.replaceRunWithRuns(&isolatedRun.runToReplace, isolatedResolver.runs());
+ bidiRuns.replaceRunWithRuns(isolatedRun, isolatedResolver.runs());
// If we encountered any nested isolate runs, just move them
// to the top resolver's list for later processing.
- while (!isolatedResolver.isolatedRuns().isEmpty()) {
- auto runWithContext = WTFMove(isolatedResolver.isolatedRuns().last());
- isolatedResolver.isolatedRuns().removeLast();
- topResolver.setMidpointForIsolatedRun(runWithContext.runToReplace, isolatedResolver.midpointForIsolatedRun(runWithContext.runToReplace));
- topResolver.isolatedRuns().append(WTFMove(runWithContext));
+ if (!isolatedResolver.isolatedRuns().isEmpty()) {
+ topResolver.isolatedRuns().appendVector(isolatedResolver.isolatedRuns());
+ isolatedResolver.isolatedRuns().clear();
+ currentRoot = isolatedInline;
+ }
+ }
+}
+
+static inline void constructBidiRunsForLine(const RenderBlockFlow* block, InlineBidiResolver& topResolver, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& endOfLine, VisualDirectionOverride override, bool previousLineBrokeCleanly)
+{
+#if !ENABLE(CSS_SHAPES)
+ UNUSED_PARAM(block);
+ constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
+#else
+ ShapeInsideInfo* shapeInsideInfo = block->layoutShapeInsideInfo();
+ if (!shapeInsideInfo || !shapeInsideInfo->hasSegments()) {
+ constructBidiRunsForSegment(topResolver, bidiRuns, endOfLine, override, previousLineBrokeCleanly);
+ return;
+ }
+
+ const SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges();
+ ASSERT(segmentRanges.size());
+
+ for (size_t i = 0; i < segmentRanges.size(); i++) {
+ LineSegmentIterator iterator = segmentRanges[i].start;
+ InlineIterator segmentStart(iterator.root, iterator.object, iterator.offset);
+ iterator = segmentRanges[i].end;
+ InlineIterator segmentEnd(iterator.root, iterator.object, iterator.offset);
+ if (i) {
+ ASSERT(segmentStart.renderer());
+ BidiRun* segmentMarker = createRun(segmentStart.offset(), segmentStart.offset(), segmentStart.renderer(), topResolver);
+ segmentMarker->m_startsSegment = true;
+ bidiRuns.addRun(segmentMarker);
+ // Do not collapse midpoints between segments
+ topResolver.midpointState().setBetweenMidpoints(false);
}
+ if (segmentStart == segmentEnd)
+ continue;
+ topResolver.setPosition(segmentStart, numberOfIsolateAncestors(segmentStart));
+ constructBidiRunsForSegment(topResolver, bidiRuns, segmentEnd, override, previousLineBrokeCleanly);
}
+#endif
}
// This function constructs line boxes for all of the text runs in the resolver and computes their position.
-RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel, BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
+RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun, WordMeasurements& wordMeasurements)
{
if (!bidiRuns.runCount())
- return nullptr;
+ return 0;
// FIXME: Why is this only done when we had runs?
lineInfo.setLastLine(!end.renderer());
RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
if (!lineBox)
- return nullptr;
+ return 0;
- lineBox->setBidiLevel(bidiLevel);
lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
- bool isSVGRootInlineBox = is<SVGRootInlineBox>(*lineBox);
+#if ENABLE(SVG)
+ bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
+#else
+ bool isSVGRootInlineBox = false;
+#endif
GlyphOverflowAndFallbackFontsMap textBoxDataMap;
@@ -1156,6 +1012,7 @@ RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel,
// Now position our text runs vertically.
computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache);
+#if ENABLE(SVG)
// SVG text layout code computes vertical & horizontal positions on its own.
// Note that we still need to execute computeVerticalPositionsForLine() as
// it calls InlineTextBox::positionLineBox(), which tracks whether the box
@@ -1163,12 +1020,18 @@ RootInlineBox* RenderBlockFlow::createLineBoxesFromBidiRuns(unsigned bidiLevel,
// text selection in RTL boxes would not work as expected.
if (isSVGRootInlineBox) {
ASSERT_WITH_SECURITY_IMPLICATION(isSVGText());
- downcast<SVGRootInlineBox>(*lineBox).computePerCharacterLayoutInformation();
+ toSVGRootInlineBox(lineBox)->computePerCharacterLayoutInformation();
}
+#endif
// Compute our overflow now.
lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
+#if PLATFORM(MAC)
+ // Highlight acts as an overflow inflation.
+ if (style().highlight() != nullAtom)
+ lineBox->addHighlightOverflow();
+#endif
return lineBox;
}
@@ -1190,9 +1053,6 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has
// We want to skip ahead to the first dirty line
InlineBidiResolver resolver;
RootInlineBox* startLine = determineStartPosition(layoutState, resolver);
-
- if (startLine)
- marginCollapseLinesFromStart(layoutState, startLine);
unsigned consecutiveHyphenatedLines = 0;
if (startLine) {
@@ -1210,7 +1070,7 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has
// that the block really needed a full layout, we missed our chance to repaint the layer
// before layout started. Luckily the layer has cached the repaint rect for its original
// position and size, and so we can use that to make a repaint happen now.
- repaintUsingContainer(containerForRepaint(), layer()->repaintRect());
+ repaintUsingContainer(containerForRepaint(), pixelSnappedIntRect(layer()->repaintRect()));
}
}
@@ -1241,7 +1101,7 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has
if (lastObject->isBR()) {
EClear clear = lastObject->style().clear();
if (clear != CNONE)
- clearFloats(clear);
+ newLine(clear);
}
}
}
@@ -1251,6 +1111,16 @@ void RenderBlockFlow::layoutRunsAndFloats(LineLayoutState& layoutState, bool has
repaintDirtyFloats(layoutState.floats());
}
+RenderTextInfo::RenderTextInfo()
+ : m_text(0)
+ , m_font(0)
+{
+}
+
+RenderTextInfo::~RenderTextInfo()
+{
+}
+
// Before restarting the layout loop with a new logicalHeight, remove all floats that were added and reset the resolver.
inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange(LayoutUnit oldLogicalHeight, LayoutUnit newLogicalHeight, FloatingObject* lastFloatFromPreviousLine, InlineBidiResolver& resolver, const InlineIterator& oldEnd)
{
@@ -1260,6 +1130,170 @@ inline const InlineIterator& RenderBlockFlow::restartLayoutRunsAndFloatsInRange(
return oldEnd;
}
+#if ENABLE(CSS_SHAPES)
+static inline void pushShapeContentOverflowBelowTheContentBox(RenderBlockFlow* block, ShapeInsideInfo* shapeInsideInfo, LayoutUnit lineTop, LayoutUnit lineHeight)
+{
+ ASSERT(shapeInsideInfo);
+
+ LayoutUnit logicalLineBottom = lineTop + lineHeight;
+ LayoutUnit shapeLogicalBottom = shapeInsideInfo->shapeLogicalBottom();
+ LayoutUnit shapeContainingBlockLogicalHeight = shapeInsideInfo->shapeContainingBlockLogicalHeight();
+
+ bool isOverflowPositionedAlready = (shapeContainingBlockLogicalHeight - shapeInsideInfo->owner().borderAndPaddingAfter() + lineHeight) <= lineTop;
+
+ // If the last line overlaps with the shape, we don't need the segments anymore
+ if (lineTop < shapeLogicalBottom && shapeLogicalBottom < logicalLineBottom)
+ shapeInsideInfo->clearSegments();
+
+ if (logicalLineBottom <= shapeLogicalBottom || !shapeContainingBlockLogicalHeight || isOverflowPositionedAlready)
+ return;
+
+ LayoutUnit newLogicalHeight = block->logicalHeight() + (shapeContainingBlockLogicalHeight - (lineTop + shapeInsideInfo->owner().borderAndPaddingAfter()));
+ block->setLogicalHeight(newLogicalHeight);
+}
+
+void RenderBlockFlow::updateShapeAndSegmentsForCurrentLine(ShapeInsideInfo*& shapeInsideInfo, const LayoutSize& logicalOffsetFromShapeContainer, LineLayoutState& layoutState)
+{
+ if (layoutState.flowThread())
+ return updateShapeAndSegmentsForCurrentLineInFlowThread(shapeInsideInfo, layoutState);
+
+ if (!shapeInsideInfo)
+ return;
+
+ LayoutUnit lineTop = logicalHeight() + logicalOffsetFromShapeContainer.height();
+ LayoutUnit lineLeft = logicalOffsetFromShapeContainer.width();
+ LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
+
+ // FIXME: Bug 95361: It is possible for a line to grow beyond lineHeight, in which case these segments may be incorrect.
+ shapeInsideInfo->updateSegmentsForLine(LayoutSize(lineLeft, lineTop), lineHeight);
+
+ pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
+}
+
+void RenderBlockFlow::updateShapeAndSegmentsForCurrentLineInFlowThread(ShapeInsideInfo*& shapeInsideInfo, LineLayoutState& layoutState)
+{
+ ASSERT(layoutState.flowThread());
+
+ RenderRegion* currentRegion = regionAtBlockOffset(logicalHeight());
+ if (!currentRegion || !currentRegion->logicalHeight())
+ return;
+
+ shapeInsideInfo = currentRegion->shapeInsideInfo();
+
+ RenderRegion* nextRegion = 0;
+ if (!currentRegion->isLastRegion()) {
+ RenderRegionList regionList = layoutState.flowThread()->renderRegionList();
+ auto it = regionList.find(currentRegion);
+ nextRegion = *(++it);
+ }
+
+ // We only want to deal regions with shapes, so we check if the next region has a shape
+ if (!shapeInsideInfo && nextRegion && !nextRegion->shapeInsideInfo())
+ return;
+
+ LayoutUnit lineHeight = this->lineHeight(layoutState.lineInfo().isFirstLine(), isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
+ LayoutUnit logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage();
+ LayoutUnit logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight;
+ LayoutUnit logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent();
+ LayoutUnit logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter();
+
+ LayoutUnit shapeBottomInFlowThread = LayoutUnit::max();
+ if (shapeInsideInfo)
+ shapeBottomInFlowThread = shapeInsideInfo->shapeLogicalBottom() + currentRegion->logicalTopForFlowThreadContent();
+
+ bool lineOverLapsWithShapeBottom = shapeBottomInFlowThread < logicalLineBottomInFlowThread;
+ bool lineTopAdjustedIntoNextRegion = layoutState.adjustedLogicalLineTop() >= currentRegion->logicalHeight();
+ bool lineOverLapsWithRegionBottom = logicalLineBottomInFlowThread > logicalRegionBottomInFlowThread || lineTopAdjustedIntoNextRegion;
+ bool overFlowsToNextRegion = nextRegion && (lineOverLapsWithShapeBottom || lineOverLapsWithRegionBottom);
+
+ // If the line is between two shapes/regions we position the line to the top of the next shape/region
+ if (overFlowsToNextRegion) {
+ ASSERT(currentRegion != nextRegion);
+ LayoutUnit deltaToNextRegion = logicalRegionBottomInFlowThread - logicalLineTopInFlowThread;
+ setLogicalHeight(logicalHeight() + deltaToNextRegion);
+
+ currentRegion = nextRegion;
+ shapeInsideInfo = currentRegion->shapeInsideInfo();
+
+ logicalLineTopInFlowThread = logicalHeight() + offsetFromLogicalTopOfFirstPage();
+ logicalLineBottomInFlowThread = logicalLineTopInFlowThread + lineHeight;
+ logicalRegionTopInFlowThread = currentRegion->logicalTopForFlowThreadContent();
+ logicalRegionBottomInFlowThread = logicalRegionTopInFlowThread + currentRegion->logicalHeight() - currentRegion->borderAndPaddingBefore() - currentRegion->borderAndPaddingAfter();
+
+ if (lineTopAdjustedIntoNextRegion)
+ layoutState.setAdjustedLogicalLineTop(0);
+ }
+
+ if (!shapeInsideInfo)
+ return;
+
+ bool isFirstLineInRegion = logicalLineBottomInFlowThread <= (logicalRegionTopInFlowThread + lineHeight);
+ bool isFirstLineAdjusted = (logicalLineTopInFlowThread - logicalRegionTopInFlowThread) < (layoutState.adjustedLogicalLineTop() - currentRegion->borderAndPaddingBefore());
+ // We position the first line to the top of the shape in the region or to the previously adjusted position in the shape
+ if (isFirstLineInRegion || isFirstLineAdjusted) {
+ LayoutUnit shapeTopOffset = layoutState.adjustedLogicalLineTop();
+
+ if (!shapeTopOffset && (shapeInsideInfo->shapeLogicalTop() > 0))
+ shapeTopOffset = shapeInsideInfo->shapeLogicalTop();
+
+ LayoutUnit shapePositionInFlowThread = currentRegion->logicalTopForFlowThreadContent() + shapeTopOffset;
+ LayoutUnit shapeTopLineTopDelta = shapePositionInFlowThread - logicalLineTopInFlowThread - currentRegion->borderAndPaddingBefore();
+
+ setLogicalHeight(logicalHeight() + shapeTopLineTopDelta);
+ logicalLineTopInFlowThread += shapeTopLineTopDelta;
+ layoutState.setAdjustedLogicalLineTop(0);
+ }
+
+ LayoutUnit lineTop = logicalLineTopInFlowThread - currentRegion->logicalTopForFlowThreadContent() + currentRegion->borderAndPaddingBefore();
+
+ // FIXME: 118571 - Shape inside on a region does not yet take into account its padding for nested flow blocks
+ shapeInsideInfo->updateSegmentsForLine(LayoutSize(0, lineTop), lineHeight);
+
+ if (currentRegion->isLastRegion())
+ pushShapeContentOverflowBelowTheContentBox(this, shapeInsideInfo, lineTop, lineHeight);
+}
+
+static inline LayoutUnit adjustLogicalLineTop(ShapeInsideInfo* shapeInsideInfo, InlineIterator start, InlineIterator end, const WordMeasurements& wordMeasurements)
+{
+ if (!shapeInsideInfo || end != start)
+ return 0;
+
+ float minWidth = firstPositiveWidth(wordMeasurements);
+ ASSERT(minWidth || wordMeasurements.isEmpty());
+ if (minWidth > 0 && shapeInsideInfo->adjustLogicalLineTop(minWidth))
+ return shapeInsideInfo->logicalLineTop();
+
+ return shapeInsideInfo->shapeLogicalBottom();
+}
+
+bool RenderBlockFlow::adjustLogicalLineTopAndLogicalHeightIfNeeded(ShapeInsideInfo* shapeInsideInfo, LayoutUnit absoluteLogicalTop, LineLayoutState& layoutState, InlineBidiResolver& resolver, FloatingObject* lastFloatFromPreviousLine, InlineIterator& end, WordMeasurements& wordMeasurements)
+{
+ LayoutUnit adjustedLogicalLineTop = adjustLogicalLineTop(shapeInsideInfo, resolver.position(), end, wordMeasurements);
+
+ if (shapeInsideInfo && containsFloats()) {
+ lastFloatFromPreviousLine = m_floatingObjects->set().last().get();
+ if (!wordMeasurements.size()) {
+ LayoutUnit floatLogicalTopOffset = shapeInsideInfo->computeFirstFitPositionForFloat(logicalSizeForFloat(lastFloatFromPreviousLine));
+ if (logicalHeight() < floatLogicalTopOffset)
+ adjustedLogicalLineTop = floatLogicalTopOffset;
+ }
+ }
+
+ if (!adjustedLogicalLineTop)
+ return false;
+
+ LayoutUnit newLogicalHeight = adjustedLogicalLineTop - absoluteLogicalTop;
+
+ if (layoutState.flowThread()) {
+ layoutState.setAdjustedLogicalLineTop(adjustedLogicalLineTop);
+ newLogicalHeight = logicalHeight();
+ }
+
+ end = restartLayoutRunsAndFloatsInRange(logicalHeight(), newLogicalHeight, lastFloatFromPreviousLine, resolver, end);
+ return true;
+}
+#endif
+
void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines)
{
const RenderStyle& styleToUse = style();
@@ -1272,13 +1306,32 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
LineBreaker lineBreaker(*this);
+#if ENABLE(CSS_SHAPES)
+ LayoutSize logicalOffsetFromShapeContainer;
+ ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
+ if (shapeInsideInfo) {
+ ASSERT(&shapeInsideInfo->owner() == this || allowsShapeInsideInfoSharing());
+ if (shapeInsideInfo != this->shapeInsideInfo()) {
+ // FIXME Bug 100284: If subsequent LayoutStates are pushed, we will have to add
+ // their offsets from the original shape-inside container.
+ logicalOffsetFromShapeContainer = logicalOffsetFromShapeAncestorContainer(&shapeInsideInfo->owner());
+ }
+ // Begin layout at the logical top of our shape inside.
+ if (logicalHeight() + logicalOffsetFromShapeContainer.height() < shapeInsideInfo->shapeLogicalTop()) {
+ LayoutUnit logicalHeight = shapeInsideInfo->shapeLogicalTop() - logicalOffsetFromShapeContainer.height();
+ if (layoutState.flowThread())
+ logicalHeight -= shapeInsideInfo->owner().borderAndPaddingBefore();
+ setLogicalHeight(logicalHeight);
+ }
+ }
+#endif
+
while (!end.atEnd()) {
// FIXME: Is this check necessary before the first iteration or can it be moved to the end?
if (checkForEndLineMatch) {
layoutState.setEndLineMatched(matchedEndLine(layoutState, resolver, cleanLineStart, cleanLineBidiStatus));
if (layoutState.endLineMatched()) {
resolver.setPosition(InlineIterator(resolver.position().root(), 0, 0), 0);
- layoutState.marginInfo().clearMargin();
break;
}
}
@@ -1290,12 +1343,14 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
const InlineIterator oldEnd = end;
bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly();
- FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : nullptr;
+ FloatingObject* lastFloatFromPreviousLine = (containsFloats()) ? m_floatingObjects->set().last().get() : 0;
+#if ENABLE(CSS_SHAPES)
+ updateShapeAndSegmentsForCurrentLine(shapeInsideInfo, logicalOffsetFromShapeContainer, layoutState);
+#endif
WordMeasurements wordMeasurements;
- end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), layoutState, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
- cachePriorCharactersIfNeeded(renderTextInfo.lineBreakIterator);
- renderTextInfo.lineBreakIterator.resetPriorContext();
+ end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
+ renderTextInfo.m_lineBreakIterator.resetPriorContext();
if (resolver.position().atEnd()) {
// FIXME: We shouldn't be creating any runs in nextLineBreak to begin with!
// Once BidiRunList is separated from BidiResolver this will not be needed.
@@ -1306,6 +1361,10 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
break;
}
+#if ENABLE(CSS_SHAPES)
+ if (adjustLogicalLineTopAndLogicalHeightIfNeeded(shapeInsideInfo, logicalOffsetFromShapeContainer.height(), layoutState, resolver, lastFloatFromPreviousLine, end, wordMeasurements))
+ continue;
+#endif
ASSERT(end != resolver.position());
// This is a short-cut for empty lines.
@@ -1322,10 +1381,10 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
}
// FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
BidiRunList<BidiRun>& bidiRuns = resolver.runs();
- constructBidiRunsForSegment(resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
+ constructBidiRunsForLine(this, resolver, bidiRuns, end, override, layoutState.lineInfo().previousLineBrokeCleanly());
ASSERT(resolver.position() == end);
- BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : nullptr;
+ BidiRun* trailingSpaceRun = !layoutState.lineInfo().previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0;
if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated()) {
bidiRuns.logicallyLastRun()->m_hasHyphen = true;
@@ -1338,7 +1397,7 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
// inline flow boxes.
LayoutUnit oldLogicalHeight = logicalHeight();
- RootInlineBox* lineBox = createLineBoxesFromBidiRuns(resolver.status().context->level(), bidiRuns, end, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
+ RootInlineBox* lineBox = createLineBoxesFromBidiRuns(bidiRuns, end, layoutState.lineInfo(), verticalPositionCache, trailingSpaceRun, wordMeasurements);
bidiRuns.deleteRuns();
resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
@@ -1347,54 +1406,24 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
lineBox->setLineBreakInfo(end.renderer(), end.offset(), resolver.status());
if (layoutState.usesRepaintBounds())
layoutState.updateRepaintRangeFromBox(lineBox);
-
- LayoutUnit adjustment = 0;
- bool overflowsRegion = false;
-
- // If our previous line was an anonymous block and we are not an anonymous block,
- // simulate a margin collapse now so that we get the proper
- // increased height. We also have to simulate a margin collapse to propagate margins
- // through to the top of our block.
- if (!lineBox->hasAnonymousInlineBlock()) {
- RootInlineBox* prevRoot = lineBox->prevRootBox();
- if (prevRoot && prevRoot->hasAnonymousInlineBlock()) {
- LayoutUnit currentLogicalHeight = logicalHeight();
- setLogicalHeight(oldLogicalHeight);
- collapseMarginsWithChildInfo(nullptr, nullptr, layoutState.marginInfo());
- adjustment = logicalHeight() - oldLogicalHeight;
- setLogicalHeight(currentLogicalHeight);
- }
- layoutState.marginInfo().setAtBeforeSideOfBlock(false);
- }
-
- if (paginated)
- adjustLinePositionForPagination(lineBox, adjustment, overflowsRegion, layoutState.flowThread());
- if (adjustment) {
- IndentTextOrNot shouldIndentText = layoutState.lineInfo().isFirstLine() ? IndentText : DoNotIndentText;
- LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, shouldIndentText);
- lineBox->adjustBlockDirectionPosition(adjustment);
- if (layoutState.usesRepaintBounds())
- layoutState.updateRepaintRangeFromBox(lineBox);
-
- if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, shouldIndentText) != oldLineWidth) {
- // We have to delete this line, remove all floats that got added, and let line layout re-run.
- lineBox->deleteLine();
- end = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, oldEnd);
- continue;
- }
- setLogicalHeight(lineBox->lineBottomWithLeading());
- }
-
if (paginated) {
- if (RenderFlowThread* flowThread = flowThreadContainingBlock()) {
- if (flowThread->isRenderNamedFlowThread() && overflowsRegion && hasNextPage(lineBox->lineTop())) {
- // Limit the height of this block to the end of the current region because
- // it is also fragmented into the next region.
- LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalTop(), ExcludePageBoundary);
- if (logicalHeight() > remainingLogicalHeight)
- setLogicalHeight(remainingLogicalHeight);
+ LayoutUnit adjustment = 0;
+ adjustLinePositionForPagination(lineBox, adjustment, layoutState.flowThread());
+ if (adjustment) {
+ LayoutUnit oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, layoutState.lineInfo().isFirstLine());
+ lineBox->adjustBlockDirectionPosition(adjustment);
+ if (layoutState.usesRepaintBounds())
+ layoutState.updateRepaintRangeFromBox(lineBox);
+
+ if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, layoutState.lineInfo().isFirstLine()) != oldLineWidth) {
+ // We have to delete this line, remove all floats that got added, and let line layout re-run.
+ lineBox->deleteLine();
+ end = restartLayoutRunsAndFloatsInRange(oldLogicalHeight, oldLogicalHeight + adjustment, lastFloatFromPreviousLine, resolver, oldEnd);
+ continue;
}
+
+ setLogicalHeight(lineBox->lineBottomWithLeading());
}
if (layoutState.flowThread())
@@ -1404,11 +1433,11 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
}
for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
- setStaticPositions(*this, *lineBreaker.positionedObjects()[i], DoNotIndentText);
+ setStaticPositions(*this, *lineBreaker.positionedObjects()[i]);
if (!layoutState.lineInfo().isEmpty()) {
layoutState.lineInfo().setFirstLine(false);
- clearFloats(lineBreaker.clear());
+ newLine(lineBreaker.clear());
}
if (m_floatingObjects && lastRootBox()) {
@@ -1496,44 +1525,22 @@ void RenderBlockFlow::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, I
markLinesDirtyInBlockRange(lastRootBox()->lineBottomWithLeading(), lineBox->lineBottomWithLeading(), lineBox);
}
}
- clearDidBreakAtLineToAvoidWidow();
-}
-
-void RenderBlockFlow::reattachCleanLineFloats(RootInlineBox& cleanLine, LayoutUnit delta, bool isFirstCleanLine)
-{
- auto* cleanLineFloats = cleanLine.floatsPtr();
- if (!cleanLineFloats)
- return;
- for (auto* floatingBox : *cleanLineFloats) {
- auto* floatingObject = insertFloatingObject(*floatingBox);
- if (isFirstCleanLine && floatingObject->originatingLine()) {
- // Float box does not belong to this line anymore.
- ASSERT_WITH_SECURITY_IMPLICATION(cleanLine.prevRootBox() == floatingObject->originatingLine());
- cleanLine.removeFloat(*floatingBox);
- continue;
- }
- ASSERT_WITH_SECURITY_IMPLICATION(!floatingObject->originatingLine());
- floatingObject->setOriginatingLine(&cleanLine);
- setLogicalHeight(logicalTopForChild(*floatingBox) - marginBeforeForChild(*floatingBox) + delta);
- positionNewFloats();
- }
+ clearDidBreakAtLineToAvoidWidow();
}
void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState)
{
- auto* firstCleanLine = layoutState.endLine();
- if (firstCleanLine) {
+ if (layoutState.endLine()) {
if (layoutState.endLineMatched()) {
bool paginated = view().layoutState() && view().layoutState()->isPaginated();
// Attach all the remaining lines, and then adjust their y-positions as needed.
LayoutUnit delta = logicalHeight() - layoutState.endLineLogicalTop();
- for (auto* line = firstCleanLine; line; line = line->nextRootBox()) {
+ for (RootInlineBox* line = layoutState.endLine(); line; line = line->nextRootBox()) {
line->attachLine();
if (paginated) {
delta -= line->paginationStrut();
- bool overflowsRegion;
- adjustLinePositionForPagination(line, delta, overflowsRegion, layoutState.flowThread());
+ adjustLinePositionForPagination(line, delta, layoutState.flowThread());
}
if (delta) {
layoutState.updateRepaintRangeFromBox(line, delta);
@@ -1541,7 +1548,16 @@ void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState)
}
if (layoutState.flowThread())
updateRegionForLine(line);
- reattachCleanLineFloats(*line, delta, line == firstCleanLine);
+ if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
+ for (auto it = cleanLineFloats->begin(), end = cleanLineFloats->end(); it != end; ++it) {
+ RenderBox* floatingBox = *it;
+ FloatingObject* floatingObject = insertFloatingObject(*floatingBox);
+ ASSERT(!floatingObject->originatingLine());
+ floatingObject->setOriginatingLine(line);
+ setLogicalHeight(logicalTopForChild(*floatingBox) - marginBeforeForChild(*floatingBox) + delta);
+ positionNewFloats();
+ }
+ }
}
setLogicalHeight(lastRootBox()->lineBottomWithLeading());
} else {
@@ -1559,7 +1575,7 @@ void RenderBlockFlow::linkToEndLineIfNeeded(LineLayoutState& layoutState)
LayoutUnit bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow();
auto newLineBox = std::make_unique<TrailingFloatsRootInlineBox>(*this);
auto trailingFloatsLineBox = newLineBox.get();
- m_lineBoxes.appendLineBox(WTFMove(newLineBox));
+ m_lineBoxes.appendLineBox(std::move(newLineBox));
trailingFloatsLineBox->setConstructed();
GlyphOverflowAndFallbackFontsMap textBoxDataMap;
VerticalPositionCache verticalPositionCache;
@@ -1620,7 +1636,7 @@ void RenderBlockFlow::layoutLineBoxes(bool relayoutChildren, LayoutUnit& repaint
// Figure out if we should clear out our line boxes.
// FIXME: Handle resize eventually!
bool isFullLayout = !firstRootBox() || selfNeedsLayout() || relayoutChildren || clearLinesForPagination;
- LineLayoutState layoutState(*this, isFullLayout, repaintLogicalTop, repaintLogicalBottom, flowThread);
+ LineLayoutState layoutState(isFullLayout, repaintLogicalTop, repaintLogicalBottom, flowThread);
if (isFullLayout)
lineBoxes().deleteLineBoxes();
@@ -1653,7 +1669,7 @@ void RenderBlockFlow::layoutLineBoxes(bool relayoutChildren, LayoutUnit& repaint
hasInlineChild = true;
if (o.isReplaced() || o.isFloating() || o.isOutOfFlowPositioned()) {
- RenderBox& box = downcast<RenderBox>(o);
+ RenderBox& box = toRenderBox(o);
if (relayoutChildren || box.hasRelativeDimensions())
box.setChildNeedsLayout(MarkOnlyThis);
@@ -1669,16 +1685,14 @@ void RenderBlockFlow::layoutLineBoxes(bool relayoutChildren, LayoutUnit& repaint
else if (isFullLayout || box.needsLayout()) {
// Replaced element.
box.dirtyLineBoxes(isFullLayout);
- if (!o.isAnonymousInlineBlock()) {
- if (isFullLayout)
- replacedChildren.append(&box);
- else
- box.layoutIfNeeded();
- }
+ if (isFullLayout)
+ replacedChildren.append(&box);
+ else
+ box.layoutIfNeeded();
}
- } else if (o.isTextOrLineBreak() || (is<RenderInline>(o) && !walker.atEndOfInline())) {
- if (is<RenderInline>(o))
- downcast<RenderInline>(o).updateAlwaysCreateLineBoxes(layoutState.isFullLayout());
+ } else if (o.isTextOrLineBreak() || (o.isRenderInline() && !walker.atEndOfInline())) {
+ if (o.isRenderInline())
+ toRenderInline(o).updateAlwaysCreateLineBoxes(layoutState.isFullLayout());
if (layoutState.isFullLayout() || o.selfNeedsLayout())
dirtyLineBoxesForRenderer(o, layoutState.isFullLayout());
o.clearNeedsLayout();
@@ -1700,17 +1714,9 @@ void RenderBlockFlow::layoutLineBoxes(bool relayoutChildren, LayoutUnit& repaint
else
lastLineAnnotationsAdjustment = lastRootBox()->computeOverAnnotationAdjustment(lowestAllowedPosition);
}
-
- // Now do the handling of the bottom of the block, adding in our bottom border/padding and
- // determining the correct collapsed bottom margin information. This collapse is only necessary
- // if our last child was an anonymous inline block that might need to propagate margin information out to
- // us.
- LayoutUnit beforeEdge = borderAndPaddingBefore();
- LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight() + lastLineAnnotationsAdjustment;
- if (lastRootBox() && lastRootBox()->hasAnonymousInlineBlock())
- handleAfterSideOfBlock(beforeEdge, afterEdge, layoutState.marginInfo());
- else
- setLogicalHeight(logicalHeight() + afterEdge);
+
+ // Now add in the bottom border/padding.
+ setLogicalHeight(logicalHeight() + lastLineAnnotationsAdjustment + borderAndPaddingAfter() + scrollbarLogicalHeight());
if (!firstRootBox() && hasLineIfEmpty())
setLogicalHeight(logicalHeight() + lineHeight(true, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
@@ -1735,16 +1741,14 @@ void RenderBlockFlow::checkFloatsInCleanLine(RootInlineBox* line, Vector<FloatWi
for (auto it = cleanLineFloats->begin(), end = cleanLineFloats->end(); it != end; ++it) {
RenderBox* floatingBox = *it;
floatingBox->layoutIfNeeded();
- LayoutSize newSize(floatingBox->width() + floatingBox->horizontalMarginExtent(), floatingBox->height() + floatingBox->verticalMarginExtent());
+ LayoutSize newSize(floatingBox->width() + floatingBox->marginWidth(), floatingBox->height() + floatingBox->marginHeight());
ASSERT_WITH_SECURITY_IMPLICATION(floatIndex < floats.size());
if (&floats[floatIndex].object != floatingBox) {
encounteredNewFloat = true;
return;
}
-
- // We have to reset the cap-height alignment done by the first-letter floats when initial-letter is set, so just always treat first-letter floats
- // as dirty.
- if (floats[floatIndex].rect.size() != newSize || (floatingBox->style().styleType() == FIRST_LETTER && floatingBox->style().initialLetterDrop() > 0)) {
+
+ if (floats[floatIndex].rect.size() != newSize) {
LayoutUnit floatTop = isHorizontalWritingMode() ? floats[floatIndex].rect.y() : floats[floatIndex].rect.x();
LayoutUnit floatHeight = isHorizontalWritingMode() ? std::max(floats[floatIndex].rect.height(), newSize.height()) : std::max(floats[floatIndex].rect.width(), newSize.width());
floatHeight = std::min(floatHeight, LayoutUnit::max() - floatTop);
@@ -1776,8 +1780,7 @@ RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutSt
break;
}
paginationDelta -= curr->paginationStrut();
- bool overflowsRegion;
- adjustLinePositionForPagination(curr, paginationDelta, overflowsRegion, layoutState.flowThread());
+ adjustLinePositionForPagination(curr, paginationDelta, layoutState.flowThread());
if (paginationDelta) {
if (containsFloats() || !layoutState.floats().isEmpty()) {
// FIXME: Do better eventually. For now if we ever shift because of pagination and floats are present just go to a full layout.
@@ -1816,13 +1819,18 @@ RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutSt
// We have a dirty line.
if (RootInlineBox* prevRootBox = curr->prevRootBox()) {
// We have a previous line.
- if (!dirtiedByFloat && !curr->hasAnonymousInlineBlock() && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (is<RenderText>(*prevRootBox->lineBreakObj()) && prevRootBox->lineBreakPos() >= downcast<RenderText>(*prevRootBox->lineBreakObj()).textLength()))) {
+ if (!dirtiedByFloat && (!prevRootBox->endsWithBreak() || !prevRootBox->lineBreakObj() || (prevRootBox->lineBreakObj()->isText() && prevRootBox->lineBreakPos() >= toRenderText(prevRootBox->lineBreakObj())->textLength())))
// The previous line didn't break cleanly or broke at a newline
// that has been deleted, so treat it as dirty too.
curr = prevRootBox;
- }
}
+ } else {
+ // No dirty lines were found.
+ // If the last line didn't break cleanly, treat it as dirty.
+ if (lastRootBox() && !lastRootBox()->endsWithBreak())
+ curr = lastRootBox();
}
+
// If we have no dirty lines, then last is just the last root box.
last = curr ? curr->prevRootBox() : lastRootBox();
}
@@ -1837,7 +1845,7 @@ RootInlineBox* RenderBlockFlow::determineStartPosition(LineLayoutState& layoutSt
for (auto it = cleanLineFloats->begin(), end = cleanLineFloats->end(); it != end; ++it) {
RenderBox* floatingBox = *it;
FloatingObject* floatingObject = insertFloatingObject(*floatingBox);
- ASSERT_WITH_SECURITY_IMPLICATION(!floatingObject->originatingLine());
+ ASSERT(!floatingObject->originatingLine());
floatingObject->setOriginatingLine(line);
setLogicalHeight(logicalTopForChild(*floatingBox) - marginBeforeForChild(*floatingBox));
positionNewFloats();
@@ -1920,9 +1928,8 @@ bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutS
// This isn't the real move we're going to do, so don't update the line box's pagination
// strut yet.
LayoutUnit oldPaginationStrut = lineBox->paginationStrut();
- bool overflowsRegion;
lineDelta -= oldPaginationStrut;
- adjustLinePositionForPagination(lineBox, lineDelta, overflowsRegion, layoutState.flowThread());
+ adjustLinePositionForPagination(lineBox, lineDelta, layoutState.flowThread());
lineBox->setPaginationStrut(oldPaginationStrut);
}
if (lineWidthForPaginatedLineChanged(lineBox, lineDelta, layoutState.flowThread()))
@@ -1945,7 +1952,7 @@ bool RenderBlockFlow::checkPaginationAndFloatsAtEndLine(LineLayoutState& layoutS
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
auto end = floatingObjectSet.end();
for (auto it = floatingObjectSet.begin(); it != end; ++it) {
- const auto& floatingObject = *it->get();
+ FloatingObject* floatingObject = it->get();
if (logicalBottomForFloat(floatingObject) >= logicalTop && logicalBottomForFloat(floatingObject) < logicalBottom)
return false;
}
@@ -1975,11 +1982,11 @@ bool RenderBlockFlow::matchedEndLine(LineLayoutState& layoutState, const InlineB
// The first clean line doesn't match, but we can check a handful of following lines to try
// to match back up.
- static const int numLines = 8; // The # of lines we're willing to match against.
+ static int numLines = 8; // The # of lines we're willing to match against.
RootInlineBox* originalEndLine = layoutState.endLine();
RootInlineBox* line = originalEndLine;
for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
- if (line->lineBreakObj() == resolver.position().renderer() && line->lineBreakPos() == resolver.position().offset() && !line->hasAnonymousInlineBlock()) {
+ if (line->lineBreakObj() == resolver.position().renderer() && line->lineBreakPos() == resolver.position().offset()) {
// We have a match.
if (line->lineBreakBidiStatus() != resolver.status())
return false; // ...but the bidi state doesn't match.
@@ -2026,14 +2033,13 @@ void RenderBlockFlow::addOverflowFromInlineChildren()
endPadding = 1;
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
- RenderRegion* region = flowThreadContainingBlock() ? curr->containingRegion() : nullptr;
+ RenderRegion* region = curr->containingRegion();
if (region)
region->addLayoutOverflowForBox(this, curr->paddedLayoutOverflowRect(endPadding));
if (!hasOverflowClip()) {
- LayoutRect childVisualOverflowRect = curr->visualOverflowRect(curr->lineTop(), curr->lineBottom());
- addVisualOverflow(childVisualOverflowRect);
+ addVisualOverflow(curr->visualOverflowRect(curr->lineTop(), curr->lineBottom()));
if (region)
- region->addVisualOverflowForBox(this, childVisualOverflowRect);
+ region->addVisualOverflowForBox(this, curr->visualOverflowRect(curr->lineTop(), curr->lineBottom()));
}
}
}
@@ -2042,23 +2048,23 @@ void RenderBlockFlow::deleteEllipsisLineBoxes()
{
ETextAlign textAlign = style().textAlign();
bool ltr = style().isLeftToRightDirection();
- IndentTextOrNot shouldIndentText = IndentText;
+ bool firstLine = true;
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
if (curr->hasEllipsisBox()) {
curr->clearTruncation();
// Shift the line back where it belongs if we cannot accomodate an ellipsis.
- float logicalLeft = logicalLeftOffsetForLine(curr->lineTop(), shouldIndentText);
- float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), DoNotIndentText) - logicalLeft;
+ float logicalLeft = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine);
+ float availableLogicalWidth = logicalRightOffsetForLine(curr->lineTop(), false) - logicalLeft;
float totalLogicalWidth = curr->logicalWidth();
- updateLogicalWidthForAlignment(textAlign, curr, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
+ updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
if (ltr)
curr->adjustLogicalPosition((logicalLeft - curr->logicalLeft()), 0);
else
curr->adjustLogicalPosition(-(curr->logicalLeft() - logicalLeft), 0);
}
- shouldIndentText = DoNotIndentText;
+ firstLine = false;
}
}
@@ -2066,11 +2072,11 @@ void RenderBlockFlow::checkLinesForTextOverflow()
{
// Determine the width of the ellipsis using the current font.
// FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if horizontal ellipsis is "not renderable"
- const FontCascade& font = style().fontCascade();
- static NeverDestroyed<AtomicString> ellipsisStr(&horizontalEllipsis, 1);
- const FontCascade& firstLineFont = firstLineStyle().fontCascade();
- float firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle()));
- float ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
+ const Font& font = style().font();
+ DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
+ const Font& firstLineFont = firstLineStyle().font();
+ int firstLineEllipsisWidth = firstLineFont.width(constructTextRun(this, firstLineFont, &horizontalEllipsis, 1, firstLineStyle()));
+ int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
// For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
// if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
@@ -2080,23 +2086,25 @@ void RenderBlockFlow::checkLinesForTextOverflow()
ETextAlign textAlign = style().textAlign();
bool firstLine = true;
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
- IndentTextOrNot shouldIndentText = firstLine ? IndentText : DoNotIndentText;
- LayoutUnit blockRightEdge = logicalRightOffsetForLine(curr->lineTop(), shouldIndentText);
- LayoutUnit blockLeftEdge = logicalLeftOffsetForLine(curr->lineTop(), shouldIndentText);
- LayoutUnit lineBoxEdge = ltr ? curr->x() + curr->logicalWidth() : curr->x();
+ // FIXME: Use pixelSnappedLogicalRightOffsetForLine instead of snapping it ourselves once the column workaround in said method has been fixed.
+ // https://bugs.webkit.org/show_bug.cgi?id=105461
+ int blockRightEdge = snapSizeToPixel(logicalRightOffsetForLine(curr->lineTop(), firstLine), curr->x());
+ int blockLeftEdge = pixelSnappedLogicalLeftOffsetForLine(curr->lineTop(), firstLine);
+ int lineBoxEdge = ltr ? snapSizeToPixel(curr->x() + curr->logicalWidth(), curr->x()) : snapSizeToPixel(curr->x(), 0);
if ((ltr && lineBoxEdge > blockRightEdge) || (!ltr && lineBoxEdge < blockLeftEdge)) {
// This line spills out of our box in the appropriate direction. Now we need to see if the line
// can be truncated. In order for truncation to be possible, the line must have sufficient space to
// accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
// space.
+
LayoutUnit width = firstLine ? firstLineEllipsisWidth : ellipsisWidth;
LayoutUnit blockEdge = ltr ? blockRightEdge : blockLeftEdge;
if (curr->lineCanAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width)) {
float totalLogicalWidth = curr->placeEllipsis(ellipsisStr, ltr, blockLeftEdge, blockRightEdge, width);
float logicalLeft = 0; // We are only interested in the delta from the base position.
- float truncatedWidth = availableLogicalWidthForLine(curr->lineTop(), shouldIndentText);
- updateLogicalWidthForAlignment(textAlign, curr, nullptr, logicalLeft, totalLogicalWidth, truncatedWidth, 0);
+ float truncatedWidth = pixelSnappedLogicalRightOffsetForLine(curr->lineTop(), firstLine);
+ updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, truncatedWidth, 0);
if (ltr)
curr->adjustLogicalPosition(logicalLeft, 0);
else
@@ -2107,7 +2115,7 @@ void RenderBlockFlow::checkLinesForTextOverflow()
}
}
-bool RenderBlockFlow::positionNewFloatOnLine(const FloatingObject& newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
+bool RenderBlockFlow::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
{
if (!positionNewFloats())
return false;
@@ -2117,14 +2125,14 @@ bool RenderBlockFlow::positionNewFloatOnLine(const FloatingObject& newFloat, Flo
// We only connect floats to lines for pagination purposes if the floats occur at the start of
// the line and the previous line had a hard break (so this line is either the first in the block
// or follows a <br>).
- if (!newFloat.paginationStrut() || !lineInfo.previousLineBrokeCleanly() || !lineInfo.isEmpty())
+ if (!newFloat->paginationStrut() || !lineInfo.previousLineBrokeCleanly() || !lineInfo.isEmpty())
return true;
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
- ASSERT(floatingObjectSet.last().get() == &newFloat);
+ ASSERT(floatingObjectSet.last().get() == newFloat);
LayoutUnit floatLogicalTop = logicalTopForFloat(newFloat);
- LayoutUnit paginationStrut = newFloat.paginationStrut();
+ int paginationStrut = newFloat->paginationStrut();
if (floatLogicalTop - paginationStrut != logicalHeight() + lineInfo.floatPaginationStrut())
return true;
@@ -2134,26 +2142,26 @@ bool RenderBlockFlow::positionNewFloatOnLine(const FloatingObject& newFloat, Flo
auto begin = floatingObjectSet.begin();
while (it != begin) {
--it;
- auto& floatingObject = *it->get();
- if (&floatingObject == lastFloatFromPreviousLine)
+ FloatingObject* floatingObject = it->get();
+ if (floatingObject == lastFloatFromPreviousLine)
break;
if (logicalTopForFloat(floatingObject) == logicalHeight() + lineInfo.floatPaginationStrut()) {
- floatingObject.setPaginationStrut(paginationStrut + floatingObject.paginationStrut());
- RenderBox& floatBox = floatingObject.renderer();
+ floatingObject->setPaginationStrut(paginationStrut + floatingObject->paginationStrut());
+ RenderBox& floatBox = floatingObject->renderer();
setLogicalTopForChild(floatBox, logicalTopForChild(floatBox) + marginBeforeForChild(floatBox) + paginationStrut);
- if (updateRegionRangeForBoxChild(floatBox))
+ if (updateRegionRangeForBoxChild(floatingObject->renderer()))
floatBox.setNeedsLayout(MarkOnlyThis);
- else if (is<RenderBlock>(floatBox))
- downcast<RenderBlock>(floatBox).setChildNeedsLayout(MarkOnlyThis);
+ else if (floatBox.isRenderBlock())
+ toRenderBlock(floatBox).setChildNeedsLayout(MarkOnlyThis);
floatBox.layoutIfNeeded();
// Save the old logical top before calling removePlacedObject which will set
// isPlaced to false. Otherwise it will trigger an assert in logicalTopForFloat.
LayoutUnit oldLogicalTop = logicalTopForFloat(floatingObject);
- m_floatingObjects->removePlacedObject(&floatingObject);
+ m_floatingObjects->removePlacedObject(floatingObject);
setLogicalTopForFloat(floatingObject, oldLogicalTop + paginationStrut);
- m_floatingObjects->addPlacedObject(&floatingObject);
+ m_floatingObjects->addPlacedObject(floatingObject);
}
}
@@ -2163,39 +2171,22 @@ bool RenderBlockFlow::positionNewFloatOnLine(const FloatingObject& newFloat, Flo
return true;
}
-LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, IndentTextOrNot shouldIndentText)
+LayoutUnit RenderBlockFlow::startAlignedOffsetForLine(LayoutUnit position, bool firstLine)
{
ETextAlign textAlign = style().textAlign();
- bool shouldApplyIndentText = false;
- switch (textAlign) {
- case LEFT:
- case WEBKIT_LEFT:
- shouldApplyIndentText = style().isLeftToRightDirection();
- break;
- case RIGHT:
- case WEBKIT_RIGHT:
- shouldApplyIndentText = !style().isLeftToRightDirection();
- break;
- case TASTART:
- shouldApplyIndentText = true;
- break;
- default:
- shouldApplyIndentText = false;
- }
+
// <rdar://problem/15427571>
// https://bugs.webkit.org/show_bug.cgi?id=124522
// This quirk is for legacy content that doesn't work properly with the center positioning scheme
// being honored (e.g., epubs).
- if (shouldApplyIndentText || document().settings()->useLegacyTextAlignPositionedElementBehavior()) // FIXME: Handle TAEND here
- return startOffsetForLine(position, shouldIndentText);
+ if (textAlign == TASTART || document().settings()->useLegacyTextAlignPositionedElementBehavior()) // FIXME: Handle TAEND here
+ return startOffsetForLine(position, firstLine);
// updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here
float totalLogicalWidth = 0;
- float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), DoNotIndentText);
- float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), DoNotIndentText) - logicalLeft;
-
- // FIXME: Bug 129311: We need to pass a valid RootInlineBox here, considering the bidi level used to construct the line.
- updateLogicalWidthForAlignment(textAlign, 0, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
+ float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false);
+ float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft;
+ updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0);
if (!style().isLeftToRightDirection())
return logicalWidth() - logicalLeft;
@@ -2206,14 +2197,10 @@ void RenderBlockFlow::updateRegionForLine(RootInlineBox* lineBox) const
{
ASSERT(lineBox);
- if (!hasRegionRangeInFlowThread())
+ if (auto containingRegion = regionAtBlockOffset(lineBox->lineTopWithLeading()))
+ lineBox->setContainingRegion(*containingRegion);
+ else
lineBox->clearContainingRegion();
- else {
- if (auto containingRegion = regionAtBlockOffset(lineBox->lineTopWithLeading()))
- lineBox->setContainingRegion(*containingRegion);
- else
- lineBox->clearContainingRegion();
- }
RootInlineBox* prevLineBox = lineBox->prevRootBox();
if (!prevLineBox)
@@ -2226,42 +2213,4 @@ void RenderBlockFlow::updateRegionForLine(RootInlineBox* lineBox) const
lineBox->setIsFirstAfterPageBreak(true);
}
-void RenderBlockFlow::marginCollapseLinesFromStart(LineLayoutState& layoutState, RootInlineBox* stopLine)
-{
- // We have to handle an anonymous inline block streak at the start of the block in order to make sure our own margins are
- // correct. We only have to do this if the children can propagate margins out to us.
- bool resetLogicalHeight = false;
- if (layoutState.marginInfo().canCollapseWithMarginBefore()) {
- RootInlineBox* startLine = firstRootBox();
- RootInlineBox* curr;
- for (curr = startLine; curr && curr->hasAnonymousInlineBlock() && layoutState.marginInfo().canCollapseWithMarginBefore(); curr = curr->nextRootBox()) {
- if (curr == stopLine)
- return;
- if (!resetLogicalHeight) {
- setLogicalHeight(borderAndPaddingBefore());
- resetLogicalHeight = true;
- }
- layoutBlockChild(*curr->anonymousInlineBlock(), layoutState.marginInfo(),
- layoutState.prevFloatBottomFromAnonymousInlineBlock(), layoutState.maxFloatBottomFromAnonymousInlineBlock());
- }
- }
-
- // Now that we've handled the top of the block, if the stopLine isn't an anonymous block, then we're done.
- if (!stopLine->hasAnonymousInlineBlock())
- return;
-
- // Re-run margin collapsing on the block sequence that stopLine is a part of.
- // First go backwards to get the entire sequence.
- RootInlineBox* prev = stopLine;
- for ( ; prev->hasAnonymousInlineBlock(); prev = prev->prevRootBox()) {
- };
-
- // Update the block height to the correct state.
- setLogicalHeight(prev->lineBottomWithLeading());
-
- // Now run margin collapsing on those lines.
- for (prev = prev->nextRootBox(); prev != stopLine; prev = prev->nextRootBox())
- layoutBlockChild(*prev->anonymousInlineBlock(), layoutState.marginInfo(), layoutState.prevFloatBottomFromAnonymousInlineBlock(), layoutState.maxFloatBottomFromAnonymousInlineBlock());
-}
-
}