| Index: Source/core/rendering/RenderObject.cpp
|
| diff --git a/Source/core/rendering/RenderObject.cpp b/Source/core/rendering/RenderObject.cpp
|
| deleted file mode 100644
|
| index aaaa481c1b0117438ce9062671bf1ca24d071773..0000000000000000000000000000000000000000
|
| --- a/Source/core/rendering/RenderObject.cpp
|
| +++ /dev/null
|
| @@ -1,3178 +0,0 @@
|
| -/*
|
| - * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
|
| - * (C) 1999 Antti Koivisto (koivisto@kde.org)
|
| - * (C) 2000 Dirk Mueller (mueller@kde.org)
|
| - * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
|
| - * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
|
| - * Copyright (C) 2009 Google Inc. All rights reserved.
|
| - * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
|
| - *
|
| - * This library is free software; you can redistribute it and/or
|
| - * modify it under the terms of the GNU Library General Public
|
| - * License as published by the Free Software Foundation; either
|
| - * version 2 of the License, or (at your option) any later version.
|
| - *
|
| - * This library is distributed in the hope that it will be useful,
|
| - * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| - * Library General Public License for more details.
|
| - *
|
| - * You should have received a copy of the GNU Library General Public License
|
| - * along with this library; see the file COPYING.LIB. If not, write to
|
| - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
| - * Boston, MA 02110-1301, USA.
|
| - *
|
| - */
|
| -
|
| -#include "config.h"
|
| -#include "core/rendering/RenderObject.h"
|
| -
|
| -#include "core/HTMLNames.h"
|
| -#include "core/css/resolver/StyleResolver.h"
|
| -#include "core/dom/AXObjectCache.h"
|
| -#include "core/dom/ElementTraversal.h"
|
| -#include "core/dom/StyleEngine.h"
|
| -#include "core/dom/shadow/ShadowRoot.h"
|
| -#include "core/editing/EditingBoundary.h"
|
| -#include "core/editing/FrameSelection.h"
|
| -#include "core/editing/htmlediting.h"
|
| -#include "core/fetch/ResourceLoadPriorityOptimizer.h"
|
| -#include "core/fetch/ResourceLoader.h"
|
| -#include "core/frame/EventHandlerRegistry.h"
|
| -#include "core/frame/FrameView.h"
|
| -#include "core/frame/LocalFrame.h"
|
| -#include "core/frame/Settings.h"
|
| -#include "core/frame/UseCounter.h"
|
| -#include "core/html/HTMLAnchorElement.h"
|
| -#include "core/html/HTMLElement.h"
|
| -#include "core/html/HTMLHtmlElement.h"
|
| -#include "core/html/HTMLTableCellElement.h"
|
| -#include "core/html/HTMLTableElement.h"
|
| -#include "core/layout/HitTestResult.h"
|
| -#include "core/layout/Layer.h"
|
| -#include "core/layout/LayoutCounter.h"
|
| -#include "core/layout/LayoutTableCaption.h"
|
| -#include "core/layout/LayoutTableCell.h"
|
| -#include "core/layout/LayoutTableCol.h"
|
| -#include "core/layout/LayoutTableRow.h"
|
| -#include "core/layout/LayoutTheme.h"
|
| -#include "core/layout/compositing/CompositedLayerMapping.h"
|
| -#include "core/layout/compositing/LayerCompositor.h"
|
| -#include "core/page/AutoscrollController.h"
|
| -#include "core/page/EventHandler.h"
|
| -#include "core/page/Page.h"
|
| -#include "core/paint/ObjectPainter.h"
|
| -#include "core/rendering/RenderDeprecatedFlexibleBox.h"
|
| -#include "core/rendering/RenderFlexibleBox.h"
|
| -#include "core/rendering/RenderFlowThread.h"
|
| -#include "core/rendering/RenderGeometryMap.h"
|
| -#include "core/rendering/RenderGrid.h"
|
| -#include "core/rendering/RenderImage.h"
|
| -#include "core/rendering/RenderImageResourceStyleImage.h"
|
| -#include "core/rendering/RenderInline.h"
|
| -#include "core/rendering/RenderListItem.h"
|
| -#include "core/rendering/RenderMultiColumnSpannerPlaceholder.h"
|
| -#include "core/rendering/RenderObjectInlines.h"
|
| -#include "core/rendering/RenderPart.h"
|
| -#include "core/rendering/RenderScrollbarPart.h"
|
| -#include "core/rendering/RenderView.h"
|
| -#include "core/rendering/style/ContentData.h"
|
| -#include "core/rendering/style/ShadowList.h"
|
| -#include "platform/JSONValues.h"
|
| -#include "platform/Partitions.h"
|
| -#include "platform/RuntimeEnabledFeatures.h"
|
| -#include "platform/TraceEvent.h"
|
| -#include "platform/TracedValue.h"
|
| -#include "platform/geometry/TransformState.h"
|
| -#include "platform/graphics/GraphicsContext.h"
|
| -#include "platform/graphics/paint/DisplayItemList.h"
|
| -#include "wtf/RefCountedLeakCounter.h"
|
| -#include "wtf/text/StringBuilder.h"
|
| -#include "wtf/text/WTFString.h"
|
| -#include <algorithm>
|
| -#ifndef NDEBUG
|
| -#include <stdio.h>
|
| -#endif
|
| -
|
| -namespace blink {
|
| -
|
| -namespace {
|
| -
|
| -static bool gModifyRenderTreeStructureAnyState = false;
|
| -
|
| -} // namespace
|
| -
|
| -using namespace HTMLNames;
|
| -
|
| -#if ENABLE(ASSERT)
|
| -
|
| -RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject& renderObject)
|
| - : m_renderObject(renderObject)
|
| - , m_preexistingForbidden(m_renderObject.isSetNeedsLayoutForbidden())
|
| -{
|
| - m_renderObject.setNeedsLayoutIsForbidden(true);
|
| -}
|
| -
|
| -RenderObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope()
|
| -{
|
| - m_renderObject.setNeedsLayoutIsForbidden(m_preexistingForbidden);
|
| -}
|
| -#endif
|
| -
|
| -struct SameSizeAsRenderObject {
|
| - virtual ~SameSizeAsRenderObject() { } // Allocate vtable pointer.
|
| - void* pointers[5];
|
| -#if ENABLE(ASSERT)
|
| - unsigned m_debugBitfields : 2;
|
| -#endif
|
| - unsigned m_bitfields;
|
| - unsigned m_bitfields2;
|
| - LayoutRect rect; // Stores the previous paint invalidation rect.
|
| - LayoutPoint position; // Stores the previous position from the paint invalidation container.
|
| -};
|
| -
|
| -static_assert(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), "RenderObject should stay small");
|
| -
|
| -bool RenderObject::s_affectsParentBlock = false;
|
| -
|
| -typedef HashMap<const RenderObject*, LayoutRect> SelectionPaintInvalidationMap;
|
| -static SelectionPaintInvalidationMap* selectionPaintInvalidationMap = 0;
|
| -
|
| -void* RenderObject::operator new(size_t sz)
|
| -{
|
| - ASSERT(isMainThread());
|
| - return partitionAlloc(Partitions::getRenderingPartition(), sz);
|
| -}
|
| -
|
| -void RenderObject::operator delete(void* ptr)
|
| -{
|
| - ASSERT(isMainThread());
|
| - partitionFree(ptr);
|
| -}
|
| -
|
| -RenderObject* RenderObject::createObject(Element* element, const RenderStyle& style)
|
| -{
|
| - ASSERT(isAllowedToModifyRenderTreeStructure(element->document()));
|
| -
|
| - // Minimal support for content properties replacing an entire element.
|
| - // Works only if we have exactly one piece of content and it's a URL.
|
| - // Otherwise acts as if we didn't support this feature.
|
| - const ContentData* contentData = style.contentData();
|
| - if (contentData && !contentData->next() && contentData->isImage() && !element->isPseudoElement()) {
|
| - RenderImage* image = new RenderImage(element);
|
| - // RenderImageResourceStyleImage requires a style being present on the image but we don't want to
|
| - // trigger a style change now as the node is not fully attached. Moving this code to style change
|
| - // doesn't make sense as it should be run once at renderer creation.
|
| - image->setStyleInternal(const_cast<RenderStyle*>(&style));
|
| - if (const StyleImage* styleImage = toImageContentData(contentData)->image()) {
|
| - image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage)));
|
| - image->setIsGeneratedContent();
|
| - } else
|
| - image->setImageResource(RenderImageResource::create());
|
| - image->setStyleInternal(nullptr);
|
| - return image;
|
| - }
|
| -
|
| - switch (style.display()) {
|
| - case NONE:
|
| - return 0;
|
| - case INLINE:
|
| - return new RenderInline(element);
|
| - case BLOCK:
|
| - case INLINE_BLOCK:
|
| - return new RenderBlockFlow(element);
|
| - case LIST_ITEM:
|
| - return new RenderListItem(element);
|
| - case TABLE:
|
| - case INLINE_TABLE:
|
| - return new LayoutTable(element);
|
| - case TABLE_ROW_GROUP:
|
| - case TABLE_HEADER_GROUP:
|
| - case TABLE_FOOTER_GROUP:
|
| - return new LayoutTableSection(element);
|
| - case TABLE_ROW:
|
| - return new LayoutTableRow(element);
|
| - case TABLE_COLUMN_GROUP:
|
| - case TABLE_COLUMN:
|
| - return new LayoutTableCol(element);
|
| - case TABLE_CELL:
|
| - return new LayoutTableCell(element);
|
| - case TABLE_CAPTION:
|
| - return new LayoutTableCaption(element);
|
| - case BOX:
|
| - case INLINE_BOX:
|
| - return new RenderDeprecatedFlexibleBox(*element);
|
| - case FLEX:
|
| - case INLINE_FLEX:
|
| - return new RenderFlexibleBox(element);
|
| - case GRID:
|
| - case INLINE_GRID:
|
| - return new RenderGrid(element);
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("RenderObject"));
|
| -unsigned RenderObject::s_instanceCount = 0;
|
| -
|
| -RenderObject::RenderObject(Node* node)
|
| - : ImageResourceClient()
|
| - , m_style(nullptr)
|
| - , m_node(node)
|
| - , m_parent(nullptr)
|
| - , m_previous(nullptr)
|
| - , m_next(nullptr)
|
| -#if ENABLE(ASSERT)
|
| - , m_hasAXObject(false)
|
| - , m_setNeedsLayoutForbidden(false)
|
| -#endif
|
| - , m_bitfields(node)
|
| -{
|
| -#ifndef NDEBUG
|
| - renderObjectCounter.increment();
|
| -#endif
|
| - ++s_instanceCount;
|
| -}
|
| -
|
| -RenderObject::~RenderObject()
|
| -{
|
| - ASSERT(!m_hasAXObject);
|
| -#ifndef NDEBUG
|
| - renderObjectCounter.decrement();
|
| -#endif
|
| - --s_instanceCount;
|
| -}
|
| -
|
| -String RenderObject::debugName() const
|
| -{
|
| - StringBuilder name;
|
| - name.append(renderName());
|
| -
|
| - if (Node* node = this->node()) {
|
| - name.append(' ');
|
| - name.append(node->debugName());
|
| - }
|
| -
|
| - return name.toString();
|
| -}
|
| -
|
| -bool RenderObject::isDescendantOf(const RenderObject* obj) const
|
| -{
|
| - for (const RenderObject* r = this; r; r = r->m_parent) {
|
| - if (r == obj)
|
| - return true;
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -bool RenderObject::isHR() const
|
| -{
|
| - return isHTMLHRElement(node());
|
| -}
|
| -
|
| -bool RenderObject::isLegend() const
|
| -{
|
| - return isHTMLLegendElement(node());
|
| -}
|
| -
|
| -void RenderObject::setFlowThreadStateIncludingDescendants(FlowThreadState state)
|
| -{
|
| - for (RenderObject *object = this; object; object = object->nextInPreOrder(this)) {
|
| - // If object is a fragmentation context it already updated the descendants flag accordingly.
|
| - if (object->isRenderFlowThread())
|
| - continue;
|
| - ASSERT(state != object->flowThreadState());
|
| - object->setFlowThreadState(state);
|
| - }
|
| -}
|
| -
|
| -bool RenderObject::requiresAnonymousTableWrappers(const RenderObject* newChild) const
|
| -{
|
| - // Check should agree with:
|
| - // CSS 2.1 Tables: 17.2.1 Anonymous table objects
|
| - // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
|
| - if (newChild->isLayoutTableCol()) {
|
| - const LayoutTableCol* newTableColumn = toLayoutTableCol(newChild);
|
| - bool isColumnInColumnGroup = newTableColumn->isTableColumn() && isLayoutTableCol();
|
| - return !isTable() && !isColumnInColumnGroup;
|
| - }
|
| - if (newChild->isTableCaption())
|
| - return !isTable();
|
| - if (newChild->isTableSection())
|
| - return !isTable();
|
| - if (newChild->isTableRow())
|
| - return !isTableSection();
|
| - if (newChild->isTableCell())
|
| - return !isTableRow();
|
| - return false;
|
| -}
|
| -
|
| -void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
|
| -{
|
| - ASSERT(isAllowedToModifyRenderTreeStructure(document()));
|
| -
|
| - RenderObjectChildList* children = virtualChildren();
|
| - ASSERT(children);
|
| - if (!children)
|
| - return;
|
| -
|
| - if (requiresAnonymousTableWrappers(newChild)) {
|
| - // Generate an anonymous table or reuse existing one from previous child
|
| - // Per: 17.2.1 Anonymous table objects 3. Generate missing parents
|
| - // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
|
| - LayoutTable* table;
|
| - RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : children->lastChild();
|
| - if (afterChild && afterChild->isAnonymous() && afterChild->isTable() && !afterChild->isBeforeContent())
|
| - table = toLayoutTable(afterChild);
|
| - else {
|
| - table = LayoutTable::createAnonymousWithParentRenderer(this);
|
| - addChild(table, beforeChild);
|
| - }
|
| - table->addChild(newChild);
|
| - } else
|
| - children->insertChildNode(this, newChild, beforeChild);
|
| -
|
| - if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE)
|
| - toRenderText(newChild)->transformText();
|
| -
|
| - // SVG creates renderers for <g display="none">, as SVG requires children of hidden
|
| - // <g>s to have renderers - at least that's how our implementation works. Consider:
|
| - // <g display="none"><foreignObject><body style="position: relative">FOO...
|
| - // - layerTypeRequired() would return true for the <body>, creating a new Layer
|
| - // - when the document is painted, both layers are painted. The <body> layer doesn't
|
| - // know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't.
|
| - // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree
|
| - // and stop creating layers at all for these cases - they're not used anyways.
|
| - if (newChild->hasLayer() && !layerCreationAllowedForSubtree())
|
| - toLayoutLayerModelObject(newChild)->layer()->removeOnlyThisLayer();
|
| -}
|
| -
|
| -void RenderObject::removeChild(RenderObject* oldChild)
|
| -{
|
| - ASSERT(isAllowedToModifyRenderTreeStructure(document()));
|
| -
|
| - RenderObjectChildList* children = virtualChildren();
|
| - ASSERT(children);
|
| - if (!children)
|
| - return;
|
| -
|
| - children->removeChildNode(this, oldChild);
|
| -}
|
| -
|
| -RenderObject* RenderObject::nextInPreOrder() const
|
| -{
|
| - if (RenderObject* o = slowFirstChild())
|
| - return o;
|
| -
|
| - return nextInPreOrderAfterChildren();
|
| -}
|
| -
|
| -RenderObject* RenderObject::nextInPreOrderAfterChildren() const
|
| -{
|
| - RenderObject* o = nextSibling();
|
| - if (!o) {
|
| - o = parent();
|
| - while (o && !o->nextSibling())
|
| - o = o->parent();
|
| - if (o)
|
| - o = o->nextSibling();
|
| - }
|
| -
|
| - return o;
|
| -}
|
| -
|
| -RenderObject* RenderObject::nextInPreOrder(const RenderObject* stayWithin) const
|
| -{
|
| - if (RenderObject* o = slowFirstChild())
|
| - return o;
|
| -
|
| - return nextInPreOrderAfterChildren(stayWithin);
|
| -}
|
| -
|
| -RenderObject* RenderObject::nextInPreOrderAfterChildren(const RenderObject* stayWithin) const
|
| -{
|
| - if (this == stayWithin)
|
| - return 0;
|
| -
|
| - const RenderObject* current = this;
|
| - RenderObject* next = current->nextSibling();
|
| - for (; !next; next = current->nextSibling()) {
|
| - current = current->parent();
|
| - if (!current || current == stayWithin)
|
| - return 0;
|
| - }
|
| - return next;
|
| -}
|
| -
|
| -RenderObject* RenderObject::previousInPreOrder() const
|
| -{
|
| - if (RenderObject* o = previousSibling()) {
|
| - while (RenderObject* lastChild = o->slowLastChild())
|
| - o = lastChild;
|
| - return o;
|
| - }
|
| -
|
| - return parent();
|
| -}
|
| -
|
| -RenderObject* RenderObject::previousInPreOrder(const RenderObject* stayWithin) const
|
| -{
|
| - if (this == stayWithin)
|
| - return 0;
|
| -
|
| - return previousInPreOrder();
|
| -}
|
| -
|
| -RenderObject* RenderObject::childAt(unsigned index) const
|
| -{
|
| - RenderObject* child = slowFirstChild();
|
| - for (unsigned i = 0; child && i < index; i++)
|
| - child = child->nextSibling();
|
| - return child;
|
| -}
|
| -
|
| -RenderObject* RenderObject::lastLeafChild() const
|
| -{
|
| - RenderObject* r = slowLastChild();
|
| - while (r) {
|
| - RenderObject* n = 0;
|
| - n = r->slowLastChild();
|
| - if (!n)
|
| - break;
|
| - r = n;
|
| - }
|
| - return r;
|
| -}
|
| -
|
| -static void addLayers(RenderObject* obj, Layer* parentLayer, RenderObject*& newObject,
|
| - Layer*& beforeChild)
|
| -{
|
| - if (obj->hasLayer()) {
|
| - if (!beforeChild && newObject) {
|
| - // We need to figure out the layer that follows newObject. We only do
|
| - // this the first time we find a child layer, and then we update the
|
| - // pointer values for newObject and beforeChild used by everyone else.
|
| - beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
|
| - newObject = 0;
|
| - }
|
| - parentLayer->addChild(toLayoutLayerModelObject(obj)->layer(), beforeChild);
|
| - return;
|
| - }
|
| -
|
| - for (RenderObject* curr = obj->slowFirstChild(); curr; curr = curr->nextSibling())
|
| - addLayers(curr, parentLayer, newObject, beforeChild);
|
| -}
|
| -
|
| -void RenderObject::addLayers(Layer* parentLayer)
|
| -{
|
| - if (!parentLayer)
|
| - return;
|
| -
|
| - RenderObject* object = this;
|
| - Layer* beforeChild = 0;
|
| - blink::addLayers(this, parentLayer, object, beforeChild);
|
| -}
|
| -
|
| -void RenderObject::removeLayers(Layer* parentLayer)
|
| -{
|
| - if (!parentLayer)
|
| - return;
|
| -
|
| - if (hasLayer()) {
|
| - parentLayer->removeChild(toLayoutLayerModelObject(this)->layer());
|
| - return;
|
| - }
|
| -
|
| - for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
|
| - curr->removeLayers(parentLayer);
|
| -}
|
| -
|
| -void RenderObject::moveLayers(Layer* oldParent, Layer* newParent)
|
| -{
|
| - if (!newParent)
|
| - return;
|
| -
|
| - if (hasLayer()) {
|
| - Layer* layer = toLayoutLayerModelObject(this)->layer();
|
| - ASSERT(oldParent == layer->parent());
|
| - if (oldParent)
|
| - oldParent->removeChild(layer);
|
| - newParent->addChild(layer);
|
| - return;
|
| - }
|
| -
|
| - for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
|
| - curr->moveLayers(oldParent, newParent);
|
| -}
|
| -
|
| -Layer* RenderObject::findNextLayer(Layer* parentLayer, RenderObject* startPoint,
|
| - bool checkParent)
|
| -{
|
| - // Error check the parent layer passed in. If it's null, we can't find anything.
|
| - if (!parentLayer)
|
| - return 0;
|
| -
|
| - // Step 1: If our layer is a child of the desired parent, then return our layer.
|
| - Layer* ourLayer = hasLayer() ? toLayoutLayerModelObject(this)->layer() : 0;
|
| - if (ourLayer && ourLayer->parent() == parentLayer)
|
| - return ourLayer;
|
| -
|
| - // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
|
| - // into our siblings trying to find the next layer whose parent is the desired parent.
|
| - if (!ourLayer || ourLayer == parentLayer) {
|
| - for (RenderObject* curr = startPoint ? startPoint->nextSibling() : slowFirstChild();
|
| - curr; curr = curr->nextSibling()) {
|
| - Layer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
|
| - if (nextLayer)
|
| - return nextLayer;
|
| - }
|
| - }
|
| -
|
| - // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
|
| - // find anything.
|
| - if (parentLayer == ourLayer)
|
| - return 0;
|
| -
|
| - // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
|
| - // follow us to see if we can locate a layer.
|
| - if (checkParent && parent())
|
| - return parent()->findNextLayer(parentLayer, this, true);
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -Layer* RenderObject::enclosingLayer() const
|
| -{
|
| - for (const RenderObject* current = this; current; current = current->parent()) {
|
| - if (current->hasLayer())
|
| - return toLayoutLayerModelObject(current)->layer();
|
| - }
|
| - // FIXME: we should get rid of detached render subtrees, at which point this code should
|
| - // not be reached. crbug.com/411429
|
| - return 0;
|
| -}
|
| -
|
| -bool RenderObject::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
|
| -{
|
| - RenderBox* enclosingBox = this->enclosingBox();
|
| - if (!enclosingBox)
|
| - return false;
|
| -
|
| - enclosingBox->scrollRectToVisible(rect, alignX, alignY);
|
| - return true;
|
| -}
|
| -
|
| -RenderBox* RenderObject::enclosingBox() const
|
| -{
|
| - RenderObject* curr = const_cast<RenderObject*>(this);
|
| - while (curr) {
|
| - if (curr->isBox())
|
| - return toRenderBox(curr);
|
| - curr = curr->parent();
|
| - }
|
| -
|
| - ASSERT_NOT_REACHED();
|
| - return 0;
|
| -}
|
| -
|
| -RenderBoxModelObject* RenderObject::enclosingBoxModelObject() const
|
| -{
|
| - RenderObject* curr = const_cast<RenderObject*>(this);
|
| - while (curr) {
|
| - if (curr->isBoxModelObject())
|
| - return toRenderBoxModelObject(curr);
|
| - curr = curr->parent();
|
| - }
|
| -
|
| - ASSERT_NOT_REACHED();
|
| - return 0;
|
| -}
|
| -
|
| -RenderBox* RenderObject::enclosingScrollableBox() const
|
| -{
|
| - for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
|
| - if (!ancestor->isBox())
|
| - continue;
|
| -
|
| - RenderBox* ancestorBox = toRenderBox(ancestor);
|
| - if (ancestorBox->canBeScrolledAndHasScrollableArea())
|
| - return ancestorBox;
|
| - }
|
| -
|
| - return 0;
|
| -}
|
| -
|
| -RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const
|
| -{
|
| - ASSERT(flowThreadState() != NotInsideFlowThread);
|
| -
|
| - // See if we have the thread cached because we're in the middle of layout.
|
| - if (LayoutState* layoutState = view()->layoutState()) {
|
| - if (RenderFlowThread* flowThread = layoutState->flowThread())
|
| - return flowThread;
|
| - }
|
| -
|
| - // Not in the middle of layout so have to find the thread the slow way.
|
| - RenderObject* curr = const_cast<RenderObject*>(this);
|
| - while (curr) {
|
| - if (curr->isRenderFlowThread())
|
| - return toRenderFlowThread(curr);
|
| - curr = curr->containingBlock();
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -bool RenderObject::skipInvalidationWhenLaidOutChildren() const
|
| -{
|
| - if (!neededLayoutBecauseOfChildren())
|
| - return false;
|
| -
|
| - // SVG renderers need to be invalidated when their children are laid out.
|
| - // RenderBlocks with line boxes are responsible to invalidate them so we can't ignore them.
|
| - if (isSVG() || (isRenderBlockFlow() && toRenderBlockFlow(this)->firstLineBox()))
|
| - return false;
|
| -
|
| - return rendererHasNoBoxEffect();
|
| -}
|
| -
|
| -RenderBlock* RenderObject::firstLineBlock() const
|
| -{
|
| - return 0;
|
| -}
|
| -
|
| -static inline bool objectIsRelayoutBoundary(const RenderObject* object)
|
| -{
|
| - // FIXME: In future it may be possible to broaden these conditions in order to improve performance.
|
| - if (object->isTextControl())
|
| - return true;
|
| -
|
| - if (object->isSVGRoot())
|
| - return true;
|
| -
|
| - if (!object->hasOverflowClip())
|
| - return false;
|
| -
|
| - if (object->style()->width().isIntrinsicOrAuto() || object->style()->height().isIntrinsicOrAuto() || object->style()->height().isPercent())
|
| - return false;
|
| -
|
| - // Table parts can't be relayout roots since the table is responsible for layouting all the parts.
|
| - if (object->isTablePart())
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot, SubtreeLayoutScope* layouter)
|
| -{
|
| - ASSERT(!scheduleRelayout || !newRoot);
|
| - ASSERT(!isSetNeedsLayoutForbidden());
|
| - ASSERT(!layouter || this != layouter->root());
|
| -
|
| - RenderObject* object = container();
|
| - RenderObject* last = this;
|
| -
|
| - bool simplifiedNormalFlowLayout = needsSimplifiedNormalFlowLayout() && !selfNeedsLayout() && !normalChildNeedsLayout();
|
| -
|
| - while (object) {
|
| - if (object->selfNeedsLayout())
|
| - return;
|
| -
|
| - // Don't mark the outermost object of an unrooted subtree. That object will be
|
| - // marked when the subtree is added to the document.
|
| - RenderObject* container = object->container();
|
| - if (!container && !object->isRenderView())
|
| - return;
|
| - if (!last->isText() && last->style()->hasOutOfFlowPosition()) {
|
| - bool willSkipRelativelyPositionedInlines = !object->isRenderBlock() || object->isAnonymousBlock();
|
| - // Skip relatively positioned inlines and anonymous blocks to get to the enclosing RenderBlock.
|
| - while (object && (!object->isRenderBlock() || object->isAnonymousBlock()))
|
| - object = object->container();
|
| - if (!object || object->posChildNeedsLayout())
|
| - return;
|
| - if (willSkipRelativelyPositionedInlines)
|
| - container = object->container();
|
| - object->setPosChildNeedsLayout(true);
|
| - simplifiedNormalFlowLayout = true;
|
| - ASSERT(!object->isSetNeedsLayoutForbidden());
|
| - } else if (simplifiedNormalFlowLayout) {
|
| - if (object->needsSimplifiedNormalFlowLayout())
|
| - return;
|
| - object->setNeedsSimplifiedNormalFlowLayout(true);
|
| - ASSERT(!object->isSetNeedsLayoutForbidden());
|
| - } else {
|
| - if (object->normalChildNeedsLayout())
|
| - return;
|
| - object->setNormalChildNeedsLayout(true);
|
| - ASSERT(!object->isSetNeedsLayoutForbidden());
|
| - }
|
| -
|
| - if (layouter) {
|
| - layouter->addRendererToLayout(object);
|
| - if (object == layouter->root())
|
| - return;
|
| - }
|
| -
|
| - if (object == newRoot)
|
| - return;
|
| -
|
| - last = object;
|
| - if (scheduleRelayout && objectIsRelayoutBoundary(last))
|
| - break;
|
| - object = container;
|
| - }
|
| -
|
| - if (scheduleRelayout)
|
| - last->scheduleRelayout();
|
| -}
|
| -
|
| -#if ENABLE(ASSERT)
|
| -void RenderObject::checkBlockPositionedObjectsNeedLayout()
|
| -{
|
| - ASSERT(!needsLayout());
|
| -
|
| - if (isRenderBlock())
|
| - toRenderBlock(this)->checkPositionedObjectsNeedLayout();
|
| -}
|
| -#endif
|
| -
|
| -void RenderObject::setPreferredLogicalWidthsDirty(MarkingBehavior markParents)
|
| -{
|
| - m_bitfields.setPreferredLogicalWidthsDirty(true);
|
| - if (markParents == MarkContainingBlockChain && (isText() || !style()->hasOutOfFlowPosition()))
|
| - invalidateContainerPreferredLogicalWidths();
|
| -}
|
| -
|
| -void RenderObject::clearPreferredLogicalWidthsDirty()
|
| -{
|
| - m_bitfields.setPreferredLogicalWidthsDirty(false);
|
| -}
|
| -
|
| -void RenderObject::invalidateContainerPreferredLogicalWidths()
|
| -{
|
| - // In order to avoid pathological behavior when inlines are deeply nested, we do include them
|
| - // in the chain that we mark dirty (even though they're kind of irrelevant).
|
| - RenderObject* o = isTableCell() ? containingBlock() : container();
|
| - while (o && !o->preferredLogicalWidthsDirty()) {
|
| - // Don't invalidate the outermost object of an unrooted subtree. That object will be
|
| - // invalidated when the subtree is added to the document.
|
| - RenderObject* container = o->isTableCell() ? o->containingBlock() : o->container();
|
| - if (!container && !o->isRenderView())
|
| - break;
|
| -
|
| - o->m_bitfields.setPreferredLogicalWidthsDirty(true);
|
| - if (o->style()->hasOutOfFlowPosition())
|
| - // A positioned object has no effect on the min/max width of its containing block ever.
|
| - // We can optimize this case and not go up any further.
|
| - break;
|
| - o = container;
|
| - }
|
| -}
|
| -
|
| -RenderBlock* RenderObject::containerForFixedPosition(const LayoutLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const
|
| -{
|
| - ASSERT(!paintInvalidationContainerSkipped || !*paintInvalidationContainerSkipped);
|
| - ASSERT(!isText());
|
| - ASSERT(style()->position() == FixedPosition);
|
| -
|
| - RenderObject* ancestor = parent();
|
| - for (; ancestor && !ancestor->canContainFixedPositionObjects(); ancestor = ancestor->parent()) {
|
| - if (paintInvalidationContainerSkipped && ancestor == paintInvalidationContainer)
|
| - *paintInvalidationContainerSkipped = true;
|
| - }
|
| -
|
| - ASSERT(!ancestor || !ancestor->isAnonymousBlock());
|
| - return toRenderBlock(ancestor);
|
| -}
|
| -
|
| -RenderBlock* RenderObject::containingBlock() const
|
| -{
|
| - RenderObject* o = parent();
|
| - if (!o && isRenderScrollbarPart())
|
| - o = toRenderScrollbarPart(this)->rendererOwningScrollbar();
|
| - if (!isText() && m_style->position() == FixedPosition) {
|
| - return containerForFixedPosition();
|
| - } else if (!isText() && m_style->position() == AbsolutePosition) {
|
| - while (o) {
|
| - // For relpositioned inlines, we return the nearest non-anonymous enclosing block. We don't try
|
| - // to return the inline itself. This allows us to avoid having a positioned objects
|
| - // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
|
| - // from this method. The container() method can actually be used to obtain the
|
| - // inline directly.
|
| - if (o->style()->position() != StaticPosition && (!o->isInline() || o->isReplaced()))
|
| - break;
|
| -
|
| - if (o->canContainFixedPositionObjects())
|
| - break;
|
| -
|
| - if (o->style()->hasInFlowPosition() && o->isInline() && !o->isReplaced()) {
|
| - o = o->containingBlock();
|
| - break;
|
| - }
|
| -
|
| - o = o->parent();
|
| - }
|
| -
|
| - if (o && !o->isRenderBlock())
|
| - o = o->containingBlock();
|
| -
|
| - while (o && o->isAnonymousBlock())
|
| - o = o->containingBlock();
|
| - } else if (isColumnSpanAll()) {
|
| - o = spannerPlaceholder()->containingBlock();
|
| - } else {
|
| - while (o && ((o->isInline() && !o->isReplaced()) || !o->isRenderBlock()))
|
| - o = o->parent();
|
| - }
|
| -
|
| - if (!o || !o->isRenderBlock())
|
| - return 0; // This can still happen in case of an orphaned tree
|
| -
|
| - return toRenderBlock(o);
|
| -}
|
| -
|
| -bool RenderObject::canRenderBorderImage() const
|
| -{
|
| - if (!style()->hasBorder())
|
| - return false;
|
| -
|
| - StyleImage* borderImage = style()->borderImage().image();
|
| - return borderImage && borderImage->canRender(*this, style()->effectiveZoom()) && borderImage->isLoaded();
|
| -}
|
| -
|
| -bool RenderObject::mustInvalidateFillLayersPaintOnWidthChange(const FillLayer& layer) const
|
| -{
|
| - // Nobody will use multiple layers without wanting fancy positioning.
|
| - if (layer.next())
|
| - return true;
|
| -
|
| - // Make sure we have a valid image.
|
| - StyleImage* img = layer.image();
|
| - if (!img || !img->canRender(*this, style()->effectiveZoom()))
|
| - return false;
|
| -
|
| - if (layer.repeatX() != RepeatFill && layer.repeatX() != NoRepeatFill)
|
| - return true;
|
| -
|
| - if (layer.xPosition().isPercent() && !layer.xPosition().isZero())
|
| - return true;
|
| -
|
| - if (layer.backgroundXOrigin() != LeftEdge)
|
| - return true;
|
| -
|
| - EFillSizeType sizeType = layer.sizeType();
|
| -
|
| - if (sizeType == Contain || sizeType == Cover)
|
| - return true;
|
| -
|
| - if (sizeType == SizeLength) {
|
| - if (layer.sizeLength().width().isPercent() && !layer.sizeLength().width().isZero())
|
| - return true;
|
| - if (img->isGeneratedImage() && layer.sizeLength().width().isAuto())
|
| - return true;
|
| - } else if (img->usesImageContainerSize()) {
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -bool RenderObject::mustInvalidateFillLayersPaintOnHeightChange(const FillLayer& layer) const
|
| -{
|
| - // Nobody will use multiple layers without wanting fancy positioning.
|
| - if (layer.next())
|
| - return true;
|
| -
|
| - // Make sure we have a valid image.
|
| - StyleImage* img = layer.image();
|
| - if (!img || !img->canRender(*this, style()->effectiveZoom()))
|
| - return false;
|
| -
|
| - if (layer.repeatY() != RepeatFill && layer.repeatY() != NoRepeatFill)
|
| - return true;
|
| -
|
| - if (layer.yPosition().isPercent() && !layer.yPosition().isZero())
|
| - return true;
|
| -
|
| - if (layer.backgroundYOrigin() != TopEdge)
|
| - return true;
|
| -
|
| - EFillSizeType sizeType = layer.sizeType();
|
| -
|
| - if (sizeType == Contain || sizeType == Cover)
|
| - return true;
|
| -
|
| - if (sizeType == SizeLength) {
|
| - if (layer.sizeLength().height().isPercent() && !layer.sizeLength().height().isZero())
|
| - return true;
|
| - if (img->isGeneratedImage() && layer.sizeLength().height().isAuto())
|
| - return true;
|
| - } else if (img->usesImageContainerSize()) {
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -bool RenderObject::mustInvalidateBackgroundOrBorderPaintOnWidthChange() const
|
| -{
|
| - if (hasMask() && mustInvalidateFillLayersPaintOnWidthChange(style()->maskLayers()))
|
| - return true;
|
| -
|
| - // If we don't have a background/border/mask, then nothing to do.
|
| - if (!hasBoxDecorationBackground())
|
| - return false;
|
| -
|
| - if (mustInvalidateFillLayersPaintOnWidthChange(style()->backgroundLayers()))
|
| - return true;
|
| -
|
| - // Our fill layers are ok. Let's check border.
|
| - if (style()->hasBorder() && canRenderBorderImage())
|
| - return true;
|
| -
|
| - return false;
|
| -}
|
| -
|
| -bool RenderObject::mustInvalidateBackgroundOrBorderPaintOnHeightChange() const
|
| -{
|
| - if (hasMask() && mustInvalidateFillLayersPaintOnHeightChange(style()->maskLayers()))
|
| - return true;
|
| -
|
| - // If we don't have a background/border/mask, then nothing to do.
|
| - if (!hasBoxDecorationBackground())
|
| - return false;
|
| -
|
| - if (mustInvalidateFillLayersPaintOnHeightChange(style()->backgroundLayers()))
|
| - return true;
|
| -
|
| - // Our fill layers are ok. Let's check border.
|
| - if (style()->hasBorder() && canRenderBorderImage())
|
| - return true;
|
| -
|
| - return false;
|
| -}
|
| -
|
| -IntRect RenderObject::absoluteBoundingBoxRect() const
|
| -{
|
| - Vector<FloatQuad> quads;
|
| - absoluteQuads(quads);
|
| -
|
| - size_t n = quads.size();
|
| - if (!n)
|
| - return IntRect();
|
| -
|
| - IntRect result = quads[0].enclosingBoundingBox();
|
| - for (size_t i = 1; i < n; ++i)
|
| - result.unite(quads[i].enclosingBoundingBox());
|
| - return result;
|
| -}
|
| -
|
| -IntRect RenderObject::absoluteBoundingBoxRectIgnoringTransforms() const
|
| -{
|
| - FloatPoint absPos = localToAbsolute();
|
| - Vector<IntRect> rects;
|
| - absoluteRects(rects, flooredLayoutPoint(absPos));
|
| -
|
| - size_t n = rects.size();
|
| - if (!n)
|
| - return IntRect();
|
| -
|
| - LayoutRect result = rects[0];
|
| - for (size_t i = 1; i < n; ++i)
|
| - result.unite(rects[i]);
|
| - return pixelSnappedIntRect(result);
|
| -}
|
| -
|
| -IntRect RenderObject::absoluteFocusRingBoundingBoxRect() const
|
| -{
|
| - Vector<LayoutRect> rects;
|
| - const LayoutLayerModelObject* container = enclosingLayer()->renderer();
|
| - addFocusRingRects(rects, LayoutPoint(localToContainerPoint(FloatPoint(), container)));
|
| - return container->localToAbsoluteQuad(FloatQuad(unionRect(rects))).enclosingBoundingBox();
|
| -}
|
| -
|
| -FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range)
|
| -{
|
| - if (!range || !range->startContainer())
|
| - return FloatRect();
|
| -
|
| - range->ownerDocument().updateLayout();
|
| -
|
| - Vector<FloatQuad> quads;
|
| - range->textQuads(quads);
|
| -
|
| - FloatRect result;
|
| - for (size_t i = 0; i < quads.size(); ++i)
|
| - result.unite(quads[i].boundingBox());
|
| -
|
| - return result;
|
| -}
|
| -
|
| -void RenderObject::addAbsoluteRectForLayer(LayoutRect& result)
|
| -{
|
| - if (hasLayer())
|
| - result.unite(absoluteBoundingBoxRect());
|
| - for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling())
|
| - current->addAbsoluteRectForLayer(result);
|
| -}
|
| -
|
| -LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
|
| -{
|
| - LayoutRect result = absoluteBoundingBoxRect();
|
| - topLevelRect = result;
|
| - for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling())
|
| - current->addAbsoluteRectForLayer(result);
|
| - return result;
|
| -}
|
| -
|
| -void RenderObject::paint(const PaintInfo&, const LayoutPoint&)
|
| -{
|
| -}
|
| -
|
| -const LayoutLayerModelObject* RenderObject::containerForPaintInvalidation() const
|
| -{
|
| - RELEASE_ASSERT(isRooted());
|
| - return adjustCompositedContainerForSpecialAncestors(enclosingCompositedContainer());
|
| -}
|
| -
|
| -const LayoutLayerModelObject* RenderObject::enclosingCompositedContainer() const
|
| -{
|
| - LayoutLayerModelObject* container = 0;
|
| - // FIXME: CompositingState is not necessarily up to date for many callers of this function.
|
| - DisableCompositingQueryAsserts disabler;
|
| -
|
| - if (Layer* compositingLayer = enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries())
|
| - container = compositingLayer->renderer();
|
| - return container;
|
| -}
|
| -
|
| -const LayoutLayerModelObject* RenderObject::adjustCompositedContainerForSpecialAncestors(const LayoutLayerModelObject* paintInvalidationContainer) const
|
| -{
|
| - if (paintInvalidationContainer)
|
| - return paintInvalidationContainer;
|
| -
|
| - RenderView* renderView = view();
|
| - while (renderView->frame()->ownerRenderer())
|
| - renderView = renderView->frame()->ownerRenderer()->view();
|
| - return renderView;
|
| -}
|
| -
|
| -bool RenderObject::isPaintInvalidationContainer() const
|
| -{
|
| - return hasLayer() && toLayoutLayerModelObject(this)->layer()->isPaintInvalidationContainer();
|
| -}
|
| -
|
| -template <typename T>
|
| -void addJsonObjectForRect(TracedValue* value, const char* name, const T& rect)
|
| -{
|
| - value->beginDictionary(name);
|
| - value->setDouble("x", rect.x());
|
| - value->setDouble("y", rect.y());
|
| - value->setDouble("width", rect.width());
|
| - value->setDouble("height", rect.height());
|
| - value->endDictionary();
|
| -}
|
| -
|
| -template <typename T>
|
| -void addJsonObjectForPoint(TracedValue* value, const char* name, const T& point)
|
| -{
|
| - value->beginDictionary(name);
|
| - value->setDouble("x", point.x());
|
| - value->setDouble("y", point.y());
|
| - value->endDictionary();
|
| -}
|
| -
|
| -static PassRefPtr<TraceEvent::ConvertableToTraceFormat> jsonObjectForPaintInvalidationInfo(const LayoutRect& rect, const String& invalidationReason)
|
| -{
|
| - RefPtr<TracedValue> value = TracedValue::create();
|
| - addJsonObjectForRect(value.get(), "rect", rect);
|
| - value->setString("invalidation_reason", invalidationReason);
|
| - return value;
|
| -}
|
| -
|
| -LayoutRect RenderObject::computePaintInvalidationRect(const LayoutLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
|
| -{
|
| - return clippedOverflowRectForPaintInvalidation(paintInvalidationContainer, paintInvalidationState);
|
| -}
|
| -
|
| -void RenderObject::invalidatePaintUsingContainer(const LayoutLayerModelObject* paintInvalidationContainer, const LayoutRect& r, PaintInvalidationReason invalidationReason) const
|
| -{
|
| - if (r.isEmpty())
|
| - return;
|
| -
|
| - if (RuntimeEnabledFeatures::slimmingPaintEnabled()) {
|
| - if (Layer* container = enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries())
|
| - invalidateDisplayItemClients(container->graphicsLayerBacking()->displayItemList());
|
| - }
|
| -
|
| - RELEASE_ASSERT(isRooted());
|
| -
|
| - // FIXME: Unify "devtools.timeline.invalidationTracking" and "blink.invalidation". crbug.com/413527.
|
| - TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
|
| - "PaintInvalidationTracking",
|
| - "data", InspectorPaintInvalidationTrackingEvent::data(this, paintInvalidationContainer));
|
| - TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintUsingContainer()",
|
| - "object", this->debugName().ascii(),
|
| - "info", jsonObjectForPaintInvalidationInfo(r, paintInvalidationReasonToString(invalidationReason)));
|
| -
|
| - if (paintInvalidationContainer->isRenderView()) {
|
| - toRenderView(paintInvalidationContainer)->invalidatePaintForRectangle(r, invalidationReason);
|
| - return;
|
| - }
|
| -
|
| - if (paintInvalidationContainer->view()->usesCompositing()) {
|
| - ASSERT(paintInvalidationContainer->isPaintInvalidationContainer());
|
| - paintInvalidationContainer->setBackingNeedsPaintInvalidationInRect(r, invalidationReason);
|
| - }
|
| -}
|
| -
|
| -void RenderObject::invalidateDisplayItemClients(DisplayItemList* displayItemList) const
|
| -{
|
| - displayItemList->invalidate(displayItemClient());
|
| -}
|
| -
|
| -LayoutRect RenderObject::boundsRectForPaintInvalidation(const LayoutLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const
|
| -{
|
| - if (!paintInvalidationContainer)
|
| - return computePaintInvalidationRect(paintInvalidationContainer, paintInvalidationState);
|
| - return Layer::computePaintInvalidationRect(this, paintInvalidationContainer->layer(), paintInvalidationState);
|
| -}
|
| -
|
| -void RenderObject::invalidatePaintRectangle(const LayoutRect& r) const
|
| -{
|
| - RELEASE_ASSERT(isRooted());
|
| -
|
| - if (view()->document().printing())
|
| - return; // Don't invalidate paints if we're printing.
|
| -
|
| - LayoutRect dirtyRect(r);
|
| -
|
| - const LayoutLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation();
|
| - Layer::mapRectToPaintInvalidationBacking(this, paintInvalidationContainer, dirtyRect);
|
| - invalidatePaintUsingContainer(paintInvalidationContainer, dirtyRect, PaintInvalidationRectangle);
|
| -}
|
| -
|
| -void RenderObject::invalidateTreeIfNeeded(const PaintInvalidationState& paintInvalidationState)
|
| -{
|
| - ASSERT(!needsLayout());
|
| -
|
| - // If we didn't need paint invalidation then our children don't need as well.
|
| - // Skip walking down the tree as everything should be fine below us.
|
| - if (!shouldCheckForPaintInvalidation(paintInvalidationState))
|
| - return;
|
| -
|
| - invalidatePaintIfNeeded(paintInvalidationState, paintInvalidationState.paintInvalidationContainer());
|
| - clearPaintInvalidationState(paintInvalidationState);
|
| - invalidatePaintOfSubtreesIfNeeded(paintInvalidationState);
|
| -}
|
| -
|
| -void RenderObject::invalidatePaintOfSubtreesIfNeeded(const PaintInvalidationState& childPaintInvalidationState)
|
| -{
|
| - for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
|
| - if (!child->isOutOfFlowPositioned())
|
| - child->invalidateTreeIfNeeded(childPaintInvalidationState);
|
| - }
|
| -}
|
| -
|
| -static PassRefPtr<TraceEvent::ConvertableToTraceFormat> jsonObjectForOldAndNewRects(const LayoutRect& oldRect, const LayoutPoint& oldLocation, const LayoutRect& newRect, const LayoutPoint& newLocation)
|
| -{
|
| - RefPtr<TracedValue> value = TracedValue::create();
|
| - addJsonObjectForRect(value.get(), "oldRect", oldRect);
|
| - addJsonObjectForPoint(value.get(), "oldLocation", oldLocation);
|
| - addJsonObjectForRect(value.get(), "newRect", newRect);
|
| - addJsonObjectForPoint(value.get(), "newLocation", newLocation);
|
| - return value;
|
| -}
|
| -
|
| -LayoutRect RenderObject::previousSelectionRectForPaintInvalidation() const
|
| -{
|
| - if (!selectionPaintInvalidationMap)
|
| - return LayoutRect();
|
| -
|
| - return selectionPaintInvalidationMap->get(this);
|
| -}
|
| -
|
| -void RenderObject::setPreviousSelectionRectForPaintInvalidation(const LayoutRect& selectionRect)
|
| -{
|
| - if (!selectionPaintInvalidationMap) {
|
| - if (selectionRect.isEmpty())
|
| - return;
|
| - selectionPaintInvalidationMap = new SelectionPaintInvalidationMap();
|
| - }
|
| -
|
| - if (selectionRect.isEmpty())
|
| - selectionPaintInvalidationMap->remove(this);
|
| - else
|
| - selectionPaintInvalidationMap->set(this, selectionRect);
|
| -}
|
| -
|
| -void RenderObject::invalidateSelectionIfNeeded(const LayoutLayerModelObject& paintInvalidationContainer, PaintInvalidationReason invalidationReason)
|
| -{
|
| - // Update selection rect when we are doing full invalidation (in case that the object is moved, composite status changed, etc.)
|
| - // or shouldInvalidationSelection is set (in case that the selection itself changed).
|
| - bool fullInvalidation = view()->doingFullPaintInvalidation() || isFullPaintInvalidationReason(invalidationReason);
|
| - if (!fullInvalidation && !shouldInvalidateSelection())
|
| - return;
|
| -
|
| - LayoutRect oldSelectionRect = previousSelectionRectForPaintInvalidation();
|
| - LayoutRect newSelectionRect = selectionRectForPaintInvalidation(&paintInvalidationContainer);
|
| - setPreviousSelectionRectForPaintInvalidation(newSelectionRect);
|
| -
|
| - if (fullInvalidation)
|
| - return;
|
| -
|
| - fullyInvalidatePaint(paintInvalidationContainer, PaintInvalidationSelection, oldSelectionRect, newSelectionRect);
|
| -}
|
| -
|
| -PaintInvalidationReason RenderObject::invalidatePaintIfNeeded(const PaintInvalidationState& paintInvalidationState, const LayoutLayerModelObject& paintInvalidationContainer)
|
| -{
|
| - RenderView* v = view();
|
| - if (v->document().printing())
|
| - return PaintInvalidationNone; // Don't invalidate paints if we're printing.
|
| -
|
| - const LayoutRect oldBounds = previousPaintInvalidationRect();
|
| - const LayoutPoint oldLocation = previousPositionFromPaintInvalidationBacking();
|
| - const LayoutRect newBounds = boundsRectForPaintInvalidation(&paintInvalidationContainer, &paintInvalidationState);
|
| - const LayoutPoint newLocation = Layer::positionFromPaintInvalidationBacking(this, &paintInvalidationContainer, &paintInvalidationState);
|
| - setPreviousPaintInvalidationRect(newBounds);
|
| - setPreviousPositionFromPaintInvalidationBacking(newLocation);
|
| -
|
| - PaintInvalidationReason invalidationReason = paintInvalidationReason(paintInvalidationContainer, oldBounds, oldLocation, newBounds, newLocation);
|
| -
|
| - // We need to invalidate the selection before checking for whether we are doing a full invalidation.
|
| - // This is because we need to update the old rect regardless.
|
| - invalidateSelectionIfNeeded(paintInvalidationContainer, invalidationReason);
|
| -
|
| - // If we are set to do a full paint invalidation that means the RenderView will issue
|
| - // paint invalidations. We can then skip issuing of paint invalidations for the child
|
| - // renderers as they'll be covered by the RenderView.
|
| - if (view()->doingFullPaintInvalidation())
|
| - return invalidationReason;
|
| -
|
| - TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintIfNeeded()",
|
| - "object", this->debugName().ascii(),
|
| - "info", jsonObjectForOldAndNewRects(oldBounds, oldLocation, newBounds, newLocation));
|
| -
|
| - if (invalidationReason == PaintInvalidationNone)
|
| - return invalidationReason;
|
| -
|
| - if (invalidationReason == PaintInvalidationIncremental) {
|
| - incrementallyInvalidatePaint(paintInvalidationContainer, oldBounds, newBounds, newLocation);
|
| - return invalidationReason;
|
| - }
|
| -
|
| - fullyInvalidatePaint(paintInvalidationContainer, invalidationReason, oldBounds, newBounds);
|
| - return invalidationReason;
|
| -}
|
| -
|
| -PaintInvalidationReason RenderObject::paintInvalidationReason(const LayoutLayerModelObject& paintInvalidationContainer,
|
| - const LayoutRect& oldBounds, const LayoutPoint& oldPositionFromPaintInvalidationBacking,
|
| - const LayoutRect& newBounds, const LayoutPoint& newPositionFromPaintInvalidationBacking) const
|
| -{
|
| - // First check for InvalidationLocationChange to avoid it from being hidden by other
|
| - // invalidation reasons because we'll need to force check for paint invalidation for
|
| - // children when location of this object changed.
|
| - if (newPositionFromPaintInvalidationBacking != oldPositionFromPaintInvalidationBacking)
|
| - return PaintInvalidationLocationChange;
|
| -
|
| - if (shouldDoFullPaintInvalidation())
|
| - return m_bitfields.fullPaintInvalidationReason();
|
| -
|
| - // If the bounds are the same then we know that none of the statements below
|
| - // can match, so we can early out since we will not need to do any
|
| - // invalidation.
|
| - if (oldBounds == newBounds)
|
| - return PaintInvalidationNone;
|
| -
|
| - // If we shifted, we don't know the exact reason so we are conservative and trigger a full invalidation. Shifting could
|
| - // be caused by some layout property (left / top) or some in-flow renderer inserted / removed before us in the tree.
|
| - if (newBounds.location() != oldBounds.location())
|
| - return PaintInvalidationBoundsChange;
|
| -
|
| - // This covers the case where we mark containing blocks for layout
|
| - // and they change size but don't have anything to paint. This is
|
| - // a pretty common case for <body> as we add / remove children
|
| - // (and the default background is done by FrameView).
|
| - if (skipInvalidationWhenLaidOutChildren())
|
| - return PaintInvalidationNone;
|
| -
|
| - // If the size is zero on one of our bounds then we know we're going to have
|
| - // to do a full invalidation of either old bounds or new bounds. If we fall
|
| - // into the incremental invalidation we'll issue two invalidations instead
|
| - // of one.
|
| - if (oldBounds.isEmpty())
|
| - return PaintInvalidationBecameVisible;
|
| - if (newBounds.isEmpty())
|
| - return PaintInvalidationBecameInvisible;
|
| -
|
| - return PaintInvalidationIncremental;
|
| -}
|
| -
|
| -void RenderObject::incrementallyInvalidatePaint(const LayoutLayerModelObject& paintInvalidationContainer, const LayoutRect& oldBounds, const LayoutRect& newBounds, const LayoutPoint& positionFromPaintInvalidationBacking)
|
| -{
|
| - ASSERT(oldBounds.location() == newBounds.location());
|
| -
|
| - LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX();
|
| - if (deltaRight > 0)
|
| - invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height()), PaintInvalidationIncremental);
|
| - else if (deltaRight < 0)
|
| - invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height()), PaintInvalidationIncremental);
|
| -
|
| - LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY();
|
| - if (deltaBottom > 0)
|
| - invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom), PaintInvalidationIncremental);
|
| - else if (deltaBottom < 0)
|
| - invalidatePaintUsingContainer(&paintInvalidationContainer, LayoutRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom), PaintInvalidationIncremental);
|
| -}
|
| -
|
| -void RenderObject::fullyInvalidatePaint(const LayoutLayerModelObject& paintInvalidationContainer, PaintInvalidationReason invalidationReason, const LayoutRect& oldBounds, const LayoutRect& newBounds)
|
| -{
|
| - // Otherwise do full paint invalidation.
|
| - invalidatePaintUsingContainer(&paintInvalidationContainer, oldBounds, invalidationReason);
|
| - if (newBounds != oldBounds)
|
| - invalidatePaintUsingContainer(&paintInvalidationContainer, newBounds, invalidationReason);
|
| -}
|
| -
|
| -void RenderObject::invalidatePaintForOverflow()
|
| -{
|
| -}
|
| -
|
| -void RenderObject::invalidatePaintForOverflowIfNeeded()
|
| -{
|
| - if (shouldInvalidateOverflowForPaint())
|
| - invalidatePaintForOverflow();
|
| -}
|
| -
|
| -LayoutRect RenderObject::rectWithOutlineForPaintInvalidation(const LayoutLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* paintInvalidationState) const
|
| -{
|
| - LayoutRect r(clippedOverflowRectForPaintInvalidation(paintInvalidationContainer, paintInvalidationState));
|
| - r.inflate(outlineWidth);
|
| - return r;
|
| -}
|
| -
|
| -LayoutRect RenderObject::absoluteClippedOverflowRect() const
|
| -{
|
| - return clippedOverflowRectForPaintInvalidation(view());
|
| -}
|
| -
|
| -LayoutRect RenderObject::clippedOverflowRectForPaintInvalidation(const LayoutLayerModelObject*, const PaintInvalidationState*) const
|
| -{
|
| - ASSERT_NOT_REACHED();
|
| - return LayoutRect();
|
| -}
|
| -
|
| -void RenderObject::mapRectToPaintInvalidationBacking(const LayoutLayerModelObject* paintInvalidationContainer, LayoutRect& rect, const PaintInvalidationState* paintInvalidationState) const
|
| -{
|
| - if (paintInvalidationContainer == this)
|
| - return;
|
| -
|
| - if (paintInvalidationState && paintInvalidationState->canMapToContainer(paintInvalidationContainer)) {
|
| - rect.move(paintInvalidationState->paintOffset());
|
| - if (paintInvalidationState->isClipped())
|
| - rect.intersect(paintInvalidationState->clipRect());
|
| - return;
|
| - }
|
| -
|
| - if (RenderObject* o = parent()) {
|
| - if (o->isRenderBlockFlow()) {
|
| - RenderBlock* cb = toRenderBlock(o);
|
| - if (cb->hasColumns())
|
| - cb->adjustRectForColumns(rect);
|
| - }
|
| -
|
| - if (o->hasOverflowClip()) {
|
| - RenderBox* boxParent = toRenderBox(o);
|
| - boxParent->applyCachedClipAndScrollOffsetForPaintInvalidation(rect);
|
| - if (rect.isEmpty())
|
| - return;
|
| - }
|
| -
|
| - o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, paintInvalidationState);
|
| - }
|
| -}
|
| -
|
| -void RenderObject::dirtyLinesFromChangedChild(RenderObject*)
|
| -{
|
| -}
|
| -
|
| -#ifndef NDEBUG
|
| -
|
| -void RenderObject::showTreeForThis() const
|
| -{
|
| - if (node())
|
| - node()->showTreeForThis();
|
| -}
|
| -
|
| -void RenderObject::showRenderTreeForThis() const
|
| -{
|
| - showRenderTree(this, 0);
|
| -}
|
| -
|
| -void RenderObject::showLineTreeForThis() const
|
| -{
|
| - if (containingBlock())
|
| - containingBlock()->showLineTreeAndMark(0, 0, 0, 0, this);
|
| -}
|
| -
|
| -void RenderObject::showRenderObject() const
|
| -{
|
| - showRenderObject(0);
|
| -}
|
| -
|
| -void RenderObject::showRenderObject(int printedCharacters) const
|
| -{
|
| - printedCharacters += fprintf(stderr, "%s %p", renderName(), this);
|
| -
|
| - if (isText() && toRenderText(this)->isTextFragment())
|
| - printedCharacters += fprintf(stderr, " \"%s\" ", toRenderText(this)->text().ascii().data());
|
| -
|
| - if (node()) {
|
| - if (printedCharacters)
|
| - for (; printedCharacters < showTreeCharacterOffset; printedCharacters++)
|
| - fputc(' ', stderr);
|
| - fputc('\t', stderr);
|
| - node()->showNode();
|
| - } else
|
| - fputc('\n', stderr);
|
| -}
|
| -
|
| -void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, const char* markedLabel1, const RenderObject* markedObject2, const char* markedLabel2, int depth) const
|
| -{
|
| - int printedCharacters = 0;
|
| - if (markedObject1 == this && markedLabel1)
|
| - printedCharacters += fprintf(stderr, "%s", markedLabel1);
|
| - if (markedObject2 == this && markedLabel2)
|
| - printedCharacters += fprintf(stderr, "%s", markedLabel2);
|
| - for (; printedCharacters < depth * 2; printedCharacters++)
|
| - fputc(' ', stderr);
|
| -
|
| - showRenderObject(printedCharacters);
|
| -
|
| - for (const RenderObject* child = slowFirstChild(); child; child = child->nextSibling())
|
| - child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1);
|
| -}
|
| -
|
| -#endif // NDEBUG
|
| -
|
| -bool RenderObject::isSelectable() const
|
| -{
|
| - return !isInert() && !(style()->userSelect() == SELECT_NONE && style()->userModify() == READ_ONLY);
|
| -}
|
| -
|
| -Color RenderObject::selectionBackgroundColor() const
|
| -{
|
| - if (!isSelectable())
|
| - return Color::transparent;
|
| -
|
| - if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost())
|
| - return resolveColor(*pseudoStyle, CSSPropertyBackgroundColor).blendWithWhite();
|
| - return frame()->selection().isFocusedAndActive() ?
|
| - LayoutTheme::theme().activeSelectionBackgroundColor() :
|
| - LayoutTheme::theme().inactiveSelectionBackgroundColor();
|
| -}
|
| -
|
| -Color RenderObject::selectionColor(int colorProperty) const
|
| -{
|
| - // If the element is unselectable, or we are only painting the selection,
|
| - // don't override the foreground color with the selection foreground color.
|
| - if (!isSelectable() || (frame()->view()->paintBehavior() & PaintBehaviorSelectionOnly))
|
| - return resolveColor(colorProperty);
|
| -
|
| - if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost())
|
| - return resolveColor(*pseudoStyle, colorProperty);
|
| - if (!LayoutTheme::theme().supportsSelectionForegroundColors())
|
| - return resolveColor(colorProperty);
|
| - return frame()->selection().isFocusedAndActive() ?
|
| - LayoutTheme::theme().activeSelectionForegroundColor() :
|
| - LayoutTheme::theme().inactiveSelectionForegroundColor();
|
| -}
|
| -
|
| -Color RenderObject::selectionForegroundColor() const
|
| -{
|
| - return selectionColor(CSSPropertyWebkitTextFillColor);
|
| -}
|
| -
|
| -Color RenderObject::selectionEmphasisMarkColor() const
|
| -{
|
| - return selectionColor(CSSPropertyWebkitTextEmphasisColor);
|
| -}
|
| -
|
| -void RenderObject::selectionStartEnd(int& spos, int& epos) const
|
| -{
|
| - view()->selectionStartEnd(spos, epos);
|
| -}
|
| -
|
| -void RenderObject::handleDynamicFloatPositionChange()
|
| -{
|
| - // We have gone from not affecting the inline status of the parent flow to suddenly
|
| - // having an impact. See if there is a mismatch between the parent flow's
|
| - // childrenInline() state and our state.
|
| - setInline(style()->isDisplayInlineType());
|
| - if (isInline() != parent()->childrenInline()) {
|
| - if (!isInline())
|
| - toRenderBoxModelObject(parent())->childBecameNonInline(this);
|
| - else {
|
| - // An anonymous block must be made to wrap this inline.
|
| - RenderBlock* block = toRenderBlock(parent())->createAnonymousBlock();
|
| - RenderObjectChildList* childlist = parent()->virtualChildren();
|
| - childlist->insertChildNode(parent(), block, this);
|
| - block->children()->appendChildNode(block, childlist->removeChildNode(parent(), this));
|
| - }
|
| - }
|
| -}
|
| -
|
| -StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff) const
|
| -{
|
| - if (diff.transformChanged() && isSVG())
|
| - diff.setNeedsFullLayout();
|
| -
|
| - // If transform changed, and the layer does not paint into its own separate backing, then we need to invalidate paints.
|
| - if (diff.transformChanged()) {
|
| - // Text nodes share style with their parents but transforms don't apply to them,
|
| - // hence the !isText() check.
|
| - if (!isText() && (!hasLayer() || !toLayoutLayerModelObject(this)->layer()->hasStyleDeterminedDirectCompositingReasons()))
|
| - diff.setNeedsPaintInvalidationLayer();
|
| - }
|
| -
|
| - // If opacity or zIndex changed, and the layer does not paint into its own separate backing, then we need to invalidate paints (also
|
| - // ignoring text nodes)
|
| - if (diff.opacityChanged() || diff.zIndexChanged()) {
|
| - if (!isText() && (!hasLayer() || !toLayoutLayerModelObject(this)->layer()->hasStyleDeterminedDirectCompositingReasons()))
|
| - diff.setNeedsPaintInvalidationLayer();
|
| - }
|
| -
|
| - // If filter changed, and the layer does not paint into its own separate backing or it paints with filters, then we need to invalidate paints.
|
| - if (diff.filterChanged() && hasLayer()) {
|
| - Layer* layer = toLayoutLayerModelObject(this)->layer();
|
| - if (!layer->hasStyleDeterminedDirectCompositingReasons() || layer->paintsWithFilters())
|
| - diff.setNeedsPaintInvalidationLayer();
|
| - }
|
| -
|
| - if (diff.textOrColorChanged() && !diff.needsPaintInvalidation()) {
|
| - if (style()->hasBorder() || style()->hasOutline()
|
| - || (isText() && !toRenderText(this)->isAllCollapsibleWhitespace()))
|
| - diff.setNeedsPaintInvalidationObject();
|
| - }
|
| -
|
| - // The answer to layerTypeRequired() for plugins, iframes, and canvas can change without the actual
|
| - // style changing, since it depends on whether we decide to composite these elements. When the
|
| - // layer status of one of these elements changes, we need to force a layout.
|
| - if (!diff.needsFullLayout() && style() && isLayoutLayerModelObject()) {
|
| - bool requiresLayer = toLayoutLayerModelObject(this)->layerTypeRequired() != NoLayer;
|
| - if (hasLayer() != requiresLayer)
|
| - diff.setNeedsFullLayout();
|
| - }
|
| -
|
| - // If we have no layer(), just treat a PaintInvalidationLayer hint as a normal paint invalidation.
|
| - if (diff.needsPaintInvalidationLayer() && !hasLayer()) {
|
| - diff.clearNeedsPaintInvalidation();
|
| - diff.setNeedsPaintInvalidationObject();
|
| - }
|
| -
|
| - return diff;
|
| -}
|
| -
|
| -void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle)
|
| -{
|
| - ASSERT(pseudoStyle->styleType() == BEFORE || pseudoStyle->styleType() == AFTER || pseudoStyle->styleType() == FIRST_LETTER);
|
| -
|
| - // FIXME: We should consider just making all pseudo items use an inherited style.
|
| -
|
| - // Images are special and must inherit the pseudoStyle so the width and height of
|
| - // the pseudo element doesn't change the size of the image. In all other cases we
|
| - // can just share the style.
|
| - //
|
| - // Quotes are also RenderInline, so we need to create an inherited style to avoid
|
| - // getting an inline with positioning or an invalid display.
|
| - //
|
| - if (isImage() || isQuote()) {
|
| - RefPtr<RenderStyle> style = RenderStyle::create();
|
| - style->inheritFrom(pseudoStyle.get());
|
| - setStyle(style.release());
|
| - return;
|
| - }
|
| -
|
| - setStyle(pseudoStyle);
|
| -}
|
| -
|
| -void RenderObject::markContainingBlocksForOverflowRecalc()
|
| -{
|
| - for (RenderBlock* container = containingBlock(); container && !container->childNeedsOverflowRecalcAfterStyleChange(); container = container->containingBlock())
|
| - container->setChildNeedsOverflowRecalcAfterStyleChange(true);
|
| -}
|
| -
|
| -void RenderObject::setNeedsOverflowRecalcAfterStyleChange()
|
| -{
|
| - bool neededRecalc = needsOverflowRecalcAfterStyleChange();
|
| - setSelfNeedsOverflowRecalcAfterStyleChange(true);
|
| - if (!neededRecalc)
|
| - markContainingBlocksForOverflowRecalc();
|
| -}
|
| -
|
| -void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
|
| -{
|
| - ASSERT(style);
|
| -
|
| - if (m_style == style) {
|
| - // We need to run through adjustStyleDifference() for iframes, plugins, and canvas so
|
| - // style sharing is disabled for them. That should ensure that we never hit this code path.
|
| - ASSERT(!isRenderIFrame() && !isEmbeddedObject() && !isCanvas());
|
| - return;
|
| - }
|
| -
|
| - StyleDifference diff;
|
| - if (m_style)
|
| - diff = m_style->visualInvalidationDiff(*style);
|
| -
|
| - diff = adjustStyleDifference(diff);
|
| -
|
| - styleWillChange(diff, *style);
|
| -
|
| - RefPtr<RenderStyle> oldStyle = m_style.release();
|
| - setStyleInternal(style);
|
| -
|
| - updateFillImages(oldStyle ? &oldStyle->backgroundLayers() : 0, m_style->backgroundLayers());
|
| - updateFillImages(oldStyle ? &oldStyle->maskLayers() : 0, m_style->maskLayers());
|
| -
|
| - updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style->borderImage().image());
|
| - updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style->maskBoxImage().image());
|
| -
|
| - updateShapeImage(oldStyle ? oldStyle->shapeOutside() : 0, m_style->shapeOutside());
|
| -
|
| - bool doesNotNeedLayoutOrPaintInvalidation = !m_parent;
|
| -
|
| - styleDidChange(diff, oldStyle.get());
|
| -
|
| - // FIXME: |this| might be destroyed here. This can currently happen for a RenderTextFragment when
|
| - // its first-letter block gets an update in RenderTextFragment::styleDidChange. For RenderTextFragment(s),
|
| - // we will safely bail out with the doesNotNeedLayoutOrPaintInvalidation flag. We might want to broaden
|
| - // this condition in the future as we move renderer changes out of layout and into style changes.
|
| - if (doesNotNeedLayoutOrPaintInvalidation)
|
| - return;
|
| -
|
| - // Now that the layer (if any) has been updated, we need to adjust the diff again,
|
| - // check whether we should layout now, and decide if we need to invalidate paints.
|
| - StyleDifference updatedDiff = adjustStyleDifference(diff);
|
| -
|
| - if (!diff.needsFullLayout()) {
|
| - if (updatedDiff.needsFullLayout())
|
| - setNeedsLayoutAndPrefWidthsRecalc();
|
| - else if (updatedDiff.needsPositionedMovementLayout())
|
| - setNeedsPositionedMovementLayout();
|
| - }
|
| -
|
| - if (diff.transformChanged() && !needsLayout()) {
|
| - if (RenderBlock* container = containingBlock())
|
| - container->setNeedsOverflowRecalcAfterStyleChange();
|
| - }
|
| -
|
| - if (updatedDiff.needsPaintInvalidationLayer())
|
| - toLayoutLayerModelObject(this)->layer()->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
|
| - else if (diff.needsPaintInvalidationObject() || updatedDiff.needsPaintInvalidationObject())
|
| - setShouldDoFullPaintInvalidation();
|
| -}
|
| -
|
| -static inline bool rendererHasBackground(const RenderObject* renderer)
|
| -{
|
| - return renderer && renderer->hasBackground();
|
| -}
|
| -
|
| -void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
|
| -{
|
| - if (m_style) {
|
| - // If our z-index changes value or our visibility changes,
|
| - // we need to dirty our stacking context's z-order list.
|
| - bool visibilityChanged = m_style->visibility() != newStyle.visibility()
|
| - || m_style->zIndex() != newStyle.zIndex()
|
| - || m_style->hasAutoZIndex() != newStyle.hasAutoZIndex();
|
| - if (visibilityChanged) {
|
| - document().setAnnotatedRegionsDirty(true);
|
| - if (AXObjectCache* cache = document().existingAXObjectCache())
|
| - cache->childrenChanged(parent());
|
| - }
|
| -
|
| - // Keep layer hierarchy visibility bits up to date if visibility changes.
|
| - if (m_style->visibility() != newStyle.visibility()) {
|
| - // We might not have an enclosing layer yet because we might not be in the tree.
|
| - if (Layer* layer = enclosingLayer())
|
| - layer->potentiallyDirtyVisibleContentStatus(newStyle.visibility());
|
| - }
|
| -
|
| - if (isFloating() && (m_style->floating() != newStyle.floating()))
|
| - // For changes in float styles, we need to conceivably remove ourselves
|
| - // from the floating objects list.
|
| - toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();
|
| - else if (isOutOfFlowPositioned() && (m_style->position() != newStyle.position()))
|
| - // For changes in positioning styles, we need to conceivably remove ourselves
|
| - // from the positioned objects list.
|
| - toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();
|
| -
|
| - s_affectsParentBlock = isFloatingOrOutOfFlowPositioned()
|
| - && (!newStyle.isFloating() && !newStyle.hasOutOfFlowPosition())
|
| - && parent() && (parent()->isRenderBlockFlow() || parent()->isRenderInline());
|
| -
|
| - // Clearing these bits is required to avoid leaving stale renderers.
|
| - // FIXME: We shouldn't need that hack if our logic was totally correct.
|
| - if (diff.needsLayout()) {
|
| - setFloating(false);
|
| - clearPositionedState();
|
| - }
|
| - } else {
|
| - s_affectsParentBlock = false;
|
| - }
|
| -
|
| - if (view()->frameView()) {
|
| - bool shouldBlitOnFixedBackgroundImage = false;
|
| - if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) {
|
| - // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays
|
| - // when scrolling a page with a fixed background image. As an optimization, assuming there are
|
| - // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we
|
| - // ignore the CSS property "background-attachment: fixed".
|
| - shouldBlitOnFixedBackgroundImage = true;
|
| - }
|
| - bool newStyleSlowScroll = !shouldBlitOnFixedBackgroundImage && newStyle.hasFixedBackgroundImage();
|
| - bool oldStyleSlowScroll = m_style && !shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage();
|
| -
|
| - bool drawsRootBackground = isDocumentElement() || (isBody() && !rendererHasBackground(document().documentElement()->renderer()));
|
| - if (drawsRootBackground && !shouldBlitOnFixedBackgroundImage) {
|
| - if (view()->compositor()->supportsFixedRootBackgroundCompositing()) {
|
| - if (newStyleSlowScroll && newStyle.hasEntirelyFixedBackground())
|
| - newStyleSlowScroll = false;
|
| -
|
| - if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground())
|
| - oldStyleSlowScroll = false;
|
| - }
|
| - }
|
| -
|
| - if (oldStyleSlowScroll != newStyleSlowScroll) {
|
| - if (oldStyleSlowScroll)
|
| - view()->frameView()->removeSlowRepaintObject();
|
| - if (newStyleSlowScroll)
|
| - view()->frameView()->addSlowRepaintObject();
|
| - }
|
| - }
|
| -
|
| - // Elements with non-auto touch-action will send a SetTouchAction message
|
| - // on touchstart in EventHandler::handleTouchEvent, and so effectively have
|
| - // a touchstart handler that must be reported.
|
| - //
|
| - // Since a CSS property cannot be applied directly to a text node, a
|
| - // handler will have already been added for its parent so ignore it.
|
| - TouchAction oldTouchAction = m_style ? m_style->touchAction() : TouchActionAuto;
|
| - if (node() && !node()->isTextNode() && (oldTouchAction == TouchActionAuto) != (newStyle.touchAction() == TouchActionAuto)) {
|
| - EventHandlerRegistry& registry = document().frameHost()->eventHandlerRegistry();
|
| - if (newStyle.touchAction() != TouchActionAuto)
|
| - registry.didAddEventHandler(*node(), EventHandlerRegistry::TouchEvent);
|
| - else
|
| - registry.didRemoveEventHandler(*node(), EventHandlerRegistry::TouchEvent);
|
| - }
|
| -}
|
| -
|
| -static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b)
|
| -{
|
| - ASSERT(a->cursors() != b->cursors());
|
| - return a->cursors() && b->cursors() && *a->cursors() == *b->cursors();
|
| -}
|
| -
|
| -static inline bool areCursorsEqual(const RenderStyle* a, const RenderStyle* b)
|
| -{
|
| - return a->cursor() == b->cursor() && (a->cursors() == b->cursors() || areNonIdenticalCursorListsEqual(a, b));
|
| -}
|
| -
|
| -void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
|
| -{
|
| - if (s_affectsParentBlock)
|
| - handleDynamicFloatPositionChange();
|
| -
|
| - if (!m_parent)
|
| - return;
|
| -
|
| - if (diff.needsFullLayout()) {
|
| - LayoutCounter::rendererStyleChanged(*this, oldStyle, m_style.get());
|
| -
|
| - // If the object already needs layout, then setNeedsLayout won't do
|
| - // any work. But if the containing block has changed, then we may need
|
| - // to mark the new containing blocks for layout. The change that can
|
| - // directly affect the containing block of this object is a change to
|
| - // the position style.
|
| - if (needsLayout() && oldStyle->position() != m_style->position())
|
| - markContainingBlocksForLayout();
|
| -
|
| - // Ditto.
|
| - if (needsOverflowRecalcAfterStyleChange() && oldStyle->position() != m_style->position())
|
| - markContainingBlocksForOverflowRecalc();
|
| -
|
| - if (diff.needsFullLayout())
|
| - setNeedsLayoutAndPrefWidthsRecalc();
|
| - } else if (diff.needsPositionedMovementLayout())
|
| - setNeedsPositionedMovementLayout();
|
| -
|
| - // Don't check for paint invalidation here; we need to wait until the layer has been
|
| - // updated by subclasses before we know if we have to invalidate paints (in setStyle()).
|
| -
|
| - if (oldStyle && !areCursorsEqual(oldStyle, style())) {
|
| - if (LocalFrame* frame = this->frame())
|
| - frame->eventHandler().scheduleCursorUpdate();
|
| - }
|
| -}
|
| -
|
| -void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly)
|
| -{
|
| - // FIXME: We could save this call when the change only affected non-inherited properties.
|
| - for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
|
| - if (!child->isAnonymous() || child->style()->styleType() != NOPSEUDO)
|
| - continue;
|
| -
|
| - if (blockChildrenOnly && !child->isRenderBlock())
|
| - continue;
|
| -
|
| - if (child->isRenderFullScreen() || child->isRenderFullScreenPlaceholder())
|
| - continue;
|
| -
|
| - RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), child->style()->display());
|
| - if (!document().regionBasedColumnsEnabled()) {
|
| - if (style()->specifiesColumns()) {
|
| - if (child->style()->specifiesColumns())
|
| - newStyle->inheritColumnPropertiesFrom(style());
|
| - if (child->style()->columnSpan())
|
| - newStyle->setColumnSpan(ColumnSpanAll);
|
| - }
|
| - }
|
| -
|
| - // Preserve the position style of anonymous block continuations as they can have relative position when
|
| - // they contain block descendants of relative positioned inlines.
|
| - if (child->isRelPositioned() && toRenderBlock(child)->isAnonymousBlockContinuation())
|
| - newStyle->setPosition(child->style()->position());
|
| -
|
| - updateAnonymousChildStyle(child, newStyle.get());
|
| -
|
| - child->setStyle(newStyle.release());
|
| - }
|
| -}
|
| -
|
| -void RenderObject::updateFillImages(const FillLayer* oldLayers, const FillLayer& newLayers)
|
| -{
|
| - // Optimize the common case
|
| - if (oldLayers && !oldLayers->next() && !newLayers.next() && (oldLayers->image() == newLayers.image()))
|
| - return;
|
| -
|
| - // Go through the new layers and addClients first, to avoid removing all clients of an image.
|
| - for (const FillLayer* currNew = &newLayers; currNew; currNew = currNew->next()) {
|
| - if (currNew->image())
|
| - currNew->image()->addClient(this);
|
| - }
|
| -
|
| - for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
|
| - if (currOld->image())
|
| - currOld->image()->removeClient(this);
|
| - }
|
| -}
|
| -
|
| -void RenderObject::updateImage(StyleImage* oldImage, StyleImage* newImage)
|
| -{
|
| - if (oldImage != newImage) {
|
| - if (oldImage)
|
| - oldImage->removeClient(this);
|
| - if (newImage)
|
| - newImage->addClient(this);
|
| - }
|
| -}
|
| -
|
| -void RenderObject::updateShapeImage(const ShapeValue* oldShapeValue, const ShapeValue* newShapeValue)
|
| -{
|
| - if (oldShapeValue || newShapeValue)
|
| - updateImage(oldShapeValue ? oldShapeValue->image() : 0, newShapeValue ? newShapeValue->image() : 0);
|
| -}
|
| -
|
| -LayoutRect RenderObject::viewRect() const
|
| -{
|
| - return view()->viewRect();
|
| -}
|
| -
|
| -FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode) const
|
| -{
|
| - TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
|
| - mapLocalToContainer(0, transformState, mode | ApplyContainerFlip);
|
| - transformState.flatten();
|
| -
|
| - return transformState.lastPlanarPoint();
|
| -}
|
| -
|
| -FloatPoint RenderObject::absoluteToLocal(const FloatPoint& containerPoint, MapCoordinatesFlags mode) const
|
| -{
|
| - TransformState transformState(TransformState::UnapplyInverseTransformDirection, containerPoint);
|
| - mapAbsoluteToLocalPoint(mode, transformState);
|
| - transformState.flatten();
|
| -
|
| - return transformState.lastPlanarPoint();
|
| -}
|
| -
|
| -FloatQuad RenderObject::absoluteToLocalQuad(const FloatQuad& quad, MapCoordinatesFlags mode) const
|
| -{
|
| - TransformState transformState(TransformState::UnapplyInverseTransformDirection, quad.boundingBox().center(), quad);
|
| - mapAbsoluteToLocalPoint(mode, transformState);
|
| - transformState.flatten();
|
| - return transformState.lastPlanarQuad();
|
| -}
|
| -
|
| -void RenderObject::mapLocalToContainer(const LayoutLayerModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
|
| -{
|
| - if (paintInvalidationContainer == this)
|
| - return;
|
| -
|
| - RenderObject* o = parent();
|
| - if (!o)
|
| - return;
|
| -
|
| - // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called.
|
| - LayoutPoint centerPoint = roundedLayoutPoint(transformState.mappedPoint());
|
| - if (mode & ApplyContainerFlip && o->isBox()) {
|
| - if (o->style()->isFlippedBlocksWritingMode())
|
| - transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedLayoutPoint(transformState.mappedPoint())) - centerPoint);
|
| - mode &= ~ApplyContainerFlip;
|
| - }
|
| -
|
| - transformState.move(o->columnOffset(roundedLayoutPoint(transformState.mappedPoint())));
|
| -
|
| - if (o->hasOverflowClip())
|
| - transformState.move(-toRenderBox(o)->scrolledContentOffset());
|
| -
|
| - o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed, paintInvalidationState);
|
| -}
|
| -
|
| -const RenderObject* RenderObject::pushMappingToContainer(const LayoutLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
|
| -{
|
| - ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != this);
|
| -
|
| - RenderObject* container = parent();
|
| - if (!container)
|
| - return 0;
|
| -
|
| - // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called.
|
| - LayoutSize offset;
|
| - if (container->hasOverflowClip())
|
| - offset = -LayoutSize(toRenderBox(container)->scrolledContentOffset());
|
| -
|
| - geometryMap.push(this, offset, hasColumns());
|
| -
|
| - return container;
|
| -}
|
| -
|
| -void RenderObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
|
| -{
|
| - RenderObject* o = parent();
|
| - if (o) {
|
| - o->mapAbsoluteToLocalPoint(mode, transformState);
|
| - if (o->hasOverflowClip())
|
| - transformState.move(toRenderBox(o)->scrolledContentOffset());
|
| - }
|
| -}
|
| -
|
| -bool RenderObject::shouldUseTransformFromContainer(const RenderObject* containerObject) const
|
| -{
|
| - // hasTransform() indicates whether the object has transform, transform-style or perspective. We just care about transform,
|
| - // so check the layer's transform directly.
|
| - return (hasLayer() && toLayoutLayerModelObject(this)->layer()->transform()) || (containerObject && containerObject->style()->hasPerspective());
|
| -}
|
| -
|
| -void RenderObject::getTransformFromContainer(const RenderObject* containerObject, const LayoutSize& offsetInContainer, TransformationMatrix& transform) const
|
| -{
|
| - transform.makeIdentity();
|
| - transform.translate(offsetInContainer.width().toFloat(), offsetInContainer.height().toFloat());
|
| - Layer* layer = hasLayer() ? toLayoutLayerModelObject(this)->layer() : 0;
|
| - if (layer && layer->transform())
|
| - transform.multiply(layer->currentTransform());
|
| -
|
| - if (containerObject && containerObject->hasLayer() && containerObject->style()->hasPerspective()) {
|
| - // Perpsective on the container affects us, so we have to factor it in here.
|
| - ASSERT(containerObject->hasLayer());
|
| - FloatPoint perspectiveOrigin = toLayoutLayerModelObject(containerObject)->layer()->perspectiveOrigin();
|
| -
|
| - TransformationMatrix perspectiveMatrix;
|
| - perspectiveMatrix.applyPerspective(containerObject->style()->perspective());
|
| -
|
| - transform.translateRight3d(-perspectiveOrigin.x(), -perspectiveOrigin.y(), 0);
|
| - transform = perspectiveMatrix * transform;
|
| - transform.translateRight3d(perspectiveOrigin.x(), perspectiveOrigin.y(), 0);
|
| - }
|
| -}
|
| -
|
| -FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const LayoutLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed) const
|
| -{
|
| - // Track the point at the center of the quad's bounding box. As mapLocalToContainer() calls offsetFromContainer(),
|
| - // it will use that point as the reference point to decide which column's transform to apply in multiple-column blocks.
|
| - TransformState transformState(TransformState::ApplyTransformDirection, localQuad.boundingBox().center(), localQuad);
|
| - mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
|
| - transformState.flatten();
|
| -
|
| - return transformState.lastPlanarQuad();
|
| -}
|
| -
|
| -FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const LayoutLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed, const PaintInvalidationState* paintInvalidationState) const
|
| -{
|
| - TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
|
| - mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed, paintInvalidationState);
|
| - transformState.flatten();
|
| -
|
| - return transformState.lastPlanarPoint();
|
| -}
|
| -
|
| -FloatPoint RenderObject::localToInvalidationBackingPoint(const LayoutPoint& localPoint, Layer** backingLayer)
|
| -{
|
| - const LayoutLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation();
|
| - ASSERT(paintInvalidationContainer);
|
| - ASSERT(paintInvalidationContainer->layer());
|
| -
|
| - if (backingLayer)
|
| - *backingLayer = paintInvalidationContainer->layer();
|
| - FloatPoint containerPoint = localToContainerPoint(FloatPoint(localPoint), paintInvalidationContainer, TraverseDocumentBoundaries);
|
| -
|
| - // A renderer can have no invalidation backing if it is from a detached frame,
|
| - // or when forced compositing is disabled.
|
| - if (paintInvalidationContainer->layer()->compositingState() == NotComposited)
|
| - return containerPoint;
|
| -
|
| - Layer::mapPointToPaintBackingCoordinates(paintInvalidationContainer, containerPoint);
|
| - return containerPoint;
|
| -}
|
| -
|
| -LayoutSize RenderObject::offsetFromContainer(const RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
|
| -{
|
| - ASSERT(o == container());
|
| -
|
| - LayoutSize offset = o->columnOffset(point);
|
| -
|
| - if (o->hasOverflowClip())
|
| - offset -= toRenderBox(o)->scrolledContentOffset();
|
| -
|
| - if (offsetDependsOnPoint)
|
| - *offsetDependsOnPoint = hasColumns() || o->isRenderFlowThread();
|
| -
|
| - return offset;
|
| -}
|
| -
|
| -LayoutSize RenderObject::offsetFromAncestorContainer(const RenderObject* container) const
|
| -{
|
| - if (container == this)
|
| - return LayoutSize();
|
| -
|
| - LayoutSize offset;
|
| - LayoutPoint referencePoint;
|
| - const RenderObject* currContainer = this;
|
| - do {
|
| - const RenderObject* nextContainer = currContainer->container();
|
| - ASSERT(nextContainer); // This means we reached the top without finding container.
|
| - if (!nextContainer)
|
| - break;
|
| - ASSERT(!currContainer->hasTransformRelatedProperty());
|
| - LayoutSize currentOffset = currContainer->offsetFromContainer(nextContainer, referencePoint);
|
| - offset += currentOffset;
|
| - referencePoint.move(currentOffset);
|
| - currContainer = nextContainer;
|
| - } while (currContainer != container);
|
| -
|
| - return offset;
|
| -}
|
| -
|
| -LayoutRect RenderObject::localCaretRect(InlineBox*, int, LayoutUnit* extraWidthToEndOfLine)
|
| -{
|
| - if (extraWidthToEndOfLine)
|
| - *extraWidthToEndOfLine = 0;
|
| -
|
| - return LayoutRect();
|
| -}
|
| -
|
| -void RenderObject::computeLayerHitTestRects(LayerHitTestRects& layerRects) const
|
| -{
|
| - // Figure out what layer our container is in. Any offset (or new layer) for this
|
| - // renderer within it's container will be applied in addLayerHitTestRects.
|
| - LayoutPoint layerOffset;
|
| - const Layer* currentLayer = 0;
|
| -
|
| - if (!hasLayer()) {
|
| - RenderObject* container = this->container();
|
| - currentLayer = container->enclosingLayer();
|
| - if (container && currentLayer->renderer() != container) {
|
| - layerOffset.move(container->offsetFromAncestorContainer(currentLayer->renderer()));
|
| - // If the layer itself is scrolled, we have to undo the subtraction of its scroll
|
| - // offset since we want the offset relative to the scrolling content, not the
|
| - // element itself.
|
| - if (currentLayer->renderer()->hasOverflowClip())
|
| - layerOffset.move(currentLayer->renderBox()->scrolledContentOffset());
|
| - }
|
| - }
|
| -
|
| - this->addLayerHitTestRects(layerRects, currentLayer, layerOffset, LayoutRect());
|
| -}
|
| -
|
| -void RenderObject::addLayerHitTestRects(LayerHitTestRects& layerRects, const Layer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
|
| -{
|
| - ASSERT(currentLayer);
|
| - ASSERT(currentLayer == this->enclosingLayer());
|
| -
|
| - // Compute the rects for this renderer only and add them to the results.
|
| - // Note that we could avoid passing the offset and instead adjust each result, but this
|
| - // seems slightly simpler.
|
| - Vector<LayoutRect> ownRects;
|
| - LayoutRect newContainerRect;
|
| - computeSelfHitTestRects(ownRects, layerOffset);
|
| -
|
| - // When we get to have a lot of rects on a layer, the performance cost of tracking those
|
| - // rects outweighs the benefit of doing compositor thread hit testing.
|
| - // FIXME: This limit needs to be low due to the O(n^2) algorithm in
|
| - // WebLayer::setTouchEventHandlerRegion - crbug.com/300282.
|
| - const size_t maxRectsPerLayer = 100;
|
| -
|
| - LayerHitTestRects::iterator iter = layerRects.find(currentLayer);
|
| - Vector<LayoutRect>* iterValue;
|
| - if (iter == layerRects.end())
|
| - iterValue = &layerRects.add(currentLayer, Vector<LayoutRect>()).storedValue->value;
|
| - else
|
| - iterValue = &iter->value;
|
| - for (size_t i = 0; i < ownRects.size(); i++) {
|
| - if (!containerRect.contains(ownRects[i])) {
|
| - iterValue->append(ownRects[i]);
|
| - if (iterValue->size() > maxRectsPerLayer) {
|
| - // Just mark the entire layer instead, and switch to walking the layer
|
| - // tree instead of the render tree.
|
| - layerRects.remove(currentLayer);
|
| - currentLayer->addLayerHitTestRects(layerRects);
|
| - return;
|
| - }
|
| - if (newContainerRect.isEmpty())
|
| - newContainerRect = ownRects[i];
|
| - }
|
| - }
|
| - if (newContainerRect.isEmpty())
|
| - newContainerRect = containerRect;
|
| -
|
| - // If it's possible for children to have rects outside our bounds, then we need to descend into
|
| - // the children and compute them.
|
| - // Ideally there would be other cases where we could detect that children couldn't have rects
|
| - // outside our bounds and prune the tree walk.
|
| - // Note that we don't use Region here because Union is O(N) - better to just keep a list of
|
| - // partially redundant rectangles. If we find examples where this is expensive, then we could
|
| - // rewrite Region to be more efficient. See https://bugs.webkit.org/show_bug.cgi?id=100814.
|
| - if (!isRenderView()) {
|
| - for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) {
|
| - curr->addLayerHitTestRects(layerRects, currentLayer, layerOffset, newContainerRect);
|
| - }
|
| - }
|
| -}
|
| -
|
| -bool RenderObject::isRooted() const
|
| -{
|
| - const RenderObject* object = this;
|
| - while (object->parent() && !object->hasLayer())
|
| - object = object->parent();
|
| - if (object->hasLayer())
|
| - return toLayoutLayerModelObject(object)->layer()->root()->isRootLayer();
|
| - return false;
|
| -}
|
| -
|
| -RenderObject* RenderObject::rendererForRootBackground()
|
| -{
|
| - ASSERT(isDocumentElement());
|
| - if (!hasBackground() && isHTMLHtmlElement(node())) {
|
| - // Locate the <body> element using the DOM. This is easier than trying
|
| - // to crawl around a render tree with potential :before/:after content and
|
| - // anonymous blocks created by inline <body> tags etc. We can locate the <body>
|
| - // render object very easily via the DOM.
|
| - HTMLElement* body = document().body();
|
| - RenderObject* bodyObject = isHTMLBodyElement(body) ? body->renderer() : 0;
|
| - if (bodyObject)
|
| - return bodyObject;
|
| - }
|
| -
|
| - return this;
|
| -}
|
| -
|
| -RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const
|
| -{
|
| - // Respect the image's orientation if it's being used as a full-page image or it's
|
| - // an <img> and the setting to respect it everywhere is set.
|
| - return document().isImageDocument()
|
| - || (document().settings() && document().settings()->shouldRespectImageOrientation() && isHTMLImageElement(node())) ? RespectImageOrientation : DoNotRespectImageOrientation;
|
| -}
|
| -
|
| -bool RenderObject::hasEntirelyFixedBackground() const
|
| -{
|
| - return m_style->hasEntirelyFixedBackground();
|
| -}
|
| -
|
| -RenderObject* RenderObject::container(const LayoutLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const
|
| -{
|
| - if (paintInvalidationContainerSkipped)
|
| - *paintInvalidationContainerSkipped = false;
|
| -
|
| - // This method is extremely similar to containingBlock(), but with a few notable
|
| - // exceptions.
|
| - // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
|
| - // the object is not part of the primary document subtree yet.
|
| - // (2) For normal flow elements, it just returns the parent.
|
| - // (3) For absolute positioned elements, it will return a relative positioned inline.
|
| - // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
|
| - // the layout of the positioned object. This does mean that computePositionedLogicalWidth and
|
| - // computePositionedLogicalHeight have to use container().
|
| - RenderObject* o = parent();
|
| -
|
| - if (isText())
|
| - return o;
|
| -
|
| - EPosition pos = m_style->position();
|
| - if (pos == FixedPosition) {
|
| - return containerForFixedPosition(paintInvalidationContainer, paintInvalidationContainerSkipped);
|
| - } else if (pos == AbsolutePosition) {
|
| - // We technically just want our containing block, but
|
| - // we may not have one if we're part of an uninstalled
|
| - // subtree. We'll climb as high as we can though.
|
| - while (o) {
|
| - if (o->style()->position() != StaticPosition)
|
| - break;
|
| -
|
| - if (o->canContainFixedPositionObjects())
|
| - break;
|
| -
|
| - if (paintInvalidationContainerSkipped && o == paintInvalidationContainer)
|
| - *paintInvalidationContainerSkipped = true;
|
| -
|
| - o = o->parent();
|
| - }
|
| - } else if (isColumnSpanAll()) {
|
| - RenderObject* multicolContainer = spannerPlaceholder()->container();
|
| - if (paintInvalidationContainerSkipped && paintInvalidationContainer) {
|
| - // We jumped directly from the spanner to the multicol container. Need to check if
|
| - // we skipped |paintInvalidationContainer| on the way.
|
| - for (RenderObject* walker = parent(); walker && walker != multicolContainer; walker = walker->parent()) {
|
| - if (walker == paintInvalidationContainer) {
|
| - *paintInvalidationContainerSkipped = true;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - return multicolContainer;
|
| - }
|
| -
|
| - return o;
|
| -}
|
| -
|
| -bool RenderObject::isSelectionBorder() const
|
| -{
|
| - SelectionState st = selectionState();
|
| - return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
|
| -}
|
| -
|
| -inline void RenderObject::clearLayoutRootIfNeeded() const
|
| -{
|
| - if (frame()) {
|
| - if (FrameView* view = frame()->view()) {
|
| - if (view->layoutRoot() == this) {
|
| - if (!documentBeingDestroyed())
|
| - ASSERT_NOT_REACHED();
|
| - // This indicates a failure to layout the child, which is why
|
| - // the layout root is still set to |this|. Make sure to clear it
|
| - // since we are getting destroyed.
|
| - view->clearLayoutSubtreeRoot();
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void RenderObject::willBeDestroyed()
|
| -{
|
| - // Destroy any leftover anonymous children.
|
| - RenderObjectChildList* children = virtualChildren();
|
| - if (children)
|
| - children->destroyLeftoverChildren();
|
| -
|
| - // If this renderer is being autoscrolled, stop the autoscrolling.
|
| - if (LocalFrame* frame = this->frame()) {
|
| - if (frame->page())
|
| - frame->page()->autoscrollController().stopAutoscrollIfNeeded(this);
|
| - }
|
| -
|
| - // For accessibility management, notify the parent of the imminent change to its child set.
|
| - // We do it now, before remove(), while the parent pointer is still available.
|
| - if (AXObjectCache* cache = document().existingAXObjectCache())
|
| - cache->childrenChanged(this->parent());
|
| -
|
| - remove();
|
| -
|
| - // The remove() call above may invoke axObjectCache()->childrenChanged() on the parent, which may require the AX render
|
| - // object for this renderer. So we remove the AX render object now, after the renderer is removed.
|
| - if (AXObjectCache* cache = document().existingAXObjectCache())
|
| - cache->remove(this);
|
| -
|
| - // If this renderer had a parent, remove should have destroyed any counters
|
| - // attached to this renderer and marked the affected other counters for
|
| - // reevaluation. This apparently redundant check is here for the case when
|
| - // this renderer had no parent at the time remove() was called.
|
| -
|
| - if (hasCounterNodeMap())
|
| - LayoutCounter::destroyCounterNodes(*this);
|
| -
|
| - // Remove the handler if node had touch-action set. Handlers are not added
|
| - // for text nodes so don't try removing for one too. Need to check if
|
| - // m_style is null in cases of partial construction. Any handler we added
|
| - // previously may have already been removed by the Document independently.
|
| - if (node() && !node()->isTextNode() && m_style && m_style->touchAction() != TouchActionAuto) {
|
| - EventHandlerRegistry& registry = document().frameHost()->eventHandlerRegistry();
|
| - if (registry.eventHandlerTargets(EventHandlerRegistry::TouchEvent)->contains(node()))
|
| - registry.didRemoveEventHandler(*node(), EventHandlerRegistry::TouchEvent);
|
| - }
|
| -
|
| - setAncestorLineBoxDirty(false);
|
| -
|
| - if (selectionPaintInvalidationMap)
|
| - selectionPaintInvalidationMap->remove(this);
|
| -
|
| - clearLayoutRootIfNeeded();
|
| -}
|
| -
|
| -void RenderObject::insertedIntoTree()
|
| -{
|
| - // FIXME: We should ASSERT(isRooted()) here but generated content makes some out-of-order insertion.
|
| -
|
| - // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
|
| - // and don't have a layer attached to ourselves.
|
| - Layer* layer = 0;
|
| - if (slowFirstChild() || hasLayer()) {
|
| - layer = parent()->enclosingLayer();
|
| - addLayers(layer);
|
| - }
|
| -
|
| - // If |this| is visible but this object was not, tell the layer it has some visible content
|
| - // that needs to be drawn and layer visibility optimization can't be used
|
| - if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
|
| - if (!layer)
|
| - layer = parent()->enclosingLayer();
|
| - if (layer)
|
| - layer->dirtyVisibleContentStatus();
|
| - }
|
| -
|
| - if (!isFloating() && parent()->childrenInline())
|
| - parent()->dirtyLinesFromChangedChild(this);
|
| -
|
| - if (RenderFlowThread* flowThread = parent()->flowThreadContainingBlock())
|
| - flowThread->flowThreadDescendantWasInserted(this);
|
| -}
|
| -
|
| -void RenderObject::willBeRemovedFromTree()
|
| -{
|
| - // FIXME: We should ASSERT(isRooted()) but we have some out-of-order removals which would need to be fixed first.
|
| -
|
| - // If we remove a visible child from an invisible parent, we don't know the layer visibility any more.
|
| - Layer* layer = 0;
|
| - if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
|
| - layer = parent()->enclosingLayer();
|
| - if (layer)
|
| - layer->dirtyVisibleContentStatus();
|
| - }
|
| -
|
| - // Keep our layer hierarchy updated.
|
| - if (slowFirstChild() || hasLayer()) {
|
| - if (!layer)
|
| - layer = parent()->enclosingLayer();
|
| - removeLayers(layer);
|
| - }
|
| -
|
| - if (isOutOfFlowPositioned() && parent()->childrenInline())
|
| - parent()->dirtyLinesFromChangedChild(this);
|
| -
|
| - removeFromRenderFlowThread();
|
| -
|
| - // Update cached boundaries in SVG renderers if a child is removed.
|
| - if (parent()->isSVG())
|
| - parent()->setNeedsBoundariesUpdate();
|
| -}
|
| -
|
| -void RenderObject::removeFromRenderFlowThread()
|
| -{
|
| - if (flowThreadState() == NotInsideFlowThread)
|
| - return;
|
| -
|
| - // Sometimes we remove the element from the flow, but it's not destroyed at that time.
|
| - // It's only until later when we actually destroy it and remove all the children from it.
|
| - // Currently, that happens for firstLetter elements and list markers.
|
| - // Pass in the flow thread so that we don't have to look it up for all the children.
|
| - // If we're a column spanner, we need to use our parent to find the flow thread, since a spanner
|
| - // doesn't have the flow thread in its containing block chain. We still need to notify the flow
|
| - // thread when the renderer removed happens to be a spanner, so that we get rid of the spanner
|
| - // placeholder, and column sets around the placeholder get merged.
|
| - RenderFlowThread* flowThread = isColumnSpanAll() ? parent()->flowThreadContainingBlock() : flowThreadContainingBlock();
|
| - removeFromRenderFlowThreadRecursive(flowThread);
|
| -}
|
| -
|
| -void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderFlowThread)
|
| -{
|
| - if (const RenderObjectChildList* children = virtualChildren()) {
|
| - for (RenderObject* child = children->firstChild(); child; child = child->nextSibling())
|
| - child->removeFromRenderFlowThreadRecursive(renderFlowThread);
|
| - }
|
| -
|
| - if (renderFlowThread && renderFlowThread != this)
|
| - renderFlowThread->flowThreadDescendantWillBeRemoved(this);
|
| - setFlowThreadState(NotInsideFlowThread);
|
| - RELEASE_ASSERT(!spannerPlaceholder());
|
| -}
|
| -
|
| -void RenderObject::destroyAndCleanupAnonymousWrappers()
|
| -{
|
| - // If the tree is destroyed, there is no need for a clean-up phase.
|
| - if (documentBeingDestroyed()) {
|
| - destroy();
|
| - return;
|
| - }
|
| -
|
| - RenderObject* destroyRoot = this;
|
| - for (RenderObject* destroyRootParent = destroyRoot->parent(); destroyRootParent && destroyRootParent->isAnonymous(); destroyRoot = destroyRootParent, destroyRootParent = destroyRootParent->parent()) {
|
| - // Anonymous block continuations are tracked and destroyed elsewhere (see the bottom of RenderBlock::removeChild)
|
| - if (destroyRootParent->isRenderBlock() && toRenderBlock(destroyRootParent)->isAnonymousBlockContinuation())
|
| - break;
|
| - // A flow thread is tracked by its containing block. Whether its children are removed or not is irrelevant.
|
| - if (destroyRootParent->isRenderFlowThread())
|
| - break;
|
| - // Column spans are tracked elsewhere.
|
| - if (destroyRootParent->isAnonymousColumnSpanBlock())
|
| - break;
|
| -
|
| - if (destroyRootParent->slowFirstChild() != destroyRoot || destroyRootParent->slowLastChild() != destroyRoot)
|
| - break; // Need to keep the anonymous parent, since it won't become empty by the removal of this renderer.
|
| - }
|
| -
|
| - destroyRoot->destroy();
|
| -
|
| - // WARNING: |this| is deleted here.
|
| -}
|
| -
|
| -void RenderObject::destroy()
|
| -{
|
| - willBeDestroyed();
|
| - postDestroy();
|
| -}
|
| -
|
| -void RenderObject::removeShapeImageClient(ShapeValue* shapeValue)
|
| -{
|
| - if (!shapeValue)
|
| - return;
|
| - if (StyleImage* shapeImage = shapeValue->image())
|
| - shapeImage->removeClient(this);
|
| -}
|
| -
|
| -void RenderObject::postDestroy()
|
| -{
|
| - // It seems ugly that this is not in willBeDestroyed().
|
| - if (m_style) {
|
| - for (const FillLayer* bgLayer = &m_style->backgroundLayers(); bgLayer; bgLayer = bgLayer->next()) {
|
| - if (StyleImage* backgroundImage = bgLayer->image())
|
| - backgroundImage->removeClient(this);
|
| - }
|
| -
|
| - for (const FillLayer* maskLayer = &m_style->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
|
| - if (StyleImage* maskImage = maskLayer->image())
|
| - maskImage->removeClient(this);
|
| - }
|
| -
|
| - if (StyleImage* borderImage = m_style->borderImage().image())
|
| - borderImage->removeClient(this);
|
| -
|
| - if (StyleImage* maskBoxImage = m_style->maskBoxImage().image())
|
| - maskBoxImage->removeClient(this);
|
| -
|
| - removeShapeImageClient(m_style->shapeOutside());
|
| - }
|
| - ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeRenderObject(this);
|
| - delete this;
|
| -}
|
| -
|
| -PositionWithAffinity RenderObject::positionForPoint(const LayoutPoint&)
|
| -{
|
| - return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
|
| -}
|
| -
|
| -void RenderObject::updateDragState(bool dragOn)
|
| -{
|
| - bool valueChanged = (dragOn != isDragging());
|
| - setIsDragging(dragOn);
|
| - if (valueChanged && node()) {
|
| - if (node()->isElementNode() && toElement(node())->childrenOrSiblingsAffectedByDrag())
|
| - node()->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Drag));
|
| - else if (style()->affectedByDrag())
|
| - node()->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Drag));
|
| - }
|
| - for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
|
| - curr->updateDragState(dragOn);
|
| -}
|
| -
|
| -CompositingState RenderObject::compositingState() const
|
| -{
|
| - return hasLayer() ? toLayoutLayerModelObject(this)->layer()->compositingState() : NotComposited;
|
| -}
|
| -
|
| -CompositingReasons RenderObject::additionalCompositingReasons() const
|
| -{
|
| - return CompositingReasonNone;
|
| -}
|
| -
|
| -bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter)
|
| -{
|
| - bool inside = false;
|
| - if (hitTestFilter != HitTestSelf) {
|
| - // First test the foreground layer (lines and inlines).
|
| - inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestForeground);
|
| -
|
| - // Test floats next.
|
| - if (!inside)
|
| - inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestFloat);
|
| -
|
| - // Finally test to see if the mouse is in the background (within a child block's background).
|
| - if (!inside)
|
| - inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestChildBlockBackgrounds);
|
| - }
|
| -
|
| - // See if the mouse is inside us but not any of our descendants
|
| - if (hitTestFilter != HitTestDescendants && !inside)
|
| - inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestBlockBackground);
|
| -
|
| - return inside;
|
| -}
|
| -
|
| -void RenderObject::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
|
| -{
|
| - if (result.innerNode())
|
| - return;
|
| -
|
| - Node* node = this->node();
|
| -
|
| - // If we hit the anonymous renderers inside generated content we should
|
| - // actually hit the generated content so walk up to the PseudoElement.
|
| - if (!node && parent() && parent()->isBeforeOrAfterContent()) {
|
| - for (RenderObject* renderer = parent(); renderer && !node; renderer = renderer->parent())
|
| - node = renderer->node();
|
| - }
|
| -
|
| - if (node) {
|
| - result.setInnerNode(node);
|
| - if (!result.innerNonSharedNode())
|
| - result.setInnerNonSharedNode(node);
|
| - result.setLocalPoint(point);
|
| - }
|
| -}
|
| -
|
| -bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& /*locationInContainer*/, const LayoutPoint& /*accumulatedOffset*/, HitTestAction)
|
| -{
|
| - return false;
|
| -}
|
| -
|
| -void RenderObject::scheduleRelayout()
|
| -{
|
| - if (isRenderView()) {
|
| - FrameView* view = toRenderView(this)->frameView();
|
| - if (view)
|
| - view->scheduleRelayout();
|
| - } else {
|
| - if (isRooted()) {
|
| - if (RenderView* renderView = view()) {
|
| - if (FrameView* frameView = renderView->frameView())
|
| - frameView->scheduleRelayoutOfSubtree(this);
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -void RenderObject::forceLayout()
|
| -{
|
| - setSelfNeedsLayout(true);
|
| - setShouldDoFullPaintInvalidation();
|
| - layout();
|
| -}
|
| -
|
| -// FIXME: Does this do anything different than forceLayout given that we don't walk
|
| -// the containing block chain. If not, we should change all callers to use forceLayout.
|
| -void RenderObject::forceChildLayout()
|
| -{
|
| - setNormalChildNeedsLayout(true);
|
| - layout();
|
| -}
|
| -
|
| -enum StyleCacheState {
|
| - Cached,
|
| - Uncached
|
| -};
|
| -
|
| -static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheState type, const RenderObject* renderer, RenderStyle* style)
|
| -{
|
| - const RenderObject* rendererForFirstLineStyle = renderer;
|
| - if (renderer->isBeforeOrAfterContent())
|
| - rendererForFirstLineStyle = renderer->parent();
|
| -
|
| - if (rendererForFirstLineStyle->isRenderBlockFlow() || rendererForFirstLineStyle->isRenderButton()) {
|
| - if (RenderBlock* firstLineBlock = rendererForFirstLineStyle->firstLineBlock()) {
|
| - if (type == Cached)
|
| - return firstLineBlock->getCachedPseudoStyle(FIRST_LINE, style);
|
| - return firstLineBlock->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE), style, firstLineBlock == renderer ? style : 0);
|
| - }
|
| - } else if (!rendererForFirstLineStyle->isAnonymous() && rendererForFirstLineStyle->isRenderInline()
|
| - && !rendererForFirstLineStyle->node()->isFirstLetterPseudoElement()) {
|
| - RenderStyle* parentStyle = rendererForFirstLineStyle->parent()->firstLineStyle();
|
| - if (parentStyle != rendererForFirstLineStyle->parent()->style()) {
|
| - if (type == Cached) {
|
| - // A first-line style is in effect. Cache a first-line style for ourselves.
|
| - rendererForFirstLineStyle->style()->setHasPseudoStyle(FIRST_LINE_INHERITED);
|
| - return rendererForFirstLineStyle->getCachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle);
|
| - }
|
| - return rendererForFirstLineStyle->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), parentStyle, style);
|
| - }
|
| - }
|
| - return nullptr;
|
| -}
|
| -
|
| -PassRefPtr<RenderStyle> RenderObject::uncachedFirstLineStyle(RenderStyle* style) const
|
| -{
|
| - if (!document().styleEngine()->usesFirstLineRules())
|
| - return nullptr;
|
| -
|
| - ASSERT(!isText());
|
| -
|
| - return firstLineStyleForCachedUncachedType(Uncached, this, style);
|
| -}
|
| -
|
| -RenderStyle* RenderObject::cachedFirstLineStyle() const
|
| -{
|
| - ASSERT(document().styleEngine()->usesFirstLineRules());
|
| -
|
| - if (RefPtr<RenderStyle> style = firstLineStyleForCachedUncachedType(Cached, isText() ? parent() : this, m_style.get()))
|
| - return style.get();
|
| -
|
| - return m_style.get();
|
| -}
|
| -
|
| -RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle) const
|
| -{
|
| - if (pseudo < FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo))
|
| - return 0;
|
| -
|
| - RenderStyle* cachedStyle = style()->getCachedPseudoStyle(pseudo);
|
| - if (cachedStyle)
|
| - return cachedStyle;
|
| -
|
| - RefPtr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle);
|
| - if (result)
|
| - return style()->addCachedPseudoStyle(result.release());
|
| - return 0;
|
| -}
|
| -
|
| -PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const
|
| -{
|
| - if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId))
|
| - return nullptr;
|
| -
|
| - if (!parentStyle) {
|
| - ASSERT(!ownStyle);
|
| - parentStyle = style();
|
| - }
|
| -
|
| - if (!node())
|
| - return nullptr;
|
| -
|
| - Element* element = Traversal<Element>::firstAncestorOrSelf(*node());
|
| - if (!element)
|
| - return nullptr;
|
| -
|
| - if (pseudoStyleRequest.pseudoId == FIRST_LINE_INHERITED) {
|
| - RefPtr<RenderStyle> result = document().ensureStyleResolver().styleForElement(element, parentStyle, DisallowStyleSharing);
|
| - result->setStyleType(FIRST_LINE_INHERITED);
|
| - return result.release();
|
| - }
|
| -
|
| - return document().ensureStyleResolver().pseudoStyleForElement(element, pseudoStyleRequest, parentStyle);
|
| -}
|
| -
|
| -PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyleFromParentOrShadowHost() const
|
| -{
|
| - if (!node())
|
| - return nullptr;
|
| -
|
| - if (ShadowRoot* root = node()->containingShadowRoot()) {
|
| - if (root->type() == ShadowRoot::UserAgentShadowRoot) {
|
| - if (Element* shadowHost = node()->shadowHost()) {
|
| - return shadowHost->renderer()->getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
|
| - }
|
| - }
|
| - }
|
| -
|
| - return getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
|
| -}
|
| -
|
| -void RenderObject::getTextDecorations(unsigned decorations, AppliedTextDecoration& underline, AppliedTextDecoration& overline, AppliedTextDecoration& linethrough, bool quirksMode, bool firstlineStyle)
|
| -{
|
| - RenderObject* curr = this;
|
| - RenderStyle* styleToUse = 0;
|
| - unsigned currDecs = TextDecorationNone;
|
| - Color resultColor;
|
| - TextDecorationStyle resultStyle;
|
| - do {
|
| - styleToUse = curr->style(firstlineStyle);
|
| - currDecs = styleToUse->textDecoration();
|
| - currDecs &= decorations;
|
| - resultColor = styleToUse->visitedDependentColor(CSSPropertyTextDecorationColor);
|
| - resultStyle = styleToUse->textDecorationStyle();
|
| - // Parameter 'decorations' is cast as an int to enable the bitwise operations below.
|
| - if (currDecs) {
|
| - if (currDecs & TextDecorationUnderline) {
|
| - decorations &= ~TextDecorationUnderline;
|
| - underline.color = resultColor;
|
| - underline.style = resultStyle;
|
| - }
|
| - if (currDecs & TextDecorationOverline) {
|
| - decorations &= ~TextDecorationOverline;
|
| - overline.color = resultColor;
|
| - overline.style = resultStyle;
|
| - }
|
| - if (currDecs & TextDecorationLineThrough) {
|
| - decorations &= ~TextDecorationLineThrough;
|
| - linethrough.color = resultColor;
|
| - linethrough.style = resultStyle;
|
| - }
|
| - }
|
| - if (curr->isRubyText())
|
| - return;
|
| - curr = curr->parent();
|
| - if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation())
|
| - curr = toRenderBlock(curr)->continuation();
|
| - } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(*curr->node()) && !isHTMLFontElement(*curr->node()))));
|
| -
|
| - // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
|
| - if (decorations && curr) {
|
| - styleToUse = curr->style(firstlineStyle);
|
| - resultColor = styleToUse->visitedDependentColor(CSSPropertyTextDecorationColor);
|
| - if (decorations & TextDecorationUnderline) {
|
| - underline.color = resultColor;
|
| - underline.style = resultStyle;
|
| - }
|
| - if (decorations & TextDecorationOverline) {
|
| - overline.color = resultColor;
|
| - overline.style = resultStyle;
|
| - }
|
| - if (decorations & TextDecorationLineThrough) {
|
| - linethrough.color = resultColor;
|
| - linethrough.style = resultStyle;
|
| - }
|
| - }
|
| -}
|
| -
|
| -void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
|
| -{
|
| - // Convert the style regions to absolute coordinates.
|
| - if (style()->visibility() != VISIBLE || !isBox())
|
| - return;
|
| -
|
| - if (style()->getDraggableRegionMode() == DraggableRegionNone)
|
| - return;
|
| -
|
| - RenderBox* box = toRenderBox(this);
|
| - FloatRect localBounds(FloatPoint(), FloatSize(box->size()));
|
| - FloatRect absBounds = localToAbsoluteQuad(localBounds).boundingBox();
|
| -
|
| - AnnotatedRegionValue region;
|
| - region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
|
| - region.bounds = LayoutRect(absBounds);
|
| - regions.append(region);
|
| -}
|
| -
|
| -void RenderObject::collectAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
|
| -{
|
| - // RenderTexts don't have their own style, they just use their parent's style,
|
| - // so we don't want to include them.
|
| - if (isText())
|
| - return;
|
| -
|
| - addAnnotatedRegions(regions);
|
| - for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
|
| - curr->collectAnnotatedRegions(regions);
|
| -}
|
| -
|
| -bool RenderObject::willRenderImage(ImageResource*)
|
| -{
|
| - // Without visibility we won't render (and therefore don't care about animation).
|
| - if (style()->visibility() != VISIBLE)
|
| - return false;
|
| -
|
| - // We will not render a new image when Active DOM is suspended
|
| - if (document().activeDOMObjectsAreSuspended())
|
| - return false;
|
| -
|
| - // If we're not in a window (i.e., we're dormant from being in a background tab)
|
| - // then we don't want to render either.
|
| - return document().view()->isVisible();
|
| -}
|
| -
|
| -bool RenderObject::getImageAnimationPolicy(ImageResource*, ImageAnimationPolicy& policy)
|
| -{
|
| - if (!document().settings())
|
| - return false;
|
| -
|
| - policy = document().settings()->imageAnimationPolicy();
|
| - return true;
|
| -}
|
| -
|
| -int RenderObject::caretMinOffset() const
|
| -{
|
| - return 0;
|
| -}
|
| -
|
| -int RenderObject::caretMaxOffset() const
|
| -{
|
| - if (isReplaced())
|
| - return node() ? std::max(1U, node()->countChildren()) : 1;
|
| - if (isHR())
|
| - return 1;
|
| - return 0;
|
| -}
|
| -
|
| -int RenderObject::previousOffset(int current) const
|
| -{
|
| - return current - 1;
|
| -}
|
| -
|
| -int RenderObject::previousOffsetForBackwardDeletion(int current) const
|
| -{
|
| - return current - 1;
|
| -}
|
| -
|
| -int RenderObject::nextOffset(int current) const
|
| -{
|
| - return current + 1;
|
| -}
|
| -
|
| -bool RenderObject::isInert() const
|
| -{
|
| - const RenderObject* renderer = this;
|
| - while (!renderer->node())
|
| - renderer = renderer->parent();
|
| - return renderer->node()->isInert();
|
| -}
|
| -
|
| -// touch-action applies to all elements with both width AND height properties.
|
| -// According to the CSS Box Model Spec (http://dev.w3.org/csswg/css-box/#the-width-and-height-properties)
|
| -// width applies to all elements but non-replaced inline elements, table rows, and row groups and
|
| -// height applies to all elements but non-replaced inline elements, table columns, and column groups.
|
| -bool RenderObject::supportsTouchAction() const
|
| -{
|
| - if (isInline() && !isReplaced())
|
| - return false;
|
| - if (isTableRow() || isLayoutTableCol())
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void RenderObject::imageChanged(ImageResource* image, const IntRect* rect)
|
| -{
|
| - imageChanged(static_cast<WrappedImagePtr>(image), rect);
|
| -}
|
| -
|
| -Element* RenderObject::offsetParent() const
|
| -{
|
| - if (isDocumentElement() || isBody())
|
| - return 0;
|
| -
|
| - if (isOutOfFlowPositioned() && style()->position() == FixedPosition)
|
| - return 0;
|
| -
|
| - float effectiveZoom = style()->effectiveZoom();
|
| - Node* node = 0;
|
| - for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
|
| - // Spec: http://www.w3.org/TR/cssom-view/#offset-attributes
|
| -
|
| - node = ancestor->node();
|
| -
|
| - if (!node)
|
| - continue;
|
| -
|
| - if (ancestor->isPositioned())
|
| - break;
|
| -
|
| - if (isHTMLBodyElement(*node))
|
| - break;
|
| -
|
| - if (!isPositioned() && (isHTMLTableElement(*node) || isHTMLTableCellElement(*node)))
|
| - break;
|
| -
|
| - // Webkit specific extension where offsetParent stops at zoom level changes.
|
| - if (effectiveZoom != ancestor->style()->effectiveZoom())
|
| - break;
|
| - }
|
| -
|
| - return node && node->isElementNode() ? toElement(node) : 0;
|
| -}
|
| -
|
| -PositionWithAffinity RenderObject::createPositionWithAffinity(int offset, EAffinity affinity)
|
| -{
|
| - // If this is a non-anonymous renderer in an editable area, then it's simple.
|
| - if (Node* node = nonPseudoNode()) {
|
| - if (!node->hasEditableStyle()) {
|
| - // If it can be found, we prefer a visually equivalent position that is editable.
|
| - Position position = createLegacyEditingPosition(node, offset);
|
| - Position candidate = position.downstream(CanCrossEditingBoundary);
|
| - if (candidate.deprecatedNode()->hasEditableStyle())
|
| - return PositionWithAffinity(candidate, affinity);
|
| - candidate = position.upstream(CanCrossEditingBoundary);
|
| - if (candidate.deprecatedNode()->hasEditableStyle())
|
| - return PositionWithAffinity(candidate, affinity);
|
| - }
|
| - // FIXME: Eliminate legacy editing positions
|
| - return PositionWithAffinity(createLegacyEditingPosition(node, offset), affinity);
|
| - }
|
| -
|
| - // We don't want to cross the boundary between editable and non-editable
|
| - // regions of the document, but that is either impossible or at least
|
| - // extremely unlikely in any normal case because we stop as soon as we
|
| - // find a single non-anonymous renderer.
|
| -
|
| - // Find a nearby non-anonymous renderer.
|
| - RenderObject* child = this;
|
| - while (RenderObject* parent = child->parent()) {
|
| - // Find non-anonymous content after.
|
| - for (RenderObject* renderer = child->nextInPreOrder(parent); renderer; renderer = renderer->nextInPreOrder(parent)) {
|
| - if (Node* node = renderer->nonPseudoNode())
|
| - return PositionWithAffinity(firstPositionInOrBeforeNode(node), DOWNSTREAM);
|
| - }
|
| -
|
| - // Find non-anonymous content before.
|
| - for (RenderObject* renderer = child->previousInPreOrder(); renderer; renderer = renderer->previousInPreOrder()) {
|
| - if (renderer == parent)
|
| - break;
|
| - if (Node* node = renderer->nonPseudoNode())
|
| - return PositionWithAffinity(lastPositionInOrAfterNode(node), DOWNSTREAM);
|
| - }
|
| -
|
| - // Use the parent itself unless it too is anonymous.
|
| - if (Node* node = parent->nonPseudoNode())
|
| - return PositionWithAffinity(firstPositionInOrBeforeNode(node), DOWNSTREAM);
|
| -
|
| - // Repeat at the next level up.
|
| - child = parent;
|
| - }
|
| -
|
| - // Everything was anonymous. Give up.
|
| - return PositionWithAffinity();
|
| -}
|
| -
|
| -PositionWithAffinity RenderObject::createPositionWithAffinity(const Position& position)
|
| -{
|
| - if (position.isNotNull())
|
| - return PositionWithAffinity(position);
|
| -
|
| - ASSERT(!node());
|
| - return createPositionWithAffinity(0, DOWNSTREAM);
|
| -}
|
| -
|
| -CursorDirective RenderObject::getCursor(const LayoutPoint&, Cursor&) const
|
| -{
|
| - return SetCursorBasedOnStyle;
|
| -}
|
| -
|
| -bool RenderObject::canUpdateSelectionOnRootLineBoxes() const
|
| -{
|
| - if (needsLayout())
|
| - return false;
|
| -
|
| - const RenderBlock* containingBlock = this->containingBlock();
|
| - return containingBlock ? !containingBlock->needsLayout() : false;
|
| -}
|
| -
|
| -// We only create "generated" child renderers like one for first-letter if:
|
| -// - the firstLetterBlock can have children in the DOM and
|
| -// - the block doesn't have any special assumption on its text children.
|
| -// This correctly prevents form controls from having such renderers.
|
| -bool RenderObject::canHaveGeneratedChildren() const
|
| -{
|
| - return canHaveChildren();
|
| -}
|
| -
|
| -void RenderObject::setNeedsBoundariesUpdate()
|
| -{
|
| - if (RenderObject* renderer = parent())
|
| - renderer->setNeedsBoundariesUpdate();
|
| -}
|
| -
|
| -FloatRect RenderObject::objectBoundingBox() const
|
| -{
|
| - ASSERT_NOT_REACHED();
|
| - return FloatRect();
|
| -}
|
| -
|
| -FloatRect RenderObject::strokeBoundingBox() const
|
| -{
|
| - ASSERT_NOT_REACHED();
|
| - return FloatRect();
|
| -}
|
| -
|
| -// Returns the smallest rectangle enclosing all of the painted content
|
| -// respecting clipping, masking, filters, opacity, stroke-width and markers
|
| -FloatRect RenderObject::paintInvalidationRectInLocalCoordinates() const
|
| -{
|
| - ASSERT_NOT_REACHED();
|
| - return FloatRect();
|
| -}
|
| -
|
| -AffineTransform RenderObject::localTransform() const
|
| -{
|
| - static const AffineTransform identity;
|
| - return identity;
|
| -}
|
| -
|
| -const AffineTransform& RenderObject::localToParentTransform() const
|
| -{
|
| - static const AffineTransform identity;
|
| - return identity;
|
| -}
|
| -
|
| -bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction)
|
| -{
|
| - ASSERT_NOT_REACHED();
|
| - return false;
|
| -}
|
| -
|
| -bool RenderObject::isRelayoutBoundaryForInspector() const
|
| -{
|
| - return objectIsRelayoutBoundary(this);
|
| -}
|
| -
|
| -static PaintInvalidationReason documentLifecycleBasedPaintInvalidationReason(const DocumentLifecycle& documentLifecycle)
|
| -{
|
| - switch (documentLifecycle.state()) {
|
| - case DocumentLifecycle::InStyleRecalc:
|
| - return PaintInvalidationStyleChange;
|
| - case DocumentLifecycle::InPreLayout:
|
| - case DocumentLifecycle::InPerformLayout:
|
| - case DocumentLifecycle::AfterPerformLayout:
|
| - return PaintInvalidationForcedByLayout;
|
| - case DocumentLifecycle::InCompositingUpdate:
|
| - return PaintInvalidationCompositingUpdate;
|
| - default:
|
| - return PaintInvalidationFull;
|
| - }
|
| -}
|
| -
|
| -void RenderObject::setShouldDoFullPaintInvalidation(PaintInvalidationReason reason)
|
| -{
|
| - // Only full invalidation reasons are allowed.
|
| - ASSERT(isFullPaintInvalidationReason(reason));
|
| -
|
| - if (m_bitfields.fullPaintInvalidationReason() == PaintInvalidationNone) {
|
| - if (reason == PaintInvalidationFull)
|
| - reason = documentLifecycleBasedPaintInvalidationReason(document().lifecycle());
|
| - m_bitfields.setFullPaintInvalidationReason(reason);
|
| - }
|
| -
|
| - ASSERT(document().lifecycle().state() != DocumentLifecycle::InPaintInvalidation);
|
| - frame()->page()->animator().scheduleVisualUpdate(); // In case that this is called outside of FrameView::updateLayoutAndStyleForPainting().
|
| - markContainingBlockChainForPaintInvalidation();
|
| -}
|
| -
|
| -void RenderObject::setMayNeedPaintInvalidation()
|
| -{
|
| - if (mayNeedPaintInvalidation())
|
| - return;
|
| - m_bitfields.setMayNeedPaintInvalidation(true);
|
| - // Make sure our parent is marked as needing invalidation.
|
| - markContainingBlockChainForPaintInvalidation();
|
| - frame()->page()->animator().scheduleVisualUpdate(); // In case that this is called outside of FrameView::updateLayoutAndStyleForPainting().
|
| -}
|
| -
|
| -void RenderObject::clearMayNeedPaintInvalidation()
|
| -{
|
| - m_bitfields.setMayNeedPaintInvalidation(false);
|
| -}
|
| -
|
| -void RenderObject::setSelfMayNeedPaintInvalidation()
|
| -{
|
| - m_bitfields.setMayNeedPaintInvalidation(true);
|
| -}
|
| -
|
| -void RenderObject::markContainingBlockChainForPaintInvalidation()
|
| -{
|
| - for (RenderObject* container = this->container(); container && !container->shouldCheckForPaintInvalidationRegardlessOfPaintInvalidationState(); container = container->container())
|
| - container->setSelfMayNeedPaintInvalidation();
|
| -}
|
| -
|
| -void RenderObject::clearPaintInvalidationState(const PaintInvalidationState& paintInvalidationState)
|
| -{
|
| - // paintInvalidationStateIsDirty should be kept in sync with the
|
| - // booleans that are cleared below.
|
| - ASSERT(paintInvalidationState.forceCheckForPaintInvalidation() || paintInvalidationStateIsDirty());
|
| - clearShouldDoFullPaintInvalidation();
|
| - setNeededLayoutBecauseOfChildren(false);
|
| - setShouldInvalidateOverflowForPaint(false);
|
| - clearLayoutDidGetCalledSinceLastFrame();
|
| - clearMayNeedPaintInvalidation();
|
| - clearShouldInvalidateSelection();
|
| -}
|
| -
|
| -bool RenderObject::isAllowedToModifyRenderTreeStructure(Document& document)
|
| -{
|
| - return DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState()
|
| - || document.lifecycle().stateAllowsRenderTreeMutations();
|
| -}
|
| -
|
| -DeprecatedDisableModifyRenderTreeStructureAsserts::DeprecatedDisableModifyRenderTreeStructureAsserts()
|
| - : m_disabler(gModifyRenderTreeStructureAnyState, true)
|
| -{
|
| -}
|
| -
|
| -bool DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState()
|
| -{
|
| - return gModifyRenderTreeStructureAnyState;
|
| -}
|
| -
|
| -// Since we're only painting non-composited layers, we know that they all share the same paintInvalidationContainer.
|
| -void RenderObject::invalidatePaintIncludingNonCompositingDescendants()
|
| -{
|
| - invalidatePaintIncludingNonCompositingDescendantsInternal(containerForPaintInvalidation());
|
| -}
|
| -
|
| -void RenderObject::invalidatePaintIncludingNonCompositingDescendantsInternal(const LayoutLayerModelObject* paintInvalidationContainer)
|
| -{
|
| - invalidatePaintUsingContainer(paintInvalidationContainer, previousPaintInvalidationRect(), PaintInvalidationLayer);
|
| -
|
| - for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
|
| - if (!child->isPaintInvalidationContainer())
|
| - child->invalidatePaintIncludingNonCompositingDescendantsInternal(paintInvalidationContainer);
|
| - }
|
| -}
|
| -
|
| -
|
| -} // namespace blink
|
| -
|
| -#ifndef NDEBUG
|
| -
|
| -void showTree(const blink::RenderObject* object)
|
| -{
|
| - if (object)
|
| - object->showTreeForThis();
|
| -}
|
| -
|
| -void showLineTree(const blink::RenderObject* object)
|
| -{
|
| - if (object)
|
| - object->showLineTreeForThis();
|
| -}
|
| -
|
| -void showRenderTree(const blink::RenderObject* object1)
|
| -{
|
| - showRenderTree(object1, 0);
|
| -}
|
| -
|
| -void showRenderTree(const blink::RenderObject* object1, const blink::RenderObject* object2)
|
| -{
|
| - if (object1) {
|
| - const blink::RenderObject* root = object1;
|
| - while (root->parent())
|
| - root = root->parent();
|
| - root->showRenderTreeAndMark(object1, "*", object2, "-", 0);
|
| - }
|
| -}
|
| -
|
| -#endif
|
|
|