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