RenderDeprecatedFlexibleBox.cpp 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  1. /*
  2. * This file is part of the render object implementation for KHTML.
  3. *
  4. * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  5. * (C) 1999 Antti Koivisto (koivisto@kde.org)
  6. * Copyright (C) 2003 Apple Computer, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Library General Public
  10. * License as published by the Free Software Foundation; either
  11. * version 2 of the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Library General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Library General Public License
  19. * along with this library; see the file COPYING.LIB. If not, write to
  20. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  21. * Boston, MA 02110-1301, USA.
  22. *
  23. */
  24. #include "config.h"
  25. #include "RenderDeprecatedFlexibleBox.h"
  26. #include "FeatureObserver.h"
  27. #include "Font.h"
  28. #include "LayoutRepainter.h"
  29. #include "RenderLayer.h"
  30. #include "RenderView.h"
  31. #include <wtf/StdLibExtras.h>
  32. #include <wtf/unicode/CharacterNames.h>
  33. using namespace std;
  34. namespace WebCore {
  35. class FlexBoxIterator {
  36. public:
  37. FlexBoxIterator(RenderDeprecatedFlexibleBox* parent)
  38. : m_box(parent)
  39. , m_largestOrdinal(1)
  40. {
  41. if (m_box->style()->boxOrient() == HORIZONTAL && !m_box->style()->isLeftToRightDirection())
  42. m_forward = m_box->style()->boxDirection() != BNORMAL;
  43. else
  44. m_forward = m_box->style()->boxDirection() == BNORMAL;
  45. if (!m_forward) {
  46. // No choice, since we're going backwards, we have to find out the highest ordinal up front.
  47. RenderBox* child = m_box->firstChildBox();
  48. while (child) {
  49. if (child->style()->boxOrdinalGroup() > m_largestOrdinal)
  50. m_largestOrdinal = child->style()->boxOrdinalGroup();
  51. child = child->nextSiblingBox();
  52. }
  53. }
  54. reset();
  55. }
  56. void reset()
  57. {
  58. m_currentChild = 0;
  59. m_ordinalIteration = -1;
  60. }
  61. RenderBox* first()
  62. {
  63. reset();
  64. return next();
  65. }
  66. RenderBox* next()
  67. {
  68. do {
  69. if (!m_currentChild) {
  70. ++m_ordinalIteration;
  71. if (!m_ordinalIteration)
  72. m_currentOrdinal = m_forward ? 1 : m_largestOrdinal;
  73. else {
  74. if (m_ordinalIteration >= m_ordinalValues.size() + 1)
  75. return 0;
  76. // Only copy+sort the values once per layout even if the iterator is reset.
  77. if (static_cast<size_t>(m_ordinalValues.size()) != m_sortedOrdinalValues.size()) {
  78. copyToVector(m_ordinalValues, m_sortedOrdinalValues);
  79. sort(m_sortedOrdinalValues.begin(), m_sortedOrdinalValues.end());
  80. }
  81. m_currentOrdinal = m_forward ? m_sortedOrdinalValues[m_ordinalIteration - 1] : m_sortedOrdinalValues[m_sortedOrdinalValues.size() - m_ordinalIteration];
  82. }
  83. m_currentChild = m_forward ? m_box->firstChildBox() : m_box->lastChildBox();
  84. } else
  85. m_currentChild = m_forward ? m_currentChild->nextSiblingBox() : m_currentChild->previousSiblingBox();
  86. if (m_currentChild && notFirstOrdinalValue())
  87. m_ordinalValues.add(m_currentChild->style()->boxOrdinalGroup());
  88. } while (!m_currentChild || (!m_currentChild->isAnonymous()
  89. && m_currentChild->style()->boxOrdinalGroup() != m_currentOrdinal));
  90. return m_currentChild;
  91. }
  92. private:
  93. bool notFirstOrdinalValue()
  94. {
  95. unsigned int firstOrdinalValue = m_forward ? 1 : m_largestOrdinal;
  96. return m_currentOrdinal == firstOrdinalValue && m_currentChild->style()->boxOrdinalGroup() != firstOrdinalValue;
  97. }
  98. RenderDeprecatedFlexibleBox* m_box;
  99. RenderBox* m_currentChild;
  100. bool m_forward;
  101. unsigned int m_currentOrdinal;
  102. unsigned int m_largestOrdinal;
  103. HashSet<unsigned int> m_ordinalValues;
  104. Vector<unsigned int> m_sortedOrdinalValues;
  105. int m_ordinalIteration;
  106. };
  107. RenderDeprecatedFlexibleBox::RenderDeprecatedFlexibleBox(Element* element)
  108. : RenderBlock(element)
  109. {
  110. setChildrenInline(false); // All of our children must be block-level
  111. m_stretchingChildren = false;
  112. if (!isAnonymous()) {
  113. const KURL& url = document()->url();
  114. if (url.protocolIs("chrome"))
  115. FeatureObserver::observe(document(), FeatureObserver::DeprecatedFlexboxChrome);
  116. else if (url.protocolIs("chrome-extension"))
  117. FeatureObserver::observe(document(), FeatureObserver::DeprecatedFlexboxChromeExtension);
  118. else
  119. FeatureObserver::observe(document(), FeatureObserver::DeprecatedFlexboxWebContent);
  120. }
  121. }
  122. RenderDeprecatedFlexibleBox::~RenderDeprecatedFlexibleBox()
  123. {
  124. }
  125. RenderDeprecatedFlexibleBox* RenderDeprecatedFlexibleBox::createAnonymous(Document* document)
  126. {
  127. RenderDeprecatedFlexibleBox* renderer = new (document->renderArena()) RenderDeprecatedFlexibleBox(0);
  128. renderer->setDocumentForAnonymous(document);
  129. return renderer;
  130. }
  131. static LayoutUnit marginWidthForChild(RenderBox* child)
  132. {
  133. // A margin basically has three types: fixed, percentage, and auto (variable).
  134. // Auto and percentage margins simply become 0 when computing min/max width.
  135. // Fixed margins can be added in as is.
  136. Length marginLeft = child->style()->marginLeft();
  137. Length marginRight = child->style()->marginRight();
  138. LayoutUnit margin = 0;
  139. if (marginLeft.isFixed())
  140. margin += marginLeft.value();
  141. if (marginRight.isFixed())
  142. margin += marginRight.value();
  143. return margin;
  144. }
  145. static bool childDoesNotAffectWidthOrFlexing(RenderObject* child)
  146. {
  147. // Positioned children and collapsed children don't affect the min/max width.
  148. return child->isOutOfFlowPositioned() || child->style()->visibility() == COLLAPSE;
  149. }
  150. static LayoutUnit contentWidthForChild(RenderBox* child)
  151. {
  152. if (child->hasOverrideWidth())
  153. return child->overrideLogicalContentWidth();
  154. return child->logicalWidth() - child->borderAndPaddingLogicalWidth();
  155. }
  156. static LayoutUnit contentHeightForChild(RenderBox* child)
  157. {
  158. if (child->hasOverrideHeight())
  159. return child->overrideLogicalContentHeight();
  160. return child->logicalHeight() - child->borderAndPaddingLogicalHeight();
  161. }
  162. void RenderDeprecatedFlexibleBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
  163. {
  164. RenderStyle* oldStyle = style();
  165. if (oldStyle && !oldStyle->lineClamp().isNone() && newStyle->lineClamp().isNone())
  166. clearLineClamp();
  167. RenderBlock::styleWillChange(diff, newStyle);
  168. }
  169. void RenderDeprecatedFlexibleBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
  170. {
  171. if (hasMultipleLines() || isVertical()) {
  172. for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
  173. if (childDoesNotAffectWidthOrFlexing(child))
  174. continue;
  175. LayoutUnit margin = marginWidthForChild(child);
  176. LayoutUnit width = child->minPreferredLogicalWidth() + margin;
  177. minLogicalWidth = max(width, minLogicalWidth);
  178. width = child->maxPreferredLogicalWidth() + margin;
  179. maxLogicalWidth = max(width, maxLogicalWidth);
  180. }
  181. } else {
  182. for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
  183. if (childDoesNotAffectWidthOrFlexing(child))
  184. continue;
  185. LayoutUnit margin = marginWidthForChild(child);
  186. minLogicalWidth += child->minPreferredLogicalWidth() + margin;
  187. maxLogicalWidth += child->maxPreferredLogicalWidth() + margin;
  188. }
  189. }
  190. maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
  191. LayoutUnit scrollbarWidth = instrinsicScrollbarLogicalWidth();
  192. maxLogicalWidth += scrollbarWidth;
  193. minLogicalWidth += scrollbarWidth;
  194. }
  195. void RenderDeprecatedFlexibleBox::computePreferredLogicalWidths()
  196. {
  197. ASSERT(preferredLogicalWidthsDirty());
  198. m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
  199. if (style()->width().isFixed() && style()->width().value() > 0)
  200. m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(style()->width().value());
  201. else
  202. computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
  203. if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
  204. m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
  205. m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->minWidth().value()));
  206. }
  207. if (style()->maxWidth().isFixed()) {
  208. m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
  209. m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(style()->maxWidth().value()));
  210. }
  211. LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
  212. m_minPreferredLogicalWidth += borderAndPadding;
  213. m_maxPreferredLogicalWidth += borderAndPadding;
  214. setPreferredLogicalWidthsDirty(false);
  215. }
  216. // Use an inline capacity of 8, since flexbox containers usually have less than 8 children.
  217. typedef Vector<LayoutRect, 8> ChildFrameRects;
  218. typedef Vector<LayoutSize, 8> ChildLayoutDeltas;
  219. static void appendChildFrameRects(RenderDeprecatedFlexibleBox* box, ChildFrameRects& childFrameRects)
  220. {
  221. FlexBoxIterator iterator(box);
  222. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  223. if (!child->isOutOfFlowPositioned())
  224. childFrameRects.append(child->frameRect());
  225. }
  226. }
  227. static void appendChildLayoutDeltas(RenderDeprecatedFlexibleBox* box, ChildLayoutDeltas& childLayoutDeltas)
  228. {
  229. FlexBoxIterator iterator(box);
  230. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  231. if (!child->isOutOfFlowPositioned())
  232. childLayoutDeltas.append(LayoutSize());
  233. }
  234. }
  235. static void repaintChildrenDuringLayoutIfMoved(RenderDeprecatedFlexibleBox* box, const ChildFrameRects& oldChildRects)
  236. {
  237. size_t childIndex = 0;
  238. FlexBoxIterator iterator(box);
  239. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  240. if (child->isOutOfFlowPositioned())
  241. continue;
  242. // If the child moved, we have to repaint it as well as any floating/positioned
  243. // descendants. An exception is if we need a layout. In this case, we know we're going to
  244. // repaint ourselves (and the child) anyway.
  245. if (!box->selfNeedsLayout() && child->checkForRepaintDuringLayout())
  246. child->repaintDuringLayoutIfMoved(oldChildRects[childIndex]);
  247. ++childIndex;
  248. }
  249. ASSERT(childIndex == oldChildRects.size());
  250. }
  251. void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit)
  252. {
  253. ASSERT(needsLayout());
  254. if (!relayoutChildren && simplifiedLayout())
  255. return;
  256. LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
  257. LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
  258. // Regions changing widths can force us to relayout our children.
  259. RenderFlowThread* flowThread = flowThreadContainingBlock();
  260. if (logicalWidthChangedInRegions(flowThread))
  261. relayoutChildren = true;
  262. if (updateRegionsAndExclusionsBeforeChildLayout(flowThread))
  263. relayoutChildren = true;
  264. LayoutSize previousSize = size();
  265. updateLogicalWidth();
  266. updateLogicalHeight();
  267. if (previousSize != size()
  268. || (parent()->isDeprecatedFlexibleBox() && parent()->style()->boxOrient() == HORIZONTAL
  269. && parent()->style()->boxAlign() == BSTRETCH))
  270. relayoutChildren = true;
  271. setHeight(0);
  272. m_stretchingChildren = false;
  273. initMaxMarginValues();
  274. #if !ASSERT_DISABLED
  275. LayoutSize oldLayoutDelta = view()->layoutDelta();
  276. #endif
  277. ChildFrameRects oldChildRects;
  278. appendChildFrameRects(this, oldChildRects);
  279. dirtyForLayoutFromPercentageHeightDescendants();
  280. if (isHorizontal())
  281. layoutHorizontalBox(relayoutChildren);
  282. else
  283. layoutVerticalBox(relayoutChildren);
  284. repaintChildrenDuringLayoutIfMoved(this, oldChildRects);
  285. ASSERT(view()->layoutDeltaMatches(oldLayoutDelta));
  286. LayoutUnit oldClientAfterEdge = clientLogicalBottom();
  287. updateLogicalHeight();
  288. if (previousSize.height() != height())
  289. relayoutChildren = true;
  290. layoutPositionedObjects(relayoutChildren || isRoot());
  291. updateRegionsAndExclusionsAfterChildLayout(flowThread);
  292. if (!isFloatingOrOutOfFlowPositioned() && height() == 0) {
  293. // We are a block with no border and padding and a computed height
  294. // of 0. The CSS spec states that zero-height blocks collapse their margins
  295. // together.
  296. // When blocks are self-collapsing, we just use the top margin values and set the
  297. // bottom margin max values to 0. This way we don't factor in the values
  298. // twice when we collapse with our previous vertically adjacent and
  299. // following vertically adjacent blocks.
  300. LayoutUnit pos = maxPositiveMarginBefore();
  301. LayoutUnit neg = maxNegativeMarginBefore();
  302. if (maxPositiveMarginAfter() > pos)
  303. pos = maxPositiveMarginAfter();
  304. if (maxNegativeMarginAfter() > neg)
  305. neg = maxNegativeMarginAfter();
  306. setMaxMarginBeforeValues(pos, neg);
  307. setMaxMarginAfterValues(0, 0);
  308. }
  309. computeOverflow(oldClientAfterEdge);
  310. statePusher.pop();
  311. updateLayerTransform();
  312. if (view()->layoutState()->pageLogicalHeight())
  313. setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop()));
  314. // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if
  315. // we overflow or not.
  316. updateScrollInfoAfterLayout();
  317. // Repaint with our new bounds if they are different from our old bounds.
  318. repainter.repaintAfterLayout();
  319. setNeedsLayout(false);
  320. }
  321. // The first walk over our kids is to find out if we have any flexible children.
  322. static void gatherFlexChildrenInfo(FlexBoxIterator& iterator, bool relayoutChildren, unsigned int& highestFlexGroup, unsigned int& lowestFlexGroup, bool& haveFlex)
  323. {
  324. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  325. // Check to see if this child flexes.
  326. if (!childDoesNotAffectWidthOrFlexing(child) && child->style()->boxFlex() > 0.0f) {
  327. // We always have to lay out flexible objects again, since the flex distribution
  328. // may have changed, and we need to reallocate space.
  329. child->clearOverrideSize();
  330. if (!relayoutChildren)
  331. child->setChildNeedsLayout(true, MarkOnlyThis);
  332. haveFlex = true;
  333. unsigned int flexGroup = child->style()->boxFlexGroup();
  334. if (lowestFlexGroup == 0)
  335. lowestFlexGroup = flexGroup;
  336. if (flexGroup < lowestFlexGroup)
  337. lowestFlexGroup = flexGroup;
  338. if (flexGroup > highestFlexGroup)
  339. highestFlexGroup = flexGroup;
  340. }
  341. }
  342. }
  343. static void layoutChildIfNeededApplyingDelta(RenderBox* child, const LayoutSize& layoutDelta)
  344. {
  345. if (!child->needsLayout())
  346. return;
  347. child->view()->addLayoutDelta(layoutDelta);
  348. child->layoutIfNeeded();
  349. child->view()->addLayoutDelta(-layoutDelta);
  350. }
  351. void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren)
  352. {
  353. LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
  354. LayoutUnit yPos = borderTop() + paddingTop();
  355. LayoutUnit xPos = borderLeft() + paddingLeft();
  356. bool heightSpecified = false;
  357. LayoutUnit oldHeight = 0;
  358. LayoutUnit remainingSpace = 0;
  359. FlexBoxIterator iterator(this);
  360. unsigned int highestFlexGroup = 0;
  361. unsigned int lowestFlexGroup = 0;
  362. bool haveFlex = false, flexingChildren = false;
  363. gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
  364. RenderBlock::startDelayUpdateScrollInfo();
  365. ChildLayoutDeltas childLayoutDeltas;
  366. appendChildLayoutDeltas(this, childLayoutDeltas);
  367. // We do 2 passes. The first pass is simply to lay everyone out at
  368. // their preferred widths. The subsequent passes handle flexing the children.
  369. // The first pass skips flexible objects completely.
  370. do {
  371. // Reset our height.
  372. setHeight(yPos);
  373. xPos = borderLeft() + paddingLeft();
  374. size_t childIndex = 0;
  375. // Our first pass is done without flexing. We simply lay the children
  376. // out within the box. We have to do a layout first in order to determine
  377. // our box's intrinsic height.
  378. LayoutUnit maxAscent = 0, maxDescent = 0;
  379. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  380. if (relayoutChildren)
  381. child->setChildNeedsLayout(true, MarkOnlyThis);
  382. if (child->isOutOfFlowPositioned())
  383. continue;
  384. LayoutSize& childLayoutDelta = childLayoutDeltas[childIndex++];
  385. // Compute the child's vertical margins.
  386. child->computeAndSetBlockDirectionMargins(this);
  387. if (!child->needsLayout())
  388. child->markForPaginationRelayoutIfNeeded();
  389. // Apply the child's current layout delta.
  390. layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
  391. // Now do the layout.
  392. layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
  393. // Update our height and overflow height.
  394. if (style()->boxAlign() == BBASELINE) {
  395. LayoutUnit ascent = child->firstLineBoxBaseline();
  396. if (ascent == -1)
  397. ascent = child->height() + child->marginBottom();
  398. ascent += child->marginTop();
  399. LayoutUnit descent = (child->height() + child->marginHeight()) - ascent;
  400. // Update our maximum ascent.
  401. maxAscent = max(maxAscent, ascent);
  402. // Update our maximum descent.
  403. maxDescent = max(maxDescent, descent);
  404. // Now update our height.
  405. setHeight(max(yPos + maxAscent + maxDescent, height()));
  406. }
  407. else
  408. setHeight(max(height(), yPos + child->height() + child->marginHeight()));
  409. }
  410. ASSERT(childIndex == childLayoutDeltas.size());
  411. if (!iterator.first() && hasLineIfEmpty())
  412. setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
  413. setHeight(height() + toAdd);
  414. oldHeight = height();
  415. updateLogicalHeight();
  416. relayoutChildren = false;
  417. if (oldHeight != height())
  418. heightSpecified = true;
  419. // Now that our height is actually known, we can place our boxes.
  420. childIndex = 0;
  421. m_stretchingChildren = (style()->boxAlign() == BSTRETCH);
  422. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  423. if (child->isOutOfFlowPositioned()) {
  424. child->containingBlock()->insertPositionedObject(child);
  425. RenderLayer* childLayer = child->layer();
  426. childLayer->setStaticInlinePosition(xPos); // FIXME: Not right for regions.
  427. if (childLayer->staticBlockPosition() != yPos) {
  428. childLayer->setStaticBlockPosition(yPos);
  429. if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
  430. child->setChildNeedsLayout(true, MarkOnlyThis);
  431. }
  432. continue;
  433. }
  434. LayoutSize& childLayoutDelta = childLayoutDeltas[childIndex++];
  435. if (child->style()->visibility() == COLLAPSE) {
  436. // visibility: collapsed children do not participate in our positioning.
  437. // But we need to lay them out.
  438. layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
  439. continue;
  440. }
  441. // We need to see if this child's height has changed, since we make block elements
  442. // fill the height of a containing box by default.
  443. // Now do a layout.
  444. LayoutUnit oldChildHeight = child->height();
  445. child->updateLogicalHeight();
  446. if (oldChildHeight != child->height())
  447. child->setChildNeedsLayout(true, MarkOnlyThis);
  448. if (!child->needsLayout())
  449. child->markForPaginationRelayoutIfNeeded();
  450. layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
  451. // We can place the child now, using our value of box-align.
  452. xPos += child->marginLeft();
  453. LayoutUnit childY = yPos;
  454. switch (style()->boxAlign()) {
  455. case BCENTER:
  456. childY += child->marginTop() + max<LayoutUnit>(0, (contentHeight() - (child->height() + child->marginHeight())) / 2);
  457. break;
  458. case BBASELINE: {
  459. LayoutUnit ascent = child->firstLineBoxBaseline();
  460. if (ascent == -1)
  461. ascent = child->height() + child->marginBottom();
  462. ascent += child->marginTop();
  463. childY += child->marginTop() + (maxAscent - ascent);
  464. break;
  465. }
  466. case BEND:
  467. childY += contentHeight() - child->marginBottom() - child->height();
  468. break;
  469. default: // BSTART
  470. childY += child->marginTop();
  471. break;
  472. }
  473. placeChild(child, LayoutPoint(xPos, childY), &childLayoutDelta);
  474. xPos += child->width() + child->marginRight();
  475. }
  476. ASSERT(childIndex == childLayoutDeltas.size());
  477. remainingSpace = borderLeft() + paddingLeft() + contentWidth() - xPos;
  478. m_stretchingChildren = false;
  479. if (flexingChildren)
  480. haveFlex = false; // We're done.
  481. else if (haveFlex) {
  482. // We have some flexible objects. See if we need to grow/shrink them at all.
  483. if (!remainingSpace)
  484. break;
  485. // Allocate the remaining space among the flexible objects. If we are trying to
  486. // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
  487. // we go from the highest flex group to the lowest group.
  488. bool expanding = remainingSpace > 0;
  489. unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
  490. unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
  491. for (unsigned int i = start; i <= end && remainingSpace; i++) {
  492. // Always start off by assuming the group can get all the remaining space.
  493. LayoutUnit groupRemainingSpace = remainingSpace;
  494. do {
  495. // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
  496. // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
  497. // computing the allowed growth before an object hits its min/max width (and thus
  498. // forces a totalFlex recomputation).
  499. LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
  500. float totalFlex = 0.0f;
  501. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  502. if (allowedChildFlex(child, expanding, i))
  503. totalFlex += child->style()->boxFlex();
  504. }
  505. LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
  506. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  507. LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
  508. if (allowedFlex) {
  509. LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : LayoutUnit(allowedFlex * (totalFlex / child->style()->boxFlex()));
  510. spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
  511. }
  512. }
  513. // The flex groups may not have any flexible objects this time around.
  514. if (!spaceAvailableThisPass || totalFlex == 0.0f) {
  515. // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
  516. groupRemainingSpace = 0;
  517. continue;
  518. }
  519. // Now distribute the space to objects.
  520. for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
  521. if (child->style()->visibility() == COLLAPSE)
  522. continue;
  523. if (allowedChildFlex(child, expanding, i)) {
  524. LayoutUnit spaceAdd = LayoutUnit(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
  525. if (spaceAdd) {
  526. child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
  527. flexingChildren = true;
  528. relayoutChildren = true;
  529. }
  530. spaceAvailableThisPass -= spaceAdd;
  531. remainingSpace -= spaceAdd;
  532. groupRemainingSpace -= spaceAdd;
  533. totalFlex -= child->style()->boxFlex();
  534. }
  535. }
  536. if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
  537. // This is not advancing, avoid getting stuck by distributing the remaining pixels.
  538. LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
  539. for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
  540. if (allowedChildFlex(child, expanding, i)) {
  541. child->setOverrideLogicalContentWidth(contentWidthForChild(child) + spaceAdd);
  542. flexingChildren = true;
  543. relayoutChildren = true;
  544. remainingSpace -= spaceAdd;
  545. groupRemainingSpace -= spaceAdd;
  546. }
  547. }
  548. }
  549. } while (absoluteValue(groupRemainingSpace) >= 1);
  550. }
  551. // We didn't find any children that could grow.
  552. if (haveFlex && !flexingChildren)
  553. haveFlex = false;
  554. }
  555. } while (haveFlex);
  556. RenderBlock::finishDelayUpdateScrollInfo();
  557. if (remainingSpace > 0 && ((style()->isLeftToRightDirection() && style()->boxPack() != Start)
  558. || (!style()->isLeftToRightDirection() && style()->boxPack() != End))) {
  559. // Children must be repositioned.
  560. LayoutUnit offset = 0;
  561. if (style()->boxPack() == Justify) {
  562. // Determine the total number of children.
  563. int totalChildren = 0;
  564. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  565. if (childDoesNotAffectWidthOrFlexing(child))
  566. continue;
  567. ++totalChildren;
  568. }
  569. // Iterate over the children and space them out according to the
  570. // justification level.
  571. if (totalChildren > 1) {
  572. --totalChildren;
  573. bool firstChild = true;
  574. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  575. if (childDoesNotAffectWidthOrFlexing(child))
  576. continue;
  577. if (firstChild) {
  578. firstChild = false;
  579. continue;
  580. }
  581. offset += remainingSpace/totalChildren;
  582. remainingSpace -= (remainingSpace/totalChildren);
  583. --totalChildren;
  584. placeChild(child, child->location() + LayoutSize(offset, 0));
  585. }
  586. }
  587. } else {
  588. if (style()->boxPack() == Center)
  589. offset += remainingSpace / 2;
  590. else // END for LTR, START for RTL
  591. offset += remainingSpace;
  592. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  593. if (childDoesNotAffectWidthOrFlexing(child))
  594. continue;
  595. placeChild(child, child->location() + LayoutSize(offset, 0));
  596. }
  597. }
  598. }
  599. // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
  600. // a height change, we revert our height back to the intrinsic height before returning.
  601. if (heightSpecified)
  602. setHeight(oldHeight);
  603. }
  604. void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren)
  605. {
  606. LayoutUnit yPos = borderTop() + paddingTop();
  607. LayoutUnit toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
  608. bool heightSpecified = false;
  609. LayoutUnit oldHeight = 0;
  610. LayoutUnit remainingSpace = 0;
  611. FlexBoxIterator iterator(this);
  612. unsigned int highestFlexGroup = 0;
  613. unsigned int lowestFlexGroup = 0;
  614. bool haveFlex = false, flexingChildren = false;
  615. gatherFlexChildrenInfo(iterator, relayoutChildren, highestFlexGroup, lowestFlexGroup, haveFlex);
  616. // We confine the line clamp ugliness to vertical flexible boxes (thus keeping it out of
  617. // mainstream block layout); this is not really part of the XUL box model.
  618. bool haveLineClamp = !style()->lineClamp().isNone();
  619. if (haveLineClamp)
  620. applyLineClamp(iterator, relayoutChildren);
  621. RenderBlock::startDelayUpdateScrollInfo();
  622. ChildLayoutDeltas childLayoutDeltas;
  623. appendChildLayoutDeltas(this, childLayoutDeltas);
  624. // We do 2 passes. The first pass is simply to lay everyone out at
  625. // their preferred widths. The second pass handles flexing the children.
  626. // Our first pass is done without flexing. We simply lay the children
  627. // out within the box.
  628. do {
  629. setHeight(borderTop() + paddingTop());
  630. LayoutUnit minHeight = height() + toAdd;
  631. size_t childIndex = 0;
  632. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  633. // Make sure we relayout children if we need it.
  634. if (!haveLineClamp && relayoutChildren)
  635. child->setChildNeedsLayout(true, MarkOnlyThis);
  636. if (child->isOutOfFlowPositioned()) {
  637. child->containingBlock()->insertPositionedObject(child);
  638. RenderLayer* childLayer = child->layer();
  639. childLayer->setStaticInlinePosition(borderStart() + paddingStart()); // FIXME: Not right for regions.
  640. if (childLayer->staticBlockPosition() != height()) {
  641. childLayer->setStaticBlockPosition(height());
  642. if (child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
  643. child->setChildNeedsLayout(true, MarkOnlyThis);
  644. }
  645. continue;
  646. }
  647. LayoutSize& childLayoutDelta = childLayoutDeltas[childIndex++];
  648. if (child->style()->visibility() == COLLAPSE) {
  649. // visibility: collapsed children do not participate in our positioning.
  650. // But we need to lay them down.
  651. layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
  652. continue;
  653. }
  654. // Compute the child's vertical margins.
  655. child->computeAndSetBlockDirectionMargins(this);
  656. // Add in the child's marginTop to our height.
  657. setHeight(height() + child->marginTop());
  658. if (!child->needsLayout())
  659. child->markForPaginationRelayoutIfNeeded();
  660. // Now do a layout.
  661. layoutChildIfNeededApplyingDelta(child, childLayoutDelta);
  662. // We can place the child now, using our value of box-align.
  663. LayoutUnit childX = borderLeft() + paddingLeft();
  664. switch (style()->boxAlign()) {
  665. case BCENTER:
  666. case BBASELINE: // Baseline just maps to center for vertical boxes
  667. childX += child->marginLeft() + max<LayoutUnit>(0, (contentWidth() - (child->width() + child->marginWidth())) / 2);
  668. break;
  669. case BEND:
  670. if (!style()->isLeftToRightDirection())
  671. childX += child->marginLeft();
  672. else
  673. childX += contentWidth() - child->marginRight() - child->width();
  674. break;
  675. default: // BSTART/BSTRETCH
  676. if (style()->isLeftToRightDirection())
  677. childX += child->marginLeft();
  678. else
  679. childX += contentWidth() - child->marginRight() - child->width();
  680. break;
  681. }
  682. // Place the child.
  683. placeChild(child, LayoutPoint(childX, height()), &childLayoutDelta);
  684. setHeight(height() + child->height() + child->marginBottom());
  685. }
  686. ASSERT(childIndex == childLayoutDeltas.size());
  687. yPos = height();
  688. if (!iterator.first() && hasLineIfEmpty())
  689. setHeight(height() + lineHeight(true, style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
  690. setHeight(height() + toAdd);
  691. // Negative margins can cause our height to shrink below our minimal height (border/padding).
  692. // If this happens, ensure that the computed height is increased to the minimal height.
  693. if (height() < minHeight)
  694. setHeight(minHeight);
  695. // Now we have to calc our height, so we know how much space we have remaining.
  696. oldHeight = height();
  697. updateLogicalHeight();
  698. if (oldHeight != height())
  699. heightSpecified = true;
  700. remainingSpace = borderTop() + paddingTop() + contentHeight() - yPos;
  701. if (flexingChildren)
  702. haveFlex = false; // We're done.
  703. else if (haveFlex) {
  704. // We have some flexible objects. See if we need to grow/shrink them at all.
  705. if (!remainingSpace)
  706. break;
  707. // Allocate the remaining space among the flexible objects. If we are trying to
  708. // grow, then we go from the lowest flex group to the highest flex group. For shrinking,
  709. // we go from the highest flex group to the lowest group.
  710. bool expanding = remainingSpace > 0;
  711. unsigned int start = expanding ? lowestFlexGroup : highestFlexGroup;
  712. unsigned int end = expanding? highestFlexGroup : lowestFlexGroup;
  713. for (unsigned int i = start; i <= end && remainingSpace; i++) {
  714. // Always start off by assuming the group can get all the remaining space.
  715. LayoutUnit groupRemainingSpace = remainingSpace;
  716. do {
  717. // Flexing consists of multiple passes, since we have to change ratios every time an object hits its max/min-width
  718. // For a given pass, we always start off by computing the totalFlex of all objects that can grow/shrink at all, and
  719. // computing the allowed growth before an object hits its min/max width (and thus
  720. // forces a totalFlex recomputation).
  721. LayoutUnit groupRemainingSpaceAtBeginning = groupRemainingSpace;
  722. float totalFlex = 0.0f;
  723. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  724. if (allowedChildFlex(child, expanding, i))
  725. totalFlex += child->style()->boxFlex();
  726. }
  727. LayoutUnit spaceAvailableThisPass = groupRemainingSpace;
  728. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  729. LayoutUnit allowedFlex = allowedChildFlex(child, expanding, i);
  730. if (allowedFlex) {
  731. LayoutUnit projectedFlex = (allowedFlex == LayoutUnit::max()) ? allowedFlex : static_cast<LayoutUnit>(allowedFlex * (totalFlex / child->style()->boxFlex()));
  732. spaceAvailableThisPass = expanding ? min(spaceAvailableThisPass, projectedFlex) : max(spaceAvailableThisPass, projectedFlex);
  733. }
  734. }
  735. // The flex groups may not have any flexible objects this time around.
  736. if (!spaceAvailableThisPass || totalFlex == 0.0f) {
  737. // If we just couldn't grow/shrink any more, then it's time to transition to the next flex group.
  738. groupRemainingSpace = 0;
  739. continue;
  740. }
  741. // Now distribute the space to objects.
  742. for (RenderBox* child = iterator.first(); child && spaceAvailableThisPass && totalFlex; child = iterator.next()) {
  743. if (allowedChildFlex(child, expanding, i)) {
  744. LayoutUnit spaceAdd = static_cast<LayoutUnit>(spaceAvailableThisPass * (child->style()->boxFlex() / totalFlex));
  745. if (spaceAdd) {
  746. child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
  747. flexingChildren = true;
  748. relayoutChildren = true;
  749. }
  750. spaceAvailableThisPass -= spaceAdd;
  751. remainingSpace -= spaceAdd;
  752. groupRemainingSpace -= spaceAdd;
  753. totalFlex -= child->style()->boxFlex();
  754. }
  755. }
  756. if (groupRemainingSpace == groupRemainingSpaceAtBeginning) {
  757. // This is not advancing, avoid getting stuck by distributing the remaining pixels.
  758. LayoutUnit spaceAdd = groupRemainingSpace > 0 ? 1 : -1;
  759. for (RenderBox* child = iterator.first(); child && groupRemainingSpace; child = iterator.next()) {
  760. if (allowedChildFlex(child, expanding, i)) {
  761. child->setOverrideLogicalContentHeight(contentHeightForChild(child) + spaceAdd);
  762. flexingChildren = true;
  763. relayoutChildren = true;
  764. remainingSpace -= spaceAdd;
  765. groupRemainingSpace -= spaceAdd;
  766. }
  767. }
  768. }
  769. } while (absoluteValue(groupRemainingSpace) >= 1);
  770. }
  771. // We didn't find any children that could grow.
  772. if (haveFlex && !flexingChildren)
  773. haveFlex = false;
  774. }
  775. } while (haveFlex);
  776. RenderBlock::finishDelayUpdateScrollInfo();
  777. if (style()->boxPack() != Start && remainingSpace > 0) {
  778. // Children must be repositioned.
  779. LayoutUnit offset = 0;
  780. if (style()->boxPack() == Justify) {
  781. // Determine the total number of children.
  782. int totalChildren = 0;
  783. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  784. if (childDoesNotAffectWidthOrFlexing(child))
  785. continue;
  786. ++totalChildren;
  787. }
  788. // Iterate over the children and space them out according to the
  789. // justification level.
  790. if (totalChildren > 1) {
  791. --totalChildren;
  792. bool firstChild = true;
  793. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  794. if (childDoesNotAffectWidthOrFlexing(child))
  795. continue;
  796. if (firstChild) {
  797. firstChild = false;
  798. continue;
  799. }
  800. offset += remainingSpace/totalChildren;
  801. remainingSpace -= (remainingSpace/totalChildren);
  802. --totalChildren;
  803. placeChild(child, child->location() + LayoutSize(0, offset));
  804. }
  805. }
  806. } else {
  807. if (style()->boxPack() == Center)
  808. offset += remainingSpace / 2;
  809. else // END
  810. offset += remainingSpace;
  811. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  812. if (childDoesNotAffectWidthOrFlexing(child))
  813. continue;
  814. placeChild(child, child->location() + LayoutSize(0, offset));
  815. }
  816. }
  817. }
  818. // So that the computeLogicalHeight in layoutBlock() knows to relayout positioned objects because of
  819. // a height change, we revert our height back to the intrinsic height before returning.
  820. if (heightSpecified)
  821. setHeight(oldHeight);
  822. }
  823. void RenderDeprecatedFlexibleBox::applyLineClamp(FlexBoxIterator& iterator, bool relayoutChildren)
  824. {
  825. int maxLineCount = 0;
  826. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  827. if (childDoesNotAffectWidthOrFlexing(child))
  828. continue;
  829. child->clearOverrideSize();
  830. if (relayoutChildren || (child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
  831. || (child->style()->height().isAuto() && child->isBlockFlow())) {
  832. child->setChildNeedsLayout(true, MarkOnlyThis);
  833. // Dirty all the positioned objects.
  834. if (child->isRenderBlock()) {
  835. toRenderBlock(child)->markPositionedObjectsForLayout();
  836. toRenderBlock(child)->clearTruncation();
  837. }
  838. }
  839. child->layoutIfNeeded();
  840. if (child->style()->height().isAuto() && child->isBlockFlow())
  841. maxLineCount = max(maxLineCount, toRenderBlock(child)->lineCount());
  842. }
  843. // Get the number of lines and then alter all block flow children with auto height to use the
  844. // specified height. We always try to leave room for at least one line.
  845. LineClampValue lineClamp = style()->lineClamp();
  846. int numVisibleLines = lineClamp.isPercentage() ? max(1, (maxLineCount + 1) * lineClamp.value() / 100) : lineClamp.value();
  847. if (numVisibleLines >= maxLineCount)
  848. return;
  849. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  850. if (childDoesNotAffectWidthOrFlexing(child) || !child->style()->height().isAuto() || !child->isBlockFlow())
  851. continue;
  852. RenderBlock* blockChild = toRenderBlock(child);
  853. int lineCount = blockChild->lineCount();
  854. if (lineCount <= numVisibleLines)
  855. continue;
  856. LayoutUnit newHeight = blockChild->heightForLineCount(numVisibleLines);
  857. if (newHeight == child->height())
  858. continue;
  859. child->setChildNeedsLayout(true, MarkOnlyThis);
  860. child->setOverrideLogicalContentHeight(newHeight - child->borderAndPaddingHeight());
  861. child->layoutIfNeeded();
  862. // FIXME: For now don't support RTL.
  863. if (style()->direction() != LTR)
  864. continue;
  865. // Get the last line
  866. RootInlineBox* lastLine = blockChild->lineAtIndex(lineCount - 1);
  867. if (!lastLine)
  868. continue;
  869. RootInlineBox* lastVisibleLine = blockChild->lineAtIndex(numVisibleLines - 1);
  870. if (!lastVisibleLine)
  871. continue;
  872. const UChar ellipsisAndSpace[2] = { horizontalEllipsis, ' ' };
  873. DEFINE_STATIC_LOCAL(AtomicString, ellipsisAndSpaceStr, (ellipsisAndSpace, 2));
  874. DEFINE_STATIC_LOCAL(AtomicString, ellipsisStr, (&horizontalEllipsis, 1));
  875. const Font& font = style(numVisibleLines == 1)->font();
  876. // Get ellipsis width, and if the last child is an anchor, it will go after the ellipsis, so add in a space and the anchor width too
  877. LayoutUnit totalWidth;
  878. InlineBox* anchorBox = lastLine->lastChild();
  879. if (anchorBox && anchorBox->renderer()->style()->isLink())
  880. totalWidth = anchorBox->logicalWidth() + font.width(constructTextRun(this, font, ellipsisAndSpace, 2, style()));
  881. else {
  882. anchorBox = 0;
  883. totalWidth = font.width(constructTextRun(this, font, &horizontalEllipsis, 1, style()));
  884. }
  885. // See if this width can be accommodated on the last visible line
  886. RenderBlock* destBlock = toRenderBlock(lastVisibleLine->renderer());
  887. RenderBlock* srcBlock = toRenderBlock(lastLine->renderer());
  888. // FIXME: Directions of src/destBlock could be different from our direction and from one another.
  889. if (!srcBlock->style()->isLeftToRightDirection())
  890. continue;
  891. bool leftToRight = destBlock->style()->isLeftToRightDirection();
  892. if (!leftToRight)
  893. continue;
  894. LayoutUnit blockRightEdge = destBlock->logicalRightOffsetForLine(lastVisibleLine->y(), false);
  895. if (!lastVisibleLine->lineCanAccommodateEllipsis(leftToRight, blockRightEdge, lastVisibleLine->x() + lastVisibleLine->logicalWidth(), totalWidth))
  896. continue;
  897. // Let the truncation code kick in.
  898. // FIXME: the text alignment should be recomputed after the width changes due to truncation.
  899. LayoutUnit blockLeftEdge = destBlock->logicalLeftOffsetForLine(lastVisibleLine->y(), false);
  900. lastVisibleLine->placeEllipsis(anchorBox ? ellipsisAndSpaceStr : ellipsisStr, leftToRight, blockLeftEdge, blockRightEdge, totalWidth, anchorBox);
  901. destBlock->setHasMarkupTruncation(true);
  902. }
  903. }
  904. void RenderDeprecatedFlexibleBox::clearLineClamp()
  905. {
  906. FlexBoxIterator iterator(this);
  907. for (RenderBox* child = iterator.first(); child; child = iterator.next()) {
  908. if (childDoesNotAffectWidthOrFlexing(child))
  909. continue;
  910. child->clearOverrideSize();
  911. if ((child->isReplaced() && (child->style()->width().isPercent() || child->style()->height().isPercent()))
  912. || (child->style()->height().isAuto() && child->isBlockFlow())) {
  913. child->setChildNeedsLayout(true);
  914. if (child->isRenderBlock()) {
  915. toRenderBlock(child)->markPositionedObjectsForLayout();
  916. toRenderBlock(child)->clearTruncation();
  917. }
  918. }
  919. }
  920. }
  921. void RenderDeprecatedFlexibleBox::placeChild(RenderBox* child, const LayoutPoint& location, LayoutSize* childLayoutDelta)
  922. {
  923. // Place the child and track the layout delta so we can apply it if we do another layout.
  924. if (childLayoutDelta)
  925. *childLayoutDelta += LayoutSize(child->x() - location.x(), child->y() - location.y());
  926. child->setLocation(location);
  927. }
  928. LayoutUnit RenderDeprecatedFlexibleBox::allowedChildFlex(RenderBox* child, bool expanding, unsigned int group)
  929. {
  930. if (childDoesNotAffectWidthOrFlexing(child) || child->style()->boxFlex() == 0.0f || child->style()->boxFlexGroup() != group)
  931. return 0;
  932. if (expanding) {
  933. if (isHorizontal()) {
  934. // FIXME: For now just handle fixed values.
  935. LayoutUnit maxWidth = LayoutUnit::max();
  936. LayoutUnit width = contentWidthForChild(child);
  937. if (!child->style()->maxWidth().isUndefined() && child->style()->maxWidth().isFixed())
  938. maxWidth = child->style()->maxWidth().value();
  939. else if (child->style()->maxWidth().type() == Intrinsic)
  940. maxWidth = child->maxPreferredLogicalWidth();
  941. else if (child->style()->maxWidth().type() == MinIntrinsic)
  942. maxWidth = child->minPreferredLogicalWidth();
  943. if (maxWidth == LayoutUnit::max())
  944. return maxWidth;
  945. return max<LayoutUnit>(0, maxWidth - width);
  946. } else {
  947. // FIXME: For now just handle fixed values.
  948. LayoutUnit maxHeight = LayoutUnit::max();
  949. LayoutUnit height = contentHeightForChild(child);
  950. if (!child->style()->maxHeight().isUndefined() && child->style()->maxHeight().isFixed())
  951. maxHeight = child->style()->maxHeight().value();
  952. if (maxHeight == LayoutUnit::max())
  953. return maxHeight;
  954. return max<LayoutUnit>(0, maxHeight - height);
  955. }
  956. }
  957. // FIXME: For now just handle fixed values.
  958. if (isHorizontal()) {
  959. LayoutUnit minWidth = child->minPreferredLogicalWidth();
  960. LayoutUnit width = contentWidthForChild(child);
  961. if (child->style()->minWidth().isFixed())
  962. minWidth = child->style()->minWidth().value();
  963. else if (child->style()->minWidth().type() == Intrinsic)
  964. minWidth = child->maxPreferredLogicalWidth();
  965. else if (child->style()->minWidth().type() == MinIntrinsic)
  966. minWidth = child->minPreferredLogicalWidth();
  967. else if (child->style()->minWidth().type() == Auto)
  968. minWidth = 0;
  969. LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minWidth - width);
  970. return allowedShrinkage;
  971. } else {
  972. Length minHeight = child->style()->minHeight();
  973. if (minHeight.isFixed() || minHeight.isAuto()) {
  974. LayoutUnit minHeight = child->style()->minHeight().value();
  975. LayoutUnit height = contentHeightForChild(child);
  976. LayoutUnit allowedShrinkage = min<LayoutUnit>(0, minHeight - height);
  977. return allowedShrinkage;
  978. }
  979. }
  980. return 0;
  981. }
  982. const char* RenderDeprecatedFlexibleBox::renderName() const
  983. {
  984. if (isFloating())
  985. return "RenderDeprecatedFlexibleBox (floating)";
  986. if (isOutOfFlowPositioned())
  987. return "RenderDeprecatedFlexibleBox (positioned)";
  988. // FIXME: Temporary hack while the new generated content system is being implemented.
  989. if (isPseudoElement())
  990. return "RenderDeprecatedFlexibleBox (generated)";
  991. if (isAnonymous())
  992. return "RenderDeprecatedFlexibleBox (generated)";
  993. if (isRelPositioned())
  994. return "RenderDeprecatedFlexibleBox (relative positioned)";
  995. return "RenderDeprecatedFlexibleBox";
  996. }
  997. } // namespace WebCore