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 |