OLD | NEW |
---|---|
1 /** | 1 /** |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. | 4 * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. |
5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) | 5 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) |
6 * | 6 * |
7 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
10 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
(...skipping 11 matching lines...) Expand all Loading... | |
22 */ | 22 */ |
23 | 23 |
24 #include "config.h" | 24 #include "config.h" |
25 #include "core/layout/LayoutListItem.h" | 25 #include "core/layout/LayoutListItem.h" |
26 | 26 |
27 #include "core/HTMLNames.h" | 27 #include "core/HTMLNames.h" |
28 #include "core/dom/shadow/ComposedTreeTraversal.h" | 28 #include "core/dom/shadow/ComposedTreeTraversal.h" |
29 #include "core/html/HTMLOListElement.h" | 29 #include "core/html/HTMLOListElement.h" |
30 #include "core/layout/LayoutListMarker.h" | 30 #include "core/layout/LayoutListMarker.h" |
31 #include "core/layout/LayoutView.h" | 31 #include "core/layout/LayoutView.h" |
32 #include "core/layout/TextAutosizer.h" | |
33 #include "wtf/StdLibExtras.h" | 32 #include "wtf/StdLibExtras.h" |
34 #include "wtf/text/StringBuilder.h" | 33 #include "wtf/text/StringBuilder.h" |
35 | 34 |
36 namespace blink { | 35 namespace blink { |
37 | 36 |
38 using namespace HTMLNames; | 37 using namespace HTMLNames; |
39 | 38 |
40 LayoutListItem::LayoutListItem(Element* element) | 39 LayoutListItem::LayoutListItem(Element* element) |
41 : LayoutBlockFlow(element) | 40 : LayoutBlockFlow(element) |
42 , m_marker(nullptr) | 41 , m_marker(nullptr) |
43 , m_hasExplicitValue(false) | 42 , m_hasExplicitValue(false) |
44 , m_isValueUpToDate(false) | 43 , m_isValueUpToDate(false) |
45 , m_notInList(false) | 44 , m_notInList(false) |
46 { | 45 { |
47 setInline(false); | 46 setInline(false); |
47 | |
48 setConsumesSubtreeChangeNotification(); | |
49 registerSubtreeChangeListenerOnDescendants(true); | |
50 notifyOfSubtreeChange(); | |
esprehn
2015/05/06 16:10:28
This isn't right though, it's like calling setNeed
| |
48 } | 51 } |
49 | 52 |
50 void LayoutListItem::styleDidChange(StyleDifference diff, const ComputedStyle* o ldStyle) | 53 void LayoutListItem::styleDidChange(StyleDifference diff, const ComputedStyle* o ldStyle) |
51 { | 54 { |
52 LayoutBlockFlow::styleDidChange(diff, oldStyle); | 55 LayoutBlockFlow::styleDidChange(diff, oldStyle); |
53 | 56 |
54 if (style()->listStyleType() != NoneListStyle | 57 if (style()->listStyleType() != NoneListStyle |
55 || (style()->listStyleImage() && !style()->listStyleImage()->errorOccurr ed())) { | 58 || (style()->listStyleImage() && !style()->listStyleImage()->errorOccurr ed())) { |
56 if (!m_marker) | 59 if (!m_marker) |
57 m_marker = LayoutListMarker::createAnonymous(this); | 60 m_marker = LayoutListMarker::createAnonymous(this); |
58 m_marker->listItemStyleDidChange(); | 61 m_marker->listItemStyleDidChange(); |
62 notifyOfSubtreeChange(); | |
59 } else if (m_marker) { | 63 } else if (m_marker) { |
60 m_marker->destroy(); | 64 m_marker->destroy(); |
61 m_marker = nullptr; | 65 m_marker = nullptr; |
62 } | 66 } |
63 } | 67 } |
64 | 68 |
65 void LayoutListItem::willBeDestroyed() | 69 void LayoutListItem::willBeDestroyed() |
66 { | 70 { |
67 if (m_marker) { | 71 if (m_marker) { |
68 m_marker->destroy(); | 72 m_marker->destroy(); |
69 m_marker = nullptr; | 73 m_marker = nullptr; |
70 } | 74 } |
71 LayoutBlockFlow::willBeDestroyed(); | 75 LayoutBlockFlow::willBeDestroyed(); |
72 } | 76 } |
73 | 77 |
74 void LayoutListItem::insertedIntoTree() | 78 void LayoutListItem::insertedIntoTree() |
75 { | 79 { |
76 LayoutBlockFlow::insertedIntoTree(); | 80 LayoutBlockFlow::insertedIntoTree(); |
77 | 81 |
78 updateListMarkerNumbers(); | 82 updateListMarkerNumbers(); |
79 } | 83 } |
80 | 84 |
81 void LayoutListItem::willBeRemovedFromTree() | 85 void LayoutListItem::willBeRemovedFromTree() |
82 { | 86 { |
83 LayoutBlockFlow::willBeRemovedFromTree(); | 87 LayoutBlockFlow::willBeRemovedFromTree(); |
84 | 88 |
85 updateListMarkerNumbers(); | 89 updateListMarkerNumbers(); |
86 } | 90 } |
87 | 91 |
92 void LayoutListItem::subtreeDidChange() | |
93 { | |
94 if (!m_marker) | |
95 return; | |
96 | |
97 if (!updateMarkerLocation()) | |
98 return; | |
99 | |
100 // If the marker is inside we need to redo the preferred width calculations | |
101 // as the size of the item now includes the size of the list marker. | |
102 if (m_marker->isInside()) | |
103 setPreferredLogicalWidthsDirty(); | |
104 } | |
105 | |
88 static bool isList(const Node& node) | 106 static bool isList(const Node& node) |
89 { | 107 { |
90 return isHTMLUListElement(node) || isHTMLOListElement(node); | 108 return isHTMLUListElement(node) || isHTMLOListElement(node); |
91 } | 109 } |
92 | 110 |
93 // Returns the enclosing list with respect to the DOM order. | 111 // Returns the enclosing list with respect to the DOM order. |
94 static Node* enclosingList(const LayoutListItem* listItem) | 112 static Node* enclosingList(const LayoutListItem* listItem) |
95 { | 113 { |
96 Node* listItemNode = listItem->node(); | 114 Node* listItemNode = listItem->node(); |
97 if (!listItemNode) | 115 if (!listItemNode) |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 } | 276 } |
259 | 277 |
260 static LayoutObject* firstNonMarkerChild(LayoutObject* parent) | 278 static LayoutObject* firstNonMarkerChild(LayoutObject* parent) |
261 { | 279 { |
262 LayoutObject* result = parent->slowFirstChild(); | 280 LayoutObject* result = parent->slowFirstChild(); |
263 while (result && result->isListMarker()) | 281 while (result && result->isListMarker()) |
264 result = result->nextSibling(); | 282 result = result->nextSibling(); |
265 return result; | 283 return result; |
266 } | 284 } |
267 | 285 |
268 void LayoutListItem::updateMarkerLocationAndInvalidateWidth() | |
269 { | |
270 ASSERT(m_marker); | |
271 | |
272 // FIXME: We should not modify the structure of the layout tree | |
273 // during layout. crbug.com/370461 | |
274 DeprecatedDisableModifyLayoutTreeStructureAsserts disabler; | |
275 LayoutState* layoutState = view()->layoutState(); | |
276 LayoutFlowThread* currentFlowThread = nullptr; | |
277 if (layoutState) { | |
278 // We're about to modify the layout tree structure (during layout!), and any code using | |
279 // LayoutState might get utterly confused by that. There's no evidence t hat anything other | |
280 // than the flow thread code will suffer, though, so just reset the curr ent flow thread | |
281 // temporarily. | |
282 // FIXME: get rid of this hack, including the flow thread setter in Layo utState, as part of | |
283 // fixing crbug.com/370461 | |
284 currentFlowThread = layoutState->flowThread(); | |
285 layoutState->setFlowThread(nullptr); | |
286 } | |
287 if (updateMarkerLocation()) { | |
288 // If the marker is inside we need to redo the preferred width calculati ons | |
289 // as the size of the item now includes the size of the list marker. | |
290 if (m_marker->isInside()) | |
291 containingBlock()->updateLogicalWidth(); | |
292 } | |
293 if (layoutState) | |
294 layoutState->setFlowThread(currentFlowThread); | |
295 } | |
296 | |
297 bool LayoutListItem::updateMarkerLocation() | 286 bool LayoutListItem::updateMarkerLocation() |
298 { | 287 { |
299 ASSERT(m_marker); | 288 ASSERT(m_marker); |
289 | |
300 LayoutObject* markerParent = m_marker->parent(); | 290 LayoutObject* markerParent = m_marker->parent(); |
301 LayoutObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker); | 291 LayoutObject* lineBoxParent = getParentOfFirstLineBox(this, m_marker); |
302 if (!lineBoxParent) { | 292 if (!lineBoxParent) { |
303 // If the marker is currently contained inside an anonymous box, then we | 293 // If the marker is currently contained inside an anonymous box, then we |
304 // are the only item in that anonymous box (since no line box parent was | 294 // are the only item in that anonymous box (since no line box parent was |
305 // found). It's ok to just leave the marker where it is in this case. | 295 // found). It's ok to just leave the marker where it is in this case. |
306 if (markerParent && markerParent->isAnonymousBlock()) | 296 if (markerParent && markerParent->isAnonymousBlock()) |
307 lineBoxParent = markerParent; | 297 lineBoxParent = markerParent; |
308 else | 298 else |
309 lineBoxParent = this; | 299 lineBoxParent = this; |
310 } | 300 } |
311 | 301 |
312 if (markerParent != lineBoxParent) { | 302 if (markerParent != lineBoxParent) { |
313 m_marker->remove(); | 303 m_marker->remove(); |
314 lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); | 304 lineBoxParent->addChild(m_marker, firstNonMarkerChild(lineBoxParent)); |
315 m_marker->updateMarginsAndContent(); | 305 m_marker->updateMarginsAndContent(); |
316 // If markerParent is an anonymous block with no children, destroy it. | 306 // If markerParent is an anonymous block with no children, destroy it. |
317 if (markerParent && markerParent->isAnonymousBlock() && !toLayoutBlock(m arkerParent)->firstChild() && !toLayoutBlock(markerParent)->continuation()) | 307 if (markerParent && markerParent->isAnonymousBlock() && !toLayoutBlock(m arkerParent)->firstChild() && !toLayoutBlock(markerParent)->continuation()) |
318 markerParent->destroy(); | 308 markerParent->destroy(); |
319 return true; | 309 return true; |
320 } | 310 } |
321 | 311 |
322 return false; | 312 return false; |
323 } | 313 } |
324 | 314 |
325 void LayoutListItem::layout() | |
326 { | |
327 ASSERT(needsLayout()); | |
328 | |
329 if (m_marker) { | |
330 // The marker must be autosized before calling | |
331 // updateMarkerLocationAndInvalidateWidth. It cannot be done in the | |
332 // parent's beginLayout because it is not yet in the layout tree. | |
333 if (TextAutosizer* textAutosizer = document().textAutosizer()) | |
334 textAutosizer->inflateListItem(this, m_marker); | |
335 | |
336 updateMarkerLocationAndInvalidateWidth(); | |
337 } | |
338 | |
339 LayoutBlockFlow::layout(); | |
340 } | |
341 | |
342 void LayoutListItem::addOverflowFromChildren() | 315 void LayoutListItem::addOverflowFromChildren() |
343 { | 316 { |
344 LayoutBlockFlow::addOverflowFromChildren(); | 317 LayoutBlockFlow::addOverflowFromChildren(); |
345 positionListMarker(); | 318 positionListMarker(); |
346 } | 319 } |
347 | 320 |
348 void LayoutListItem::positionListMarker() | 321 void LayoutListItem::positionListMarker() |
349 { | 322 { |
350 if (m_marker && m_marker->parent()->isBox() && !m_marker->isInside() && m_ma rker->inlineBoxWrapper()) { | 323 if (m_marker && m_marker->parent() && m_marker->parent()->isBox() && !m_mark er->isInside() && m_marker->inlineBoxWrapper()) { |
351 LayoutUnit markerOldLogicalLeft = m_marker->logicalLeft(); | 324 LayoutUnit markerOldLogicalLeft = m_marker->logicalLeft(); |
352 LayoutUnit blockOffset = 0; | 325 LayoutUnit blockOffset = 0; |
353 LayoutUnit lineOffset = 0; | 326 LayoutUnit lineOffset = 0; |
354 for (LayoutBox* o = m_marker->parentBox(); o != this; o = o->parentBox() ) { | 327 for (LayoutBox* o = m_marker->parentBox(); o != this; o = o->parentBox() ) { |
355 blockOffset += o->logicalTop(); | 328 blockOffset += o->logicalTop(); |
356 lineOffset += o->logicalLeft(); | 329 lineOffset += o->logicalLeft(); |
357 } | 330 } |
358 | 331 |
359 bool adjustOverflow = false; | 332 bool adjustOverflow = false; |
360 LayoutUnit markerLogicalLeft; | 333 LayoutUnit markerLogicalLeft; |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
482 if (!m_hasExplicitValue) | 455 if (!m_hasExplicitValue) |
483 return; | 456 return; |
484 m_hasExplicitValue = false; | 457 m_hasExplicitValue = false; |
485 m_isValueUpToDate = false; | 458 m_isValueUpToDate = false; |
486 explicitValueChanged(); | 459 explicitValueChanged(); |
487 } | 460 } |
488 | 461 |
489 void LayoutListItem::setNotInList(bool notInList) | 462 void LayoutListItem::setNotInList(bool notInList) |
490 { | 463 { |
491 m_notInList = notInList; | 464 m_notInList = notInList; |
492 if (m_marker) | |
493 updateMarkerLocation(); | |
494 } | 465 } |
495 | 466 |
496 static LayoutListItem* previousOrNextItem(bool isListReversed, Node* list, Layou tListItem* item) | 467 static LayoutListItem* previousOrNextItem(bool isListReversed, Node* list, Layou tListItem* item) |
497 { | 468 { |
498 return isListReversed ? previousListItem(list, item) : nextListItem(list, it em); | 469 return isListReversed ? previousListItem(list, item) : nextListItem(list, it em); |
499 } | 470 } |
500 | 471 |
501 void LayoutListItem::updateListMarkerNumbers() | 472 void LayoutListItem::updateListMarkerNumbers() |
502 { | 473 { |
503 // If distribution recalc is needed, updateListMarkerNumber will be re-invok ed | 474 // If distribution recalc is needed, updateListMarkerNumber will be re-invok ed |
(...skipping 24 matching lines...) Expand all Loading... | |
528 // assume that all the following ones have too. | 499 // assume that all the following ones have too. |
529 // This gives us the opportunity to stop here and avoid | 500 // This gives us the opportunity to stop here and avoid |
530 // marking the same nodes again. | 501 // marking the same nodes again. |
531 break; | 502 break; |
532 } | 503 } |
533 item->updateValue(); | 504 item->updateValue(); |
534 } | 505 } |
535 } | 506 } |
536 | 507 |
537 } // namespace blink | 508 } // namespace blink |
OLD | NEW |