summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/line
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-05-24 08:28:08 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-05-24 08:28:08 +0000
commita4e969f4965059196ca948db781e52f7cfebf19e (patch)
tree6ca352808c8fdc52006a0f33f6ae3c593b23867d /Source/WebCore/rendering/line
parent41386e9cb918eed93b3f13648cbef387e371e451 (diff)
downloadWebKitGtk-tarball-a4e969f4965059196ca948db781e52f7cfebf19e.tar.gz
webkitgtk-2.12.3webkitgtk-2.12.3
Diffstat (limited to 'Source/WebCore/rendering/line')
-rw-r--r--Source/WebCore/rendering/line/BreakingContext.h (renamed from Source/WebCore/rendering/line/BreakingContextInlineHeaders.h)687
-rw-r--r--Source/WebCore/rendering/line/LineBreaker.cpp79
-rw-r--r--Source/WebCore/rendering/line/LineBreaker.h20
-rw-r--r--Source/WebCore/rendering/line/LineInlineHeaders.h18
-rw-r--r--Source/WebCore/rendering/line/LineLayoutState.h15
-rw-r--r--Source/WebCore/rendering/line/LineWidth.cpp159
-rw-r--r--Source/WebCore/rendering/line/LineWidth.h32
-rw-r--r--Source/WebCore/rendering/line/TrailingObjects.cpp2
-rw-r--r--Source/WebCore/rendering/line/TrailingObjects.h4
9 files changed, 572 insertions, 444 deletions
diff --git a/Source/WebCore/rendering/line/BreakingContextInlineHeaders.h b/Source/WebCore/rendering/line/BreakingContext.h
index 33d296b28..c1f947689 100644
--- a/Source/WebCore/rendering/line/BreakingContextInlineHeaders.h
+++ b/Source/WebCore/rendering/line/BreakingContext.h
@@ -22,30 +22,27 @@
*
*/
-#ifndef BreakingContextInlineHeaders_h
-#define BreakingContextInlineHeaders_h
+#ifndef BreakingContext_h
+#define BreakingContext_h
#include "Hyphenation.h"
#include "LineBreaker.h"
#include "LineInfo.h"
+#include "LineLayoutState.h"
#include "LineWidth.h"
#include "RenderCombineText.h"
#include "RenderCounter.h"
#include "RenderInline.h"
+#include "RenderLineBreak.h"
#include "RenderListMarker.h"
#include "RenderRubyRun.h"
+#include "RenderSVGInlineText.h"
#include "TrailingObjects.h"
#include "break_lines.h"
+#include <wtf/Optional.h>
+#include <wtf/text/StringView.h>
#include <wtf/unicode/CharacterNames.h>
-#if ENABLE(SVG)
-#include "RenderSVGInlineText.h"
-#endif
-
-#if ENABLE(CSS_SHAPES)
-#include "ShapeInsideInfo.h"
-#endif
-
namespace WebCore {
// We don't let our line box tree for a single line get any deeper than this.
@@ -64,25 +61,59 @@ struct WordMeasurement {
float width;
int startOffset;
int endOffset;
- HashSet<const SimpleFontData*> fallbackFonts;
+ HashSet<const Font*> fallbackFonts;
+};
+
+struct WordTrailingSpace {
+ WordTrailingSpace(RenderText& renderer, const RenderStyle& style, TextLayout* textLayout = nullptr)
+ : m_renderer(renderer)
+ , m_style(style)
+ , m_textLayout(textLayout)
+ {
+ }
+
+ WTF::Optional<float> width(HashSet<const Font*>& fallbackFonts)
+ {
+ if (m_state == WordTrailingSpaceState::Computed)
+ return m_width;
+
+ const FontCascade& font = m_style.fontCascade();
+ if (font.enableKerning() && !m_textLayout)
+ m_width = font.width(RenderBlock::constructTextRun(&m_renderer, font, &space, 1, m_style), &fallbackFonts) + font.wordSpacing();
+ m_state = WordTrailingSpaceState::Computed;
+ return m_width;
+ }
+
+private:
+ enum class WordTrailingSpaceState { Uninitialized, Computed };
+ WordTrailingSpaceState m_state { WordTrailingSpaceState::Uninitialized };
+ WTF::Optional<float> m_width;
+ RenderText& m_renderer;
+ const RenderStyle& m_style;
+ TextLayout* m_textLayout { nullptr };
};
class BreakingContext {
public:
- BreakingContext(LineBreaker& lineBreaker, InlineBidiResolver& resolver, LineInfo& inLineInfo, LineWidth& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatFromPreviousLine, bool appliedStartWidth, RenderBlockFlow& block)
+ BreakingContext(LineBreaker& lineBreaker, InlineBidiResolver& resolver, LineInfo& inLineInfo, LineLayoutState& layoutState, LineWidth& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatFromPreviousLine, bool appliedStartWidth, RenderBlockFlow& block)
: m_lineBreaker(lineBreaker)
, m_resolver(resolver)
, m_current(resolver.position())
- , m_lineBreak(resolver.position())
+#if ENABLE(CSS_TRAILING_WORD)
+ , m_lineBreakHistory(InlineIterator(resolver.position()), block.style().trailingWord() == TrailingWord::PartiallyBalanced ? 5 : 1)
+#else
+ , m_lineBreakHistory(InlineIterator(resolver.position()), 1)
+#endif
, m_block(block)
, m_lastObject(m_current.renderer())
- , m_nextObject(0)
- , m_currentStyle(0)
+ , m_nextObject(nullptr)
+ , m_currentStyle(nullptr)
, m_blockStyle(block.style())
, m_lineInfo(inLineInfo)
, m_renderTextInfo(inRenderTextInfo)
, m_lastFloatFromPreviousLine(inLastFloatFromPreviousLine)
, m_width(lineWidth)
+ , m_lineLayoutState(layoutState)
, m_currWS(NORMAL)
, m_lastWS(NORMAL)
, m_preservesNewline(false)
@@ -106,8 +137,7 @@ public:
}
RenderObject* currentObject() { return m_current.renderer(); }
- InlineIterator lineBreak() { return m_lineBreak; }
- InlineIterator& lineBreakRef() {return m_lineBreak; }
+ InlineIterator lineBreak() { return m_lineBreakHistory.current(); }
LineWidth& lineWidth() { return m_width; }
bool atEnd() { return m_atEnd; }
@@ -124,32 +154,96 @@ public:
bool canBreakAtThisPosition();
void commitAndUpdateLineBreakIfNeeded();
InlineIterator handleEndOfLine();
+#if ENABLE(CSS_TRAILING_WORD)
+ InlineIterator optimalLineBreakLocationForTrailingWord();
+#endif
void clearLineBreakIfFitsOnLine(bool ignoringTrailingSpace = false)
{
if (m_width.fitsOnLine(ignoringTrailingSpace) || m_lastWS == NOWRAP)
- m_lineBreak.clear();
+ m_lineBreakHistory.clear();
}
- void commitLineBreakAtCurrentWidth(RenderObject* object, unsigned offset = 0, int nextBreak = -1)
+ void commitLineBreakAtCurrentWidth(RenderObject& object, unsigned offset = 0, int nextBreak = -1)
{
m_width.commit();
- m_lineBreak.moveTo(object, offset, nextBreak);
+ m_lineBreakHistory.moveTo(&object, offset, nextBreak);
}
private:
+ // This class keeps a sliding window of the past n locations for an InlineIterator.
+ class InlineIteratorHistory : private Vector<InlineIterator, 1> {
+ public:
+ InlineIteratorHistory() = delete;
+ InlineIteratorHistory(const InlineIterator& initial, size_t capacity)
+ : m_capacity(capacity)
+ {
+ ASSERT(capacity > 0);
+ this->append(initial);
+ }
+
+ void push(std::function<void(InlineIterator& modifyMe)> updater)
+ {
+ ASSERT(!this->isEmpty());
+ if (m_capacity != 1)
+ this->insert(0, InlineIterator(this->at(0)));
+ updater(this->at(0));
+ if (m_capacity != 1)
+ this->resize(m_capacity);
+ }
+
+ void update(std::function<void(InlineIterator& modifyMe)> updater)
+ {
+ ASSERT(!this->isEmpty());
+ updater(this->at(0));
+ }
+
+ RenderObject* renderer() const { return this->at(0).renderer(); }
+ unsigned offset() const { return this->at(0).offset(); }
+ int nextBreakablePosition() const { return this->at(0).nextBreakablePosition(); }
+ bool atTextParagraphSeparator() const { return this->at(0).atTextParagraphSeparator(); }
+ UChar previousInSameNode() const { return this->at(0).previousInSameNode(); }
+ const InlineIterator& get(size_t i) const { return this->at(i); };
+ const InlineIterator& current() const { return get(0); }
+ size_t historyLength() const { return this->size(); }
+
+ void moveTo(RenderObject* object, unsigned offset, int nextBreak = -1)
+ {
+ push([&](InlineIterator& modifyMe) {
+ modifyMe.moveTo(object, offset, nextBreak);
+ });
+ }
+
+ void increment()
+ {
+ update([](InlineIterator& modifyMe) {
+ modifyMe.increment();
+ });
+ }
+
+ void clear()
+ {
+ push([](InlineIterator& modifyMe) {
+ modifyMe.clear();
+ });
+ }
+
+ private:
+ const size_t m_capacity;
+ };
+
LineBreaker& m_lineBreaker;
InlineBidiResolver& m_resolver;
InlineIterator m_current;
- InlineIterator m_lineBreak;
+ InlineIteratorHistory m_lineBreakHistory;
InlineIterator m_startOfIgnoredSpaces;
RenderBlockFlow& m_block;
RenderObject* m_lastObject;
RenderObject* m_nextObject;
- RenderStyle* m_currentStyle;
+ const RenderStyle* m_currentStyle;
// Firefox and Opera will allow a table cell to grow to fit an image inside it under
// very specific circumstances (in order to match common WinIE renderings).
@@ -163,6 +257,8 @@ private:
FloatingObject* m_lastFloatFromPreviousLine;
LineWidth m_width;
+
+ LineLayoutState& m_lineLayoutState;
EWhiteSpace m_currWS;
EWhiteSpace m_lastWS;
@@ -199,7 +295,7 @@ inline void BreakingContext::initializeForCurrentObject()
{
m_hadUncommittedWidthBeforeCurrent = !!m_width.uncommittedWidth();
- m_currentStyle = &m_current.renderer()->style();
+ m_currentStyle = &m_current.renderer()->style(); // FIXME: Should this be &lineStyle(*m_current.renderer(), m_lineInfo); ?
ASSERT(m_currentStyle);
@@ -213,11 +309,7 @@ inline void BreakingContext::initializeForCurrentObject()
m_autoWrap = RenderStyle::autoWrap(m_currWS);
m_autoWrapWasEverTrueOnLine = m_autoWrapWasEverTrueOnLine || m_autoWrap;
-#if ENABLE(SVG)
m_preservesNewline = m_current.renderer()->isSVGInlineText() ? false : RenderStyle::preserveNewline(m_currWS);
-#else
- m_preservesNewline = RenderStyle::preserveNewline(m_currWS);
-#endif
m_collapseWhiteSpace = RenderStyle::collapseWhiteSpace(m_currWS);
}
@@ -237,8 +329,10 @@ inline void BreakingContext::handleBR(EClear& clear)
{
if (m_width.fitsOnLine()) {
RenderObject* br = m_current.renderer();
- m_lineBreak.moveToStartOf(br);
- m_lineBreak.increment();
+ m_lineBreakHistory.push([&](InlineIterator& modifyMe) {
+ modifyMe.moveToStartOf(br);
+ modifyMe.increment();
+ });
// A <br> always breaks a line, so don't let the line be collapsed
// away. Also, the space at the end of a line with a <br> does not
@@ -279,15 +373,23 @@ inline LayoutUnit borderPaddingMarginEnd(const RenderInline& child)
inline bool shouldAddBorderPaddingMargin(RenderObject* child)
{
+ if (!child)
+ return true;
// When deciding whether we're at the edge of an inline, adjacent collapsed whitespace is the same as no sibling at all.
- return !child || (child->isText() && !toRenderText(child)->textLength());
+ if (is<RenderText>(*child) && !downcast<RenderText>(*child).textLength())
+ return true;
+#if ENABLE(CSS_BOX_DECORATION_BREAK)
+ if (is<RenderLineBreak>(*child) && child->parent()->style().boxDecorationBreak() == DCLONE)
+ return true;
+#endif
+ return false;
}
inline RenderObject* previousInFlowSibling(RenderObject* child)
{
- child = child->previousSibling();
- while (child && child->isOutOfFlowPositioned())
+ do {
child = child->previousSibling();
+ } while (child && child->isOutOfFlowPositioned());
return child;
}
@@ -296,8 +398,8 @@ inline LayoutUnit inlineLogicalWidth(RenderObject* child, bool checkStartEdge =
unsigned lineDepth = 1;
LayoutUnit extraWidth = 0;
RenderElement* parent = child->parent();
- while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
- const RenderInline& parentAsRenderInline = toRenderInline(*parent);
+ while (is<RenderInline>(*parent) && lineDepth++ < cMaxLineDepth) {
+ const auto& parentAsRenderInline = downcast<RenderInline>(*parent);
if (!isEmptyInline(parentAsRenderInline)) {
checkStartEdge = checkStartEdge && shouldAddBorderPaddingMargin(previousInFlowSibling(child));
if (checkStartEdge)
@@ -316,50 +418,47 @@ inline LayoutUnit inlineLogicalWidth(RenderObject* child, bool checkStartEdge =
inline void BreakingContext::handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects)
{
- // If our original display wasn't an inline type, then we can
- // go ahead and determine our static inline position now.
- RenderBox* box = toRenderBox(m_current.renderer());
- bool isInlineType = box->style().isOriginalDisplayInlineType();
+ // If our original display wasn't an inline type, then we can determine our static inline position now.
+ auto& box = downcast<RenderBox>(*m_current.renderer());
+ bool isInlineType = box.style().isOriginalDisplayInlineType();
if (!isInlineType)
- m_block.setStaticInlinePositionForChild(*box, m_block.logicalHeight(), m_block.startOffsetForContent(m_block.logicalHeight()));
+ m_block.setStaticInlinePositionForChild(box, m_block.logicalHeight(), m_block.startOffsetForContent(m_block.logicalHeight()));
else {
- // If our original display was an INLINE type, then we can go ahead
- // and determine our static y position now.
- box->layer()->setStaticBlockPosition(m_block.logicalHeight());
+ // If our original display was an INLINE type, then we can determine our static y position now.
+ box.layer()->setStaticBlockPosition(m_block.logicalHeight());
}
// If we're ignoring spaces, we have to stop and include this object and
// then start ignoring spaces again.
- if (isInlineType || box->container()->isRenderInline()) {
+ if (isInlineType || box.container()->isRenderInline()) {
if (m_ignoringSpaces)
- m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(box);
- m_trailingObjects.appendBoxIfNeeded(box);
+ m_lineMidpointState.ensureLineBoxInsideIgnoredSpaces(&box);
+ m_trailingObjects.appendBoxIfNeeded(&box);
} else
- positionedObjects.append(box);
+ positionedObjects.append(&box);
- m_width.addUncommittedWidth(inlineLogicalWidth(box));
+ m_width.addUncommittedWidth(inlineLogicalWidth(&box));
// Reset prior line break context characters.
- m_renderTextInfo.m_lineBreakIterator.resetPriorContext();
+ m_renderTextInfo.lineBreakIterator.resetPriorContext();
}
inline void BreakingContext::handleFloat()
{
- RenderBox& floatBox = toRenderBox(*m_current.renderer());
- FloatingObject* floatingObject = m_lineBreaker.insertFloatingObject(floatBox);
+ auto& floatBox = downcast<RenderBox>(*m_current.renderer());
+ const auto& floatingObject = *m_lineBreaker.insertFloatingObject(floatBox);
// check if it fits in the current line.
// If it does, position it now, otherwise, position
- // it after moving to next line (in newLine() func)
- // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
+ // it after moving to next line (in clearFloats() func)
if (m_floatsFitOnLine && m_width.fitsOnLineExcludingTrailingWhitespace(m_block.logicalWidthForFloat(floatingObject))) {
m_lineBreaker.positionNewFloatOnLine(floatingObject, m_lastFloatFromPreviousLine, m_lineInfo, m_width);
- if (m_lineBreak.renderer() == m_current.renderer()) {
- ASSERT(!m_lineBreak.offset());
- m_lineBreak.increment();
+ if (m_lineBreakHistory.renderer() == m_current.renderer()) {
+ ASSERT(!m_lineBreakHistory.offset());
+ m_lineBreakHistory.increment();
}
} else
m_floatsFitOnLine = false;
// Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element.
- m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
+ m_renderTextInfo.lineBreakIterator.updatePriorContext(replacementCharacter);
}
// This is currently just used for list markers and inline flows that have line boxes. Neither should
@@ -370,11 +469,11 @@ inline bool shouldSkipWhitespaceAfterStartObject(RenderBlockFlow& block, RenderO
while (next && next->isFloatingOrOutOfFlowPositioned())
next = bidiNextSkippingEmptyInlines(block, next);
- if (next && next->isText() && toRenderText(next)->textLength() > 0) {
- RenderText* nextText = toRenderText(next);
- UChar nextChar = nextText->characterAt(0);
- if (nextText->style().isCollapsibleWhiteSpace(nextChar)) {
- lineMidpointState.startIgnoringSpaces(InlineIterator(0, o, 0));
+ if (is<RenderText>(next) && downcast<RenderText>(*next).textLength() > 0) {
+ RenderText& nextText = downcast<RenderText>(*next);
+ UChar nextChar = nextText.characterAt(0);
+ if (nextText.style().isCollapsibleWhiteSpace(nextChar)) {
+ lineMidpointState.startIgnoringSpaces(InlineIterator(nullptr, o, 0));
return true;
}
}
@@ -384,7 +483,7 @@ inline bool shouldSkipWhitespaceAfterStartObject(RenderBlockFlow& block, RenderO
inline void BreakingContext::handleEmptyInline()
{
- RenderInline& flowBox = toRenderInline(*m_current.renderer());
+ RenderInline& flowBox = downcast<RenderInline>(*m_current.renderer());
// This should only end up being called on empty inlines
ASSERT(isEmptyInline(flowBox));
@@ -418,16 +517,26 @@ inline void BreakingContext::handleEmptyInline()
inline void BreakingContext::handleReplaced()
{
- RenderBox& replacedBox = toRenderBox(*m_current.renderer());
+ auto& replacedBox = downcast<RenderBox>(*m_current.renderer());
if (m_atStart)
m_width.updateAvailableWidth(replacedBox.logicalHeight());
// Break on replaced elements if either has normal white-space.
- if ((m_autoWrap || RenderStyle::autoWrap(m_lastWS)) && (!m_current.renderer()->isImage() || m_allowImagesToBreak)) {
- m_width.commit();
- m_lineBreak.moveToStartOf(m_current.renderer());
+ if (((m_autoWrap || RenderStyle::autoWrap(m_lastWS)) && (!m_current.renderer()->isImage() || m_allowImagesToBreak)
+ && (!m_current.renderer()->isRubyRun() || downcast<RenderRubyRun>(m_current.renderer())->canBreakBefore(m_renderTextInfo.lineBreakIterator))) || replacedBox.isAnonymousInlineBlock()) {
+ commitLineBreakAtCurrentWidth(*m_current.renderer());
+ if (m_width.committedWidth() && replacedBox.isAnonymousInlineBlock()) {
+ // Always force a break before an anonymous inline block if there is content on the line
+ // already.
+ m_atEnd = true;
+ return;
+ }
}
+
+ if (replacedBox.isAnonymousInlineBlock())
+ m_block.layoutBlockChild(replacedBox, m_lineLayoutState.marginInfo(),
+ m_lineLayoutState.prevFloatBottomFromAnonymousInlineBlock(), m_lineLayoutState.maxFloatBottomFromAnonymousInlineBlock());
if (m_ignoringSpaces)
m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.renderer(), 0));
@@ -441,7 +550,7 @@ inline void BreakingContext::handleReplaced()
// Optimize for a common case. If we can't find whitespace after the list
// item, then this is all moot.
LayoutUnit replacedLogicalWidth = m_block.logicalWidthForChild(replacedBox) + m_block.marginStartForChild(replacedBox) + m_block.marginEndForChild(replacedBox) + inlineLogicalWidth(m_current.renderer());
- if (m_current.renderer()->isListMarker()) {
+ if (is<RenderListMarker>(*m_current.renderer())) {
if (m_blockStyle.collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.renderer(), m_lineMidpointState)) {
// Like with inline flows, we start ignoring spaces to make sure that any
// additional spaces we see will be discarded.
@@ -449,14 +558,22 @@ inline void BreakingContext::handleReplaced()
m_currentCharacterIsWS = false;
m_ignoringSpaces = true;
}
- if (toRenderListMarker(*m_current.renderer()).isInside())
- m_width.addUncommittedWidth(replacedLogicalWidth);
+ if (downcast<RenderListMarker>(*m_current.renderer()).isInside())
+ m_width.addUncommittedReplacedWidth(replacedLogicalWidth);
} else
- m_width.addUncommittedWidth(replacedLogicalWidth);
- if (m_current.renderer()->isRubyRun())
- m_width.applyOverhang(toRenderRubyRun(m_current.renderer()), m_lastObject, m_nextObject);
- // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
- m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter);
+ m_width.addUncommittedReplacedWidth(replacedLogicalWidth);
+ if (is<RenderRubyRun>(*m_current.renderer())) {
+ m_width.applyOverhang(downcast<RenderRubyRun>(m_current.renderer()), m_lastObject, m_nextObject);
+ downcast<RenderRubyRun>(m_current.renderer())->updatePriorContextFromCachedBreakIterator(m_renderTextInfo.lineBreakIterator);
+ } else {
+ // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
+ m_renderTextInfo.lineBreakIterator.updatePriorContext(replacementCharacter);
+ }
+
+ if (replacedBox.isAnonymousInlineBlock()) {
+ m_atEnd = true;
+ m_lineInfo.setPreviousLineBrokeCleanly(true);
+ }
}
inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)
@@ -468,49 +585,6 @@ inline float firstPositiveWidth(const WordMeasurements& wordMeasurements)
return 0;
}
-#if ENABLE(CSS_SHAPES)
-inline void updateSegmentsForShapes(RenderBlockFlow& block, const FloatingObject* lastFloatFromPreviousLine, const WordMeasurements& wordMeasurements, LineWidth& width, bool isFirstLine)
-{
- ASSERT(lastFloatFromPreviousLine);
-
- ShapeInsideInfo* shapeInsideInfo = block.layoutShapeInsideInfo();
- if (!lastFloatFromPreviousLine->isPlaced() || !shapeInsideInfo)
- return;
-
- bool isHorizontalWritingMode = block.isHorizontalWritingMode();
- LayoutUnit logicalOffsetFromShapeContainer = block.logicalOffsetFromShapeAncestorContainer(&shapeInsideInfo->owner()).height();
-
- LayoutUnit lineLogicalTop = block.logicalHeight() + logicalOffsetFromShapeContainer;
- LayoutUnit lineLogicalHeight = block.lineHeight(isFirstLine, isHorizontalWritingMode ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
- LayoutUnit lineLogicalBottom = lineLogicalTop + lineLogicalHeight;
-
- LayoutUnit floatLogicalTop = block.logicalTopForFloat(lastFloatFromPreviousLine);
- LayoutUnit floatLogicalBottom = block.logicalBottomForFloat(lastFloatFromPreviousLine);
-
- bool lineOverlapsWithFloat = (floatLogicalTop < lineLogicalBottom) && (lineLogicalTop < floatLogicalBottom);
- if (!lineOverlapsWithFloat)
- return;
-
- float minSegmentWidth = firstPositiveWidth(wordMeasurements);
-
- LayoutUnit floatLogicalWidth = block.logicalWidthForFloat(lastFloatFromPreviousLine);
- LayoutUnit availableLogicalWidth = block.logicalWidth() - block.logicalRightForFloat(lastFloatFromPreviousLine);
- if (availableLogicalWidth < minSegmentWidth)
- block.setLogicalHeight(floatLogicalBottom);
-
- if (block.logicalHeight() < floatLogicalTop) {
- shapeInsideInfo->adjustLogicalLineTop(minSegmentWidth + floatLogicalWidth);
- block.setLogicalHeight(shapeInsideInfo->logicalLineTop() - logicalOffsetFromShapeContainer);
- }
-
- lineLogicalTop = block.logicalHeight() + logicalOffsetFromShapeContainer;
-
- shapeInsideInfo->updateSegmentsForLine(lineLogicalTop, lineLogicalHeight);
- width.updateCurrentShapeSegment();
- width.updateAvailableWidth();
-}
-#endif
-
inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText& renderer)
{
return iter.renderer() == &renderer && iter.offset() >= renderer.textLength();
@@ -526,33 +600,33 @@ inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar&
// so we don't need this hack.
inline void updateCounterIfNeeded(RenderText& renderText)
{
- if (!renderText.preferredLogicalWidthsDirty() || !renderText.isCounter())
+ if (!renderText.preferredLogicalWidthsDirty() || !is<RenderCounter>(renderText))
return;
- toRenderCounter(renderText).updateCounter();
+ downcast<RenderCounter>(renderText).updateCounter();
}
-inline float measureHyphenWidth(RenderText* renderer, const Font& font, HashSet<const SimpleFontData*>* fallbackFonts = 0)
+inline float measureHyphenWidth(RenderText& renderer, const FontCascade& font, HashSet<const Font*>* fallbackFonts = 0)
{
- const RenderStyle& style = renderer->style();
- return font.width(RenderBlock::constructTextRun(renderer, font, style.hyphenString().string(), style), fallbackFonts);
+ const RenderStyle& style = renderer.style();
+ return font.width(RenderBlock::constructTextRun(&renderer, font, style.hyphenString().string(), style), fallbackFonts);
}
-ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const SimpleFontData*>& fallbackFonts, TextLayout* layout = 0)
+ALWAYS_INLINE float textWidth(RenderText& text, unsigned from, unsigned len, const FontCascade& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, HashSet<const Font*>& fallbackFonts, TextLayout* layout = nullptr)
{
- const RenderStyle& style = text->style();
+ const RenderStyle& style = text.style();
GlyphOverflow glyphOverflow;
- if (isFixedPitch || (!from && len == text->textLength()) || style.hasTextCombine())
- return text->width(from, len, font, xPos, &fallbackFonts, &glyphOverflow);
+ if (isFixedPitch || (!from && len == text.textLength()) || style.hasTextCombine())
+ return text.width(from, len, font, xPos, &fallbackFonts, &glyphOverflow);
if (layout)
- return Font::width(*layout, from, len, &fallbackFonts);
+ return FontCascade::width(*layout, from, len, &fallbackFonts);
- TextRun run = RenderBlock::constructTextRun(text, font, text, from, len, style);
- run.setCharactersLength(text->textLength() - from);
+ TextRun run = RenderBlock::constructTextRun(&text, font, &text, from, len, style);
+ run.setCharactersLength(text.textLength() - from);
ASSERT(run.charactersLength() >= run.length());
- run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());
+ run.setCharacterScanForCodePath(!text.canUseSimpleFontCodePath());
run.setTabSize(!collapseWhiteSpace, style.tabSize());
run.setXPos(xPos);
return font.width(run, &fallbackFonts, &glyphOverflow);
@@ -566,7 +640,7 @@ inline void ensureCharacterGetsLineBox(LineMidpointState& lineMidpointState, Inl
lineMidpointState.stopIgnoringSpaces(InlineIterator(0, textParagraphSeparator.renderer(), textParagraphSeparator.offset()));
}
-inline void tryHyphenating(RenderText* text, const Font& font, const AtomicString& localeIdentifier, unsigned consecutiveHyphenatedLines, int consecutiveHyphenatedLinesLimit, int minimumPrefixLimit, int minimumSuffixLimit, unsigned lastSpace, unsigned pos, float xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated)
+inline void tryHyphenating(RenderText& text, const FontCascade& font, const AtomicString& localeIdentifier, unsigned consecutiveHyphenatedLines, int consecutiveHyphenatedLinesLimit, int minimumPrefixLimit, int minimumSuffixLimit, unsigned lastSpace, unsigned pos, float xPos, int availableWidth, bool isFixedPitch, bool collapseWhiteSpace, int lastSpaceWordSpacing, InlineIterator& lineBreak, int nextBreakable, bool& hyphenated)
{
// Map 'hyphenate-limit-{before,after}: auto;' to 2.
unsigned minimumPrefixLength;
@@ -596,9 +670,9 @@ inline void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
if (maxPrefixWidth <= font.pixelSize() * 5 / 4)
return;
- const RenderStyle& style = text->style();
- TextRun run = RenderBlock::constructTextRun(text, font, text, lastSpace, pos - lastSpace, style);
- run.setCharactersLength(text->textLength() - lastSpace);
+ const RenderStyle& style = text.style();
+ TextRun run = RenderBlock::constructTextRun(&text, font, &text, lastSpace, pos - lastSpace, style);
+ run.setCharactersLength(text.textLength() - lastSpace);
ASSERT(run.charactersLength() >= run.length());
run.setTabSize(!collapseWhiteSpace, style.tabSize());
@@ -608,14 +682,14 @@ inline void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
if (prefixLength < minimumPrefixLength)
return;
- prefixLength = lastHyphenLocation(text->deprecatedCharacters() + lastSpace, pos - lastSpace, std::min(prefixLength, pos - lastSpace - minimumSuffixLength) + 1, localeIdentifier);
+ prefixLength = lastHyphenLocation(StringView(text.text()).substring(lastSpace, pos - lastSpace), std::min(prefixLength, pos - lastSpace - minimumSuffixLength) + 1, localeIdentifier);
if (!prefixLength || prefixLength < minimumPrefixLength)
return;
- // When lastSapce is a space, which it always is except sometimes at the beginning of a line or after collapsed
+ // When lastSpace is a space, which it always is except sometimes at the beginning of a line or after collapsed
// space, it should not count towards hyphenate-limit-before.
if (prefixLength == minimumPrefixLength) {
- UChar characterAtLastSpace = text->characterAt(lastSpace);
+ UChar characterAtLastSpace = text.characterAt(lastSpace);
if (characterAtLastSpace == ' ' || characterAtLastSpace == '\n' || characterAtLastSpace == '\t' || characterAtLastSpace == noBreakSpace)
return;
}
@@ -623,14 +697,14 @@ inline void tryHyphenating(RenderText* text, const Font& font, const AtomicStrin
ASSERT(pos - lastSpace - prefixLength >= minimumSuffixLength);
#if !ASSERT_DISABLED
- HashSet<const SimpleFontData*> fallbackFonts;
+ HashSet<const Font*> fallbackFonts;
float prefixWidth = hyphenWidth + textWidth(text, lastSpace, prefixLength, font, xPos, isFixedPitch, collapseWhiteSpace, fallbackFonts) + lastSpaceWordSpacing;
ASSERT(xPos + prefixWidth <= availableWidth);
#else
UNUSED_PARAM(isFixedPitch);
#endif
- lineBreak.moveTo(text, lastSpace + prefixLength, nextBreakable);
+ lineBreak.moveTo(&text, lastSpace + prefixLength, nextBreakable);
hyphenated = true;
}
@@ -639,35 +713,33 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
if (!m_current.offset())
m_appliedStartWidth = false;
- RenderText* renderText = toRenderText(m_current.renderer());
+ RenderText& renderText = downcast<RenderText>(*m_current.renderer());
-#if ENABLE(SVG)
- bool isSVGText = renderText->isSVGInlineText();
-#endif
+ bool isSVGText = renderText.isSVGInlineText();
// If we have left a no-wrap inline and entered an autowrap inline while ignoring spaces
// then we need to mark the start of the autowrap inline as a potential linebreak now.
if (m_autoWrap && !RenderStyle::autoWrap(m_lastWS) && m_ignoringSpaces)
- commitLineBreakAtCurrentWidth(m_current.renderer());
+ commitLineBreakAtCurrentWidth(renderText);
- if (renderText->style().hasTextCombine() && m_current.renderer()->isCombineText() && !toRenderCombineText(*m_current.renderer()).isCombined()) {
- RenderCombineText& combineRenderer = toRenderCombineText(*m_current.renderer());
+ if (renderText.style().hasTextCombine() && is<RenderCombineText>(*m_current.renderer())) {
+ auto& combineRenderer = downcast<RenderCombineText>(*m_current.renderer());
combineRenderer.combineText();
// The length of the renderer's text may have changed. Increment stale iterator positions
- if (iteratorIsBeyondEndOfRenderCombineText(m_lineBreak, combineRenderer)) {
+ if (iteratorIsBeyondEndOfRenderCombineText(m_lineBreakHistory.current(), combineRenderer)) {
ASSERT(iteratorIsBeyondEndOfRenderCombineText(m_resolver.position(), combineRenderer));
- m_lineBreak.increment();
+ m_lineBreakHistory.increment();
m_resolver.increment();
}
}
- const RenderStyle& style = lineStyle(*renderText->parent(), m_lineInfo);
- const Font& font = style.font();
+ const RenderStyle& style = lineStyle(renderText, m_lineInfo);
+ const FontCascade& font = style.fontCascade();
bool isFixedPitch = font.isFixedPitch();
bool canHyphenate = style.hyphens() == HyphensAuto && WebCore::canHyphenate(style.locale());
unsigned lastSpace = m_current.offset();
- float wordSpacing = m_currentStyle->font().wordSpacing();
+ float wordSpacing = m_currentStyle->fontCascade().wordSpacing();
float lastSpaceWordSpacing = 0;
float wordSpacingForWordMeasurement = 0;
@@ -676,38 +748,40 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
bool breakNBSP = m_autoWrap && m_currentStyle->nbspMode() == SPACE;
// Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
// which is only possible if the word is the first thing on the line, that is, if |w| is zero.
- bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.committedWidth()) || m_currWS == PRE);
+ bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.hasCommitted()) || m_currWS == PRE);
bool midWordBreak = false;
bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap;
+ bool keepAllWords = m_currentStyle->wordBreak() == KeepAllWordBreak;
float hyphenWidth = 0;
-#if ENABLE(SVG)
+ bool isLooseCJKMode = false;
+
if (isSVGText) {
breakWords = false;
breakAll = false;
}
-#endif
- if (m_renderTextInfo.m_text != renderText) {
- updateCounterIfNeeded(*renderText);
- m_renderTextInfo.m_text = renderText;
- m_renderTextInfo.m_font = &font;
- m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
- m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(renderText->text(), style.locale());
- } else if (m_renderTextInfo.m_layout && m_renderTextInfo.m_font != &font) {
- m_renderTextInfo.m_font = &font;
- m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
+ if (m_renderTextInfo.text != &renderText) {
+ updateCounterIfNeeded(renderText);
+ m_renderTextInfo.text = &renderText;
+ m_renderTextInfo.font = &font;
+ m_renderTextInfo.layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
+ m_renderTextInfo.lineBreakIterator.resetStringAndReleaseIterator(renderText.text(), style.locale(), mapLineBreakToIteratorMode(m_blockStyle.lineBreak()));
+ isLooseCJKMode = m_renderTextInfo.lineBreakIterator.isLooseCJKMode();
+ } else if (m_renderTextInfo.layout && m_renderTextInfo.font != &font) {
+ m_renderTextInfo.font = &font;
+ m_renderTextInfo.layout = font.createLayout(renderText, m_width.currentWidth(), m_collapseWhiteSpace);
}
- TextLayout* textLayout = m_renderTextInfo.m_layout.get();
+ TextLayout* textLayout = m_renderTextInfo.layout.get();
// Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
// words with their trailing space, then subtract its width.
- HashSet<const SimpleFontData*> fallbackFonts;
- float wordTrailingSpaceWidth = (font.typesettingFeatures() & Kerning) && !textLayout ? font.width(RenderBlock::constructTextRun(renderText, font, &space, 1, style), &fallbackFonts) + wordSpacing : 0;
-
- UChar lastCharacter = m_renderTextInfo.m_lineBreakIterator.lastCharacter();
- UChar secondToLastCharacter = m_renderTextInfo.m_lineBreakIterator.secondToLastCharacter();
- for (; m_current.offset() < renderText->textLength(); m_current.fastIncrementInTextNode()) {
+ HashSet<const Font*> fallbackFonts;
+ UChar lastCharacterFromPreviousRenderText = m_renderTextInfo.lineBreakIterator.lastCharacter();
+ UChar lastCharacter = m_renderTextInfo.lineBreakIterator.lastCharacter();
+ UChar secondToLastCharacter = m_renderTextInfo.lineBreakIterator.secondToLastCharacter();
+ WordTrailingSpace wordTrailingSpace(renderText, style, textLayout);
+ for (; m_current.offset() < renderText.textLength(); m_current.fastIncrementInTextNode()) {
bool previousCharacterIsSpace = m_currentCharacterIsSpace;
bool previousCharacterIsWS = m_currentCharacterIsWS;
UChar c = m_current.current();
@@ -727,13 +801,13 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
if ((breakAll || breakWords) && !midWordBreak && (!m_currentCharacterIsSpace || style.whiteSpace() != PRE_WRAP)) {
wrapW += charWidth;
- bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.offset() + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.offset() + 1]);
+ bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.offset() + 1 < renderText.textLength() && U16_IS_TRAIL(renderText[m_current.offset() + 1]);
charWidth = textWidth(renderText, m_current.offset(), midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, fallbackFonts, textLayout);
midWordBreak = m_width.committedWidth() + wrapW + charWidth > m_width.availableWidth();
}
int nextBreakablePosition = m_current.nextBreakablePosition();
- bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP)
+ bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.lineBreakIterator, m_current.offset(), nextBreakablePosition, breakNBSP, isLooseCJKMode, keepAllWords)
&& (style.hyphens() != HyphensNone || (m_current.previousInSameNode() != softHyphen)));
m_current.setNextBreakablePosition(nextBreakablePosition);
@@ -759,13 +833,18 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
wordMeasurements.grow(wordMeasurements.size() + 1);
WordMeasurement& wordMeasurement = wordMeasurements.last();
- wordMeasurement.renderer = renderText;
+ wordMeasurement.renderer = &renderText;
wordMeasurement.endOffset = m_current.offset();
wordMeasurement.startOffset = lastSpace;
float additionalTempWidth;
- if (wordTrailingSpaceWidth && c == ' ')
- additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
+ WTF::Optional<float> wordTrailingSpaceWidth;
+ if (c == ' ')
+ wordTrailingSpaceWidth = wordTrailingSpace.width(fallbackFonts);
+ if (wordTrailingSpaceWidth) {
+ additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace,
+ wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth.value();
+ }
else
additionalTempWidth = textWidth(renderText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
@@ -785,14 +864,10 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
m_appliedStartWidth = true;
}
-#if ENABLE(CSS_SHAPES)
- if (m_lastFloatFromPreviousLine)
- updateSegmentsForShapes(m_block, m_lastFloatFromPreviousLine, wordMeasurements, m_width, m_lineInfo.isFirstLine());
-#endif
applyWordSpacing = wordSpacing && m_currentCharacterIsSpace;
- if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine())
- m_width.fitBelowFloats();
+ if (!m_width.hasCommitted() && m_autoWrap && !m_width.fitsOnLine())
+ m_width.fitBelowFloats(m_lineInfo.isFirstLine());
if (m_autoWrap || breakWords) {
// If we break only after white-space, consider the current character
@@ -807,30 +882,59 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
// additional whitespace.
if (!m_width.fitsOnLineIncludingExtraWidth(charWidth)) {
lineWasTooWide = true;
- m_lineBreak.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
- m_lineBreaker.skipTrailingWhitespace(m_lineBreak, m_lineInfo);
+ m_lineBreakHistory.push([&](InlineIterator& modifyMe) {
+ modifyMe.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
+ m_lineBreaker.skipTrailingWhitespace(modifyMe, m_lineInfo);
+ });
}
}
if (lineWasTooWide || !m_width.fitsOnLine()) {
if (canHyphenate && !m_width.fitsOnLine()) {
- tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
+ m_lineBreakHistory.push([&](InlineIterator& modifyMe) {
+ tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, modifyMe, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
+ });
if (m_lineBreaker.m_hyphenated) {
m_atEnd = true;
return false;
}
}
- if (m_lineBreak.atTextParagraphSeparator()) {
+ if (m_lineBreakHistory.atTextParagraphSeparator()) {
if (!stoppedIgnoringSpaces && m_current.offset() > 0)
ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
- m_lineBreak.increment();
+ m_lineBreakHistory.increment();
m_lineInfo.setPreviousLineBrokeCleanly(true);
- wordMeasurement.endOffset = m_lineBreak.offset();
+ wordMeasurement.endOffset = m_lineBreakHistory.offset();
}
- if (m_lineBreak.renderer() && m_lineBreak.offset() && m_lineBreak.renderer()->isText() && toRenderText(m_lineBreak.renderer())->textLength() && toRenderText(m_lineBreak.renderer())->characterAt(m_lineBreak.offset() - 1) == softHyphen && style.hyphens() != HyphensNone)
- hyphenated = true;
- if (m_lineBreak.offset() && m_lineBreak.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
+ // Check if the last breaking position is a soft-hyphen.
+ if (!hyphenated && style.hyphens() != HyphensNone) {
+ Optional<int> lastBreakingPositon;
+ const RenderObject* rendererAtBreakingPosition = nullptr;
+ if (m_lineBreakHistory.offset() || m_lineBreakHistory.nextBreakablePosition() > -1) {
+ lastBreakingPositon = m_lineBreakHistory.offset();
+ rendererAtBreakingPosition = m_lineBreakHistory.renderer();
+ } else if (m_current.nextBreakablePosition() > -1 && (unsigned)m_current.nextBreakablePosition() <= m_current.offset()) {
+ // We might just be right after the soft-hyphen
+ lastBreakingPositon = m_current.nextBreakablePosition();
+ rendererAtBreakingPosition = m_current.renderer();
+ }
+ if (lastBreakingPositon) {
+ Optional<UChar> characterBeforeBreakingPosition;
+ // When last breaking position points to the start of the current context, we need to look at the last character from
+ // the previous non-empty text renderer.
+ if (!lastBreakingPositon.value())
+ characterBeforeBreakingPosition = lastCharacterFromPreviousRenderText;
+ else if (is<RenderText>(rendererAtBreakingPosition)) {
+ const auto& textRenderer = downcast<RenderText>(*rendererAtBreakingPosition);
+ ASSERT(textRenderer.textLength() > (unsigned)(lastBreakingPositon.value() - 1));
+ characterBeforeBreakingPosition = textRenderer.characterAt(lastBreakingPositon.value() - 1);
+ }
+ if (characterBeforeBreakingPosition)
+ hyphenated = characterBeforeBreakingPosition.value() == softHyphen;
+ }
+ }
+ if (m_lineBreakHistory.offset() && m_lineBreakHistory.offset() != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) {
if (charWidth) {
- wordMeasurement.endOffset = m_lineBreak.offset();
+ wordMeasurement.endOffset = m_lineBreakHistory.offset();
wordMeasurement.width = charWidth;
}
}
@@ -853,16 +957,15 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
if (c == '\n' && m_preservesNewline) {
if (!stoppedIgnoringSpaces && m_current.offset())
ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
- m_lineBreak.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
- m_lineBreak.increment();
+ commitLineBreakAtCurrentWidth(*m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
+ m_lineBreakHistory.increment();
m_lineInfo.setPreviousLineBrokeCleanly(true);
return true;
}
if (m_autoWrap && betweenWords) {
- m_width.commit();
+ commitLineBreakAtCurrentWidth(*m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
wrapW = 0;
- m_lineBreak.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
// Auto-wrapping text should not wrap in the middle of a word once it has had an
// opportunity to break after a word.
breakWords = false;
@@ -871,7 +974,7 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
if (midWordBreak && !U16_IS_TRAIL(c) && !(U_GET_GC_MASK(c) & U_GC_M_MASK)) {
// Remember this as a breakable position in case
// adding the end width forces a break.
- m_lineBreak.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
+ m_lineBreakHistory.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
midWordBreak &= (breakWords || breakAll);
}
@@ -882,9 +985,8 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
}
if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) {
- // If we encounter a newline, or if we encounter a
- // second space, we need to go ahead and break up this
- // run and enter a mode where we start collapsing spaces.
+ // If we encounter a newline, or if we encounter a second space,
+ // we need to break up this run and enter a mode where we start collapsing spaces.
if (m_currentCharacterIsSpace && previousCharacterIsSpace) {
m_ignoringSpaces = true;
@@ -902,15 +1004,14 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0;
lastSpace = m_current.offset(); // e.g., "Foo goo", don't add in any of the ignored spaces.
- m_lineMidpointState.stopIgnoringSpaces(InlineIterator(0, m_current.renderer(), m_current.offset()));
+ m_lineMidpointState.stopIgnoringSpaces(InlineIterator(nullptr, m_current.renderer(), m_current.offset()));
}
-#if ENABLE(SVG)
+
if (isSVGText && m_current.offset()) {
// Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks).
- if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m_current.offset()))
+ if (downcast<RenderSVGInlineText>(renderText).characterStartsNewTextChunk(m_current.offset()))
ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
}
-#endif
if (m_currentCharacterIsSpace && !previousCharacterIsSpace) {
m_startOfIgnoredSpaces.setRenderer(m_current.renderer());
@@ -918,21 +1019,21 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
// Spaces after right-aligned text and before a line-break get collapsed away completely so that the trailing
// space doesn't seem to push the text out from the right-hand edge.
// FIXME: Do this regardless of the container's alignment - will require rebaselining a lot of test results.
- if (m_nextObject && m_nextObject->isBR() && (m_blockStyle.textAlign() == RIGHT || m_blockStyle.textAlign() == WEBKIT_RIGHT)) {
+ if (m_nextObject && m_startOfIgnoredSpaces.offset() && m_nextObject->isBR() && (m_blockStyle.textAlign() == RIGHT || m_blockStyle.textAlign() == WEBKIT_RIGHT)) {
m_startOfIgnoredSpaces.setOffset(m_startOfIgnoredSpaces.offset() - 1);
// If there's just a single trailing space start ignoring it now so it collapses away.
- if (m_current.offset() == renderText->textLength() - 1)
+ if (m_current.offset() == renderText.textLength() - 1)
m_lineMidpointState.startIgnoringSpaces(m_startOfIgnoredSpaces);
}
}
if (!m_currentCharacterIsWS && previousCharacterIsWS) {
if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace())
- m_lineBreak.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
+ m_lineBreakHistory.moveTo(m_current.renderer(), m_current.offset(), m_current.nextBreakablePosition());
}
if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces)
- m_trailingObjects.setTrailingWhitespace(toRenderText(m_current.renderer()));
+ m_trailingObjects.setTrailingWhitespace(downcast<RenderText>(m_current.renderer()));
else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace)
m_trailingObjects.clear();
@@ -940,11 +1041,11 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
nextCharacter(c, lastCharacter, secondToLastCharacter);
}
- m_renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
+ m_renderTextInfo.lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter);
wordMeasurements.grow(wordMeasurements.size() + 1);
WordMeasurement& wordMeasurement = wordMeasurements.last();
- wordMeasurement.renderer = renderText;
+ wordMeasurement.renderer = &renderText;
// IMPORTANT: current.m_pos is > length here!
float additionalTempWidth = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpace, m_current.offset() - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, wordMeasurement.fallbackFonts, textLayout);
@@ -966,10 +1067,13 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
m_includeEndWidth = false;
if (!m_width.fitsOnLine()) {
- if (canHyphenate)
- tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, m_lineBreak, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
+ if (canHyphenate) {
+ m_lineBreakHistory.push([&](InlineIterator& modifyMe) {
+ tryHyphenating(renderText, font, style.locale(), consecutiveHyphenatedLines, m_blockStyle.hyphenationLimitLines(), style.hyphenationLimitBefore(), style.hyphenationLimitAfter(), lastSpace, m_current.offset(), m_width.currentWidth() - additionalTempWidth, m_width.availableWidth(), isFixedPitch, m_collapseWhiteSpace, lastSpaceWordSpacing, modifyMe, m_current.nextBreakablePosition(), m_lineBreaker.m_hyphenated);
+ });
+ }
- if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphen && style.hyphens() != HyphensNone) {
+ if (!hyphenated && m_lineBreakHistory.previousInSameNode() == softHyphen && style.hyphens() != HyphensNone) {
hyphenated = true;
m_atEnd = true;
}
@@ -977,14 +1081,10 @@ inline bool BreakingContext::handleText(WordMeasurements& wordMeasurements, bool
return false;
}
-inline bool textBeginsWithBreakablePosition(RenderObject* next)
+inline bool textBeginsWithBreakablePosition(RenderText& nextText)
{
- ASSERT(next->isText());
- RenderText* nextText = toRenderText(next);
- if (!nextText->textLength())
- return false;
- UChar c = nextText->characterAt(0);
- return c == ' ' || c == '\t' || (c == '\n' && !nextText->preservesNewline());
+ UChar c = nextText.characterAt(0);
+ return c == ' ' || c == '\t' || (c == '\n' && !nextText.preservesNewline());
}
inline bool BreakingContext::canBreakAtThisPosition()
@@ -993,8 +1093,12 @@ inline bool BreakingContext::canBreakAtThisPosition()
if (m_width.committedWidth() && !m_width.fitsOnLine(m_currentCharacterIsSpace) && m_currWS == NOWRAP)
return true;
- // Avoid breaking before empty inlines.
- if (m_nextObject && m_nextObject->isRenderInline() && isEmptyInline(toRenderInline(*m_nextObject)))
+ // Avoid breaking on empty inlines.
+ if (is<RenderInline>(*m_current.renderer()) && isEmptyInline(downcast<RenderInline>(*m_current.renderer())))
+ return false;
+
+ // Avoid breaking before empty inlines (as long as the current object isn't replaced).
+ if (!m_current.renderer()->isReplaced() && is<RenderInline>(m_nextObject) && isEmptyInline(downcast<RenderInline>(*m_nextObject)))
return false;
// Return early if we autowrap and the current character is a space as we will always want to break at such a position.
@@ -1004,23 +1108,24 @@ inline bool BreakingContext::canBreakAtThisPosition()
if (m_nextObject && m_nextObject->isLineBreakOpportunity())
return m_autoWrap;
- bool nextIsAutoWrappingText = (m_nextObject && m_nextObject->isText() && (m_autoWrap || m_nextObject->style().autoWrap()));
+ bool nextIsAutoWrappingText = is<RenderText>(m_nextObject) && (m_autoWrap || m_nextObject->style().autoWrap());
if (!nextIsAutoWrappingText)
return m_autoWrap;
- bool currentIsTextOrEmptyInline = m_current.renderer()->isText() || (m_current.renderer()->isRenderInline() && isEmptyInline(toRenderInline(*m_current.renderer())));
+ RenderText& nextRenderText = downcast<RenderText>(*m_nextObject);
+ bool currentIsTextOrEmptyInline = is<RenderText>(*m_current.renderer()) || (is<RenderInline>(*m_current.renderer()) && isEmptyInline(downcast<RenderInline>(*m_current.renderer())));
if (!currentIsTextOrEmptyInline)
- return m_autoWrap;
+ return m_autoWrap && !m_current.renderer()->isRubyRun();
- bool canBreakHere = !m_currentCharacterIsSpace && textBeginsWithBreakablePosition(m_nextObject);
+ bool canBreakHere = !m_currentCharacterIsSpace && textBeginsWithBreakablePosition(nextRenderText);
// See if attempting to fit below floats creates more available width on the line.
- if (!m_width.fitsOnLine() && !m_width.committedWidth())
- m_width.fitBelowFloats();
+ if (!m_width.fitsOnLine() && !m_width.hasCommitted())
+ m_width.fitBelowFloats(m_lineInfo.isFirstLine());
bool canPlaceOnLine = m_width.fitsOnLine() || !m_autoWrapWasEverTrueOnLine;
if (canPlaceOnLine && canBreakHere)
- commitLineBreakAtCurrentWidth(m_nextObject);
+ commitLineBreakAtCurrentWidth(nextRenderText);
return canBreakHere;
}
@@ -1039,7 +1144,7 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded()
return;
}
- m_width.fitBelowFloats();
+ m_width.fitBelowFloats(m_lineInfo.isFirstLine());
// |width| may have been adjusted because we got shoved down past a float (thus
// giving us more room), so we need to retest, and only jump to
@@ -1048,22 +1153,20 @@ inline void BreakingContext::commitAndUpdateLineBreakIfNeeded()
m_atEnd = true;
return;
}
- } else if (m_blockStyle.autoWrap() && !m_width.fitsOnLine() && !m_width.committedWidth()) {
+ } else if (m_blockStyle.autoWrap() && !m_width.fitsOnLine() && !m_width.hasCommitted()) {
// If the container autowraps but the current child does not then we still need to ensure that it
// wraps and moves below any floats.
- m_width.fitBelowFloats();
+ m_width.fitBelowFloats(m_lineInfo.isFirstLine());
}
if (!m_current.renderer()->isFloatingOrOutOfFlowPositioned()) {
m_lastObject = m_current.renderer();
- if (m_lastObject->isReplaced() && m_autoWrap && (!m_lastObject->isImage() || m_allowImagesToBreak) && (!m_lastObject->isListMarker() || toRenderListMarker(*m_lastObject).isInside())) {
- m_width.commit();
- m_lineBreak.moveToStartOf(m_nextObject);
- }
+ if (m_lastObject->isReplaced() && m_autoWrap && !m_lastObject->isRubyRun() && (!m_lastObject->isImage() || m_allowImagesToBreak) && (!is<RenderListMarker>(*m_lastObject) || downcast<RenderListMarker>(*m_lastObject).isInside()))
+ commitLineBreakAtCurrentWidth(*m_nextObject);
}
}
-inline void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak)
+inline TrailingObjects::CollapseFirstSpaceOrNot checkMidpoints(LineMidpointState& lineMidpointState, const InlineIterator& lBreak)
{
// Check to see if our last midpoint is a start point beyond the line break. If so,
// shave it off the list, and shave off a trailing space if the previous end point doesn't
@@ -1077,63 +1180,101 @@ inline void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator&
currpoint.increment();
if (currpoint == lBreak) {
// We hit the line break before the start point. Shave off the start point.
- lineMidpointState.decreaseNumMidpoints();
- if (endpoint.renderer()->style().collapseWhiteSpace() && endpoint.renderer()->isText())
- endpoint.setOffset(endpoint.offset() - 1);
+ lineMidpointState.decrementNumMidpoints();
+ if (endpoint.renderer()->style().collapseWhiteSpace() && endpoint.renderer()->isText()) {
+ endpoint.fastDecrement();
+ return TrailingObjects::DoNotCollapseFirstSpace;
+ }
}
}
+ return TrailingObjects::CollapseFirstSpace;
}
inline InlineIterator BreakingContext::handleEndOfLine()
{
-#if ENABLE(CSS_SHAPES)
- ShapeInsideInfo* shapeInfo = m_block.layoutShapeInsideInfo();
- bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments();
-#else
- bool segmentAllowsOverflow = true;
-#endif
- if (segmentAllowsOverflow) {
- if (m_lineBreak == m_resolver.position()) {
- if (!m_lineBreak.renderer() || !m_lineBreak.renderer()->isBR()) {
- // we just add as much as possible
- if (m_blockStyle.whiteSpace() == PRE && !m_current.offset()) {
- m_lineBreak.moveTo(m_lastObject, m_lastObject->isText() ? m_lastObject->length() : 0);
- } else if (m_lineBreak.renderer()) {
- // Don't ever break in the middle of a word if we can help it.
- // There's no room at all. We just have to be on this line,
- // even though we'll spill out.
- m_lineBreak.moveTo(m_current.renderer(), m_current.offset());
- }
+ if (m_lineBreakHistory.current() == m_resolver.position()) {
+ if (!m_lineBreakHistory.renderer() || !m_lineBreakHistory.renderer()->isBR()) {
+ // we just add as much as possible
+ if (m_blockStyle.whiteSpace() == PRE && !m_current.offset())
+ commitLineBreakAtCurrentWidth(*m_lastObject, m_lastObject->isText() ? m_lastObject->length() : 0);
+ else if (m_lineBreakHistory.renderer()) {
+ // Don't ever break in the middle of a word if we can help it.
+ // There's no room at all. We just have to be on this line,
+ // even though we'll spill out.
+ commitLineBreakAtCurrentWidth(*m_current.renderer(), m_current.offset());
}
- // make sure we consume at least one char/object.
- if (m_lineBreak == m_resolver.position())
- m_lineBreak.increment();
- } else if (!m_current.offset() && !m_width.committedWidth() && m_width.uncommittedWidth() && !m_hadUncommittedWidthBeforeCurrent) {
- // Do not push the current object to the next line, when this line has some content, but it is still considered empty.
- // Empty inline elements like <span></span> can produce such lines and now we just ignore these break opportunities
- // at the start of a line, if no width has been committed yet.
- // Behave as if it was actually empty and consume at least one object.
- m_lineBreak.increment();
}
+ // make sure we consume at least one char/object.
+ if (m_lineBreakHistory.current() == m_resolver.position())
+ m_lineBreakHistory.increment();
+ } else if (!m_current.offset() && !m_width.committedWidth() && m_width.uncommittedWidth() && !m_hadUncommittedWidthBeforeCurrent) {
+ // Do not push the current object to the next line, when this line has some content, but it is still considered empty.
+ // Empty inline elements like <span></span> can produce such lines and now we just ignore these break opportunities
+ // at the start of a line, if no width has been committed yet.
+ // Behave as if it was actually empty and consume at least one object.
+ m_lineBreakHistory.increment();
}
// Sanity check our midpoints.
- checkMidpoints(m_lineMidpointState, m_lineBreak);
+ TrailingObjects::CollapseFirstSpaceOrNot collapsed = checkMidpoints(m_lineMidpointState, m_lineBreakHistory.current());
- m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, m_lineBreak, TrailingObjects::CollapseFirstSpace);
+ m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, m_lineBreakHistory.current(), collapsed);
// We might have made lineBreak an iterator that points past the end
// of the object. Do this adjustment to make it point to the start
// of the next object instead to avoid confusing the rest of the
// code.
- if (m_lineBreak.offset()) {
- m_lineBreak.setOffset(m_lineBreak.offset() - 1);
- m_lineBreak.increment();
+ if (m_lineBreakHistory.offset()) {
+ m_lineBreakHistory.update([](InlineIterator& modifyMe) {
+ modifyMe.setOffset(modifyMe.offset() - 1);
+ modifyMe.increment();
+ });
}
- return m_lineBreak;
+#if ENABLE(CSS_TRAILING_WORD)
+ if (m_blockStyle.trailingWord() == TrailingWord::PartiallyBalanced)
+ return optimalLineBreakLocationForTrailingWord();
+#endif
+ return m_lineBreakHistory.current();
}
+#if ENABLE(CSS_TRAILING_WORD)
+inline InlineIterator BreakingContext::optimalLineBreakLocationForTrailingWord()
+{
+ const unsigned longTrailingWordLength = 20;
+ const float optimalTrailingLineRatio = 0.1;
+ InlineIterator lineBreak = m_lineBreakHistory.current();
+ if (!lineBreak.renderer() || !m_lineInfo.isFirstLine() || bidiNextSkippingEmptyInlines(*lineBreak.root(), lineBreak.renderer()) || !is<RenderText>(lineBreak.renderer()))
+ return lineBreak;
+ RenderText& renderText = downcast<RenderText>(*lineBreak.renderer());
+ // Don't even bother measuring if our remaining line has many characters
+ if (renderText.textLength() == lineBreak.offset() || renderText.textLength() - lineBreak.offset() > longTrailingWordLength)
+ return lineBreak;
+ bool isLooseCJKMode = m_renderTextInfo.text != &renderText && m_renderTextInfo.lineBreakIterator.isLooseCJKMode();
+ bool breakNBSP = m_autoWrap && m_currentStyle->nbspMode() == SPACE;
+ int nextBreakablePosition = lineBreak.nextBreakablePosition();
+ isBreakable(m_renderTextInfo.lineBreakIterator, lineBreak.offset() + 1, nextBreakablePosition, breakNBSP, isLooseCJKMode, m_currentStyle->wordBreak() == KeepAllWordBreak);
+ if (nextBreakablePosition < 0 || static_cast<unsigned>(nextBreakablePosition) != renderText.textLength())
+ return lineBreak;
+ const RenderStyle& style = lineStyle(renderText, m_lineInfo);
+ const FontCascade& font = style.fontCascade();
+ HashSet<const Font*> dummyFonts;
+ InlineIterator best = lineBreak;
+ for (size_t i = 1; i < m_lineBreakHistory.historyLength(); ++i) {
+ const InlineIterator& candidate = m_lineBreakHistory.get(i);
+ if (candidate.renderer() != lineBreak.renderer())
+ return best;
+ float width = textWidth(renderText, candidate.offset(), renderText.textLength() - candidate.offset(), font, 0, font.isFixedPitch(), m_collapseWhiteSpace, dummyFonts);
+ if (width > m_width.availableWidth())
+ return best;
+ if (width / m_width.availableWidth() > optimalTrailingLineRatio) // Subsequent line is long enough
+ return candidate;
+ best = candidate;
+ }
+ return best;
+}
+#endif
+
}
-#endif // BreakingContextInlineHeaders_h
+#endif // BreakingContext_h
diff --git a/Source/WebCore/rendering/line/LineBreaker.cpp b/Source/WebCore/rendering/line/LineBreaker.cpp
index d8296a669..6eafa2906 100644
--- a/Source/WebCore/rendering/line/LineBreaker.cpp
+++ b/Source/WebCore/rendering/line/LineBreaker.cpp
@@ -25,9 +25,8 @@
#include "config.h"
#include "LineBreaker.h"
-#include "BreakingContextInlineHeaders.h"
+#include "BreakingContext.h"
#include "RenderCombineText.h"
-#include "ShapeInsideInfo.h"
namespace WebCore {
@@ -49,9 +48,9 @@ void LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInf
while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) {
RenderObject& object = *iterator.renderer();
if (object.isOutOfFlowPositioned())
- setStaticPositions(m_block, toRenderBox(object));
+ setStaticPositions(m_block, downcast<RenderBox>(object), DoNotIndentText);
else if (object.isFloating())
- m_block.insertFloatingObject(toRenderBox(object));
+ m_block.insertFloatingObject(downcast<RenderBox>(object));
iterator.increment();
}
}
@@ -61,16 +60,16 @@ void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo&
while (!resolver.position().atEnd() && !requiresLineBox(resolver.position(), lineInfo, LeadingWhitespace)) {
RenderObject& object = *resolver.position().renderer();
if (object.isOutOfFlowPositioned()) {
- setStaticPositions(m_block, toRenderBox(object));
+ setStaticPositions(m_block, downcast<RenderBox>(object), width.shouldIndentText());
if (object.style().isOriginalDisplayInlineType()) {
resolver.runs().addRun(new BidiRun(0, 1, object, resolver.context(), resolver.dir()));
lineInfo.incrementRunsFromLeadingWhitespace();
}
} else if (object.isFloating())
- m_block.positionNewFloatOnLine(m_block.insertFloatingObject(toRenderBox(object)), lastFloatFromPreviousLine, lineInfo, width);
- else if (object.isText() && object.style().hasTextCombine() && object.isCombineText() && !toRenderCombineText(object).isCombined()) {
- toRenderCombineText(object).combineText();
- if (toRenderCombineText(object).isCombined())
+ m_block.positionNewFloatOnLine(*m_block.insertFloatingObject(downcast<RenderBox>(object)), lastFloatFromPreviousLine, lineInfo, width);
+ else if (object.style().hasTextCombine() && is<RenderCombineText>(object)) {
+ downcast<RenderCombineText>(object).combineText();
+ if (downcast<RenderCombineText>(object).isCombined())
continue;
}
resolver.increment();
@@ -78,61 +77,7 @@ void LineBreaker::skipLeadingWhitespace(InlineBidiResolver& resolver, LineInfo&
resolver.commitExplicitEmbedding();
}
-InlineIterator LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
-{
-#if !ENABLE(CSS_SHAPES)
- return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
-#else
- ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo();
-
- if (!shapeInsideInfo || !shapeInsideInfo->lineOverlapsShapeBounds())
- return nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
-
- InlineIterator end = resolver.position();
- InlineIterator oldEnd = end;
-
- if (!shapeInsideInfo->hasSegments()) {
- end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
- resolver.setPositionIgnoringNestedIsolates(oldEnd);
- return oldEnd;
- }
-
- const SegmentList& segments = shapeInsideInfo->segments();
- SegmentRangeList& segmentRanges = shapeInsideInfo->segmentRanges();
-
- for (unsigned i = 0; i < segments.size() && !end.atEnd(); i++) {
- InlineIterator segmentStart = resolver.position();
- end = nextSegmentBreak(resolver, lineInfo, renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines, wordMeasurements);
-
- ASSERT(segmentRanges.size() == i);
- if (resolver.position().atEnd()) {
- segmentRanges.append(LineSegmentRange(segmentStart, end));
- break;
- }
- if (resolver.position() == end) {
- // Nothing fit this segment
- end = segmentStart;
- segmentRanges.append(LineSegmentRange(segmentStart, segmentStart));
- resolver.setPositionIgnoringNestedIsolates(segmentStart);
- } else {
- // Note that resolver.position is already skipping some of the white space at the beginning of the line,
- // so that's why segmentStart might be different than resolver.position().
- LineSegmentRange range(resolver.position(), end);
- segmentRanges.append(range);
- resolver.setPosition(end, numberOfIsolateAncestors(end));
-
- if (lineInfo.previousLineBrokeCleanly()) {
- // If we hit a new line break, just stop adding anything to this line.
- break;
- }
- }
- }
- resolver.setPositionIgnoringNestedIsolates(oldEnd);
- return end;
-#endif
-}
-
-InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
+InlineIterator LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, LineLayoutState& layoutState, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements)
{
reset();
@@ -147,7 +92,7 @@ InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineI
if (resolver.position().atEnd())
return resolver.position();
- BreakingContext context(*this, resolver, lineInfo, width, renderTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block);
+ BreakingContext context(*this, resolver, lineInfo, layoutState, width, renderTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block);
while (context.currentObject()) {
context.initializeForCurrentObject();
@@ -163,11 +108,11 @@ InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineI
context.handleReplaced();
} else if (context.currentObject()->isText()) {
if (context.handleText(wordMeasurements, m_hyphenated, consecutiveHyphenatedLines)) {
- // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return.
+ // We've hit a hard text line break. Our line break iterator is updated, so early return.
return context.lineBreak();
}
} else if (context.currentObject()->isLineBreakOpportunity())
- context.commitLineBreakAtCurrentWidth(context.currentObject());
+ context.commitLineBreakAtCurrentWidth(*context.currentObject());
else
ASSERT_NOT_REACHED();
diff --git a/Source/WebCore/rendering/line/LineBreaker.h b/Source/WebCore/rendering/line/LineBreaker.h
index 70c404960..2774f2685 100644
--- a/Source/WebCore/rendering/line/LineBreaker.h
+++ b/Source/WebCore/rendering/line/LineBreaker.h
@@ -36,26 +36,23 @@ namespace WebCore {
class RenderText;
struct RenderTextInfo {
- // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors.
- RenderTextInfo();
- ~RenderTextInfo();
-
- RenderText* m_text;
- OwnPtr<TextLayout> m_layout;
- LazyLineBreakIterator m_lineBreakIterator;
- const Font* m_font;
+ RenderText* text { nullptr };
+ std::unique_ptr<TextLayout, TextLayoutDeleter> layout;
+ LazyLineBreakIterator lineBreakIterator;
+ const FontCascade* font { nullptr };
};
class LineBreaker {
public:
friend class BreakingContext;
- LineBreaker(RenderBlockFlow& block)
+
+ explicit LineBreaker(RenderBlockFlow& block)
: m_block(block)
{
reset();
}
- InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
+ InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, LineLayoutState&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
bool lineWasHyphenated() { return m_hyphenated; }
const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; }
@@ -64,12 +61,11 @@ public:
private:
void reset();
- InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&);
void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&);
FloatingObject* insertFloatingObject(RenderBox& floatBox) { return m_block.insertFloatingObject(floatBox); }
- bool positionNewFloatOnLine(FloatingObject* newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
+ bool positionNewFloatOnLine(const FloatingObject& newFloat, FloatingObject* lastFloatFromPreviousLine, LineInfo& lineInfo, LineWidth& width)
{
return m_block.positionNewFloatOnLine(newFloat, lastFloatFromPreviousLine, lineInfo, width);
}
diff --git a/Source/WebCore/rendering/line/LineInlineHeaders.h b/Source/WebCore/rendering/line/LineInlineHeaders.h
index 0b0c44e6e..dbe552cdf 100644
--- a/Source/WebCore/rendering/line/LineInlineHeaders.h
+++ b/Source/WebCore/rendering/line/LineInlineHeaders.h
@@ -43,7 +43,7 @@ inline bool hasInlineDirectionBordersPaddingOrMargin(const RenderInline& flow)
return shouldApplyEndBorderPaddingOrMargin && (flow.borderEnd() || flow.marginEnd() || flow.paddingEnd());
}
-inline const RenderStyle& lineStyle(const RenderElement& renderer, const LineInfo& lineInfo)
+inline const RenderStyle& lineStyle(const RenderObject& renderer, const LineInfo& lineInfo)
{
return lineInfo.isFirstLine() ? renderer.firstLineStyle() : renderer.style();
}
@@ -56,7 +56,7 @@ inline bool requiresLineBoxForContent(const RenderInline& flow, const LineInfo&
const RenderStyle& parentStyle = lineStyle(*parent, lineInfo);
if (flowStyle.lineHeight() != parentStyle.lineHeight()
|| flowStyle.verticalAlign() != parentStyle.verticalAlign()
- || !parentStyle.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(flowStyle.font().fontMetrics()))
+ || !parentStyle.fontCascade().fontMetrics().hasIdenticalAscentDescentAndLineGap(flowStyle.fontCascade().fontMetrics()))
return true;
}
return false;
@@ -105,8 +105,8 @@ inline bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo =
return true;
bool rendererIsEmptyInline = false;
- if (it.renderer()->isRenderInline()) {
- const RenderInline& inlineRenderer = toRenderInline(*it.renderer());
+ if (is<RenderInline>(*it.renderer())) {
+ const auto& inlineRenderer = downcast<RenderInline>(*it.renderer());
if (!alwaysRequiresLineBox(inlineRenderer) && !requiresLineBoxForContent(inlineRenderer, lineInfo))
return false;
rendererIsEmptyInline = isEmptyInline(inlineRenderer);
@@ -120,20 +120,20 @@ inline bool requiresLineBox(const InlineIterator& it, const LineInfo& lineInfo =
return notJustWhitespace || rendererIsEmptyInline;
}
-inline void setStaticPositions(RenderBlockFlow& block, RenderBox& child)
+inline void setStaticPositions(RenderBlockFlow& block, RenderBox& child, IndentTextOrNot shouldIndentText)
{
// FIXME: The math here is actually not really right. It's a best-guess approximation that
// will work for the common cases
RenderElement* containerBlock = child.container();
LayoutUnit blockHeight = block.logicalHeight();
- if (containerBlock->isRenderInline()) {
+ if (is<RenderInline>(*containerBlock)) {
// A relative positioned inline encloses us. In this case, we also have to determine our
// position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
// inline so that we can obtain the value later.
- toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block.startAlignedOffsetForLine(blockHeight, false));
- toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
+ downcast<RenderInline>(*containerBlock).layer()->setStaticInlinePosition(block.startAlignedOffsetForLine(blockHeight, DoNotIndentText));
+ downcast<RenderInline>(*containerBlock).layer()->setStaticBlockPosition(blockHeight);
}
- block.updateStaticInlinePositionForChild(child, blockHeight);
+ block.updateStaticInlinePositionForChild(child, blockHeight, shouldIndentText);
child.layer()->setStaticBlockPosition(blockHeight);
}
diff --git a/Source/WebCore/rendering/line/LineLayoutState.h b/Source/WebCore/rendering/line/LineLayoutState.h
index 4cf7296aa..0229e3a90 100644
--- a/Source/WebCore/rendering/line/LineLayoutState.h
+++ b/Source/WebCore/rendering/line/LineLayoutState.h
@@ -35,14 +35,14 @@
#define LineLayoutState_h
#include "LayoutRect.h"
-#include "RenderBox.h"
+#include "RenderBlockFlow.h"
namespace WebCore {
struct FloatWithRect {
FloatWithRect(RenderBox& f)
: object(f)
- , rect(LayoutRect(f.x() - f.marginLeft(), f.y() - f.marginTop(), f.width() + f.marginWidth(), f.height() + f.marginHeight()))
+ , rect(LayoutRect(f.x() - f.marginLeft(), f.y() - f.marginTop(), f.width() + f.horizontalMarginExtent(), f.height() + f.verticalMarginExtent()))
, everHadLayout(f.everHadLayout())
{
}
@@ -56,7 +56,7 @@ struct FloatWithRect {
// during an entire linebox tree layout pass (aka layoutInlineChildren).
class LineLayoutState {
public:
- LineLayoutState(bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, RenderFlowThread* flowThread)
+ LineLayoutState(const RenderBlockFlow& blockFlow, bool fullLayout, LayoutUnit& repaintLogicalTop, LayoutUnit& repaintLogicalBottom, RenderFlowThread* flowThread)
: m_endLineLogicalTop(0)
, m_endLine(0)
, m_lastFloat(0)
@@ -65,6 +65,7 @@ public:
, m_flowThread(flowThread)
, m_repaintLogicalTop(repaintLogicalTop)
, m_repaintLogicalBottom(repaintLogicalBottom)
+ , m_marginInfo(blockFlow, blockFlow.borderAndPaddingBefore(), blockFlow.borderAndPaddingAfter() + blockFlow.scrollbarLogicalHeight())
, m_endLineMatched(false)
, m_checkForFloatsFromLastLine(false)
, m_isFullLayout(fullLayout)
@@ -119,6 +120,10 @@ public:
m_repaintLogicalBottom = std::max(m_repaintLogicalBottom, box->logicalBottomVisualOverflow() + std::max<LayoutUnit>(paginationDelta, 0));
}
+ RenderBlockFlow::MarginInfo& marginInfo() { return m_marginInfo; }
+ LayoutUnit& prevFloatBottomFromAnonymousInlineBlock() { return m_prevFloatBottomFromAnonymousInlineBlock; }
+ LayoutUnit& maxFloatBottomFromAnonymousInlineBlock() { return m_maxFloatBottomFromAnonymousInlineBlock; }
+
private:
LineInfo m_lineInfo;
LayoutUnit m_endLineLogicalTop;
@@ -136,6 +141,10 @@ private:
LayoutUnit& m_repaintLogicalTop;
LayoutUnit& m_repaintLogicalBottom;
+ RenderBlockFlow::MarginInfo m_marginInfo;
+ LayoutUnit m_prevFloatBottomFromAnonymousInlineBlock;
+ LayoutUnit m_maxFloatBottomFromAnonymousInlineBlock;
+
bool m_endLineMatched : 1;
bool m_checkForFloatsFromLastLine : 1;
bool m_isFullLayout : 1;
diff --git a/Source/WebCore/rendering/line/LineWidth.cpp b/Source/WebCore/rendering/line/LineWidth.cpp
index 7ffa20715..f3b12b3ef 100644
--- a/Source/WebCore/rendering/line/LineWidth.cpp
+++ b/Source/WebCore/rendering/line/LineWidth.cpp
@@ -33,10 +33,6 @@
#include "RenderBlockFlow.h"
#include "RenderRubyRun.h"
-#if ENABLE(CSS_SHAPES)
-#include "ShapeInsideInfo.h"
-#endif
-
namespace WebCore {
LineWidth::LineWidth(RenderBlockFlow& block, bool isFirstLine, IndentTextOrNot shouldIndentText)
@@ -49,15 +45,9 @@ LineWidth::LineWidth(RenderBlockFlow& block, bool isFirstLine, IndentTextOrNot s
, m_left(0)
, m_right(0)
, m_availableWidth(0)
-#if ENABLE(CSS_SHAPES)
- , m_segment(0)
-#endif
, m_isFirstLine(isFirstLine)
, m_shouldIndentText(shouldIndentText)
{
-#if ENABLE(CSS_SHAPES)
- updateCurrentShapeSegment();
-#endif
updateAvailableWidth();
}
@@ -83,38 +73,42 @@ void LineWidth::updateAvailableWidth(LayoutUnit replacedHeight)
m_left = m_block.logicalLeftOffsetForLine(height, shouldIndentText(), logicalHeight);
m_right = m_block.logicalRightOffsetForLine(height, shouldIndentText(), logicalHeight);
-#if ENABLE(CSS_SHAPES)
- if (m_segment) {
- m_left = std::max<float>(m_segment->logicalLeft, m_left);
- m_right = std::min<float>(m_segment->logicalRight, m_right);
- }
-#endif
-
computeAvailableWidthFromLeftAndRight();
}
-void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject* newFloat)
+static bool newFloatShrinksLine(const FloatingObject& newFloat, const RenderBlockFlow& block, bool isFirstLine)
{
- LayoutUnit height = m_block.logicalHeight();
- if (height < m_block.logicalTopForFloat(newFloat) || height >= m_block.logicalBottomForFloat(newFloat))
- return;
+ LayoutUnit blockOffset = block.logicalHeight();
+ if (blockOffset >= block.logicalTopForFloat(newFloat) && blockOffset < block.logicalBottomForFloat(newFloat))
+ return true;
+
+ // initial-letter float always shrinks the first line.
+ const auto& style = newFloat.renderer().style();
+ if (isFirstLine && style.styleType() == FIRST_LETTER && !style.initialLetter().isEmpty())
+ return true;
+ return false;
+}
+void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(const FloatingObject& newFloat)
+{
+ if (!newFloatShrinksLine(newFloat, m_block, m_isFirstLine))
+ return;
#if ENABLE(CSS_SHAPES)
- ShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer().shapeOutsideInfo();
- if (shapeOutsideInfo) {
+ ShapeOutsideDeltas shapeDeltas;
+ if (ShapeOutsideInfo* shapeOutsideInfo = newFloat.renderer().shapeOutsideInfo()) {
LayoutUnit lineHeight = m_block.lineHeight(m_isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
- shapeOutsideInfo->updateDeltasForContainingBlockLine(m_block, *newFloat, m_block.logicalHeight(), lineHeight);
+ shapeDeltas = shapeOutsideInfo->computeDeltasForContainingBlockLine(m_block, newFloat, m_block.logicalHeight(), lineHeight);
}
#endif
- if (newFloat->type() == FloatingObject::FloatLeft) {
+ if (newFloat.type() == FloatingObject::FloatLeft) {
float newLeft = m_block.logicalRightForFloat(newFloat);
- if (shouldIndentText() && m_block.style().isLeftToRightDirection())
+ if (shouldIndentText() == IndentText && m_block.style().isLeftToRightDirection())
newLeft += floorToInt(m_block.textIndentOffset());
#if ENABLE(CSS_SHAPES)
- if (shapeOutsideInfo) {
- if (shapeOutsideInfo->lineOverlapsShape())
- newLeft += shapeOutsideInfo->rightMarginBoxDelta();
+ if (shapeDeltas.isValid()) {
+ if (shapeDeltas.lineOverlapsShape())
+ newLeft += shapeDeltas.rightMarginBoxDelta();
else // If the line doesn't overlap the shape, then we need to act as if this float didn't exist.
newLeft = m_left;
}
@@ -122,12 +116,12 @@ void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject* newFloat
m_left = std::max<float>(m_left, newLeft);
} else {
float newRight = m_block.logicalLeftForFloat(newFloat);
- if (shouldIndentText() && !m_block.style().isLeftToRightDirection())
+ if (shouldIndentText() == IndentText && !m_block.style().isLeftToRightDirection())
newRight -= floorToInt(m_block.textIndentOffset());
#if ENABLE(CSS_SHAPES)
- if (shapeOutsideInfo) {
- if (shapeOutsideInfo->lineOverlapsShape())
- newRight += shapeOutsideInfo->leftMarginBoxDelta();
+ if (shapeDeltas.isValid()) {
+ if (shapeDeltas.lineOverlapsShape())
+ newRight += shapeDeltas.leftMarginBoxDelta();
else // If the line doesn't overlap the shape, then we need to act as if this float didn't exist.
newRight = m_right;
}
@@ -142,24 +136,76 @@ void LineWidth::commit()
{
m_committedWidth += m_uncommittedWidth;
m_uncommittedWidth = 0;
+ if (m_hasUncommittedReplaced) {
+ m_hasCommittedReplaced = true;
+ m_hasUncommittedReplaced = false;
+ }
}
void LineWidth::applyOverhang(RenderRubyRun* rubyRun, RenderObject* startRenderer, RenderObject* endRenderer)
{
- int startOverhang;
- int endOverhang;
+ float startOverhang;
+ float endOverhang;
rubyRun->getOverhang(m_isFirstLine, startRenderer, endRenderer, startOverhang, endOverhang);
- startOverhang = std::min<int>(startOverhang, m_committedWidth);
+ startOverhang = std::min(startOverhang, m_committedWidth);
m_availableWidth += startOverhang;
- endOverhang = std::max(std::min<int>(endOverhang, m_availableWidth - currentWidth()), 0);
+ endOverhang = std::max(std::min(endOverhang, m_availableWidth - currentWidth()), 0.0f);
m_availableWidth += endOverhang;
m_overhangWidth += startOverhang + endOverhang;
}
-void LineWidth::fitBelowFloats()
+inline static float availableWidthAtOffset(const RenderBlockFlow& block, const LayoutUnit& offset, IndentTextOrNot shouldIndentText,
+ float& newLineLeft, float& newLineRight, const LayoutUnit& lineHeight = 0)
+{
+ newLineLeft = block.logicalLeftOffsetForLine(offset, shouldIndentText, lineHeight);
+ newLineRight = block.logicalRightOffsetForLine(offset, shouldIndentText, lineHeight);
+ return std::max(0.0f, newLineRight - newLineLeft);
+}
+
+void LineWidth::updateLineDimension(LayoutUnit newLineTop, LayoutUnit newLineWidth, float newLineLeft, float newLineRight)
+{
+ if (newLineWidth <= m_availableWidth)
+ return;
+
+ m_block.setLogicalHeight(newLineTop);
+ m_availableWidth = newLineWidth + m_overhangWidth;
+ m_left = newLineLeft;
+ m_right = newLineRight;
+}
+
+#if ENABLE(CSS_SHAPES)
+void LineWidth::wrapNextToShapeOutside(bool isFirstLine)
+{
+ LayoutUnit lineHeight = m_block.lineHeight(isFirstLine, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
+ LayoutUnit lineLogicalTop = m_block.logicalHeight();
+ LayoutUnit newLineTop = lineLogicalTop;
+ LayoutUnit floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lineLogicalTop);
+
+ float newLineWidth;
+ float newLineLeft = m_left;
+ float newLineRight = m_right;
+ while (true) {
+ newLineWidth = availableWidthAtOffset(m_block, newLineTop, shouldIndentText(), newLineLeft, newLineRight, lineHeight);
+ if (newLineWidth >= m_uncommittedWidth)
+ break;
+
+ if (newLineTop >= floatLogicalBottom)
+ break;
+
+ ++newLineTop;
+ }
+ updateLineDimension(newLineTop, newLineWidth, newLineLeft, newLineRight);
+}
+#endif
+
+void LineWidth::fitBelowFloats(bool isFirstLine)
{
+#if !ENABLE(CSS_SHAPES)
+ UNUSED_PARAM(isFirstLine);
+#endif
+
ASSERT(!m_committedWidth);
ASSERT(!fitsOnLine());
@@ -168,37 +214,26 @@ void LineWidth::fitBelowFloats()
float newLineWidth = m_availableWidth;
float newLineLeft = m_left;
float newLineRight = m_right;
+
+#if ENABLE(CSS_SHAPES)
+ FloatingObject* lastFloatFromPreviousLine = (m_block.containsFloats() ? m_block.m_floatingObjects->set().last().get() : 0);
+ if (lastFloatFromPreviousLine && lastFloatFromPreviousLine->renderer().shapeOutsideInfo())
+ return wrapNextToShapeOutside(isFirstLine);
+#endif
+
while (true) {
floatLogicalBottom = m_block.nextFloatLogicalBottomBelow(lastFloatLogicalBottom);
if (floatLogicalBottom <= lastFloatLogicalBottom)
break;
- newLineLeft = m_block.logicalLeftOffsetForLine(floatLogicalBottom, shouldIndentText());
- newLineRight = m_block.logicalRightOffsetForLine(floatLogicalBottom, shouldIndentText());
- newLineWidth = std::max(0.0f, newLineRight - newLineLeft);
+ newLineWidth = availableWidthAtOffset(m_block, floatLogicalBottom, shouldIndentText(), newLineLeft, newLineRight);
lastFloatLogicalBottom = floatLogicalBottom;
-#if ENABLE(CSS_SHAPES)
- // FIXME: This code should be refactored to incorporate with the code above.
- ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo();
- if (shapeInsideInfo) {
- LayoutUnit logicalOffsetFromShapeContainer = m_block.logicalOffsetFromShapeAncestorContainer(&shapeInsideInfo->owner()).height();
- LayoutUnit lineHeight = m_block.lineHeight(false, m_block.isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
- shapeInsideInfo->updateSegmentsForLine(lastFloatLogicalBottom + logicalOffsetFromShapeContainer, lineHeight);
- updateCurrentShapeSegment();
- updateAvailableWidth();
- }
-#endif
if (newLineWidth >= m_uncommittedWidth)
break;
}
- if (newLineWidth > m_availableWidth) {
- m_block.setLogicalHeight(lastFloatLogicalBottom);
- m_availableWidth = newLineWidth + m_overhangWidth;
- m_left = newLineLeft;
- m_right = newLineRight;
- }
+ updateLineDimension(lastFloatLogicalBottom, newLineWidth, newLineLeft, newLineRight);
}
void LineWidth::setTrailingWhitespaceWidth(float collapsedWhitespace, float borderPaddingMargin)
@@ -207,14 +242,6 @@ void LineWidth::setTrailingWhitespaceWidth(float collapsedWhitespace, float bord
m_trailingWhitespaceWidth = collapsedWhitespace + borderPaddingMargin;
}
-#if ENABLE(CSS_SHAPES)
-void LineWidth::updateCurrentShapeSegment()
-{
- if (ShapeInsideInfo* shapeInsideInfo = m_block.layoutShapeInsideInfo())
- m_segment = shapeInsideInfo->currentSegment();
-}
-#endif
-
void LineWidth::computeAvailableWidthFromLeftAndRight()
{
m_availableWidth = std::max<float>(0, m_right - m_left) + m_overhangWidth;
diff --git a/Source/WebCore/rendering/line/LineWidth.h b/Source/WebCore/rendering/line/LineWidth.h
index 11d7ae499..949d2c392 100644
--- a/Source/WebCore/rendering/line/LineWidth.h
+++ b/Source/WebCore/rendering/line/LineWidth.h
@@ -58,24 +58,33 @@ public:
float committedWidth() const { return m_committedWidth; }
float availableWidth() const { return m_availableWidth; }
float logicalLeftOffset() const { return m_left; }
+
+ bool hasCommitted() const { return m_committedWidth > 0 || m_hasCommittedReplaced; }
void updateAvailableWidth(LayoutUnit minimumHeight = 0);
- void shrinkAvailableWidthForNewFloatIfNeeded(FloatingObject*);
- void addUncommittedWidth(float delta) { m_uncommittedWidth += delta; }
+ void shrinkAvailableWidthForNewFloatIfNeeded(const FloatingObject&);
+ void addUncommittedWidth(float delta)
+ {
+ m_uncommittedWidth += delta;
+ }
+ void addUncommittedReplacedWidth(float delta)
+ {
+ addUncommittedWidth(delta);
+ m_hasUncommittedReplaced = true;
+ }
void commit();
void applyOverhang(RenderRubyRun*, RenderObject* startRenderer, RenderObject* endRenderer);
- void fitBelowFloats();
+ void fitBelowFloats(bool isFirstLine = false);
void setTrailingWhitespaceWidth(float collapsedWhitespace, float borderPaddingMargin = 0);
-
-#if ENABLE(CSS_SHAPES)
- void updateCurrentShapeSegment();
-#endif
-
- bool shouldIndentText() const { return m_shouldIndentText == IndentText; }
+ IndentTextOrNot shouldIndentText() const { return m_shouldIndentText; }
private:
void computeAvailableWidthFromLeftAndRight();
bool fitsOnLineExcludingTrailingCollapsedWhitespace() const;
+ void updateLineDimension(LayoutUnit newLineTop, LayoutUnit newLineWidth, float newLineLeft, float newLineRight);
+#if ENABLE(CSS_SHAPES)
+ void wrapNextToShapeOutside(bool isFirstLine);
+#endif
RenderBlockFlow& m_block;
float m_uncommittedWidth;
@@ -86,10 +95,9 @@ private:
float m_left;
float m_right;
float m_availableWidth;
-#if ENABLE(CSS_SHAPES)
- const LineSegment* m_segment;
-#endif
bool m_isFirstLine;
+ bool m_hasUncommittedReplaced { false };
+ bool m_hasCommittedReplaced { false };
IndentTextOrNot m_shouldIndentText;
};
diff --git a/Source/WebCore/rendering/line/TrailingObjects.cpp b/Source/WebCore/rendering/line/TrailingObjects.cpp
index 96490cd5b..2242488e6 100644
--- a/Source/WebCore/rendering/line/TrailingObjects.cpp
+++ b/Source/WebCore/rendering/line/TrailingObjects.cpp
@@ -42,7 +42,7 @@ void TrailingObjects::updateMidpointsForTrailingBoxes(LineMidpointState& lineMid
for ( ; trailingSpaceMidpoint > 0 && lineMidpointState.midpoints()[trailingSpaceMidpoint].renderer() != m_whitespace; --trailingSpaceMidpoint) { }
ASSERT(trailingSpaceMidpoint >= 0);
if (collapseFirstSpace == CollapseFirstSpace)
- lineMidpointState.midpoints()[trailingSpaceMidpoint].setOffset(lineMidpointState.midpoints()[trailingSpaceMidpoint].offset() -1);
+ lineMidpointState.midpoints()[trailingSpaceMidpoint].fastDecrement();
// Now make sure every single trailingPositionedBox following the trailingSpaceMidpoint properly stops and starts
// ignoring spaces.
diff --git a/Source/WebCore/rendering/line/TrailingObjects.h b/Source/WebCore/rendering/line/TrailingObjects.h
index 5aedea60e..46cae6549 100644
--- a/Source/WebCore/rendering/line/TrailingObjects.h
+++ b/Source/WebCore/rendering/line/TrailingObjects.h
@@ -34,10 +34,12 @@ class RenderBoxModelObject;
class RenderText;
struct BidiRun;
+struct BidiIsolatedRun;
template <class Iterator, class Run> class BidiResolver;
+template <class Iterator, class Run, class IsolateRun> class BidiResolverWithIsolate;
template <class Iterator> class MidpointState;
-typedef BidiResolver<InlineIterator, BidiRun> InlineBidiResolver;
+typedef BidiResolverWithIsolate<InlineIterator, BidiRun, BidiIsolatedRun> InlineBidiResolver;
typedef MidpointState<InlineIterator> LineMidpointState;
class TrailingObjects {