1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) 6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved. 7 * Copyright (C) 2010, 2012 Google Inc. All rights reserved. 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Library General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Library General Public License for more details. 18 * 19 * You should have received a copy of the GNU Library General Public License 20 * along with this library; see the file COPYING.LIB. If not, write to 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA. 23 */ 24 25#include "config.h" 26#include "RenderElement.h" 27 28#include "AXObjectCache.h" 29#include "ContentData.h" 30#include "ControlStates.h" 31#include "CursorList.h" 32#include "EventHandler.h" 33#include "Frame.h" 34#include "FrameSelection.h" 35#include "HTMLElement.h" 36#include "HTMLNames.h" 37#include "FlowThreadController.h" 38#include "RenderCounter.h" 39#include "RenderDeprecatedFlexibleBox.h" 40#include "RenderFlexibleBox.h" 41#include "RenderImage.h" 42#include "RenderImageResourceStyleImage.h" 43#include "RenderIterator.h" 44#include "RenderLayer.h" 45#include "RenderLayerCompositor.h" 46#include "RenderLineBreak.h" 47#include "RenderListItem.h" 48#include "RenderNamedFlowThread.h" 49#include "RenderRegion.h" 50#include "RenderRuby.h" 51#include "RenderRubyText.h" 52#include "RenderTableCaption.h" 53#include "RenderTableCell.h" 54#include "RenderTableCol.h" 55#include "RenderTableRow.h" 56#include "RenderText.h" 57#include "RenderTheme.h" 58#include "RenderView.h" 59#include "SVGRenderSupport.h" 60#include "Settings.h" 61#include "StyleResolver.h" 62#include <wtf/MathExtras.h> 63#include <wtf/StackStats.h> 64 65#if ENABLE(CSS_GRID_LAYOUT) 66#include "RenderGrid.h" 67#endif 68 69namespace WebCore { 70 71bool RenderElement::s_affectsParentBlock = false; 72bool RenderElement::s_noLongerAffectsParentBlock = false; 73 74static HashMap<const RenderObject*, ControlStates*>& controlStatesRendererMap() 75{ 76 static NeverDestroyed<HashMap<const RenderObject*, ControlStates*>> map; 77 return map; 78} 79 80inline RenderElement::RenderElement(ContainerNode& elementOrDocument, PassRef<RenderStyle> style, unsigned baseTypeFlags) 81 : RenderObject(elementOrDocument) 82 , m_baseTypeFlags(baseTypeFlags) 83 , m_ancestorLineBoxDirty(false) 84 , m_hasInitializedStyle(false) 85 , m_renderInlineAlwaysCreatesLineBoxes(false) 86 , m_renderBoxNeedsLazyRepaint(false) 87 , m_hasPausedImageAnimations(false) 88 , m_firstChild(nullptr) 89 , m_lastChild(nullptr) 90 , m_style(WTF::move(style)) 91{ 92} 93 94RenderElement::RenderElement(Element& element, PassRef<RenderStyle> style, unsigned baseTypeFlags) 95 : RenderElement(static_cast<ContainerNode&>(element), WTF::move(style), baseTypeFlags) 96{ 97} 98 99RenderElement::RenderElement(Document& document, PassRef<RenderStyle> style, unsigned baseTypeFlags) 100 : RenderElement(static_cast<ContainerNode&>(document), WTF::move(style), baseTypeFlags) 101{ 102} 103 104RenderElement::~RenderElement() 105{ 106 if (hasInitializedStyle()) { 107 for (const FillLayer* bgLayer = m_style->backgroundLayers(); bgLayer; bgLayer = bgLayer->next()) { 108 if (StyleImage* backgroundImage = bgLayer->image()) 109 backgroundImage->removeClient(this); 110 } 111 112 for (const FillLayer* maskLayer = m_style->maskLayers(); maskLayer; maskLayer = maskLayer->next()) { 113 if (StyleImage* maskImage = maskLayer->image()) 114 maskImage->removeClient(this); 115 } 116 117 if (StyleImage* borderImage = m_style->borderImage().image()) 118 borderImage->removeClient(this); 119 120 if (StyleImage* maskBoxImage = m_style->maskBoxImage().image()) 121 maskBoxImage->removeClient(this); 122 123#if ENABLE(CSS_SHAPES) 124 if (auto shapeValue = m_style->shapeOutside()) { 125 if (auto shapeImage = shapeValue->image()) 126 shapeImage->removeClient(this); 127 } 128#endif 129 } 130 if (m_hasPausedImageAnimations) 131 view().removeRendererWithPausedImageAnimations(*this); 132} 133 134RenderPtr<RenderElement> RenderElement::createFor(Element& element, PassRef<RenderStyle> style) 135{ 136 // Minimal support for content properties replacing an entire element. 137 // Works only if we have exactly one piece of content and it's a URL. 138 // Otherwise acts as if we didn't support this feature. 139 const ContentData* contentData = style.get().contentData(); 140 if (contentData && !contentData->next() && contentData->isImage() && !element.isPseudoElement()) { 141 auto& styleImage = toImageContentData(contentData)->image(); 142 auto image = createRenderer<RenderImage>(element, WTF::move(style), const_cast<StyleImage*>(&styleImage)); 143 image->setIsGeneratedContent(); 144 return WTF::move(image); 145 } 146 147 if (element.hasTagName(HTMLNames::rubyTag)) { 148 if (style.get().display() == INLINE) 149 return createRenderer<RenderRubyAsInline>(element, WTF::move(style)); 150 if (style.get().display() == BLOCK) 151 return createRenderer<RenderRubyAsBlock>(element, WTF::move(style)); 152 } 153 // treat <rt> as ruby text ONLY if it still has its default treatment of block 154 if (element.hasTagName(HTMLNames::rtTag) && style.get().display() == BLOCK) 155 return createRenderer<RenderRubyText>(element, WTF::move(style)); 156 switch (style.get().display()) { 157 case NONE: 158 style.dropRef(); 159 return nullptr; 160 case INLINE: 161 return createRenderer<RenderInline>(element, WTF::move(style)); 162 case BLOCK: 163 case INLINE_BLOCK: 164 case COMPACT: 165 return createRenderer<RenderBlockFlow>(element, WTF::move(style)); 166 case LIST_ITEM: 167 return createRenderer<RenderListItem>(element, WTF::move(style)); 168 case TABLE: 169 case INLINE_TABLE: 170 return createRenderer<RenderTable>(element, WTF::move(style)); 171 case TABLE_ROW_GROUP: 172 case TABLE_HEADER_GROUP: 173 case TABLE_FOOTER_GROUP: 174 return createRenderer<RenderTableSection>(element, WTF::move(style)); 175 case TABLE_ROW: 176 return createRenderer<RenderTableRow>(element, WTF::move(style)); 177 case TABLE_COLUMN_GROUP: 178 case TABLE_COLUMN: 179 return createRenderer<RenderTableCol>(element, WTF::move(style)); 180 case TABLE_CELL: 181 return createRenderer<RenderTableCell>(element, WTF::move(style)); 182 case TABLE_CAPTION: 183 return createRenderer<RenderTableCaption>(element, WTF::move(style)); 184 case BOX: 185 case INLINE_BOX: 186 return createRenderer<RenderDeprecatedFlexibleBox>(element, WTF::move(style)); 187 case FLEX: 188 case INLINE_FLEX: 189 return createRenderer<RenderFlexibleBox>(element, WTF::move(style)); 190#if ENABLE(CSS_GRID_LAYOUT) 191 case GRID: 192 case INLINE_GRID: 193 return createRenderer<RenderGrid>(element, WTF::move(style)); 194#endif 195 } 196 ASSERT_NOT_REACHED(); 197 return nullptr; 198} 199 200enum StyleCacheState { 201 Cached, 202 Uncached 203}; 204 205static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheState type, const RenderElement& renderer, RenderStyle* style) 206{ 207 RenderElement& rendererForFirstLineStyle = renderer.isBeforeOrAfterContent() ? *renderer.parent() : const_cast<RenderElement&>(renderer); 208 209 if (rendererForFirstLineStyle.isRenderBlockFlow() || rendererForFirstLineStyle.isRenderButton()) { 210 if (RenderBlock* firstLineBlock = rendererForFirstLineStyle.firstLineBlock()) { 211 if (type == Cached) 212 return firstLineBlock->getCachedPseudoStyle(FIRST_LINE, style); 213 return firstLineBlock->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE), style, firstLineBlock == &renderer ? style : nullptr); 214 } 215 } else if (!rendererForFirstLineStyle.isAnonymous() && rendererForFirstLineStyle.isRenderInline()) { 216 RenderStyle& parentStyle = rendererForFirstLineStyle.parent()->firstLineStyle(); 217 if (&parentStyle != &rendererForFirstLineStyle.parent()->style()) { 218 if (type == Cached) { 219 // A first-line style is in effect. Cache a first-line style for ourselves. 220 rendererForFirstLineStyle.style().setHasPseudoStyle(FIRST_LINE_INHERITED); 221 return rendererForFirstLineStyle.getCachedPseudoStyle(FIRST_LINE_INHERITED, &parentStyle); 222 } 223 return rendererForFirstLineStyle.getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), &parentStyle, style); 224 } 225 } 226 return nullptr; 227} 228 229PassRefPtr<RenderStyle> RenderElement::uncachedFirstLineStyle(RenderStyle* style) const 230{ 231 if (!document().styleSheetCollection().usesFirstLineRules()) 232 return nullptr; 233 234 return firstLineStyleForCachedUncachedType(Uncached, *this, style); 235} 236 237RenderStyle* RenderElement::cachedFirstLineStyle() const 238{ 239 ASSERT(document().styleSheetCollection().usesFirstLineRules()); 240 241 RenderStyle& style = this->style(); 242 if (RefPtr<RenderStyle> firstLineStyle = firstLineStyleForCachedUncachedType(Cached, *this, &style)) 243 return firstLineStyle.get(); 244 245 return &style; 246} 247 248StyleDifference RenderElement::adjustStyleDifference(StyleDifference diff, unsigned contextSensitiveProperties) const 249{ 250 // If transform changed, and we are not composited, need to do a layout. 251 if (contextSensitiveProperties & ContextSensitivePropertyTransform) { 252 // Text nodes share style with their parents but transforms don't apply to them, 253 // hence the !isText() check. 254 // FIXME: when transforms are taken into account for overflow, we will need to do a layout. 255 if (!hasLayer() || !toRenderLayerModelObject(this)->layer()->isComposited()) { 256 // We need to set at least SimplifiedLayout, but if PositionedMovementOnly is already set 257 // then we actually need SimplifiedLayoutAndPositionedMovement. 258 if (!hasLayer()) 259 diff = StyleDifferenceLayout; // FIXME: Do this for now since SimplifiedLayout cannot handle updating floating objects lists. 260 else if (diff < StyleDifferenceLayoutPositionedMovementOnly) 261 diff = StyleDifferenceSimplifiedLayout; 262 else if (diff < StyleDifferenceSimplifiedLayout) 263 diff = StyleDifferenceSimplifiedLayoutAndPositionedMovement; 264 } else if (diff < StyleDifferenceRecompositeLayer) 265 diff = StyleDifferenceRecompositeLayer; 266 } 267 268 // If opacity changed, and we are not composited, need to repaint (also 269 // ignoring text nodes) 270 if (contextSensitiveProperties & ContextSensitivePropertyOpacity) { 271 if (!hasLayer() || !toRenderLayerModelObject(this)->layer()->isComposited()) 272 diff = StyleDifferenceRepaintLayer; 273 else if (diff < StyleDifferenceRecompositeLayer) 274 diff = StyleDifferenceRecompositeLayer; 275 } 276 277#if ENABLE(CSS_FILTERS) 278 if ((contextSensitiveProperties & ContextSensitivePropertyFilter) && hasLayer()) { 279 RenderLayer* layer = toRenderLayerModelObject(this)->layer(); 280 if (!layer->isComposited() || layer->paintsWithFilters()) 281 diff = StyleDifferenceRepaintLayer; 282 else if (diff < StyleDifferenceRecompositeLayer) 283 diff = StyleDifferenceRecompositeLayer; 284 } 285#endif 286 287 // The answer to requiresLayer() for plugins, iframes, and canvas can change without the actual 288 // style changing, since it depends on whether we decide to composite these elements. When the 289 // layer status of one of these elements changes, we need to force a layout. 290 if (diff == StyleDifferenceEqual && isRenderLayerModelObject()) { 291 if (hasLayer() != toRenderLayerModelObject(this)->requiresLayer()) 292 diff = StyleDifferenceLayout; 293 } 294 295 // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint. 296 if (diff == StyleDifferenceRepaintLayer && !hasLayer()) 297 diff = StyleDifferenceRepaint; 298 299 return diff; 300} 301 302inline bool RenderElement::hasImmediateNonWhitespaceTextChildOrBorderOrOutline() const 303{ 304 for (auto& child : childrenOfType<RenderObject>(*this)) { 305 if (child.isText() && !toRenderText(child).isAllCollapsibleWhitespace()) 306 return true; 307 if (child.style().hasOutline() || child.style().hasBorder()) 308 return true; 309 } 310 return false; 311} 312 313inline bool RenderElement::shouldRepaintForStyleDifference(StyleDifference diff) const 314{ 315 return diff == StyleDifferenceRepaint || (diff == StyleDifferenceRepaintIfTextOrBorderOrOutline && hasImmediateNonWhitespaceTextChildOrBorderOrOutline()); 316} 317 318void RenderElement::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers) 319{ 320 // Optimize the common case 321 if (oldLayers && !oldLayers->next() && newLayers && !newLayers->next() && (oldLayers->image() == newLayers->image())) 322 return; 323 324 // Go through the new layers and addClients first, to avoid removing all clients of an image. 325 for (const FillLayer* currNew = newLayers; currNew; currNew = currNew->next()) { 326 if (currNew->image()) 327 currNew->image()->addClient(this); 328 } 329 330 for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) { 331 if (currOld->image()) 332 currOld->image()->removeClient(this); 333 } 334} 335 336void RenderElement::updateImage(StyleImage* oldImage, StyleImage* newImage) 337{ 338 if (oldImage == newImage) 339 return; 340 if (oldImage) 341 oldImage->removeClient(this); 342 if (newImage) 343 newImage->addClient(this); 344} 345 346#if ENABLE(CSS_SHAPES) 347void RenderElement::updateShapeImage(const ShapeValue* oldShapeValue, const ShapeValue* newShapeValue) 348{ 349 if (oldShapeValue || newShapeValue) 350 updateImage(oldShapeValue ? oldShapeValue->image() : nullptr, newShapeValue ? newShapeValue->image() : nullptr); 351} 352#endif 353 354void RenderElement::initializeStyle() 355{ 356 styleWillChange(StyleDifferenceEqual, style()); 357 358 m_hasInitializedStyle = true; 359 360 updateFillImages(nullptr, m_style->backgroundLayers()); 361 updateFillImages(nullptr, m_style->maskLayers()); 362 363 updateImage(nullptr, m_style->borderImage().image()); 364 updateImage(nullptr, m_style->maskBoxImage().image()); 365 366#if ENABLE(CSS_SHAPES) 367 updateShapeImage(nullptr, m_style->shapeOutside()); 368#endif 369 370 // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen 371 // during styleDidChange (it's used by clippedOverflowRectForRepaint()). 372 if (m_style->outlineWidth() > 0 && m_style->outlineSize() > maximalOutlineSize(PaintPhaseOutline)) 373 view().setMaximalOutlineSize(std::max(theme().platformFocusRingMaxWidth(), static_cast<int>(m_style->outlineSize()))); 374 375 styleDidChange(StyleDifferenceEqual, nullptr); 376 377 // We shouldn't have any text children that would need styleDidChange at this point. 378 ASSERT(!childrenOfType<RenderText>(*this).first()); 379 380 // It would be nice to assert that !parent() here, but some RenderLayer subrenderers 381 // have their parent set before getting a call to initializeStyle() :| 382} 383 384void RenderElement::setStyle(PassRef<RenderStyle> style) 385{ 386 // FIXME: Should change RenderView so it can use initializeStyle too. 387 // If we do that, we can assert m_hasInitializedStyle unconditionally, 388 // and remove the check of m_hasInitializedStyle below too. 389 ASSERT(m_hasInitializedStyle || isRenderView()); 390 391 if (&m_style.get() == &style.get()) { 392 // FIXME: Can we change things so we never hit this code path? 393 // We need to run through adjustStyleDifference() for iframes, plugins, and canvas so 394 // style sharing is disabled for them. That should ensure that we never hit this code path. 395 ASSERT(!isRenderIFrame()); 396 ASSERT(!isEmbeddedObject()); 397 ASSERT(!isCanvas()); 398 style.dropRef(); 399 return; 400 } 401 402 StyleDifference diff = StyleDifferenceEqual; 403 unsigned contextSensitiveProperties = ContextSensitivePropertyNone; 404 if (m_hasInitializedStyle) 405 diff = m_style->diff(&style.get(), contextSensitiveProperties); 406 407 diff = adjustStyleDifference(diff, contextSensitiveProperties); 408 409 styleWillChange(diff, style.get()); 410 411 Ref<RenderStyle> oldStyle(m_style.replace(WTF::move(style))); 412 413 updateFillImages(oldStyle.get().backgroundLayers(), m_style->backgroundLayers()); 414 updateFillImages(oldStyle.get().maskLayers(), m_style->maskLayers()); 415 416 updateImage(oldStyle.get().borderImage().image(), m_style->borderImage().image()); 417 updateImage(oldStyle.get().maskBoxImage().image(), m_style->maskBoxImage().image()); 418 419#if ENABLE(CSS_SHAPES) 420 updateShapeImage(oldStyle.get().shapeOutside(), m_style->shapeOutside()); 421#endif 422 423 // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen 424 // during styleDidChange (it's used by clippedOverflowRectForRepaint()). 425 if (m_style->outlineWidth() > 0 && m_style->outlineSize() > maximalOutlineSize(PaintPhaseOutline)) 426 view().setMaximalOutlineSize(std::max(theme().platformFocusRingMaxWidth(), static_cast<int>(m_style->outlineSize()))); 427 428 bool doesNotNeedLayout = !parent(); 429 430 styleDidChange(diff, &oldStyle.get()); 431 432 // Text renderers use their parent style. Notify them about the change. 433 for (auto& child : childrenOfType<RenderText>(*this)) 434 child.styleDidChange(diff, &oldStyle.get()); 435 436 // FIXME: |this| might be destroyed here. This can currently happen for a RenderTextFragment when 437 // its first-letter block gets an update in RenderTextFragment::styleDidChange. For RenderTextFragment(s), 438 // we will safely bail out with the doesNotNeedLayout flag. We might want to broaden this condition 439 // in the future as we move renderer changes out of layout and into style changes. 440 if (doesNotNeedLayout) 441 return; 442 443 // Now that the layer (if any) has been updated, we need to adjust the diff again, 444 // check whether we should layout now, and decide if we need to repaint. 445 StyleDifference updatedDiff = adjustStyleDifference(diff, contextSensitiveProperties); 446 447 if (diff <= StyleDifferenceLayoutPositionedMovementOnly) { 448 if (updatedDiff == StyleDifferenceLayout) 449 setNeedsLayoutAndPrefWidthsRecalc(); 450 else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly) 451 setNeedsPositionedMovementLayout(&oldStyle.get()); 452 else if (updatedDiff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) { 453 setNeedsPositionedMovementLayout(&oldStyle.get()); 454 setNeedsSimplifiedNormalFlowLayout(); 455 } else if (updatedDiff == StyleDifferenceSimplifiedLayout) 456 setNeedsSimplifiedNormalFlowLayout(); 457 } 458 459 if (updatedDiff == StyleDifferenceRepaintLayer || shouldRepaintForStyleDifference(updatedDiff)) { 460 // Do a repaint with the new style now, e.g., for example if we go from 461 // not having an outline to having an outline. 462 repaint(); 463 } 464} 465 466void RenderElement::addChild(RenderObject* newChild, RenderObject* beforeChild) 467{ 468 bool needsTable = false; 469 470 if (newChild->isRenderTableCol()) { 471 RenderTableCol* newTableColumn = toRenderTableCol(newChild); 472 bool isColumnInColumnGroup = newTableColumn->isTableColumn() && isRenderTableCol(); 473 needsTable = !isTable() && !isColumnInColumnGroup; 474 } else if (newChild->isTableCaption()) 475 needsTable = !isTable(); 476 else if (newChild->isTableSection()) 477 needsTable = !isTable(); 478 else if (newChild->isTableRow()) 479 needsTable = !isTableSection(); 480 else if (newChild->isTableCell()) 481 needsTable = !isTableRow(); 482 483 if (needsTable) { 484 RenderTable* table; 485 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : m_lastChild; 486 if (afterChild && afterChild->isAnonymous() && afterChild->isTable() && !afterChild->isBeforeContent()) 487 table = toRenderTable(afterChild); 488 else { 489 table = RenderTable::createAnonymousWithParentRenderer(this); 490 addChild(table, beforeChild); 491 } 492 table->addChild(newChild); 493 } else 494 insertChildInternal(newChild, beforeChild, NotifyChildren); 495 496 if (newChild->isText()) 497 toRenderText(newChild)->styleDidChange(StyleDifferenceEqual, nullptr); 498 499 // SVG creates renderers for <g display="none">, as SVG requires children of hidden 500 // <g>s to have renderers - at least that's how our implementation works. Consider: 501 // <g display="none"><foreignObject><body style="position: relative">FOO... 502 // - requiresLayer() would return true for the <body>, creating a new RenderLayer 503 // - when the document is painted, both layers are painted. The <body> layer doesn't 504 // know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't. 505 // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree 506 // and stop creating layers at all for these cases - they're not used anyways. 507 if (newChild->hasLayer() && !layerCreationAllowedForSubtree()) 508 toRenderLayerModelObject(newChild)->layer()->removeOnlyThisLayer(); 509 510 SVGRenderSupport::childAdded(*this, *newChild); 511} 512 513RenderObject* RenderElement::removeChild(RenderObject& oldChild) 514{ 515 return removeChildInternal(oldChild, NotifyChildren); 516} 517 518void RenderElement::destroyLeftoverChildren() 519{ 520 while (m_firstChild) { 521 if (m_firstChild->isListMarker() || (m_firstChild->style().styleType() == FIRST_LETTER && !m_firstChild->isText())) { 522 m_firstChild->removeFromParent(); // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment. 523 } else { 524 // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields. 525 if (m_firstChild->node()) 526 m_firstChild->node()->setRenderer(nullptr); 527 m_firstChild->destroy(); 528 } 529 } 530} 531 532void RenderElement::insertChildInternal(RenderObject* newChild, RenderObject* beforeChild, NotifyChildrenType notifyChildren) 533{ 534 ASSERT(canHaveChildren() || canHaveGeneratedChildren()); 535 ASSERT(!newChild->parent()); 536 ASSERT(!isRenderBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell())); 537 538 while (beforeChild && beforeChild->parent() && beforeChild->parent() != this) 539 beforeChild = beforeChild->parent(); 540 541 // This should never happen, but if it does prevent render tree corruption 542 // where child->parent() ends up being owner but child->nextSibling()->parent() 543 // is not owner. 544 if (beforeChild && beforeChild->parent() != this) { 545 ASSERT_NOT_REACHED(); 546 return; 547 } 548 549 newChild->setParent(this); 550 551 if (m_firstChild == beforeChild) 552 m_firstChild = newChild; 553 554 if (beforeChild) { 555 RenderObject* previousSibling = beforeChild->previousSibling(); 556 if (previousSibling) 557 previousSibling->setNextSibling(newChild); 558 newChild->setPreviousSibling(previousSibling); 559 newChild->setNextSibling(beforeChild); 560 beforeChild->setPreviousSibling(newChild); 561 } else { 562 if (lastChild()) 563 lastChild()->setNextSibling(newChild); 564 newChild->setPreviousSibling(lastChild()); 565 m_lastChild = newChild; 566 } 567 568 if (!documentBeingDestroyed()) { 569 if (notifyChildren == NotifyChildren) 570 newChild->insertedIntoTree(); 571 RenderCounter::rendererSubtreeAttached(newChild); 572 } 573 574 newChild->setNeedsLayoutAndPrefWidthsRecalc(); 575 setPreferredLogicalWidthsDirty(true); 576 if (!normalChildNeedsLayout()) 577 setChildNeedsLayout(); // We may supply the static position for an absolute positioned child. 578 579 if (AXObjectCache* cache = document().axObjectCache()) 580 cache->childrenChanged(this, newChild); 581} 582 583RenderObject* RenderElement::removeChildInternal(RenderObject& oldChild, NotifyChildrenType notifyChildren) 584{ 585 ASSERT(canHaveChildren() || canHaveGeneratedChildren()); 586 ASSERT(oldChild.parent() == this); 587 588 if (oldChild.isFloatingOrOutOfFlowPositioned()) 589 toRenderBox(oldChild).removeFloatingOrPositionedChildFromBlockLists(); 590 591 // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or 592 // that a positioned child got yanked). We also repaint, so that the area exposed when the child 593 // disappears gets repainted properly. 594 if (!documentBeingDestroyed() && notifyChildren == NotifyChildren && oldChild.everHadLayout()) { 595 oldChild.setNeedsLayoutAndPrefWidthsRecalc(); 596 // We only repaint |oldChild| if we have a RenderLayer as its visual overflow may not be tracked by its parent. 597 if (oldChild.isBody()) 598 view().repaintRootContents(); 599 else 600 oldChild.repaint(); 601 } 602 603 // If we have a line box wrapper, delete it. 604 if (oldChild.isBox()) 605 toRenderBox(oldChild).deleteLineBoxWrapper(); 606 else if (oldChild.isLineBreak()) 607 toRenderLineBreak(oldChild).deleteInlineBoxWrapper(); 608 609 // If oldChild is the start or end of the selection, then clear the selection to 610 // avoid problems of invalid pointers. 611 if (!documentBeingDestroyed() && oldChild.isSelectionBorder()) 612 frame().selection().setNeedsSelectionUpdate(); 613 614 if (!documentBeingDestroyed() && notifyChildren == NotifyChildren) 615 oldChild.willBeRemovedFromTree(); 616 617 // WARNING: There should be no code running between willBeRemovedFromTree and the actual removal below. 618 // This is needed to avoid race conditions where willBeRemovedFromTree would dirty the tree's structure 619 // and the code running here would force an untimely rebuilding, leaving |oldChild| dangling. 620 621 RenderObject* nextSibling = oldChild.nextSibling(); 622 623 if (oldChild.previousSibling()) 624 oldChild.previousSibling()->setNextSibling(nextSibling); 625 if (nextSibling) 626 nextSibling->setPreviousSibling(oldChild.previousSibling()); 627 628 if (m_firstChild == &oldChild) 629 m_firstChild = nextSibling; 630 if (m_lastChild == &oldChild) 631 m_lastChild = oldChild.previousSibling(); 632 633 oldChild.setPreviousSibling(nullptr); 634 oldChild.setNextSibling(nullptr); 635 oldChild.setParent(nullptr); 636 637 // rendererRemovedFromTree walks the whole subtree. We can improve performance 638 // by skipping this step when destroying the entire tree. 639 if (!documentBeingDestroyed()) 640 RenderCounter::rendererRemovedFromTree(oldChild); 641 642 if (AXObjectCache* cache = document().existingAXObjectCache()) 643 cache->childrenChanged(this); 644 645 return nextSibling; 646} 647 648static void addLayers(RenderElement& renderer, RenderLayer* parentLayer, RenderElement*& newObject, RenderLayer*& beforeChild) 649{ 650 if (renderer.hasLayer()) { 651 if (!beforeChild && newObject) { 652 // We need to figure out the layer that follows newObject. We only do 653 // this the first time we find a child layer, and then we update the 654 // pointer values for newObject and beforeChild used by everyone else. 655 beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject); 656 newObject = nullptr; 657 } 658 parentLayer->addChild(toRenderLayerModelObject(renderer).layer(), beforeChild); 659 return; 660 } 661 662 for (auto& child : childrenOfType<RenderElement>(renderer)) 663 addLayers(child, parentLayer, newObject, beforeChild); 664} 665 666void RenderElement::addLayers(RenderLayer* parentLayer) 667{ 668 if (!parentLayer) 669 return; 670 671 RenderElement* renderer = this; 672 RenderLayer* beforeChild = nullptr; 673 WebCore::addLayers(*this, parentLayer, renderer, beforeChild); 674} 675 676void RenderElement::removeLayers(RenderLayer* parentLayer) 677{ 678 if (!parentLayer) 679 return; 680 681 if (hasLayer()) { 682 parentLayer->removeChild(toRenderLayerModelObject(this)->layer()); 683 return; 684 } 685 686 for (auto& child : childrenOfType<RenderElement>(*this)) 687 child.removeLayers(parentLayer); 688} 689 690void RenderElement::moveLayers(RenderLayer* oldParent, RenderLayer* newParent) 691{ 692 if (!newParent) 693 return; 694 695 if (hasLayer()) { 696 RenderLayer* layer = toRenderLayerModelObject(this)->layer(); 697 ASSERT(oldParent == layer->parent()); 698 if (oldParent) 699 oldParent->removeChild(layer); 700 newParent->addChild(layer); 701 return; 702 } 703 704 for (auto& child : childrenOfType<RenderElement>(*this)) 705 child.moveLayers(oldParent, newParent); 706} 707 708RenderLayer* RenderElement::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, bool checkParent) 709{ 710 // Error check the parent layer passed in. If it's null, we can't find anything. 711 if (!parentLayer) 712 return nullptr; 713 714 // Step 1: If our layer is a child of the desired parent, then return our layer. 715 RenderLayer* ourLayer = hasLayer() ? toRenderLayerModelObject(this)->layer() : nullptr; 716 if (ourLayer && ourLayer->parent() == parentLayer) 717 return ourLayer; 718 719 // Step 2: If we don't have a layer, or our layer is the desired parent, then descend 720 // into our siblings trying to find the next layer whose parent is the desired parent. 721 if (!ourLayer || ourLayer == parentLayer) { 722 for (RenderObject* child = startPoint ? startPoint->nextSibling() : firstChild(); child; child = child->nextSibling()) { 723 if (!child->isRenderElement()) 724 continue; 725 RenderLayer* nextLayer = toRenderElement(child)->findNextLayer(parentLayer, nullptr, false); 726 if (nextLayer) 727 return nextLayer; 728 } 729 } 730 731 // Step 3: If our layer is the desired parent layer, then we're finished. We didn't 732 // find anything. 733 if (parentLayer == ourLayer) 734 return nullptr; 735 736 // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that 737 // follow us to see if we can locate a layer. 738 if (checkParent && parent()) 739 return parent()->findNextLayer(parentLayer, this, true); 740 741 return nullptr; 742} 743 744bool RenderElement::layerCreationAllowedForSubtree() const 745{ 746 RenderElement* parentRenderer = parent(); 747 while (parentRenderer) { 748 if (parentRenderer->isSVGHiddenContainer()) 749 return false; 750 parentRenderer = parentRenderer->parent(); 751 } 752 753 return true; 754} 755 756void RenderElement::propagateStyleToAnonymousChildren(StylePropagationType propagationType) 757{ 758 // FIXME: We could save this call when the change only affected non-inherited properties. 759 for (auto& elementChild : childrenOfType<RenderElement>(*this)) { 760 if (!elementChild.isAnonymous() || elementChild.style().styleType() != NOPSEUDO) 761 continue; 762 763 if (propagationType == PropagateToBlockChildrenOnly && !elementChild.isRenderBlock()) 764 continue; 765 766#if ENABLE(FULLSCREEN_API) 767 if (elementChild.isRenderFullScreen() || elementChild.isRenderFullScreenPlaceholder()) 768 continue; 769#endif 770 771 // RenderFlowThreads are updated through the RenderView::styleDidChange function. 772 if (elementChild.isRenderFlowThread()) 773 continue; 774 775 auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), elementChild.style().display()); 776 if (style().specifiesColumns()) { 777 if (elementChild.style().specifiesColumns()) 778 newStyle.get().inheritColumnPropertiesFrom(&style()); 779 if (elementChild.style().columnSpan()) 780 newStyle.get().setColumnSpan(ColumnSpanAll); 781 } 782 783 // Preserve the position style of anonymous block continuations as they can have relative or sticky position when 784 // they contain block descendants of relative or sticky positioned inlines. 785 if (elementChild.isInFlowPositioned() && toRenderBlock(elementChild).isAnonymousBlockContinuation()) 786 newStyle.get().setPosition(elementChild.style().position()); 787 788 elementChild.setStyle(WTF::move(newStyle)); 789 } 790} 791 792static inline bool rendererHasBackground(const RenderElement* renderer) 793{ 794 return renderer && renderer->hasBackground(); 795} 796 797void RenderElement::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) 798{ 799 RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr; 800 if (oldStyle) { 801 // If our z-index changes value or our visibility changes, 802 // we need to dirty our stacking context's z-order list. 803 bool visibilityChanged = m_style->visibility() != newStyle.visibility() 804 || m_style->zIndex() != newStyle.zIndex() 805 || m_style->hasAutoZIndex() != newStyle.hasAutoZIndex(); 806#if ENABLE(DASHBOARD_SUPPORT) 807 if (visibilityChanged) 808 document().setAnnotatedRegionsDirty(true); 809#endif 810#if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS) 811 if (visibilityChanged) 812 document().dirtyTouchEventRects(); 813#endif 814 if (visibilityChanged) { 815 if (AXObjectCache* cache = document().existingAXObjectCache()) 816 cache->childrenChanged(parent(), this); 817 } 818 819 // Keep layer hierarchy visibility bits up to date if visibility changes. 820 if (m_style->visibility() != newStyle.visibility()) { 821 if (RenderLayer* layer = enclosingLayer()) { 822 if (newStyle.visibility() == VISIBLE) 823 layer->setHasVisibleContent(); 824 else if (layer->hasVisibleContent() && (this == &layer->renderer() || layer->renderer().style().visibility() != VISIBLE)) { 825 layer->dirtyVisibleContentStatus(); 826 if (diff > StyleDifferenceRepaintLayer) 827 repaint(); 828 } 829 } 830 } 831 832 if (m_parent && (newStyle.outlineSize() < m_style->outlineSize() || shouldRepaintForStyleDifference(diff))) 833 repaint(); 834 if (isFloating() && (m_style->floating() != newStyle.floating())) 835 // For changes in float styles, we need to conceivably remove ourselves 836 // from the floating objects list. 837 toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); 838 else if (isOutOfFlowPositioned() && (m_style->position() != newStyle.position())) 839 // For changes in positioning styles, we need to conceivably remove ourselves 840 // from the positioned objects list. 841 toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); 842 843 s_affectsParentBlock = isFloatingOrOutOfFlowPositioned() 844 && (!newStyle.isFloating() && !newStyle.hasOutOfFlowPosition()) 845 && parent() && (parent()->isRenderBlockFlow() || parent()->isRenderInline()); 846 847 s_noLongerAffectsParentBlock = ((!isFloating() && newStyle.isFloating()) || (!isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())) 848 && parent() && parent()->isRenderBlock(); 849 850 // reset style flags 851 if (diff == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) { 852 setFloating(false); 853 clearPositionedState(); 854 } 855 setHorizontalWritingMode(true); 856 setHasBoxDecorations(false); 857 setHasOverflowClip(false); 858 setHasTransform(false); 859 setHasReflection(false); 860 } else { 861 s_affectsParentBlock = false; 862 s_noLongerAffectsParentBlock = false; 863 } 864 865 bool newStyleUsesFixedBackgrounds = newStyle.hasFixedBackgroundImage(); 866 bool oldStyleUsesFixedBackgrounds = m_style->hasFixedBackgroundImage(); 867 if (newStyleUsesFixedBackgrounds || oldStyleUsesFixedBackgrounds) { 868 bool repaintFixedBackgroundsOnScroll = !frame().settings().fixedBackgroundsPaintRelativeToDocument(); 869 870 bool newStyleSlowScroll = repaintFixedBackgroundsOnScroll && newStyleUsesFixedBackgrounds; 871 bool oldStyleSlowScroll = oldStyle && repaintFixedBackgroundsOnScroll && oldStyleUsesFixedBackgrounds; 872 bool drawsRootBackground = isRoot() || (isBody() && !rendererHasBackground(document().documentElement()->renderer())); 873 if (drawsRootBackground && repaintFixedBackgroundsOnScroll) { 874 if (view().compositor().supportsFixedRootBackgroundCompositing()) { 875 if (newStyleSlowScroll && newStyle.hasEntirelyFixedBackground()) 876 newStyleSlowScroll = false; 877 878 if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground()) 879 oldStyleSlowScroll = false; 880 } 881 } 882 883 if (oldStyleSlowScroll != newStyleSlowScroll) { 884 if (oldStyleSlowScroll) 885 view().frameView().removeSlowRepaintObject(this); 886 887 if (newStyleSlowScroll) 888 view().frameView().addSlowRepaintObject(this); 889 } 890 } 891 892 if (isRoot() || isBody()) 893 view().frameView().updateExtendBackgroundIfNecessary(); 894} 895 896#if !PLATFORM(IOS) 897static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b) 898{ 899 ASSERT(a->cursors() != b->cursors()); 900 return a->cursors() && b->cursors() && *a->cursors() == *b->cursors(); 901} 902 903static inline bool areCursorsEqual(const RenderStyle* a, const RenderStyle* b) 904{ 905 return a->cursor() == b->cursor() && (a->cursors() == b->cursors() || areNonIdenticalCursorListsEqual(a, b)); 906} 907#endif 908 909void RenderElement::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 910{ 911 if (s_affectsParentBlock) 912 handleDynamicFloatPositionChange(); 913 914 if (s_noLongerAffectsParentBlock) 915 removeAnonymousWrappersForInlinesIfNecessary(); 916 917 SVGRenderSupport::styleChanged(*this, oldStyle); 918 919 if (!m_parent) 920 return; 921 922 if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) { 923 RenderCounter::rendererStyleChanged(this, oldStyle, &m_style.get()); 924 925 // If the object already needs layout, then setNeedsLayout won't do 926 // any work. But if the containing block has changed, then we may need 927 // to mark the new containing blocks for layout. The change that can 928 // directly affect the containing block of this object is a change to 929 // the position style. 930 if (needsLayout() && oldStyle->position() != m_style->position()) 931 markContainingBlocksForLayout(); 932 933 if (diff == StyleDifferenceLayout) 934 setNeedsLayoutAndPrefWidthsRecalc(); 935 else 936 setNeedsSimplifiedNormalFlowLayout(); 937 } else if (diff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) { 938 setNeedsPositionedMovementLayout(oldStyle); 939 setNeedsSimplifiedNormalFlowLayout(); 940 } else if (diff == StyleDifferenceLayoutPositionedMovementOnly) 941 setNeedsPositionedMovementLayout(oldStyle); 942 943 // Don't check for repaint here; we need to wait until the layer has been 944 // updated by subclasses before we know if we have to repaint (in setStyle()). 945 946#if !PLATFORM(IOS) 947 if (oldStyle && !areCursorsEqual(oldStyle, &style())) 948 frame().eventHandler().scheduleCursorUpdate(); 949#endif 950} 951 952void RenderElement::insertedIntoTree() 953{ 954 if (auto* containerFlowThread = parent()->renderNamedFlowThreadWrapper()) 955 containerFlowThread->addFlowChild(*this); 956 957 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 958 // and don't have a layer attached to ourselves. 959 RenderLayer* layer = nullptr; 960 if (firstChild() || hasLayer()) { 961 layer = parent()->enclosingLayer(); 962 addLayers(layer); 963 } 964 965 // If |this| is visible but this object was not, tell the layer it has some visible content 966 // that needs to be drawn and layer visibility optimization can't be used 967 if (parent()->style().visibility() != VISIBLE && style().visibility() == VISIBLE && !hasLayer()) { 968 if (!layer) 969 layer = parent()->enclosingLayer(); 970 if (layer) 971 layer->setHasVisibleContent(); 972 } 973 974 RenderObject::insertedIntoTree(); 975} 976 977void RenderElement::willBeRemovedFromTree() 978{ 979 // If we remove a visible child from an invisible parent, we don't know the layer visibility any more. 980 RenderLayer* layer = nullptr; 981 if (parent()->style().visibility() != VISIBLE && style().visibility() == VISIBLE && !hasLayer()) { 982 if ((layer = parent()->enclosingLayer())) 983 layer->dirtyVisibleContentStatus(); 984 } 985 // Keep our layer hierarchy updated. 986 if (firstChild() || hasLayer()) { 987 if (!layer) 988 layer = parent()->enclosingLayer(); 989 removeLayers(layer); 990 } 991 992 if (m_style->hasFixedBackgroundImage() && !frame().settings().fixedBackgroundsPaintRelativeToDocument()) 993 view().frameView().removeSlowRepaintObject(this); 994 995 if (isOutOfFlowPositioned() && parent()->childrenInline()) 996 parent()->dirtyLinesFromChangedChild(this); 997 998 if (auto* containerFlowThread = parent()->renderNamedFlowThreadWrapper()) 999 containerFlowThread->removeFlowChild(*this); 1000 1001 RenderObject::willBeRemovedFromTree(); 1002} 1003 1004void RenderElement::willBeDestroyed() 1005{ 1006 animation().cancelAnimations(this); 1007 1008 destroyLeftoverChildren(); 1009 1010 RenderObject::willBeDestroyed(); 1011 1012#if !ASSERT_DISABLED 1013 if (!documentBeingDestroyed() && view().hasRenderNamedFlowThreads()) { 1014 // After remove, the object and the associated information should not be in any flow thread. 1015 for (auto& flowThread : *view().flowThreadController().renderNamedFlowThreadList()) { 1016 ASSERT(!flowThread->hasChild(*this)); 1017 ASSERT(!flowThread->hasChildInfo(this)); 1018 } 1019 } 1020#endif 1021} 1022 1023void RenderElement::setNeedsPositionedMovementLayout(const RenderStyle* oldStyle) 1024{ 1025 ASSERT(!isSetNeedsLayoutForbidden()); 1026 if (needsPositionedMovementLayout()) 1027 return; 1028 setNeedsPositionedMovementLayoutBit(true); 1029 markContainingBlocksForLayout(); 1030 if (hasLayer()) { 1031 if (oldStyle && style().diffRequiresLayerRepaint(*oldStyle, toRenderLayerModelObject(this)->layer()->isComposited())) 1032 setLayerNeedsFullRepaint(); 1033 else 1034 setLayerNeedsFullRepaintForPositionedMovementLayout(); 1035 } 1036} 1037 1038void RenderElement::clearChildNeedsLayout() 1039{ 1040 setNormalChildNeedsLayoutBit(false); 1041 setPosChildNeedsLayoutBit(false); 1042 setNeedsSimplifiedNormalFlowLayoutBit(false); 1043 setNormalChildNeedsLayoutBit(false); 1044 setNeedsPositionedMovementLayoutBit(false); 1045} 1046 1047void RenderElement::setNeedsSimplifiedNormalFlowLayout() 1048{ 1049 ASSERT(!isSetNeedsLayoutForbidden()); 1050 if (needsSimplifiedNormalFlowLayout()) 1051 return; 1052 setNeedsSimplifiedNormalFlowLayoutBit(true); 1053 markContainingBlocksForLayout(); 1054 if (hasLayer()) 1055 setLayerNeedsFullRepaint(); 1056} 1057 1058RenderElement& RenderElement::rendererForRootBackground() 1059{ 1060 ASSERT(isRoot()); 1061 if (!hasBackground() && element() && element()->hasTagName(HTMLNames::htmlTag)) { 1062 // Locate the <body> element using the DOM. This is easier than trying 1063 // to crawl around a render tree with potential :before/:after content and 1064 // anonymous blocks created by inline <body> tags etc. We can locate the <body> 1065 // render object very easily via the DOM. 1066 if (auto body = document().body()) { 1067 if (body->hasTagName(HTMLNames::bodyTag)) { 1068 if (auto renderer = body->renderer()) 1069 return *renderer; 1070 } 1071 } 1072 } 1073 return *this; 1074} 1075 1076RenderElement* RenderElement::hoverAncestor() const 1077{ 1078 // When searching for the hover ancestor and encountering a named flow thread, 1079 // the search will continue with the DOM ancestor of the top-most element 1080 // in the named flow thread. 1081 // See https://bugs.webkit.org/show_bug.cgi?id=111749 1082 RenderElement* hoverAncestor = parent(); 1083 1084 // Skip anonymous blocks directly flowed into flow threads as it would 1085 // prevent us from continuing the search on the DOM tree when reaching the named flow thread. 1086 if (hoverAncestor && hoverAncestor->isAnonymousBlock() && hoverAncestor->parent() && hoverAncestor->parent()->isRenderNamedFlowThread()) 1087 hoverAncestor = hoverAncestor->parent(); 1088 1089 if (hoverAncestor && hoverAncestor->isRenderNamedFlowThread()) { 1090 hoverAncestor = nullptr; 1091 if (Element* element = this->element()) { 1092 if (auto parent = element->parentNode()) 1093 hoverAncestor = parent->renderer(); 1094 } 1095 } 1096 1097 return hoverAncestor; 1098} 1099 1100void RenderElement::layout() 1101{ 1102 StackStats::LayoutCheckPoint layoutCheckPoint; 1103 ASSERT(needsLayout()); 1104 RenderObject* child = firstChild(); 1105 while (child) { 1106 if (child->needsLayout()) 1107 toRenderElement(child)->layout(); 1108 ASSERT(!child->needsLayout()); 1109 child = child->nextSibling(); 1110 } 1111 clearNeedsLayout(); 1112} 1113 1114static bool mustRepaintFillLayers(const RenderElement& renderer, const FillLayer* layer) 1115{ 1116 // Nobody will use multiple layers without wanting fancy positioning. 1117 if (layer->next()) 1118 return true; 1119 1120 // Make sure we have a valid image. 1121 StyleImage* image = layer->image(); 1122 if (!image || !image->canRender(&renderer, renderer.style().effectiveZoom())) 1123 return false; 1124 1125 if (!layer->xPosition().isZero() || !layer->yPosition().isZero()) 1126 return true; 1127 1128 EFillSizeType sizeType = layer->sizeType(); 1129 1130 if (sizeType == Contain || sizeType == Cover) 1131 return true; 1132 1133 if (sizeType == SizeLength) { 1134 LengthSize size = layer->sizeLength(); 1135 if (size.width().isPercent() || size.height().isPercent()) 1136 return true; 1137 // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'. 1138 if ((size.width().isAuto() || size.height().isAuto()) && image->isGeneratedImage()) 1139 return true; 1140 } else if (image->usesImageContainerSize()) 1141 return true; 1142 1143 return false; 1144} 1145 1146static bool mustRepaintBackgroundOrBorder(const RenderElement& renderer) 1147{ 1148 if (renderer.hasMask() && mustRepaintFillLayers(renderer, renderer.style().maskLayers())) 1149 return true; 1150 1151 // If we don't have a background/border/mask, then nothing to do. 1152 if (!renderer.hasBoxDecorations()) 1153 return false; 1154 1155 if (mustRepaintFillLayers(renderer, renderer.style().backgroundLayers())) 1156 return true; 1157 1158 // Our fill layers are ok. Let's check border. 1159 if (renderer.style().hasBorder() && renderer.borderImageIsLoadedAndCanBeRendered()) 1160 return true; 1161 1162 return false; 1163} 1164 1165bool RenderElement::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr, const LayoutRect* newOutlineBoxRectPtr) 1166{ 1167 if (view().printing()) 1168 return false; // Don't repaint if we're printing. 1169 1170 // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 1171 // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer)); 1172 LayoutRect newBounds = newBoundsPtr ? *newBoundsPtr : clippedOverflowRectForRepaint(repaintContainer); 1173 LayoutRect newOutlineBox; 1174 1175 bool fullRepaint = selfNeedsLayout(); 1176 // Presumably a background or a border exists if border-fit:lines was specified. 1177 if (!fullRepaint && style().borderFit() == BorderFitLines) 1178 fullRepaint = true; 1179 if (!fullRepaint) { 1180 // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 1181 // ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer)); 1182 newOutlineBox = newOutlineBoxRectPtr ? *newOutlineBoxRectPtr : outlineBoundsForRepaint(repaintContainer); 1183 if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder(*this) && (newBounds != oldBounds || newOutlineBox != oldOutlineBox))) 1184 fullRepaint = true; 1185 } 1186 1187 if (!repaintContainer) 1188 repaintContainer = &view(); 1189 1190 if (fullRepaint) { 1191 repaintUsingContainer(repaintContainer, oldBounds); 1192 if (newBounds != oldBounds) 1193 repaintUsingContainer(repaintContainer, newBounds); 1194 return true; 1195 } 1196 1197 if (newBounds == oldBounds && newOutlineBox == oldOutlineBox) 1198 return false; 1199 1200 LayoutUnit deltaLeft = newBounds.x() - oldBounds.x(); 1201 if (deltaLeft > 0) 1202 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height())); 1203 else if (deltaLeft < 0) 1204 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height())); 1205 1206 LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX(); 1207 if (deltaRight > 0) 1208 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height())); 1209 else if (deltaRight < 0) 1210 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height())); 1211 1212 LayoutUnit deltaTop = newBounds.y() - oldBounds.y(); 1213 if (deltaTop > 0) 1214 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop)); 1215 else if (deltaTop < 0) 1216 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop)); 1217 1218 LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY(); 1219 if (deltaBottom > 0) 1220 repaintUsingContainer(repaintContainer, LayoutRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom)); 1221 else if (deltaBottom < 0) 1222 repaintUsingContainer(repaintContainer, LayoutRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom)); 1223 1224 if (newOutlineBox == oldOutlineBox) 1225 return false; 1226 1227 // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly 1228 // two rectangles (but typically only one). 1229 const RenderStyle& outlineStyle = outlineStyleForRepaint(); 1230 LayoutUnit outlineWidth = outlineStyle.outlineSize(); 1231 LayoutBoxExtent insetShadowExtent = style().getBoxShadowInsetExtent(); 1232 LayoutUnit width = absoluteValue(newOutlineBox.width() - oldOutlineBox.width()); 1233 if (width) { 1234 LayoutUnit shadowLeft; 1235 LayoutUnit shadowRight; 1236 style().getBoxShadowHorizontalExtent(shadowLeft, shadowRight); 1237 LayoutUnit borderRight = isBox() ? toRenderBox(this)->borderRight() : LayoutUnit::fromPixel(0); 1238 LayoutUnit boxWidth = isBox() ? toRenderBox(this)->width() : LayoutUnit(); 1239 LayoutUnit minInsetRightShadowExtent = std::min<LayoutUnit>(-insetShadowExtent.right(), std::min<LayoutUnit>(newBounds.width(), oldBounds.width())); 1240 LayoutUnit borderWidth = std::max<LayoutUnit>(borderRight, std::max<LayoutUnit>(valueForLength(style().borderTopRightRadius().width(), boxWidth), valueForLength(style().borderBottomRightRadius().width(), boxWidth))); 1241 LayoutUnit decorationsWidth = std::max<LayoutUnit>(-outlineStyle.outlineOffset(), borderWidth + minInsetRightShadowExtent) + std::max<LayoutUnit>(outlineWidth, shadowRight); 1242 LayoutRect rightRect(newOutlineBox.x() + std::min(newOutlineBox.width(), oldOutlineBox.width()) - decorationsWidth, 1243 newOutlineBox.y(), 1244 width + decorationsWidth, 1245 std::max(newOutlineBox.height(), oldOutlineBox.height())); 1246 LayoutUnit right = std::min<LayoutUnit>(newBounds.maxX(), oldBounds.maxX()); 1247 if (rightRect.x() < right) { 1248 rightRect.setWidth(std::min(rightRect.width(), right - rightRect.x())); 1249 repaintUsingContainer(repaintContainer, rightRect); 1250 } 1251 } 1252 LayoutUnit height = absoluteValue(newOutlineBox.height() - oldOutlineBox.height()); 1253 if (height) { 1254 LayoutUnit shadowTop; 1255 LayoutUnit shadowBottom; 1256 style().getBoxShadowVerticalExtent(shadowTop, shadowBottom); 1257 LayoutUnit borderBottom = isBox() ? toRenderBox(this)->borderBottom() : LayoutUnit::fromPixel(0); 1258 LayoutUnit boxHeight = isBox() ? toRenderBox(this)->height() : LayoutUnit(); 1259 LayoutUnit minInsetBottomShadowExtent = std::min<LayoutUnit>(-insetShadowExtent.bottom(), std::min<LayoutUnit>(newBounds.height(), oldBounds.height())); 1260 LayoutUnit borderHeight = std::max<LayoutUnit>(borderBottom, std::max<LayoutUnit>(valueForLength(style().borderBottomLeftRadius().height(), boxHeight), 1261 valueForLength(style().borderBottomRightRadius().height(), boxHeight))); 1262 LayoutUnit decorationsHeight = std::max<LayoutUnit>(-outlineStyle.outlineOffset(), borderHeight + minInsetBottomShadowExtent) + std::max<LayoutUnit>(outlineWidth, shadowBottom); 1263 LayoutRect bottomRect(newOutlineBox.x(), 1264 std::min(newOutlineBox.maxY(), oldOutlineBox.maxY()) - decorationsHeight, 1265 std::max(newOutlineBox.width(), oldOutlineBox.width()), 1266 height + decorationsHeight); 1267 LayoutUnit bottom = std::min(newBounds.maxY(), oldBounds.maxY()); 1268 if (bottomRect.y() < bottom) { 1269 bottomRect.setHeight(std::min(bottomRect.height(), bottom - bottomRect.y())); 1270 repaintUsingContainer(repaintContainer, bottomRect); 1271 } 1272 } 1273 return false; 1274} 1275 1276bool RenderElement::borderImageIsLoadedAndCanBeRendered() const 1277{ 1278 ASSERT(style().hasBorder()); 1279 1280 StyleImage* borderImage = style().borderImage().image(); 1281 return borderImage && borderImage->canRender(this, style().effectiveZoom()) && borderImage->isLoaded(); 1282} 1283 1284static bool shouldRepaintForImageAnimation(const RenderElement& renderer, const IntRect& visibleRect) 1285{ 1286 const Document& document = renderer.document(); 1287 if (document.inPageCache()) 1288 return false; 1289 auto& frameView = renderer.view().frameView(); 1290 if (frameView.isOffscreen()) 1291 return false; 1292#if PLATFORM(IOS) 1293 if (document.frame()->timersPaused()) 1294 return false; 1295#endif 1296 if (document.activeDOMObjectsAreSuspended()) 1297 return false; 1298 if (renderer.style().visibility() != VISIBLE) 1299 return false; 1300 if (!visibleRect.intersects(renderer.absoluteBoundingBoxRect())) 1301 return false; 1302 1303 return true; 1304} 1305 1306void RenderElement::newImageAnimationFrameAvailable(CachedImage& image) 1307{ 1308 auto& frameView = view().frameView(); 1309 auto visibleRect = frameView.windowToContents(frameView.windowClipRect()); 1310 if (!shouldRepaintForImageAnimation(*this, visibleRect)) { 1311 view().addRendererWithPausedImageAnimations(*this); 1312 return; 1313 } 1314 imageChanged(&image); 1315} 1316 1317bool RenderElement::repaintForPausedImageAnimationsIfNeeded(const IntRect& visibleRect) 1318{ 1319 ASSERT(m_hasPausedImageAnimations); 1320 if (!shouldRepaintForImageAnimation(*this, visibleRect)) 1321 return false; 1322 repaint(); 1323 return true; 1324} 1325 1326RenderNamedFlowThread* RenderElement::renderNamedFlowThreadWrapper() 1327{ 1328 auto renderer = this; 1329 while (renderer && renderer->isAnonymousBlock() && !renderer->isRenderNamedFlowThread()) 1330 renderer = renderer->parent(); 1331 return renderer && renderer->isRenderNamedFlowThread() ? toRenderNamedFlowThread(renderer) : nullptr; 1332} 1333 1334bool RenderElement::hasControlStatesForRenderer(const RenderObject* o) 1335{ 1336 return controlStatesRendererMap().contains(o); 1337} 1338 1339ControlStates* RenderElement::controlStatesForRenderer(const RenderObject* o) 1340{ 1341 return controlStatesRendererMap().get(o); 1342} 1343 1344void RenderElement::removeControlStatesForRenderer(const RenderObject* o) 1345{ 1346 ControlStates* states = controlStatesRendererMap().get(o); 1347 if (states) { 1348 controlStatesRendererMap().remove(o); 1349 delete states; 1350 } 1351} 1352 1353void RenderElement::addControlStatesForRenderer(const RenderObject* o, ControlStates* states) 1354{ 1355 controlStatesRendererMap().add(o, states); 1356} 1357 1358} 1359