| OLD | NEW |
| (Empty) |
| 1 /** | |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | |
| 4 * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. | |
| 5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) | |
| 6 * | |
| 7 * This library is free software; you can redistribute it and/or | |
| 8 * modify it under the terms of the GNU Library General Public | |
| 9 * License as published by the Free Software Foundation; either | |
| 10 * version 2 of the License, or (at your option) any later version. | |
| 11 * | |
| 12 * This library is distributed in the hope that it will be useful, | |
| 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 * Library General Public License for more details. | |
| 16 * | |
| 17 * You should have received a copy of the GNU Library General Public License | |
| 18 * along with this library; see the file COPYING.LIB. If not, write to | |
| 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
| 20 * Boston, MA 02110-1301, USA. | |
| 21 * | |
| 22 */ | |
| 23 | |
| 24 #include "config.h" | |
| 25 #include "core/rendering/RenderListItem.h" | |
| 26 | |
| 27 #include "core/HTMLNames.h" | |
| 28 #include "core/dom/NodeRenderingTraversal.h" | |
| 29 #include "core/html/HTMLOListElement.h" | |
| 30 #include "core/layout/TextAutosizer.h" | |
| 31 #include "core/rendering/RenderListMarker.h" | |
| 32 #include "core/rendering/RenderView.h" | |
| 33 #include "wtf/StdLibExtras.h" | |
| 34 #include "wtf/text/StringBuilder.h" | |
| 35 | |
| 36 namespace blink { | |
| 37 | |
| 38 using namespace HTMLNames; | |
| 39 | |
| 40 RenderListItem::RenderListItem(Element* element) | |
| 41 : RenderBlockFlow(element) | |
| 42 , m_marker(nullptr) | |
| 43 , m_hasExplicitValue(false) | |
| 44 , m_isValueUpToDate(false) | |
| 45 , m_notInList(false) | |
| 46 { | |
| 47 setInline(false); | |
| 48 } | |
| 49 | |
| 50 void RenderListItem::styleDidChange(StyleDifference diff, const LayoutStyle* old
Style) | |
| 51 { | |
| 52 RenderBlockFlow::styleDidChange(diff, oldStyle); | |
| 53 | |
| 54 if (style()->listStyleType() != NoneListStyle | |
| 55 || (style()->listStyleImage() && !style()->listStyleImage()->errorOccurr
ed())) { | |
| 56 if (!m_marker) | |
| 57 m_marker = RenderListMarker::createAnonymous(this); | |
| 58 m_marker->listItemStyleDidChange(); | |
| 59 } else if (m_marker) { | |
| 60 m_marker->destroy(); | |
| 61 m_marker = nullptr; | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 void RenderListItem::willBeDestroyed() | |
| 66 { | |
| 67 if (m_marker) { | |
| 68 m_marker->destroy(); | |
| 69 m_marker = nullptr; | |
| 70 } | |
| 71 RenderBlockFlow::willBeDestroyed(); | |
| 72 } | |
| 73 | |
| 74 void RenderListItem::insertedIntoTree() | |
| 75 { | |
| 76 RenderBlockFlow::insertedIntoTree(); | |
| 77 | |
| 78 updateListMarkerNumbers(); | |
| 79 } | |
| 80 | |
| 81 void RenderListItem::willBeRemovedFromTree() | |
| 82 { | |
| 83 RenderBlockFlow::willBeRemovedFromTree(); | |
| 84 | |
| 85 updateListMarkerNumbers(); | |
| 86 } | |
| 87 | |
| 88 static bool isList(const Node& node) | |
| 89 { | |
| 90 return isHTMLUListElement(node) || isHTMLOListElement(node); | |
| 91 } | |
| 92 | |
| 93 // Returns the enclosing list with respect to the DOM order. | |
| 94 static Node* enclosingList(const RenderListItem* listItem) | |
| 95 { | |
| 96 Node* listItemNode = listItem->node(); | |
| 97 if (!listItemNode) | |
| 98 return nullptr; | |
| 99 Node* firstNode = nullptr; | |
| 100 // We use parentNode because the enclosing list could be a ShadowRoot that's
not Element. | |
| 101 for (Node* parent = NodeRenderingTraversal::parent(*listItemNode); parent; p
arent = NodeRenderingTraversal::parent(*parent)) { | |
| 102 if (isList(*parent)) | |
| 103 return parent; | |
| 104 if (!firstNode) | |
| 105 firstNode = parent; | |
| 106 } | |
| 107 | |
| 108 // If there's no actual <ul> or <ol> list element, then the first found | |
| 109 // node acts as our list for purposes of determining what other list items | |
| 110 // should be numbered as part of the same list. | |
| 111 return firstNode; | |
| 112 } | |
| 113 | |
| 114 // Returns the next list item with respect to the DOM order. | |
| 115 static RenderListItem* nextListItem(const Node* listNode, const RenderListItem*
item = 0) | |
| 116 { | |
| 117 if (!listNode) | |
| 118 return 0; | |
| 119 | |
| 120 const Node* current = item ? item->node() : listNode; | |
| 121 ASSERT(current); | |
| 122 ASSERT(!current->document().childNeedsDistributionRecalc()); | |
| 123 current = NodeRenderingTraversal::next(*current, listNode); | |
| 124 | |
| 125 while (current) { | |
| 126 if (isList(*current)) { | |
| 127 // We've found a nested, independent list: nothing to do here. | |
| 128 current = NodeRenderingTraversal::nextSkippingChildren(*current, lis
tNode); | |
| 129 continue; | |
| 130 } | |
| 131 | |
| 132 LayoutObject* renderer = current->renderer(); | |
| 133 if (renderer && renderer->isListItem()) | |
| 134 return toRenderListItem(renderer); | |
| 135 | |
| 136 // FIXME: Can this be optimized to skip the children of the elements wit
hout a renderer? | |
| 137 current = NodeRenderingTraversal::next(*current, listNode); | |
| 138 } | |
| 139 | |
| 140 return 0; | |
| 141 } | |
| 142 | |
| 143 // Returns the previous list item with respect to the DOM order. | |
| 144 static RenderListItem* previousListItem(const Node* listNode, const RenderListIt
em* item) | |
| 145 { | |
| 146 Node* current = item->node(); | |
| 147 ASSERT(current); | |
| 148 ASSERT(!current->document().childNeedsDistributionRecalc()); | |
| 149 for (current = NodeRenderingTraversal::previous(*current, listNode); current
&& current != listNode; current = NodeRenderingTraversal::previous(*current, li
stNode)) { | |
| 150 LayoutObject* renderer = current->renderer(); | |
| 151 if (!renderer || (renderer && !renderer->isListItem())) | |
| 152 continue; | |
| 153 Node* otherList = enclosingList(toRenderListItem(renderer)); | |
| 154 // This item is part of our current list, so it's what we're looking for
. | |
| 155 if (listNode == otherList) | |
| 156 return toRenderListItem(renderer); | |
| 157 // We found ourself inside another list; lets skip the rest of it. | |
| 158 // Use nextIncludingPseudo() here because the other list itself may actu
ally | |
| 159 // be a list item itself. We need to examine it, so we do this to counte
ract | |
| 160 // the previousIncludingPseudo() that will be done by the loop. | |
| 161 if (otherList) | |
| 162 current = NodeRenderingTraversal::next(*otherList, listNode); | |
| 163 } | |
| 164 return 0; | |
| 165 } | |
| 166 | |
| 167 void RenderListItem::updateItemValuesForOrderedList(const HTMLOListElement* list
Node) | |
| 168 { | |
| 169 ASSERT(listNode); | |
| 170 | |
| 171 for (RenderListItem* listItem = nextListItem(listNode); listItem; listItem =
nextListItem(listNode, listItem)) | |
| 172 listItem->updateValue(); | |
| 173 } | |
| 174 | |
| 175 unsigned RenderListItem::itemCountForOrderedList(const HTMLOListElement* listNod
e) | |
| 176 { | |
| 177 ASSERT(listNode); | |
| 178 | |
| 179 unsigned itemCount = 0; | |
| 180 for (RenderListItem* listItem = nextListItem(listNode); listItem; listItem =
nextListItem(listNode, listItem)) | |
| 181 itemCount++; | |
| 182 | |
| 183 return itemCount; | |
| 184 } | |
| 185 | |
| 186 inline int RenderListItem::calcValue() const | |
| 187 { | |
| 188 if (m_hasExplicitValue) | |
| 189 return m_explicitValue; | |
| 190 | |
| 191 Node* list = enclosingList(this); | |
| 192 HTMLOListElement* oListElement = isHTMLOListElement(list) ? toHTMLOListEleme
nt(list) : 0; | |
| 193 int valueStep = 1; | |
| 194 if (oListElement && oListElement->isReversed()) | |
| 195 valueStep = -1; | |
| 196 | |
| 197 // FIXME: This recurses to a possible depth of the length of the list. | |
| 198 // That's not good -- we need to change this to an iterative algorithm. | |
| 199 if (RenderListItem* previousItem = previousListItem(list, this)) | |
| 200 return previousItem->value() + valueStep; | |
| 201 | |
| 202 if (oListElement) | |
| 203 return oListElement->start(); | |
| 204 | |
| 205 return 1; | |
| 206 } | |
| 207 | |
| 208 void RenderListItem::updateValueNow() const | |
| 209 { | |
| 210 m_value = calcValue(); | |
| 211 m_isValueUpToDate = true; | |
| 212 } | |
| 213 | |
| 214 bool RenderListItem::isEmpty() const | |
| 215 { | |
| 216 return lastChild() == m_marker; | |
| 217 } | |
| 218 | |
| 219 static LayoutObject* getParentOfFirstLineBox(RenderBlockFlow* curr, LayoutObject
* marker) | |
| 220 { | |
| 221 LayoutObject* firstChild = curr->firstChild(); | |
| 222 if (!firstChild) | |
| 223 return 0; | |
| 224 | |
| 225 bool inQuirksMode = curr->document().inQuirksMode(); | |
| 226 for (LayoutObject* currChild = firstChild; currChild; currChild = currChild-
>nextSibling()) { | |
| 227 if (currChild == marker) | |
| 228 continue; | |
| 229 | |
| 230 if (currChild->isInline() && (!currChild->isRenderInline() || curr->gene
ratesLineBoxesForInlineChild(currChild))) | |
| 231 return curr; | |
| 232 | |
| 233 if (currChild->isFloating() || currChild->isOutOfFlowPositioned()) | |
| 234 continue; | |
| 235 | |
| 236 if (!currChild->isRenderBlockFlow() || (currChild->isBox() && toRenderBo
x(currChild)->isWritingModeRoot())) | |
| 237 break; | |
| 238 | |
| 239 if (curr->isListItem() && inQuirksMode && currChild->node() && | |
| 240 (isHTMLUListElement(*currChild->node()) || isHTMLOListElement(*currC
hild->node()))) | |
| 241 break; | |
| 242 | |
| 243 LayoutObject* lineBox = getParentOfFirstLineBox(toRenderBlockFlow(currCh
ild), marker); | |
| 244 if (lineBox) | |
| 245 return lineBox; | |
| 246 } | |
| 247 | |
| 248 return 0; | |
| 249 } | |
| 250 | |
| 251 void RenderListItem::updateValue() | |
| 252 { | |
| 253 if (!m_hasExplicitValue) { | |
| 254 m_isValueUpToDate = false; | |
| 255 if (m_marker) | |
| 256 m_marker->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
); | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 static LayoutObject* firstNonMarkerChild(LayoutObject* parent) | |
| 261 { | |
| 262 LayoutObject* result = parent->slowFirstChild(); | |
| 263 while (result && result->isListMarker()) | |
| 264 result = result->nextSibling(); | |
| 265 return result; | |
| 266 } | |
| 267 | |
| 268 void RenderListItem::updateMarkerLocationAndInvalidateWidth() | |
| 269 { | |
| 270 ASSERT(m_marker); | |
| 271 | |
| 272 // FIXME: We should not modify the structure of the render tree | |
| 273 // during layout. crbug.com/370461 | |
| 274 DeprecatedDisableModifyRenderTreeStructureAsserts disabler; | |
| 275 if (updateMarkerLocation()) { | |
| 276 // If the marker is inside we need to redo the preferred width calculati
ons | |
| 277 // as the size of the item now includes the size of the list marker. | |
| 278 if (m_marker->isInside()) | |
| 279 containingBlock()->updateLogicalWidth(); | |
| 280 } | |
| 281 } | |
| 282 | |
| 283 bool RenderListItem::updateMarkerLocation() | |
| 284 { | |
| 285 ASSERT(m_marker); | |
| 286 LayoutObject* markerParent = m_marker->parent(); | |
| 287 LayoutObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker); | |
| 288 if (!lineBoxParent) { | |
| 289 // If the marker is currently contained inside an anonymous box, then we | |
| 290 // are the only item in that anonymous box (since no line box parent was | |
| 291 // found). It's ok to just leave the marker where it is in this case. | |
| 292 if (markerParent && markerParent->isAnonymousBlock()) | |
| 293 lineBoxParent = markerParent; | |
| 294 else | |
| 295 lineBoxParent = this; | |
| 296 } | |
| 297 | |
| 298 if (markerParent != lineBoxParent) { | |
| 299 m_marker->remove(); | |
| 300 lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); | |
| 301 m_marker->updateMarginsAndContent(); | |
| 302 // If markerParent is an anonymous block with no children, destroy it. | |
| 303 if (markerParent && markerParent->isAnonymousBlock() && !toRenderBlock(m
arkerParent)->firstChild() && !toRenderBlock(markerParent)->continuation()) | |
| 304 markerParent->destroy(); | |
| 305 return true; | |
| 306 } | |
| 307 | |
| 308 return false; | |
| 309 } | |
| 310 | |
| 311 void RenderListItem::layout() | |
| 312 { | |
| 313 ASSERT(needsLayout()); | |
| 314 | |
| 315 if (m_marker) { | |
| 316 // The marker must be autosized before calling | |
| 317 // updateMarkerLocationAndInvalidateWidth. It cannot be done in the | |
| 318 // parent's beginLayout because it is not yet in the render tree. | |
| 319 if (TextAutosizer* textAutosizer = document().textAutosizer()) | |
| 320 textAutosizer->inflateListItem(this, m_marker); | |
| 321 | |
| 322 updateMarkerLocationAndInvalidateWidth(); | |
| 323 } | |
| 324 | |
| 325 RenderBlockFlow::layout(); | |
| 326 } | |
| 327 | |
| 328 void RenderListItem::addOverflowFromChildren() | |
| 329 { | |
| 330 RenderBlockFlow::addOverflowFromChildren(); | |
| 331 positionListMarker(); | |
| 332 } | |
| 333 | |
| 334 void RenderListItem::positionListMarker() | |
| 335 { | |
| 336 if (m_marker && m_marker->parent()->isBox() && !m_marker->isInside() && m_ma
rker->inlineBoxWrapper()) { | |
| 337 LayoutUnit markerOldLogicalLeft = m_marker->logicalLeft(); | |
| 338 LayoutUnit blockOffset = 0; | |
| 339 LayoutUnit lineOffset = 0; | |
| 340 for (RenderBox* o = m_marker->parentBox(); o != this; o = o->parentBox()
) { | |
| 341 blockOffset += o->logicalTop(); | |
| 342 lineOffset += o->logicalLeft(); | |
| 343 } | |
| 344 | |
| 345 bool adjustOverflow = false; | |
| 346 LayoutUnit markerLogicalLeft; | |
| 347 RootInlineBox& root = m_marker->inlineBoxWrapper()->root(); | |
| 348 bool hitSelfPaintingLayer = false; | |
| 349 | |
| 350 LayoutUnit lineTop = root.lineTop(); | |
| 351 LayoutUnit lineBottom = root.lineBottom(); | |
| 352 | |
| 353 // FIXME: Need to account for relative positioning in the layout overflo
w. | |
| 354 if (style()->isLeftToRightDirection()) { | |
| 355 LayoutUnit leftLineOffset = logicalLeftOffsetForLine(blockOffset, lo
gicalLeftOffsetForLine(blockOffset, false), false); | |
| 356 markerLogicalLeft = leftLineOffset - lineOffset - paddingStart() - b
orderStart() + m_marker->marginStart(); | |
| 357 m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLog
icalLeft - markerOldLogicalLeft).toFloat()); | |
| 358 for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); bo
x; box = box->parent()) { | |
| 359 LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOver
flowRect(lineTop, lineBottom); | |
| 360 LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOver
flowRect(lineTop, lineBottom); | |
| 361 if (markerLogicalLeft < newLogicalVisualOverflowRect.x() && !hit
SelfPaintingLayer) { | |
| 362 newLogicalVisualOverflowRect.setWidth(newLogicalVisualOverfl
owRect.maxX() - markerLogicalLeft); | |
| 363 newLogicalVisualOverflowRect.setX(markerLogicalLeft); | |
| 364 if (box == root) | |
| 365 adjustOverflow = true; | |
| 366 } | |
| 367 if (markerLogicalLeft < newLogicalLayoutOverflowRect.x()) { | |
| 368 newLogicalLayoutOverflowRect.setWidth(newLogicalLayoutOverfl
owRect.maxX() - markerLogicalLeft); | |
| 369 newLogicalLayoutOverflowRect.setX(markerLogicalLeft); | |
| 370 if (box == root) | |
| 371 adjustOverflow = true; | |
| 372 } | |
| 373 box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, n
ewLogicalVisualOverflowRect, lineTop, lineBottom); | |
| 374 if (box->boxModelObject()->hasSelfPaintingLayer()) | |
| 375 hitSelfPaintingLayer = true; | |
| 376 } | |
| 377 } else { | |
| 378 LayoutUnit rightLineOffset = logicalRightOffsetForLine(blockOffset,
logicalRightOffsetForLine(blockOffset, false), false); | |
| 379 markerLogicalLeft = rightLineOffset - lineOffset + paddingStart() +
borderStart() + m_marker->marginEnd(); | |
| 380 m_marker->inlineBoxWrapper()->adjustLineDirectionPosition((markerLog
icalLeft - markerOldLogicalLeft).toFloat()); | |
| 381 for (InlineFlowBox* box = m_marker->inlineBoxWrapper()->parent(); bo
x; box = box->parent()) { | |
| 382 LayoutRect newLogicalVisualOverflowRect = box->logicalVisualOver
flowRect(lineTop, lineBottom); | |
| 383 LayoutRect newLogicalLayoutOverflowRect = box->logicalLayoutOver
flowRect(lineTop, lineBottom); | |
| 384 if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalVis
ualOverflowRect.maxX() && !hitSelfPaintingLayer) { | |
| 385 newLogicalVisualOverflowRect.setWidth(markerLogicalLeft + m_
marker->logicalWidth() - newLogicalVisualOverflowRect.x()); | |
| 386 if (box == root) | |
| 387 adjustOverflow = true; | |
| 388 } | |
| 389 if (markerLogicalLeft + m_marker->logicalWidth() > newLogicalLay
outOverflowRect.maxX()) { | |
| 390 newLogicalLayoutOverflowRect.setWidth(markerLogicalLeft + m_
marker->logicalWidth() - newLogicalLayoutOverflowRect.x()); | |
| 391 if (box == root) | |
| 392 adjustOverflow = true; | |
| 393 } | |
| 394 box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, n
ewLogicalVisualOverflowRect, lineTop, lineBottom); | |
| 395 | |
| 396 if (box->boxModelObject()->hasSelfPaintingLayer()) | |
| 397 hitSelfPaintingLayer = true; | |
| 398 } | |
| 399 } | |
| 400 | |
| 401 if (adjustOverflow) { | |
| 402 LayoutRect markerRect(LayoutPoint(markerLogicalLeft + lineOffset, bl
ockOffset), m_marker->size()); | |
| 403 if (!style()->isHorizontalWritingMode()) | |
| 404 markerRect = markerRect.transposedRect(); | |
| 405 RenderBox* o = m_marker; | |
| 406 bool propagateVisualOverflow = true; | |
| 407 bool propagateLayoutOverflow = true; | |
| 408 do { | |
| 409 o = o->parentBox(); | |
| 410 if (o->isRenderBlock()) { | |
| 411 if (propagateVisualOverflow) | |
| 412 toRenderBlock(o)->addContentsVisualOverflow(markerRect); | |
| 413 if (propagateLayoutOverflow) | |
| 414 toRenderBlock(o)->addLayoutOverflow(markerRect); | |
| 415 } | |
| 416 if (o->hasOverflowClip()) { | |
| 417 propagateLayoutOverflow = false; | |
| 418 propagateVisualOverflow = false; | |
| 419 } | |
| 420 if (o->hasSelfPaintingLayer()) | |
| 421 propagateVisualOverflow = false; | |
| 422 markerRect.moveBy(-o->location()); | |
| 423 } while (o != this && propagateVisualOverflow && propagateLayoutOver
flow); | |
| 424 } | |
| 425 } | |
| 426 } | |
| 427 | |
| 428 void RenderListItem::paint(const PaintInfo& paintInfo, const LayoutPoint& paintO
ffset) | |
| 429 { | |
| 430 if (!logicalHeight() && hasOverflowClip()) | |
| 431 return; | |
| 432 | |
| 433 RenderBlockFlow::paint(paintInfo, paintOffset); | |
| 434 } | |
| 435 | |
| 436 const String& RenderListItem::markerText() const | |
| 437 { | |
| 438 if (m_marker) | |
| 439 return m_marker->text(); | |
| 440 return nullAtom.string(); | |
| 441 } | |
| 442 | |
| 443 void RenderListItem::explicitValueChanged() | |
| 444 { | |
| 445 if (m_marker) | |
| 446 m_marker->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(); | |
| 447 Node* listNode = enclosingList(this); | |
| 448 for (RenderListItem* item = this; item; item = nextListItem(listNode, item)) | |
| 449 item->updateValue(); | |
| 450 } | |
| 451 | |
| 452 void RenderListItem::setExplicitValue(int value) | |
| 453 { | |
| 454 ASSERT(node()); | |
| 455 | |
| 456 if (m_hasExplicitValue && m_explicitValue == value) | |
| 457 return; | |
| 458 m_explicitValue = value; | |
| 459 m_value = value; | |
| 460 m_hasExplicitValue = true; | |
| 461 explicitValueChanged(); | |
| 462 } | |
| 463 | |
| 464 void RenderListItem::clearExplicitValue() | |
| 465 { | |
| 466 ASSERT(node()); | |
| 467 | |
| 468 if (!m_hasExplicitValue) | |
| 469 return; | |
| 470 m_hasExplicitValue = false; | |
| 471 m_isValueUpToDate = false; | |
| 472 explicitValueChanged(); | |
| 473 } | |
| 474 | |
| 475 void RenderListItem::setNotInList(bool notInList) | |
| 476 { | |
| 477 m_notInList = notInList; | |
| 478 if (m_marker) | |
| 479 updateMarkerLocation(); | |
| 480 } | |
| 481 | |
| 482 static RenderListItem* previousOrNextItem(bool isListReversed, Node* list, Rende
rListItem* item) | |
| 483 { | |
| 484 return isListReversed ? previousListItem(list, item) : nextListItem(list, it
em); | |
| 485 } | |
| 486 | |
| 487 void RenderListItem::updateListMarkerNumbers() | |
| 488 { | |
| 489 // If distribution recalc is needed, updateListMarkerNumber will be re-invok
ed | |
| 490 // after distribution is calculated. | |
| 491 if (node()->document().childNeedsDistributionRecalc()) | |
| 492 return; | |
| 493 | |
| 494 Node* listNode = enclosingList(this); | |
| 495 ASSERT(listNode); | |
| 496 | |
| 497 bool isListReversed = false; | |
| 498 HTMLOListElement* oListElement = isHTMLOListElement(listNode) ? toHTMLOListE
lement(listNode) : 0; | |
| 499 if (oListElement) { | |
| 500 oListElement->itemCountChanged(); | |
| 501 isListReversed = oListElement->isReversed(); | |
| 502 } | |
| 503 | |
| 504 // FIXME: The n^2 protection below doesn't help if the elements were inserte
d after the | |
| 505 // the list had already been displayed. | |
| 506 | |
| 507 // Avoid an O(n^2) walk over the children below when they're all known to be
attaching. | |
| 508 if (listNode->needsAttach()) | |
| 509 return; | |
| 510 | |
| 511 for (RenderListItem* item = previousOrNextItem(isListReversed, listNode, thi
s); item; item = previousOrNextItem(isListReversed, listNode, item)) { | |
| 512 if (!item->m_isValueUpToDate) { | |
| 513 // If an item has been marked for update before, we can safely | |
| 514 // assume that all the following ones have too. | |
| 515 // This gives us the opportunity to stop here and avoid | |
| 516 // marking the same nodes again. | |
| 517 break; | |
| 518 } | |
| 519 item->updateValue(); | |
| 520 } | |
| 521 } | |
| 522 | |
| 523 } // namespace blink | |
| OLD | NEW |