/src/3rdparty/webkit/Source/WebCore/rendering/RenderBlockLineLayout.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 2461 lines · 1817 code · 339 blank · 305 comment · 737 complexity · 26d2e012c089f2a89fc45467119eb825 MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. * Copyright (C) 2000 Lars Knoll (knoll@kde.org)
  3. * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All right reserved.
  4. * Copyright (C) 2010 Google Inc. All rights reserved.
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Library General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Library General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Library General Public License
  17. * along with this library; see the file COPYING.LIB. If not, write to
  18. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  19. * Boston, MA 02110-1301, USA.
  20. *
  21. */
  22. #include "config.h"
  23. #include "BidiResolver.h"
  24. #include "Hyphenation.h"
  25. #include "InlineIterator.h"
  26. #include "InlineTextBox.h"
  27. #include "Logging.h"
  28. #include "RenderArena.h"
  29. #include "RenderCombineText.h"
  30. #include "RenderInline.h"
  31. #include "RenderLayer.h"
  32. #include "RenderListMarker.h"
  33. #include "RenderRubyRun.h"
  34. #include "RenderView.h"
  35. #include "Settings.h"
  36. #include "TextBreakIterator.h"
  37. #include "TextRun.h"
  38. #include "TrailingFloatsRootInlineBox.h"
  39. #include "VerticalPositionCache.h"
  40. #include "break_lines.h"
  41. #include <wtf/AlwaysInline.h>
  42. #include <wtf/RefCountedLeakCounter.h>
  43. #include <wtf/StdLibExtras.h>
  44. #include <wtf/Vector.h>
  45. #include <wtf/unicode/CharacterNames.h>
  46. #if ENABLE(SVG)
  47. #include "RenderSVGInlineText.h"
  48. #include "SVGRootInlineBox.h"
  49. #endif
  50. using namespace std;
  51. using namespace WTF;
  52. using namespace Unicode;
  53. namespace WebCore {
  54. // We don't let our line box tree for a single line get any deeper than this.
  55. const unsigned cMaxLineDepth = 200;
  56. class LineInfo {
  57. public:
  58. LineInfo()
  59. : m_isFirstLine(true)
  60. , m_isLastLine(false)
  61. , m_isEmpty(true)
  62. , m_previousLineBrokeCleanly(true)
  63. { }
  64. bool isFirstLine() const { return m_isFirstLine; }
  65. bool isLastLine() const { return m_isLastLine; }
  66. bool isEmpty() const { return m_isEmpty; }
  67. bool previousLineBrokeCleanly() const { return m_previousLineBrokeCleanly; }
  68. void setFirstLine(bool firstLine) { m_isFirstLine = firstLine; }
  69. void setLastLine(bool lastLine) { m_isLastLine = lastLine; }
  70. void setEmpty(bool empty) { m_isEmpty = empty; }
  71. void setPreviousLineBrokeCleanly(bool previousLineBrokeCleanly) { m_previousLineBrokeCleanly = previousLineBrokeCleanly; }
  72. private:
  73. bool m_isFirstLine;
  74. bool m_isLastLine;
  75. bool m_isEmpty;
  76. bool m_previousLineBrokeCleanly;
  77. };
  78. static inline int borderPaddingMarginStart(RenderInline* child)
  79. {
  80. return child->marginStart() + child->paddingStart() + child->borderStart();
  81. }
  82. static inline int borderPaddingMarginEnd(RenderInline* child)
  83. {
  84. return child->marginEnd() + child->paddingEnd() + child->borderEnd();
  85. }
  86. static int inlineLogicalWidth(RenderObject* child, bool start = true, bool end = true)
  87. {
  88. unsigned lineDepth = 1;
  89. int extraWidth = 0;
  90. RenderObject* parent = child->parent();
  91. while (parent->isRenderInline() && lineDepth++ < cMaxLineDepth) {
  92. RenderInline* parentAsRenderInline = toRenderInline(parent);
  93. if (start && !child->previousSibling())
  94. extraWidth += borderPaddingMarginStart(parentAsRenderInline);
  95. if (end && !child->nextSibling())
  96. extraWidth += borderPaddingMarginEnd(parentAsRenderInline);
  97. child = parent;
  98. parent = child->parent();
  99. }
  100. return extraWidth;
  101. }
  102. static void checkMidpoints(LineMidpointState& lineMidpointState, InlineIterator& lBreak)
  103. {
  104. // Check to see if our last midpoint is a start point beyond the line break. If so,
  105. // shave it off the list, and shave off a trailing space if the previous end point doesn't
  106. // preserve whitespace.
  107. if (lBreak.m_obj && lineMidpointState.numMidpoints && !(lineMidpointState.numMidpoints % 2)) {
  108. InlineIterator* midpoints = lineMidpointState.midpoints.data();
  109. InlineIterator& endpoint = midpoints[lineMidpointState.numMidpoints - 2];
  110. const InlineIterator& startpoint = midpoints[lineMidpointState.numMidpoints - 1];
  111. InlineIterator currpoint = endpoint;
  112. while (!currpoint.atEnd() && currpoint != startpoint && currpoint != lBreak)
  113. currpoint.increment();
  114. if (currpoint == lBreak) {
  115. // We hit the line break before the start point. Shave off the start point.
  116. lineMidpointState.numMidpoints--;
  117. if (endpoint.m_obj->style()->collapseWhiteSpace())
  118. endpoint.m_pos--;
  119. }
  120. }
  121. }
  122. static void addMidpoint(LineMidpointState& lineMidpointState, const InlineIterator& midpoint)
  123. {
  124. if (lineMidpointState.midpoints.size() <= lineMidpointState.numMidpoints)
  125. lineMidpointState.midpoints.grow(lineMidpointState.numMidpoints + 10);
  126. InlineIterator* midpoints = lineMidpointState.midpoints.data();
  127. midpoints[lineMidpointState.numMidpoints++] = midpoint;
  128. }
  129. static inline BidiRun* createRun(int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
  130. {
  131. return new (obj->renderArena()) BidiRun(start, end, obj, resolver.context(), resolver.dir());
  132. }
  133. void RenderBlock::appendRunsForObject(BidiRunList<BidiRun>& runs, int start, int end, RenderObject* obj, InlineBidiResolver& resolver)
  134. {
  135. if (start > end || obj->isFloating() ||
  136. (obj->isPositioned() && !obj->style()->isOriginalDisplayInlineType() && !obj->container()->isRenderInline()))
  137. return;
  138. LineMidpointState& lineMidpointState = resolver.midpointState();
  139. bool haveNextMidpoint = (lineMidpointState.currentMidpoint < lineMidpointState.numMidpoints);
  140. InlineIterator nextMidpoint;
  141. if (haveNextMidpoint)
  142. nextMidpoint = lineMidpointState.midpoints[lineMidpointState.currentMidpoint];
  143. if (lineMidpointState.betweenMidpoints) {
  144. if (!(haveNextMidpoint && nextMidpoint.m_obj == obj))
  145. return;
  146. // This is a new start point. Stop ignoring objects and
  147. // adjust our start.
  148. lineMidpointState.betweenMidpoints = false;
  149. start = nextMidpoint.m_pos;
  150. lineMidpointState.currentMidpoint++;
  151. if (start < end)
  152. return appendRunsForObject(runs, start, end, obj, resolver);
  153. } else {
  154. if (!haveNextMidpoint || (obj != nextMidpoint.m_obj)) {
  155. runs.addRun(createRun(start, end, obj, resolver));
  156. return;
  157. }
  158. // An end midpoint has been encountered within our object. We
  159. // need to go ahead and append a run with our endpoint.
  160. if (static_cast<int>(nextMidpoint.m_pos + 1) <= end) {
  161. lineMidpointState.betweenMidpoints = true;
  162. lineMidpointState.currentMidpoint++;
  163. if (nextMidpoint.m_pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
  164. if (static_cast<int>(nextMidpoint.m_pos + 1) > start)
  165. runs.addRun(createRun(start, nextMidpoint.m_pos + 1, obj, resolver));
  166. return appendRunsForObject(runs, nextMidpoint.m_pos + 1, end, obj, resolver);
  167. }
  168. } else
  169. runs.addRun(createRun(start, end, obj, resolver));
  170. }
  171. }
  172. static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRootLineBox, bool isOnlyRun = false)
  173. {
  174. if (isRootLineBox)
  175. return toRenderBlock(obj)->createAndAppendRootInlineBox();
  176. if (obj->isText()) {
  177. InlineTextBox* textBox = toRenderText(obj)->createInlineTextBox();
  178. // We only treat a box as text for a <br> if we are on a line by ourself or in strict mode
  179. // (Note the use of strict mode. In "almost strict" mode, we don't treat the box for <br> as text.)
  180. if (obj->isBR())
  181. textBox->setIsText(isOnlyRun || obj->document()->inNoQuirksMode());
  182. return textBox;
  183. }
  184. if (obj->isBox())
  185. return toRenderBox(obj)->createInlineBox();
  186. return toRenderInline(obj)->createAndAppendInlineFlowBox();
  187. }
  188. static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout)
  189. {
  190. if (o->isText()) {
  191. if (o->preferredLogicalWidthsDirty() && (o->isCounter() || o->isQuote()))
  192. toRenderText(o)->computePreferredLogicalWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed.
  193. toRenderText(o)->dirtyLineBoxes(fullLayout);
  194. } else
  195. toRenderInline(o)->dirtyLineBoxes(fullLayout);
  196. }
  197. static bool parentIsConstructedOrHaveNext(InlineFlowBox* parentBox)
  198. {
  199. do {
  200. if (parentBox->isConstructed() || parentBox->nextOnLine())
  201. return true;
  202. parentBox = parentBox->parent();
  203. } while (parentBox);
  204. return false;
  205. }
  206. InlineFlowBox* RenderBlock::createLineBoxes(RenderObject* obj, const LineInfo& lineInfo, InlineBox* childBox)
  207. {
  208. // See if we have an unconstructed line box for this object that is also
  209. // the last item on the line.
  210. unsigned lineDepth = 1;
  211. InlineFlowBox* parentBox = 0;
  212. InlineFlowBox* result = 0;
  213. bool hasDefaultLineBoxContain = style()->lineBoxContain() == RenderStyle::initialLineBoxContain();
  214. do {
  215. ASSERT(obj->isRenderInline() || obj == this);
  216. RenderInline* inlineFlow = (obj != this) ? toRenderInline(obj) : 0;
  217. // Get the last box we made for this render object.
  218. parentBox = inlineFlow ? inlineFlow->lastLineBox() : toRenderBlock(obj)->lastLineBox();
  219. // If this box or its ancestor is constructed then it is from a previous line, and we need
  220. // to make a new box for our line. If this box or its ancestor is unconstructed but it has
  221. // something following it on the line, then we know we have to make a new box
  222. // as well. In this situation our inline has actually been split in two on
  223. // the same line (this can happen with very fancy language mixtures).
  224. bool constructedNewBox = false;
  225. bool allowedToConstructNewBox = !hasDefaultLineBoxContain || !inlineFlow || inlineFlow->alwaysCreateLineBoxes();
  226. bool canUseExistingParentBox = parentBox && !parentIsConstructedOrHaveNext(parentBox);
  227. if (allowedToConstructNewBox && !canUseExistingParentBox) {
  228. // We need to make a new box for this render object. Once
  229. // made, we need to place it at the end of the current line.
  230. InlineBox* newBox = createInlineBoxForRenderer(obj, obj == this);
  231. ASSERT(newBox->isInlineFlowBox());
  232. parentBox = static_cast<InlineFlowBox*>(newBox);
  233. parentBox->setFirstLineStyleBit(lineInfo.isFirstLine());
  234. parentBox->setIsHorizontal(isHorizontalWritingMode());
  235. if (!hasDefaultLineBoxContain)
  236. parentBox->clearDescendantsHaveSameLineHeightAndBaseline();
  237. constructedNewBox = true;
  238. }
  239. if (constructedNewBox || canUseExistingParentBox) {
  240. if (!result)
  241. result = parentBox;
  242. // If we have hit the block itself, then |box| represents the root
  243. // inline box for the line, and it doesn't have to be appended to any parent
  244. // inline.
  245. if (childBox)
  246. parentBox->addToLine(childBox);
  247. if (!constructedNewBox || obj == this)
  248. break;
  249. childBox = parentBox;
  250. }
  251. // If we've exceeded our line depth, then jump straight to the root and skip all the remaining
  252. // intermediate inline flows.
  253. obj = (++lineDepth >= cMaxLineDepth) ? this : obj->parent();
  254. } while (true);
  255. return result;
  256. }
  257. static bool reachedEndOfTextRenderer(const BidiRunList<BidiRun>& bidiRuns)
  258. {
  259. BidiRun* run = bidiRuns.logicallyLastRun();
  260. if (!run)
  261. return true;
  262. unsigned int pos = run->stop();
  263. RenderObject* r = run->m_object;
  264. if (!r->isText() || r->isBR())
  265. return false;
  266. RenderText* renderText = toRenderText(r);
  267. if (pos >= renderText->textLength())
  268. return true;
  269. while (isASCIISpace(renderText->characters()[pos])) {
  270. pos++;
  271. if (pos >= renderText->textLength())
  272. return true;
  273. }
  274. return false;
  275. }
  276. RootInlineBox* RenderBlock::constructLine(BidiRunList<BidiRun>& bidiRuns, const LineInfo& lineInfo)
  277. {
  278. ASSERT(bidiRuns.firstRun());
  279. bool rootHasSelectedChildren = false;
  280. InlineFlowBox* parentBox = 0;
  281. for (BidiRun* r = bidiRuns.firstRun(); r; r = r->next()) {
  282. // Create a box for our object.
  283. bool isOnlyRun = (bidiRuns.runCount() == 1);
  284. if (bidiRuns.runCount() == 2 && !r->m_object->isListMarker())
  285. isOnlyRun = (!style()->isLeftToRightDirection() ? bidiRuns.lastRun() : bidiRuns.firstRun())->m_object->isListMarker();
  286. InlineBox* box = createInlineBoxForRenderer(r->m_object, false, isOnlyRun);
  287. r->m_box = box;
  288. ASSERT(box);
  289. if (!box)
  290. continue;
  291. if (!rootHasSelectedChildren && box->renderer()->selectionState() != RenderObject::SelectionNone)
  292. rootHasSelectedChildren = true;
  293. // If we have no parent box yet, or if the run is not simply a sibling,
  294. // then we need to construct inline boxes as necessary to properly enclose the
  295. // run's inline box.
  296. if (!parentBox || parentBox->renderer() != r->m_object->parent())
  297. // Create new inline boxes all the way back to the appropriate insertion point.
  298. parentBox = createLineBoxes(r->m_object->parent(), lineInfo, box);
  299. else {
  300. // Append the inline box to this line.
  301. parentBox->addToLine(box);
  302. }
  303. bool visuallyOrdered = r->m_object->style()->visuallyOrdered();
  304. box->setBidiLevel(r->level());
  305. if (box->isInlineTextBox()) {
  306. InlineTextBox* text = static_cast<InlineTextBox*>(box);
  307. text->setStart(r->m_start);
  308. text->setLen(r->m_stop - r->m_start);
  309. text->m_dirOverride = r->dirOverride(visuallyOrdered);
  310. if (r->m_hasHyphen)
  311. text->setHasHyphen(true);
  312. }
  313. }
  314. // We should have a root inline box. It should be unconstructed and
  315. // be the last continuation of our line list.
  316. ASSERT(lastLineBox() && !lastLineBox()->isConstructed());
  317. // Set the m_selectedChildren flag on the root inline box if one of the leaf inline box
  318. // from the bidi runs walk above has a selection state.
  319. if (rootHasSelectedChildren)
  320. lastLineBox()->root()->setHasSelectedChildren(true);
  321. // Set bits on our inline flow boxes that indicate which sides should
  322. // paint borders/margins/padding. This knowledge will ultimately be used when
  323. // we determine the horizontal positions and widths of all the inline boxes on
  324. // the line.
  325. bool isLogicallyLastRunWrapped = bidiRuns.logicallyLastRun()->m_object && bidiRuns.logicallyLastRun()->m_object->isText() ? !reachedEndOfTextRenderer(bidiRuns) : true;
  326. lastLineBox()->determineSpacingForFlowBoxes(lineInfo.isLastLine(), isLogicallyLastRunWrapped, bidiRuns.logicallyLastRun()->m_object);
  327. // Now mark the line boxes as being constructed.
  328. lastLineBox()->setConstructed();
  329. // Return the last line.
  330. return lastRootBox();
  331. }
  332. ETextAlign RenderBlock::textAlignmentForLine(bool endsWithSoftBreak) const
  333. {
  334. ETextAlign alignment = style()->textAlign();
  335. if (!endsWithSoftBreak && alignment == JUSTIFY)
  336. alignment = TAAUTO;
  337. return alignment;
  338. }
  339. static void updateLogicalWidthForLeftAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
  340. {
  341. // The direction of the block should determine what happens with wide lines.
  342. // In particular with RTL blocks, wide lines should still spill out to the left.
  343. if (isLeftToRightDirection) {
  344. if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
  345. trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
  346. return;
  347. }
  348. if (trailingSpaceRun)
  349. trailingSpaceRun->m_box->setLogicalWidth(0);
  350. else if (totalLogicalWidth > availableLogicalWidth)
  351. logicalLeft -= (totalLogicalWidth - availableLogicalWidth);
  352. }
  353. static void updateLogicalWidthForRightAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
  354. {
  355. // Wide lines spill out of the block based off direction.
  356. // So even if text-align is right, if direction is LTR, wide lines should overflow out of the right
  357. // side of the block.
  358. if (isLeftToRightDirection) {
  359. if (trailingSpaceRun) {
  360. totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
  361. trailingSpaceRun->m_box->setLogicalWidth(0);
  362. }
  363. if (totalLogicalWidth < availableLogicalWidth)
  364. logicalLeft += availableLogicalWidth - totalLogicalWidth;
  365. return;
  366. }
  367. if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun) {
  368. trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
  369. totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
  370. } else
  371. logicalLeft += availableLogicalWidth - totalLogicalWidth;
  372. }
  373. static void updateLogicalWidthForCenterAlignedBlock(bool isLeftToRightDirection, BidiRun* trailingSpaceRun, float& logicalLeft, float& totalLogicalWidth, float availableLogicalWidth)
  374. {
  375. float trailingSpaceWidth = 0;
  376. if (trailingSpaceRun) {
  377. totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
  378. trailingSpaceWidth = min(trailingSpaceRun->m_box->logicalWidth(), (availableLogicalWidth - totalLogicalWidth + 1) / 2);
  379. trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceWidth));
  380. }
  381. if (isLeftToRightDirection)
  382. logicalLeft += max<float>((availableLogicalWidth - totalLogicalWidth) / 2, 0);
  383. else
  384. logicalLeft += totalLogicalWidth > availableLogicalWidth ? (availableLogicalWidth - totalLogicalWidth) : (availableLogicalWidth - totalLogicalWidth) / 2 - trailingSpaceWidth;
  385. }
  386. void RenderBlock::setMarginsForRubyRun(BidiRun* run, RenderRubyRun* renderer, RenderObject* previousObject, const LineInfo& lineInfo)
  387. {
  388. int startOverhang;
  389. int endOverhang;
  390. RenderObject* nextObject = 0;
  391. for (BidiRun* runWithNextObject = run->next(); runWithNextObject; runWithNextObject = runWithNextObject->next()) {
  392. if (!runWithNextObject->m_object->isPositioned() && !runWithNextObject->m_box->isLineBreak()) {
  393. nextObject = runWithNextObject->m_object;
  394. break;
  395. }
  396. }
  397. renderer->getOverhang(lineInfo.isFirstLine(), renderer->style()->isLeftToRightDirection() ? previousObject : nextObject, renderer->style()->isLeftToRightDirection() ? nextObject : previousObject, startOverhang, endOverhang);
  398. setMarginStartForChild(renderer, -startOverhang);
  399. setMarginEndForChild(renderer, -endOverhang);
  400. }
  401. static inline void setLogicalWidthForTextRun(RootInlineBox* lineBox, BidiRun* run, RenderText* renderer, float xPos, const LineInfo& lineInfo,
  402. GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
  403. {
  404. HashSet<const SimpleFontData*> fallbackFonts;
  405. GlyphOverflow glyphOverflow;
  406. // Always compute glyph overflow if the block's line-box-contain value is "glyphs".
  407. if (lineBox->fitsToGlyphs()) {
  408. // If we don't stick out of the root line's font box, then don't bother computing our glyph overflow. This optimization
  409. // will keep us from computing glyph bounds in nearly all cases.
  410. bool includeRootLine = lineBox->includesRootLineBoxFontOrLeading();
  411. int baselineShift = lineBox->verticalPositionForBox(run->m_box, verticalPositionCache);
  412. int rootDescent = includeRootLine ? lineBox->renderer()->style(lineInfo.isFirstLine())->font().fontMetrics().descent() : 0;
  413. int rootAscent = includeRootLine ? lineBox->renderer()->style(lineInfo.isFirstLine())->font().fontMetrics().ascent() : 0;
  414. int boxAscent = renderer->style(lineInfo.isFirstLine())->font().fontMetrics().ascent() - baselineShift;
  415. int boxDescent = renderer->style(lineInfo.isFirstLine())->font().fontMetrics().descent() + baselineShift;
  416. if (boxAscent > rootDescent || boxDescent > rootAscent)
  417. glyphOverflow.computeBounds = true;
  418. }
  419. int hyphenWidth = 0;
  420. if (static_cast<InlineTextBox*>(run->m_box)->hasHyphen()) {
  421. const AtomicString& hyphenString = renderer->style()->hyphenString();
  422. hyphenWidth = renderer->style(lineInfo.isFirstLine())->font().width(TextRun(hyphenString.characters(), hyphenString.length()));
  423. }
  424. run->m_box->setLogicalWidth(renderer->width(run->m_start, run->m_stop - run->m_start, xPos, lineInfo.isFirstLine(), &fallbackFonts, &glyphOverflow) + hyphenWidth);
  425. if (!fallbackFonts.isEmpty()) {
  426. ASSERT(run->m_box->isText());
  427. GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
  428. ASSERT(it->second.first.isEmpty());
  429. copyToVector(fallbackFonts, it->second.first);
  430. run->m_box->parent()->clearDescendantsHaveSameLineHeightAndBaseline();
  431. }
  432. if ((glyphOverflow.top || glyphOverflow.bottom || glyphOverflow.left || glyphOverflow.right)) {
  433. ASSERT(run->m_box->isText());
  434. GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.add(static_cast<InlineTextBox*>(run->m_box), make_pair(Vector<const SimpleFontData*>(), GlyphOverflow())).first;
  435. it->second.second = glyphOverflow;
  436. run->m_box->clearKnownToHaveNoOverflow();
  437. }
  438. }
  439. static inline void computeExpansionForJustifiedText(BidiRun* firstRun, BidiRun* trailingSpaceRun, Vector<unsigned, 16>& expansionOpportunities, unsigned expansionOpportunityCount, float& totalLogicalWidth, float availableLogicalWidth)
  440. {
  441. if (!expansionOpportunityCount || availableLogicalWidth <= totalLogicalWidth)
  442. return;
  443. size_t i = 0;
  444. for (BidiRun* r = firstRun; r; r = r->next()) {
  445. if (!r->m_box || r == trailingSpaceRun)
  446. continue;
  447. if (r->m_object->isText()) {
  448. unsigned opportunitiesInRun = expansionOpportunities[i++];
  449. ASSERT(opportunitiesInRun <= expansionOpportunityCount);
  450. // Only justify text if whitespace is collapsed.
  451. if (r->m_object->style()->collapseWhiteSpace()) {
  452. InlineTextBox* textBox = static_cast<InlineTextBox*>(r->m_box);
  453. int expansion = (availableLogicalWidth - totalLogicalWidth) * opportunitiesInRun / expansionOpportunityCount;
  454. textBox->setExpansion(expansion);
  455. totalLogicalWidth += expansion;
  456. }
  457. expansionOpportunityCount -= opportunitiesInRun;
  458. if (!expansionOpportunityCount)
  459. break;
  460. }
  461. }
  462. }
  463. void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, const LineInfo& lineInfo, BidiRun* firstRun, BidiRun* trailingSpaceRun, bool reachedEnd,
  464. GlyphOverflowAndFallbackFontsMap& textBoxDataMap, VerticalPositionCache& verticalPositionCache)
  465. {
  466. ETextAlign textAlign = textAlignmentForLine(!reachedEnd && !lineBox->endsWithBreak());
  467. float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), lineInfo.isFirstLine());
  468. float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), lineInfo.isFirstLine()) - logicalLeft;
  469. bool needsWordSpacing = false;
  470. float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth();
  471. unsigned expansionOpportunityCount = 0;
  472. bool isAfterExpansion = true;
  473. Vector<unsigned, 16> expansionOpportunities;
  474. RenderObject* previousObject = 0;
  475. for (BidiRun* r = firstRun; r; r = r->next()) {
  476. if (!r->m_box || r->m_object->isPositioned() || r->m_box->isLineBreak())
  477. continue; // Positioned objects are only participating to figure out their
  478. // correct static x position. They have no effect on the width.
  479. // Similarly, line break boxes have no effect on the width.
  480. if (r->m_object->isText()) {
  481. RenderText* rt = toRenderText(r->m_object);
  482. if (textAlign == JUSTIFY && r != trailingSpaceRun) {
  483. if (!isAfterExpansion)
  484. static_cast<InlineTextBox*>(r->m_box)->setCanHaveLeadingExpansion(true);
  485. unsigned opportunitiesInRun = Font::expansionOpportunityCount(rt->characters() + r->m_start, r->m_stop - r->m_start, r->m_box->direction(), isAfterExpansion);
  486. expansionOpportunities.append(opportunitiesInRun);
  487. expansionOpportunityCount += opportunitiesInRun;
  488. }
  489. if (int length = rt->textLength()) {
  490. if (!r->m_start && needsWordSpacing && isSpaceOrNewline(rt->characters()[r->m_start]))
  491. totalLogicalWidth += rt->style(lineInfo.isFirstLine())->font().wordSpacing();
  492. needsWordSpacing = !isSpaceOrNewline(rt->characters()[r->m_stop - 1]) && r->m_stop == length;
  493. }
  494. setLogicalWidthForTextRun(lineBox, r, rt, totalLogicalWidth, lineInfo, textBoxDataMap, verticalPositionCache);
  495. } else {
  496. isAfterExpansion = false;
  497. if (!r->m_object->isRenderInline()) {
  498. RenderBox* renderBox = toRenderBox(r->m_object);
  499. if (renderBox->isRubyRun())
  500. setMarginsForRubyRun(r, toRenderRubyRun(renderBox), previousObject, lineInfo);
  501. r->m_box->setLogicalWidth(logicalWidthForChild(renderBox));
  502. totalLogicalWidth += marginStartForChild(renderBox) + marginEndForChild(renderBox);
  503. }
  504. }
  505. totalLogicalWidth += r->m_box->logicalWidth();
  506. previousObject = r->m_object;
  507. }
  508. if (isAfterExpansion && !expansionOpportunities.isEmpty()) {
  509. expansionOpportunities.last()--;
  510. expansionOpportunityCount--;
  511. }
  512. // Armed with the total width of the line (without justification),
  513. // we now examine our text-align property in order to determine where to position the
  514. // objects horizontally. The total width of the line can be increased if we end up
  515. // justifying text.
  516. switch (textAlign) {
  517. case LEFT:
  518. case WEBKIT_LEFT:
  519. updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
  520. break;
  521. case JUSTIFY:
  522. adjustInlineDirectionLineBounds(expansionOpportunityCount, logicalLeft, availableLogicalWidth);
  523. if (expansionOpportunityCount) {
  524. if (trailingSpaceRun) {
  525. totalLogicalWidth -= trailingSpaceRun->m_box->logicalWidth();
  526. trailingSpaceRun->m_box->setLogicalWidth(0);
  527. }
  528. break;
  529. }
  530. // fall through
  531. case TAAUTO:
  532. // for right to left fall through to right aligned
  533. if (style()->isLeftToRightDirection()) {
  534. if (totalLogicalWidth > availableLogicalWidth && trailingSpaceRun)
  535. trailingSpaceRun->m_box->setLogicalWidth(max<float>(0, trailingSpaceRun->m_box->logicalWidth() - totalLogicalWidth + availableLogicalWidth));
  536. break;
  537. }
  538. case RIGHT:
  539. case WEBKIT_RIGHT:
  540. updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
  541. break;
  542. case CENTER:
  543. case WEBKIT_CENTER:
  544. updateLogicalWidthForCenterAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
  545. break;
  546. case TASTART:
  547. if (style()->isLeftToRightDirection())
  548. updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
  549. else
  550. updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
  551. break;
  552. case TAEND:
  553. if (style()->isLeftToRightDirection())
  554. updateLogicalWidthForRightAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
  555. else
  556. updateLogicalWidthForLeftAlignedBlock(style()->isLeftToRightDirection(), trailingSpaceRun, logicalLeft, totalLogicalWidth, availableLogicalWidth);
  557. break;
  558. }
  559. computeExpansionForJustifiedText(firstRun, trailingSpaceRun, expansionOpportunities, expansionOpportunityCount, totalLogicalWidth, availableLogicalWidth);
  560. // The widths of all runs are now known. We can now place every inline box (and
  561. // compute accurate widths for the inline flow boxes).
  562. needsWordSpacing = false;
  563. lineBox->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap);
  564. }
  565. void RenderBlock::computeBlockDirectionPositionsForLine(RootInlineBox* lineBox, BidiRun* firstRun, GlyphOverflowAndFallbackFontsMap& textBoxDataMap,
  566. VerticalPositionCache& verticalPositionCache)
  567. {
  568. setLogicalHeight(lineBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache));
  569. lineBox->setBlockLogicalHeight(logicalHeight());
  570. // Now make sure we place replaced render objects correctly.
  571. for (BidiRun* r = firstRun; r; r = r->next()) {
  572. ASSERT(r->m_box);
  573. if (!r->m_box)
  574. continue; // Skip runs with no line boxes.
  575. // Align positioned boxes with the top of the line box. This is
  576. // a reasonable approximation of an appropriate y position.
  577. if (r->m_object->isPositioned())
  578. r->m_box->setLogicalTop(logicalHeight());
  579. // Position is used to properly position both replaced elements and
  580. // to update the static normal flow x/y of positioned elements.
  581. if (r->m_object->isText())
  582. toRenderText(r->m_object)->positionLineBox(r->m_box);
  583. else if (r->m_object->isBox())
  584. toRenderBox(r->m_object)->positionLineBox(r->m_box);
  585. }
  586. // Positioned objects and zero-length text nodes destroy their boxes in
  587. // position(), which unnecessarily dirties the line.
  588. lineBox->markDirty(false);
  589. }
  590. static inline bool isCollapsibleSpace(UChar character, RenderText* renderer)
  591. {
  592. if (character == ' ' || character == '\t' || character == softHyphen)
  593. return true;
  594. if (character == '\n')
  595. return !renderer->style()->preserveNewline();
  596. if (character == noBreakSpace)
  597. return renderer->style()->nbspMode() == SPACE;
  598. return false;
  599. }
  600. static void setStaticPositions(RenderBlock* block, RenderBox* child)
  601. {
  602. // FIXME: The math here is actually not really right. It's a best-guess approximation that
  603. // will work for the common cases
  604. RenderObject* containerBlock = child->container();
  605. int blockHeight = block->logicalHeight();
  606. if (containerBlock->isRenderInline()) {
  607. // A relative positioned inline encloses us. In this case, we also have to determine our
  608. // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned
  609. // inline so that we can obtain the value later.
  610. toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startOffsetForLine(blockHeight, false));
  611. toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight);
  612. }
  613. if (child->style()->isOriginalDisplayInlineType())
  614. child->layer()->setStaticInlinePosition(block->startOffsetForLine(blockHeight, false));
  615. else
  616. child->layer()->setStaticInlinePosition(block->borderAndPaddingStart());
  617. child->layer()->setStaticBlockPosition(blockHeight);
  618. }
  619. inline BidiRun* RenderBlock::handleTrailingSpaces(BidiRunList<BidiRun>& bidiRuns, BidiContext* currentContext)
  620. {
  621. if (!bidiRuns.runCount()
  622. || !bidiRuns.logicallyLastRun()->m_object->style()->breakOnlyAfterWhiteSpace()
  623. || !bidiRuns.logicallyLastRun()->m_object->style()->autoWrap())
  624. return 0;
  625. BidiRun* trailingSpaceRun = bidiRuns.logicallyLastRun();
  626. RenderObject* lastObject = trailingSpaceRun->m_object;
  627. if (!lastObject->isText())
  628. return 0;
  629. RenderText* lastText = toRenderText(lastObject);
  630. const UChar* characters = lastText->characters();
  631. int firstSpace = trailingSpaceRun->stop();
  632. while (firstSpace > trailingSpaceRun->start()) {
  633. UChar current = characters[firstSpace - 1];
  634. if (!isCollapsibleSpace(current, lastText))
  635. break;
  636. firstSpace--;
  637. }
  638. if (firstSpace == trailingSpaceRun->stop())
  639. return 0;
  640. TextDirection direction = style()->direction();
  641. bool shouldReorder = trailingSpaceRun != (direction == LTR ? bidiRuns.lastRun() : bidiRuns.firstRun());
  642. if (firstSpace != trailingSpaceRun->start()) {
  643. BidiContext* baseContext = currentContext;
  644. while (BidiContext* parent = baseContext->parent())
  645. baseContext = parent;
  646. BidiRun* newTrailingRun = new (renderArena()) BidiRun(firstSpace, trailingSpaceRun->m_stop, trailingSpaceRun->m_object, baseContext, OtherNeutral);
  647. trailingSpaceRun->m_stop = firstSpace;
  648. if (direction == LTR)
  649. bidiRuns.addRun(newTrailingRun);
  650. else
  651. bidiRuns.prependRun(newTrailingRun);
  652. trailingSpaceRun = newTrailingRun;
  653. return trailingSpaceRun;
  654. }
  655. if (!shouldReorder)
  656. return trailingSpaceRun;
  657. if (direction == LTR) {
  658. bidiRuns.moveRunToEnd(trailingSpaceRun);
  659. trailingSpaceRun->m_level = 0;
  660. } else {
  661. bidiRuns.moveRunToBeginning(trailingSpaceRun);
  662. trailingSpaceRun->m_level = 1;
  663. }
  664. return trailingSpaceRun;
  665. }
  666. void RenderBlock::appendFloatingObjectToLastLine(FloatingObject* floatingObject)
  667. {
  668. ASSERT(!floatingObject->m_originatingLine);
  669. floatingObject->m_originatingLine = lastRootBox();
  670. lastRootBox()->appendFloat(floatingObject->renderer());
  671. }
  672. // This function constructs line boxes for all of the text runs in the resolver and computes their position.
  673. RootInlineBox* RenderBlock::createLineBoxesFromBidiRuns(BidiRunList<BidiRun>& bidiRuns, const InlineIterator& end, LineInfo& lineInfo, VerticalPositionCache& verticalPositionCache, BidiRun* trailingSpaceRun)
  674. {
  675. if (!bidiRuns.runCount())
  676. return 0;
  677. // FIXME: Why is this only done when we had runs?
  678. lineInfo.setLastLine(!end.m_obj);
  679. RootInlineBox* lineBox = constructLine(bidiRuns, lineInfo);
  680. if (!lineBox)
  681. return 0;
  682. lineBox->setEndsWithBreak(lineInfo.previousLineBrokeCleanly());
  683. #if ENABLE(SVG)
  684. bool isSVGRootInlineBox = lineBox->isSVGRootInlineBox();
  685. #else
  686. bool isSVGRootInlineBox = false;
  687. #endif
  688. GlyphOverflowAndFallbackFontsMap textBoxDataMap;
  689. // Now we position all of our text runs horizontally.
  690. if (!isSVGRootInlineBox)
  691. computeInlineDirectionPositionsForLine(lineBox, lineInfo, bidiRuns.firstRun(), trailingSpaceRun, end.atEnd(), textBoxDataMap, verticalPositionCache);
  692. // Now position our text runs vertically.
  693. computeBlockDirectionPositionsForLine(lineBox, bidiRuns.firstRun(), textBoxDataMap, verticalPositionCache);
  694. #if ENABLE(SVG)
  695. // SVG text layout code computes vertical & horizontal positions on its own.
  696. // Note that we still need to execute computeVerticalPositionsForLine() as
  697. // it calls InlineTextBox::positionLineBox(), which tracks whether the box
  698. // contains reversed text or not. If we wouldn't do that editing and thus
  699. // text selection in RTL boxes would not work as expected.
  700. if (isSVGRootInlineBox) {
  701. ASSERT(isSVGText());
  702. static_cast<SVGRootInlineBox*>(lineBox)->computePerCharacterLayoutInformation();
  703. }
  704. #endif
  705. // Compute our overflow now.
  706. lineBox->computeOverflow(lineBox->lineTop(), lineBox->lineBottom(), textBoxDataMap);
  707. #if PLATFORM(MAC)
  708. // Highlight acts as an overflow inflation.
  709. if (style()->highlight() != nullAtom)
  710. lineBox->addHighlightOverflow();
  711. #endif
  712. return lineBox;
  713. }
  714. void RenderBlock::layoutRunsAndFloats(bool fullLayout, bool hasInlineChild, Vector<FloatWithRect>& floats, int& repaintLogicalTop, int& repaintLogicalBottom)
  715. {
  716. // We want to skip ahead to the first dirty line
  717. InlineBidiResolver resolver;
  718. unsigned floatIndex;
  719. LineInfo lineInfo;
  720. bool useRepaintBounds = false;
  721. RootInlineBox* startLine = determineStartPosition(lineInfo, fullLayout, resolver, floats, floatIndex,
  722. useRepaintBounds, repaintLogicalTop, repaintLogicalBottom);
  723. // FIXME: This would make more sense outside of this function, but since
  724. // determineStartPosition can change the fullLayout flag we have to do this here. Failure to call
  725. // determineStartPosition first will break fast/repaint/line-flow-with-floats-9.html.
  726. if (fullLayout && hasInlineChild && !selfNeedsLayout()) {
  727. setNeedsLayout(true, false); // Mark ourselves as needing a full layout. This way we'll repaint like
  728. // we're supposed to.
  729. RenderView* v = view();
  730. if (v && !v->doingFullRepaint() && hasLayer()) {
  731. // Because we waited until we were already inside layout to discover
  732. // that the block really needed a full layout, we missed our chance to repaint the layer
  733. // before layout started. Luckily the layer has cached the repaint rect for its original
  734. // position and size, and so we can use that to make a repaint happen now.
  735. repaintUsingContainer(containerForRepaint(), layer()->repaintRect());
  736. }
  737. }
  738. FloatingObject* lastFloat = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0;
  739. LineMidpointState& lineMidpointState = resolver.midpointState();
  740. // We also find the first clean line and extract these lines. We will add them back
  741. // if we determine that we're able to synchronize after handling all our dirty lines.
  742. InlineIterator cleanLineStart;
  743. BidiStatus cleanLineBidiStatus;
  744. int endLineLogicalTop = 0;
  745. RootInlineBox* endLine = (fullLayout || !startLine) ?
  746. 0 : determineEndPosition(startLine, floats, floatIndex, cleanLineStart, cleanLineBidiStatus, endLineLogicalTop);
  747. if (startLine) {
  748. if (!useRepaintBounds) {
  749. useRepaintBounds = true;
  750. repaintLogicalTop = logicalHeight();
  751. repaintLogicalBottom = logicalHeight();
  752. }
  753. RenderArena* arena = renderArena();
  754. RootInlineBox* box = startLine;
  755. while (box) {
  756. repaintLogicalTop = min(repaintLogicalTop, box->logicalTopVisualOverflow());
  757. repaintLogicalBottom = max(repaintLogicalBottom, box->logicalBottomVisualOverflow());
  758. RootInlineBox* next = box->nextRootBox();
  759. box->deleteLine(arena);
  760. box = next;
  761. }
  762. }
  763. InlineIterator end = resolver.position();
  764. if (!fullLayout && lastRootBox() && lastRootBox()->endsWithBreak()) {
  765. // If the last line before the start line ends with a line break that clear floats,
  766. // adjust the height accordingly.
  767. // A line break can be either the first or the last object on a line, depending on its direction.
  768. if (InlineBox* lastLeafChild = lastRootBox()->lastLeafChild()) {
  769. RenderObject* lastObject = lastLeafChild->renderer();
  770. if (!lastObject->isBR())
  771. lastObject = lastRootBox()->firstLeafChild()->renderer();
  772. if (lastObject->isBR()) {
  773. EClear clear = lastObject->style()->clear();
  774. if (clear != CNONE)
  775. newLine(clear);
  776. }
  777. }
  778. }
  779. bool endLineMatched = false;
  780. bool checkForEndLineMatch = endLine;
  781. bool checkForFloatsFromLastLine = false;
  782. bool paginated = view()->layoutState() && view()->layoutState()->isPaginated();
  783. LineBreakIteratorInfo lineBreakIteratorInfo;
  784. VerticalPositionCache verticalPositionCache;
  785. LineBreaker lineBreaker(this);
  786. while (!end.atEnd()) {
  787. // FIXME: Is this check necessary before the first iteration or can it be moved to the end?
  788. if (checkForEndLineMatch && (endLineMatched = matchedEndLine(resolver, cleanLineStart, cleanLineBidiStatus, endLine, endLineLogicalTop, repaintLogicalBottom, repaintLogicalTop)))
  789. break;
  790. lineMidpointState.reset();
  791. lineInfo.setEmpty(true);
  792. InlineIterator oldEnd = end;
  793. FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0;
  794. end = lineBreaker.nextLineBreak(resolver, lineInfo, lineBreakIteratorInfo, lastFloatFromPreviousLine);
  795. if (resolver.position().atEnd()) {
  796. // FIXME: We shouldn't be creating any runs in findNextLineBreak to begin with!
  797. // Once BidiRunList is separated from BidiResolver this will not be needed.
  798. resolver.runs().deleteRuns();
  799. resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
  800. checkForFloatsFromLastLine = true;
  801. break;
  802. }
  803. ASSERT(end != resolver.position());
  804. // This is a short-cut for empty lines.
  805. if (lineInfo.isEmpty()) {
  806. if (lastRootBox())
  807. lastRootBox()->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
  808. } else {
  809. VisualDirectionOverride override = (style()->visuallyOrdered() ? (style()->direction() == LTR ? VisualLeftToRightOverride : VisualRightToLeftOverride) : NoVisualOverride);
  810. // FIXME: This ownership is reversed. We should own the BidiRunList and pass it to createBidiRunsForLine.
  811. BidiRunList<BidiRun>& bidiRuns = resolver.runs();
  812. resolver.createBidiRunsForLine(end, override, lineInfo.previousLineBrokeCleanly());
  813. ASSERT(resolver.position() == end);
  814. BidiRun* trailingSpaceRun = !lineInfo.previousLineBrokeCleanly() ? handleTrailingSpaces(bidiRuns, resolver.context()) : 0;
  815. if (bidiRuns.runCount() && lineBreaker.lineWasHyphenated())
  816. bidiRuns.logicallyLastRun()->m_hasHyphen = true;
  817. // Now that the runs have been ordered, we create the line boxes.
  818. // At the same time we figure out where border/padding/margin should be applied for
  819. // inline flow boxes.
  820. int oldLogicalHeight = logicalHeight();
  821. RootInlineBox* lineBox = createLineBoxesFromBidiRuns(bidiRuns, end, lineInfo, verticalPositionCache, trailingSpaceRun);
  822. bidiRuns.deleteRuns();
  823. resolver.markCurrentRunEmpty(); // FIXME: This can probably be replaced by an ASSERT (or just removed).
  824. if (lineBox) {
  825. lineBox->setLineBreakInfo(end.m_obj, end.m_pos, resolver.status());
  826. if (useRepaintBounds) {
  827. repaintLogicalTop = min(repaintLogicalTop, lineBox->logicalTopVisualOverflow());
  828. repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow());
  829. }
  830. if (paginated) {
  831. int adjustment = 0;
  832. adjustLinePositionForPagination(lineBox, adjustment);
  833. if (adjustment) {
  834. int oldLineWidth = availableLogicalWidthForLine(oldLogicalHeight, lineInfo.isFirstLine());
  835. lineBox->adjustBlockDirectionPosition(adjustment);
  836. if (useRepaintBounds) // This can only be a positive adjustment, so no need to update repaintTop.
  837. repaintLogicalBottom = max(repaintLogicalBottom, lineBox->logicalBottomVisualOverflow());
  838. if (availableLogicalWidthForLine(oldLogicalHeight + adjustment, lineInfo.isFirstLine()) != oldLineWidth) {
  839. // We have to delete this line, remove all floats that got added, and let line layout re-run.
  840. lineBox->deleteLine(renderArena());
  841. removeFloatingObjectsBelow(lastFloatFromPreviousLine, oldLogicalHeight);
  842. setLogicalHeight(oldLogicalHeight + adjustment);
  843. resolver.setPosition(oldEnd);
  844. end = oldEnd;
  845. continue;
  846. }
  847. setLogicalHeight(lineBox->blockLogicalHeight());
  848. }
  849. }
  850. }
  851. for (size_t i = 0; i < lineBreaker.positionedObjects().size(); ++i)
  852. setStaticPositions(this, lineBreaker.positionedObjects()[i]);
  853. lineInfo.setFirstLine(false);
  854. newLine(lineBreaker.clear());
  855. }
  856. if (m_floatingObjects && lastRootBox()) {
  857. FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
  858. FloatingObjectSetIterator it = floatingObjectSet.begin();
  859. FloatingObjectSetIterator end = floatingObjectSet.end();
  860. if (lastFloat) {
  861. FloatingObjectSetIterator lastFloatIterator = floatingObjectSet.find(lastFloat);
  862. ASSERT(lastFloatIterator != end);
  863. ++lastFloatIterator;
  864. it = lastFloatIterator;
  865. }
  866. for (; it != end; ++it) {
  867. FloatingObject* f = *it;
  868. appendFloatingObjectToLastLine(f);
  869. ASSERT(f->m_renderer == floats[floatIndex].object);
  870. // If a float's geometry has changed, give up on syncing with clean lines.
  871. if (floats[floatIndex].rect != f->frameRect())
  872. checkForEndLineMatch = false;
  873. floatIndex++;
  874. }
  875. lastFloat = !floatingObjectSet.isEmpty() ? floatingObjectSet.last() : 0;
  876. }
  877. lineMidpointState.reset();
  878. resolver.setPosition(end);
  879. }
  880. if (endLine) {
  881. if (endLineMatched) {
  882. // Attach all the remaining lines, and then adjust their y-positions as needed.
  883. int delta = logicalHeight() - endLineLogicalTop;
  884. for (RootInlineBox* line = endLine; line; line = line->nextRootBox()) {
  885. line->attachLine();
  886. if (paginated) {
  887. delta -= line->paginationStrut();
  888. adjustLinePositionForPagination(line, delta);
  889. }
  890. if (delta) {
  891. repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow() + min(delta, 0));
  892. repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow() + max(delta, 0));
  893. line->adjustBlockDirectionPosition(delta);
  894. }
  895. if (Vector<RenderBox*>* cleanLineFloats = line->floatsPtr()) {
  896. Vector<RenderBox*>::iterator end = cleanLineFloats->end();
  897. for (Vector<RenderBox*>::iterator f = cleanLineFloats->begin(); f != end; ++f) {
  898. FloatingObject* floatingObject = insertFloatingObject(*f);
  899. ASSERT(!floatingObject->m_originatingLine);
  900. floatingObject->m_originatingLine = line;
  901. setLogicalHeight(logicalTopForChild(*f) - marginBeforeForChild(*f) + delta);
  902. positionNewFloats();
  903. }
  904. }
  905. }
  906. setLogicalHeight(lastRootBox()->blockLogicalHeight());
  907. } else {
  908. // Delete all the remaining lines.
  909. RootInlineBox* line = endLine;
  910. RenderArena* arena = renderArena();
  911. while (line) {
  912. repaintLogicalTop = min(repaintLogicalTop, line->logicalTopVisualOverflow());
  913. repaintLogicalBottom = max(repaintLogicalBottom, line->logicalBottomVisualOverflow());
  914. RootInlineBox* next = line->nextRootBox();
  915. line->deleteLine(arena);
  916. line = next;
  917. }
  918. }
  919. }
  920. if (m_floatingObjects && (checkForFloatsFromLastLine || positionNewFloats()) && lastRootBox()) {
  921. // In case we have a float on the last line, it might not be positioned up to now.
  922. // This has to be done before adding in the bottom border/padding, or the float will
  923. // include the padding incorrectly. -dwh
  924. if (checkForFloatsFromLastLine) {
  925. int bottomVisualOverflow = lastRootBox()->logicalBottomVisualOverflow();
  926. int bottomLayoutOverflow = lastRootBox()->logicalBottomLayoutOverflow();
  927. TrailingFloatsRootInlineBox* trailingFloatsLineBox = new (renderArena()) TrailingFloatsRootInlineBox(this);
  928. m_lineBoxes.appendLineBox(trailingFloatsLineBox);
  929. trailingFloatsLineBox->setConstructed();
  930. GlyphOverflowAndFallbackFontsMap textBoxDataMap;
  931. VerticalPo