LayoutListItem.cpp 19.2 KB
Newer Older
1
2
3
/**
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4
 * Copyright (C) 2003, 2004, 2005, 2006, 2010 Apple Inc. All rights reserved.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
ddkilzer's avatar
ddkilzer committed
19
20
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
21
22
 *
 */
darin's avatar
darin committed
23

24
#include "core/layout/LayoutListItem.h"
25

26
#include "core/HTMLNames.h"
hayato's avatar
hayato committed
27
#include "core/dom/shadow/FlatTreeTraversal.h"
28
#include "core/html/HTMLOListElement.h"
29
#include "core/layout/LayoutListMarker.h"
30
#include "core/paint/ListItemPainter.h"
31
32
33
#include "platform/wtf/SaturatedArithmetic.h"
#include "platform/wtf/StdLibExtras.h"
#include "platform/wtf/text/StringBuilder.h"
34

abarth@chromium.org's avatar
abarth@chromium.org committed
35
namespace blink {
36
37
38

using namespace HTMLNames;

39
LayoutListItem::LayoutListItem(Element* element)
Blink Reformat's avatar
Blink Reformat committed
40
    : LayoutBlockFlow(element),
Blink Reformat's avatar
Blink Reformat committed
41
42
43
44
45
46
47
48
      marker_(nullptr),
      has_explicit_value_(false),
      is_value_up_to_date_(false),
      not_in_list_(false) {
  SetInline(false);

  SetConsumesSubtreeChangeNotification();
  RegisterSubtreeChangeListenerOnDescendants(true);
49
50
}

Blink Reformat's avatar
Blink Reformat committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
void LayoutListItem::StyleDidChange(StyleDifference diff,
                                    const ComputedStyle* old_style) {
  LayoutBlockFlow::StyleDidChange(diff, old_style);

  StyleImage* current_image = Style()->ListStyleImage();
  if (Style()->ListStyleType() != EListStyleType::kNone ||
      (current_image && !current_image->ErrorOccurred())) {
    if (!marker_)
      marker_ = LayoutListMarker::CreateAnonymous(this);
    marker_->ListItemStyleDidChange();
    NotifyOfSubtreeChange();
  } else if (marker_) {
    marker_->Destroy();
    marker_ = nullptr;
Blink Reformat's avatar
Blink Reformat committed
65
66
  }

Blink Reformat's avatar
Blink Reformat committed
67
68
69
70
71
72
  StyleImage* old_image = old_style ? old_style->ListStyleImage() : nullptr;
  if (old_image != current_image) {
    if (old_image)
      old_image->RemoveClient(this);
    if (current_image)
      current_image->AddClient(this);
Blink Reformat's avatar
Blink Reformat committed
73
  }
74
75
}

Blink Reformat's avatar
Blink Reformat committed
76
77
78
79
void LayoutListItem::WillBeDestroyed() {
  if (marker_) {
    marker_->Destroy();
    marker_ = nullptr;
Blink Reformat's avatar
Blink Reformat committed
80
  }
81

Blink Reformat's avatar
Blink Reformat committed
82
  LayoutBlockFlow::WillBeDestroyed();
83

Blink Reformat's avatar
Blink Reformat committed
84
85
  if (Style() && Style()->ListStyleImage())
    Style()->ListStyleImage()->RemoveClient(this);
86
87
}

Blink Reformat's avatar
Blink Reformat committed
88
89
void LayoutListItem::InsertedIntoTree() {
  LayoutBlockFlow::InsertedIntoTree();
90

Blink Reformat's avatar
Blink Reformat committed
91
  UpdateListMarkerNumbers();
92
93
}

Blink Reformat's avatar
Blink Reformat committed
94
95
void LayoutListItem::WillBeRemovedFromTree() {
  LayoutBlockFlow::WillBeRemovedFromTree();
96

Blink Reformat's avatar
Blink Reformat committed
97
  UpdateListMarkerNumbers();
98
99
}

Blink Reformat's avatar
Blink Reformat committed
100
101
void LayoutListItem::SubtreeDidChange() {
  if (!marker_)
Blink Reformat's avatar
Blink Reformat committed
102
    return;
103

Blink Reformat's avatar
Blink Reformat committed
104
  if (!UpdateMarkerLocation())
Blink Reformat's avatar
Blink Reformat committed
105
    return;
106

Blink Reformat's avatar
Blink Reformat committed
107
108
  // If the marker is inside we need to redo the preferred width calculations
  // as the size of the item now includes the size of the list marker.
Blink Reformat's avatar
Blink Reformat committed
109
110
  if (marker_->IsInside())
    SetPreferredLogicalWidthsDirty();
111
112
}

Blink Reformat's avatar
Blink Reformat committed
113
static bool IsList(const Node& node) {
Blink Reformat's avatar
Blink Reformat committed
114
  return isHTMLUListElement(node) || isHTMLOListElement(node);
115
116
}

117
// Returns the enclosing list with respect to the DOM order.
Blink Reformat's avatar
Blink Reformat committed
118
119
120
static Node* EnclosingList(const LayoutListItem* list_item) {
  Node* list_item_node = list_item->GetNode();
  if (!list_item_node)
Blink Reformat's avatar
Blink Reformat committed
121
    return nullptr;
Blink Reformat's avatar
Blink Reformat committed
122
  Node* first_node = nullptr;
123
124
  // We use parentNode because the enclosing list could be a ShadowRoot that's
  // not Element.
Blink Reformat's avatar
Blink Reformat committed
125
126
127
  for (Node* parent = FlatTreeTraversal::Parent(*list_item_node); parent;
       parent = FlatTreeTraversal::Parent(*parent)) {
    if (IsList(*parent))
Blink Reformat's avatar
Blink Reformat committed
128
      return parent;
Blink Reformat's avatar
Blink Reformat committed
129
130
    if (!first_node)
      first_node = parent;
Blink Reformat's avatar
Blink Reformat committed
131
132
133
134
135
  }

  // If there's no actual <ul> or <ol> list element, then the first found
  // node acts as our list for purposes of determining what other list items
  // should be numbered as part of the same list.
Blink Reformat's avatar
Blink Reformat committed
136
  return first_node;
137
138
}

139
// Returns the next list item with respect to the DOM order.
Blink Reformat's avatar
Blink Reformat committed
140
static LayoutListItem* NextListItem(const Node* list_node,
Blink Reformat's avatar
Blink Reformat committed
141
                                    const LayoutListItem* item = nullptr) {
Blink Reformat's avatar
Blink Reformat committed
142
  if (!list_node)
Blink Reformat's avatar
Blink Reformat committed
143
    return nullptr;
144

Blink Reformat's avatar
Blink Reformat committed
145
  const Node* current = item ? item->GetNode() : list_node;
146
  DCHECK(current);
Blink Reformat's avatar
Blink Reformat committed
147
148
  DCHECK(!current->GetDocument().ChildNeedsDistributionRecalc());
  current = LayoutTreeBuilderTraversal::Next(*current, list_node);
Blink Reformat's avatar
Blink Reformat committed
149
150

  while (current) {
Blink Reformat's avatar
Blink Reformat committed
151
    if (IsList(*current)) {
Blink Reformat's avatar
Blink Reformat committed
152
153
      // We've found a nested, independent list: nothing to do here.
      current =
Blink Reformat's avatar
Blink Reformat committed
154
          LayoutTreeBuilderTraversal::NextSkippingChildren(*current, list_node);
Blink Reformat's avatar
Blink Reformat committed
155
156
      continue;
    }
157

Blink Reformat's avatar
Blink Reformat committed
158
159
160
    LayoutObject* layout_object = current->GetLayoutObject();
    if (layout_object && layout_object->IsListItem())
      return ToLayoutListItem(layout_object);
161

162
163
    // FIXME: Can this be optimized to skip the children of the elements without
    // a layoutObject?
Blink Reformat's avatar
Blink Reformat committed
164
    current = LayoutTreeBuilderTraversal::Next(*current, list_node);
Blink Reformat's avatar
Blink Reformat committed
165
  }
166

Blink Reformat's avatar
Blink Reformat committed
167
  return nullptr;
168
169
}

170
// Returns the previous list item with respect to the DOM order.
Blink Reformat's avatar
Blink Reformat committed
171
static LayoutListItem* PreviousListItem(const Node* list_node,
Blink Reformat's avatar
Blink Reformat committed
172
                                        const LayoutListItem* item) {
Blink Reformat's avatar
Blink Reformat committed
173
  Node* current = item->GetNode();
174
  DCHECK(current);
Blink Reformat's avatar
Blink Reformat committed
175
176
177
178
179
180
  DCHECK(!current->GetDocument().ChildNeedsDistributionRecalc());
  for (current = LayoutTreeBuilderTraversal::Previous(*current, list_node);
       current && current != list_node;
       current = LayoutTreeBuilderTraversal::Previous(*current, list_node)) {
    LayoutObject* layout_object = current->GetLayoutObject();
    if (!layout_object || (layout_object && !layout_object->IsListItem()))
Blink Reformat's avatar
Blink Reformat committed
181
      continue;
Blink Reformat's avatar
Blink Reformat committed
182
    Node* other_list = EnclosingList(ToLayoutListItem(layout_object));
Blink Reformat's avatar
Blink Reformat committed
183
    // This item is part of our current list, so it's what we're looking for.
Blink Reformat's avatar
Blink Reformat committed
184
185
    if (list_node == other_list)
      return ToLayoutListItem(layout_object);
Blink Reformat's avatar
Blink Reformat committed
186
187
188
189
    // We found ourself inside another list; lets skip the rest of it.
    // Use nextIncludingPseudo() here because the other list itself may actually
    // be a list item itself. We need to examine it, so we do this to counteract
    // the previousIncludingPseudo() that will be done by the loop.
Blink Reformat's avatar
Blink Reformat committed
190
191
    if (other_list)
      current = LayoutTreeBuilderTraversal::Next(*other_list, list_node);
Blink Reformat's avatar
Blink Reformat committed
192
193
  }
  return nullptr;
194
195
}

Blink Reformat's avatar
Blink Reformat committed
196
197
198
void LayoutListItem::UpdateItemValuesForOrderedList(
    const HTMLOListElement* list_node) {
  DCHECK(list_node);
199

Blink Reformat's avatar
Blink Reformat committed
200
201
202
  for (LayoutListItem* list_item = NextListItem(list_node); list_item;
       list_item = NextListItem(list_node, list_item))
    list_item->UpdateValue();
203
204
}

Blink Reformat's avatar
Blink Reformat committed
205
206
207
unsigned LayoutListItem::ItemCountForOrderedList(
    const HTMLOListElement* list_node) {
  DCHECK(list_node);
208

Blink Reformat's avatar
Blink Reformat committed
209
210
211
212
  unsigned item_count = 0;
  for (LayoutListItem* list_item = NextListItem(list_node); list_item;
       list_item = NextListItem(list_node, list_item))
    item_count++;
213

Blink Reformat's avatar
Blink Reformat committed
214
  return item_count;
215
216
}

Blink Reformat's avatar
Blink Reformat committed
217
218
219
inline int LayoutListItem::CalcValue() const {
  if (has_explicit_value_)
    return explicit_value_;
220

Blink Reformat's avatar
Blink Reformat committed
221
222
  Node* list = EnclosingList(this);
  HTMLOListElement* o_list_element =
Blink Reformat's avatar
Blink Reformat committed
223
      isHTMLOListElement(list) ? toHTMLOListElement(list) : nullptr;
Blink Reformat's avatar
Blink Reformat committed
224
225
226
  int value_step = 1;
  if (o_list_element && o_list_element->IsReversed())
    value_step = -1;
227

Blink Reformat's avatar
Blink Reformat committed
228
229
  // FIXME: This recurses to a possible depth of the length of the list.
  // That's not good -- we need to change this to an iterative algorithm.
Blink Reformat's avatar
Blink Reformat committed
230
231
  if (LayoutListItem* previous_item = PreviousListItem(list, this))
    return SaturatedAddition(previous_item->Value(), value_step);
232

Blink Reformat's avatar
Blink Reformat committed
233
234
  if (o_list_element)
    return o_list_element->start();
235

Blink Reformat's avatar
Blink Reformat committed
236
  return 1;
darin's avatar
darin committed
237
238
}

Blink Reformat's avatar
Blink Reformat committed
239
240
241
void LayoutListItem::UpdateValueNow() const {
  value_ = CalcValue();
  is_value_up_to_date_ = true;
242
243
}

Blink Reformat's avatar
Blink Reformat committed
244
245
bool LayoutListItem::IsEmpty() const {
  return LastChild() == marker_;
246
247
}

Blink Reformat's avatar
Blink Reformat committed
248
static LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr,
Blink Reformat's avatar
Blink Reformat committed
249
                                             LayoutObject* marker) {
Blink Reformat's avatar
Blink Reformat committed
250
251
  LayoutObject* first_child = curr->FirstChild();
  if (!first_child)
Blink Reformat's avatar
Blink Reformat committed
252
    return nullptr;
weinig's avatar
weinig committed
253

Blink Reformat's avatar
Blink Reformat committed
254
255
256
257
  bool in_quirks_mode = curr->GetDocument().InQuirksMode();
  for (LayoutObject* curr_child = first_child; curr_child;
       curr_child = curr_child->NextSibling()) {
    if (curr_child == marker)
Blink Reformat's avatar
Blink Reformat committed
258
      continue;
weinig's avatar
weinig committed
259

260
261
    // Shouldn't add marker into Overflow box, instead, add marker
    // into listitem
Blink Reformat's avatar
Blink Reformat committed
262
    if (curr_child->HasOverflowClip())
263
264
      break;

Blink Reformat's avatar
Blink Reformat committed
265
266
267
    if (curr_child->IsInline() &&
        (!curr_child->IsLayoutInline() ||
         curr->GeneratesLineBoxesForInlineChild(curr_child)))
Blink Reformat's avatar
Blink Reformat committed
268
      return curr;
weinig's avatar
weinig committed
269

Blink Reformat's avatar
Blink Reformat committed
270
    if (curr_child->IsFloating() || curr_child->IsOutOfFlowPositioned())
Blink Reformat's avatar
Blink Reformat committed
271
      continue;
weinig's avatar
weinig committed
272

Blink Reformat's avatar
Blink Reformat committed
273
274
    if (!curr_child->IsLayoutBlockFlow() ||
        (curr_child->IsBox() && ToLayoutBox(curr_child)->IsWritingModeRoot()))
Blink Reformat's avatar
Blink Reformat committed
275
      break;
weinig's avatar
weinig committed
276

Blink Reformat's avatar
Blink Reformat committed
277
278
279
    if (curr->IsListItem() && in_quirks_mode && curr_child->GetNode() &&
        (isHTMLUListElement(*curr_child->GetNode()) ||
         isHTMLOListElement(*curr_child->GetNode())))
Blink Reformat's avatar
Blink Reformat committed
280
      break;
weinig's avatar
weinig committed
281

Blink Reformat's avatar
Blink Reformat committed
282
283
284
285
    LayoutObject* line_box =
        GetParentOfFirstLineBox(ToLayoutBlockFlow(curr_child), marker);
    if (line_box)
      return line_box;
Blink Reformat's avatar
Blink Reformat committed
286
  }
weinig's avatar
weinig committed
287

Blink Reformat's avatar
Blink Reformat committed
288
  return nullptr;
289
290
}

Blink Reformat's avatar
Blink Reformat committed
291
292
293
294
295
296
void LayoutListItem::UpdateValue() {
  if (!has_explicit_value_) {
    is_value_up_to_date_ = false;
    if (marker_)
      marker_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
          LayoutInvalidationReason::kListValueChange);
Blink Reformat's avatar
Blink Reformat committed
297
  }
298
299
}

Blink Reformat's avatar
Blink Reformat committed
300
301
302
303
static LayoutObject* FirstNonMarkerChild(LayoutObject* parent) {
  LayoutObject* result = parent->SlowFirstChild();
  while (result && result->IsListMarker())
    result = result->NextSibling();
Blink Reformat's avatar
Blink Reformat committed
304
  return result;
305
306
}

Blink Reformat's avatar
Blink Reformat committed
307
308
bool LayoutListItem::UpdateMarkerLocation() {
  DCHECK(marker_);
Blink Reformat's avatar
Blink Reformat committed
309

Blink Reformat's avatar
Blink Reformat committed
310
  LayoutObject* marker_parent = marker_->Parent();
311
312
  // list-style-position:inside makes the ::marker pseudo an ordinary
  // position:static element that should be attached to LayoutListItem block.
Blink Reformat's avatar
Blink Reformat committed
313
314
315
  LayoutObject* line_box_parent =
      marker_->IsInside() ? this : GetParentOfFirstLineBox(this, marker_);
  if (!line_box_parent) {
Blink Reformat's avatar
Blink Reformat committed
316
317
318
    // If the marker is currently contained inside an anonymous box, then we
    // are the only item in that anonymous box (since no line box parent was
    // found). It's ok to just leave the marker where it is in this case.
Blink Reformat's avatar
Blink Reformat committed
319
320
    if (marker_parent && marker_parent->IsAnonymousBlock())
      line_box_parent = marker_parent;
Blink Reformat's avatar
Blink Reformat committed
321
    else
Blink Reformat's avatar
Blink Reformat committed
322
      line_box_parent = this;
Blink Reformat's avatar
Blink Reformat committed
323
324
  }

Blink Reformat's avatar
Blink Reformat committed
325
326
327
  if (marker_parent != line_box_parent) {
    marker_->Remove();
    line_box_parent->AddChild(marker_, FirstNonMarkerChild(line_box_parent));
328
329
330
331
    // TODO(rhogan): lineBoxParent and markerParent may be deleted by addChild,
    // so they are not safe to reference here.
    // Once we have a safe way of referencing them delete markerParent if it is
    // an empty anonymous block.
Blink Reformat's avatar
Blink Reformat committed
332
    marker_->UpdateMarginsAndContent();
Blink Reformat's avatar
Blink Reformat committed
333
334
335
336
    return true;
  }

  return false;
337
338
}

Blink Reformat's avatar
Blink Reformat committed
339
340
341
void LayoutListItem::AddOverflowFromChildren() {
  LayoutBlockFlow::AddOverflowFromChildren();
  PositionListMarker();
342
343
}

Blink Reformat's avatar
Blink Reformat committed
344
345
346
347
348
349
350
351
352
void LayoutListItem::PositionListMarker() {
  if (marker_ && marker_->Parent() && marker_->Parent()->IsBox() &&
      !marker_->IsInside() && marker_->InlineBoxWrapper()) {
    LayoutUnit marker_old_logical_left = marker_->LogicalLeft();
    LayoutUnit block_offset;
    LayoutUnit line_offset;
    for (LayoutBox* o = marker_->ParentBox(); o != this; o = o->ParentBox()) {
      block_offset += o->LogicalTop();
      line_offset += o->LogicalLeft();
Blink Reformat's avatar
Blink Reformat committed
353
    }
mitz@apple.com's avatar
mitz@apple.com committed
354

Blink Reformat's avatar
Blink Reformat committed
355
356
357
358
    bool adjust_overflow = false;
    LayoutUnit marker_logical_left;
    RootInlineBox& root = marker_->InlineBoxWrapper()->Root();
    bool hit_self_painting_layer = false;
Blink Reformat's avatar
Blink Reformat committed
359

Blink Reformat's avatar
Blink Reformat committed
360
361
    LayoutUnit line_top = root.LineTop();
    LayoutUnit line_bottom = root.LineBottom();
Blink Reformat's avatar
Blink Reformat committed
362
363
364
365

    // TODO(jchaffraix): Propagating the overflow to the line boxes seems
    // pretty wrong (https://crbug.com/554160).
    // FIXME: Need to account for relative positioning in the layout overflow.
Blink Reformat's avatar
Blink Reformat committed
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
    if (Style()->IsLeftToRightDirection()) {
      marker_logical_left = marker_->LineOffset() - line_offset -
                            PaddingStart() - BorderStart() +
                            marker_->MarginStart();
      marker_->InlineBoxWrapper()->MoveInInlineDirection(
          marker_logical_left - marker_old_logical_left);
      for (InlineFlowBox* box = marker_->InlineBoxWrapper()->Parent(); box;
           box = box->Parent()) {
        LayoutRect new_logical_visual_overflow_rect =
            box->LogicalVisualOverflowRect(line_top, line_bottom);
        LayoutRect new_logical_layout_overflow_rect =
            box->LogicalLayoutOverflowRect(line_top, line_bottom);
        if (marker_logical_left < new_logical_visual_overflow_rect.X() &&
            !hit_self_painting_layer) {
          new_logical_visual_overflow_rect.SetWidth(
              new_logical_visual_overflow_rect.MaxX() - marker_logical_left);
          new_logical_visual_overflow_rect.SetX(marker_logical_left);
Blink Reformat's avatar
Blink Reformat committed
383
          if (box == root)
Blink Reformat's avatar
Blink Reformat committed
384
            adjust_overflow = true;
Blink Reformat's avatar
Blink Reformat committed
385
        }
Blink Reformat's avatar
Blink Reformat committed
386
387
388
389
        if (marker_logical_left < new_logical_layout_overflow_rect.X()) {
          new_logical_layout_overflow_rect.SetWidth(
              new_logical_layout_overflow_rect.MaxX() - marker_logical_left);
          new_logical_layout_overflow_rect.SetX(marker_logical_left);
Blink Reformat's avatar
Blink Reformat committed
390
          if (box == root)
Blink Reformat's avatar
Blink Reformat committed
391
            adjust_overflow = true;
Blink Reformat's avatar
Blink Reformat committed
392
        }
Blink Reformat's avatar
Blink Reformat committed
393
394
395
396
397
        box->OverrideOverflowFromLogicalRects(new_logical_layout_overflow_rect,
                                              new_logical_visual_overflow_rect,
                                              line_top, line_bottom);
        if (box->BoxModelObject().HasSelfPaintingLayer())
          hit_self_painting_layer = true;
Blink Reformat's avatar
Blink Reformat committed
398
399
      }
    } else {
Blink Reformat's avatar
Blink Reformat committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
      marker_logical_left = marker_->LineOffset() - line_offset +
                            PaddingStart() + BorderStart() +
                            marker_->MarginEnd();
      marker_->InlineBoxWrapper()->MoveInInlineDirection(
          marker_logical_left - marker_old_logical_left);
      for (InlineFlowBox* box = marker_->InlineBoxWrapper()->Parent(); box;
           box = box->Parent()) {
        LayoutRect new_logical_visual_overflow_rect =
            box->LogicalVisualOverflowRect(line_top, line_bottom);
        LayoutRect new_logical_layout_overflow_rect =
            box->LogicalLayoutOverflowRect(line_top, line_bottom);
        if (marker_logical_left + marker_->LogicalWidth() >
                new_logical_visual_overflow_rect.MaxX() &&
            !hit_self_painting_layer) {
          new_logical_visual_overflow_rect.SetWidth(
              marker_logical_left + marker_->LogicalWidth() -
              new_logical_visual_overflow_rect.X());
Blink Reformat's avatar
Blink Reformat committed
417
          if (box == root)
Blink Reformat's avatar
Blink Reformat committed
418
            adjust_overflow = true;
mitz@apple.com's avatar
mitz@apple.com committed
419
        }
Blink Reformat's avatar
Blink Reformat committed
420
421
422
423
424
        if (marker_logical_left + marker_->LogicalWidth() >
            new_logical_layout_overflow_rect.MaxX()) {
          new_logical_layout_overflow_rect.SetWidth(
              marker_logical_left + marker_->LogicalWidth() -
              new_logical_layout_overflow_rect.X());
Blink Reformat's avatar
Blink Reformat committed
425
          if (box == root)
Blink Reformat's avatar
Blink Reformat committed
426
            adjust_overflow = true;
Blink Reformat's avatar
Blink Reformat committed
427
        }
Blink Reformat's avatar
Blink Reformat committed
428
429
430
        box->OverrideOverflowFromLogicalRects(new_logical_layout_overflow_rect,
                                              new_logical_visual_overflow_rect,
                                              line_top, line_bottom);
mitz@apple.com's avatar
mitz@apple.com committed
431

Blink Reformat's avatar
Blink Reformat committed
432
433
        if (box->BoxModelObject().HasSelfPaintingLayer())
          hit_self_painting_layer = true;
Blink Reformat's avatar
Blink Reformat committed
434
435
436
      }
    }

Blink Reformat's avatar
Blink Reformat committed
437
438
439
    if (adjust_overflow) {
      LayoutRect marker_rect(
          LayoutPoint(marker_logical_left + line_offset, block_offset),
440
          marker_->Size());
Blink Reformat's avatar
Blink Reformat committed
441
442
443
444
445
      if (!Style()->IsHorizontalWritingMode())
        marker_rect = marker_rect.TransposedRect();
      LayoutBox* o = marker_;
      bool propagate_visual_overflow = true;
      bool propagate_layout_overflow = true;
Blink Reformat's avatar
Blink Reformat committed
446
      do {
Blink Reformat's avatar
Blink Reformat committed
447
448
449
450
451
452
        o = o->ParentBox();
        if (o->IsLayoutBlock()) {
          if (propagate_visual_overflow)
            ToLayoutBlock(o)->AddContentsVisualOverflow(marker_rect);
          if (propagate_layout_overflow)
            ToLayoutBlock(o)->AddLayoutOverflow(marker_rect);
Blink Reformat's avatar
Blink Reformat committed
453
        }
Blink Reformat's avatar
Blink Reformat committed
454
455
456
        if (o->HasOverflowClip()) {
          propagate_layout_overflow = false;
          propagate_visual_overflow = false;
mitz@apple.com's avatar
mitz@apple.com committed
457
        }
Blink Reformat's avatar
Blink Reformat committed
458
459
460
461
462
        if (o->HasSelfPaintingLayer())
          propagate_visual_overflow = false;
        marker_rect.MoveBy(-o->Location());
      } while (o != this && propagate_visual_overflow &&
               propagate_layout_overflow);
463
    }
Blink Reformat's avatar
Blink Reformat committed
464
  }
465
466
}

Blink Reformat's avatar
Blink Reformat committed
467
468
469
void LayoutListItem::Paint(const PaintInfo& paint_info,
                           const LayoutPoint& paint_offset) const {
  ListItemPainter(*this).Paint(paint_info, paint_offset);
470
471
}

Blink Reformat's avatar
Blink Reformat committed
472
473
474
475
const String& LayoutListItem::MarkerText() const {
  if (marker_)
    return marker_->GetText();
  return g_null_atom.GetString();
darin's avatar
darin committed
476
477
}

Blink Reformat's avatar
Blink Reformat committed
478
479
480
481
482
483
484
void LayoutListItem::ExplicitValueChanged() {
  if (marker_)
    marker_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
        LayoutInvalidationReason::kListValueChange);
  Node* list_node = EnclosingList(this);
  for (LayoutListItem* item = this; item; item = NextListItem(list_node, item))
    item->UpdateValue();
darin's avatar
darin committed
485
486
}

Blink Reformat's avatar
Blink Reformat committed
487
488
void LayoutListItem::SetExplicitValue(int value) {
  DCHECK(GetNode());
489

Blink Reformat's avatar
Blink Reformat committed
490
  if (has_explicit_value_ && explicit_value_ == value)
Blink Reformat's avatar
Blink Reformat committed
491
    return;
Blink Reformat's avatar
Blink Reformat committed
492
493
494
495
  explicit_value_ = value;
  value_ = value;
  has_explicit_value_ = true;
  ExplicitValueChanged();
darin's avatar
darin committed
496
497
}

Blink Reformat's avatar
Blink Reformat committed
498
499
void LayoutListItem::ClearExplicitValue() {
  DCHECK(GetNode());
500

Blink Reformat's avatar
Blink Reformat committed
501
  if (!has_explicit_value_)
Blink Reformat's avatar
Blink Reformat committed
502
    return;
Blink Reformat's avatar
Blink Reformat committed
503
504
505
  has_explicit_value_ = false;
  is_value_up_to_date_ = false;
  ExplicitValueChanged();
506
507
}

Blink Reformat's avatar
Blink Reformat committed
508
509
void LayoutListItem::SetNotInList(bool not_in_list) {
  not_in_list_ = not_in_list;
510
511
}

Blink Reformat's avatar
Blink Reformat committed
512
static LayoutListItem* PreviousOrNextItem(bool is_list_reversed,
Blink Reformat's avatar
Blink Reformat committed
513
514
                                          Node* list,
                                          LayoutListItem* item) {
Blink Reformat's avatar
Blink Reformat committed
515
516
  return is_list_reversed ? PreviousListItem(list, item)
                          : NextListItem(list, item);
517
518
}

Blink Reformat's avatar
Blink Reformat committed
519
void LayoutListItem::UpdateListMarkerNumbers() {
Blink Reformat's avatar
Blink Reformat committed
520
521
  // If distribution recalc is needed, updateListMarkerNumber will be re-invoked
  // after distribution is calculated.
Blink Reformat's avatar
Blink Reformat committed
522
  if (GetNode()->GetDocument().ChildNeedsDistributionRecalc())
Blink Reformat's avatar
Blink Reformat committed
523
524
    return;

Blink Reformat's avatar
Blink Reformat committed
525
  Node* list_node = EnclosingList(this);
526
  CHECK(list_node);
Blink Reformat's avatar
Blink Reformat committed
527

Blink Reformat's avatar
Blink Reformat committed
528
529
530
531
532
533
  bool is_list_reversed = false;
  HTMLOListElement* o_list_element =
      isHTMLOListElement(list_node) ? toHTMLOListElement(list_node) : 0;
  if (o_list_element) {
    o_list_element->ItemCountChanged();
    is_list_reversed = o_list_element->IsReversed();
Blink Reformat's avatar
Blink Reformat committed
534
535
  }

536
537
  // FIXME: The n^2 protection below doesn't help if the elements were inserted
  // after the the list had already been displayed.
Blink Reformat's avatar
Blink Reformat committed
538

539
540
  // Avoid an O(n^2) walk over the children below when they're all known to be
  // attaching.
Blink Reformat's avatar
Blink Reformat committed
541
  if (list_node->NeedsAttach())
Blink Reformat's avatar
Blink Reformat committed
542
543
544
    return;

  for (LayoutListItem* item =
Blink Reformat's avatar
Blink Reformat committed
545
546
547
           PreviousOrNextItem(is_list_reversed, list_node, this);
       item; item = PreviousOrNextItem(is_list_reversed, list_node, item)) {
    if (!item->is_value_up_to_date_) {
Blink Reformat's avatar
Blink Reformat committed
548
549
550
551
552
      // If an item has been marked for update before, we can safely
      // assume that all the following ones have too.
      // This gives us the opportunity to stop here and avoid
      // marking the same nodes again.
      break;
553
    }
Blink Reformat's avatar
Blink Reformat committed
554
    item->UpdateValue();
Blink Reformat's avatar
Blink Reformat committed
555
  }
556
557
}

Blink Reformat's avatar
Blink Reformat committed
558
}  // namespace blink