Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(229)

Side by Side Diff: Source/core/rendering/RenderBlockLineLayout.cpp

Issue 25054004: Refactor LineBreaker::nextSegmentBreak and add a BreakingContext that holds all its state (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Fixing from eae's review Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ight reserved. 3 * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r ight reserved.
4 * Copyright (C) 2010 Google Inc. All rights reserved. 4 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * 5 *
6 * This library is free software; you can redistribute it and/or 6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public 7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either 8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version. 9 * version 2 of the License, or (at your option) any later version.
10 * 10 *
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors. 59 // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors.
60 RenderTextInfo(); 60 RenderTextInfo();
61 ~RenderTextInfo(); 61 ~RenderTextInfo();
62 62
63 RenderText* m_text; 63 RenderText* m_text;
64 OwnPtr<TextLayout> m_layout; 64 OwnPtr<TextLayout> m_layout;
65 LazyLineBreakIterator m_lineBreakIterator; 65 LazyLineBreakIterator m_lineBreakIterator;
66 const Font* m_font; 66 const Font* m_font;
67 }; 67 };
68 68
69 class LineBreaker { 69 class TrailingObjects {
70 public: 70 public:
71 LineBreaker(RenderBlock* block) 71 TrailingObjects();
72 : m_block(block) 72 void setTrailingWhitespace(RenderText*);
73 { 73 void clear();
74 reset(); 74 void appendBoxIfNeeded(RenderBox*);
75 }
76 75
77 InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo& , FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines , WordMeasurements&); 76 enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace } ;
78 77
79 bool lineWasHyphenated() { return m_hyphenated; } 78 void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterato r& lBreak, CollapseFirstSpaceOrNot);
80 const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; } 79
81 EClear clear() { return m_clear; }
82 private: 80 private:
83 void reset(); 81 RenderText* m_whitespace;
84 82 Vector<RenderBox*, 4> m_boxes;
85 InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextIn fo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLi nes, WordMeasurements&);
86 void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
87 void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* l astFloatFromPreviousLine, LineWidth&);
88
89 RenderBlock* m_block;
90 bool m_hyphenated;
91 EClear m_clear;
92 Vector<RenderBox*> m_positionedObjects;
93 }; 83 };
94 84
95 ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
96 {
97 ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo();
98
99 if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfo Sharing()) {
100 LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode( ) ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
101 // regionAtBlockOffset returns regions like an array first={0,N-1}, seco nd={N,M-1}, ...
102 LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1);
103 RenderRegion* region = regionAtBlockOffset(offset);
104 if (region)
105 shapeInsideInfo = region->shapeInsideInfo();
106 }
107
108 return shapeInsideInfo;
109 }
110
111 class LineInfo { 85 class LineInfo {
112 public: 86 public:
113 LineInfo() 87 LineInfo()
114 : m_isFirstLine(true) 88 : m_isFirstLine(true)
115 , m_isLastLine(false) 89 , m_isLastLine(false)
116 , m_isEmpty(true) 90 , m_isEmpty(true)
117 , m_previousLineBrokeCleanly(true) 91 , m_previousLineBrokeCleanly(true)
118 , m_floatPaginationStrut(0) 92 , m_floatPaginationStrut(0)
119 , m_runsFromLeadingWhitespace(0) 93 , m_runsFromLeadingWhitespace(0)
120 { } 94 { }
(...skipping 26 matching lines...) Expand all
147 121
148 private: 122 private:
149 bool m_isFirstLine; 123 bool m_isFirstLine;
150 bool m_isLastLine; 124 bool m_isLastLine;
151 bool m_isEmpty; 125 bool m_isEmpty;
152 bool m_previousLineBrokeCleanly; 126 bool m_previousLineBrokeCleanly;
153 LayoutUnit m_floatPaginationStrut; 127 LayoutUnit m_floatPaginationStrut;
154 unsigned m_runsFromLeadingWhitespace; 128 unsigned m_runsFromLeadingWhitespace;
155 }; 129 };
156 130
131 static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBrea k, RenderStyle* style)
132 {
133 if (isFirstLine)
134 return IndentText;
135 if (isAfterHardLineBreak && style->textIndentLine() == TextIndentEachLine)
136 return IndentText;
137
138 return DoNotIndentText;
139 }
140
141 class LineBreaker {
142 public:
143 LineBreaker(RenderBlock* block)
144 : m_block(block)
145 {
146 reset();
147 }
148
149 InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo& , FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines , WordMeasurements&);
150
151 bool lineWasHyphenated() { return m_hyphenated; }
152 const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; }
153 EClear clear() { return m_clear; }
154 private:
155 void reset();
156
157 InlineIterator nextSegmentBreak(InlineBidiResolver&, LineInfo&, RenderTextIn fo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLi nes, WordMeasurements&);
158
159 class BreakingContext {
160 public:
161 BreakingContext(InlineBidiResolver& resolver, LineInfo& inLineInfo, Line Width& lineWidth, RenderTextInfo& inRenderTextInfo, FloatingObject* inLastFloatF romPreviousLine, bool appliedStartWidth, RenderBlock* block)
162 : m_resolver(resolver)
163 , m_current(resolver.position())
164 , m_lineBreak(resolver.position())
165 , m_lastObject(m_current.m_obj)
166 , m_block(block)
167 , m_blockStyle(block->style())
168 , m_lineInfo(inLineInfo)
169 , m_renderTextInfo(inRenderTextInfo)
170 , m_lastFloatFromPreviousLine(inLastFloatFromPreviousLine)
171 , m_width(lineWidth)
172 , m_preservesNewline(m_current.m_obj->isSVGInlineText() ? false : Re nderStyle::preserveNewline(m_currWS))
173 , m_atStart(true)
174 , m_ignoringSpaces(false)
175 , m_currentCharacterIsSpace(false)
176 , m_currentCharacterShouldCollapseIfPreWap(false)
177 , m_appliedStartWidth(appliedStartWidth)
178 , m_includeEndWidth(true)
179 , m_autoWrap(RenderStyle::autoWrap(m_currWS))
180 , m_autoWrapWasEverTrueOnLine(m_autoWrap)
181 , m_floatsFitOnLine(true)
182 , m_collapseWhiteSpace(RenderStyle::collapseWhiteSpace(m_currWS))
183 , m_startingNewParagraph(m_lineInfo.previousLineBrokeCleanly())
184 , m_allowImagesToBreak(!block->document().inQuirksMode() || !block-> isTableCell() || !m_blockStyle->logicalWidth().isIntrinsicOrAuto())
185 , m_atEnd(false)
186 , m_lineMidpointState(resolver.midpointState())
187 {
188 m_lineInfo.setPreviousLineBrokeCleanly(false);
189 }
190
191 void setupContext();
192
193 RenderObject* currentObject() { return m_current.m_obj; }
194 InlineIterator lineBreak() { return m_lineBreak; }
195 bool atEnd() { return m_atEnd; }
196
197 void initializeForCurrentObject();
198
199 void increment();
200
201 void handleBR(EClear&);
202 void handleOutOfFlowPositioned(Vector<RenderBox*>& positionedObjects);
203 void handleFloat();
204 void handleEmptyInline();
205 void handleReplaced();
206 bool handleText(WordMeasurements&, bool& hyphenated);
207 void commitAndUpdateLineBreakIfNeeded();
208 InlineIterator handleEndOfLine();
209
210 void clearLineBreakIfFitsOnLine()
211 {
212 if (m_width.fitsOnLine() || m_lastWS == NOWRAP)
213 m_lineBreak.clear();
214 }
215
216 private:
217 void skipTrailingWhitespace(InlineIterator&, const LineInfo&);
218
219 InlineBidiResolver& m_resolver;
220
221 InlineIterator m_current;
222 InlineIterator m_lineBreak;
223 InlineIterator m_startOfIgnoredSpaces;
224
225 RenderBlock* m_block;
226 RenderObject* m_lastObject;
227 RenderObject* m_nextObject;
228
229 RenderStyle* m_currentStyle;
230 RenderStyle* m_blockStyle;
231
232 LineInfo& m_lineInfo;
233
234 RenderTextInfo& m_renderTextInfo;
235
236 FloatingObject* m_lastFloatFromPreviousLine;
237
238 LineWidth m_width;
239
240 EWhiteSpace m_currWS;
241 EWhiteSpace m_lastWS;
242
243 bool m_preservesNewline;
244 bool m_atStart;
245 bool m_ignoringSpaces;
246 bool m_currentCharacterIsSpace;
247 bool m_currentCharacterShouldCollapseIfPreWap;
248 bool m_appliedStartWidth;
249 bool m_includeEndWidth;
250 bool m_autoWrap;
251 bool m_autoWrapWasEverTrueOnLine;
252 bool m_floatsFitOnLine;
253 bool m_collapseWhiteSpace;
254 bool m_startingNewParagraph;
255 bool m_allowImagesToBreak;
256 bool m_atEnd;
257
258 LineMidpointState& m_lineMidpointState;
259
260 TrailingObjects m_trailingObjects;
261 };
262
263 void skipLeadingWhitespace(InlineBidiResolver&, LineInfo&, FloatingObject* l astFloatFromPreviousLine, LineWidth&);
264
265 RenderBlock* m_block;
266 bool m_hyphenated;
267 EClear m_clear;
268 Vector<RenderBox*> m_positionedObjects;
269 };
270
271 inline void LineBreaker::BreakingContext::initializeForCurrentObject()
272 {
273 m_currentStyle = m_current.m_obj->style();
274 m_nextObject = bidiNextSkippingEmptyInlines(m_block, m_current.m_obj);
275 if (m_nextObject && m_nextObject->parent() && !m_nextObject->parent()->isDes cendantOf(m_current.m_obj->parent()))
276 m_includeEndWidth = true;
277
278 m_currWS = m_current.m_obj->isReplaced() ? m_current.m_obj->parent()->style( )->whiteSpace() : m_currentStyle->whiteSpace();
279 m_lastWS = m_lastObject->isReplaced() ? m_lastObject->parent()->style()->whi teSpace() : m_lastObject->style()->whiteSpace();
280
281 m_autoWrap = RenderStyle::autoWrap(m_currWS);
282 m_autoWrapWasEverTrueOnLine = m_autoWrapWasEverTrueOnLine || m_autoWrap;
283
284 m_preservesNewline = m_current.m_obj->isSVGInlineText() ? false : RenderStyl e::preserveNewline(m_currWS);
285
286 m_collapseWhiteSpace = RenderStyle::collapseWhiteSpace(m_currWS);
287 }
288
289 inline void LineBreaker::BreakingContext::increment()
290 {
291 // Clear out our character space bool, since inline <pre>s don't collapse wh itespace
292 // with adjacent inline normal/nowrap spans.
293 if (!m_collapseWhiteSpace)
294 m_currentCharacterIsSpace = false;
295
296 m_current.moveToStartOf(m_nextObject);
297 m_atStart = false;
298 }
299
300 ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
301 {
302 ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo();
303
304 if (!shapeInsideInfo && flowThreadContainingBlock() && allowsShapeInsideInfo Sharing()) {
305 LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode( ) ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
306 // regionAtBlockOffset returns regions like an array first={0,N-1}, seco nd={N,M-1}, ...
307 LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1);
308 RenderRegion* region = regionAtBlockOffset(offset);
309 if (region)
310 shapeInsideInfo = region->shapeInsideInfo();
311 }
312
313 return shapeInsideInfo;
314 }
315
157 static inline LayoutUnit borderPaddingMarginStart(RenderInline* child) 316 static inline LayoutUnit borderPaddingMarginStart(RenderInline* child)
158 { 317 {
159 return child->marginStart() + child->paddingStart() + child->borderStart(); 318 return child->marginStart() + child->paddingStart() + child->borderStart();
160 } 319 }
161 320
162 static inline LayoutUnit borderPaddingMarginEnd(RenderInline* child) 321 static inline LayoutUnit borderPaddingMarginEnd(RenderInline* child)
163 { 322 {
164 return child->marginEnd() + child->paddingEnd() + child->borderEnd(); 323 return child->marginEnd() + child->paddingEnd() + child->borderEnd();
165 } 324 }
166 325
(...skipping 658 matching lines...) Expand 10 before | Expand all | Expand 10 after
825 break; 984 break;
826 case TAEND: 985 case TAEND:
827 if (direction == LTR) 986 if (direction == LTR)
828 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirecti on(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 987 updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirecti on(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
829 else 988 else
830 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirectio n(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth); 989 updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirectio n(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
831 break; 990 break;
832 } 991 }
833 } 992 }
834 993
835 static IndentTextOrNot requiresIndent(bool isFirstLine, bool isAfterHardLineBrea k, RenderStyle* style)
836 {
837 if (isFirstLine)
838 return IndentText;
839 if (isAfterHardLineBreak && style->textIndentLine() == TextIndentEachLine)
840 return IndentText;
841
842 return DoNotIndentText;
843 }
844
845 static void updateLogicalInlinePositions(RenderBlock* block, float& lineLogicalL eft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, Inde ntTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight) 994 static void updateLogicalInlinePositions(RenderBlock* block, float& lineLogicalL eft, float& lineLogicalRight, float& availableLogicalWidth, bool firstLine, Inde ntTextOrNot shouldIndentText, LayoutUnit boxLogicalHeight)
846 { 995 {
847 LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(first Line, boxLogicalHeight); 996 LayoutUnit lineLogicalHeight = block->minLineHeightForReplacedRenderer(first Line, boxLogicalHeight);
848 lineLogicalLeft = block->pixelSnappedLogicalLeftOffsetForLine(block->logical Height(), shouldIndentText == IndentText, lineLogicalHeight); 997 lineLogicalLeft = block->pixelSnappedLogicalLeftOffsetForLine(block->logical Height(), shouldIndentText == IndentText, lineLogicalHeight);
849 lineLogicalRight = block->pixelSnappedLogicalRightOffsetForLine(block->logic alHeight(), shouldIndentText == IndentText, lineLogicalHeight); 998 lineLogicalRight = block->pixelSnappedLogicalRightOffsetForLine(block->logic alHeight(), shouldIndentText == IndentText, lineLogicalHeight);
850 availableLogicalWidth = lineLogicalRight - lineLogicalLeft; 999 availableLogicalWidth = lineLogicalRight - lineLogicalLeft;
851 } 1000 }
852 1001
853 void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool re achedEnd, 1002 void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool re achedEnd,
854 GlyphOverflowAndFallbac kFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMea surements& wordMeasurements) 1003 GlyphOverflowAndFallbac kFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache, WordMea surements& wordMeasurements)
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
1104 floatingObject->setOriginatingLine(lastRootBox()); 1253 floatingObject->setOriginatingLine(lastRootBox());
1105 lastRootBox()->appendFloat(floatingObject->renderer()); 1254 lastRootBox()->appendFloat(floatingObject->renderer());
1106 } 1255 }
1107 1256
1108 // FIXME: This should be a BidiStatus constructor or create method. 1257 // FIXME: This should be a BidiStatus constructor or create method.
1109 static inline BidiStatus statusWithDirection(TextDirection textDirection, bool i sOverride) 1258 static inline BidiStatus statusWithDirection(TextDirection textDirection, bool i sOverride)
1110 { 1259 {
1111 WTF::Unicode::Direction direction = textDirection == LTR ? LeftToRight : Rig htToLeft; 1260 WTF::Unicode::Direction direction = textDirection == LTR ? LeftToRight : Rig htToLeft;
1112 RefPtr<BidiContext> context = BidiContext::create(textDirection == LTR ? 0 : 1, direction, isOverride, FromStyleOrDOM); 1261 RefPtr<BidiContext> context = BidiContext::create(textDirection == LTR ? 0 : 1, direction, isOverride, FromStyleOrDOM);
1113 1262
1114 // This copies BidiStatus and may churn the ref on BidiContext. I doubt it m atters. 1263 // This copies BidiStatus and may churn the ref on BidiContext I doubt it ma tters.
1115 return BidiStatus(direction, direction, direction, context.release()); 1264 return BidiStatus(direction, direction, direction, context.release());
1116 } 1265 }
1117 1266
1118 static inline void setupResolverToResumeInIsolate(InlineBidiResolver& resolver, RenderObject* root, RenderObject* startObject) 1267 static inline void setupResolverToResumeInIsolate(InlineBidiResolver& resolver, RenderObject* root, RenderObject* startObject)
1119 { 1268 {
1120 if (root != startObject) { 1269 if (root != startObject) {
1121 RenderObject* parent = startObject->parent(); 1270 RenderObject* parent = startObject->parent();
1122 setupResolverToResumeInIsolate(resolver, root, parent); 1271 setupResolverToResumeInIsolate(resolver, root, parent);
1123 notifyObserverEnteredObject(&resolver, startObject); 1272 notifyObserverEnteredObject(&resolver, startObject);
1124 } 1273 }
(...skipping 1230 matching lines...) Expand 10 before | Expand all | Expand 10 after
2355 2504
2356 return !it.atEnd(); 2505 return !it.atEnd();
2357 } 2506 }
2358 2507
2359 // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, s ince we really need to be building 2508 // FIXME: The entire concept of the skipTrailingWhitespace function is flawed, s ince we really need to be building
2360 // line boxes even for containers that may ultimately collapse away. Otherwise w e'll never get positioned 2509 // line boxes even for containers that may ultimately collapse away. Otherwise w e'll never get positioned
2361 // elements quite right. In other words, we need to build this function's work i nto the normal line 2510 // elements quite right. In other words, we need to build this function's work i nto the normal line
2362 // object iteration process. 2511 // object iteration process.
2363 // NB. this function will insert any floating elements that would otherwise 2512 // NB. this function will insert any floating elements that would otherwise
2364 // be skipped but it will not position them. 2513 // be skipped but it will not position them.
2365 void LineBreaker::skipTrailingWhitespace(InlineIterator& iterator, const LineInf o& lineInfo) 2514 inline void LineBreaker::BreakingContext::skipTrailingWhitespace(InlineIterator& iterator, const LineInfo& lineInfo)
2366 { 2515 {
2367 while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhi tespace)) { 2516 while (!iterator.atEnd() && !requiresLineBox(iterator, lineInfo, TrailingWhi tespace)) {
2368 RenderObject* object = iterator.m_obj; 2517 RenderObject* object = iterator.m_obj;
2369 if (object->isOutOfFlowPositioned()) 2518 if (object->isOutOfFlowPositioned())
2370 setStaticPositions(m_block, toRenderBox(object)); 2519 setStaticPositions(m_block, toRenderBox(object));
2371 else if (object->isFloating()) 2520 else if (object->isFloating())
2372 m_block->insertFloatingObject(toRenderBox(object)); 2521 m_block->insertFloatingObject(toRenderBox(object));
2373 iterator.increment(); 2522 iterator.increment();
2374 } 2523 }
2375 } 2524 }
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
2435 TextRun run = RenderBlock::constructTextRun(text, font, text, from, len, tex t->style()); 2584 TextRun run = RenderBlock::constructTextRun(text, font, text, from, len, tex t->style());
2436 run.setCharactersLength(text->textLength() - from); 2585 run.setCharactersLength(text->textLength() - from);
2437 ASSERT(run.charactersLength() >= run.length()); 2586 ASSERT(run.charactersLength() >= run.length());
2438 2587
2439 run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath()); 2588 run.setCharacterScanForCodePath(!text->canUseSimpleFontCodePath());
2440 run.setTabSize(!collapseWhiteSpace, text->style()->tabSize()); 2589 run.setTabSize(!collapseWhiteSpace, text->style()->tabSize());
2441 run.setXPos(xPos); 2590 run.setXPos(xPos);
2442 return font.width(run, fallbackFonts, &glyphOverflow); 2591 return font.width(run, fallbackFonts, &glyphOverflow);
2443 } 2592 }
2444 2593
2445 class TrailingObjects {
2446 public:
2447 TrailingObjects();
2448 void setTrailingWhitespace(RenderText*);
2449 void clear();
2450 void appendBoxIfNeeded(RenderBox*);
2451
2452 enum CollapseFirstSpaceOrNot { DoNotCollapseFirstSpace, CollapseFirstSpace } ;
2453
2454 void updateMidpointsForTrailingBoxes(LineMidpointState&, const InlineIterato r& lBreak, CollapseFirstSpaceOrNot);
2455
2456 private:
2457 RenderText* m_whitespace;
2458 Vector<RenderBox*, 4> m_boxes;
2459 };
2460
2461 TrailingObjects::TrailingObjects() 2594 TrailingObjects::TrailingObjects()
2462 : m_whitespace(0) 2595 : m_whitespace(0)
2463 { 2596 {
2464 } 2597 }
2465 2598
2466 inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace) 2599 inline void TrailingObjects::setTrailingWhitespace(RenderText* whitespace)
2467 { 2600 {
2468 ASSERT(whitespace); 2601 ASSERT(whitespace);
2469 m_whitespace = whitespace; 2602 m_whitespace = whitespace;
2470 } 2603 }
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
2581 } 2714 }
2582 resolver.setPositionIgnoringNestedIsolates(oldEnd); 2715 resolver.setPositionIgnoringNestedIsolates(oldEnd);
2583 return end; 2716 return end;
2584 } 2717 }
2585 2718
2586 static inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer) 2719 static inline bool iteratorIsBeyondEndOfRenderCombineText(const InlineIterator& iter, RenderCombineText* renderer)
2587 { 2720 {
2588 return iter.m_obj == renderer && iter.m_pos >= renderer->textLength(); 2721 return iter.m_obj == renderer && iter.m_pos >= renderer->textLength();
2589 } 2722 }
2590 2723
2591 InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineI nfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPrev iousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurement s) 2724 inline void LineBreaker::BreakingContext::handleBR(EClear& clear)
2592 { 2725 {
2593 reset(); 2726 if (m_width.fitsOnLine()) {
2594 2727 RenderObject* br = m_current.m_obj;
2595 ASSERT(resolver.position().root() == m_block); 2728 m_lineBreak.moveToStartOf(br);
2596 2729 m_lineBreak.increment();
2597 bool appliedStartWidth = resolver.position().m_pos > 0; 2730
2598 bool includeEndWidth = true; 2731 // A <br> always breaks a line, so don't let the line be collapsed
2599 LineMidpointState& lineMidpointState = resolver.midpointState(); 2732 // away. Also, the space at the end of a line with a <br> does not
2600 2733 // get collapsed away. It only does this if the previous line broke
2601 LineWidth width(*m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.is FirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style())); 2734 // cleanly. Otherwise the <br> has no effect on whether the line is
2602 2735 // empty or not.
2603 skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width); 2736 if (m_startingNewParagraph)
2604 2737 m_lineInfo.setEmpty(false, m_block, &m_width);
2605 if (resolver.position().atEnd()) 2738 m_trailingObjects.clear();
2606 return resolver.position(); 2739 m_lineInfo.setPreviousLineBrokeCleanly(true);
2607 2740
2608 // This variable is used only if whitespace isn't set to PRE, and it tells u s whether 2741 // A <br> with clearance always needs a linebox in case the lines below it get dirtied later and
2609 // or not we are currently ignoring whitespace. 2742 // need to check for floats to clear - so if we're ignoring spaces, stop ignoring them and add a
2610 bool ignoringSpaces = false; 2743 // run for this object.
2611 InlineIterator ignoreStart; 2744 if (m_ignoringSpaces && m_currentStyle->clear() != CNONE)
2612 2745 ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, br);
2613 // This variable tracks whether the very last character we saw was a space. We use 2746
2614 // this to detect when we encounter a second space so we know we have to ter minate 2747 if (!m_lineInfo.isEmpty())
2615 // a run. 2748 clear = m_currentStyle->clear();
2616 bool currentCharacterIsSpace = false; 2749 }
2617 bool currentCharacterShouldCollapseIfPreWap = false; 2750 m_atEnd = true;
2618 TrailingObjects trailingObjects; 2751 }
2619 2752
2620 InlineIterator lBreak = resolver.position(); 2753 inline void LineBreaker::BreakingContext::handleOutOfFlowPositioned(Vector<Rende rBox*>& positionedObjects)
2621 2754 {
2622 // FIXME: It is error-prone to split the position object out like this. 2755 // If our original display wasn't an inline type, then we can
2623 // Teach this code to work with objects instead of this split tuple. 2756 // go ahead and determine our static inline position now.
2624 InlineIterator current = resolver.position(); 2757 RenderBox* box = toRenderBox(m_current.m_obj);
2625 RenderObject* last = current.m_obj; 2758 bool isInlineType = box->style()->isOriginalDisplayInlineType();
2626 bool atStart = true; 2759 if (!isInlineType) {
2627 2760 m_block->setStaticInlinePositionForChild(box, m_block->logicalHeight(), m_block->startOffsetForContent(m_block->logicalHeight()));
2628 bool startingNewParagraph = lineInfo.previousLineBrokeCleanly(); 2761 } else {
2629 lineInfo.setPreviousLineBrokeCleanly(false); 2762 // If our original display was an INLINE type, then we can go ahead
2630 2763 // and determine our static y position now.
2631 bool autoWrapWasEverTrueOnLine = false; 2764 box->layer()->setStaticBlockPosition(m_block->logicalHeight());
2632 bool floatsFitOnLine = true; 2765 }
2633 2766
2634 // Firefox and Opera will allow a table cell to grow to fit an image inside it under 2767 // If we're ignoring spaces, we have to stop and include this object and
2635 // very specific circumstances (in order to match common WinIE renderings). 2768 // then start ignoring spaces again.
2636 // Not supporting the quirk has caused us to mis-render some real sites. (Se e Bugzilla 10517.) 2769 if (isInlineType || box->container()->isRenderInline()) {
2637 RenderStyle* blockStyle = m_block->style(); 2770 if (m_ignoringSpaces)
2638 bool allowImagesToBreak = !m_block->document().inQuirksMode() || !m_block->i sTableCell() || !blockStyle->logicalWidth().isIntrinsicOrAuto(); 2771 ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, box);
2639 2772 m_trailingObjects.appendBoxIfNeeded(box);
2640 EWhiteSpace currWS = blockStyle->whiteSpace(); 2773 } else {
2641 EWhiteSpace lastWS = currWS; 2774 positionedObjects.append(box);
2642 while (current.m_obj) { 2775 }
2643 RenderStyle* currentStyle = current.m_obj->style(); 2776 m_width.addUncommittedWidth(inlineLogicalWidth(box));
2644 RenderObject* next = bidiNextSkippingEmptyInlines(m_block, current.m_obj ); 2777 // Reset prior line break context characters.
2645 if (next && next->parent() && !next->parent()->isDescendantOf(current.m_ obj->parent())) 2778 m_renderTextInfo.m_lineBreakIterator.resetPriorContext();
2646 includeEndWidth = true; 2779 }
2647 2780
2648 currWS = current.m_obj->isReplaced() ? current.m_obj->parent()->style()- >whiteSpace() : currentStyle->whiteSpace(); 2781 inline void LineBreaker::BreakingContext::handleFloat()
2649 lastWS = last->isReplaced() ? last->parent()->style()->whiteSpace() : la st->style()->whiteSpace(); 2782 {
2650 2783 RenderBox* floatBox = toRenderBox(m_current.m_obj);
2651 bool autoWrap = RenderStyle::autoWrap(currWS); 2784 FloatingObject* floatingObject = m_block->insertFloatingObject(floatBox);
2652 autoWrapWasEverTrueOnLine = autoWrapWasEverTrueOnLine || autoWrap; 2785 // check if it fits in the current line.
2653 2786 // If it does, position it now, otherwise, position
2654 bool preserveNewline = current.m_obj->isSVGInlineText() ? false : Render Style::preserveNewline(currWS); 2787 // it after moving to next line (in newLine() func)
2655 2788 // FIXME: Bug 110372: Properly position multiple stacked floats with non-rec tangular shape outside.
2656 bool collapseWhiteSpace = RenderStyle::collapseWhiteSpace(currWS); 2789 if (m_floatsFitOnLine && m_width.fitsOnLine(floatingObject->logicalWidth(m_b lock->isHorizontalWritingMode()))) {
2657 2790 m_block->positionNewFloatOnLine(floatingObject, m_lastFloatFromPreviousL ine, m_lineInfo, m_width);
2658 if (current.m_obj->isBR()) { 2791 if (m_lineBreak.m_obj == m_current.m_obj) {
2659 if (width.fitsOnLine()) { 2792 ASSERT(!m_lineBreak.m_pos);
2660 lBreak.moveToStartOf(current.m_obj); 2793 m_lineBreak.increment();
2661 lBreak.increment(); 2794 }
2662 2795 } else {
2663 // A <br> always breaks a line, so don't let the line be collaps ed 2796 m_floatsFitOnLine = false;
2664 // away. Also, the space at the end of a line with a <br> does n ot 2797 }
2665 // get collapsed away. It only does this if the previous line b roke 2798 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEM ENT CHARACTER) for floating element.
2666 // cleanly. Otherwise the <br> has no effect on whether the lin e is 2799 m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter );
2667 // empty or not. 2800 }
2668 if (startingNewParagraph) 2801
2669 lineInfo.setEmpty(false, m_block, &width); 2802 inline void LineBreaker::BreakingContext::handleEmptyInline()
2670 trailingObjects.clear(); 2803 {
2671 lineInfo.setPreviousLineBrokeCleanly(true); 2804 // This should only end up being called on empty inlines
2672 2805 ASSERT(isEmptyInline(m_current.m_obj));
2673 // A <br> with clearance always needs a linebox in case the line s below it get dirtied later and 2806
2674 // need to check for floats to clear - so if we're ignoring spac es, stop ignoring them and add a 2807 RenderInline* flowBox = toRenderInline(m_current.m_obj);
2675 // run for this object. 2808
2676 if (ignoringSpaces && currentStyle->clear() != CNONE) 2809 // Now that some inline flows have line boxes, if we are already ignoring sp aces, we need
2677 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current. m_obj); 2810 // to make sure that we stop to include this object and then start ignoring spaces again.
2678 2811 // If this object is at the start of the line, we need to behave like list m arkers and
2679 if (!lineInfo.isEmpty()) 2812 // start ignoring spaces.
2680 m_clear = currentStyle->clear(); 2813 bool requiresLineBox = alwaysRequiresLineBox(m_current.m_obj);
2681 } 2814 if (requiresLineBox || requiresLineBoxForContent(flowBox, m_lineInfo)) {
2682 goto end; 2815 // An empty inline that only has line-height, vertical-align or font-met rics will only get a
2683 } 2816 // line box to affect the height of the line if the rest of the line is not empty.
2684 2817 if (requiresLineBox)
2685 if (current.m_obj->isOutOfFlowPositioned()) { 2818 m_lineInfo.setEmpty(false, m_block, &m_width);
2686 // If our original display wasn't an inline type, then we can 2819 if (m_ignoringSpaces) {
2687 // go ahead and determine our static inline position now. 2820 m_trailingObjects.clear();
2688 RenderBox* box = toRenderBox(current.m_obj); 2821 ensureLineBoxInsideIgnoredSpaces(m_lineMidpointState, m_current.m_ob j);
2689 bool isInlineType = box->style()->isOriginalDisplayInlineType(); 2822 } else if (m_blockStyle->collapseWhiteSpace() && m_resolver.position().m _obj == m_current.m_obj
2690 if (!isInlineType) 2823 && shouldSkipWhitespaceAfterStartObject(m_block, m_current.m_obj, m_ lineMidpointState)) {
2691 m_block->setStaticInlinePositionForChild(box, m_block->logicalHe ight(), m_block->startOffsetForContent(m_block->logicalHeight())); 2824 // Like with list markers, we start ignoring spaces to make sure tha t any
2692 else { 2825 // additional spaces we see will be discarded.
2693 // If our original display was an INLINE type, then we can go ah ead 2826 m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true;
2694 // and determine our static y position now. 2827 m_ignoringSpaces = true;
2695 box->layer()->setStaticBlockPosition(m_block->logicalHeight()); 2828 }
2696 } 2829 }
2697 2830
2698 // If we're ignoring spaces, we have to stop and include this object and 2831 m_width.addUncommittedWidth(inlineLogicalWidth(m_current.m_obj) + borderPadd ingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox));
2699 // then start ignoring spaces again. 2832 }
2700 if (isInlineType || current.m_obj->container()->isRenderInline()) { 2833
2701 if (ignoringSpaces) 2834 inline void LineBreaker::BreakingContext::handleReplaced()
2702 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current. m_obj); 2835 {
2703 trailingObjects.appendBoxIfNeeded(box); 2836 RenderBox* replacedBox = toRenderBox(m_current.m_obj);
2704 } else 2837
2705 m_positionedObjects.append(box); 2838 if (m_atStart)
2706 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj)); 2839 m_width.updateAvailableWidth(replacedBox->logicalHeight());
2707 // Reset prior line break context characters. 2840
2708 renderTextInfo.m_lineBreakIterator.resetPriorContext(); 2841 // Break on replaced elements if either has normal white-space.
2709 } else if (current.m_obj->isFloating()) { 2842 if ((m_autoWrap || RenderStyle::autoWrap(m_lastWS)) && (!m_current.m_obj->is Image() || m_allowImagesToBreak)) {
2710 RenderBox* floatBox = toRenderBox(current.m_obj); 2843 m_width.commit();
2711 FloatingObject* f = m_block->insertFloatingObject(floatBox); 2844 m_lineBreak.moveToStartOf(m_current.m_obj);
2712 // check if it fits in the current line. 2845 }
2713 // If it does, position it now, otherwise, position 2846
2714 // it after moving to next line (in newLine() func) 2847 if (m_ignoringSpaces)
2715 // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside. 2848 stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current.m_ob j, 0));
2716 if (floatsFitOnLine && width.fitsOnLine(f->logicalWidth(m_block->isH orizontalWritingMode()))) { 2849
2717 m_block->positionNewFloatOnLine(f, lastFloatFromPreviousLine, li neInfo, width); 2850 m_lineInfo.setEmpty(false, m_block, &m_width);
2718 if (lBreak.m_obj == current.m_obj) { 2851 m_ignoringSpaces = false;
2719 ASSERT(!lBreak.m_pos); 2852 m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = false ;
2720 lBreak.increment(); 2853 m_trailingObjects.clear();
2854
2855 // Optimize for a common case. If we can't find whitespace after the list
2856 // item, then this is all moot.
2857 LayoutUnit replacedLogicalWidth = m_block->logicalWidthForChild(replacedBox) + m_block->marginStartForChild(replacedBox) + m_block->marginEndForChild(replac edBox) + inlineLogicalWidth(m_current.m_obj);
2858 if (m_current.m_obj->isListMarker()) {
2859 if (m_blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfterStart Object(m_block, m_current.m_obj, m_lineMidpointState)) {
2860 // Like with inline flows, we start ignoring spaces to make sure tha t any
2861 // additional spaces we see will be discarded.
2862 m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = true;
2863 m_ignoringSpaces = true;
2864 }
2865 if (toRenderListMarker(m_current.m_obj)->isInside())
2866 m_width.addUncommittedWidth(replacedLogicalWidth);
2867 } else {
2868 m_width.addUncommittedWidth(replacedLogicalWidth);
2869 }
2870 if (m_current.m_obj->isRubyRun())
2871 m_width.applyOverhang(toRenderRubyRun(m_current.m_obj), m_lastObject, m_ nextObject);
2872 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEM ENT CHARACTER) for replaced element.
2873 m_renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCharacter );
2874 }
2875
2876 static inline void nextCharacter(UChar& currentCharacter, UChar& lastCharacter, UChar& secondToLastCharacter)
2877 {
2878 secondToLastCharacter = lastCharacter;
2879 lastCharacter = currentCharacter;
2880 }
2881
2882 inline bool LineBreaker::BreakingContext::handleText(WordMeasurements& wordMeasu rements, bool& hyphenated)
2883 {
2884 if (!m_current.m_pos)
2885 m_appliedStartWidth = false;
2886
2887 RenderText* renderText = toRenderText(m_current.m_obj);
2888
2889 bool isSVGText = renderText->isSVGInlineText();
2890
2891 if (renderText->style()->hasTextCombine() && m_current.m_obj->isCombineText( ) && !toRenderCombineText(m_current.m_obj)->isCombined()) {
2892 RenderCombineText* combineRenderer = toRenderCombineText(m_current.m_obj );
2893 combineRenderer->combineText();
2894 // The length of the renderer's text may have changed. Increment stale i terator positions
2895 if (iteratorIsBeyondEndOfRenderCombineText(m_lineBreak, combineRenderer) ) {
2896 ASSERT(iteratorIsBeyondEndOfRenderCombineText(m_resolver.position(), combineRenderer));
2897 m_lineBreak.increment();
2898 m_resolver.position().increment(&m_resolver);
2899 }
2900 }
2901
2902 RenderStyle* style = renderText->style(m_lineInfo.isFirstLine());
2903 const Font& font = style->font();
2904 bool isFixedPitch = font.isFixedPitch();
2905
2906 unsigned lastSpace = m_current.m_pos;
2907 float wordSpacing = m_currentStyle->wordSpacing();
2908 float lastSpaceWordSpacing = 0;
2909 float wordSpacingForWordMeasurement = 0;
2910
2911 float wrapW = m_width.uncommittedWidth() + inlineLogicalWidth(m_current.m_ob j, !m_appliedStartWidth, true);
2912 float charWidth = 0;
2913 // Auto-wrapping text should wrap in the middle of a word only if it could n ot wrap before the word,
2914 // which is only possible if the word is the first thing on the line, that i s, if |w| is zero.
2915 bool breakWords = m_currentStyle->breakWords() && ((m_autoWrap && !m_width.c ommittedWidth()) || m_currWS == PRE);
2916 bool midWordBreak = false;
2917 bool breakAll = m_currentStyle->wordBreak() == BreakAllWordBreak && m_autoWr ap;
2918 float hyphenWidth = 0;
2919
2920 if (isSVGText) {
2921 breakWords = false;
2922 breakAll = false;
2923 }
2924
2925 if (renderText->isWordBreak()) {
2926 m_width.commit();
2927 m_lineBreak.moveToStartOf(m_current.m_obj);
2928 ASSERT(m_current.m_pos == renderText->textLength());
2929 }
2930
2931 if (m_renderTextInfo.m_text != renderText) {
2932 m_renderTextInfo.m_text = renderText;
2933 m_renderTextInfo.m_font = &font;
2934 m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.curren tWidth(), m_collapseWhiteSpace);
2935 m_renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator(rende rText->text(), style->locale());
2936 } else if (m_renderTextInfo.m_layout && m_renderTextInfo.m_font != &font) {
2937 m_renderTextInfo.m_font = &font;
2938 m_renderTextInfo.m_layout = font.createLayout(renderText, m_width.curren tWidth(), m_collapseWhiteSpace);
2939 }
2940
2941 TextLayout* textLayout = m_renderTextInfo.m_layout.get();
2942
2943 // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
2944 // words with their trailing space, then subtract its width.
2945 float wordTrailingSpaceWidth = (font.typesettingFeatures() & Kerning) && !te xtLayout ? font.width(RenderBlock::constructTextRun(renderText, font, &space, 1, style)) + wordSpacing : 0;
2946
2947 UChar lastCharacter = m_renderTextInfo.m_lineBreakIterator.lastCharacter();
2948 UChar secondToLastCharacter = m_renderTextInfo.m_lineBreakIterator.secondToL astCharacter();
2949 for (; m_current.m_pos < renderText->textLength(); m_current.fastIncrementIn TextNode()) {
2950 bool previousCharacterIsSpace = m_currentCharacterIsSpace;
2951 bool previousCharacterShouldCollapseIfPreWap = m_currentCharacterShouldC ollapseIfPreWap;
2952 UChar c = m_current.current();
2953 m_currentCharacterShouldCollapseIfPreWap = m_currentCharacterIsSpace = c == ' ' || c == '\t' || (!m_preservesNewline && (c == '\n'));
2954
2955 if (!m_collapseWhiteSpace || !m_currentCharacterIsSpace)
2956 m_lineInfo.setEmpty(false, m_block, &m_width);
2957
2958 if (c == softHyphen && m_autoWrap && !hyphenWidth) {
2959 hyphenWidth = measureHyphenWidth(renderText, font);
2960 m_width.addUncommittedWidth(hyphenWidth);
2961 }
2962
2963 bool applyWordSpacing = false;
2964
2965 if ((breakAll || breakWords) && !midWordBreak) {
2966 wrapW += charWidth;
2967 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && m_current .m_pos + 1 < renderText->textLength() && U16_IS_TRAIL((*renderText)[m_current.m_ pos + 1]);
2968 charWidth = textWidth(renderText, m_current.m_pos, midWordBreakIsBef oreSurrogatePair ? 2 : 1, font, m_width.committedWidth() + wrapW, isFixedPitch, m_collapseWhiteSpace, 0, textLayout);
2969 midWordBreak = m_width.committedWidth() + wrapW + charWidth > m_widt h.availableWidth();
2970 }
2971
2972 bool betweenWords = c == '\n' || (m_currWS != PRE && !m_atStart && isBre akable(m_renderTextInfo.m_lineBreakIterator, m_current.m_pos, m_current.m_nextBr eakablePosition));
2973
2974 if (betweenWords || midWordBreak) {
2975 bool stoppedIgnoringSpaces = false;
2976 if (m_ignoringSpaces) {
2977 lastSpaceWordSpacing = 0;
2978 if (!m_currentCharacterIsSpace) {
2979 // Stop ignoring spaces and begin at this
2980 // new point.
2981 m_ignoringSpaces = false;
2982 wordSpacingForWordMeasurement = 0;
2983 lastSpace = m_current.m_pos; // e.g., "Foo goo", don't ad d in any of the ignored spaces.
2984 stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_ current.m_obj, m_current.m_pos));
2985 stoppedIgnoringSpaces = true;
2986 } else {
2987 // Just keep ignoring these spaces.
2988 nextCharacter(c, lastCharacter, secondToLastCharacter);
2989 continue;
2721 } 2990 }
2722 } else 2991 }
2723 floatsFitOnLine = false; 2992
2724 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for floating element. 2993 wordMeasurements.grow(wordMeasurements.size() + 1);
2725 renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCha racter); 2994 WordMeasurement& wordMeasurement = wordMeasurements.last();
2726 } else if (current.m_obj->isRenderInline()) { 2995
2727 // Right now, we should only encounter empty inlines here. 2996 wordMeasurement.renderer = renderText;
2728 ASSERT(isEmptyInline(current.m_obj)); 2997 wordMeasurement.endOffset = m_current.m_pos;
2729 2998 wordMeasurement.startOffset = lastSpace;
2730 RenderInline* flowBox = toRenderInline(current.m_obj); 2999
2731 3000 float additionalTmpW;
2732 // Now that some inline flows have line boxes, if we are already ign oring spaces, we need 3001 if (wordTrailingSpaceWidth && c == ' ')
2733 // to make sure that we stop to include this object and then start i gnoring spaces again. 3002 additionalTmpW = textWidth(renderText, lastSpace, m_current.m_po s + 1 - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSp ace, &wordMeasurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
2734 // If this object is at the start of the line, we need to behave lik e list markers and 3003 else
2735 // start ignoring spaces. 3004 additionalTmpW = textWidth(renderText, lastSpace, m_current.m_po s - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
2736 bool requiresLineBox = alwaysRequiresLineBox(current.m_obj); 3005
2737 if (requiresLineBox || requiresLineBoxForContent(flowBox, lineInfo)) { 3006 wordMeasurement.width = additionalTmpW + wordSpacingForWordMeasureme nt;
2738 // An empty inline that only has line-height, vertical-align or font-metrics will only get a 3007 additionalTmpW += lastSpaceWordSpacing;
2739 // line box to affect the height of the line if the rest of the line is not empty. 3008 m_width.addUncommittedWidth(additionalTmpW);
2740 if (requiresLineBox) 3009 if (!m_appliedStartWidth) {
2741 lineInfo.setEmpty(false, m_block, &width); 3010 m_width.addUncommittedWidth(inlineLogicalWidth(m_current.m_obj, true, false));
2742 if (ignoringSpaces) { 3011 m_appliedStartWidth = true;
2743 trailingObjects.clear(); 3012 }
2744 ensureLineBoxInsideIgnoredSpaces(lineMidpointState, current. m_obj); 3013
2745 } else if (blockStyle->collapseWhiteSpace() && resolver.position ().m_obj == current.m_obj 3014 applyWordSpacing = wordSpacing && m_currentCharacterIsSpace;
2746 && shouldSkipWhitespaceAfterStartObject(m_block, current.m_o bj, lineMidpointState)) { 3015
2747 // Like with list markers, we start ignoring spaces to make sure that any 3016 if (!m_width.committedWidth() && m_autoWrap && !m_width.fitsOnLine() )
2748 // additional spaces we see will be discarded. 3017 m_width.fitBelowFloats();
2749 currentCharacterShouldCollapseIfPreWap = currentCharacterIsS pace = true; 3018
2750 ignoringSpaces = true; 3019 if (m_autoWrap || breakWords) {
3020 // If we break only after white-space, consider the current char acter
3021 // as candidate width for this line.
3022 bool lineWasTooWide = false;
3023 if (m_width.fitsOnLine() && m_currentCharacterIsSpace && m_curre ntStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
3024 float charWidth = textWidth(renderText, m_current.m_pos, 1, font, m_width.currentWidth(), isFixedPitch, m_collapseWhiteSpace, &wordMeasureme nt.fallbackFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
3025 // Check if line is too big even without the extra space
3026 // at the end of the line. If it is not, do nothing.
3027 // If the line needs the extra whitespace to be too long,
3028 // then move the line break to the space and skip all
3029 // additional whitespace.
3030 if (!m_width.fitsOnLine(charWidth)) {
3031 lineWasTooWide = true;
3032 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_c urrent.m_nextBreakablePosition);
3033 skipTrailingWhitespace(m_lineBreak, m_lineInfo);
3034 }
2751 } 3035 }
2752 } 3036 if (lineWasTooWide || !m_width.fitsOnLine()) {
2753 3037 if (m_lineBreak.atTextParagraphSeparator()) {
2754 width.addUncommittedWidth(inlineLogicalWidth(current.m_obj) + border PaddingMarginStart(flowBox) + borderPaddingMarginEnd(flowBox)); 3038 if (!stoppedIgnoringSpaces && m_current.m_pos > 0)
2755 } else if (current.m_obj->isReplaced()) { 3039 ensureCharacterGetsLineBox(m_lineMidpointState, m_cu rrent);
2756 RenderBox* replacedBox = toRenderBox(current.m_obj); 3040 m_lineBreak.increment();
2757 3041 m_lineInfo.setPreviousLineBrokeCleanly(true);
2758 if (atStart) 3042 wordMeasurement.endOffset = m_lineBreak.m_pos;
2759 width.updateAvailableWidth(replacedBox->logicalHeight()); 3043 }
2760 3044 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)
2761 // Break on replaced elements if either has normal white-space. 3045 hyphenated = true;
2762 if ((autoWrap || RenderStyle::autoWrap(lastWS)) && (!current.m_obj-> isImage() || allowImagesToBreak)) { 3046 if (m_lineBreak.m_pos && m_lineBreak.m_pos != (unsigned)word Measurement.endOffset && !wordMeasurement.width) {
2763 width.commit(); 3047 if (charWidth) {
2764 lBreak.moveToStartOf(current.m_obj); 3048 wordMeasurement.endOffset = m_lineBreak.m_pos;
2765 } 3049 wordMeasurement.width = charWidth;
2766
2767 if (ignoringSpaces)
2768 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, current. m_obj, 0));
2769
2770 lineInfo.setEmpty(false, m_block, &width);
2771 ignoringSpaces = false;
2772 currentCharacterShouldCollapseIfPreWap = currentCharacterIsSpace = f alse;
2773 trailingObjects.clear();
2774
2775 // Optimize for a common case. If we can't find whitespace after the list
2776 // item, then this is all moot.
2777 LayoutUnit replacedLogicalWidth = m_block->logicalWidthForChild(repl acedBox) + m_block->marginStartForChild(replacedBox) + m_block->marginEndForChil d(replacedBox) + inlineLogicalWidth(current.m_obj);
2778 if (current.m_obj->isListMarker()) {
2779 if (blockStyle->collapseWhiteSpace() && shouldSkipWhitespaceAfte rStartObject(m_block, current.m_obj, lineMidpointState)) {
2780 // Like with inline flows, we start ignoring spaces to make sure that any
2781 // additional spaces we see will be discarded.
2782 currentCharacterShouldCollapseIfPreWap = currentCharacterIsS pace = true;
2783 ignoringSpaces = true;
2784 }
2785 if (toRenderListMarker(current.m_obj)->isInside())
2786 width.addUncommittedWidth(replacedLogicalWidth);
2787 } else
2788 width.addUncommittedWidth(replacedLogicalWidth);
2789 if (current.m_obj->isRubyRun())
2790 width.applyOverhang(toRenderRubyRun(current.m_obj), last, next);
2791 // Update prior line break context characters, using U+FFFD (OBJECT REPLACEMENT CHARACTER) for replaced element.
2792 renderTextInfo.m_lineBreakIterator.updatePriorContext(replacementCha racter);
2793 } else if (current.m_obj->isText()) {
2794 if (!current.m_pos)
2795 appliedStartWidth = false;
2796
2797 RenderText* t = toRenderText(current.m_obj);
2798
2799 bool isSVGText = t->isSVGInlineText();
2800
2801 if (t->style()->hasTextCombine() && current.m_obj->isCombineText() & & !toRenderCombineText(current.m_obj)->isCombined()) {
2802 RenderCombineText* combineRenderer = toRenderCombineText(current .m_obj);
2803 combineRenderer->combineText();
2804 // The length of the renderer's text may have changed. Increment stale iterator positions
2805 if (iteratorIsBeyondEndOfRenderCombineText(lBreak, combineRender er)) {
2806 ASSERT(iteratorIsBeyondEndOfRenderCombineText(resolver.posit ion(), combineRenderer));
2807 lBreak.increment();
2808 resolver.position().increment(&resolver);
2809 }
2810 }
2811
2812 RenderStyle* style = t->style(lineInfo.isFirstLine());
2813 const Font& f = style->font();
2814 bool isFixedPitch = f.isFixedPitch();
2815
2816 unsigned lastSpace = current.m_pos;
2817 float wordSpacing = currentStyle->wordSpacing();
2818 float lastSpaceWordSpacing = 0;
2819 float wordSpacingForWordMeasurement = 0;
2820
2821 float wrapW = width.uncommittedWidth() + inlineLogicalWidth(current. m_obj, !appliedStartWidth, true);
2822 float charWidth = 0;
2823 // Auto-wrapping text should wrap in the middle of a word only if it could not wrap before the word,
2824 // which is only possible if the word is the first thing on the line , that is, if |w| is zero.
2825 bool breakWords = currentStyle->breakWords() && ((autoWrap && !width .committedWidth()) || currWS == PRE);
2826 bool midWordBreak = false;
2827 bool breakAll = currentStyle->wordBreak() == BreakAllWordBreak && au toWrap;
2828 float hyphenWidth = 0;
2829
2830 if (isSVGText) {
2831 breakWords = false;
2832 breakAll = false;
2833 }
2834
2835 if (t->isWordBreak()) {
2836 width.commit();
2837 lBreak.moveToStartOf(current.m_obj);
2838 ASSERT(current.m_pos == t->textLength());
2839 }
2840
2841 if (renderTextInfo.m_text != t) {
2842 renderTextInfo.m_text = t;
2843 renderTextInfo.m_font = &f;
2844 renderTextInfo.m_layout = f.createLayout(t, width.currentWidth() , collapseWhiteSpace);
2845 renderTextInfo.m_lineBreakIterator.resetStringAndReleaseIterator (t->text(), style->locale());
2846 } else if (renderTextInfo.m_layout && renderTextInfo.m_font != &f) {
2847 renderTextInfo.m_font = &f;
2848 renderTextInfo.m_layout = f.createLayout(t, width.currentWidth() , collapseWhiteSpace);
2849 }
2850
2851 TextLayout* textLayout = renderTextInfo.m_layout.get();
2852
2853 // Non-zero only when kerning is enabled and TextLayout isn't used, in which case we measure
2854 // words with their trailing space, then subtract its width.
2855 float wordTrailingSpaceWidth = (f.typesettingFeatures() & Kerning) & & !textLayout ? f.width(RenderBlock::constructTextRun(t, f, &space, 1, style)) + wordSpacing : 0;
2856
2857 UChar lastCharacter = renderTextInfo.m_lineBreakIterator.lastCharact er();
2858 UChar secondToLastCharacter = renderTextInfo.m_lineBreakIterator.sec ondToLastCharacter();
2859 for (; current.m_pos < t->textLength(); current.fastIncrementInTextN ode()) {
2860 bool previousCharacterIsSpace = currentCharacterIsSpace;
2861 bool previousCharacterShouldCollapseIfPreWap = currentCharacterS houldCollapseIfPreWap;
2862 UChar c = current.current();
2863 currentCharacterShouldCollapseIfPreWap = currentCharacterIsSpace = c == ' ' || c == '\t' || (!preserveNewline && (c == '\n'));
2864
2865 if (!collapseWhiteSpace || !currentCharacterIsSpace)
2866 lineInfo.setEmpty(false, m_block, &width);
2867
2868 if (c == softHyphen && autoWrap && !hyphenWidth) {
2869 hyphenWidth = measureHyphenWidth(t, f);
2870 width.addUncommittedWidth(hyphenWidth);
2871 }
2872
2873 bool applyWordSpacing = false;
2874
2875 if ((breakAll || breakWords) && !midWordBreak) {
2876 wrapW += charWidth;
2877 bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && c urrent.m_pos + 1 < t->textLength() && U16_IS_TRAIL((*t)[current.m_pos + 1]);
2878 charWidth = textWidth(t, current.m_pos, midWordBreakIsBefore SurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapse WhiteSpace, 0, textLayout);
2879 midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth();
2880 }
2881
2882 bool betweenWords = c == '\n' || (currWS != PRE && !atStart && i sBreakable(renderTextInfo.m_lineBreakIterator, current.m_pos, current.m_nextBrea kablePosition));
2883
2884 if (betweenWords || midWordBreak) {
2885 bool stoppedIgnoringSpaces = false;
2886 if (ignoringSpaces) {
2887 lastSpaceWordSpacing = 0;
2888 if (!currentCharacterIsSpace) {
2889 // Stop ignoring spaces and begin at this
2890 // new point.
2891 ignoringSpaces = false;
2892 wordSpacingForWordMeasurement = 0;
2893 lastSpace = current.m_pos; // e.g., "Foo goo", do n't add in any of the ignored spaces.
2894 stopIgnoringSpaces(lineMidpointState, InlineIterator (0, current.m_obj, current.m_pos));
2895 stoppedIgnoringSpaces = true;
2896 } else {
2897 // Just keep ignoring these spaces.
2898 goto nextCharacter;
2899 } 3050 }
2900 } 3051 }
2901 3052 // Didn't fit. Jump to the end unless there's still an oppor tunity to collapse whitespace.
2902 wordMeasurements.grow(wordMeasurements.size() + 1); 3053 if (m_ignoringSpaces || !m_collapseWhiteSpace || !m_currentC haracterIsSpace || !previousCharacterIsSpace) {
2903 WordMeasurement& wordMeasurement = wordMeasurements.last(); 3054 m_atEnd = true;
2904 3055 return false;
2905 wordMeasurement.renderer = t;
2906 wordMeasurement.endOffset = current.m_pos;
2907 wordMeasurement.startOffset = lastSpace;
2908
2909 float additionalTmpW;
2910 if (wordTrailingSpaceWidth && c == ' ')
2911 additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &word Measurement.fallbackFonts, textLayout) - wordTrailingSpaceWidth;
2912 else
2913 additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeas urement.fallbackFonts, textLayout);
2914
2915 wordMeasurement.width = additionalTmpW + wordSpacingForWordM easurement;
2916 additionalTmpW += lastSpaceWordSpacing;
2917 width.addUncommittedWidth(additionalTmpW);
2918 if (!appliedStartWidth) {
2919 width.addUncommittedWidth(inlineLogicalWidth(current.m_o bj, true, false));
2920 appliedStartWidth = true;
2921 } 3056 }
2922 3057 } else {
2923 applyWordSpacing = wordSpacing && currentCharacterIsSpace; 3058 if (!betweenWords || (midWordBreak && !m_autoWrap))
2924 3059 m_width.addUncommittedWidth(-additionalTmpW);
2925 if (!width.committedWidth() && autoWrap && !width.fitsOnLine ()) 3060 if (hyphenWidth) {
2926 width.fitBelowFloats(); 3061 // Subtract the width of the soft hyphen out since we fi t on a line.
2927 3062 m_width.addUncommittedWidth(-hyphenWidth);
2928 if (autoWrap || breakWords) { 3063 hyphenWidth = 0;
2929 // If we break only after white-space, consider the curr ent character
2930 // as candidate width for this line.
2931 bool lineWasTooWide = false;
2932 if (width.fitsOnLine() && currentCharacterIsSpace && cur rentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) {
2933 float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, &wordMeasurement.fallbac kFonts, textLayout) + (applyWordSpacing ? wordSpacing : 0);
2934 // Check if line is too big even without the extra s pace
2935 // at the end of the line. If it is not, do nothing.
2936 // If the line needs the extra whitespace to be too long,
2937 // then move the line break to the space and skip al l
2938 // additional whitespace.
2939 if (!width.fitsOnLine(charWidth)) {
2940 lineWasTooWide = true;
2941 lBreak.moveTo(current.m_obj, current.m_pos, curr ent.m_nextBreakablePosition);
2942 skipTrailingWhitespace(lBreak, lineInfo);
2943 }
2944 }
2945 if (lineWasTooWide || !width.fitsOnLine()) {
2946 if (lBreak.atTextParagraphSeparator()) {
2947 if (!stoppedIgnoringSpaces && current.m_pos > 0)
2948 ensureCharacterGetsLineBox(lineMidpointState , current);
2949 lBreak.increment();
2950 lineInfo.setPreviousLineBrokeCleanly(true);
2951 wordMeasurement.endOffset = lBreak.m_pos;
2952 }
2953 if (lBreak.m_obj && lBreak.m_pos && lBreak.m_obj->is Text() && toRenderText(lBreak.m_obj)->textLength() && toRenderText(lBreak.m_obj) ->characterAt(lBreak.m_pos - 1) == softHyphen)
2954 m_hyphenated = true;
2955 if (lBreak.m_pos && lBreak.m_pos != (unsigned)wordMe asurement.endOffset && !wordMeasurement.width) {
2956 if (charWidth) {
2957 wordMeasurement.endOffset = lBreak.m_pos;
2958 wordMeasurement.width = charWidth;
2959 }
2960 }
2961 // Didn't fit. Jump to the end unless there's still an opportunity to collapse whitespace.
2962 if (ignoringSpaces || !collapseWhiteSpace || !curren tCharacterIsSpace || !previousCharacterIsSpace)
2963 goto end;
2964 } else {
2965 if (!betweenWords || (midWordBreak && !autoWrap))
2966 width.addUncommittedWidth(-additionalTmpW);
2967 if (hyphenWidth) {
2968 // Subtract the width of the soft hyphen out sin ce we fit on a line.
2969 width.addUncommittedWidth(-hyphenWidth);
2970 hyphenWidth = 0;
2971 }
2972 }
2973 } 3064 }
2974
2975 if (c == '\n' && preserveNewline) {
2976 if (!stoppedIgnoringSpaces && current.m_pos > 0)
2977 ensureCharacterGetsLineBox(lineMidpointState, curren t);
2978 lBreak.moveTo(current.m_obj, current.m_pos, current.m_ne xtBreakablePosition);
2979 lBreak.increment();
2980 lineInfo.setPreviousLineBrokeCleanly(true);
2981 return lBreak;
2982 }
2983
2984 if (autoWrap && betweenWords) {
2985 width.commit();
2986 wrapW = 0;
2987 lBreak.moveTo(current.m_obj, current.m_pos, current.m_ne xtBreakablePosition);
2988 // Auto-wrapping text should not wrap in the middle of a word once it has had an
2989 // opportunity to break after a word.
2990 breakWords = false;
2991 }
2992
2993 if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mar k_NonSpacing | Mark_Enclosing | Mark_SpacingCombining))) {
2994 // Remember this as a breakable position in case
2995 // adding the end width forces a break.
2996 lBreak.moveTo(current.m_obj, current.m_pos, current.m_ne xtBreakablePosition);
2997 midWordBreak &= (breakWords || breakAll);
2998 }
2999
3000 if (betweenWords) {
3001 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
3002 wordSpacingForWordMeasurement = (applyWordSpacing && wor dMeasurement.width) ? wordSpacing : 0;
3003 lastSpace = current.m_pos;
3004 }
3005
3006 if (!ignoringSpaces && currentStyle->collapseWhiteSpace()) {
3007 // If we encounter a newline, or if we encounter a
3008 // second space, we need to go ahead and break up this
3009 // run and enter a mode where we start collapsing spaces .
3010 if (currentCharacterIsSpace && previousCharacterIsSpace) {
3011 ignoringSpaces = true;
3012
3013 // We just entered a mode where we are ignoring
3014 // spaces. Create a midpoint to terminate the run
3015 // before the second space.
3016 startIgnoringSpaces(lineMidpointState, ignoreStart);
3017 trailingObjects.updateMidpointsForTrailingBoxes(line MidpointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
3018 }
3019 }
3020 } else if (ignoringSpaces) {
3021 // Stop ignoring spaces and begin at this
3022 // new point.
3023 ignoringSpaces = false;
3024 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
3025 wordSpacingForWordMeasurement = (applyWordSpacing && wordMea surements.last().width) ? wordSpacing : 0;
3026 lastSpace = current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
3027 stopIgnoringSpaces(lineMidpointState, InlineIterator(0, curr ent.m_obj, current.m_pos));
3028 } 3065 }
3029 3066 }
3030 if (isSVGText && current.m_pos > 0) { 3067
3031 // Force creation of new InlineBoxes for each absolute posit ioned character (those that start new text chunks). 3068 if (c == '\n' && m_preservesNewline) {
3032 if (toRenderSVGInlineText(t)->characterStartsNewTextChunk(cu rrent.m_pos)) 3069 if (!stoppedIgnoringSpaces && m_current.m_pos > 0)
3033 ensureCharacterGetsLineBox(lineMidpointState, current); 3070 ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
3071 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m _nextBreakablePosition);
3072 m_lineBreak.increment();
3073 m_lineInfo.setPreviousLineBrokeCleanly(true);
3074 return true;
3075 }
3076
3077 if (m_autoWrap && betweenWords) {
3078 m_width.commit();
3079 wrapW = 0;
3080 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m _nextBreakablePosition);
3081 // Auto-wrapping text should not wrap in the middle of a word on ce it has had an
3082 // opportunity to break after a word.
3083 breakWords = false;
3084 }
3085
3086 if (midWordBreak && !U16_IS_TRAIL(c) && !(category(c) & (Mark_NonSpa cing | Mark_Enclosing | Mark_SpacingCombining))) {
3087 // Remember this as a breakable position in case
3088 // adding the end width forces a break.
3089 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m _nextBreakablePosition);
3090 midWordBreak &= (breakWords || breakAll);
3091 }
3092
3093 if (betweenWords) {
3094 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
3095 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasure ment.width) ? wordSpacing : 0;
3096 lastSpace = m_current.m_pos;
3097 }
3098
3099 if (!m_ignoringSpaces && m_currentStyle->collapseWhiteSpace()) {
3100 // If we encounter a newline, or if we encounter a
3101 // second space, we need to go ahead and break up this
3102 // run and enter a mode where we start collapsing spaces.
3103 if (m_currentCharacterIsSpace && previousCharacterIsSpace) {
3104 m_ignoringSpaces = true;
3105
3106 // We just entered a mode where we are ignoring
3107 // spaces. Create a midpoint to terminate the run
3108 // before the second space.
3109 startIgnoringSpaces(m_lineMidpointState, m_startOfIgnoredSpa ces);
3110 m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidp ointState, InlineIterator(), TrailingObjects::DoNotCollapseFirstSpace);
3034 } 3111 }
3035 3112 }
3036 if (currentCharacterIsSpace && !previousCharacterIsSpace) { 3113 } else if (m_ignoringSpaces) {
3037 ignoreStart.m_obj = current.m_obj; 3114 // Stop ignoring spaces and begin at this
3038 ignoreStart.m_pos = current.m_pos; 3115 // new point.
3039 } 3116 m_ignoringSpaces = false;
3040 3117 lastSpaceWordSpacing = applyWordSpacing ? wordSpacing : 0;
3041 if (!currentCharacterIsSpace && previousCharacterShouldCollapseI fPreWap) { 3118 wordSpacingForWordMeasurement = (applyWordSpacing && wordMeasurement s.last().width) ? wordSpacing : 0;
3042 if (autoWrap && currentStyle->breakOnlyAfterWhiteSpace()) 3119 lastSpace = m_current.m_pos; // e.g., "Foo goo", don't add in any of the ignored spaces.
3043 lBreak.moveTo(current.m_obj, current.m_pos, current.m_ne xtBreakablePosition); 3120 stopIgnoringSpaces(m_lineMidpointState, InlineIterator(0, m_current. m_obj, m_current.m_pos));
3044 } 3121 }
3045 3122
3046 if (collapseWhiteSpace && currentCharacterIsSpace && !ignoringSp aces) 3123 if (isSVGText && m_current.m_pos > 0) {
3047 trailingObjects.setTrailingWhitespace(toRenderText(current.m _obj)); 3124 // Force creation of new InlineBoxes for each absolute positioned ch aracter (those that start new text chunks).
3048 else if (!currentStyle->collapseWhiteSpace() || !currentCharacte rIsSpace) 3125 if (toRenderSVGInlineText(renderText)->characterStartsNewTextChunk(m _current.m_pos))
3049 trailingObjects.clear(); 3126 ensureCharacterGetsLineBox(m_lineMidpointState, m_current);
3050 3127 }
3051 atStart = false; 3128
3052 nextCharacter: 3129 if (m_currentCharacterIsSpace && !previousCharacterIsSpace) {
3053 secondToLastCharacter = lastCharacter; 3130 m_startOfIgnoredSpaces.m_obj = m_current.m_obj;
3054 lastCharacter = c; 3131 m_startOfIgnoredSpaces.m_pos = m_current.m_pos;
3055 } 3132 }
3056 3133
3057 renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, se condToLastCharacter); 3134 if (!m_currentCharacterIsSpace && previousCharacterShouldCollapseIfPreWa p) {
3058 3135 if (m_autoWrap && m_currentStyle->breakOnlyAfterWhiteSpace())
3059 wordMeasurements.grow(wordMeasurements.size() + 1); 3136 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos, m_current.m _nextBreakablePosition);
3060 WordMeasurement& wordMeasurement = wordMeasurements.last(); 3137 }
3061 wordMeasurement.renderer = t; 3138
3062 3139 if (m_collapseWhiteSpace && m_currentCharacterIsSpace && !m_ignoringSpac es)
3063 // IMPORTANT: current.m_pos is > length here! 3140 m_trailingObjects.setTrailingWhitespace(toRenderText(m_current.m_obj ));
3064 float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteS pace, &wordMeasurement.fallbackFonts, textLayout); 3141 else if (!m_currentStyle->collapseWhiteSpace() || !m_currentCharacterIsS pace)
3065 wordMeasurement.startOffset = lastSpace; 3142 m_trailingObjects.clear();
3066 wordMeasurement.endOffset = current.m_pos; 3143
3067 wordMeasurement.width = ignoringSpaces ? 0 : additionalTmpW + wordSp acingForWordMeasurement; 3144 m_atStart = false;
3068 additionalTmpW += lastSpaceWordSpacing; 3145 nextCharacter(c, lastCharacter, secondToLastCharacter);
3069 width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(curren t.m_obj, !appliedStartWidth, includeEndWidth)); 3146 }
3070 includeEndWidth = false; 3147
3071 3148 m_renderTextInfo.m_lineBreakIterator.setPriorContext(lastCharacter, secondTo LastCharacter);
3072 if (!width.fitsOnLine()) { 3149
3073 if (!m_hyphenated && lBreak.previousInSameNode() == softHyphen) 3150 wordMeasurements.grow(wordMeasurements.size() + 1);
3074 m_hyphenated = true; 3151 WordMeasurement& wordMeasurement = wordMeasurements.last();
3075 3152 wordMeasurement.renderer = renderText;
3076 if (m_hyphenated) 3153
3077 goto end; 3154 // IMPORTANT: current.m_pos is > length here!
3078 } 3155 float additionalTmpW = m_ignoringSpaces ? 0 : textWidth(renderText, lastSpac e, m_current.m_pos - lastSpace, font, m_width.currentWidth(), isFixedPitch, m_co llapseWhiteSpace, &wordMeasurement.fallbackFonts, textLayout);
3079 } else 3156 wordMeasurement.startOffset = lastSpace;
3080 ASSERT_NOT_REACHED(); 3157 wordMeasurement.endOffset = m_current.m_pos;
3081 3158 wordMeasurement.width = m_ignoringSpaces ? 0 : additionalTmpW + wordSpacingF orWordMeasurement;
3082 bool checkForBreak = autoWrap; 3159 additionalTmpW += lastSpaceWordSpacing;
3083 if (width.committedWidth() && !width.fitsOnLine() && lBreak.m_obj && cur rWS == NOWRAP) 3160 m_width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(m_current.m_ obj, !m_appliedStartWidth, m_includeEndWidth));
3161 m_includeEndWidth = false;
3162
3163 if (!m_width.fitsOnLine()) {
3164 if (!hyphenated && m_lineBreak.previousInSameNode() == softHyphen) {
3165 hyphenated = true;
3166 m_atEnd = true;
3167 }
3168 }
3169 return false;
3170 }
3171
3172 inline void LineBreaker::BreakingContext::commitAndUpdateLineBreakIfNeeded()
3173 {
3174 bool checkForBreak = m_autoWrap;
3175 if (m_width.committedWidth() && !m_width.fitsOnLine() && m_lineBreak.m_obj & & m_currWS == NOWRAP) {
3176 checkForBreak = true;
3177 } else if (m_nextObject && m_current.m_obj->isText() && m_nextObject->isText () && !m_nextObject->isBR() && (m_autoWrap || m_nextObject->style()->autoWrap()) ) {
3178 if (m_autoWrap && m_currentCharacterIsSpace) {
3084 checkForBreak = true; 3179 checkForBreak = true;
3085 else if (next && current.m_obj->isText() && next->isText() && !next->isB R() && (autoWrap || next->style()->autoWrap())) { 3180 } else {
3086 if (autoWrap && currentCharacterIsSpace) 3181 RenderText* nextText = toRenderText(m_nextObject);
3182 if (nextText->textLength()) {
3183 UChar c = nextText->characterAt(0);
3184 // If the next item on the line is text, and if we did not end w ith
3185 // a space, then the next text run continues our word (and so it needs to
3186 // keep adding to the uncommitted width. Just update and continu e.
3187 checkForBreak = !m_currentCharacterIsSpace && (c == ' ' || c == '\t' || (c == '\n' && !m_nextObject->preservesNewline()));
3188 } else if (nextText->isWordBreak()) {
3087 checkForBreak = true; 3189 checkForBreak = true;
3088 else { 3190 }
3089 RenderText* nextText = toRenderText(next); 3191
3090 if (nextText->textLength()) { 3192 if (!m_width.fitsOnLine() && !m_width.committedWidth())
3091 UChar c = nextText->characterAt(0); 3193 m_width.fitBelowFloats();
3092 // If the next item on the line is text, and if we did not e nd with 3194
3093 // a space, then the next text run continues our word (and s o it needs to 3195 bool canPlaceOnLine = m_width.fitsOnLine() || !m_autoWrapWasEverTrue OnLine;
3094 // keep adding to the uncommitted width. Just update and con tinue. 3196 if (canPlaceOnLine && checkForBreak) {
3095 checkForBreak = !currentCharacterIsSpace && (c == ' ' || c = = '\t' || (c == '\n' && !next->preservesNewline())); 3197 m_width.commit();
3096 } else if (nextText->isWordBreak()) 3198 m_lineBreak.moveToStartOf(m_nextObject);
3097 checkForBreak = true; 3199 }
3098 3200 }
3099 if (!width.fitsOnLine() && !width.committedWidth()) 3201 }
3100 width.fitBelowFloats(); 3202
3101 3203 if (checkForBreak && !m_width.fitsOnLine()) {
3102 bool canPlaceOnLine = width.fitsOnLine() || !autoWrapWasEverTrue OnLine; 3204 // if we have floats, try to get below them.
3103 if (canPlaceOnLine && checkForBreak) { 3205 if (m_currentCharacterIsSpace && !m_ignoringSpaces && m_currentStyle->co llapseWhiteSpace())
3104 width.commit(); 3206 m_trailingObjects.clear();
3105 lBreak.moveToStartOf(next); 3207
3106 } 3208 if (m_width.committedWidth()) {
3107 } 3209 m_atEnd = true;
3108 } 3210 return;
3109 3211 }
3110 if (checkForBreak && !width.fitsOnLine()) { 3212
3111 // if we have floats, try to get below them. 3213 m_width.fitBelowFloats();
3112 if (currentCharacterIsSpace && !ignoringSpaces && currentStyle->coll apseWhiteSpace()) 3214
3113 trailingObjects.clear(); 3215 // |width| may have been adjusted because we got shoved down past a floa t (thus
3114 3216 // giving us more room), so we need to retest, and only jump to
3115 if (width.committedWidth()) 3217 // the end label if we still don't fit on the line. -dwh
3116 goto end; 3218 if (!m_width.fitsOnLine()) {
3117 3219 m_atEnd = true;
3118 width.fitBelowFloats(); 3220 return;
3119 3221 }
3120 // |width| may have been adjusted because we got shoved down past a float (thus 3222 } else if (m_blockStyle->autoWrap() && !m_width.fitsOnLine() && !m_width.com mittedWidth()) {
3121 // giving us more room), so we need to retest, and only jump to 3223 // If the container autowraps but the current child does not then we sti ll need to ensure that it
3122 // the end label if we still don't fit on the line. -dwh 3224 // wraps and moves below any floats.
3123 if (!width.fitsOnLine()) 3225 m_width.fitBelowFloats();
3124 goto end; 3226 }
3125 } else if (blockStyle->autoWrap() && !width.fitsOnLine() && !width.commi ttedWidth()) { 3227
3126 // If the container autowraps but the current child does not then we still need to ensure that it 3228 if (!m_current.m_obj->isFloatingOrOutOfFlowPositioned()) {
3127 // wraps and moves below any floats. 3229 m_lastObject = m_current.m_obj;
3128 width.fitBelowFloats(); 3230 if (m_lastObject->isReplaced() && m_autoWrap && (!m_lastObject->isImage( ) || m_allowImagesToBreak) && (!m_lastObject->isListMarker() || toRenderListMark er(m_lastObject)->isInside())) {
3129 } 3231 m_width.commit();
3130 3232 m_lineBreak.moveToStartOf(m_nextObject);
3131 if (!current.m_obj->isFloatingOrOutOfFlowPositioned()) { 3233 }
3132 last = current.m_obj; 3234 }
3133 if (last->isReplaced() && autoWrap && (!last->isImage() || allowImag esToBreak) && (!last->isListMarker() || toRenderListMarker(last)->isInside())) { 3235 }
3134 width.commit(); 3236
3135 lBreak.moveToStartOf(next); 3237 InlineIterator LineBreaker::BreakingContext::handleEndOfLine()
3136 } 3238 {
3137 }
3138
3139 // Clear out our character space bool, since inline <pre>s don't collaps e whitespace
3140 // with adjacent inline normal/nowrap spans.
3141 if (!collapseWhiteSpace)
3142 currentCharacterIsSpace = false;
3143
3144 current.moveToStartOf(next);
3145 atStart = false;
3146 }
3147
3148 if (width.fitsOnLine() || lastWS == NOWRAP)
3149 lBreak.clear();
3150
3151 end:
3152 ShapeInsideInfo* shapeInfo = m_block->layoutShapeInsideInfo(); 3239 ShapeInsideInfo* shapeInfo = m_block->layoutShapeInsideInfo();
3153 bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments(); 3240 bool segmentAllowsOverflow = !shapeInfo || !shapeInfo->hasSegments();
3154 3241
3155 if (lBreak == resolver.position() && (!lBreak.m_obj || !lBreak.m_obj->isBR() ) && segmentAllowsOverflow) { 3242 if (m_lineBreak == m_resolver.position() && (!m_lineBreak.m_obj || !m_lineBr eak.m_obj->isBR()) && segmentAllowsOverflow) {
3156 // we just add as much as possible 3243 // we just add as much as possible
3157 if (blockStyle->whiteSpace() == PRE && !current.m_pos) { 3244 if (m_blockStyle->whiteSpace() == PRE && !m_current.m_pos) {
3158 lBreak.moveTo(last, last->isText() ? last->length() : 0); 3245 m_lineBreak.moveTo(m_lastObject, m_lastObject->isText() ? m_lastObje ct->length() : 0);
3159 } else if (lBreak.m_obj) { 3246 } else if (m_lineBreak.m_obj) {
3160 // Don't ever break in the middle of a word if we can help it. 3247 // Don't ever break in the middle of a word if we can help it.
3161 // There's no room at all. We just have to be on this line, 3248 // There's no room at all. We just have to be on this line,
3162 // even though we'll spill out. 3249 // even though we'll spill out.
3163 lBreak.moveTo(current.m_obj, current.m_pos); 3250 m_lineBreak.moveTo(m_current.m_obj, m_current.m_pos);
3164 } 3251 }
3165 } 3252 }
3166 3253
3167 // FIXME Bug 100049: We do not need to consume input in a multi-segment line 3254 // FIXME Bug 100049: We do not need to consume input in a multi-segment line
3168 // unless no segment will. 3255 // unless no segment will.
3169 // make sure we consume at least one char/object. 3256 // make sure we consume at least one char/object.
3170 if (lBreak == resolver.position() && segmentAllowsOverflow) 3257 if (m_lineBreak == m_resolver.position() && segmentAllowsOverflow)
3171 lBreak.increment(); 3258 m_lineBreak.increment();
3172 3259
3173 // Sanity check our midpoints. 3260 // Sanity check our midpoints.
3174 checkMidpoints(lineMidpointState, lBreak); 3261 checkMidpoints(m_lineMidpointState, m_lineBreak);
3175 3262
3176 trailingObjects.updateMidpointsForTrailingBoxes(lineMidpointState, lBreak, T railingObjects::CollapseFirstSpace); 3263 m_trailingObjects.updateMidpointsForTrailingBoxes(m_lineMidpointState, m_lin eBreak, TrailingObjects::CollapseFirstSpace);
3177 3264
3178 // We might have made lBreak an iterator that points past the end 3265 // We might have made lineBreak an iterator that points past the end
3179 // of the object. Do this adjustment to make it point to the start 3266 // of the object. Do this adjustment to make it point to the start
3180 // of the next object instead to avoid confusing the rest of the 3267 // of the next object instead to avoid confusing the rest of the
3181 // code. 3268 // code.
3182 if (lBreak.m_pos > 0) { 3269 if (m_lineBreak.m_pos > 0) {
3183 lBreak.m_pos--; 3270 m_lineBreak.m_pos--;
3184 lBreak.increment(); 3271 m_lineBreak.increment();
3185 } 3272 }
3186 3273
3187 return lBreak; 3274 return m_lineBreak;
3275 }
3276
3277 InlineIterator LineBreaker::nextSegmentBreak(InlineBidiResolver& resolver, LineI nfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPrev iousLine, unsigned consecutiveHyphenatedLines, WordMeasurements& wordMeasurement s)
3278 {
3279 reset();
3280
3281 ASSERT(resolver.position().root() == m_block);
3282
3283 bool appliedStartWidth = resolver.position().m_pos > 0;
3284
3285 LineWidth width(*m_block, lineInfo.isFirstLine(), requiresIndent(lineInfo.is FirstLine(), lineInfo.previousLineBrokeCleanly(), m_block->style()));
3286
3287 skipLeadingWhitespace(resolver, lineInfo, lastFloatFromPreviousLine, width);
3288
3289 if (resolver.position().atEnd())
3290 return resolver.position();
3291
3292 BreakingContext context(resolver, lineInfo, width, renderTextInfo, lastFloat FromPreviousLine, appliedStartWidth, m_block);
3293
3294 while (context.currentObject()) {
3295 context.initializeForCurrentObject();
3296 if (context.currentObject()->isBR()) {
3297 context.handleBR(m_clear);
3298 } else if (context.currentObject()->isOutOfFlowPositioned()) {
3299 context.handleOutOfFlowPositioned(m_positionedObjects);
3300 } else if (context.currentObject()->isFloating()) {
3301 context.handleFloat();
3302 } else if (context.currentObject()->isRenderInline()) {
3303 context.handleEmptyInline();
3304 } else if (context.currentObject()->isReplaced()) {
3305 context.handleReplaced();
3306 } else if (context.currentObject()->isText()) {
3307 if (context.handleText(wordMeasurements, m_hyphenated)) {
3308 // We've hit a hard text line break. Our line break iterator is updated, so go ahead and early return.
3309 return context.lineBreak();
3310 }
3311 } else {
3312 ASSERT_NOT_REACHED();
3313 }
3314
3315 if (context.atEnd())
3316 return context.handleEndOfLine();
3317
3318 context.commitAndUpdateLineBreakIfNeeded();
3319
3320 if (context.atEnd())
3321 return context.handleEndOfLine();
3322
3323 context.increment();
3324 }
3325
3326 context.clearLineBreakIfFitsOnLine();
3327
3328 return context.handleEndOfLine();
3188 } 3329 }
3189 3330
3190 void RenderBlock::addOverflowFromInlineChildren() 3331 void RenderBlock::addOverflowFromInlineChildren()
3191 { 3332 {
3192 LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : LayoutUnit(); 3333 LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : LayoutUnit();
3193 // FIXME: Need to find another way to do this, since scrollbars could show w hen we don't want them to. 3334 // FIXME: Need to find another way to do this, since scrollbars could show w hen we don't want them to.
3194 if (hasOverflowClip() && !endPadding && node() && node()->isRootEditableElem ent() && style()->isLeftToRightDirection()) 3335 if (hasOverflowClip() && !endPadding && node() && node()->isRootEditableElem ent() && style()->isLeftToRightDirection())
3195 endPadding = 1; 3336 endPadding = 1;
3196 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 3337 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
3197 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding)); 3338 addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding));
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
3360 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, ver ticalPositionCache); 3501 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, ver ticalPositionCache);
3361 3502
3362 setLineGridBox(lineGridBox); 3503 setLineGridBox(lineGridBox);
3363 3504
3364 // FIXME: If any of the characteristics of the box change compared to the ol d one, then we need to do a deep dirtying 3505 // FIXME: If any of the characteristics of the box change compared to the ol d one, then we need to do a deep dirtying
3365 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping 3506 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
3366 // to this grid. 3507 // to this grid.
3367 } 3508 }
3368 3509
3369 } 3510 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698