Index: Source/core/rendering/RenderBlockLineLayout.cpp |
diff --git a/Source/core/rendering/RenderBlockLineLayout.cpp b/Source/core/rendering/RenderBlockLineLayout.cpp |
index 70bdd9a1af09743930887808004715a1011476b5..833354e4124f8a4978283f5c63b3b42036f75d04 100644 |
--- a/Source/core/rendering/RenderBlockLineLayout.cpp |
+++ b/Source/core/rendering/RenderBlockLineLayout.cpp |
@@ -66,48 +66,22 @@ struct RenderTextInfo { |
const Font* m_font; |
}; |
-class LineBreaker { |
+class TrailingObjects { |
public: |
- LineBreaker(RenderBlock* block) |
- : m_block(block) |
- { |
- reset(); |
- } |
- |
- InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&); |
+ TrailingObjects(); |
+ void setTrailingWhitespace(RenderText*); |
+ void clear(); |
+ void appendBoxIfNeeded(RenderBox*); |
- bool lineWasHyphenated() { return m_hyphenated; } |
- const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; } |
- EClear clear() { return m_clear; } |
-private: |
- void reset(); |
+ enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace }; |
- InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&); |
- void skipTrailingWhitespace(InlineIterator&, const LineInfo&); |
- void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&); |
+ void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot); |
- RenderBlock* m_block; |
- bool m_hyphenated; |
- EClear m_clear; |
- Vector<RenderBox*> m_positionedObjects; |
+private: |
+ RenderText* m_whitespace; |
+ Vector<RenderBox*, 4> m_boxes; |
}; |
-ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const |
-{ |
- ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo(); |
- |
- if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfoSharing()) { |
- LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); |
- // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ... |
- LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1); |
- RenderRegion* region = regionAtBlockOffset(offset); |
- if (region) |
- shapeInsideInfo = region->shapeInsideInfo(); |
- } |
- |
- return shapeInsideInfo; |
-} |
- |
class LineInfo { |
public: |
LineInfo() |
@@ -154,6 +128,191 @@ private: |
unsigned m_runsFromLeadingWhitespace; |
}; |
+static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, RenderStyle* style) |
+{ |
+ if (isFirstLine) |
+ return IndentText; |
+ if (isAfterHardLineBreak && style->textIndentLine() == TextIndentEachLine) |
+ return IndentText; |
+ |
+ return DoNotIndentText; |
+} |
+ |
+class LineBreaker { |
+public: |
+ LineBreaker(RenderBlock* block) |
+ : m_block(block) |
+ { |
+ reset(); |
+ } |
+ |
+ InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&); |
+ |
+ bool lineWasHyphenated() { return m_hyphenated; } |
+ const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; } |
+ EClear clear() { return m_clear; } |
+private: |
+ void reset(); |
+ |
+ InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements&); |
+ |
+ class BreakingContext { |
+ public: |
+ BreakingContext(InlineBidiResolver& resolver, LineInfo& inLineInfo, LineWidth& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatFromPreviousLine, bool appliedStartWidth, RenderBlock* block) |
+ : m_resolver(resolver) |
+ , m_current(resolver.position()) |
+ , m_lineBreak(resolver.position()) |
+ , m_lastObject(m_current.m_obj) |
+ , m_block(block) |
+ , m_blockStyle(block->style()) |
+ , m_lineInfo(inLineInfo) |
+ , m_renderTextInfo(inRenderTextInfo) |
+ , m_lastFloatFromPreviousLine(inLastFloatFromPreviousLine) |
+ , m_width(lineWidth) |
+ , m_preservesNewline(m_current.m_obj->isSVGInlineText() ? false : RenderStyle::preserveNewline(m_currWS)) |
+ , m_atStart(true) |
+ , m_ignoringSpaces(false) |
+ , m_currentCharacterIsSpace(false) |
+ , m_currentCharacterShouldCollapseIfPreWap(false) |
+ , m_appliedStartWidth(appliedStartWidth) |
+ , m_includeEndWidth(true) |
+ , m_autoWrap(RenderStyle::autoWrap(m_currWS)) |
+ , m_autoWrapWasEverTrueOnLine(m_autoWrap) |
+ , m_floatsFitOnLine(true) |
+ , m_collapseWhiteSpace(RenderStyle::collapseWhiteSpace(m_currWS)) |
+ , m_startingNewParagraph(m_lineInfo.previousLineBrokeCleanly()) |
+ , m_allowImagesToBreak(!block->document().inQuirksMode() || !block->isTableCell() || !m_blockStyle->logicalWidth().isIntrinsicOrAuto()) |
+ , m_atEnd(false) |
+ , m_lineMidpointState(resolver.midpointState()) |
+ { |
+ m_lineInfo.setPreviousLineBrokeCleanly(false); |
+ } |
+ |
+ void setupContext(); |
+ |
+ RenderObject* currentObject() { return m_current.m_obj; } |
+ InlineIterator lineBreak() { return m_lineBreak; } |
+ bool atEnd() { return m_atEnd; } |
+ |
+ void initializeForCurrentObject(); |
+ |
+ void increment(); |
+ |
+ void handleBR(EClear&); |
+ void handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects); |
+ void handleFloat(); |
+ void handleEmptyInline(); |
+ void handleReplaced(); |
+ bool handleText(WordMeasurements&, bool& hyphenated); |
+ void commitAndUpdateLineBreakIfNeeded(); |
+ InlineIterator handleEndOfLine(); |
+ |
+ void clearLineBreakIfFitsOnLine() |
+ { |
+ if (m_width.fitsOnLine() || m_lastWS == NOWRAP) |
+ m_lineBreak.clear(); |
+ } |
+ |
+ private: |
+ void skipTrailingWhitespace(InlineIterator&, const LineInfo&); |
+ |
+ InlineBidiResolver& m_resolver; |
+ |
+ InlineIterator m_current; |
+ InlineIterator m_lineBreak; |
+ InlineIterator m_startOfIgnoredSpaces; |
+ |
+ RenderBlock* m_block; |
+ RenderObject* m_lastObject; |
+ RenderObject* m_nextObject; |
+ |
+ RenderStyle* m_currentStyle; |
+ RenderStyle* m_blockStyle; |
+ |
+ LineInfo& m_lineInfo; |
+ |
+ RenderTextInfo& m_renderTextInfo; |
+ |
+ FloatingObject* m_lastFloatFromPreviousLine; |
+ |
+ LineWidth m_width; |
+ |
+ EWhiteSpace m_currWS; |
+ EWhiteSpace m_lastWS; |
+ |
+ bool m_preservesNewline; |
+ bool m_atStart; |
+ bool m_ignoringSpaces; |
+ bool m_currentCharacterIsSpace; |
+ bool m_currentCharacterShouldCollapseIfPreWap; |
+ bool m_appliedStartWidth; |
+ bool m_includeEndWidth; |
+ bool m_autoWrap; |
+ bool m_autoWrapWasEverTrueOnLine; |
+ bool m_floatsFitOnLine; |
+ bool m_collapseWhiteSpace; |
+ bool m_startingNewParagraph; |
+ bool m_allowImagesToBreak; |
+ bool m_atEnd; |
+ |
+ LineMidpointState& m_lineMidpointState; |
+ |
+ TrailingObjects m_trailingObjects; |
+ }; |
+ |
+ void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* lastFloatFromPreviousLine, LineWidth&); |
+ |
+ RenderBlock* m_block; |
+ bool m_hyphenated; |
+ EClear m_clear; |
+ Vector<RenderBox*> m_positionedObjects; |
+}; |
+ |
+inline void LineBreaker::BreakingContext::initializeForCurrentObject() |
+{ |
+ m_currentStyle = m_current.m_obj->style(); |
+ m_nextObject = bidiNextSkippingEmptyInlines(m_block, m_current.m_obj); |
+ if (m_nextObject && m_nextObject->parent() && !m_nextObject->parent()->isDescendantOf(m_current.m_obj->parent())) |
+ m_includeEndWidth = true; |
+ |
+ m_currWS = m_current.m_obj->isReplaced() ? m_current.m_obj->parent()->style()->whiteSpace() : m_currentStyle->whiteSpace(); |
+ m_lastWS = m_lastObject->isReplaced() ? m_lastObject->parent()->style()->whiteSpace() : m_lastObject->style()->whiteSpace(); |
+ |
+ m_autoWrap = RenderStyle::autoWrap(m_currWS); |
+ m_autoWrapWasEverTrueOnLine = m_autoWrapWasEverTrueOnLine || m_autoWrap; |
+ |
+ m_preservesNewline = m_current.m_obj->isSVGInlineText() ? false : RenderStyle::preserveNewline(m_currWS); |
+ |
+ m_collapseWhiteSpace = RenderStyle::collapseWhiteSpace(m_currWS); |
+} |
+ |
+inline void LineBreaker::BreakingContext::increment() |
+{ |
+ // Clear out our character space bool, since inline <pre>s don't collapse whitespace |
+ // with adjacent inline normal/nowrap spans. |
+ if (!m_collapseWhiteSpace) |
+ m_currentCharacterIsSpace = false; |
+ |
+ m_current.moveToStartOf(m_nextObject); |
+ m_atStart = false; |
+} |
+ |
+ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const |
+{ |
+ ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo(); |
+ |
+ if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfoSharing()) { |
+ LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes); |
+ // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ... |
+ LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1); |
+ RenderRegion* region = regionAtBlockOffset(offset); |
+ if (region) |
+ shapeInsideInfo = region->shapeInsideInfo(); |
+ } |
+ |
+ return shapeInsideInfo; |
+} |
+ |
static inline LayoutUnit borderPaddingMarginStart(RenderInline* child) |
{ |
return child->marginStart() + child->paddingStart() + child->borderStart(); |
@@ -832,16 +991,6 @@ void RenderBlock::updateLogicalWidthForAlignment(const ETextAlign& textAlign, co |
} |
} |
-static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBreak, RenderStyle* style) |
-{ |
- if (isFirstLine) |
- return IndentText; |
- if (isAfterHardLineBreak && style->textIndentLine() == TextIndentEachLine) |
- return IndentText; |
- |
- return DoNotIndentText; |
-} |
- |
static void updateLogicalInlinePositions(RenderBlock* block, float& lineLogicalLeft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, IndentTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight) |
{ |
LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(firstLine, boxLogicalHeight); |
@@ -1111,7 +1260,7 @@ static inline BidiStatus statusWithDirection(TextDirection textDirection, bool i |
WTF::Unicode::Direction direction = textDirection == LTR ? LeftToRight : RightToLeft; |
RefPtr<BidiContext> context = BidiContext::create(textDirection == LTR ? 0 : 1, direction, isOverride, FromStyleOrDOM); |
- // This copies BidiStatus and may churn the ref on BidiContext. I doubt it matters. |
+ // This copies BidiStatus and may churn the ref on BidiContext I doubt it matters. |
return BidiStatus(direction, direction, direction, context.release()); |
} |
@@ -2362,7 +2511,7 @@ bool RenderBlock::generatesLineBoxesForInlineChild(RenderObject* inlineObj) |
// object iteration process. |
// NB. this function will insert any floating elements that would otherwise |
// be skipped but it will not position them. |
-void LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo) |
+inline void LineBreaker::BreakingContext::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo) |
{ |
while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhitespace)) { |
RenderObject* object = iterator.m_obj; |
@@ -2442,22 +2591,6 @@ static ALWAYS_INLINE float textWidth(RenderText* text, unsigned from, unsigned l |
return font.width(run, fallbackFonts, &glyphOverflow); |
} |
-class TrailingObjects { |
-public: |
- TrailingObjects(); |
- void setTrailingWhitespace(RenderText*); |
- void clear(); |
- void appendBoxIfNeeded(RenderBox*); |
- |
- enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace }; |
- |
- void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterator& lBreak, CollapseFirstSpaceOrNot); |
- |
-private: |
- RenderText* m_whitespace; |
- Vector<RenderBox*, 4> m_boxes; |
-}; |
- |
TrailingObjects::TrailingObjects() |
: m_whitespace(0) |
{ |
@@ -2588,603 +2721,611 @@ static inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& |
return iter.m_obj == renderer && iter.m_pos >= renderer->textLength(); |
} |
-InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements) |
+inline void LineBreaker::BreakingContext::handleBR(EClear& clear) |
{ |
- reset(); |
+ if (m_width.fitsOnLine()) { |
+ RenderObject* br = m_current.m_obj; |
+ m_lineBreak.moveToStartOf(br); |
+ m_lineBreak.increment(); |
- ASSERT(resolver.position().root() == m_block); |
+ // 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 |
+ // get collapsed away. It only does this if the previous line broke |
+ // cleanly. Otherwise the <br> has no effect on whether the line is |
+ // empty or not. |
+ if (m_startingNewParagraph) |
+ m_lineInfo.setEmpty(false, m_block, &m_width); |
+ m_trailingObjects.clear(); |
+ m_lineInfo.setPreviousLineBrokeCleanly(true); |
- bool appliedStartWidth = resolver.position().m_pos > 0; |
- bool includeEndWidth = true; |
- LineMidpointState& lineMidpointState = resolver.midpointState(); |
+ // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and |
+ // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a |
+ // run for this object. |
+ if (m_ignoringSpaces && m_currentStyle->clear() != CNONE) |
+ ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, br); |
- LineWidth width(*m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style())); |
+ if (!m_lineInfo.isEmpty()) |
+ clear = m_currentStyle->clear(); |
+ } |
+ m_atEnd = true; |
+} |
- skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width); |
+inline void LineBreaker::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.m_obj); |
+ bool isInlineType = box->style()->isOriginalDisplayInlineType(); |
+ if (!isInlineType) { |
+ 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 (resolver.position().atEnd()) |
- return resolver.position(); |
+ // 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 (m_ignoringSpaces) |
+ ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, box); |
+ m_trailingObjects.appendBoxIfNeeded(box); |
+ } else { |
+ positionedObjects.append(box); |
+ } |
+ m_width.addUncommittedWidth(inlineLogicalWidth(box)); |
+ // Reset prior line break context characters. |
+ m_renderTextInfo.m_lineBreakIterator.resetPriorContext(); |
+} |
+ |
+inline void LineBreaker::BreakingContext::handleFloat() |
+{ |
+ RenderBox* floatBox = toRenderBox(m_current.m_obj); |
+ FloatingObject* floatingObject = m_block->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. |
+ if (m_floatsFitOnLine && m_width.fitsOnLine(floatingObject->logicalWidth(m_block->isHorizontalWritingMode()))) { |
+ m_block->positionNewFloatOnLine(floatingObject, m_lastFloatFromPreviousLine, m_lineInfo, m_width); |
+ if (m_lineBreak.m_obj == m_current.m_obj) { |
+ ASSERT(!m_lineBreak.m_pos); |
+ m_lineBreak.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); |
+} |
+ |
+inline void LineBreaker::BreakingContext::handleEmptyInline() |
+{ |
+ // This should only end up being called on empty inlines |
+ ASSERT(isEmptyInline(m_current.m_obj)); |
+ |
+ RenderInline* flowBox = toRenderInline(m_current.m_obj); |
+ |
+ // Now that some inline flows have line boxes, if we are already ignoring spaces, we need |
+ // to make sure that we stop to include this object and then start ignoring spaces again. |
+ // If this object is at the start of the line, we need to behave like list markers and |
+ // start ignoring spaces. |
+ bool requiresLineBox = alwaysRequiresLineBox(m_current.m_obj); |
+ if (requiresLineBox || requiresLineBoxForContent(flowBox, m_lineInfo)) { |
+ // An empty inline that only has line-height, vertical-align or font-metrics will only get a |
+ // line box to affect the height of the line if the rest of the line is not empty. |
+ if (requiresLineBox) |
+ m_lineInfo.setEmpty(false, m_block, &m_width); |
+ if (m_ignoringSpaces) { |
+ m_trailingObjects.clear(); |
+ ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, m_current.m_obj); |
+ } else if (m_blockStyle->collapseWhiteSpace() && m_resolver.position().m_obj == m_current.m_obj |
+ && shouldSkipWhitespaceAfterStartObject(m_block, m_current.m_obj, m_lineMidpointState)) { |
+ // Like with list markers, we start ignoring spaces to make sure that any |
+ // additional spaces we see will be discarded. |
+ m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true; |
+ m_ignoringSpaces = true; |
+ } |
+ } |
- // This variable is used only if whitespace isn't set to PRE, and it tells us whether |
- // or not we are currently ignoring whitespace. |
- bool ignoringSpaces = false; |
- InlineIterator ignoreStart; |
- |
- // This variable tracks whether the very last character we saw was a space. We use |
- // this to detect when we encounter a second space so we know we have to terminate |
- // a run. |
- bool currentCharacterIsSpace = false; |
- bool currentCharacterShouldCollapseIfPreWap = false; |
- TrailingObjects trailingObjects; |
- |
- InlineIterator lBreak = resolver.position(); |
- |
- // FIXME: It is error-prone to split the position object out like this. |
- // Teach this code to work with objects instead of this split tuple. |
- InlineIterator current = resolver.position(); |
- RenderObject* last = current.m_obj; |
- bool atStart = true; |
- |
- bool startingNewParagraph = lineInfo.previousLineBrokeCleanly(); |
- lineInfo.setPreviousLineBrokeCleanly(false); |
- |
- bool autoWrapWasEverTrueOnLine = false; |
- bool floatsFitOnLine = true; |
- |
- // 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). |
- // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) |
- RenderStyle* blockStyle = m_block->style(); |
- bool allowImagesToBreak = !m_block->document().inQuirksMode() || !m_block->isTableCell() || !blockStyle->logicalWidth().isIntrinsicOrAuto(); |
- |
- EWhiteSpace currWS = blockStyle->whiteSpace(); |
- EWhiteSpace lastWS = currWS; |
- while (current.m_obj) { |
- RenderStyle* currentStyle = current.m_obj->style(); |
- RenderObject* next = bidiNextSkippingEmptyInlines(m_block, current.m_obj); |
- if (next && next->parent() && !next->parent()->isDescendantOf(current.m_obj->parent())) |
- includeEndWidth = true; |
- |
- currWS = current.m_obj->isReplaced() ? current.m_obj->parent()->style()->whiteSpace() : currentStyle->whiteSpace(); |
- lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : last->style()->whiteSpace(); |
- |
- bool autoWrap = RenderStyle::autoWrap(currWS); |
- autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap; |
- |
- bool preserveNewline = current.m_obj->isSVGInlineText() ? false : RenderStyle::preserveNewline(currWS); |
- |
- bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS); |
- |
- if (current.m_obj->isBR()) { |
- if (width.fitsOnLine()) { |
- lBreak.moveToStartOf(current.m_obj); |
- lBreak.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 |
- // get collapsed away. It only does this if the previous line broke |
- // cleanly. Otherwise the <br> has no effect on whether the line is |
- // empty or not. |
- if (startingNewParagraph) |
- lineInfo.setEmpty(false, m_block, &width); |
- trailingObjects.clear(); |
- lineInfo.setPreviousLineBrokeCleanly(true); |
- |
- // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and |
- // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a |
- // run for this object. |
- if (ignoringSpaces && currentStyle->clear() != CNONE) |
- ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj); |
- |
- if (!lineInfo.isEmpty()) |
- m_clear = currentStyle->clear(); |
- } |
- goto end; |
- } |
- |
- if (current.m_obj->isOutOfFlowPositioned()) { |
- // If our original display wasn't an inline type, then we can |
- // go ahead and determine our static inline position now. |
- RenderBox* box = toRenderBox(current.m_obj); |
- bool isInlineType = box->style()->isOriginalDisplayInlineType(); |
- if (!isInlineType) |
- 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()); |
- } |
+ m_width.addUncommittedWidth(inlineLogicalWidth(m_current.m_obj) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)); |
+} |
- // If we're ignoring spaces, we have to stop and include this object and |
- // then start ignoring spaces again. |
- if (isInlineType || current.m_obj->container()->isRenderInline()) { |
- if (ignoringSpaces) |
- ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj); |
- trailingObjects.appendBoxIfNeeded(box); |
- } else |
- m_positionedObjects.append(box); |
- width.addUncommittedWidth(inlineLogicalWidth(current.m_obj)); |
- // Reset prior line break context characters. |
- renderTextInfo.m_lineBreakIterator.resetPriorContext(); |
- } else if (current.m_obj->isFloating()) { |
- RenderBox* floatBox = toRenderBox(current.m_obj); |
- FloatingObject* f = m_block->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. |
- if (floatsFitOnLine && width.fitsOnLine(f->logicalWidth(m_block->isHorizontalWritingMode()))) { |
- m_block->positionNewFloatOnLine(f, lastFloatFromPreviousLine, lineInfo, width); |
- if (lBreak.m_obj == current.m_obj) { |
- ASSERT(!lBreak.m_pos); |
- lBreak.increment(); |
- } |
- } else |
- floatsFitOnLine = false; |
- // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element. |
- renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter); |
- } else if (current.m_obj->isRenderInline()) { |
- // Right now, we should only encounter empty inlines here. |
- ASSERT(isEmptyInline(current.m_obj)); |
- |
- RenderInline* flowBox = toRenderInline(current.m_obj); |
- |
- // Now that some inline flows have line boxes, if we are already ignoring spaces, we need |
- // to make sure that we stop to include this object and then start ignoring spaces again. |
- // If this object is at the start of the line, we need to behave like list markers and |
- // start ignoring spaces. |
- bool requiresLineBox = alwaysRequiresLineBox(current.m_obj); |
- if (requiresLineBox || requiresLineBoxForContent(flowBox, lineInfo)) { |
- // An empty inline that only has line-height, vertical-align or font-metrics will only get a |
- // line box to affect the height of the line if the rest of the line is not empty. |
- if (requiresLineBox) |
- lineInfo.setEmpty(false, m_block, &width); |
- if (ignoringSpaces) { |
- trailingObjects.clear(); |
- ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current.m_obj); |
- } else if (blockStyle->collapseWhiteSpace() && resolver.position().m_obj == current.m_obj |
- && shouldSkipWhitespaceAfterStartObject(m_block, current.m_obj, lineMidpointState)) { |
- // Like with list markers, we start ignoring spaces to make sure that any |
- // additional spaces we see will be discarded. |
- currentCharacterShouldCollapseIfPreWap = currentCharacterIsSpace = true; |
- ignoringSpaces = true; |
- } |
- } |
+inline void LineBreaker::BreakingContext::handleReplaced() |
+{ |
+ RenderBox* replacedBox = toRenderBox(m_current.m_obj); |
- width.addUncommittedWidth(inlineLogicalWidth(current.m_obj) + borderPaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)); |
- } else if (current.m_obj->isReplaced()) { |
- RenderBox* replacedBox = toRenderBox(current.m_obj); |
+ if (m_atStart) |
+ m_width.updateAvailableWidth(replacedBox->logicalHeight()); |
- if (atStart) |
- width.updateAvailableWidth(replacedBox->logicalHeight()); |
+ // Break on replaced elements if either has normal white-space. |
+ if ((m_autoWrap || RenderStyle::autoWrap(m_lastWS)) && (!m_current.m_obj->isImage() || m_allowImagesToBreak)) { |
+ m_width.commit(); |
+ m_lineBreak.moveToStartOf(m_current.m_obj); |
+ } |
- // Break on replaced elements if either has normal white-space. |
- if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!current.m_obj->isImage() || allowImagesToBreak)) { |
- width.commit(); |
- lBreak.moveToStartOf(current.m_obj); |
- } |
+ if (m_ignoringSpaces) |
+ stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_obj, 0)); |
- if (ignoringSpaces) |
- stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, 0)); |
- |
- lineInfo.setEmpty(false, m_block, &width); |
- ignoringSpaces = false; |
- currentCharacterShouldCollapseIfPreWap = currentCharacterIsSpace = false; |
- trailingObjects.clear(); |
- |
- // 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(current.m_obj); |
- if (current.m_obj->isListMarker()) { |
- if (blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, current.m_obj, lineMidpointState)) { |
- // Like with inline flows, we start ignoring spaces to make sure that any |
- // additional spaces we see will be discarded. |
- currentCharacterShouldCollapseIfPreWap = currentCharacterIsSpace = true; |
- ignoringSpaces = true; |
- } |
- if (toRenderListMarker(current.m_obj)->isInside()) |
- width.addUncommittedWidth(replacedLogicalWidth); |
- } else |
- width.addUncommittedWidth(replacedLogicalWidth); |
- if (current.m_obj->isRubyRun()) |
- width.applyOverhang(toRenderRubyRun(current.m_obj), last, next); |
- // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element. |
- renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter); |
- } else if (current.m_obj->isText()) { |
- if (!current.m_pos) |
- appliedStartWidth = false; |
- |
- RenderText* t = toRenderText(current.m_obj); |
- |
- bool isSVGText = t->isSVGInlineText(); |
- |
- if (t->style()->hasTextCombine() && current.m_obj->isCombineText() && !toRenderCombineText(current.m_obj)->isCombined()) { |
- RenderCombineText* combineRenderer = toRenderCombineText(current.m_obj); |
- combineRenderer->combineText(); |
- // The length of the renderer's text may have changed. Increment stale iterator positions |
- if (iteratorIsBeyondEndOfRenderCombineText(lBreak, combineRenderer)) { |
- ASSERT(iteratorIsBeyondEndOfRenderCombineText(resolver.position(), combineRenderer)); |
- lBreak.increment(); |
- resolver.position().increment(&resolver); |
- } |
- } |
+ m_lineInfo.setEmpty(false, m_block, &m_width); |
+ m_ignoringSpaces = false; |
+ m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = false; |
+ m_trailingObjects.clear(); |
- RenderStyle* style = t->style(lineInfo.isFirstLine()); |
- const Font& f = style->font(); |
- bool isFixedPitch = f.isFixedPitch(); |
- |
- unsigned lastSpace = current.m_pos; |
- float wordSpacing = currentStyle->wordSpacing(); |
- float lastSpaceWordSpacing = 0; |
- float wordSpacingForWordMeasurement = 0; |
- |
- float wrapW = width.uncommittedWidth() + inlineLogicalWidth(current.m_obj, !appliedStartWidth, true); |
- float charWidth = 0; |
- // 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 = currentStyle->breakWords() && ((autoWrap && !width.committedWidth()) || currWS == PRE); |
- bool midWordBreak = false; |
- bool breakAll = currentStyle->wordBreak() == BreakAllWordBreak && autoWrap; |
- float hyphenWidth = 0; |
- |
- if (isSVGText) { |
- breakWords = false; |
- breakAll = false; |
- } |
+ // 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.m_obj); |
+ if (m_current.m_obj->isListMarker()) { |
+ if (m_blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStartObject(m_block, m_current.m_obj, m_lineMidpointState)) { |
+ // Like with inline flows, we start ignoring spaces to make sure that any |
+ // additional spaces we see will be discarded. |
+ m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true; |
+ m_ignoringSpaces = true; |
+ } |
+ if (toRenderListMarker(m_current.m_obj)->isInside()) |
+ m_width.addUncommittedWidth(replacedLogicalWidth); |
+ } else { |
+ m_width.addUncommittedWidth(replacedLogicalWidth); |
+ } |
+ if (m_current.m_obj->isRubyRun()) |
+ m_width.applyOverhang(toRenderRubyRun(m_current.m_obj), 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); |
+} |
- if (t->isWordBreak()) { |
- width.commit(); |
- lBreak.moveToStartOf(current.m_obj); |
- ASSERT(current.m_pos == t->textLength()); |
- } |
+static inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar& secondToLastCharacter) |
+{ |
+ secondToLastCharacter = lastCharacter; |
+ lastCharacter = currentCharacter; |
+} |
- if (renderTextInfo.m_text != t) { |
- renderTextInfo.m_text = t; |
- renderTextInfo.m_font = &f; |
- renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace); |
- renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(t->text(), style->locale()); |
- } else if (renderTextInfo.m_layout && renderTextInfo.m_font != &f) { |
- renderTextInfo.m_font = &f; |
- renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace); |
- } |
+inline bool LineBreaker::BreakingContext::handleText(WordMeasurements& wordMeasurements, bool& hyphenated) |
+{ |
+ if (!m_current.m_pos) |
+ m_appliedStartWidth = false; |
- TextLayout* textLayout = renderTextInfo.m_layout.get(); |
+ RenderText* renderText = toRenderText(m_current.m_obj); |
- // 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. |
- float wordTrailingSpaceWidth = (f.typesettingFeatures() & Kerning) && !textLayout ? f.width(RenderBlock::constructTextRun(t, f, &space, 1, style)) + wordSpacing : 0; |
+ bool isSVGText = renderText->isSVGInlineText(); |
- UChar lastCharacter = renderTextInfo.m_lineBreakIterator.lastCharacter(); |
- UChar secondToLastCharacter = renderTextInfo.m_lineBreakIterator.secondToLastCharacter(); |
- for (; current.m_pos < t->textLength(); current.fastIncrementInTextNode()) { |
- bool previousCharacterIsSpace = currentCharacterIsSpace; |
- bool previousCharacterShouldCollapseIfPreWap = currentCharacterShouldCollapseIfPreWap; |
- UChar c = current.current(); |
- currentCharacterShouldCollapseIfPreWap = currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n')); |
+ if (renderText->style()->hasTextCombine() && m_current.m_obj->isCombineText() && !toRenderCombineText(m_current.m_obj)->isCombined()) { |
+ RenderCombineText* combineRenderer = toRenderCombineText(m_current.m_obj); |
+ combineRenderer->combineText(); |
+ // The length of the renderer's text may have changed. Increment stale iterator positions |
+ if (iteratorIsBeyondEndOfRenderCombineText(m_lineBreak, combineRenderer)) { |
+ ASSERT(iteratorIsBeyondEndOfRenderCombineText(m_resolver.position(), combineRenderer)); |
+ m_lineBreak.increment(); |
+ m_resolver.position().increment(&m_resolver); |
+ } |
+ } |
- if (!collapseWhiteSpace || !currentCharacterIsSpace) |
- lineInfo.setEmpty(false, m_block, &width); |
+ RenderStyle* style = renderText->style(m_lineInfo.isFirstLine()); |
+ const Font& font = style->font(); |
+ bool isFixedPitch = font.isFixedPitch(); |
- if (c == softHyphen && autoWrap && !hyphenWidth) { |
- hyphenWidth = measureHyphenWidth(t, f); |
- width.addUncommittedWidth(hyphenWidth); |
- } |
+ unsigned lastSpace = m_current.m_pos; |
+ float wordSpacing = m_currentStyle->wordSpacing(); |
+ float lastSpaceWordSpacing = 0; |
+ float wordSpacingForWordMeasurement = 0; |
- bool applyWordSpacing = false; |
+ float wrapW = m_width.uncommittedWidth() + inlineLogicalWidth(m_current.m_obj, !m_appliedStartWidth, true); |
+ float charWidth = 0; |
+ // 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 midWordBreak = false; |
+ bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWrap; |
+ float hyphenWidth = 0; |
- if ((breakAll || breakWords) && !midWordBreak) { |
- wrapW += charWidth; |
- bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && current.m_pos + 1 < t->textLength() && U16_IS_TRAIL((*t)[current.m_pos + 1]); |
- charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, 0, textLayout); |
- midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth(); |
- } |
+ if (isSVGText) { |
+ breakWords = false; |
+ breakAll = false; |
+ } |
- bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(renderTextInfo.m_lineBreakIterator, current.m_pos, current.m_nextBreakablePosition)); |
- |
- if (betweenWords || midWordBreak) { |
- bool stoppedIgnoringSpaces = false; |
- if (ignoringSpaces) { |
- lastSpaceWordSpacing = 0; |
- if (!currentCharacterIsSpace) { |
- // Stop ignoring spaces and begin at this |
- // new point. |
- ignoringSpaces = false; |
- wordSpacingForWordMeasurement = 0; |
- lastSpace = current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces. |
- stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos)); |
- stoppedIgnoringSpaces = true; |
- } else { |
- // Just keep ignoring these spaces. |
- goto nextCharacter; |
- } |
- } |
+ if (renderText->isWordBreak()) { |
+ m_width.commit(); |
+ m_lineBreak.moveToStartOf(m_current.m_obj); |
+ ASSERT(m_current.m_pos == renderText->textLength()); |
+ } |
- wordMeasurements.grow(wordMeasurements.size() + 1); |
- WordMeasurement& wordMeasurement = wordMeasurements.last(); |
+ if (m_renderTextInfo.m_text != 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); |
+ } |
- wordMeasurement.renderer = t; |
- wordMeasurement.endOffset = current.m_pos; |
- wordMeasurement.startOffset = lastSpace; |
+ TextLayout* textLayout = m_renderTextInfo.m_layout.get(); |
- float additionalTmpW; |
- if (wordTrailingSpaceWidth && c == ' ') |
- additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth; |
- else |
- additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout); |
- |
- wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasurement; |
- additionalTmpW += lastSpaceWordSpacing; |
- width.addUncommittedWidth(additionalTmpW); |
- if (!appliedStartWidth) { |
- width.addUncommittedWidth(inlineLogicalWidth(current.m_obj, true, false)); |
- appliedStartWidth = true; |
- } |
+ // 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. |
+ float wordTrailingSpaceWidth = (font.typesettingFeatures() & Kerning) && !textLayout ? font.width(RenderBlock::constructTextRun(renderText, font, &space, 1, style)) + wordSpacing : 0; |
- applyWordSpacing = wordSpacing && currentCharacterIsSpace; |
- |
- if (!width.committedWidth() && autoWrap && !width.fitsOnLine()) |
- width.fitBelowFloats(); |
- |
- if (autoWrap || breakWords) { |
- // If we break only after white-space, consider the current character |
- // as candidate width for this line. |
- bool lineWasTooWide = false; |
- if (width.fitsOnLine() && currentCharacterIsSpace && currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) { |
- float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0); |
- // Check if line is too big even without the extra space |
- // at the end of the line. If it is not, do nothing. |
- // If the line needs the extra whitespace to be too long, |
- // then move the line break to the space and skip all |
- // additional whitespace. |
- if (!width.fitsOnLine(charWidth)) { |
- lineWasTooWide = true; |
- lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition); |
- skipTrailingWhitespace(lBreak, lineInfo); |
- } |
- } |
- if (lineWasTooWide || !width.fitsOnLine()) { |
- if (lBreak.atTextParagraphSeparator()) { |
- if (!stoppedIgnoringSpaces && current.m_pos > 0) |
- ensureCharacterGetsLineBox(lineMidpointState, current); |
- lBreak.increment(); |
- lineInfo.setPreviousLineBrokeCleanly(true); |
- wordMeasurement.endOffset = lBreak.m_pos; |
- } |
- if (lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->isText() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj)->characterAt(lBreak.m_pos - 1) == softHyphen) |
- m_hyphenated = true; |
- if (lBreak.m_pos && lBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) { |
- if (charWidth) { |
- wordMeasurement.endOffset = lBreak.m_pos; |
- wordMeasurement.width = charWidth; |
- } |
- } |
- // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace. |
- if (ignoringSpaces || !collapseWhiteSpace || !currentCharacterIsSpace || !previousCharacterIsSpace) |
- goto end; |
- } else { |
- if (!betweenWords || (midWordBreak && !autoWrap)) |
- width.addUncommittedWidth(-additionalTmpW); |
- if (hyphenWidth) { |
- // Subtract the width of the soft hyphen out since we fit on a line. |
- width.addUncommittedWidth(-hyphenWidth); |
- hyphenWidth = 0; |
- } |
- } |
- } |
+ UChar lastCharacter = m_renderTextInfo.m_lineBreakIterator.lastCharacter(); |
+ UChar secondToLastCharacter = m_renderTextInfo.m_lineBreakIterator.secondToLastCharacter(); |
+ for (; m_current.m_pos < renderText->textLength(); m_current.fastIncrementInTextNode()) { |
+ bool previousCharacterIsSpace = m_currentCharacterIsSpace; |
+ bool previousCharacterShouldCollapseIfPreWap = m_currentCharacterShouldCollapseIfPreWap; |
+ UChar c = m_current.current(); |
+ m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = c == ' ' || c == '\t' || (!m_preservesNewline && (c == '\n')); |
- if (c == '\n' && preserveNewline) { |
- if (!stoppedIgnoringSpaces && current.m_pos > 0) |
- ensureCharacterGetsLineBox(lineMidpointState, current); |
- lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition); |
- lBreak.increment(); |
- lineInfo.setPreviousLineBrokeCleanly(true); |
- return lBreak; |
- } |
+ if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace) |
+ m_lineInfo.setEmpty(false, m_block, &m_width); |
- if (autoWrap && betweenWords) { |
- width.commit(); |
- wrapW = 0; |
- lBreak.moveTo(current.m_obj, current.m_pos, current.m_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; |
- } |
+ if (c == softHyphen && m_autoWrap && !hyphenWidth) { |
+ hyphenWidth = measureHyphenWidth(renderText, font); |
+ m_width.addUncommittedWidth(hyphenWidth); |
+ } |
- if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining))) { |
- // Remember this as a breakable position in case |
- // adding the end width forces a break. |
- lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition); |
- midWordBreak &= (breakWords || breakAll); |
- } |
+ bool applyWordSpacing = false; |
- if (betweenWords) { |
- lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
- wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0; |
- lastSpace = current.m_pos; |
- } |
+ if ((breakAll || breakWords) && !midWordBreak) { |
+ wrapW += charWidth; |
+ bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current.m_pos + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.m_pos + 1]); |
+ charWidth = textWidth(renderText, m_current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, 0, textLayout); |
+ midWordBreak = m_width.committedWidth() + wrapW + charWidth > m_width.availableWidth(); |
+ } |
- if (!ignoringSpaces && 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 (currentCharacterIsSpace && previousCharacterIsSpace) { |
- ignoringSpaces = true; |
- |
- // We just entered a mode where we are ignoring |
- // spaces. Create a midpoint to terminate the run |
- // before the second space. |
- startIgnoringSpaces(lineMidpointState, ignoreStart); |
- trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace); |
- } |
- } |
- } else if (ignoringSpaces) { |
+ bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBreakable(m_renderTextInfo.m_lineBreakIterator, m_current.m_pos, m_current.m_nextBreakablePosition)); |
+ |
+ if (betweenWords || midWordBreak) { |
+ bool stoppedIgnoringSpaces = false; |
+ if (m_ignoringSpaces) { |
+ lastSpaceWordSpacing = 0; |
+ if (!m_currentCharacterIsSpace) { |
// Stop ignoring spaces and begin at this |
// new point. |
- ignoringSpaces = false; |
- lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
- wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0; |
- lastSpace = current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces. |
- stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current.m_obj, current.m_pos)); |
- } |
- |
- if (isSVGText && current.m_pos > 0) { |
- // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks). |
- if (toRenderSVGInlineText(t)->characterStartsNewTextChunk(current.m_pos)) |
- ensureCharacterGetsLineBox(lineMidpointState, current); |
+ m_ignoringSpaces = false; |
+ wordSpacingForWordMeasurement = 0; |
+ lastSpace = m_current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces. |
+ stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_obj, m_current.m_pos)); |
+ stoppedIgnoringSpaces = true; |
+ } else { |
+ // Just keep ignoring these spaces. |
+ nextCharacter(c, lastCharacter, secondToLastCharacter); |
+ continue; |
} |
+ } |
- if (currentCharacterIsSpace && !previousCharacterIsSpace) { |
- ignoreStart.m_obj = current.m_obj; |
- ignoreStart.m_pos = current.m_pos; |
- } |
+ wordMeasurements.grow(wordMeasurements.size() + 1); |
+ WordMeasurement& wordMeasurement = wordMeasurements.last(); |
- if (!currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWap) { |
- if (autoWrap && currentStyle->breakOnlyAfterWhiteSpace()) |
- lBreak.moveTo(current.m_obj, current.m_pos, current.m_nextBreakablePosition); |
- } |
+ wordMeasurement.renderer = renderText; |
+ wordMeasurement.endOffset = m_current.m_pos; |
+ wordMeasurement.startOffset = lastSpace; |
- if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSpaces) |
- trailingObjects.setTrailingWhitespace(toRenderText(current.m_obj)); |
- else if (!currentStyle->collapseWhiteSpace() || !currentCharacterIsSpace) |
- trailingObjects.clear(); |
+ float additionalTmpW; |
+ if (wordTrailingSpaceWidth && c == ' ') |
+ additionalTmpW = textWidth(renderText, lastSpace, m_current.m_pos + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth; |
+ else |
+ additionalTmpW = textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout); |
- atStart = false; |
- nextCharacter: |
- secondToLastCharacter = lastCharacter; |
- lastCharacter = c; |
+ wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasurement; |
+ additionalTmpW += lastSpaceWordSpacing; |
+ m_width.addUncommittedWidth(additionalTmpW); |
+ if (!m_appliedStartWidth) { |
+ m_width.addUncommittedWidth(inlineLogicalWidth(m_current.m_obj, true, false)); |
+ m_appliedStartWidth = true; |
} |
- renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter); |
+ applyWordSpacing = wordSpacing && m_currentCharacterIsSpace; |
+ |
+ if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine()) |
+ m_width.fitBelowFloats(); |
+ |
+ if (m_autoWrap || breakWords) { |
+ // If we break only after white-space, consider the current character |
+ // as candidate width for this line. |
+ bool lineWasTooWide = false; |
+ if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) { |
+ float charWidth = textWidth(renderText, m_current.m_pos, 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0); |
+ // Check if line is too big even without the extra space |
+ // at the end of the line. If it is not, do nothing. |
+ // If the line needs the extra whitespace to be too long, |
+ // then move the line break to the space and skip all |
+ // additional whitespace. |
+ if (!m_width.fitsOnLine(charWidth)) { |
+ lineWasTooWide = true; |
+ m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition); |
+ skipTrailingWhitespace(m_lineBreak, m_lineInfo); |
+ } |
+ } |
+ if (lineWasTooWide || !m_width.fitsOnLine()) { |
+ if (m_lineBreak.atTextParagraphSeparator()) { |
+ if (!stoppedIgnoringSpaces && m_current.m_pos > 0) |
+ ensureCharacterGetsLineBox(m_lineMidpointState, m_current); |
+ m_lineBreak.increment(); |
+ m_lineInfo.setPreviousLineBrokeCleanly(true); |
+ wordMeasurement.endOffset = m_lineBreak.m_pos; |
+ } |
+ if (m_lineBreak.m_obj && m_lineBreak.m_pos && m_lineBreak.m_obj->isText() && toRenderText(m_lineBreak.m_obj)->textLength() && toRenderText(m_lineBreak.m_obj)->characterAt(m_lineBreak.m_pos - 1) == softHyphen) |
+ hyphenated = true; |
+ if (m_lineBreak.m_pos && m_lineBreak.m_pos != (unsigned)wordMeasurement.endOffset && !wordMeasurement.width) { |
+ if (charWidth) { |
+ wordMeasurement.endOffset = m_lineBreak.m_pos; |
+ wordMeasurement.width = charWidth; |
+ } |
+ } |
+ // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace. |
+ if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentCharacterIsSpace || !previousCharacterIsSpace) { |
+ m_atEnd = true; |
+ return false; |
+ } |
+ } else { |
+ if (!betweenWords || (midWordBreak && !m_autoWrap)) |
+ m_width.addUncommittedWidth(-additionalTmpW); |
+ if (hyphenWidth) { |
+ // Subtract the width of the soft hyphen out since we fit on a line. |
+ m_width.addUncommittedWidth(-hyphenWidth); |
+ hyphenWidth = 0; |
+ } |
+ } |
+ } |
- wordMeasurements.grow(wordMeasurements.size() + 1); |
- WordMeasurement& wordMeasurement = wordMeasurements.last(); |
- wordMeasurement.renderer = t; |
+ if (c == '\n' && m_preservesNewline) { |
+ if (!stoppedIgnoringSpaces && m_current.m_pos > 0) |
+ ensureCharacterGetsLineBox(m_lineMidpointState, m_current); |
+ m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition); |
+ m_lineBreak.increment(); |
+ m_lineInfo.setPreviousLineBrokeCleanly(true); |
+ return true; |
+ } |
- // IMPORTANT: current.m_pos is > length here! |
- float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout); |
- wordMeasurement.startOffset = lastSpace; |
- wordMeasurement.endOffset = current.m_pos; |
- wordMeasurement.width = ignoringSpaces ? 0 : additionalTmpW + wordSpacingForWordMeasurement; |
- additionalTmpW += lastSpaceWordSpacing; |
- width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth)); |
- includeEndWidth = false; |
+ if (m_autoWrap && betweenWords) { |
+ m_width.commit(); |
+ wrapW = 0; |
+ m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_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; |
+ } |
- if (!width.fitsOnLine()) { |
- if (!m_hyphenated && lBreak.previousInSameNode() == softHyphen) |
- m_hyphenated = true; |
+ if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mark_NonSpacing | Mark_Enclosing | Mark_SpacingCombining))) { |
+ // Remember this as a breakable position in case |
+ // adding the end width forces a break. |
+ m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition); |
+ midWordBreak &= (breakWords || breakAll); |
+ } |
- if (m_hyphenated) |
- goto end; |
+ if (betweenWords) { |
+ lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
+ wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement.width) ? wordSpacing : 0; |
+ lastSpace = m_current.m_pos; |
} |
- } else |
- ASSERT_NOT_REACHED(); |
- bool checkForBreak = autoWrap; |
- if (width.committedWidth() && !width.fitsOnLine() && lBreak.m_obj && currWS == NOWRAP) |
- checkForBreak = true; |
- else if (next && current.m_obj->isText() && next->isText() && !next->isBR() && (autoWrap || next->style()->autoWrap())) { |
- if (autoWrap && currentCharacterIsSpace) |
- checkForBreak = true; |
- else { |
- RenderText* nextText = toRenderText(next); |
- if (nextText->textLength()) { |
- UChar c = nextText->characterAt(0); |
- // If the next item on the line is text, and if we did not end with |
- // a space, then the next text run continues our word (and so it needs to |
- // keep adding to the uncommitted width. Just update and continue. |
- checkForBreak = !currentCharacterIsSpace && (c == ' ' || c == '\t' || (c == '\n' && !next->preservesNewline())); |
- } else if (nextText->isWordBreak()) |
- checkForBreak = true; |
- |
- if (!width.fitsOnLine() && !width.committedWidth()) |
- width.fitBelowFloats(); |
- |
- bool canPlaceOnLine = width.fitsOnLine() || !autoWrapWasEverTrueOnLine; |
- if (canPlaceOnLine && checkForBreak) { |
- width.commit(); |
- lBreak.moveToStartOf(next); |
+ 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 (m_currentCharacterIsSpace && previousCharacterIsSpace) { |
+ m_ignoringSpaces = true; |
+ |
+ // We just entered a mode where we are ignoring |
+ // spaces. Create a midpoint to terminate the run |
+ // before the second space. |
+ startIgnoringSpaces(m_lineMidpointState, m_startOfIgnoredSpaces); |
+ m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace); |
} |
} |
+ } else if (m_ignoringSpaces) { |
+ // Stop ignoring spaces and begin at this |
+ // new point. |
+ m_ignoringSpaces = false; |
+ lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0; |
+ wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurements.last().width) ? wordSpacing : 0; |
+ lastSpace = m_current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces. |
+ stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_obj, m_current.m_pos)); |
} |
- if (checkForBreak && !width.fitsOnLine()) { |
- // if we have floats, try to get below them. |
- if (currentCharacterIsSpace && !ignoringSpaces && currentStyle->collapseWhiteSpace()) |
- trailingObjects.clear(); |
+ if (isSVGText && m_current.m_pos > 0) { |
+ // Force creation of new InlineBoxes for each absolute positioned character (those that start new text chunks). |
+ if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m_current.m_pos)) |
+ ensureCharacterGetsLineBox(m_lineMidpointState, m_current); |
+ } |
+ |
+ if (m_currentCharacterIsSpace && !previousCharacterIsSpace) { |
+ m_startOfIgnoredSpaces.m_obj = m_current.m_obj; |
+ m_startOfIgnoredSpaces.m_pos = m_current.m_pos; |
+ } |
+ |
+ if (!m_currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWap) { |
+ if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace()) |
+ m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m_nextBreakablePosition); |
+ } |
- if (width.committedWidth()) |
- goto end; |
+ if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpaces) |
+ m_trailingObjects.setTrailingWhitespace(toRenderText(m_current.m_obj)); |
+ else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsSpace) |
+ m_trailingObjects.clear(); |
- width.fitBelowFloats(); |
+ m_atStart = false; |
+ nextCharacter(c, lastCharacter, secondToLastCharacter); |
+ } |
+ |
+ m_renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondToLastCharacter); |
+ |
+ wordMeasurements.grow(wordMeasurements.size() + 1); |
+ WordMeasurement& wordMeasurement = wordMeasurements.last(); |
+ wordMeasurement.renderer = renderText; |
- // |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 |
- // the end label if we still don't fit on the line. -dwh |
- if (!width.fitsOnLine()) |
- goto end; |
- } else if (blockStyle->autoWrap() && !width.fitsOnLine() && !width.committedWidth()) { |
- // If the container autowraps but the current child does not then we still need to ensure that it |
- // wraps and moves below any floats. |
- width.fitBelowFloats(); |
+ // IMPORTANT: current.m_pos is > length here! |
+ float additionalTmpW = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpace, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout); |
+ wordMeasurement.startOffset = lastSpace; |
+ wordMeasurement.endOffset = m_current.m_pos; |
+ wordMeasurement.width = m_ignoringSpaces ? 0 : additionalTmpW + wordSpacingForWordMeasurement; |
+ additionalTmpW += lastSpaceWordSpacing; |
+ m_width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(m_current.m_obj, !m_appliedStartWidth, m_includeEndWidth)); |
+ m_includeEndWidth = false; |
+ |
+ if (!m_width.fitsOnLine()) { |
+ if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphen) { |
+ hyphenated = true; |
+ m_atEnd = true; |
} |
+ } |
+ return false; |
+} |
+ |
+inline void LineBreaker::BreakingContext::commitAndUpdateLineBreakIfNeeded() |
+{ |
+ bool checkForBreak = m_autoWrap; |
+ if (m_width.committedWidth() && !m_width.fitsOnLine() && m_lineBreak.m_obj && m_currWS == NOWRAP) { |
+ checkForBreak = true; |
+ } else if (m_nextObject && m_current.m_obj->isText() && m_nextObject->isText() && !m_nextObject->isBR() && (m_autoWrap || m_nextObject->style()->autoWrap())) { |
+ if (m_autoWrap && m_currentCharacterIsSpace) { |
+ checkForBreak = true; |
+ } else { |
+ RenderText* nextText = toRenderText(m_nextObject); |
+ if (nextText->textLength()) { |
+ UChar c = nextText->characterAt(0); |
+ // If the next item on the line is text, and if we did not end with |
+ // a space, then the next text run continues our word (and so it needs to |
+ // keep adding to the uncommitted width. Just update and continue. |
+ checkForBreak = !m_currentCharacterIsSpace && (c == ' ' || c == '\t' || (c == '\n' && !m_nextObject->preservesNewline())); |
+ } else if (nextText->isWordBreak()) { |
+ checkForBreak = true; |
+ } |
+ |
+ if (!m_width.fitsOnLine() && !m_width.committedWidth()) |
+ m_width.fitBelowFloats(); |
- if (!current.m_obj->isFloatingOrOutOfFlowPositioned()) { |
- last = current.m_obj; |
- if (last->isReplaced() && autoWrap && (!last->isImage() || allowImagesToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) { |
- width.commit(); |
- lBreak.moveToStartOf(next); |
+ bool canPlaceOnLine = m_width.fitsOnLine() || !m_autoWrapWasEverTrueOnLine; |
+ if (canPlaceOnLine && checkForBreak) { |
+ m_width.commit(); |
+ m_lineBreak.moveToStartOf(m_nextObject); |
} |
} |
+ } |
+ |
+ if (checkForBreak && !m_width.fitsOnLine()) { |
+ // if we have floats, try to get below them. |
+ if (m_currentCharacterIsSpace && !m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) |
+ m_trailingObjects.clear(); |
+ |
+ if (m_width.committedWidth()) { |
+ m_atEnd = true; |
+ return; |
+ } |
- // Clear out our character space bool, since inline <pre>s don't collapse whitespace |
- // with adjacent inline normal/nowrap spans. |
- if (!collapseWhiteSpace) |
- currentCharacterIsSpace = false; |
+ m_width.fitBelowFloats(); |
- current.moveToStartOf(next); |
- atStart = false; |
+ // |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 |
+ // the end label if we still don't fit on the line. -dwh |
+ if (!m_width.fitsOnLine()) { |
+ m_atEnd = true; |
+ return; |
+ } |
+ } else if (m_blockStyle->autoWrap() && !m_width.fitsOnLine() && !m_width.committedWidth()) { |
+ // 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(); |
} |
- if (width.fitsOnLine() || lastWS == NOWRAP) |
- lBreak.clear(); |
+ if (!m_current.m_obj->isFloatingOrOutOfFlowPositioned()) { |
+ m_lastObject = m_current.m_obj; |
+ 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); |
+ } |
+ } |
+} |
- end: |
+InlineIterator LineBreaker::BreakingContext::handleEndOfLine() |
+{ |
ShapeInsideInfo* shapeInfo = m_block->layoutShapeInsideInfo(); |
bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments(); |
- if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR()) && segmentAllowsOverflow) { |
+ if (m_lineBreak == m_resolver.position() && (!m_lineBreak.m_obj || !m_lineBreak.m_obj->isBR()) && segmentAllowsOverflow) { |
// we just add as much as possible |
- if (blockStyle->whiteSpace() == PRE && !current.m_pos) { |
- lBreak.moveTo(last, last->isText() ? last->length() : 0); |
- } else if (lBreak.m_obj) { |
+ if (m_blockStyle->whiteSpace() == PRE && !m_current.m_pos) { |
+ m_lineBreak.moveTo(m_lastObject, m_lastObject->isText() ? m_lastObject->length() : 0); |
+ } else if (m_lineBreak.m_obj) { |
// 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. |
- lBreak.moveTo(current.m_obj, current.m_pos); |
+ m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos); |
} |
} |
// FIXME Bug 100049: We do not need to consume input in a multi-segment line |
// unless no segment will. |
// make sure we consume at least one char/object. |
- if (lBreak == resolver.position() && segmentAllowsOverflow) |
- lBreak.increment(); |
+ if (m_lineBreak == m_resolver.position() && segmentAllowsOverflow) |
+ m_lineBreak.increment(); |
// Sanity check our midpoints. |
- checkMidpoints(lineMidpointState, lBreak); |
+ checkMidpoints(m_lineMidpointState, m_lineBreak); |
- trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, lBreak, TrailingObjects::CollapseFirstSpace); |
+ m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, m_lineBreak, TrailingObjects::CollapseFirstSpace); |
- // We might have made lBreak an iterator that points past the end |
+ // 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 (lBreak.m_pos > 0) { |
- lBreak.m_pos--; |
- lBreak.increment(); |
+ if (m_lineBreak.m_pos > 0) { |
+ m_lineBreak.m_pos--; |
+ m_lineBreak.increment(); |
} |
- return lBreak; |
+ return m_lineBreak; |
+} |
+ |
+InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurements) |
+{ |
+ reset(); |
+ |
+ ASSERT(resolver.position().root() == m_block); |
+ |
+ bool appliedStartWidth = resolver.position().m_pos > 0; |
+ |
+ LineWidth width(*m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.isFirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style())); |
+ |
+ skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width); |
+ |
+ if (resolver.position().atEnd()) |
+ return resolver.position(); |
+ |
+ BreakingContext context(resolver, lineInfo, width, renderTextInfo, lastFloatFromPreviousLine, appliedStartWidth, m_block); |
+ |
+ while (context.currentObject()) { |
+ context.initializeForCurrentObject(); |
+ if (context.currentObject()->isBR()) { |
+ context.handleBR(m_clear); |
+ } else if (context.currentObject()->isOutOfFlowPositioned()) { |
+ context.handleOutOfFlowPositioned(m_positionedObjects); |
+ } else if (context.currentObject()->isFloating()) { |
+ context.handleFloat(); |
+ } else if (context.currentObject()->isRenderInline()) { |
+ context.handleEmptyInline(); |
+ } else if (context.currentObject()->isReplaced()) { |
+ context.handleReplaced(); |
+ } else if (context.currentObject()->isText()) { |
+ if (context.handleText(wordMeasurements, m_hyphenated)) { |
+ // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return. |
+ return context.lineBreak(); |
+ } |
+ } else { |
+ ASSERT_NOT_REACHED(); |
+ } |
+ |
+ if (context.atEnd()) |
+ return context.handleEndOfLine(); |
+ |
+ context.commitAndUpdateLineBreakIfNeeded(); |
+ |
+ if (context.atEnd()) |
+ return context.handleEndOfLine(); |
+ |
+ context.increment(); |
+ } |
+ |
+ context.clearLineBreakIfFitsOnLine(); |
+ |
+ return context.handleEndOfLine(); |
} |
void RenderBlock::addOverflowFromInlineChildren() |