1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
7 * Copyright (C) 2009 Google Inc. All rights reserved.
8 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 *
25 */
26
27 #include "config.h"
28 #include "core/rendering/RenderObject.h"
29
30 #include "core/HTMLNames.h"
31 #include "core/accessibility/AXObjectCache.h"
32 #include "core/css/resolver/StyleResolver.h"
33 #include "core/dom/ElementTraversal.h"
34 #include "core/dom/StyleEngine.h"
35 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/editing/EditingBoundary.h"
37 #include "core/editing/FrameSelection.h"
38 #include "core/editing/htmlediting.h"
39 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
40 #include "core/fetch/ResourceLoader.h"
41 #include "core/frame/EventHandlerRegistry.h"
42 #include "core/frame/FrameView.h"
43 #include "core/frame/LocalFrame.h"
44 #include "core/frame/Settings.h"
45 #include "core/frame/UseCounter.h"
46 #include "core/html/HTMLAnchorElement.h"
47 #include "core/html/HTMLElement.h"
48 #include "core/html/HTMLHtmlElement.h"
49 #include "core/html/HTMLTableCellElement.h"
50 #include "core/html/HTMLTableElement.h"
51 #include "core/page/AutoscrollController.h"
52 #include "core/page/EventHandler.h"
53 #include "core/page/Page.h"
54 #include "core/paint/ObjectPainter.h"
55 #include "core/rendering/FlowThreadController.h"
56 #include "core/rendering/HitTestResult.h"
57 #include "core/rendering/RenderCounter.h"
58 #include "core/rendering/RenderDeprecatedFlexibleBox.h"
59 #include "core/rendering/RenderFlexibleBox.h"
60 #include "core/rendering/RenderFlowThread.h"
61 #include "core/rendering/RenderGeometryMap.h"
62 #include "core/rendering/RenderGrid.h"
63 #include "core/rendering/RenderImage.h"
64 #include "core/rendering/RenderImageResourceStyleImage.h"
65 #include "core/rendering/RenderInline.h"
66 #include "core/rendering/RenderLayer.h"
67 #include "core/rendering/RenderListItem.h"
68 #include "core/rendering/RenderMarquee.h"
69 #include "core/rendering/RenderObjectInlines.h"
70 #include "core/rendering/RenderPart.h"
71 #include "core/rendering/RenderScrollbarPart.h"
72 #include "core/rendering/RenderTableCaption.h"
73 #include "core/rendering/RenderTableCell.h"
74 #include "core/rendering/RenderTableCol.h"
75 #include "core/rendering/RenderTableRow.h"
76 #include "core/rendering/RenderTheme.h"
77 #include "core/rendering/RenderView.h"
78 #include "core/rendering/compositing/CompositedLayerMapping.h"
79 #include "core/rendering/compositing/RenderLayerCompositor.h"
80 #include "core/rendering/style/ContentData.h"
81 #include "core/rendering/style/ShadowList.h"
82 #include "platform/JSONValues.h"
83 #include "platform/Partitions.h"
84 #include "platform/RuntimeEnabledFeatures.h"
85 #include "platform/TraceEvent.h"
86 #include "platform/TracedValue.h"
87 #include "platform/geometry/TransformState.h"
88 #include "platform/graphics/FirstPaintInvalidationTracking.h"
89 #include "platform/graphics/GraphicsContext.h"
90 #include "wtf/RefCountedLeakCounter.h"
91 #include "wtf/text/StringBuilder.h"
92 #include "wtf/text/WTFString.h"
93 #include <algorithm>
94 #ifndef NDEBUG
95 #include <stdio.h>
96 #endif
97
98 namespace blink {
99
100 namespace {
101
102 static bool gModifyRenderTreeStructureAnyState = false;
103
104 typedef WillBeHeapHashSet<RawPtrWillBeWeakMember<const RenderObject> > RenderObjectWeakSet;
renderObjectNeverHadPaintInvalidationSet()105 RenderObjectWeakSet& renderObjectNeverHadPaintInvalidationSet()
106 {
107 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<RenderObjectWeakSet>, set, (adoptPtrWillBeNoop(new RenderObjectWeakSet())));
108 return *set;
109 }
110
111 } // namespace
112
113 using namespace HTMLNames;
114
115 #if ENABLE(ASSERT)
116
SetLayoutNeededForbiddenScope(RenderObject & renderObject)117 RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject& renderObject)
118 : m_renderObject(renderObject)
119 , m_preexistingForbidden(m_renderObject.isSetNeedsLayoutForbidden())
120 {
121 m_renderObject.setNeedsLayoutIsForbidden(true);
122 }
123
~SetLayoutNeededForbiddenScope()124 RenderObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope()
125 {
126 m_renderObject.setNeedsLayoutIsForbidden(m_preexistingForbidden);
127 }
128 #endif
129
130 struct SameSizeAsRenderObject {
~SameSizeAsRenderObjectblink::SameSizeAsRenderObject131 virtual ~SameSizeAsRenderObject() { } // Allocate vtable pointer.
132 void* pointers[5];
133 #if ENABLE(ASSERT)
134 unsigned m_debugBitfields : 2;
135 #if ENABLE(OILPAN)
136 unsigned m_oilpanBitfields : 1;
137 #endif
138 #endif
139 unsigned m_bitfields;
140 unsigned m_bitfields2;
141 LayoutRect rect; // Stores the previous paint invalidation rect.
142 LayoutPoint position; // Stores the previous position from the paint invalidation container.
143 };
144
145 COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
146
147 bool RenderObject::s_affectsParentBlock = false;
148
149 #if !ENABLE(OILPAN)
operator new(size_t sz)150 void* RenderObject::operator new(size_t sz)
151 {
152 ASSERT(isMainThread());
153 return partitionAlloc(Partitions::getRenderingPartition(), sz);
154 }
155
operator delete(void * ptr)156 void RenderObject::operator delete(void* ptr)
157 {
158 ASSERT(isMainThread());
159 partitionFree(ptr);
160 }
161 #endif
162
createObject(Element * element,RenderStyle * style)163 RenderObject* RenderObject::createObject(Element* element, RenderStyle* style)
164 {
165 ASSERT(isAllowedToModifyRenderTreeStructure(element->document()));
166
167 // Minimal support for content properties replacing an entire element.
168 // Works only if we have exactly one piece of content and it's a URL.
169 // Otherwise acts as if we didn't support this feature.
170 const ContentData* contentData = style->contentData();
171 if (contentData && !contentData->next() && contentData->isImage() && !element->isPseudoElement()) {
172 RenderImage* image = new RenderImage(element);
173 // RenderImageResourceStyleImage requires a style being present on the image but we don't want to
174 // trigger a style change now as the node is not fully attached. Moving this code to style change
175 // doesn't make sense as it should be run once at renderer creation.
176 image->setStyleInternal(style);
177 if (const StyleImage* styleImage = toImageContentData(contentData)->image()) {
178 image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage)));
179 image->setIsGeneratedContent();
180 } else
181 image->setImageResource(RenderImageResource::create());
182 image->setStyleInternal(nullptr);
183 return image;
184 }
185
186 switch (style->display()) {
187 case NONE:
188 return 0;
189 case INLINE:
190 return new RenderInline(element);
191 case BLOCK:
192 case INLINE_BLOCK:
193 return new RenderBlockFlow(element);
194 case LIST_ITEM:
195 return new RenderListItem(element);
196 case TABLE:
197 case INLINE_TABLE:
198 return new RenderTable(element);
199 case TABLE_ROW_GROUP:
200 case TABLE_HEADER_GROUP:
201 case TABLE_FOOTER_GROUP:
202 return new RenderTableSection(element);
203 case TABLE_ROW:
204 return new RenderTableRow(element);
205 case TABLE_COLUMN_GROUP:
206 case TABLE_COLUMN:
207 return new RenderTableCol(element);
208 case TABLE_CELL:
209 return new RenderTableCell(element);
210 case TABLE_CAPTION:
211 return new RenderTableCaption(element);
212 case BOX:
213 case INLINE_BOX:
214 return new RenderDeprecatedFlexibleBox(*element);
215 case FLEX:
216 case INLINE_FLEX:
217 return new RenderFlexibleBox(element);
218 case GRID:
219 case INLINE_GRID:
220 return new RenderGrid(element);
221 }
222
223 return 0;
224 }
225
226 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("RenderObject"));
227 unsigned RenderObject::s_instanceCount = 0;
228
RenderObject(Node * node)229 RenderObject::RenderObject(Node* node)
230 : ImageResourceClient()
231 , m_style(nullptr)
232 , m_node(node)
233 , m_parent(nullptr)
234 , m_previous(nullptr)
235 , m_next(nullptr)
236 #if ENABLE(ASSERT)
237 , m_hasAXObject(false)
238 , m_setNeedsLayoutForbidden(false)
239 #if ENABLE(OILPAN)
240 , m_didCallDestroy(false)
241 #endif
242 #endif
243 , m_bitfields(node)
244 {
245 if (firstPaintInvalidationTrackingEnabled())
246 renderObjectNeverHadPaintInvalidationSet().add(this);
247
248 #ifndef NDEBUG
249 renderObjectCounter.increment();
250 #endif
251 ++s_instanceCount;
252 }
253
~RenderObject()254 RenderObject::~RenderObject()
255 {
256 if (firstPaintInvalidationTrackingEnabled())
257 renderObjectNeverHadPaintInvalidationSet().remove(this);
258
259 ASSERT(!m_hasAXObject);
260 #if ENABLE(OILPAN)
261 ASSERT(m_didCallDestroy);
262 #endif
263 #ifndef NDEBUG
264 renderObjectCounter.decrement();
265 #endif
266 --s_instanceCount;
267 }
268
trace(Visitor * visitor)269 void RenderObject::trace(Visitor* visitor)
270 {
271 visitor->trace(m_node);
272 visitor->trace(m_parent);
273 visitor->trace(m_previous);
274 visitor->trace(m_next);
275 }
276
debugName() const277 String RenderObject::debugName() const
278 {
279 StringBuilder name;
280 name.append(renderName());
281
282 if (Node* node = this->node()) {
283 name.append(' ');
284 name.append(node->debugName());
285 }
286
287 return name.toString();
288 }
289
isDescendantOf(const RenderObject * obj) const290 bool RenderObject::isDescendantOf(const RenderObject* obj) const
291 {
292 for (const RenderObject* r = this; r; r = r->m_parent) {
293 if (r == obj)
294 return true;
295 }
296 return false;
297 }
298
isHR() const299 bool RenderObject::isHR() const
300 {
301 return isHTMLHRElement(node());
302 }
303
isLegend() const304 bool RenderObject::isLegend() const
305 {
306 return isHTMLLegendElement(node());
307 }
308
setFlowThreadStateIncludingDescendants(FlowThreadState state)309 void RenderObject::setFlowThreadStateIncludingDescendants(FlowThreadState state)
310 {
311 for (RenderObject *object = this; object; object = object->nextInPreOrder(this)) {
312 // If object is a fragmentation context it already updated the descendants flag accordingly.
313 if (object->isRenderFlowThread())
314 continue;
315 ASSERT(state != object->flowThreadState());
316 object->setFlowThreadState(state);
317 }
318 }
319
requiresAnonymousTableWrappers(const RenderObject * newChild) const320 bool RenderObject::requiresAnonymousTableWrappers(const RenderObject* newChild) const
321 {
322 // Check should agree with:
323 // CSS 2.1 Tables: 17.2.1 Anonymous table objects
324 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
325 if (newChild->isRenderTableCol()) {
326 const RenderTableCol* newTableColumn = toRenderTableCol(newChild);
327 bool isColumnInColumnGroup = newTableColumn->isTableColumn() && isRenderTableCol();
328 return !isTable() && !isColumnInColumnGroup;
329 } else if (newChild->isTableCaption())
330 return !isTable();
331 else if (newChild->isTableSection())
332 return !isTable();
333 else if (newChild->isTableRow())
334 return !isTableSection();
335 else if (newChild->isTableCell())
336 return !isTableRow();
337 return false;
338 }
339
addChild(RenderObject * newChild,RenderObject * beforeChild)340 void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
341 {
342 ASSERT(isAllowedToModifyRenderTreeStructure(document()));
343
344 RenderObjectChildList* children = virtualChildren();
345 ASSERT(children);
346 if (!children)
347 return;
348
349 if (requiresAnonymousTableWrappers(newChild)) {
350 // Generate an anonymous table or reuse existing one from previous child
351 // Per: 17.2.1 Anonymous table objects 3. Generate missing parents
352 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
353 RenderTable* table;
354 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : children->lastChild();
355 if (afterChild && afterChild->isAnonymous() && afterChild->isTable() && !afterChild->isBeforeContent())
356 table = toRenderTable(afterChild);
357 else {
358 table = RenderTable::createAnonymousWithParentRenderer(this);
359 addChild(table, beforeChild);
360 }
361 table->addChild(newChild);
362 } else
363 children->insertChildNode(this, newChild, beforeChild);
364
365 if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE)
366 toRenderText(newChild)->transformText();
367
368 // SVG creates renderers for <g display="none">, as SVG requires children of hidden
369 // <g>s to have renderers - at least that's how our implementation works. Consider:
370 // <g display="none"><foreignObject><body style="position: relative">FOO...
371 // - layerTypeRequired() would return true for the <body>, creating a new RenderLayer
372 // - when the document is painted, both layers are painted. The <body> layer doesn't
373 // know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't.
374 // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree
375 // and stop creating layers at all for these cases - they're not used anyways.
376 if (newChild->hasLayer() && !layerCreationAllowedForSubtree())
377 toRenderLayerModelObject(newChild)->layer()->removeOnlyThisLayer();
378 }
379
removeChild(RenderObject * oldChild)380 void RenderObject::removeChild(RenderObject* oldChild)
381 {
382 ASSERT(isAllowedToModifyRenderTreeStructure(document()));
383
384 RenderObjectChildList* children = virtualChildren();
385 ASSERT(children);
386 if (!children)
387 return;
388
389 children->removeChildNode(this, oldChild);
390 }
391
nextInPreOrder() const392 RenderObject* RenderObject::nextInPreOrder() const
393 {
394 if (RenderObject* o = slowFirstChild())
395 return o;
396
397 return nextInPreOrderAfterChildren();
398 }
399
nextInPreOrderAfterChildren() const400 RenderObject* RenderObject::nextInPreOrderAfterChildren() const
401 {
402 RenderObject* o = nextSibling();
403 if (!o) {
404 o = parent();
405 while (o && !o->nextSibling())
406 o = o->parent();
407 if (o)
408 o = o->nextSibling();
409 }
410
411 return o;
412 }
413
nextInPreOrder(const RenderObject * stayWithin) const414 RenderObject* RenderObject::nextInPreOrder(const RenderObject* stayWithin) const
415 {
416 if (RenderObject* o = slowFirstChild())
417 return o;
418
419 return nextInPreOrderAfterChildren(stayWithin);
420 }
421
nextInPreOrderAfterChildren(const RenderObject * stayWithin) const422 RenderObject* RenderObject::nextInPreOrderAfterChildren(const RenderObject* stayWithin) const
423 {
424 if (this == stayWithin)
425 return 0;
426
427 const RenderObject* current = this;
428 RenderObject* next = current->nextSibling();
429 for (; !next; next = current->nextSibling()) {
430 current = current->parent();
431 if (!current || current == stayWithin)
432 return 0;
433 }
434 return next;
435 }
436
previousInPreOrder() const437 RenderObject* RenderObject::previousInPreOrder() const
438 {
439 if (RenderObject* o = previousSibling()) {
440 while (RenderObject* lastChild = o->slowLastChild())
441 o = lastChild;
442 return o;
443 }
444
445 return parent();
446 }
447
previousInPreOrder(const RenderObject * stayWithin) const448 RenderObject* RenderObject::previousInPreOrder(const RenderObject* stayWithin) const
449 {
450 if (this == stayWithin)
451 return 0;
452
453 return previousInPreOrder();
454 }
455
childAt(unsigned index) const456 RenderObject* RenderObject::childAt(unsigned index) const
457 {
458 RenderObject* child = slowFirstChild();
459 for (unsigned i = 0; child && i < index; i++)
460 child = child->nextSibling();
461 return child;
462 }
463
lastLeafChild() const464 RenderObject* RenderObject::lastLeafChild() const
465 {
466 RenderObject* r = slowLastChild();
467 while (r) {
468 RenderObject* n = 0;
469 n = r->slowLastChild();
470 if (!n)
471 break;
472 r = n;
473 }
474 return r;
475 }
476
addLayers(RenderObject * obj,RenderLayer * parentLayer,RenderObject * & newObject,RenderLayer * & beforeChild)477 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
478 RenderLayer*& beforeChild)
479 {
480 if (obj->hasLayer()) {
481 if (!beforeChild && newObject) {
482 // We need to figure out the layer that follows newObject. We only do
483 // this the first time we find a child layer, and then we update the
484 // pointer values for newObject and beforeChild used by everyone else.
485 beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
486 newObject = 0;
487 }
488 parentLayer->addChild(toRenderLayerModelObject(obj)->layer(), beforeChild);
489 return;
490 }
491
492 for (RenderObject* curr = obj->slowFirstChild(); curr; curr = curr->nextSibling())
493 addLayers(curr, parentLayer, newObject, beforeChild);
494 }
495
addLayers(RenderLayer * parentLayer)496 void RenderObject::addLayers(RenderLayer* parentLayer)
497 {
498 if (!parentLayer)
499 return;
500
501 RenderObject* object = this;
502 RenderLayer* beforeChild = 0;
503 blink::addLayers(this, parentLayer, object, beforeChild);
504 }
505
removeLayers(RenderLayer * parentLayer)506 void RenderObject::removeLayers(RenderLayer* parentLayer)
507 {
508 if (!parentLayer)
509 return;
510
511 if (hasLayer()) {
512 parentLayer->removeChild(toRenderLayerModelObject(this)->layer());
513 return;
514 }
515
516 for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
517 curr->removeLayers(parentLayer);
518 }
519
moveLayers(RenderLayer * oldParent,RenderLayer * newParent)520 void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
521 {
522 if (!newParent)
523 return;
524
525 if (hasLayer()) {
526 RenderLayer* layer = toRenderLayerModelObject(this)->layer();
527 ASSERT(oldParent == layer->parent());
528 if (oldParent)
529 oldParent->removeChild(layer);
530 newParent->addChild(layer);
531 return;
532 }
533
534 for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
535 curr->moveLayers(oldParent, newParent);
536 }
537
findNextLayer(RenderLayer * parentLayer,RenderObject * startPoint,bool checkParent)538 RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
539 bool checkParent)
540 {
541 // Error check the parent layer passed in. If it's null, we can't find anything.
542 if (!parentLayer)
543 return 0;
544
545 // Step 1: If our layer is a child of the desired parent, then return our layer.
546 RenderLayer* ourLayer = hasLayer() ? toRenderLayerModelObject(this)->layer() : 0;
547 if (ourLayer && ourLayer->parent() == parentLayer)
548 return ourLayer;
549
550 // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
551 // into our siblings trying to find the next layer whose parent is the desired parent.
552 if (!ourLayer || ourLayer == parentLayer) {
553 for (RenderObject* curr = startPoint ? startPoint->nextSibling() : slowFirstChild();
554 curr; curr = curr->nextSibling()) {
555 RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
556 if (nextLayer)
557 return nextLayer;
558 }
559 }
560
561 // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
562 // find anything.
563 if (parentLayer == ourLayer)
564 return 0;
565
566 // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
567 // follow us to see if we can locate a layer.
568 if (checkParent && parent())
569 return parent()->findNextLayer(parentLayer, this, true);
570
571 return 0;
572 }
573
enclosingLayer() const574 RenderLayer* RenderObject::enclosingLayer() const
575 {
576 for (const RenderObject* current = this; current; current = current->parent()) {
577 if (current->hasLayer())
578 return toRenderLayerModelObject(current)->layer();
579 }
580 // FIXME: we should get rid of detached render subtrees, at which point this code should
581 // not be reached. crbug.com/411429
582 return 0;
583 }
584
scrollRectToVisible(const LayoutRect & rect,const ScrollAlignment & alignX,const ScrollAlignment & alignY)585 bool RenderObject::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
586 {
587 RenderBox* enclosingBox = this->enclosingBox();
588 if (!enclosingBox)
589 return false;
590
591 enclosingBox->scrollRectToVisible(rect, alignX, alignY);
592 return true;
593 }
594
enclosingBox() const595 RenderBox* RenderObject::enclosingBox() const
596 {
597 RenderObject* curr = const_cast<RenderObject*>(this);
598 while (curr) {
599 if (curr->isBox())
600 return toRenderBox(curr);
601 curr = curr->parent();
602 }
603
604 ASSERT_NOT_REACHED();
605 return 0;
606 }
607
enclosingBoxModelObject() const608 RenderBoxModelObject* RenderObject::enclosingBoxModelObject() const
609 {
610 RenderObject* curr = const_cast<RenderObject*>(this);
611 while (curr) {
612 if (curr->isBoxModelObject())
613 return toRenderBoxModelObject(curr);
614 curr = curr->parent();
615 }
616
617 ASSERT_NOT_REACHED();
618 return 0;
619 }
620
enclosingScrollableBox() const621 RenderBox* RenderObject::enclosingScrollableBox() const
622 {
623 for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
624 if (!ancestor->isBox())
625 continue;
626
627 RenderBox* ancestorBox = toRenderBox(ancestor);
628 if (ancestorBox->canBeScrolledAndHasScrollableArea())
629 return ancestorBox;
630 }
631
632 return 0;
633 }
634
locateFlowThreadContainingBlock() const635 RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const
636 {
637 ASSERT(flowThreadState() != NotInsideFlowThread);
638
639 // See if we have the thread cached because we're in the middle of layout.
640 RenderFlowThread* flowThread = view()->flowThreadController()->currentRenderFlowThread();
641 if (flowThread)
642 return flowThread;
643
644 // Not in the middle of layout so have to find the thread the slow way.
645 RenderObject* curr = const_cast<RenderObject*>(this);
646 while (curr) {
647 if (curr->isRenderFlowThread())
648 return toRenderFlowThread(curr);
649 curr = curr->containingBlock();
650 }
651 return 0;
652 }
653
skipInvalidationWhenLaidOutChildren() const654 bool RenderObject::skipInvalidationWhenLaidOutChildren() const
655 {
656 if (!neededLayoutBecauseOfChildren())
657 return false;
658
659 // SVG renderers need to be invalidated when their children are laid out.
660 // RenderBlocks with line boxes are responsible to invalidate them so we can't ignore them.
661 if (isSVG() || (isRenderBlockFlow() && toRenderBlockFlow(this)->firstLineBox()))
662 return false;
663
664 return rendererHasNoBoxEffect();
665 }
666
firstLineBlock() const667 RenderBlock* RenderObject::firstLineBlock() const
668 {
669 return 0;
670 }
671
objectIsRelayoutBoundary(const RenderObject * object)672 static inline bool objectIsRelayoutBoundary(const RenderObject* object)
673 {
674 // FIXME: In future it may be possible to broaden these conditions in order to improve performance.
675 if (object->isTextControl())
676 return true;
677
678 if (object->isSVGRoot())
679 return true;
680
681 if (!object->hasOverflowClip())
682 return false;
683
684 if (object->style()->width().isIntrinsicOrAuto() || object->style()->height().isIntrinsicOrAuto() || object->style()->height().isPercent())
685 return false;
686
687 // Table parts can't be relayout roots since the table is responsible for layouting all the parts.
688 if (object->isTablePart())
689 return false;
690
691 return true;
692 }
693
markContainingBlocksForLayout(bool scheduleRelayout,RenderObject * newRoot,SubtreeLayoutScope * layouter)694 void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot, SubtreeLayoutScope* layouter)
695 {
696 ASSERT(!scheduleRelayout || !newRoot);
697 ASSERT(!isSetNeedsLayoutForbidden());
698 ASSERT(!layouter || this != layouter->root());
699
700 RenderObject* object = container();
701 RenderObject* last = this;
702
703 bool simplifiedNormalFlowLayout = needsSimplifiedNormalFlowLayout() && !selfNeedsLayout() && !normalChildNeedsLayout();
704
705 while (object) {
706 if (object->selfNeedsLayout())
707 return;
708
709 // Don't mark the outermost object of an unrooted subtree. That object will be
710 // marked when the subtree is added to the document.
711 RenderObject* container = object->container();
712 if (!container && !object->isRenderView())
713 return;
714 if (!last->isText() && last->style()->hasOutOfFlowPosition()) {
715 bool willSkipRelativelyPositionedInlines = !object->isRenderBlock() || object->isAnonymousBlock();
716 // Skip relatively positioned inlines and anonymous blocks to get to the enclosing RenderBlock.
717 while (object && (!object->isRenderBlock() || object->isAnonymousBlock()))
718 object = object->container();
719 if (!object || object->posChildNeedsLayout())
720 return;
721 if (willSkipRelativelyPositionedInlines)
722 container = object->container();
723 object->setPosChildNeedsLayout(true);
724 simplifiedNormalFlowLayout = true;
725 ASSERT(!object->isSetNeedsLayoutForbidden());
726 } else if (simplifiedNormalFlowLayout) {
727 if (object->needsSimplifiedNormalFlowLayout())
728 return;
729 object->setNeedsSimplifiedNormalFlowLayout(true);
730 ASSERT(!object->isSetNeedsLayoutForbidden());
731 } else {
732 if (object->normalChildNeedsLayout())
733 return;
734 object->setNormalChildNeedsLayout(true);
735 ASSERT(!object->isSetNeedsLayoutForbidden());
736 }
737
738 if (layouter) {
739 layouter->addRendererToLayout(object);
740 if (object == layouter->root())
741 return;
742 }
743
744 if (object == newRoot)
745 return;
746
747 last = object;
748 if (scheduleRelayout && objectIsRelayoutBoundary(last))
749 break;
750 object = container;
751 }
752
753 if (scheduleRelayout)
754 last->scheduleRelayout();
755 }
756
757 #if ENABLE(ASSERT)
checkBlockPositionedObjectsNeedLayout()758 void RenderObject::checkBlockPositionedObjectsNeedLayout()
759 {
760 ASSERT(!needsLayout());
761
762 if (isRenderBlock())
763 toRenderBlock(this)->checkPositionedObjectsNeedLayout();
764 }
765 #endif
766
setPreferredLogicalWidthsDirty(MarkingBehavior markParents)767 void RenderObject::setPreferredLogicalWidthsDirty(MarkingBehavior markParents)
768 {
769 m_bitfields.setPreferredLogicalWidthsDirty(true);
770 if (markParents == MarkContainingBlockChain && (isText() || !style()->hasOutOfFlowPosition()))
771 invalidateContainerPreferredLogicalWidths();
772 }
773
clearPreferredLogicalWidthsDirty()774 void RenderObject::clearPreferredLogicalWidthsDirty()
775 {
776 m_bitfields.setPreferredLogicalWidthsDirty(false);
777 }
778
invalidateContainerPreferredLogicalWidths()779 void RenderObject::invalidateContainerPreferredLogicalWidths()
780 {
781 // In order to avoid pathological behavior when inlines are deeply nested, we do include them
782 // in the chain that we mark dirty (even though they're kind of irrelevant).
783 RenderObject* o = isTableCell() ? containingBlock() : container();
784 while (o && !o->preferredLogicalWidthsDirty()) {
785 // Don't invalidate the outermost object of an unrooted subtree. That object will be
786 // invalidated when the subtree is added to the document.
787 RenderObject* container = o->isTableCell() ? o->containingBlock() : o->container();
788 if (!container && !o->isRenderView())
789 break;
790
791 o->m_bitfields.setPreferredLogicalWidthsDirty(true);
792 if (o->style()->hasOutOfFlowPosition())
793 // A positioned object has no effect on the min/max width of its containing block ever.
794 // We can optimize this case and not go up any further.
795 break;
796 o = container;
797 }
798 }
799
containerForFixedPosition(const RenderLayerModelObject * paintInvalidationContainer,bool * paintInvalidationContainerSkipped) const800 RenderBlock* RenderObject::containerForFixedPosition(const RenderLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const
801 {
802 ASSERT(!paintInvalidationContainerSkipped || !*paintInvalidationContainerSkipped);
803 ASSERT(!isText());
804 ASSERT(style()->position() == FixedPosition);
805
806 RenderObject* ancestor = parent();
807 for (; ancestor && !ancestor->canContainFixedPositionObjects(); ancestor = ancestor->parent()) {
808 if (paintInvalidationContainerSkipped && ancestor == paintInvalidationContainer)
809 *paintInvalidationContainerSkipped = true;
810 }
811
812 ASSERT(!ancestor || !ancestor->isAnonymousBlock());
813 return toRenderBlock(ancestor);
814 }
815
containingBlock() const816 RenderBlock* RenderObject::containingBlock() const
817 {
818 RenderObject* o = parent();
819 if (!o && isRenderScrollbarPart())
820 o = toRenderScrollbarPart(this)->rendererOwningScrollbar();
821 if (!isText() && m_style->position() == FixedPosition) {
822 return containerForFixedPosition();
823 } else if (!isText() && m_style->position() == AbsolutePosition) {
824 while (o) {
825 // For relpositioned inlines, we return the nearest non-anonymous enclosing block. We don't try
826 // to return the inline itself. This allows us to avoid having a positioned objects
827 // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
828 // from this method. The container() method can actually be used to obtain the
829 // inline directly.
830 if (o->style()->position() != StaticPosition && (!o->isInline() || o->isReplaced()))
831 break;
832
833 if (o->canContainFixedPositionObjects())
834 break;
835
836 if (o->style()->hasInFlowPosition() && o->isInline() && !o->isReplaced()) {
837 o = o->containingBlock();
838 break;
839 }
840
841 o = o->parent();
842 }
843
844 if (o && !o->isRenderBlock())
845 o = o->containingBlock();
846
847 while (o && o->isAnonymousBlock())
848 o = o->containingBlock();
849 } else {
850 while (o && ((o->isInline() && !o->isReplaced()) || !o->isRenderBlock()))
851 o = o->parent();
852 }
853
854 if (!o || !o->isRenderBlock())
855 return 0; // This can still happen in case of an orphaned tree
856
857 return toRenderBlock(o);
858 }
859
canRenderBorderImage() const860 bool RenderObject::canRenderBorderImage() const
861 {
862 if (!style()->hasBorder())
863 return false;
864
865 StyleImage* borderImage = style()->borderImage().image();
866 return borderImage && borderImage->canRender(*this, style()->effectiveZoom()) && borderImage->isLoaded();
867 }
868
mustInvalidateFillLayersPaintOnWidthChange(const FillLayer & layer) const869 bool RenderObject::mustInvalidateFillLayersPaintOnWidthChange(const FillLayer& layer) const
870 {
871 // Nobody will use multiple layers without wanting fancy positioning.
872 if (layer.next())
873 return true;
874
875 // Make sure we have a valid image.
876 StyleImage* img = layer.image();
877 if (!img || !img->canRender(*this, style()->effectiveZoom()))
878 return false;
879
880 if (layer.repeatX() != RepeatFill && layer.repeatX() != NoRepeatFill)
881 return true;
882
883 if (layer.xPosition().isPercent() && !layer.xPosition().isZero())
884 return true;
885
886 if (layer.backgroundXOrigin() != LeftEdge)
887 return true;
888
889 EFillSizeType sizeType = layer.sizeType();
890
891 if (sizeType == Contain || sizeType == Cover)
892 return true;
893
894 if (sizeType == SizeLength) {
895 if (layer.sizeLength().width().isPercent() && !layer.sizeLength().width().isZero())
896 return true;
897 if (img->isGeneratedImage() && layer.sizeLength().width().isAuto())
898 return true;
899 } else if (img->usesImageContainerSize()) {
900 return true;
901 }
902
903 return false;
904 }
905
mustInvalidateFillLayersPaintOnHeightChange(const FillLayer & layer) const906 bool RenderObject::mustInvalidateFillLayersPaintOnHeightChange(const FillLayer& layer) const
907 {
908 // Nobody will use multiple layers without wanting fancy positioning.
909 if (layer.next())
910 return true;
911
912 // Make sure we have a valid image.
913 StyleImage* img = layer.image();
914 if (!img || !img->canRender(*this, style()->effectiveZoom()))
915 return false;
916
917 if (layer.repeatY() != RepeatFill && layer.repeatY() != NoRepeatFill)
918 return true;
919
920 if (layer.yPosition().isPercent() && !layer.yPosition().isZero())
921 return true;
922
923 if (layer.backgroundYOrigin() != TopEdge)
924 return true;
925
926 EFillSizeType sizeType = layer.sizeType();
927
928 if (sizeType == Contain || sizeType == Cover)
929 return true;
930
931 if (sizeType == SizeLength) {
932 if (layer.sizeLength().height().isPercent() && !layer.sizeLength().height().isZero())
933 return true;
934 if (img->isGeneratedImage() && layer.sizeLength().height().isAuto())
935 return true;
936 } else if (img->usesImageContainerSize()) {
937 return true;
938 }
939
940 return false;
941 }
942
mustInvalidateBackgroundOrBorderPaintOnWidthChange() const943 bool RenderObject::mustInvalidateBackgroundOrBorderPaintOnWidthChange() const
944 {
945 if (hasMask() && mustInvalidateFillLayersPaintOnWidthChange(style()->maskLayers()))
946 return true;
947
948 // If we don't have a background/border/mask, then nothing to do.
949 if (!hasBoxDecorationBackground())
950 return false;
951
952 if (mustInvalidateFillLayersPaintOnWidthChange(style()->backgroundLayers()))
953 return true;
954
955 // Our fill layers are ok. Let's check border.
956 if (style()->hasBorder() && canRenderBorderImage())
957 return true;
958
959 return false;
960 }
961
mustInvalidateBackgroundOrBorderPaintOnHeightChange() const962 bool RenderObject::mustInvalidateBackgroundOrBorderPaintOnHeightChange() const
963 {
964 if (hasMask() && mustInvalidateFillLayersPaintOnHeightChange(style()->maskLayers()))
965 return true;
966
967 // If we don't have a background/border/mask, then nothing to do.
968 if (!hasBoxDecorationBackground())
969 return false;
970
971 if (mustInvalidateFillLayersPaintOnHeightChange(style()->backgroundLayers()))
972 return true;
973
974 // Our fill layers are ok. Let's check border.
975 if (style()->hasBorder() && canRenderBorderImage())
976 return true;
977
978 return false;
979 }
980
paintOutline(PaintInfo & paintInfo,const LayoutRect & paintRect)981 void RenderObject::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect)
982 {
983 ObjectPainter(*this).paintOutline(paintInfo, paintRect);
984 }
985
addChildFocusRingRects(Vector<LayoutRect> & rects,const LayoutPoint & additionalOffset,const RenderLayerModelObject * paintContainer) const986 void RenderObject::addChildFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) const
987 {
988 for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling()) {
989 if (current->isText() || current->isListMarker())
990 continue;
991
992 if (current->isBox()) {
993 RenderBox* box = toRenderBox(current);
994 if (box->hasLayer()) {
995 Vector<LayoutRect> layerFocusRingRects;
996 box->addFocusRingRects(layerFocusRingRects, LayoutPoint(), box);
997 for (size_t i = 0; i < layerFocusRingRects.size(); ++i) {
998 FloatQuad quadInBox = box->localToContainerQuad(FloatQuad(layerFocusRingRects[i]), paintContainer);
999 LayoutRect rect = LayoutRect(quadInBox.boundingBox());
1000 if (!rect.isEmpty())
1001 rects.append(rect);
1002 }
1003 } else {
1004 box->addFocusRingRects(rects, additionalOffset + box->locationOffset(), paintContainer);
1005 }
1006 } else {
1007 current->addFocusRingRects(rects, additionalOffset, paintContainer);
1008 }
1009 }
1010 }
1011
absoluteBoundingBoxRect() const1012 IntRect RenderObject::absoluteBoundingBoxRect() const
1013 {
1014 Vector<FloatQuad> quads;
1015 absoluteQuads(quads);
1016
1017 size_t n = quads.size();
1018 if (!n)
1019 return IntRect();
1020
1021 IntRect result = quads[0].enclosingBoundingBox();
1022 for (size_t i = 1; i < n; ++i)
1023 result.unite(quads[i].enclosingBoundingBox());
1024 return result;
1025 }
1026
absoluteBoundingBoxRectIgnoringTransforms() const1027 IntRect RenderObject::absoluteBoundingBoxRectIgnoringTransforms() const
1028 {
1029 FloatPoint absPos = localToAbsolute();
1030 Vector<IntRect> rects;
1031 absoluteRects(rects, flooredLayoutPoint(absPos));
1032
1033 size_t n = rects.size();
1034 if (!n)
1035 return IntRect();
1036
1037 LayoutRect result = rects[0];
1038 for (size_t i = 1; i < n; ++i)
1039 result.unite(rects[i]);
1040 return pixelSnappedIntRect(result);
1041 }
1042
absoluteFocusRingBoundingBoxRect() const1043 IntRect RenderObject::absoluteFocusRingBoundingBoxRect() const
1044 {
1045 Vector<LayoutRect> rects;
1046 const RenderLayerModelObject* container = containerForPaintInvalidation();
1047 addFocusRingRects(rects, LayoutPoint(localToContainerPoint(FloatPoint(), container)), container);
1048 return container->localToAbsoluteQuad(FloatQuad(unionRect(rects))).enclosingBoundingBox();
1049 }
1050
absoluteBoundingBoxRectForRange(const Range * range)1051 FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range)
1052 {
1053 if (!range || !range->startContainer())
1054 return FloatRect();
1055
1056 range->ownerDocument().updateLayout();
1057
1058 Vector<FloatQuad> quads;
1059 range->textQuads(quads);
1060
1061 FloatRect result;
1062 for (size_t i = 0; i < quads.size(); ++i)
1063 result.unite(quads[i].boundingBox());
1064
1065 return result;
1066 }
1067
addAbsoluteRectForLayer(LayoutRect & result)1068 void RenderObject::addAbsoluteRectForLayer(LayoutRect& result)
1069 {
1070 if (hasLayer())
1071 result.unite(absoluteBoundingBoxRect());
1072 for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling())
1073 current->addAbsoluteRectForLayer(result);
1074 }
1075
paintingRootRect(LayoutRect & topLevelRect)1076 LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
1077 {
1078 LayoutRect result = absoluteBoundingBoxRect();
1079 topLevelRect = result;
1080 for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling())
1081 current->addAbsoluteRectForLayer(result);
1082 return result;
1083 }
1084
paint(PaintInfo &,const LayoutPoint &)1085 void RenderObject::paint(PaintInfo&, const LayoutPoint&)
1086 {
1087 }
1088
setHadPaintInvalidation()1089 void RenderObject::setHadPaintInvalidation()
1090 {
1091 if (firstPaintInvalidationTrackingEnabled())
1092 renderObjectNeverHadPaintInvalidationSet().remove(this);
1093 }
1094
hadPaintInvalidation() const1095 bool RenderObject::hadPaintInvalidation() const
1096 {
1097 if (!firstPaintInvalidationTrackingEnabled())
1098 return true;
1099
1100 return !renderObjectNeverHadPaintInvalidationSet().contains(this);
1101 }
1102
containerForPaintInvalidation() const1103 const RenderLayerModelObject* RenderObject::containerForPaintInvalidation() const
1104 {
1105 RELEASE_ASSERT(isRooted());
1106 return adjustCompositedContainerForSpecialAncestors(enclosingCompositedContainer());
1107 }
1108
enclosingCompositedContainer() const1109 const RenderLayerModelObject* RenderObject::enclosingCompositedContainer() const
1110 {
1111 RenderLayerModelObject* container = 0;
1112 // FIXME: CompositingState is not necessarily up to date for many callers of this function.
1113 DisableCompositingQueryAsserts disabler;
1114
1115 if (RenderLayer* compositingLayer = enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries())
1116 container = compositingLayer->renderer();
1117 return container;
1118 }
1119
adjustCompositedContainerForSpecialAncestors(const RenderLayerModelObject * paintInvalidationContainer) const1120 const RenderLayerModelObject* RenderObject::adjustCompositedContainerForSpecialAncestors(const RenderLayerModelObject* paintInvalidationContainer) const
1121 {
1122 // If we have a flow thread, then we need to do individual paint invalidations within the RenderRegions instead.
1123 // Return the flow thread as a paint invalidation container in order to create a chokepoint that allows us to change
1124 // paint invalidation to do individual region paint invalidations.
1125 if (RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock()) {
1126 // If we have already found a paint invalidation container then we will invalidate paints in that container only if it is part of the same
1127 // flow thread. Otherwise we will need to catch the paint invalidation call and send it to the flow thread.
1128 if (!paintInvalidationContainer || paintInvalidationContainer->flowThreadContainingBlock() != parentRenderFlowThread)
1129 paintInvalidationContainer = parentRenderFlowThread;
1130 }
1131
1132 if (paintInvalidationContainer)
1133 return paintInvalidationContainer;
1134
1135 RenderView* renderView = view();
1136 while (renderView->frame()->ownerRenderer())
1137 renderView = renderView->frame()->ownerRenderer()->view();
1138 return renderView;
1139 }
1140
isPaintInvalidationContainer() const1141 bool RenderObject::isPaintInvalidationContainer() const
1142 {
1143 return hasLayer() && toRenderLayerModelObject(this)->layer()->isPaintInvalidationContainer();
1144 }
1145
1146 template <typename T>
addJsonObjectForRect(TracedValue * value,const char * name,const T & rect)1147 void addJsonObjectForRect(TracedValue* value, const char* name, const T& rect)
1148 {
1149 value->beginDictionary(name);
1150 value->setDouble("x", rect.x());
1151 value->setDouble("y", rect.y());
1152 value->setDouble("width", rect.width());
1153 value->setDouble("height", rect.height());
1154 value->endDictionary();
1155 }
1156
1157 template <typename T>
addJsonObjectForPoint(TracedValue * value,const char * name,const T & point)1158 void addJsonObjectForPoint(TracedValue* value, const char* name, const T& point)
1159 {
1160 value->beginDictionary(name);
1161 value->setDouble("x", point.x());
1162 value->setDouble("y", point.y());
1163 value->endDictionary();
1164 }
1165
jsonObjectForPaintInvalidationInfo(const LayoutRect & rect,const String & invalidationReason)1166 static PassRefPtr<TraceEvent::ConvertableToTraceFormat> jsonObjectForPaintInvalidationInfo(const LayoutRect& rect, const String& invalidationReason)
1167 {
1168 RefPtr<TracedValue> value = TracedValue::create();
1169 addJsonObjectForRect(value.get(), "rect", rect);
1170 value->setString("invalidation_reason", invalidationReason);
1171 return value;
1172 }
1173
computePaintInvalidationRect(const RenderLayerModelObject * paintInvalidationContainer,const PaintInvalidationState * paintInvalidationState) const1174 LayoutRect RenderObject::computePaintInvalidationRect(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
1175 {
1176 return clippedOverflowRectForPaintInvalidation(paintInvalidationContainer, paintInvalidationState);
1177 }
1178
invalidatePaintUsingContainer(const RenderLayerModelObject * paintInvalidationContainer,const LayoutRect & r,InvalidationReason invalidationReason) const1179 void RenderObject::invalidatePaintUsingContainer(const RenderLayerModelObject* paintInvalidationContainer, const LayoutRect& r, InvalidationReason invalidationReason) const
1180 {
1181 if (r.isEmpty())
1182 return;
1183
1184 RELEASE_ASSERT(isRooted());
1185
1186 // FIXME: Unify "devtools.timeline.invalidationTracking" and "blink.invalidation". crbug.com/413527.
1187 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
1188 "PaintInvalidationTracking",
1189 "data", InspectorPaintInvalidationTrackingEvent::data(this, paintInvalidationContainer));
1190 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintUsingContainer()",
1191 "object", this->debugName().ascii(),
1192 "info", jsonObjectForPaintInvalidationInfo(r, invalidationReasonToString(invalidationReason)));
1193
1194 if (paintInvalidationContainer->isRenderFlowThread()) {
1195 toRenderFlowThread(paintInvalidationContainer)->paintInvalidationRectangleInRegions(r);
1196 return;
1197 }
1198
1199 if (paintInvalidationContainer->isRenderView()) {
1200 toRenderView(paintInvalidationContainer)->invalidatePaintForRectangle(r);
1201 return;
1202 }
1203
1204 if (paintInvalidationContainer->view()->usesCompositing()) {
1205 ASSERT(paintInvalidationContainer->isPaintInvalidationContainer());
1206 paintInvalidationContainer->setBackingNeedsPaintInvalidationInRect(r);
1207 }
1208 }
1209
boundsRectForPaintInvalidation(const RenderLayerModelObject * paintInvalidationContainer,const PaintInvalidationState * paintInvalidationState) const1210 LayoutRect RenderObject::boundsRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
1211 {
1212 if (!paintInvalidationContainer)
1213 return computePaintInvalidationRect(paintInvalidationContainer, paintInvalidationState);
1214 return RenderLayer::computePaintInvalidationRect(this, paintInvalidationContainer->layer(), paintInvalidationState);
1215 }
1216
invalidatePaintRectangle(const LayoutRect & r) const1217 void RenderObject::invalidatePaintRectangle(const LayoutRect& r) const
1218 {
1219 RELEASE_ASSERT(isRooted());
1220
1221 if (view()->document().printing())
1222 return; // Don't invalidate paints if we're printing.
1223
1224 LayoutRect dirtyRect(r);
1225
1226 const RenderLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation();
1227 RenderLayer::mapRectToPaintInvalidationBacking(this, paintInvalidationContainer, dirtyRect);
1228 invalidatePaintUsingContainer(paintInvalidationContainer, dirtyRect, InvalidationPaintRectangle);
1229 }
1230
pixelSnappedAbsoluteClippedOverflowRect() const1231 IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const
1232 {
1233 return pixelSnappedIntRect(absoluteClippedOverflowRect());
1234 }
1235
invalidationReasonToString(InvalidationReason reason) const1236 const char* RenderObject::invalidationReasonToString(InvalidationReason reason) const
1237 {
1238 switch (reason) {
1239 case InvalidationNone:
1240 return "none";
1241 case InvalidationIncremental:
1242 return "incremental";
1243 case InvalidationFull:
1244 return "full";
1245 case InvalidationBorderFitLines:
1246 return "border fit lines";
1247 case InvalidationBorderBoxChange:
1248 return "border box change";
1249 case InvalidationBoundsChange:
1250 return "bounds change";
1251 case InvalidationLocationChange:
1252 return "location change";
1253 case InvalidationBecameVisible:
1254 return "became visible";
1255 case InvalidationBecameInvisible:
1256 return "became invisible";
1257 case InvalidationScroll:
1258 return "scroll";
1259 case InvalidationSelection:
1260 return "selection";
1261 case InvalidationLayer:
1262 return "layer";
1263 case InvalidationRendererRemoval:
1264 return "renderer removal";
1265 case InvalidationPaintRectangle:
1266 return "invalidate paint rectangle";
1267 }
1268 ASSERT_NOT_REACHED();
1269 return "";
1270 }
1271
invalidateTreeIfNeeded(const PaintInvalidationState & paintInvalidationState)1272 void RenderObject::invalidateTreeIfNeeded(const PaintInvalidationState& paintInvalidationState)
1273 {
1274 ASSERT(!needsLayout());
1275
1276 // If we didn't need paint invalidation then our children don't need as well.
1277 // Skip walking down the tree as everything should be fine below us.
1278 if (!shouldCheckForPaintInvalidation(paintInvalidationState))
1279 return;
1280
1281 invalidatePaintIfNeeded(paintInvalidationState, paintInvalidationState.paintInvalidationContainer());
1282 clearPaintInvalidationState(paintInvalidationState);
1283 invalidatePaintOfSubtreesIfNeeded(paintInvalidationState);
1284 }
1285
invalidatePaintOfSubtreesIfNeeded(const PaintInvalidationState & childPaintInvalidationState)1286 void RenderObject::invalidatePaintOfSubtreesIfNeeded(const PaintInvalidationState& childPaintInvalidationState)
1287 {
1288 for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
1289 if (!child->isOutOfFlowPositioned())
1290 child->invalidateTreeIfNeeded(childPaintInvalidationState);
1291 }
1292 }
1293
jsonObjectForOldAndNewRects(const LayoutRect & oldRect,const LayoutPoint & oldLocation,const LayoutRect & newRect,const LayoutPoint & newLocation)1294 static PassRefPtr<TraceEvent::ConvertableToTraceFormat> jsonObjectForOldAndNewRects(const LayoutRect& oldRect, const LayoutPoint& oldLocation, const LayoutRect& newRect, const LayoutPoint& newLocation)
1295 {
1296 RefPtr<TracedValue> value = TracedValue::create();
1297 addJsonObjectForRect(value.get(), "oldRect", oldRect);
1298 addJsonObjectForPoint(value.get(), "oldLocation", oldLocation);
1299 addJsonObjectForRect(value.get(), "newRect", newRect);
1300 addJsonObjectForPoint(value.get(), "newLocation", newLocation);
1301 return value;
1302 }
1303
invalidatePaintIfNeeded(const PaintInvalidationState & paintInvalidationState,const RenderLayerModelObject & paintInvalidationContainer)1304 InvalidationReason RenderObject::invalidatePaintIfNeeded(const PaintInvalidationState& paintInvalidationState, const RenderLayerModelObject& paintInvalidationContainer)
1305 {
1306 RenderView* v = view();
1307 if (v->document().printing())
1308 return InvalidationNone; // Don't invalidate paints if we're printing.
1309
1310 const LayoutRect oldBounds = previousPaintInvalidationRect();
1311 const LayoutPoint oldLocation = previousPositionFromPaintInvalidationBacking();
1312 const LayoutRect newBounds = boundsRectForPaintInvalidation(&paintInvalidationContainer, &paintInvalidationState);
1313 const LayoutPoint newLocation = RenderLayer::positionFromPaintInvalidationBacking(this, &paintInvalidationContainer, &paintInvalidationState);
1314 setPreviousPaintInvalidationRect(newBounds);
1315 setPreviousPositionFromPaintInvalidationBacking(newLocation);
1316
1317 // If we are set to do a full paint invalidation that means the RenderView will issue
1318 // paint invalidations. We can then skip issuing of paint invalidations for the child
1319 // renderers as they'll be covered by the RenderView.
1320 if (view()->doingFullPaintInvalidation())
1321 return InvalidationNone;
1322
1323 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintIfNeeded()",
1324 "object", this->debugName().ascii(),
1325 "info", jsonObjectForOldAndNewRects(oldBounds, oldLocation, newBounds, newLocation));
1326
1327 InvalidationReason invalidationReason = getPaintInvalidationReason(paintInvalidationContainer, oldBounds, oldLocation, newBounds, newLocation);
1328
1329 if (invalidationReason == InvalidationNone)
1330 return invalidationReason;
1331
1332 if (invalidationReason == InvalidationIncremental) {
1333 incrementallyInvalidatePaint(paintInvalidationContainer, oldBounds, newBounds, newLocation);
1334 return invalidationReason;
1335 }
1336
1337 fullyInvalidatePaint(paintInvalidationContainer, invalidationReason, oldBounds, newBounds);
1338 return invalidationReason;
1339 }
1340
getPaintInvalidationReason(const RenderLayerModelObject & paintInvalidationContainer,const LayoutRect & oldBounds,const LayoutPoint & oldPositionFromPaintInvalidationBacking,const LayoutRect & newBounds,const LayoutPoint & newPositionFromPaintInvalidationBacking)1341 InvalidationReason RenderObject::getPaintInvalidationReason(const RenderLayerModelObject& paintInvalidationContainer,
1342 const LayoutRect& oldBounds, const LayoutPoint& oldPositionFromPaintInvalidationBacking, const LayoutRect& newBounds, const LayoutPoint& newPositionFromPaintInvalidationBacking)
1343 {
1344 if (shouldDoFullPaintInvalidation())
1345 return InvalidationFull;
1346
1347 // Presumably a background or a border exists if border-fit:lines was specified.
1348 if (style()->borderFit() == BorderFitLines)
1349 return InvalidationBorderFitLines;
1350
1351 if (compositingState() != PaintsIntoOwnBacking && newPositionFromPaintInvalidationBacking != oldPositionFromPaintInvalidationBacking)
1352 return InvalidationLocationChange;
1353
1354 // If the bounds are the same then we know that none of the statements below
1355 // can match, so we can early out since we will not need to do any
1356 // invalidation.
1357 if (oldBounds == newBounds)
1358 return InvalidationNone;
1359
1360 // If we shifted, we don't know the exact reason so we are conservative and trigger a full invalidation. Shifting could
1361 // be caused by some layout property (left / top) or some in-flow renderer inserted / removed before us in the tree.
1362 if (newBounds.location() != oldBounds.location())
1363 return InvalidationBoundsChange;
1364
1365 // This covers the case where we mark containing blocks for layout
1366 // and they change size but don't have anything to paint. This is
1367 // a pretty common case for <body> as we add / remove children
1368 // (and the default background is done by FrameView).
1369 if (skipInvalidationWhenLaidOutChildren())
1370 return InvalidationNone;
1371
1372 // If the size is zero on one of our bounds then we know we're going to have
1373 // to do a full invalidation of either old bounds or new bounds. If we fall
1374 // into the incremental invalidation we'll issue two invalidations instead
1375 // of one.
1376 if (oldBounds.isEmpty())
1377 return InvalidationBecameVisible;
1378 if (newBounds.isEmpty())
1379 return InvalidationBecameInvisible;
1380
1381 return InvalidationIncremental;
1382 }
1383
incrementallyInvalidatePaint(const RenderLayerModelObject & paintInvalidationContainer,const LayoutRect & oldBounds,const LayoutRect & newBounds,const LayoutPoint & positionFromPaintInvalidationBacking)1384 void RenderObject::incrementallyInvalidatePaint(const RenderLayerModelObject& paintInvalidationContainer, const LayoutRect& oldBounds, const LayoutRect& newBounds, const LayoutPoint& positionFromPaintInvalidationBacking)
1385 {
1386 ASSERT(oldBounds.location() == newBounds.location());
1387
1388 LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX();
1389 if (deltaRight > 0)
1390 invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height()), InvalidationIncremental);
1391 else if (deltaRight < 0)
1392 invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height()), InvalidationIncremental);
1393
1394 LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY();
1395 if (deltaBottom > 0)
1396 invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom), InvalidationIncremental);
1397 else if (deltaBottom < 0)
1398 invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom), InvalidationIncremental);
1399 }
1400
fullyInvalidatePaint(const RenderLayerModelObject & paintInvalidationContainer,InvalidationReason invalidationReason,const LayoutRect & oldBounds,const LayoutRect & newBounds)1401 void RenderObject::fullyInvalidatePaint(const RenderLayerModelObject& paintInvalidationContainer, InvalidationReason invalidationReason, const LayoutRect& oldBounds, const LayoutRect& newBounds)
1402 {
1403 // Otherwise do full paint invalidation.
1404 invalidatePaintUsingContainer(&paintInvalidationContainer, oldBounds, invalidationReason);
1405 if (newBounds != oldBounds)
1406 invalidatePaintUsingContainer(&paintInvalidationContainer, newBounds, invalidationReason);
1407 }
1408
invalidatePaintForOverflow()1409 void RenderObject::invalidatePaintForOverflow()
1410 {
1411 }
1412
invalidatePaintForOverflowIfNeeded()1413 void RenderObject::invalidatePaintForOverflowIfNeeded()
1414 {
1415 if (shouldInvalidateOverflowForPaint())
1416 invalidatePaintForOverflow();
1417 }
1418
checkForPaintInvalidation() const1419 bool RenderObject::checkForPaintInvalidation() const
1420 {
1421 return !document().view()->needsFullPaintInvalidation() && everHadLayout();
1422 }
1423
rectWithOutlineForPaintInvalidation(const RenderLayerModelObject * paintInvalidationContainer,LayoutUnit outlineWidth,const PaintInvalidationState * paintInvalidationState) const1424 LayoutRect RenderObject::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* paintInvalidationState) const
1425 {
1426 LayoutRect r(clippedOverflowRectForPaintInvalidation(paintInvalidationContainer, paintInvalidationState));
1427 r.inflate(outlineWidth);
1428 return r;
1429 }
1430
absoluteClippedOverflowRect() const1431 LayoutRect RenderObject::absoluteClippedOverflowRect() const
1432 {
1433 return clippedOverflowRectForPaintInvalidation(view());
1434 }
1435
clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject *,const PaintInvalidationState *) const1436 LayoutRect RenderObject::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*, const PaintInvalidationState*) const
1437 {
1438 ASSERT_NOT_REACHED();
1439 return LayoutRect();
1440 }
1441
mapRectToPaintInvalidationBacking(const RenderLayerModelObject * paintInvalidationContainer,LayoutRect & rect,const PaintInvalidationState * paintInvalidationState) const1442 void RenderObject::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const
1443 {
1444 if (paintInvalidationContainer == this)
1445 return;
1446
1447 if (RenderObject* o = parent()) {
1448 if (o->isRenderBlockFlow()) {
1449 RenderBlock* cb = toRenderBlock(o);
1450 if (cb->hasColumns())
1451 cb->adjustRectForColumns(rect);
1452 }
1453
1454 if (o->hasOverflowClip()) {
1455 RenderBox* boxParent = toRenderBox(o);
1456 boxParent->applyCachedClipAndScrollOffsetForPaintInvalidation(rect);
1457 if (rect.isEmpty())
1458 return;
1459 }
1460
1461 o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
1462 }
1463 }
1464
computeFloatRectForPaintInvalidation(const RenderLayerModelObject *,FloatRect &,const PaintInvalidationState *) const1465 void RenderObject::computeFloatRectForPaintInvalidation(const RenderLayerModelObject*, FloatRect&, const PaintInvalidationState*) const
1466 {
1467 ASSERT_NOT_REACHED();
1468 }
1469
dirtyLinesFromChangedChild(RenderObject *)1470 void RenderObject::dirtyLinesFromChangedChild(RenderObject*)
1471 {
1472 }
1473
1474 #ifndef NDEBUG
1475
showTreeForThis() const1476 void RenderObject::showTreeForThis() const
1477 {
1478 if (node())
1479 node()->showTreeForThis();
1480 }
1481
showRenderTreeForThis() const1482 void RenderObject::showRenderTreeForThis() const
1483 {
1484 showRenderTree(this, 0);
1485 }
1486
showLineTreeForThis() const1487 void RenderObject::showLineTreeForThis() const
1488 {
1489 if (containingBlock())
1490 containingBlock()->showLineTreeAndMark(0, 0, 0, 0, this);
1491 }
1492
showRenderObject() const1493 void RenderObject::showRenderObject() const
1494 {
1495 showRenderObject(0);
1496 }
1497
showRenderObject(int printedCharacters) const1498 void RenderObject::showRenderObject(int printedCharacters) const
1499 {
1500 printedCharacters += fprintf(stderr, "%s %p", renderName(), this);
1501
1502 if (node()) {
1503 if (printedCharacters)
1504 for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
1505 fputc(' ', stderr);
1506 fputc('\t', stderr);
1507 node()->showNode();
1508 } else
1509 fputc('\n', stderr);
1510 }
1511
showRenderTreeAndMark(const RenderObject * markedObject1,const char * markedLabel1,const RenderObject * markedObject2,const char * markedLabel2,int depth) const1512 void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, const char* markedLabel1, const RenderObject* markedObject2, const char* markedLabel2, int depth) const
1513 {
1514 int printedCharacters = 0;
1515 if (markedObject1 == this && markedLabel1)
1516 printedCharacters += fprintf(stderr, "%s", markedLabel1);
1517 if (markedObject2 == this && markedLabel2)
1518 printedCharacters += fprintf(stderr, "%s", markedLabel2);
1519 for (; printedCharacters < depth * 2; printedCharacters++)
1520 fputc(' ', stderr);
1521
1522 showRenderObject(printedCharacters);
1523
1524 for (const RenderObject* child = slowFirstChild(); child; child = child->nextSibling())
1525 child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1);
1526 }
1527
1528 #endif // NDEBUG
1529
isSelectable() const1530 bool RenderObject::isSelectable() const
1531 {
1532 return !isInert() && !(style()->userSelect() == SELECT_NONE && style()->userModify() == READ_ONLY);
1533 }
1534
selectionBackgroundColor() const1535 Color RenderObject::selectionBackgroundColor() const
1536 {
1537 if (!isSelectable())
1538 return Color::transparent;
1539
1540 if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost())
1541 return resolveColor(pseudoStyle.get(), CSSPropertyBackgroundColor).blendWithWhite();
1542 return frame()->selection().isFocusedAndActive() ?
1543 RenderTheme::theme().activeSelectionBackgroundColor() :
1544 RenderTheme::theme().inactiveSelectionBackgroundColor();
1545 }
1546
selectionColor(int colorProperty) const1547 Color RenderObject::selectionColor(int colorProperty) const
1548 {
1549 // If the element is unselectable, or we are only painting the selection,
1550 // don't override the foreground color with the selection foreground color.
1551 if (!isSelectable() || (frame()->view()->paintBehavior() & PaintBehaviorSelectionOnly))
1552 return resolveColor(colorProperty);
1553
1554 if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost())
1555 return resolveColor(pseudoStyle.get(), colorProperty);
1556 if (!RenderTheme::theme().supportsSelectionForegroundColors())
1557 return resolveColor(colorProperty);
1558 return frame()->selection().isFocusedAndActive() ?
1559 RenderTheme::theme().activeSelectionForegroundColor() :
1560 RenderTheme::theme().inactiveSelectionForegroundColor();
1561 }
1562
selectionForegroundColor() const1563 Color RenderObject::selectionForegroundColor() const
1564 {
1565 return selectionColor(CSSPropertyWebkitTextFillColor);
1566 }
1567
selectionEmphasisMarkColor() const1568 Color RenderObject::selectionEmphasisMarkColor() const
1569 {
1570 return selectionColor(CSSPropertyWebkitTextEmphasisColor);
1571 }
1572
selectionStartEnd(int & spos,int & epos) const1573 void RenderObject::selectionStartEnd(int& spos, int& epos) const
1574 {
1575 view()->selectionStartEnd(spos, epos);
1576 }
1577
handleDynamicFloatPositionChange()1578 void RenderObject::handleDynamicFloatPositionChange()
1579 {
1580 // We have gone from not affecting the inline status of the parent flow to suddenly
1581 // having an impact. See if there is a mismatch between the parent flow's
1582 // childrenInline() state and our state.
1583 setInline(style()->isDisplayInlineType());
1584 if (isInline() != parent()->childrenInline()) {
1585 if (!isInline())
1586 toRenderBoxModelObject(parent())->childBecameNonInline(this);
1587 else {
1588 // An anonymous block must be made to wrap this inline.
1589 RenderBlock* block = toRenderBlock(parent())->createAnonymousBlock();
1590 RenderObjectChildList* childlist = parent()->virtualChildren();
1591 childlist->insertChildNode(parent(), block, this);
1592 block->children()->appendChildNode(block, childlist->removeChildNode(parent(), this));
1593 }
1594 }
1595 }
1596
adjustStyleDifference(StyleDifference diff) const1597 StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff) const
1598 {
1599 if (diff.transformChanged() && isSVG())
1600 diff.setNeedsFullLayout();
1601
1602 // If transform changed, and the layer does not paint into its own separate backing, then we need to invalidate paints.
1603 if (diff.transformChanged()) {
1604 // Text nodes share style with their parents but transforms don't apply to them,
1605 // hence the !isText() check.
1606 if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->hasStyleDeterminedDirectCompositingReasons()))
1607 diff.setNeedsPaintInvalidationLayer();
1608 }
1609
1610 // If opacity or zIndex changed, and the layer does not paint into its own separate backing, then we need to invalidate paints (also
1611 // ignoring text nodes)
1612 if (diff.opacityChanged() || diff.zIndexChanged()) {
1613 if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->hasStyleDeterminedDirectCompositingReasons()))
1614 diff.setNeedsPaintInvalidationLayer();
1615 }
1616
1617 // If filter changed, and the layer does not paint into its own separate backing or it paints with filters, then we need to invalidate paints.
1618 if (diff.filterChanged() && hasLayer()) {
1619 RenderLayer* layer = toRenderLayerModelObject(this)->layer();
1620 if (!layer->hasStyleDeterminedDirectCompositingReasons() || layer->paintsWithFilters())
1621 diff.setNeedsPaintInvalidationLayer();
1622 }
1623
1624 if (diff.textOrColorChanged() && !diff.needsPaintInvalidation()
1625 && hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor())
1626 diff.setNeedsPaintInvalidationObject();
1627
1628 // The answer to layerTypeRequired() for plugins, iframes, and canvas can change without the actual
1629 // style changing, since it depends on whether we decide to composite these elements. When the
1630 // layer status of one of these elements changes, we need to force a layout.
1631 if (!diff.needsFullLayout() && style() && isLayerModelObject()) {
1632 bool requiresLayer = toRenderLayerModelObject(this)->layerTypeRequired() != NoLayer;
1633 if (hasLayer() != requiresLayer)
1634 diff.setNeedsFullLayout();
1635 }
1636
1637 // If we have no layer(), just treat a PaintInvalidationLayer hint as a normal paint invalidation.
1638 if (diff.needsPaintInvalidationLayer() && !hasLayer()) {
1639 diff.clearNeedsPaintInvalidation();
1640 diff.setNeedsPaintInvalidationObject();
1641 }
1642
1643 return diff;
1644 }
1645
setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle)1646 void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle)
1647 {
1648 ASSERT(pseudoStyle->styleType() == BEFORE || pseudoStyle->styleType() == AFTER);
1649
1650 // FIXME: We should consider just making all pseudo items use an inherited style.
1651
1652 // Images are special and must inherit the pseudoStyle so the width and height of
1653 // the pseudo element doesn't change the size of the image. In all other cases we
1654 // can just share the style.
1655 //
1656 // Quotes are also RenderInline, so we need to create an inherited style to avoid
1657 // getting an inline with positioning or an invalid display.
1658 //
1659 if (isImage() || isQuote()) {
1660 RefPtr<RenderStyle> style = RenderStyle::create();
1661 style->inheritFrom(pseudoStyle.get());
1662 setStyle(style.release());
1663 return;
1664 }
1665
1666 setStyle(pseudoStyle);
1667 }
1668
hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor() const1669 inline bool RenderObject::hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor() const
1670 {
1671 if (style()->hasBorder() || style()->hasOutline())
1672 return true;
1673 for (const RenderObject* r = slowFirstChild(); r; r = r->nextSibling()) {
1674 if (r->isText() && !toRenderText(r)->isAllCollapsibleWhitespace())
1675 return true;
1676 if (r->style()->hasOutline() || r->style()->hasBorder())
1677 return true;
1678 }
1679 return false;
1680 }
1681
markContainingBlocksForOverflowRecalc()1682 void RenderObject::markContainingBlocksForOverflowRecalc()
1683 {
1684 for (RenderBlock* container = containingBlock(); container && !container->childNeedsOverflowRecalcAfterStyleChange(); container = container->containingBlock())
1685 container->setChildNeedsOverflowRecalcAfterStyleChange(true);
1686 }
1687
setNeedsOverflowRecalcAfterStyleChange()1688 void RenderObject::setNeedsOverflowRecalcAfterStyleChange()
1689 {
1690 bool neededRecalc = needsOverflowRecalcAfterStyleChange();
1691 setSelfNeedsOverflowRecalcAfterStyleChange(true);
1692 if (!neededRecalc)
1693 markContainingBlocksForOverflowRecalc();
1694 }
1695
setStyle(PassRefPtr<RenderStyle> style)1696 void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
1697 {
1698 ASSERT(style);
1699
1700 if (m_style == style) {
1701 // We need to run through adjustStyleDifference() for iframes, plugins, and canvas so
1702 // style sharing is disabled for them. That should ensure that we never hit this code path.
1703 ASSERT(!isRenderIFrame() && !isEmbeddedObject() && !isCanvas());
1704 return;
1705 }
1706
1707 StyleDifference diff;
1708 if (m_style)
1709 diff = m_style->visualInvalidationDiff(*style);
1710
1711 diff = adjustStyleDifference(diff);
1712
1713 styleWillChange(diff, *style);
1714
1715 RefPtr<RenderStyle> oldStyle = m_style.release();
1716 setStyleInternal(style);
1717
1718 updateFillImages(oldStyle ? &oldStyle->backgroundLayers() : 0, m_style->backgroundLayers());
1719 updateFillImages(oldStyle ? &oldStyle->maskLayers() : 0, m_style->maskLayers());
1720
1721 updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style->borderImage().image());
1722 updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style->maskBoxImage().image());
1723
1724 updateShapeImage(oldStyle ? oldStyle->shapeOutside() : 0, m_style->shapeOutside());
1725
1726 bool doesNotNeedLayout = !m_parent || isText();
1727
1728 styleDidChange(diff, oldStyle.get());
1729
1730 // FIXME: |this| might be destroyed here. This can currently happen for a RenderTextFragment when
1731 // its first-letter block gets an update in RenderTextFragment::styleDidChange. For RenderTextFragment(s),
1732 // we will safely bail out with the doesNotNeedLayout flag. We might want to broaden this condition
1733 // in the future as we move renderer changes out of layout and into style changes.
1734 if (doesNotNeedLayout)
1735 return;
1736
1737 // Now that the layer (if any) has been updated, we need to adjust the diff again,
1738 // check whether we should layout now, and decide if we need to invalidate paints.
1739 StyleDifference updatedDiff = adjustStyleDifference(diff);
1740
1741 if (!diff.needsFullLayout()) {
1742 if (updatedDiff.needsFullLayout())
1743 setNeedsLayoutAndPrefWidthsRecalc();
1744 else if (updatedDiff.needsPositionedMovementLayout())
1745 setNeedsPositionedMovementLayout();
1746 }
1747
1748 if (diff.transformChanged() && !needsLayout()) {
1749 if (RenderBlock* container = containingBlock())
1750 container->setNeedsOverflowRecalcAfterStyleChange();
1751 }
1752
1753 if (updatedDiff.needsPaintInvalidationLayer())
1754 toRenderLayerModelObject(this)->layer()->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
1755 else if (diff.needsPaintInvalidationObject() || updatedDiff.needsPaintInvalidationObject())
1756 setShouldDoFullPaintInvalidation(true);
1757 }
1758
rendererHasBackground(const RenderObject * renderer)1759 static inline bool rendererHasBackground(const RenderObject* renderer)
1760 {
1761 return renderer && renderer->hasBackground();
1762 }
1763
styleWillChange(StyleDifference diff,const RenderStyle & newStyle)1764 void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
1765 {
1766 if (m_style) {
1767 // If our z-index changes value or our visibility changes,
1768 // we need to dirty our stacking context's z-order list.
1769 bool visibilityChanged = m_style->visibility() != newStyle.visibility()
1770 || m_style->zIndex() != newStyle.zIndex()
1771 || m_style->hasAutoZIndex() != newStyle.hasAutoZIndex();
1772 if (visibilityChanged) {
1773 document().setAnnotatedRegionsDirty(true);
1774 if (AXObjectCache* cache = document().existingAXObjectCache())
1775 cache->childrenChanged(parent());
1776 }
1777
1778 // Keep layer hierarchy visibility bits up to date if visibility changes.
1779 if (m_style->visibility() != newStyle.visibility()) {
1780 // We might not have an enclosing layer yet because we might not be in the tree.
1781 if (RenderLayer* layer = enclosingLayer())
1782 layer->potentiallyDirtyVisibleContentStatus(newStyle.visibility());
1783 }
1784
1785 if (isFloating() && (m_style->floating() != newStyle.floating()))
1786 // For changes in float styles, we need to conceivably remove ourselves
1787 // from the floating objects list.
1788 toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();
1789 else if (isOutOfFlowPositioned() && (m_style->position() != newStyle.position()))
1790 // For changes in positioning styles, we need to conceivably remove ourselves
1791 // from the positioned objects list.
1792 toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();
1793
1794 s_affectsParentBlock = isFloatingOrOutOfFlowPositioned()
1795 && (!newStyle.isFloating() && !newStyle.hasOutOfFlowPosition())
1796 && parent() && (parent()->isRenderBlockFlow() || parent()->isRenderInline());
1797
1798 // Clearing these bits is required to avoid leaving stale renderers.
1799 // FIXME: We shouldn't need that hack if our logic was totally correct.
1800 if (diff.needsLayout()) {
1801 setFloating(false);
1802 clearPositionedState();
1803 }
1804 } else {
1805 s_affectsParentBlock = false;
1806 }
1807
1808 if (view()->frameView()) {
1809 bool shouldBlitOnFixedBackgroundImage = false;
1810 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) {
1811 // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
1812 // when scrolling a page with a fixed background image. As an optimization, assuming there are
1813 // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
1814 // ignore the CSS property "background-attachment: fixed".
1815 shouldBlitOnFixedBackgroundImage = true;
1816 }
1817 bool newStyleSlowScroll = !shouldBlitOnFixedBackgroundImage && newStyle.hasFixedBackgroundImage();
1818 bool oldStyleSlowScroll = m_style && !shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage();
1819
1820 bool drawsRootBackground = isDocumentElement() || (isBody() && !rendererHasBackground(document().documentElement()->renderer()));
1821 if (drawsRootBackground && !shouldBlitOnFixedBackgroundImage) {
1822 if (view()->compositor()->supportsFixedRootBackgroundCompositing()) {
1823 if (newStyleSlowScroll && newStyle.hasEntirelyFixedBackground())
1824 newStyleSlowScroll = false;
1825
1826 if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground())
1827 oldStyleSlowScroll = false;
1828 }
1829 }
1830
1831 if (oldStyleSlowScroll != newStyleSlowScroll) {
1832 if (oldStyleSlowScroll)
1833 view()->frameView()->removeSlowRepaintObject();
1834 if (newStyleSlowScroll)
1835 view()->frameView()->addSlowRepaintObject();
1836 }
1837 }
1838
1839 // Elements with non-auto touch-action will send a SetTouchAction message
1840 // on touchstart in EventHandler::handleTouchEvent, and so effectively have
1841 // a touchstart handler that must be reported.
1842 //
1843 // Since a CSS property cannot be applied directly to a text node, a
1844 // handler will have already been added for its parent so ignore it.
1845 TouchAction oldTouchAction = m_style ? m_style->touchAction() : TouchActionAuto;
1846 if (node() && !node()->isTextNode() && (oldTouchAction == TouchActionAuto) != (newStyle.touchAction() == TouchActionAuto)) {
1847 EventHandlerRegistry& registry = document().frameHost()->eventHandlerRegistry();
1848 if (newStyle.touchAction() != TouchActionAuto)
1849 registry.didAddEventHandler(*node(), EventHandlerRegistry::TouchEvent);
1850 else
1851 registry.didRemoveEventHandler(*node(), EventHandlerRegistry::TouchEvent);
1852 }
1853 }
1854
areNonIdenticalCursorListsEqual(const RenderStyle * a,const RenderStyle * b)1855 static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b)
1856 {
1857 ASSERT(a->cursors() != b->cursors());
1858 return a->cursors() && b->cursors() && *a->cursors() == *b->cursors();
1859 }
1860
areCursorsEqual(const RenderStyle * a,const RenderStyle * b)1861 static inline bool areCursorsEqual(const RenderStyle* a, const RenderStyle* b)
1862 {
1863 return a->cursor() == b->cursor() && (a->cursors() == b->cursors() || areNonIdenticalCursorListsEqual(a, b));
1864 }
1865
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)1866 void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1867 {
1868 if (s_affectsParentBlock)
1869 handleDynamicFloatPositionChange();
1870
1871 if (!m_parent)
1872 return;
1873
1874 if (diff.needsFullLayout()) {
1875 RenderCounter::rendererStyleChanged(*this, oldStyle, m_style.get());
1876
1877 // If the object already needs layout, then setNeedsLayout won't do
1878 // any work. But if the containing block has changed, then we may need
1879 // to mark the new containing blocks for layout. The change that can
1880 // directly affect the containing block of this object is a change to
1881 // the position style.
1882 if (needsLayout() && oldStyle->position() != m_style->position())
1883 markContainingBlocksForLayout();
1884
1885 // Ditto.
1886 if (needsOverflowRecalcAfterStyleChange() && oldStyle->position() != m_style->position())
1887 markContainingBlocksForOverflowRecalc();
1888
1889 if (diff.needsFullLayout())
1890 setNeedsLayoutAndPrefWidthsRecalc();
1891 } else if (diff.needsPositionedMovementLayout())
1892 setNeedsPositionedMovementLayout();
1893
1894 // Don't check for paint invalidation here; we need to wait until the layer has been
1895 // updated by subclasses before we know if we have to invalidate paints (in setStyle()).
1896
1897 if (oldStyle && !areCursorsEqual(oldStyle, style())) {
1898 if (LocalFrame* frame = this->frame())
1899 frame->eventHandler().scheduleCursorUpdate();
1900 }
1901 }
1902
propagateStyleToAnonymousChildren(bool blockChildrenOnly)1903 void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly)
1904 {
1905 // FIXME: We could save this call when the change only affected non-inherited properties.
1906 for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
1907 if (!child->isAnonymous() || child->style()->styleType() != NOPSEUDO)
1908 continue;
1909
1910 if (blockChildrenOnly && !child->isRenderBlock())
1911 continue;
1912
1913 if (child->isRenderFullScreen() || child->isRenderFullScreenPlaceholder())
1914 continue;
1915
1916 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), child->style()->display());
1917 if (!document().regionBasedColumnsEnabled()) {
1918 if (style()->specifiesColumns()) {
1919 if (child->style()->specifiesColumns())
1920 newStyle->inheritColumnPropertiesFrom(style());
1921 if (child->style()->columnSpan())
1922 newStyle->setColumnSpan(ColumnSpanAll);
1923 }
1924 }
1925
1926 // Preserve the position style of anonymous block continuations as they can have relative position when
1927 // they contain block descendants of relative positioned inlines.
1928 if (child->isRelPositioned() && toRenderBlock(child)->isAnonymousBlockContinuation())
1929 newStyle->setPosition(child->style()->position());
1930
1931 updateAnonymousChildStyle(child, newStyle.get());
1932
1933 child->setStyle(newStyle.release());
1934 }
1935 }
1936
updateFillImages(const FillLayer * oldLayers,const FillLayer & newLayers)1937 void RenderObject::updateFillImages(const FillLayer* oldLayers, const FillLayer& newLayers)
1938 {
1939 // Optimize the common case
1940 if (oldLayers && !oldLayers->next() && !newLayers.next() && (oldLayers->image() == newLayers.image()))
1941 return;
1942
1943 // Go through the new layers and addClients first, to avoid removing all clients of an image.
1944 for (const FillLayer* currNew = &newLayers; currNew; currNew = currNew->next()) {
1945 if (currNew->image())
1946 currNew->image()->addClient(this);
1947 }
1948
1949 for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
1950 if (currOld->image())
1951 currOld->image()->removeClient(this);
1952 }
1953 }
1954
updateImage(StyleImage * oldImage,StyleImage * newImage)1955 void RenderObject::updateImage(StyleImage* oldImage, StyleImage* newImage)
1956 {
1957 if (oldImage != newImage) {
1958 if (oldImage)
1959 oldImage->removeClient(this);
1960 if (newImage)
1961 newImage->addClient(this);
1962 }
1963 }
1964
updateShapeImage(const ShapeValue * oldShapeValue,const ShapeValue * newShapeValue)1965 void RenderObject::updateShapeImage(const ShapeValue* oldShapeValue, const ShapeValue* newShapeValue)
1966 {
1967 if (oldShapeValue || newShapeValue)
1968 updateImage(oldShapeValue ? oldShapeValue->image() : 0, newShapeValue ? newShapeValue->image() : 0);
1969 }
1970
viewRect() const1971 LayoutRect RenderObject::viewRect() const
1972 {
1973 return view()->viewRect();
1974 }
1975
localToAbsolute(const FloatPoint & localPoint,MapCoordinatesFlags mode) const1976 FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode) const
1977 {
1978 TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
1979 mapLocalToContainer(0, transformState, mode | ApplyContainerFlip);
1980 transformState.flatten();
1981
1982 return transformState.lastPlanarPoint();
1983 }
1984
absoluteToLocal(const FloatPoint & containerPoint,MapCoordinatesFlags mode) const1985 FloatPoint RenderObject::absoluteToLocal(const FloatPoint& containerPoint, MapCoordinatesFlags mode) const
1986 {
1987 TransformState transformState(TransformState::UnapplyInverseTransformDirection, containerPoint);
1988 mapAbsoluteToLocalPoint(mode, transformState);
1989 transformState.flatten();
1990
1991 return transformState.lastPlanarPoint();
1992 }
1993
absoluteToLocalQuad(const FloatQuad & quad,MapCoordinatesFlags mode) const1994 FloatQuad RenderObject::absoluteToLocalQuad(const FloatQuad& quad, MapCoordinatesFlags mode) const
1995 {
1996 TransformState transformState(TransformState::UnapplyInverseTransformDirection, quad.boundingBox().center(), quad);
1997 mapAbsoluteToLocalPoint(mode, transformState);
1998 transformState.flatten();
1999 return transformState.lastPlanarQuad();
2000 }
2001
mapLocalToContainer(const RenderLayerModelObject * paintInvalidationContainer,TransformState & transformState,MapCoordinatesFlags mode,bool * wasFixed,const PaintInvalidationState * paintInvalidationState) const2002 void RenderObject::mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
2003 {
2004 if (paintInvalidationContainer == this)
2005 return;
2006
2007 RenderObject* o = parent();
2008 if (!o)
2009 return;
2010
2011 // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called.
2012 LayoutPoint centerPoint = roundedLayoutPoint(transformState.mappedPoint());
2013 if (mode & ApplyContainerFlip && o->isBox()) {
2014 if (o->style()->isFlippedBlocksWritingMode())
2015 transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedLayoutPoint(transformState.mappedPoint())) - centerPoint);
2016 mode &= ~ApplyContainerFlip;
2017 }
2018
2019 transformState.move(o->columnOffset(roundedLayoutPoint(transformState.mappedPoint())));
2020
2021 if (o->hasOverflowClip())
2022 transformState.move(-toRenderBox(o)->scrolledContentOffset());
2023
2024 o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState);
2025 }
2026
pushMappingToContainer(const RenderLayerModelObject * ancestorToStopAt,RenderGeometryMap & geometryMap) const2027 const RenderObject* RenderObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
2028 {
2029 ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != this);
2030
2031 RenderObject* container = parent();
2032 if (!container)
2033 return 0;
2034
2035 // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called.
2036 LayoutSize offset;
2037 if (container->hasOverflowClip())
2038 offset = -toRenderBox(container)->scrolledContentOffset();
2039
2040 geometryMap.push(this, offset, hasColumns());
2041
2042 return container;
2043 }
2044
mapAbsoluteToLocalPoint(MapCoordinatesFlags mode,TransformState & transformState) const2045 void RenderObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
2046 {
2047 RenderObject* o = parent();
2048 if (o) {
2049 o->mapAbsoluteToLocalPoint(mode, transformState);
2050 if (o->hasOverflowClip())
2051 transformState.move(toRenderBox(o)->scrolledContentOffset());
2052 }
2053 }
2054
shouldUseTransformFromContainer(const RenderObject * containerObject) const2055 bool RenderObject::shouldUseTransformFromContainer(const RenderObject* containerObject) const
2056 {
2057 // hasTransform() indicates whether the object has transform, transform-style or perspective. We just care about transform,
2058 // so check the layer's transform directly.
2059 return (hasLayer() && toRenderLayerModelObject(this)->layer()->transform()) || (containerObject && containerObject->style()->hasPerspective());
2060 }
2061
getTransformFromContainer(const RenderObject * containerObject,const LayoutSize & offsetInContainer,TransformationMatrix & transform) const2062 void RenderObject::getTransformFromContainer(const RenderObject* containerObject, const LayoutSize& offsetInContainer, TransformationMatrix& transform) const
2063 {
2064 transform.makeIdentity();
2065 transform.translate(offsetInContainer.width().toFloat(), offsetInContainer.height().toFloat());
2066 RenderLayer* layer = hasLayer() ? toRenderLayerModelObject(this)->layer() : 0;
2067 if (layer && layer->transform())
2068 transform.multiply(layer->currentTransform());
2069
2070 if (containerObject && containerObject->hasLayer() && containerObject->style()->hasPerspective()) {
2071 // Perpsective on the container affects us, so we have to factor it in here.
2072 ASSERT(containerObject->hasLayer());
2073 FloatPoint perspectiveOrigin = toRenderLayerModelObject(containerObject)->layer()->perspectiveOrigin();
2074
2075 TransformationMatrix perspectiveMatrix;
2076 perspectiveMatrix.applyPerspective(containerObject->style()->perspective());
2077
2078 transform.translateRight3d(-perspectiveOrigin.x(), -perspectiveOrigin.y(), 0);
2079 transform = perspectiveMatrix * transform;
2080 transform.translateRight3d(perspectiveOrigin.x(), perspectiveOrigin.y(), 0);
2081 }
2082 }
2083
localToContainerQuad(const FloatQuad & localQuad,const RenderLayerModelObject * paintInvalidationContainer,MapCoordinatesFlags mode,bool * wasFixed) const2084 FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const RenderLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed) const
2085 {
2086 // Track the point at the center of the quad's bounding box. As mapLocalToContainer() calls offsetFromContainer(),
2087 // it will use that point as the reference point to decide which column's transform to apply in multiple-column blocks.
2088 TransformState transformState(TransformState::ApplyTransformDirection, localQuad.boundingBox().center(), localQuad);
2089 mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
2090 transformState.flatten();
2091
2092 return transformState.lastPlanarQuad();
2093 }
2094
localToContainerPoint(const FloatPoint & localPoint,const RenderLayerModelObject * paintInvalidationContainer,MapCoordinatesFlags mode,bool * wasFixed,const PaintInvalidationState * paintInvalidationState) const2095 FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const RenderLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
2096 {
2097 TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
2098 mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed, paintInvalidationState);
2099 transformState.flatten();
2100
2101 return transformState.lastPlanarPoint();
2102 }
2103
localToInvalidationBackingPoint(const LayoutPoint & localPoint,RenderLayer ** backingLayer)2104 FloatPoint RenderObject::localToInvalidationBackingPoint(const LayoutPoint& localPoint, RenderLayer** backingLayer)
2105 {
2106 const RenderLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation();
2107 ASSERT(paintInvalidationContainer);
2108 RenderLayer* layer = paintInvalidationContainer->layer();
2109 ASSERT(layer);
2110
2111 if (backingLayer)
2112 *backingLayer = layer;
2113 FloatPoint containerPoint = localToContainerPoint(localPoint, paintInvalidationContainer, TraverseDocumentBoundaries);
2114
2115 if (layer->compositingState() == NotComposited) // This can happen for RenderFlowThread.
2116 return containerPoint;
2117
2118 RenderLayer::mapPointToPaintBackingCoordinates(paintInvalidationContainer, containerPoint);
2119 return containerPoint;
2120 }
2121
2122
offsetFromContainer(const RenderObject * o,const LayoutPoint & point,bool * offsetDependsOnPoint) const2123 LayoutSize RenderObject::offsetFromContainer(const RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
2124 {
2125 ASSERT(o == container());
2126
2127 LayoutSize offset = o->columnOffset(point);
2128
2129 if (o->hasOverflowClip())
2130 offset -= toRenderBox(o)->scrolledContentOffset();
2131
2132 if (offsetDependsOnPoint)
2133 *offsetDependsOnPoint = hasColumns() || o->isRenderFlowThread();
2134
2135 return offset;
2136 }
2137
offsetFromAncestorContainer(const RenderObject * container) const2138 LayoutSize RenderObject::offsetFromAncestorContainer(const RenderObject* container) const
2139 {
2140 LayoutSize offset;
2141 LayoutPoint referencePoint;
2142 const RenderObject* currContainer = this;
2143 do {
2144 const RenderObject* nextContainer = currContainer->container();
2145 ASSERT(nextContainer); // This means we reached the top without finding container.
2146 if (!nextContainer)
2147 break;
2148 ASSERT(!currContainer->hasTransform());
2149 LayoutSize currentOffset = currContainer->offsetFromContainer(nextContainer, referencePoint);
2150 offset += currentOffset;
2151 referencePoint.move(currentOffset);
2152 currContainer = nextContainer;
2153 } while (currContainer != container);
2154
2155 return offset;
2156 }
2157
localCaretRect(InlineBox *,int,LayoutUnit * extraWidthToEndOfLine)2158 LayoutRect RenderObject::localCaretRect(InlineBox*, int, LayoutUnit* extraWidthToEndOfLine)
2159 {
2160 if (extraWidthToEndOfLine)
2161 *extraWidthToEndOfLine = 0;
2162
2163 return LayoutRect();
2164 }
2165
computeLayerHitTestRects(LayerHitTestRects & layerRects) const2166 void RenderObject::computeLayerHitTestRects(LayerHitTestRects& layerRects) const
2167 {
2168 // Figure out what layer our container is in. Any offset (or new layer) for this
2169 // renderer within it's container will be applied in addLayerHitTestRects.
2170 LayoutPoint layerOffset;
2171 const RenderLayer* currentLayer = 0;
2172
2173 if (!hasLayer()) {
2174 RenderObject* container = this->container();
2175 currentLayer = container->enclosingLayer();
2176 if (container && currentLayer->renderer() != container) {
2177 layerOffset.move(container->offsetFromAncestorContainer(currentLayer->renderer()));
2178 // If the layer itself is scrolled, we have to undo the subtraction of its scroll
2179 // offset since we want the offset relative to the scrolling content, not the
2180 // element itself.
2181 if (currentLayer->renderer()->hasOverflowClip())
2182 layerOffset.move(currentLayer->renderBox()->scrolledContentOffset());
2183 }
2184 }
2185
2186 this->addLayerHitTestRects(layerRects, currentLayer, layerOffset, LayoutRect());
2187 }
2188
addLayerHitTestRects(LayerHitTestRects & layerRects,const RenderLayer * currentLayer,const LayoutPoint & layerOffset,const LayoutRect & containerRect) const2189 void RenderObject::addLayerHitTestRects(LayerHitTestRects& layerRects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
2190 {
2191 ASSERT(currentLayer);
2192 ASSERT(currentLayer == this->enclosingLayer());
2193
2194 // Compute the rects for this renderer only and add them to the results.
2195 // Note that we could avoid passing the offset and instead adjust each result, but this
2196 // seems slightly simpler.
2197 Vector<LayoutRect> ownRects;
2198 LayoutRect newContainerRect;
2199 computeSelfHitTestRects(ownRects, layerOffset);
2200
2201 // When we get to have a lot of rects on a layer, the performance cost of tracking those
2202 // rects outweighs the benefit of doing compositor thread hit testing.
2203 // FIXME: This limit needs to be low due to the O(n^2) algorithm in
2204 // WebLayer::setTouchEventHandlerRegion - crbug.com/300282.
2205 const size_t maxRectsPerLayer = 100;
2206
2207 LayerHitTestRects::iterator iter = layerRects.find(currentLayer);
2208 Vector<LayoutRect>* iterValue;
2209 if (iter == layerRects.end())
2210 iterValue = &layerRects.add(currentLayer, Vector<LayoutRect>()).storedValue->value;
2211 else
2212 iterValue = &iter->value;
2213 for (size_t i = 0; i < ownRects.size(); i++) {
2214 if (!containerRect.contains(ownRects[i])) {
2215 iterValue->append(ownRects[i]);
2216 if (iterValue->size() > maxRectsPerLayer) {
2217 // Just mark the entire layer instead, and switch to walking the layer
2218 // tree instead of the render tree.
2219 layerRects.remove(currentLayer);
2220 currentLayer->addLayerHitTestRects(layerRects);
2221 return;
2222 }
2223 if (newContainerRect.isEmpty())
2224 newContainerRect = ownRects[i];
2225 }
2226 }
2227 if (newContainerRect.isEmpty())
2228 newContainerRect = containerRect;
2229
2230 // If it's possible for children to have rects outside our bounds, then we need to descend into
2231 // the children and compute them.
2232 // Ideally there would be other cases where we could detect that children couldn't have rects
2233 // outside our bounds and prune the tree walk.
2234 // Note that we don't use Region here because Union is O(N) - better to just keep a list of
2235 // partially redundant rectangles. If we find examples where this is expensive, then we could
2236 // rewrite Region to be more efficient. See https://bugs.webkit.org/show_bug.cgi?id=100814.
2237 if (!isRenderView()) {
2238 for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) {
2239 curr->addLayerHitTestRects(layerRects, currentLayer, layerOffset, newContainerRect);
2240 }
2241 }
2242 }
2243
isRooted() const2244 bool RenderObject::isRooted() const
2245 {
2246 const RenderObject* object = this;
2247 while (object->parent() && !object->hasLayer())
2248 object = object->parent();
2249 if (object->hasLayer())
2250 return toRenderLayerModelObject(object)->layer()->root()->isRootLayer();
2251 return false;
2252 }
2253
rendererForRootBackground()2254 RenderObject* RenderObject::rendererForRootBackground()
2255 {
2256 ASSERT(isDocumentElement());
2257 if (!hasBackground() && isHTMLHtmlElement(node())) {
2258 // Locate the <body> element using the DOM. This is easier than trying
2259 // to crawl around a render tree with potential :before/:after content and
2260 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
2261 // render object very easily via the DOM.
2262 HTMLElement* body = document().body();
2263 RenderObject* bodyObject = isHTMLBodyElement(body) ? body->renderer() : 0;
2264 if (bodyObject)
2265 return bodyObject;
2266 }
2267
2268 return this;
2269 }
2270
shouldRespectImageOrientation() const2271 RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const
2272 {
2273 // Respect the image's orientation if it's being used as a full-page image or it's
2274 // an <img> and the setting to respect it everywhere is set.
2275 return document().isImageDocument()
2276 || (document().settings() && document().settings()->shouldRespectImageOrientation() && isHTMLImageElement(node())) ? RespectImageOrientation : DoNotRespectImageOrientation;
2277 }
2278
hasEntirelyFixedBackground() const2279 bool RenderObject::hasEntirelyFixedBackground() const
2280 {
2281 return m_style->hasEntirelyFixedBackground();
2282 }
2283
container(const RenderLayerModelObject * paintInvalidationContainer,bool * paintInvalidationContainerSkipped) const2284 RenderObject* RenderObject::container(const RenderLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const
2285 {
2286 if (paintInvalidationContainerSkipped)
2287 *paintInvalidationContainerSkipped = false;
2288
2289 // This method is extremely similar to containingBlock(), but with a few notable
2290 // exceptions.
2291 // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2292 // the object is not part of the primary document subtree yet.
2293 // (2) For normal flow elements, it just returns the parent.
2294 // (3) For absolute positioned elements, it will return a relative positioned inline.
2295 // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2296 // the layout of the positioned object. This does mean that computePositionedLogicalWidth and
2297 // computePositionedLogicalHeight have to use container().
2298 RenderObject* o = parent();
2299
2300 if (isText())
2301 return o;
2302
2303 EPosition pos = m_style->position();
2304 if (pos == FixedPosition) {
2305 return containerForFixedPosition(paintInvalidationContainer, paintInvalidationContainerSkipped);
2306 } else if (pos == AbsolutePosition) {
2307 // We technically just want our containing block, but
2308 // we may not have one if we're part of an uninstalled
2309 // subtree. We'll climb as high as we can though.
2310 while (o) {
2311 if (o->style()->position() != StaticPosition)
2312 break;
2313
2314 if (o->canContainFixedPositionObjects())
2315 break;
2316
2317 if (paintInvalidationContainerSkipped && o == paintInvalidationContainer)
2318 *paintInvalidationContainerSkipped = true;
2319
2320 o = o->parent();
2321 }
2322 }
2323
2324 return o;
2325 }
2326
isSelectionBorder() const2327 bool RenderObject::isSelectionBorder() const
2328 {
2329 SelectionState st = selectionState();
2330 return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
2331 }
2332
clearLayoutRootIfNeeded() const2333 inline void RenderObject::clearLayoutRootIfNeeded() const
2334 {
2335 if (frame()) {
2336 if (FrameView* view = frame()->view()) {
2337 if (view->layoutRoot() == this) {
2338 if (!documentBeingDestroyed())
2339 ASSERT_NOT_REACHED();
2340 // This indicates a failure to layout the child, which is why
2341 // the layout root is still set to |this|. Make sure to clear it
2342 // since we are getting destroyed.
2343 view->clearLayoutSubtreeRoot();
2344 }
2345 }
2346 }
2347 }
2348
willBeDestroyed()2349 void RenderObject::willBeDestroyed()
2350 {
2351 // Destroy any leftover anonymous children.
2352 RenderObjectChildList* children = virtualChildren();
2353 if (children)
2354 children->destroyLeftoverChildren();
2355
2356 // If this renderer is being autoscrolled, stop the autoscrolling.
2357 if (LocalFrame* frame = this->frame()) {
2358 if (frame->page())
2359 frame->page()->autoscrollController().stopAutoscrollIfNeeded(this);
2360 }
2361
2362 // For accessibility management, notify the parent of the imminent change to its child set.
2363 // We do it now, before remove(), while the parent pointer is still available.
2364 if (AXObjectCache* cache = document().existingAXObjectCache())
2365 cache->childrenChanged(this->parent());
2366
2367 remove();
2368
2369 // The remove() call above may invoke axObjectCache()->childrenChanged() on the parent, which may require the AX render
2370 // object for this renderer. So we remove the AX render object now, after the renderer is removed.
2371 if (AXObjectCache* cache = document().existingAXObjectCache())
2372 cache->remove(this);
2373
2374 // If this renderer had a parent, remove should have destroyed any counters
2375 // attached to this renderer and marked the affected other counters for
2376 // reevaluation. This apparently redundant check is here for the case when
2377 // this renderer had no parent at the time remove() was called.
2378
2379 if (hasCounterNodeMap())
2380 RenderCounter::destroyCounterNodes(*this);
2381
2382 // Remove the handler if node had touch-action set. Don't call when
2383 // document is being destroyed as all handlers will have been cleared
2384 // previously. Handlers are not added for text nodes so don't try removing
2385 // for one too. Need to check if m_style is null in cases of partial construction.
2386 if (!documentBeingDestroyed() && node() && !node()->isTextNode() && m_style && m_style->touchAction() != TouchActionAuto)
2387 document().frameHost()->eventHandlerRegistry().didRemoveEventHandler(*node(), EventHandlerRegistry::TouchEvent);
2388
2389 setAncestorLineBoxDirty(false);
2390
2391 clearLayoutRootIfNeeded();
2392 }
2393
insertedIntoTree()2394 void RenderObject::insertedIntoTree()
2395 {
2396 // FIXME: We should ASSERT(isRooted()) here but generated content makes some out-of-order insertion.
2397
2398 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
2399 // and don't have a layer attached to ourselves.
2400 RenderLayer* layer = 0;
2401 if (slowFirstChild() || hasLayer()) {
2402 layer = parent()->enclosingLayer();
2403 addLayers(layer);
2404 }
2405
2406 // If |this| is visible but this object was not, tell the layer it has some visible content
2407 // that needs to be drawn and layer visibility optimization can't be used
2408 if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
2409 if (!layer)
2410 layer = parent()->enclosingLayer();
2411 if (layer)
2412 layer->dirtyVisibleContentStatus();
2413 }
2414
2415 if (!isFloating() && parent()->childrenInline())
2416 parent()->dirtyLinesFromChangedChild(this);
2417 }
2418
willBeRemovedFromTree()2419 void RenderObject::willBeRemovedFromTree()
2420 {
2421 // FIXME: We should ASSERT(isRooted()) but we have some out-of-order removals which would need to be fixed first.
2422
2423 // If we remove a visible child from an invisible parent, we don't know the layer visibility any more.
2424 RenderLayer* layer = 0;
2425 if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
2426 layer = parent()->enclosingLayer();
2427 if (layer)
2428 layer->dirtyVisibleContentStatus();
2429 }
2430
2431 // Keep our layer hierarchy updated.
2432 if (slowFirstChild() || hasLayer()) {
2433 if (!layer)
2434 layer = parent()->enclosingLayer();
2435 removeLayers(layer);
2436 }
2437
2438 if (isOutOfFlowPositioned() && parent()->childrenInline())
2439 parent()->dirtyLinesFromChangedChild(this);
2440
2441 removeFromRenderFlowThread();
2442
2443 // Update cached boundaries in SVG renderers if a child is removed.
2444 if (parent()->isSVG())
2445 parent()->setNeedsBoundariesUpdate();
2446 }
2447
removeFromRenderFlowThread()2448 void RenderObject::removeFromRenderFlowThread()
2449 {
2450 if (flowThreadState() == NotInsideFlowThread)
2451 return;
2452
2453 // Sometimes we remove the element from the flow, but it's not destroyed at that time.
2454 // It's only until later when we actually destroy it and remove all the children from it.
2455 // Currently, that happens for firstLetter elements and list markers.
2456 // Pass in the flow thread so that we don't have to look it up for all the children.
2457 removeFromRenderFlowThreadRecursive(flowThreadContainingBlock());
2458 }
2459
removeFromRenderFlowThreadRecursive(RenderFlowThread * renderFlowThread)2460 void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderFlowThread)
2461 {
2462 if (const RenderObjectChildList* children = virtualChildren()) {
2463 for (RenderObject* child = children->firstChild(); child; child = child->nextSibling())
2464 child->removeFromRenderFlowThreadRecursive(renderFlowThread);
2465 }
2466
2467 setFlowThreadState(NotInsideFlowThread);
2468 }
2469
destroyAndCleanupAnonymousWrappers()2470 void RenderObject::destroyAndCleanupAnonymousWrappers()
2471 {
2472 // If the tree is destroyed, there is no need for a clean-up phase.
2473 if (documentBeingDestroyed()) {
2474 destroy();
2475 return;
2476 }
2477
2478 RenderObject* destroyRoot = this;
2479 for (RenderObject* destroyRootParent = destroyRoot->parent(); destroyRootParent && destroyRootParent->isAnonymous(); destroyRoot = destroyRootParent, destroyRootParent = destroyRootParent->parent()) {
2480 // Anonymous block continuations are tracked and destroyed elsewhere (see the bottom of RenderBlock::removeChild)
2481 if (destroyRootParent->isRenderBlock() && toRenderBlock(destroyRootParent)->isAnonymousBlockContinuation())
2482 break;
2483 // Render flow threads are tracked by the FlowThreadController, so we can't destroy them here.
2484 // Column spans are tracked elsewhere.
2485 if (destroyRootParent->isRenderFlowThread() || destroyRootParent->isAnonymousColumnSpanBlock())
2486 break;
2487
2488 if (destroyRootParent->slowFirstChild() != destroyRoot || destroyRootParent->slowLastChild() != destroyRoot)
2489 break; // Need to keep the anonymous parent, since it won't become empty by the removal of this renderer.
2490 }
2491
2492 destroyRoot->destroy();
2493
2494 // WARNING: |this| is deleted here.
2495 }
2496
destroy()2497 void RenderObject::destroy()
2498 {
2499 #if ENABLE(ASSERT) && ENABLE(OILPAN)
2500 ASSERT(!m_didCallDestroy);
2501 m_didCallDestroy = true;
2502 #endif
2503 willBeDestroyed();
2504 postDestroy();
2505 }
2506
removeShapeImageClient(ShapeValue * shapeValue)2507 void RenderObject::removeShapeImageClient(ShapeValue* shapeValue)
2508 {
2509 if (!shapeValue)
2510 return;
2511 if (StyleImage* shapeImage = shapeValue->image())
2512 shapeImage->removeClient(this);
2513 }
2514
postDestroy()2515 void RenderObject::postDestroy()
2516 {
2517 // It seems ugly that this is not in willBeDestroyed().
2518 if (m_style) {
2519 for (const FillLayer* bgLayer = &m_style->backgroundLayers(); bgLayer; bgLayer = bgLayer->next()) {
2520 if (StyleImage* backgroundImage = bgLayer->image())
2521 backgroundImage->removeClient(this);
2522 }
2523
2524 for (const FillLayer* maskLayer = &m_style->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
2525 if (StyleImage* maskImage = maskLayer->image())
2526 maskImage->removeClient(this);
2527 }
2528
2529 if (StyleImage* borderImage = m_style->borderImage().image())
2530 borderImage->removeClient(this);
2531
2532 if (StyleImage* maskBoxImage = m_style->maskBoxImage().image())
2533 maskBoxImage->removeClient(this);
2534
2535 removeShapeImageClient(m_style->shapeOutside());
2536 }
2537 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeRenderObject(this);
2538 #if !ENABLE(OILPAN)
2539 delete this;
2540 #endif
2541 }
2542
positionForPoint(const LayoutPoint &)2543 PositionWithAffinity RenderObject::positionForPoint(const LayoutPoint&)
2544 {
2545 return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
2546 }
2547
updateDragState(bool dragOn)2548 void RenderObject::updateDragState(bool dragOn)
2549 {
2550 bool valueChanged = (dragOn != isDragging());
2551 setIsDragging(dragOn);
2552 if (valueChanged && node()) {
2553 if (node()->isElementNode() && toElement(node())->childrenOrSiblingsAffectedByDrag())
2554 node()->setNeedsStyleRecalc(SubtreeStyleChange);
2555 else if (style()->affectedByDrag())
2556 node()->setNeedsStyleRecalc(LocalStyleChange);
2557 }
2558 for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
2559 curr->updateDragState(dragOn);
2560 }
2561
compositingState() const2562 CompositingState RenderObject::compositingState() const
2563 {
2564 return hasLayer() ? toRenderLayerModelObject(this)->layer()->compositingState() : NotComposited;
2565 }
2566
additionalCompositingReasons() const2567 CompositingReasons RenderObject::additionalCompositingReasons() const
2568 {
2569 return CompositingReasonNone;
2570 }
2571
hitTest(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,HitTestFilter hitTestFilter)2572 bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter)
2573 {
2574 bool inside = false;
2575 if (hitTestFilter != HitTestSelf) {
2576 // First test the foreground layer (lines and inlines).
2577 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestForeground);
2578
2579 // Test floats next.
2580 if (!inside)
2581 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestFloat);
2582
2583 // Finally test to see if the mouse is in the background (within a child block's background).
2584 if (!inside)
2585 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestChildBlockBackgrounds);
2586 }
2587
2588 // See if the mouse is inside us but not any of our descendants
2589 if (hitTestFilter != HitTestDescendants && !inside)
2590 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestBlockBackground);
2591
2592 return inside;
2593 }
2594
updateHitTestResult(HitTestResult & result,const LayoutPoint & point)2595 void RenderObject::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
2596 {
2597 if (result.innerNode())
2598 return;
2599
2600 Node* node = this->node();
2601
2602 // If we hit the anonymous renderers inside generated content we should
2603 // actually hit the generated content so walk up to the PseudoElement.
2604 if (!node && parent() && parent()->isBeforeOrAfterContent()) {
2605 for (RenderObject* renderer = parent(); renderer && !node; renderer = renderer->parent())
2606 node = renderer->node();
2607 }
2608
2609 if (node) {
2610 result.setInnerNode(node);
2611 if (!result.innerNonSharedNode())
2612 result.setInnerNonSharedNode(node);
2613 result.setLocalPoint(point);
2614 }
2615 }
2616
nodeAtPoint(const HitTestRequest &,HitTestResult &,const HitTestLocation &,const LayoutPoint &,HitTestAction)2617 bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& /*locationInContainer*/, const LayoutPoint& /*accumulatedOffset*/, HitTestAction)
2618 {
2619 return false;
2620 }
2621
scheduleRelayout()2622 void RenderObject::scheduleRelayout()
2623 {
2624 if (isRenderView()) {
2625 FrameView* view = toRenderView(this)->frameView();
2626 if (view)
2627 view->scheduleRelayout();
2628 } else {
2629 if (isRooted()) {
2630 if (RenderView* renderView = view()) {
2631 if (FrameView* frameView = renderView->frameView())
2632 frameView->scheduleRelayoutOfSubtree(this);
2633 }
2634 }
2635 }
2636 }
2637
forceLayout()2638 void RenderObject::forceLayout()
2639 {
2640 setSelfNeedsLayout(true);
2641 setShouldDoFullPaintInvalidation(true);
2642 layout();
2643 }
2644
2645 // FIXME: Does this do anything different than forceLayout given that we don't walk
2646 // the containing block chain. If not, we should change all callers to use forceLayout.
forceChildLayout()2647 void RenderObject::forceChildLayout()
2648 {
2649 setNormalChildNeedsLayout(true);
2650 layout();
2651 }
2652
2653 enum StyleCacheState {
2654 Cached,
2655 Uncached
2656 };
2657
firstLineStyleForCachedUncachedType(StyleCacheState type,const RenderObject * renderer,RenderStyle * style)2658 static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheState type, const RenderObject* renderer, RenderStyle* style)
2659 {
2660 const RenderObject* rendererForFirstLineStyle = renderer;
2661 if (renderer->isBeforeOrAfterContent())
2662 rendererForFirstLineStyle = renderer->parent();
2663
2664 if (rendererForFirstLineStyle->isRenderBlockFlow() || rendererForFirstLineStyle->isRenderButton()) {
2665 if (RenderBlock* firstLineBlock = rendererForFirstLineStyle->firstLineBlock()) {
2666 if (type == Cached)
2667 return firstLineBlock->getCachedPseudoStyle(FIRST_LINE, style);
2668 return firstLineBlock->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE), style, firstLineBlock == renderer ? style : 0);
2669 }
2670 } else if (!rendererForFirstLineStyle->isAnonymous() && rendererForFirstLineStyle->isRenderInline()) {
2671 RenderStyle* parentStyle = rendererForFirstLineStyle->parent()->firstLineStyle();
2672 if (parentStyle != rendererForFirstLineStyle->parent()->style()) {
2673 if (type == Cached) {
2674 // A first-line style is in effect. Cache a first-line style for ourselves.
2675 rendererForFirstLineStyle->style()->setHasPseudoStyle(FIRST_LINE_INHERITED);
2676 return rendererForFirstLineStyle->getCachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle);
2677 }
2678 return rendererForFirstLineStyle->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), parentStyle, style);
2679 }
2680 }
2681 return nullptr;
2682 }
2683
uncachedFirstLineStyle(RenderStyle * style) const2684 PassRefPtr<RenderStyle> RenderObject::uncachedFirstLineStyle(RenderStyle* style) const
2685 {
2686 if (!document().styleEngine()->usesFirstLineRules())
2687 return nullptr;
2688
2689 ASSERT(!isText());
2690
2691 return firstLineStyleForCachedUncachedType(Uncached, this, style);
2692 }
2693
cachedFirstLineStyle() const2694 RenderStyle* RenderObject::cachedFirstLineStyle() const
2695 {
2696 ASSERT(document().styleEngine()->usesFirstLineRules());
2697
2698 if (RefPtr<RenderStyle> style = firstLineStyleForCachedUncachedType(Cached, isText() ? parent() : this, m_style.get()))
2699 return style.get();
2700
2701 return m_style.get();
2702 }
2703
getCachedPseudoStyle(PseudoId pseudo,RenderStyle * parentStyle) const2704 RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle) const
2705 {
2706 if (pseudo < FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo))
2707 return 0;
2708
2709 RenderStyle* cachedStyle = style()->getCachedPseudoStyle(pseudo);
2710 if (cachedStyle)
2711 return cachedStyle;
2712
2713 RefPtr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle);
2714 if (result)
2715 return style()->addCachedPseudoStyle(result.release());
2716 return 0;
2717 }
2718
getUncachedPseudoStyle(const PseudoStyleRequest & pseudoStyleRequest,RenderStyle * parentStyle,RenderStyle * ownStyle) const2719 PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const
2720 {
2721 if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId))
2722 return nullptr;
2723
2724 if (!parentStyle) {
2725 ASSERT(!ownStyle);
2726 parentStyle = style();
2727 }
2728
2729 if (!node())
2730 return nullptr;
2731
2732 Element* element = Traversal<Element>::firstAncestorOrSelf(*node());
2733 if (!element)
2734 return nullptr;
2735
2736 if (pseudoStyleRequest.pseudoId == FIRST_LINE_INHERITED) {
2737 RefPtr<RenderStyle> result = document().ensureStyleResolver().styleForElement(element, parentStyle, DisallowStyleSharing);
2738 result->setStyleType(FIRST_LINE_INHERITED);
2739 return result.release();
2740 }
2741
2742 return document().ensureStyleResolver().pseudoStyleForElement(element, pseudoStyleRequest, parentStyle);
2743 }
2744
getUncachedPseudoStyleFromParentOrShadowHost() const2745 PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyleFromParentOrShadowHost() const
2746 {
2747 if (!node())
2748 return nullptr;
2749
2750 if (ShadowRoot* root = node()->containingShadowRoot()) {
2751 if (root->type() == ShadowRoot::UserAgentShadowRoot) {
2752 if (Element* shadowHost = node()->shadowHost()) {
2753 return shadowHost->renderer()->getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
2754 }
2755 }
2756 }
2757
2758 return getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
2759 }
2760
hasBlendMode() const2761 bool RenderObject::hasBlendMode() const
2762 {
2763 return RuntimeEnabledFeatures::cssCompositingEnabled() && style() && style()->hasBlendMode();
2764 }
2765
getTextDecorations(unsigned decorations,AppliedTextDecoration & underline,AppliedTextDecoration & overline,AppliedTextDecoration & linethrough,bool quirksMode,bool firstlineStyle)2766 void RenderObject::getTextDecorations(unsigned decorations, AppliedTextDecoration& underline, AppliedTextDecoration& overline, AppliedTextDecoration& linethrough, bool quirksMode, bool firstlineStyle)
2767 {
2768 RenderObject* curr = this;
2769 RenderStyle* styleToUse = 0;
2770 unsigned currDecs = TextDecorationNone;
2771 Color resultColor;
2772 TextDecorationStyle resultStyle;
2773 do {
2774 styleToUse = curr->style(firstlineStyle);
2775 currDecs = styleToUse->textDecoration();
2776 currDecs &= decorations;
2777 resultColor = styleToUse->visitedDependentDecorationColor();
2778 resultStyle = styleToUse->textDecorationStyle();
2779 // Parameter 'decorations' is cast as an int to enable the bitwise operations below.
2780 if (currDecs) {
2781 if (currDecs & TextDecorationUnderline) {
2782 decorations &= ~TextDecorationUnderline;
2783 underline.color = resultColor;
2784 underline.style = resultStyle;
2785 }
2786 if (currDecs & TextDecorationOverline) {
2787 decorations &= ~TextDecorationOverline;
2788 overline.color = resultColor;
2789 overline.style = resultStyle;
2790 }
2791 if (currDecs & TextDecorationLineThrough) {
2792 decorations &= ~TextDecorationLineThrough;
2793 linethrough.color = resultColor;
2794 linethrough.style = resultStyle;
2795 }
2796 }
2797 if (curr->isRubyText())
2798 return;
2799 curr = curr->parent();
2800 if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation())
2801 curr = toRenderBlock(curr)->continuation();
2802 } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(*curr->node()) && !isHTMLFontElement(*curr->node()))));
2803
2804 // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2805 if (decorations && curr) {
2806 styleToUse = curr->style(firstlineStyle);
2807 resultColor = styleToUse->visitedDependentDecorationColor();
2808 if (decorations & TextDecorationUnderline) {
2809 underline.color = resultColor;
2810 underline.style = resultStyle;
2811 }
2812 if (decorations & TextDecorationOverline) {
2813 overline.color = resultColor;
2814 overline.style = resultStyle;
2815 }
2816 if (decorations & TextDecorationLineThrough) {
2817 linethrough.color = resultColor;
2818 linethrough.style = resultStyle;
2819 }
2820 }
2821 }
2822
addAnnotatedRegions(Vector<AnnotatedRegionValue> & regions)2823 void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
2824 {
2825 // Convert the style regions to absolute coordinates.
2826 if (style()->visibility() != VISIBLE || !isBox())
2827 return;
2828
2829 if (style()->getDraggableRegionMode() == DraggableRegionNone)
2830 return;
2831
2832 RenderBox* box = toRenderBox(this);
2833 FloatRect localBounds(FloatPoint(), FloatSize(box->width().toFloat(), box->height().toFloat()));
2834 FloatRect absBounds = localToAbsoluteQuad(localBounds).boundingBox();
2835
2836 AnnotatedRegionValue region;
2837 region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
2838 region.bounds = LayoutRect(absBounds);
2839 regions.append(region);
2840 }
2841
collectAnnotatedRegions(Vector<AnnotatedRegionValue> & regions)2842 void RenderObject::collectAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
2843 {
2844 // RenderTexts don't have their own style, they just use their parent's style,
2845 // so we don't want to include them.
2846 if (isText())
2847 return;
2848
2849 addAnnotatedRegions(regions);
2850 for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
2851 curr->collectAnnotatedRegions(regions);
2852 }
2853
willRenderImage(ImageResource *)2854 bool RenderObject::willRenderImage(ImageResource*)
2855 {
2856 // Without visibility we won't render (and therefore don't care about animation).
2857 if (style()->visibility() != VISIBLE)
2858 return false;
2859
2860 // We will not render a new image when Active DOM is suspended
2861 if (document().activeDOMObjectsAreSuspended())
2862 return false;
2863
2864 // If we're not in a window (i.e., we're dormant from being in a background tab)
2865 // then we don't want to render either.
2866 return document().view()->isVisible();
2867 }
2868
caretMinOffset() const2869 int RenderObject::caretMinOffset() const
2870 {
2871 return 0;
2872 }
2873
caretMaxOffset() const2874 int RenderObject::caretMaxOffset() const
2875 {
2876 if (isReplaced())
2877 return node() ? std::max(1U, node()->countChildren()) : 1;
2878 if (isHR())
2879 return 1;
2880 return 0;
2881 }
2882
previousOffset(int current) const2883 int RenderObject::previousOffset(int current) const
2884 {
2885 return current - 1;
2886 }
2887
previousOffsetForBackwardDeletion(int current) const2888 int RenderObject::previousOffsetForBackwardDeletion(int current) const
2889 {
2890 return current - 1;
2891 }
2892
nextOffset(int current) const2893 int RenderObject::nextOffset(int current) const
2894 {
2895 return current + 1;
2896 }
2897
isInert() const2898 bool RenderObject::isInert() const
2899 {
2900 const RenderObject* renderer = this;
2901 while (!renderer->node())
2902 renderer = renderer->parent();
2903 return renderer->node()->isInert();
2904 }
2905
2906 // touch-action applies to all elements with both width AND height properties.
2907 // According to the CSS Box Model Spec (http://dev.w3.org/csswg/css-box/#the-width-and-height-properties)
2908 // width applies to all elements but non-replaced inline elements, table rows, and row groups and
2909 // height applies to all elements but non-replaced inline elements, table columns, and column groups.
supportsTouchAction() const2910 bool RenderObject::supportsTouchAction() const
2911 {
2912 if (isInline() && !isReplaced())
2913 return false;
2914 if (isTableRow() || isRenderTableCol())
2915 return false;
2916
2917 return true;
2918 }
2919
imageChanged(ImageResource * image,const IntRect * rect)2920 void RenderObject::imageChanged(ImageResource* image, const IntRect* rect)
2921 {
2922 imageChanged(static_cast<WrappedImagePtr>(image), rect);
2923 }
2924
offsetParent() const2925 Element* RenderObject::offsetParent() const
2926 {
2927 if (isDocumentElement() || isBody())
2928 return 0;
2929
2930 if (isOutOfFlowPositioned() && style()->position() == FixedPosition)
2931 return 0;
2932
2933 // If A is an area HTML element which has a map HTML element somewhere in the ancestor
2934 // chain return the nearest ancestor map HTML element and stop this algorithm.
2935 // FIXME: Implement!
2936
2937 float effectiveZoom = style()->effectiveZoom();
2938 Node* node = 0;
2939 for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
2940 // Spec: http://www.w3.org/TR/cssom-view/#offset-attributes
2941
2942 node = ancestor->node();
2943
2944 if (!node)
2945 continue;
2946
2947 if (ancestor->isPositioned())
2948 break;
2949
2950 if (isHTMLBodyElement(*node))
2951 break;
2952
2953 if (!isPositioned() && (isHTMLTableElement(*node) || isHTMLTableCellElement(*node)))
2954 break;
2955
2956 // Webkit specific extension where offsetParent stops at zoom level changes.
2957 if (effectiveZoom != ancestor->style()->effectiveZoom())
2958 break;
2959 }
2960
2961 return node && node->isElementNode() ? toElement(node) : 0;
2962 }
2963
createPositionWithAffinity(int offset,EAffinity affinity)2964 PositionWithAffinity RenderObject::createPositionWithAffinity(int offset, EAffinity affinity)
2965 {
2966 // If this is a non-anonymous renderer in an editable area, then it's simple.
2967 if (Node* node = nonPseudoNode()) {
2968 if (!node->hasEditableStyle()) {
2969 // If it can be found, we prefer a visually equivalent position that is editable.
2970 Position position = createLegacyEditingPosition(node, offset);
2971 Position candidate = position.downstream(CanCrossEditingBoundary);
2972 if (candidate.deprecatedNode()->hasEditableStyle())
2973 return PositionWithAffinity(candidate, affinity);
2974 candidate = position.upstream(CanCrossEditingBoundary);
2975 if (candidate.deprecatedNode()->hasEditableStyle())
2976 return PositionWithAffinity(candidate, affinity);
2977 }
2978 // FIXME: Eliminate legacy editing positions
2979 return PositionWithAffinity(createLegacyEditingPosition(node, offset), affinity);
2980 }
2981
2982 // We don't want to cross the boundary between editable and non-editable
2983 // regions of the document, but that is either impossible or at least
2984 // extremely unlikely in any normal case because we stop as soon as we
2985 // find a single non-anonymous renderer.
2986
2987 // Find a nearby non-anonymous renderer.
2988 RenderObject* child = this;
2989 while (RenderObject* parent = child->parent()) {
2990 // Find non-anonymous content after.
2991 for (RenderObject* renderer = child->nextInPreOrder(parent); renderer; renderer = renderer->nextInPreOrder(parent)) {
2992 if (Node* node = renderer->nonPseudoNode())
2993 return PositionWithAffinity(firstPositionInOrBeforeNode(node), DOWNSTREAM);
2994 }
2995
2996 // Find non-anonymous content before.
2997 for (RenderObject* renderer = child->previousInPreOrder(); renderer; renderer = renderer->previousInPreOrder()) {
2998 if (renderer == parent)
2999 break;
3000 if (Node* node = renderer->nonPseudoNode())
3001 return PositionWithAffinity(lastPositionInOrAfterNode(node), DOWNSTREAM);
3002 }
3003
3004 // Use the parent itself unless it too is anonymous.
3005 if (Node* node = parent->nonPseudoNode())
3006 return PositionWithAffinity(firstPositionInOrBeforeNode(node), DOWNSTREAM);
3007
3008 // Repeat at the next level up.
3009 child = parent;
3010 }
3011
3012 // Everything was anonymous. Give up.
3013 return PositionWithAffinity();
3014 }
3015
createPositionWithAffinity(const Position & position)3016 PositionWithAffinity RenderObject::createPositionWithAffinity(const Position& position)
3017 {
3018 if (position.isNotNull())
3019 return PositionWithAffinity(position);
3020
3021 ASSERT(!node());
3022 return createPositionWithAffinity(0, DOWNSTREAM);
3023 }
3024
getCursor(const LayoutPoint &,Cursor &) const3025 CursorDirective RenderObject::getCursor(const LayoutPoint&, Cursor&) const
3026 {
3027 return SetCursorBasedOnStyle;
3028 }
3029
canUpdateSelectionOnRootLineBoxes()3030 bool RenderObject::canUpdateSelectionOnRootLineBoxes()
3031 {
3032 if (needsLayout())
3033 return false;
3034
3035 RenderBlock* containingBlock = this->containingBlock();
3036 return containingBlock ? !containingBlock->needsLayout() : false;
3037 }
3038
3039 // We only create "generated" child renderers like one for first-letter if:
3040 // - the firstLetterBlock can have children in the DOM and
3041 // - the block doesn't have any special assumption on its text children.
3042 // This correctly prevents form controls from having such renderers.
canHaveGeneratedChildren() const3043 bool RenderObject::canHaveGeneratedChildren() const
3044 {
3045 return canHaveChildren();
3046 }
3047
setNeedsBoundariesUpdate()3048 void RenderObject::setNeedsBoundariesUpdate()
3049 {
3050 if (RenderObject* renderer = parent())
3051 renderer->setNeedsBoundariesUpdate();
3052 }
3053
objectBoundingBox() const3054 FloatRect RenderObject::objectBoundingBox() const
3055 {
3056 ASSERT_NOT_REACHED();
3057 return FloatRect();
3058 }
3059
strokeBoundingBox() const3060 FloatRect RenderObject::strokeBoundingBox() const
3061 {
3062 ASSERT_NOT_REACHED();
3063 return FloatRect();
3064 }
3065
3066 // Returns the smallest rectangle enclosing all of the painted content
3067 // respecting clipping, masking, filters, opacity, stroke-width and markers
paintInvalidationRectInLocalCoordinates() const3068 FloatRect RenderObject::paintInvalidationRectInLocalCoordinates() const
3069 {
3070 ASSERT_NOT_REACHED();
3071 return FloatRect();
3072 }
3073
localTransform() const3074 AffineTransform RenderObject::localTransform() const
3075 {
3076 static const AffineTransform identity;
3077 return identity;
3078 }
3079
localToParentTransform() const3080 const AffineTransform& RenderObject::localToParentTransform() const
3081 {
3082 static const AffineTransform identity;
3083 return identity;
3084 }
3085
nodeAtFloatPoint(const HitTestRequest &,HitTestResult &,const FloatPoint &,HitTestAction)3086 bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction)
3087 {
3088 ASSERT_NOT_REACHED();
3089 return false;
3090 }
3091
isRelayoutBoundaryForInspector() const3092 bool RenderObject::isRelayoutBoundaryForInspector() const
3093 {
3094 return objectIsRelayoutBoundary(this);
3095 }
3096
setShouldDoFullPaintInvalidation(bool b,MarkingBehavior markBehavior)3097 void RenderObject::setShouldDoFullPaintInvalidation(bool b, MarkingBehavior markBehavior)
3098 {
3099 // RenderText objects don't know how to invalidate paint for themselves, since they don't know how to compute their bounds.
3100 // Instead the parent fully invalidate when any text needs full paint invalidation.
3101 if (isText()) {
3102 parent()->setShouldDoFullPaintInvalidation(b, markBehavior);
3103 return;
3104 }
3105
3106 m_bitfields.setShouldDoFullPaintInvalidation(b);
3107
3108 if (markBehavior == MarkContainingBlockChain && b) {
3109 ASSERT(document().lifecycle().state() != DocumentLifecycle::InPaintInvalidation);
3110 frame()->page()->animator().scheduleVisualUpdate(); // In case that this is called not during FrameView::updateLayoutAndStyleForPainting().
3111 markContainingBlockChainForPaintInvalidation();
3112 }
3113 }
3114
clearPaintInvalidationState(const PaintInvalidationState & paintInvalidationState)3115 void RenderObject::clearPaintInvalidationState(const PaintInvalidationState& paintInvalidationState)
3116 {
3117 // paintInvalidationStateIsDirty should be kept in sync with the
3118 // booleans that are cleared below.
3119 ASSERT(paintInvalidationState.forceCheckForPaintInvalidation() || paintInvalidationStateIsDirty());
3120 setShouldDoFullPaintInvalidation(false);
3121 setShouldDoFullPaintInvalidationIfSelfPaintingLayer(false);
3122 setOnlyNeededPositionedMovementLayout(false);
3123 setNeededLayoutBecauseOfChildren(false);
3124 setShouldInvalidateOverflowForPaint(false);
3125 setLayoutDidGetCalled(false);
3126 setMayNeedPaintInvalidation(false);
3127 }
3128
isAllowedToModifyRenderTreeStructure(Document & document)3129 bool RenderObject::isAllowedToModifyRenderTreeStructure(Document& document)
3130 {
3131 return DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState()
3132 || document.lifecycle().stateAllowsRenderTreeMutations();
3133 }
3134
DeprecatedDisableModifyRenderTreeStructureAsserts()3135 DeprecatedDisableModifyRenderTreeStructureAsserts::DeprecatedDisableModifyRenderTreeStructureAsserts()
3136 : m_disabler(gModifyRenderTreeStructureAnyState, true)
3137 {
3138 }
3139
canModifyRenderTreeStateInAnyState()3140 bool DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState()
3141 {
3142 return gModifyRenderTreeStructureAnyState;
3143 }
3144
3145 // Since we're only painting non-composited layers, we know that they all share the same paintInvalidationContainer.
invalidatePaintIncludingNonCompositingDescendants()3146 void RenderObject::invalidatePaintIncludingNonCompositingDescendants()
3147 {
3148 invalidatePaintIncludingNonCompositingDescendantsInternal(containerForPaintInvalidation());
3149 }
3150
invalidatePaintIncludingNonCompositingDescendantsInternal(const RenderLayerModelObject * paintInvalidationContainer)3151 void RenderObject::invalidatePaintIncludingNonCompositingDescendantsInternal(const RenderLayerModelObject* paintInvalidationContainer)
3152 {
3153 invalidatePaintUsingContainer(paintInvalidationContainer, previousPaintInvalidationRect(), InvalidationLayer);
3154
3155 for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
3156 if (!child->isPaintInvalidationContainer())
3157 child->invalidatePaintIncludingNonCompositingDescendantsInternal(paintInvalidationContainer);
3158 }
3159 }
3160
3161
3162 } // namespace blink
3163
3164 #ifndef NDEBUG
3165
showTree(const blink::RenderObject * object)3166 void showTree(const blink::RenderObject* object)
3167 {
3168 if (object)
3169 object->showTreeForThis();
3170 }
3171
showLineTree(const blink::RenderObject * object)3172 void showLineTree(const blink::RenderObject* object)
3173 {
3174 if (object)
3175 object->showLineTreeForThis();
3176 }
3177
showRenderTree(const blink::RenderObject * object1)3178 void showRenderTree(const blink::RenderObject* object1)
3179 {
3180 showRenderTree(object1, 0);
3181 }
3182
showRenderTree(const blink::RenderObject * object1,const blink::RenderObject * object2)3183 void showRenderTree(const blink::RenderObject* object1, const blink::RenderObject* object2)
3184 {
3185 if (object1) {
3186 const blink::RenderObject* root = object1;
3187 while (root->parent())
3188 root = root->parent();
3189 root->showRenderTreeAndMark(object1, "*", object2, "-", 0);
3190 }
3191 }
3192
3193 #endif
3194