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

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

Issue 931423003: Rename rendering/RenderList* to layout/LayoutList* (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Remove spurious LayoutLayerModelObject reference Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/rendering/RenderListItem.h ('k') | Source/core/rendering/RenderListMarker.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderListItem.h ('k') | Source/core/rendering/RenderListMarker.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698