| 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 |