summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp1497
1 files changed, 818 insertions, 679 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp
index 1192be3d768..90af71bf364 100644
--- a/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp
+++ b/chromium/third_party/WebKit/Source/core/rendering/RenderObject.cpp
@@ -27,48 +27,43 @@
#include "config.h"
#include "core/rendering/RenderObject.h"
-#include "HTMLNames.h"
-#include "RuntimeEnabledFeatures.h"
+#include "core/HTMLNames.h"
#include "core/accessibility/AXObjectCache.h"
#include "core/animation/ActiveAnimations.h"
#include "core/css/resolver/StyleResolver.h"
+#include "core/dom/ElementTraversal.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/FrameView.h"
+#include "core/frame/LocalFrame.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/page/AutoscrollController.h"
#include "core/page/EventHandler.h"
-#include "core/frame/Frame.h"
-#include "core/frame/FrameView.h"
#include "core/page/Page.h"
#include "core/frame/Settings.h"
#include "core/frame/UseCounter.h"
-#include "core/frame/animation/AnimationController.h"
-#include "core/rendering/CompositedLayerMapping.h"
#include "core/rendering/FlowThreadController.h"
#include "core/rendering/HitTestResult.h"
-#include "core/rendering/LayoutRectRecorder.h"
#include "core/rendering/RenderCounter.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/RenderLayer.h"
-#include "core/rendering/RenderLayerCompositor.h"
#include "core/rendering/RenderListItem.h"
#include "core/rendering/RenderMarquee.h"
-#include "core/rendering/RenderMultiColumnBlock.h"
-#include "core/rendering/RenderNamedFlowThread.h"
-#include "core/rendering/RenderRegion.h"
-#include "core/rendering/RenderRuby.h"
-#include "core/rendering/RenderRubyText.h"
#include "core/rendering/RenderScrollbarPart.h"
#include "core/rendering/RenderTableCaption.h"
#include "core/rendering/RenderTableCell.h"
@@ -76,15 +71,20 @@
#include "core/rendering/RenderTableRow.h"
#include "core/rendering/RenderTheme.h"
#include "core/rendering/RenderView.h"
+#include "core/rendering/compositing/CompositedLayerMapping.h"
+#include "core/rendering/compositing/RenderLayerCompositor.h"
#include "core/rendering/style/ContentData.h"
-#include "core/rendering/style/CursorList.h"
#include "core/rendering/style/ShadowList.h"
-#include "core/rendering/svg/SVGRenderSupport.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 "wtf/RefCountedLeakCounter.h"
#include "wtf/text/StringBuilder.h"
+#include "wtf/text/WTFString.h"
#include <algorithm>
#ifndef NDEBUG
#include <stdio.h>
@@ -94,20 +94,26 @@ using namespace std;
namespace WebCore {
+namespace {
+
+static bool gModifyRenderTreeStructureAnyState = false;
+
+} // namespace
+
using namespace HTMLNames;
#ifndef NDEBUG
-RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject)
+RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject& renderObject)
: m_renderObject(renderObject)
- , m_preexistingForbidden(m_renderObject->isSetNeedsLayoutForbidden())
+ , m_preexistingForbidden(m_renderObject.isSetNeedsLayoutForbidden())
{
- m_renderObject->setNeedsLayoutIsForbidden(true);
+ m_renderObject.setNeedsLayoutIsForbidden(true);
}
RenderObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope()
{
- m_renderObject->setNeedsLayoutIsForbidden(m_preexistingForbidden);
+ m_renderObject.setNeedsLayoutIsForbidden(m_preexistingForbidden);
}
#endif
@@ -119,7 +125,8 @@ struct SameSizeAsRenderObject {
#endif
unsigned m_bitfields;
unsigned m_bitfields2;
- LayoutRect rects[2]; // Stores the old/new repaint rects.
+ LayoutRect rect; // Stores the previous paint invalidation rect.
+ LayoutPoint position; // Stores the previous position from the paint invalidation container.
};
COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small);
@@ -140,7 +147,7 @@ void RenderObject::operator delete(void* ptr)
RenderObject* RenderObject::createObject(Element* element, RenderStyle* style)
{
- Document& doc = element->document();
+ 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.
@@ -157,20 +164,10 @@ RenderObject* RenderObject::createObject(Element* element, RenderStyle* style)
image->setIsGeneratedContent();
} else
image->setImageResource(RenderImageResource::create());
- image->setStyleInternal(0);
+ image->setStyleInternal(nullptr);
return image;
}
- if (element->hasTagName(rubyTag)) {
- if (style->display() == INLINE)
- return new RenderRubyAsInline(element);
- else if (style->display() == BLOCK)
- return new RenderRubyAsBlock(element);
- }
- // treat <rt> as ruby text ONLY if it still has its default treatment of block
- if (element->hasTagName(rtTag) && style->display() == BLOCK)
- return new RenderRubyText(element);
-
switch (style->display()) {
case NONE:
return 0;
@@ -178,8 +175,6 @@ RenderObject* RenderObject::createObject(Element* element, RenderStyle* style)
return new RenderInline(element);
case BLOCK:
case INLINE_BLOCK:
- if ((!style->hasAutoColumnCount() || !style->hasAutoColumnWidth()) && doc.regionBasedColumnsEnabled())
- return new RenderMultiColumnBlock(element);
return new RenderBlockFlow(element);
case LIST_ITEM:
return new RenderListItem(element);
@@ -217,7 +212,7 @@ DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("Rend
RenderObject::RenderObject(Node* node)
: ImageResourceClient()
- , m_style(0)
+ , m_style(nullptr)
, m_node(node)
, m_parent(0)
, m_previous(0)
@@ -235,6 +230,7 @@ RenderObject::RenderObject(Node* node)
RenderObject::~RenderObject()
{
+ ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeRenderObject(this);
#ifndef NDEBUG
ASSERT(!m_hasAXObject);
renderObjectCounter.decrement();
@@ -263,31 +259,24 @@ bool RenderObject::isDescendantOf(const RenderObject* obj) const
return false;
}
-bool RenderObject::isBody() const
-{
- return node() && node()->hasTagName(bodyTag);
-}
-
bool RenderObject::isHR() const
{
- return node() && node()->hasTagName(hrTag);
+ return isHTMLHRElement(node());
}
bool RenderObject::isLegend() const
{
- return node() && node()->hasTagName(legendTag);
+ return isHTMLLegendElement(node());
}
void RenderObject::setFlowThreadStateIncludingDescendants(FlowThreadState state)
{
- setFlowThreadState(state);
-
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
- // If the child is a fragmentation context it already updated the descendants flag accordingly.
- if (child->isRenderFlowThread())
+ 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 != child->flowThreadState());
- child->setFlowThreadStateIncludingDescendants(state);
+ ASSERT(state != object->flowThreadState());
+ object->setFlowThreadState(state);
}
}
@@ -313,6 +302,8 @@ bool RenderObject::requiresAnonymousTableWrappers(const RenderObject* newChild)
void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
{
+ ASSERT(isAllowedToModifyRenderTreeStructure(document()));
+
RenderObjectChildList* children = virtualChildren();
ASSERT(children);
if (!children)
@@ -340,7 +331,7 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
// 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...
- // - requiresLayer() would return true for the <body>, creating a new RenderLayer
+ // - layerTypeRequired() would return true for the <body>, creating a new RenderLayer
// - 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
@@ -351,6 +342,8 @@ void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild)
void RenderObject::removeChild(RenderObject* oldChild)
{
+ ASSERT(isAllowedToModifyRenderTreeStructure(document()));
+
RenderObjectChildList* children = virtualChildren();
ASSERT(children);
if (!children)
@@ -361,7 +354,7 @@ void RenderObject::removeChild(RenderObject* oldChild)
RenderObject* RenderObject::nextInPreOrder() const
{
- if (RenderObject* o = firstChild())
+ if (RenderObject* o = slowFirstChild())
return o;
return nextInPreOrderAfterChildren();
@@ -383,7 +376,7 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren() const
RenderObject* RenderObject::nextInPreOrder(const RenderObject* stayWithin) const
{
- if (RenderObject* o = firstChild())
+ if (RenderObject* o = slowFirstChild())
return o;
return nextInPreOrderAfterChildren(stayWithin);
@@ -407,8 +400,8 @@ RenderObject* RenderObject::nextInPreOrderAfterChildren(const RenderObject* stay
RenderObject* RenderObject::previousInPreOrder() const
{
if (RenderObject* o = previousSibling()) {
- while (o->lastChild())
- o = o->lastChild();
+ while (RenderObject* lastChild = o->slowLastChild())
+ o = lastChild;
return o;
}
@@ -425,7 +418,7 @@ RenderObject* RenderObject::previousInPreOrder(const RenderObject* stayWithin) c
RenderObject* RenderObject::childAt(unsigned index) const
{
- RenderObject* child = firstChild();
+ RenderObject* child = slowFirstChild();
for (unsigned i = 0; child && i < index; i++)
child = child->nextSibling();
return child;
@@ -433,10 +426,10 @@ RenderObject* RenderObject::childAt(unsigned index) const
RenderObject* RenderObject::lastLeafChild() const
{
- RenderObject* r = lastChild();
+ RenderObject* r = slowLastChild();
while (r) {
RenderObject* n = 0;
- n = r->lastChild();
+ n = r->slowLastChild();
if (!n)
break;
r = n;
@@ -459,7 +452,7 @@ static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*
return;
}
- for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling())
+ for (RenderObject* curr = obj->slowFirstChild(); curr; curr = curr->nextSibling())
addLayers(curr, parentLayer, newObject, beforeChild);
}
@@ -483,7 +476,7 @@ void RenderObject::removeLayers(RenderLayer* parentLayer)
return;
}
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
curr->removeLayers(parentLayer);
}
@@ -501,7 +494,7 @@ void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
return;
}
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
curr->moveLayers(oldParent, newParent);
}
@@ -520,7 +513,7 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject*
// 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() : firstChild();
+ for (RenderObject* curr = startPoint ? startPoint->nextSibling() : slowFirstChild();
curr; curr = curr->nextSibling()) {
RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
if (nextLayer)
@@ -543,13 +536,13 @@ RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject*
RenderLayer* RenderObject::enclosingLayer() const
{
- const RenderObject* curr = this;
- while (curr) {
- RenderLayer* layer = curr->hasLayer() ? toRenderLayerModelObject(curr)->layer() : 0;
- if (layer)
- return layer;
- curr = curr->parent();
+ for (const RenderObject* current = this; current; current = current->parent()) {
+ if (current->hasLayer())
+ return toRenderLayerModelObject(current)->layer();
}
+ // FIXME: We should remove the one caller that triggers this case and make
+ // this function return a reference.
+ ASSERT(!m_parent && !isRenderView());
return 0;
}
@@ -622,15 +615,6 @@ RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const
return 0;
}
-RenderNamedFlowThread* RenderObject::renderNamedFlowThreadWrapper() const
-{
- RenderObject* object = const_cast<RenderObject*>(this);
- while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread())
- object = object->parent();
-
- return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0;
-}
-
RenderBlock* RenderObject::firstLineBlock() const
{
return 0;
@@ -729,19 +713,12 @@ void RenderObject::checkBlockPositionedObjectsNeedLayout()
if (isRenderBlock())
toRenderBlock(this)->checkPositionedObjectsNeedLayout();
}
-
-void RenderObject::checkNotInPartialLayout()
-{
- // During partial layout, setNeedsLayout(true or false) should not be called.
- ASSERT(!frameView()->partialLayout().isStopping());
-}
#endif
void RenderObject::setPreferredLogicalWidthsDirty(MarkingBehavior markParents)
{
- bool alreadyDirty = preferredLogicalWidthsDirty();
m_bitfields.setPreferredLogicalWidthsDirty(true);
- if (!alreadyDirty && markParents == MarkContainingBlockChain && (isText() || !style()->hasOutOfFlowPosition()))
+ if (markParents == MarkContainingBlockChain && (isText() || !style()->hasOutOfFlowPosition()))
invalidateContainerPreferredLogicalWidths();
}
@@ -771,28 +748,22 @@ void RenderObject::invalidateContainerPreferredLogicalWidths()
}
}
-void RenderObject::setLayerNeedsFullRepaint()
-{
- ASSERT(hasLayer());
- toRenderLayerModelObject(this)->layer()->repainter().setRepaintStatus(NeedsFullRepaint);
-}
-
-void RenderObject::setLayerNeedsFullRepaintForPositionedMovementLayout()
+void RenderObject::setLayerNeedsFullPaintInvalidationForPositionedMovementLayout()
{
ASSERT(hasLayer());
toRenderLayerModelObject(this)->layer()->repainter().setRepaintStatus(NeedsFullRepaintForPositionedMovementLayout);
}
-RenderBlock* RenderObject::containerForFixedPosition(const RenderLayerModelObject* repaintContainer, bool* repaintContainerSkipped) const
+RenderBlock* RenderObject::containerForFixedPosition(const RenderLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const
{
- ASSERT(!repaintContainerSkipped || !*repaintContainerSkipped);
+ ASSERT(!paintInvalidationContainerSkipped || !*paintInvalidationContainerSkipped);
ASSERT(!isText());
ASSERT(style()->position() == FixedPosition);
RenderObject* ancestor = parent();
for (; ancestor && !ancestor->canContainFixedPositionObjects(); ancestor = ancestor->parent()) {
- if (repaintContainerSkipped && ancestor == repaintContainer)
- *repaintContainerSkipped = true;
+ if (paintInvalidationContainerSkipped && ancestor == paintInvalidationContainer)
+ *paintInvalidationContainerSkipped = true;
}
ASSERT(!ancestor || !ancestor->isAnonymousBlock());
@@ -816,7 +787,7 @@ RenderBlock* RenderObject::containingBlock() const
if (o->style()->position() != StaticPosition && (!o->isInline() || o->isReplaced()))
break;
- if (o->canContainAbsolutePositionObjects())
+ if (o->canContainFixedPositionObjects())
break;
if (o->style()->hasInFlowPosition() && o->isInline() && !o->isReplaced()) {
@@ -827,6 +798,9 @@ RenderBlock* RenderObject::containingBlock() const
o = o->parent();
}
+ if (o && !o->isRenderBlock())
+ o = o->containingBlock();
+
while (o && o->isAnonymousBlock())
o = o->containingBlock();
} else {
@@ -840,29 +814,66 @@ RenderBlock* RenderObject::containingBlock() const
return toRenderBlock(o);
}
-static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* layer)
+RenderObject* RenderObject::clippingContainer() const
+{
+ RenderObject* container = const_cast<RenderObject*>(this);
+ while (container) {
+ if (container->style()->position() == FixedPosition) {
+ for (container = container->parent(); container && !container->canContainFixedPositionObjects(); container = container->parent()) {
+ // CSS clip applies to fixed position elements even for ancestors that are not what the
+ // fixed element is positioned with respect to.
+ if (container->hasClip())
+ return container;
+ }
+ } else {
+ container = container->containingBlock();
+ }
+
+ if (!container)
+ return 0;
+ if (container->hasClipOrOverflowClip())
+ return container;
+ }
+ return 0;
+}
+
+bool RenderObject::canRenderBorderImage() const
+{
+ ASSERT(style()->hasBorder());
+
+ 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())
+ if (layer.next())
return true;
// Make sure we have a valid image.
- StyleImage* img = layer->image();
- if (!img || !img->canRender(renderer, renderer->style()->effectiveZoom()))
+ StyleImage* img = layer.image();
+ if (!img || !img->canRender(*this, style()->effectiveZoom()))
return false;
- if (!layer->xPosition().isZero() || !layer->yPosition().isZero())
+ if (layer.repeatX() != RepeatFill && layer.repeatX() != NoRepeatFill)
return true;
- EFillSizeType sizeType = layer->sizeType();
+ 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().height().isPercent())
+ if (layer.sizeLength().width().isPercent() && !layer.sizeLength().width().isZero())
return true;
- if (img->isGeneratedImage() && (layer->sizeLength().width().isAuto() || layer->sizeLength().height().isAuto()))
+ if (img->isGeneratedImage() && layer.sizeLength().width().isAuto())
return true;
} else if (img->usesImageContainerSize()) {
return true;
@@ -871,28 +882,76 @@ static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer*
return false;
}
-bool RenderObject::borderImageIsLoadedAndCanBeRendered() const
+bool RenderObject::mustInvalidateFillLayersPaintOnHeightChange(const FillLayer& layer) const
{
- ASSERT(style()->hasBorder());
+ // Nobody will use multiple layers without wanting fancy positioning.
+ if (layer.next())
+ return true;
- StyleImage* borderImage = style()->borderImage().image();
- return borderImage && borderImage->canRender(this, style()->effectiveZoom()) && borderImage->isLoaded();
+ // 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::mustRepaintBackgroundOrBorder() const
+bool RenderObject::mustInvalidateBackgroundOrBorderPaintOnWidthChange() const
{
- if (hasMask() && mustRepaintFillLayers(this, style()->maskLayers()))
+ if (hasMask() && mustInvalidateFillLayersPaintOnWidthChange(*style()->maskLayers()))
return true;
// If we don't have a background/border/mask, then nothing to do.
if (!hasBoxDecorations())
return false;
- if (mustRepaintFillLayers(this, style()->backgroundLayers()))
+ 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 (!hasBoxDecorations())
+ return false;
+
+ if (mustInvalidateFillLayersPaintOnHeightChange(*style()->backgroundLayers()))
return true;
// Our fill layers are ok. Let's check border.
- if (style()->hasBorder() && borderImageIsLoadedAndCanBeRendered())
+ if (style()->hasBorder() && canRenderBorderImage())
return true;
return false;
@@ -1250,22 +1309,62 @@ void RenderObject::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRec
graphicsContext->endLayer();
}
-IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const
+void RenderObject::addChildFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
{
- if (useTransforms) {
- Vector<FloatQuad> quads;
- absoluteQuads(quads);
-
- size_t n = quads.size();
- if (!n)
- return IntRect();
+ for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling()) {
+ if (current->isText() || current->isListMarker())
+ continue;
- IntRect result = quads[0].enclosingBoundingBox();
- for (size_t i = 1; i < n; ++i)
- result.unite(quads[i].enclosingBoundingBox());
- return result;
+ if (current->isBox()) {
+ RenderBox* box = toRenderBox(current);
+ if (box->hasLayer()) {
+ Vector<IntRect> layerFocusRingRects;
+ box->addFocusRingRects(layerFocusRingRects, LayoutPoint(), box);
+ for (size_t i = 0; i < layerFocusRingRects.size(); ++i) {
+ FloatQuad quadInBox = box->localToContainerQuad(FloatRect(layerFocusRingRects[i]), paintContainer);
+ rects.append(pixelSnappedIntRect(LayoutRect(quadInBox.boundingBox())));
+ }
+ } else {
+ FloatPoint pos(additionalOffset);
+ pos.move(box->locationOffset()); // FIXME: Snap offsets? crbug.com/350474
+ box->addFocusRingRects(rects, flooredIntPoint(pos), paintContainer);
+ }
+ } else {
+ current->addFocusRingRects(rects, additionalOffset, paintContainer);
+ }
}
+}
+
+// FIXME: In repaint-after-layout, we should be able to change the logic to remove the need for this function. See crbug.com/368416.
+LayoutPoint RenderObject::positionFromPaintInvalidationContainer(const RenderLayerModelObject* paintInvalidationContainer) const
+{
+ // FIXME: This assert should be re-enabled when we move paint invalidation to after compositing update. crbug.com/360286
+ // ASSERT(containerForPaintInvalidation() == paintInvalidationContainer);
+
+ LayoutPoint offset = isBox() ? toRenderBox(this)->location() : LayoutPoint();
+ if (paintInvalidationContainer == this)
+ return offset;
+
+ return roundedIntPoint(localToContainerPoint(offset, paintInvalidationContainer));
+}
+
+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));
@@ -1283,18 +1382,11 @@ IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const
void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
{
Vector<IntRect> rects;
- // FIXME: addFocusRingRects() needs to be passed this transform-unaware
- // localToAbsolute() offset here because RenderInline::addFocusRingRects()
- // implicitly assumes that. This doesn't work correctly with transformed
- // descendants.
- FloatPoint absolutePoint = localToAbsolute();
- addFocusRingRects(rects, flooredLayoutPoint(absolutePoint));
+ const RenderLayerModelObject* container = containerForPaintInvalidation();
+ addFocusRingRects(rects, LayoutPoint(localToContainerPoint(FloatPoint(), container)), container);
size_t count = rects.size();
- for (size_t i = 0; i < count; ++i) {
- IntRect rect = rects[i];
- rect.move(-absolutePoint.x(), -absolutePoint.y());
- quads.append(localToAbsoluteQuad(FloatQuad(rect)));
- }
+ for (size_t i = 0; i < count; ++i)
+ quads.append(container->localToAbsoluteQuad(FloatQuad(rects[i])));
}
FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range)
@@ -1317,16 +1409,16 @@ FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range)
void RenderObject::addAbsoluteRectForLayer(LayoutRect& result)
{
if (hasLayer())
- result.unite(absoluteBoundingBoxRectIgnoringTransforms());
- for (RenderObject* current = firstChild(); current; current = current->nextSibling())
+ result.unite(absoluteBoundingBoxRect());
+ for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling())
current->addAbsoluteRectForLayer(result);
}
LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect)
{
- LayoutRect result = absoluteBoundingBoxRectIgnoringTransforms();
+ LayoutRect result = absoluteBoundingBoxRect();
topLevelRect = result;
- for (RenderObject* current = firstChild(); current; current = current->nextSibling())
+ for (RenderObject* current = slowFirstChild(); current; current = current->nextSibling())
current->addAbsoluteRectForLayer(result);
return result;
}
@@ -1335,145 +1427,157 @@ void RenderObject::paint(PaintInfo&, const LayoutPoint&)
{
}
-RenderLayerModelObject* RenderObject::containerForRepaint() const
+const RenderLayerModelObject* RenderObject::containerForPaintInvalidation() const
{
- RenderView* v = view();
- if (!v)
+ if (!isRooted())
return 0;
- RenderLayerModelObject* repaintContainer = 0;
+ return adjustCompositedContainerForSpecialAncestors(enclosingCompositedContainer());
+}
- if (v->usesCompositing()) {
- if (RenderLayer* parentLayer = enclosingLayer()) {
- RenderLayer* compLayer = parentLayer->enclosingCompositingLayerForRepaint();
- if (compLayer)
- repaintContainer = compLayer->renderer();
- }
+const RenderLayerModelObject* RenderObject::enclosingCompositedContainer() const
+{
+ RenderLayerModelObject* container = 0;
+ if (view()->usesCompositing()) {
+ // FIXME: CompositingState is not necessarily up to date for many callers of this function.
+ DisableCompositingQueryAsserts disabler;
+
+ if (RenderLayer* compositingLayer = enclosingLayer()->enclosingCompositingLayerForRepaint())
+ container = compositingLayer->renderer();
}
+ return container;
+}
+
+const RenderLayerModelObject* RenderObject::adjustCompositedContainerForSpecialAncestors(const RenderLayerModelObject* paintInvalidationContainer) const
+{
if (document().view()->hasSoftwareFilters()) {
- if (RenderLayer* parentLayer = enclosingLayer()) {
- RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer();
- if (enclosingFilterLayer)
- return enclosingFilterLayer->renderer();
- }
+ if (RenderLayer* enclosingFilterLayer = enclosingLayer()->enclosingFilterLayer())
+ return enclosingFilterLayer->renderer();
}
- // If we have a flow thread, then we need to do individual repaints within the RenderRegions instead.
- // Return the flow thread as a repaint container in order to create a chokepoint that allows us to change
- // repainting to do individual region repaints.
- RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock();
- if (parentRenderFlowThread) {
- // The ancestor document will do the reparenting when the repaint propagates further up.
- // We're just a seamless child document, and we don't need to do the hacking.
- if (parentRenderFlowThread->document() != document())
- return repaintContainer;
- // If we have already found a repaint container then we will repaint into that container only if it is part of the same
- // flow thread. Otherwise we will need to catch the repaint call and send it to the flow thread.
- RenderFlowThread* repaintContainerFlowThread = repaintContainer ? repaintContainer->flowThreadContainingBlock() : 0;
- if (!repaintContainerFlowThread || repaintContainerFlowThread != parentRenderFlowThread)
- repaintContainer = parentRenderFlowThread;
+ // If we have a flow thread, then we need to do individual paint invalidations within the RenderRegions instead.
+ // Return the flow thread as a paint invalidation container in order to create a chokepoint that allows us to change
+ // paint invalidation to do individual region paint invalidations.
+ if (RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock()) {
+ // If we have already found a paint invalidation container then we will invalidate paints in that container only if it is part of the same
+ // flow thread. Otherwise we will need to catch the paint invalidation call and send it to the flow thread.
+ if (!paintInvalidationContainer || paintInvalidationContainer->flowThreadContainingBlock() != parentRenderFlowThread)
+ paintInvalidationContainer = parentRenderFlowThread;
}
- return repaintContainer;
+ return paintInvalidationContainer ? paintInvalidationContainer : view();
}
-void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintContainer, const IntRect& r) const
+bool RenderObject::isPaintInvalidationContainer() const
{
- if (!repaintContainer) {
- view()->repaintViewRectangle(r);
- return;
- }
+ return hasLayer() && toRenderLayerModelObject(this)->layer()->isRepaintContainer();
+}
- if (repaintContainer->compositingState() == PaintsIntoGroupedBacking) {
- ASSERT(repaintContainer->groupedMapping());
+template<typename T> PassRefPtr<JSONValue> jsonObjectForRect(const T& rect)
+{
+ RefPtr<JSONObject> object = JSONObject::create();
+ object->setNumber("x", rect.x());
+ object->setNumber("y", rect.y());
+ object->setNumber("width", rect.width());
+ object->setNumber("height", rect.height());
+ return object.release();
+}
- // Not clean, but if squashing layer does not yet exist here (e.g. repaint invalidation coming from within recomputing compositing requirements)
- // then it's ok to just exit here, since the squashing layer will get repainted when it is newly created.
- if (!repaintContainer->groupedMapping()->squashingLayer())
- return;
+static PassRefPtr<JSONValue> jsonObjectForPaintInvalidationInfo(const IntRect& rect, const String& invalidationReason)
+{
+ RefPtr<JSONObject> object = JSONObject::create();
+ object->setValue("rect", jsonObjectForRect(rect));
+ object->setString("invalidation_reason", invalidationReason);
+ return object.release();
+}
+LayoutRect RenderObject::computePaintInvalidationRect(const RenderLayerModelObject* paintInvalidationContainer) const
+{
+ return clippedOverflowRectForPaintInvalidation(paintInvalidationContainer);
+}
- IntRect offsetRect(r);
+void RenderObject::invalidatePaintUsingContainer(const RenderLayerModelObject* paintInvalidationContainer, const IntRect& r, InvalidationReason invalidationReason) const
+{
+ if (r.isEmpty())
+ return;
- // First, convert the repaint rect into the space of the repaintContainer
- TransformState transformState(TransformState::ApplyTransformDirection, FloatQuad(FloatRect(r)));
- mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip);
- transformState.flatten();
- offsetRect = transformState.lastPlanarQuad().enclosingBoundingBox();
+ // FIXME: This should be an assert, but editing/selection can trigger this case to invalidate
+ // the selection. crbug.com/368140.
+ if (!isRooted())
+ return;
- // FIXME: the repaint rect computed below could be tighter in uncommon nested transform cases, if we passed the quad
- // directly to the next chunk of code.
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintUsingContainer()",
+ "object", this->debugName().ascii(),
+ "info", TracedValue::fromJSONValue(jsonObjectForPaintInvalidationInfo(r, invalidationReasonToString(invalidationReason))));
- // Then, convert the repaint rect from repaintConainer space into the squashing GraphicsLayer's coordinates.
- if (repaintContainer->hasTransform())
- offsetRect = repaintContainer->layer()->transform()->mapRect(r);
- offsetRect.move(-repaintContainer->layer()->offsetFromSquashingLayerOrigin());
- repaintContainer->groupedMapping()->squashingLayer()->setNeedsDisplayInRect(offsetRect);
- return;
- }
+ // For querying RenderLayer::compositingState()
+ DisableCompositingQueryAsserts disabler;
- if (repaintContainer->isRenderFlowThread()) {
- toRenderFlowThread(repaintContainer)->repaintRectangleInRegions(r);
+ if (paintInvalidationContainer->isRenderFlowThread()) {
+ toRenderFlowThread(paintInvalidationContainer)->repaintRectangleInRegions(r);
return;
}
- if (repaintContainer->hasFilter() && repaintContainer->layer()->requiresFullLayerImageForFilters()) {
- repaintContainer->layer()->repainter().setFilterBackendNeedsRepaintingInRect(r);
+ if (paintInvalidationContainer->hasFilter() && paintInvalidationContainer->layer()->requiresFullLayerImageForFilters()) {
+ paintInvalidationContainer->layer()->repainter().setFilterBackendNeedsRepaintingInRect(r);
return;
}
RenderView* v = view();
- if (repaintContainer->isRenderView()) {
- ASSERT(repaintContainer == v);
- bool viewHasCompositedLayer = v->hasLayer() && v->layer()->compositingState() == PaintsIntoOwnBacking;
- if (!viewHasCompositedLayer) {
- IntRect repaintRectangle = r;
- if (viewHasCompositedLayer && v->layer()->transform())
- repaintRectangle = v->layer()->transform()->mapRect(r);
- v->repaintViewRectangle(repaintRectangle);
- return;
- }
+ if (paintInvalidationContainer->isRenderView()) {
+ ASSERT(paintInvalidationContainer == v);
+ v->repaintViewRectangle(r);
+ return;
}
if (v->usesCompositing()) {
- ASSERT(repaintContainer->hasLayer() && repaintContainer->layer()->compositingState() == PaintsIntoOwnBacking);
- repaintContainer->layer()->repainter().setBackingNeedsRepaintInRect(r);
+ ASSERT(paintInvalidationContainer->hasLayer() && (paintInvalidationContainer->layer()->compositingState() == PaintsIntoOwnBacking || paintInvalidationContainer->layer()->compositingState() == PaintsIntoGroupedBacking));
+ paintInvalidationContainer->layer()->repainter().setBackingNeedsRepaintInRect(r);
}
}
-void RenderObject::repaint() const
+void RenderObject::paintInvalidationForWholeRenderer() const
{
- // Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
- RenderView* view;
- if (!isRooted(&view))
+ if (!isRooted())
return;
- if (view->document().printing())
- return; // Don't repaint if we're printing.
+ if (view()->document().printing())
+ return; // Don't invalidate paints if we're printing.
- RenderLayerModelObject* repaintContainer = containerForRepaint();
- repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(clippedOverflowRectForRepaint(repaintContainer)));
+ // FIXME: really, we're in the paint invalidation phase here, and the following queries are legal.
+ // Until those states are fully fledged, I'll just disable the ASSERTS.
+ DisableCompositingQueryAsserts disabler;
+ const RenderLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation();
+ LayoutRect paintInvalidationRect = boundsRectForPaintInvalidation(paintInvalidationContainer);
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(paintInvalidationRect), InvalidationPaint);
}
-void RenderObject::repaintRectangle(const LayoutRect& r) const
+LayoutRect RenderObject::boundsRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer) const
{
- // Don't repaint if we're unrooted (note that view() still returns the view when unrooted)
- RenderView* view;
- if (!isRooted(&view))
+ if (!paintInvalidationContainer)
+ return computePaintInvalidationRect(paintInvalidationContainer);
+ return RenderLayer::computeRepaintRect(this, paintInvalidationContainer->layer());
+}
+
+void RenderObject::invalidatePaintRectangle(const LayoutRect& r) const
+{
+ if (!isRooted())
return;
- if (view->document().printing())
- return; // Don't repaint if we're printing.
+ if (view()->document().printing())
+ return; // Don't invalidate paints if we're printing.
LayoutRect dirtyRect(r);
- // FIXME: layoutDelta needs to be applied in parts before/after transforms and
- // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
- dirtyRect.move(view->layoutDelta());
+ if (!RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
+ // FIXME: layoutDelta needs to be applied in parts before/after transforms and
+ // paint invalidation containers. https://bugs.webkit.org/show_bug.cgi?id=23308
+ dirtyRect.move(view()->layoutDelta());
+ }
- RenderLayerModelObject* repaintContainer = containerForRepaint();
- computeRectForRepaint(repaintContainer, dirtyRect);
- repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(dirtyRect));
+ const RenderLayerModelObject* paintInvalidationContainer = containerForPaintInvalidation();
+ RenderLayer::mapRectToRepaintBacking(this, paintInvalidationContainer, dirtyRect);
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(dirtyRect), InvalidationPaintRectangle);
}
IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const
@@ -1481,84 +1585,165 @@ IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const
return pixelSnappedIntRect(absoluteClippedOverflowRect());
}
-bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, bool wasSelfLayout,
- const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox,
- const LayoutRect* newBoundsPtr, const LayoutRect* newOutlineBoxRectPtr)
+const char* RenderObject::invalidationReasonToString(InvalidationReason reason) const
+{
+ switch (reason) {
+ case InvalidationIncremental:
+ return "incremental";
+ case InvalidationSelfLayout:
+ return "self layout";
+ case InvalidationBorderFitLines:
+ return "border fit lines";
+ case InvalidationBorderRadius:
+ return "border radius";
+ case InvalidationBoundsChangeWithBackground:
+ return "bounds change with background";
+ case InvalidationBoundsChange:
+ return "bounds change";
+ case InvalidationLocationChange:
+ return "location change";
+ case InvalidationScroll:
+ return "scroll";
+ case InvalidationSelection:
+ return "selection";
+ case InvalidationLayer:
+ return "layer";
+ case InvalidationPaint:
+ return "invalidate paint";
+ case InvalidationPaintRectangle:
+ return "invalidate paint rectangle";
+ }
+ ASSERT_NOT_REACHED();
+ return "";
+}
+
+void RenderObject::invalidateTreeAfterLayout(const RenderLayerModelObject& paintInvalidationContainer)
+{
+ // 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 (!shouldCheckForPaintInvalidationAfterLayout())
+ return;
+
+ clearPaintInvalidationState();
+
+ for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
+ if (!child->isOutOfFlowPositioned())
+ child->invalidateTreeAfterLayout(paintInvalidationContainer);
+ }
+}
+
+static PassRefPtr<JSONValue> jsonObjectForOldAndNewRects(const LayoutRect& oldRect, const LayoutRect& newRect)
+{
+ RefPtr<JSONObject> object = JSONObject::create();
+
+ object->setValue("old", jsonObjectForRect(oldRect));
+ object->setValue("new", jsonObjectForRect(newRect));
+ return object.release();
+}
+
+bool RenderObject::invalidatePaintAfterLayoutIfNeeded(const RenderLayerModelObject* paintInvalidationContainer, bool wasSelfLayout,
+ const LayoutRect& oldBounds, const LayoutPoint& oldLocation, const LayoutRect* newBoundsPtr, const LayoutPoint* newLocationPtr)
{
RenderView* v = view();
if (v->document().printing())
- return false; // Don't repaint if we're printing.
+ return false; // Don't invalidate paints if we're printing.
// This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048
- // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer));
- LayoutRect newBounds = newBoundsPtr ? *newBoundsPtr : clippedOverflowRectForRepaint(repaintContainer);
- LayoutRect newOutlineBox;
+ // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForPaintInvalidation(paintInvalidationContainer));
+ LayoutRect newBounds = newBoundsPtr ? *newBoundsPtr : computePaintInvalidationRect();
+ LayoutPoint newLocation = newLocationPtr ? (*newLocationPtr) : RenderLayer::positionFromPaintInvalidationContainer(this, paintInvalidationContainer);
+
+ // FIXME: This should use a ConvertableToTraceFormat when they are available in Blink.
+ TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("blink.invalidation"), "RenderObject::invalidatePaintAfterLayoutIfNeeded()",
+ "object", this->debugName().ascii(),
+ "info", TracedValue::fromJSONValue(jsonObjectForOldAndNewRects(oldBounds, newBounds)));
+
+ InvalidationReason invalidationReason = wasSelfLayout ? InvalidationSelfLayout : InvalidationIncremental;
- bool fullRepaint = wasSelfLayout;
// Presumably a background or a border exists if border-fit:lines was specified.
- if (!fullRepaint && style()->borderFit() == BorderFitLines)
- fullRepaint = true;
- if (!fullRepaint && style()->hasBorderRadius()) {
+ if (invalidationReason == InvalidationIncremental && style()->borderFit() == BorderFitLines)
+ invalidationReason = InvalidationBorderFitLines;
+
+ if (invalidationReason == InvalidationIncremental && style()->hasBorderRadius()) {
// If a border-radius exists and width/height is smaller than
- // radius width/height, we cannot use delta-repaint.
- RoundedRect oldRoundedRect = style()->getRoundedBorderFor(oldBounds, v);
- RoundedRect newRoundedRect = style()->getRoundedBorderFor(newBounds, v);
- fullRepaint = oldRoundedRect.radii() != newRoundedRect.radii();
+ // radius width/height, we cannot use delta-paint-invalidation.
+ RoundedRect oldRoundedRect = style()->getRoundedBorderFor(oldBounds);
+ RoundedRect newRoundedRect = style()->getRoundedBorderFor(newBounds);
+ if (oldRoundedRect.radii() != newRoundedRect.radii())
+ invalidationReason = InvalidationBorderRadius;
}
- if (!fullRepaint) {
- // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048
- // ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer));
- newOutlineBox = newOutlineBoxRectPtr ? *newOutlineBoxRectPtr : outlineBoundsForRepaint(repaintContainer);
- if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox)))
- fullRepaint = true;
+
+ if (invalidationReason == InvalidationIncremental && compositingState() != PaintsIntoOwnBacking && newLocation != oldLocation)
+ invalidationReason = InvalidationLocationChange;
+
+ // 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 (invalidationReason == InvalidationIncremental && oldBounds == newBounds)
+ return false;
+
+ if (invalidationReason == InvalidationIncremental) {
+ if (oldBounds.width() != newBounds.width() && mustInvalidateBackgroundOrBorderPaintOnWidthChange())
+ invalidationReason = InvalidationBoundsChangeWithBackground;
+ else if (oldBounds.height() != newBounds.height() && mustInvalidateBackgroundOrBorderPaintOnHeightChange())
+ invalidationReason = InvalidationBoundsChangeWithBackground;
}
- if (!repaintContainer)
- repaintContainer = v;
+ // 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 (invalidationReason == InvalidationIncremental && newBounds.location() != oldBounds.location())
+ invalidationReason = InvalidationBoundsChange;
+
+ // 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 (invalidationReason == InvalidationIncremental && (oldBounds.size().isZero() || newBounds.size().isZero()))
+ invalidationReason = InvalidationBoundsChange;
+
+ ASSERT(paintInvalidationContainer);
- if (fullRepaint) {
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds));
+ if (invalidationReason != InvalidationIncremental) {
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds), invalidationReason);
if (newBounds != oldBounds)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds), invalidationReason);
return true;
}
- if (newBounds == oldBounds && newOutlineBox == oldOutlineBox)
- return false;
-
LayoutUnit deltaLeft = newBounds.x() - oldBounds.x();
if (deltaLeft > 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height()));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height()), invalidationReason);
else if (deltaLeft < 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height()));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height()), invalidationReason);
LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX();
if (deltaRight > 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height()));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height()), invalidationReason);
else if (deltaRight < 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height()));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height()), invalidationReason);
LayoutUnit deltaTop = newBounds.y() - oldBounds.y();
if (deltaTop > 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop), invalidationReason);
else if (deltaTop < 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop), invalidationReason);
LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY();
if (deltaBottom > 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom), invalidationReason);
else if (deltaBottom < 0)
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom), invalidationReason);
- if (newOutlineBox == oldOutlineBox)
+ // FIXME: This is a limitation of our visual overflow being a single rectangle.
+ if (!style()->boxShadow() && !style()->hasBorderImageOutsets() && !style()->hasOutline())
return false;
// We didn't move, but we did change size. Invalidate the delta, which will consist of possibly
// two rectangles (but typically only one).
- RenderStyle* outlineStyle = outlineStyleForRepaint();
+ RenderStyle* outlineStyle = outlineStyleForPaintInvalidation();
LayoutUnit outlineWidth = outlineStyle->outlineSize();
LayoutBoxExtent insetShadowExtent = style()->getBoxShadowInsetExtent();
- LayoutUnit width = absoluteValue(newOutlineBox.width() - oldOutlineBox.width());
+ LayoutUnit width = absoluteValue(newBounds.width() - oldBounds.width());
if (width) {
LayoutUnit shadowLeft;
LayoutUnit shadowRight;
@@ -1566,19 +1751,20 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repa
int borderRight = isBox() ? toRenderBox(this)->borderRight() : 0;
LayoutUnit boxWidth = isBox() ? toRenderBox(this)->width() : LayoutUnit();
LayoutUnit minInsetRightShadowExtent = min<LayoutUnit>(-insetShadowExtent.right(), min<LayoutUnit>(newBounds.width(), oldBounds.width()));
- LayoutUnit borderWidth = max<LayoutUnit>(borderRight, max<LayoutUnit>(valueForLength(style()->borderTopRightRadius().width(), boxWidth, v), valueForLength(style()->borderBottomRightRadius().width(), boxWidth, v)));
- LayoutUnit decorationsWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderWidth + minInsetRightShadowExtent) + max<LayoutUnit>(outlineWidth, shadowRight);
- LayoutRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - decorationsWidth,
- newOutlineBox.y(),
- width + decorationsWidth,
- max(newOutlineBox.height(), oldOutlineBox.height()));
+ LayoutUnit borderWidth = max<LayoutUnit>(borderRight, max<LayoutUnit>(valueForLength(style()->borderTopRightRadius().width(), boxWidth), valueForLength(style()->borderBottomRightRadius().width(), boxWidth)));
+ LayoutUnit decorationsLeftWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderWidth + minInsetRightShadowExtent) + max<LayoutUnit>(outlineWidth, -shadowLeft);
+ LayoutUnit decorationsRightWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderWidth + minInsetRightShadowExtent) + max<LayoutUnit>(outlineWidth, shadowRight);
+ LayoutRect rightRect(newBounds.x() + min(newBounds.width(), oldBounds.width()) - decorationsLeftWidth,
+ newBounds.y(),
+ width + decorationsLeftWidth + decorationsRightWidth,
+ max(newBounds.height(), oldBounds.height()));
LayoutUnit right = min<LayoutUnit>(newBounds.maxX(), oldBounds.maxX());
if (rightRect.x() < right) {
rightRect.setWidth(min(rightRect.width(), right - rightRect.x()));
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(rightRect));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(rightRect), invalidationReason);
}
}
- LayoutUnit height = absoluteValue(newOutlineBox.height() - oldOutlineBox.height());
+ LayoutUnit height = absoluteValue(newBounds.height() - oldBounds.height());
if (height) {
LayoutUnit shadowTop;
LayoutUnit shadowBottom;
@@ -1586,46 +1772,58 @@ bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repa
int borderBottom = isBox() ? toRenderBox(this)->borderBottom() : 0;
LayoutUnit boxHeight = isBox() ? toRenderBox(this)->height() : LayoutUnit();
LayoutUnit minInsetBottomShadowExtent = min<LayoutUnit>(-insetShadowExtent.bottom(), min<LayoutUnit>(newBounds.height(), oldBounds.height()));
- LayoutUnit borderHeight = max<LayoutUnit>(borderBottom, max<LayoutUnit>(valueForLength(style()->borderBottomLeftRadius().height(), boxHeight, v), valueForLength(style()->borderBottomRightRadius().height(), boxHeight, v)));
- LayoutUnit decorationsHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderHeight + minInsetBottomShadowExtent) + max<LayoutUnit>(outlineWidth, shadowBottom);
- LayoutRect bottomRect(newOutlineBox.x(),
- min(newOutlineBox.maxY(), oldOutlineBox.maxY()) - decorationsHeight,
- max(newOutlineBox.width(), oldOutlineBox.width()),
- height + decorationsHeight);
+ LayoutUnit borderHeight = max<LayoutUnit>(borderBottom, max<LayoutUnit>(valueForLength(style()->borderBottomLeftRadius().height(), boxHeight), valueForLength(style()->borderBottomRightRadius().height(), boxHeight)));
+ LayoutUnit decorationsTopHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderHeight + minInsetBottomShadowExtent) + max<LayoutUnit>(outlineWidth, -shadowTop);
+ LayoutUnit decorationsBottomHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderHeight + minInsetBottomShadowExtent) + max<LayoutUnit>(outlineWidth, shadowBottom);
+ LayoutRect bottomRect(newBounds.x(),
+ min(newBounds.maxY(), oldBounds.maxY()) - decorationsTopHeight,
+ max(newBounds.width(), oldBounds.width()),
+ height + decorationsTopHeight + decorationsBottomHeight);
LayoutUnit bottom = min(newBounds.maxY(), oldBounds.maxY());
if (bottomRect.y() < bottom) {
bottomRect.setHeight(min(bottomRect.height(), bottom - bottomRect.y()));
- repaintUsingContainer(repaintContainer, pixelSnappedIntRect(bottomRect));
+ invalidatePaintUsingContainer(paintInvalidationContainer, pixelSnappedIntRect(bottomRect), invalidationReason);
}
}
return false;
}
-void RenderObject::repaintOverflow()
+void RenderObject::invalidatePaintForOverflow()
+{
+}
+
+void RenderObject::invalidatePaintForOverflowIfNeeded()
+{
+ if (shouldInvalidateOverflowForPaint())
+ invalidatePaintForOverflow();
+}
+
+bool RenderObject::checkForPaintInvalidation() const
{
+ return !document().view()->needsFullPaintInvalidation() && everHadLayout();
}
-bool RenderObject::checkForRepaintDuringLayout() const
+bool RenderObject::checkForPaintInvalidationDuringLayout() const
{
- return !document().view()->needsFullRepaint() && !hasLayer() && everHadLayout();
+ return !RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && checkForPaintInvalidation();
}
-LayoutRect RenderObject::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
+LayoutRect RenderObject::rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth) const
{
- LayoutRect r(clippedOverflowRectForRepaint(repaintContainer));
+ LayoutRect r(clippedOverflowRectForPaintInvalidation(paintInvalidationContainer));
r.inflate(outlineWidth);
return r;
}
-LayoutRect RenderObject::clippedOverflowRectForRepaint(const RenderLayerModelObject*) const
+LayoutRect RenderObject::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*) const
{
ASSERT_NOT_REACHED();
return LayoutRect();
}
-void RenderObject::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
+void RenderObject::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, bool fixed) const
{
- if (repaintContainer == this)
+ if (paintInvalidationContainer == this)
return;
if (RenderObject* o = parent()) {
@@ -1642,11 +1840,11 @@ void RenderObject::computeRectForRepaint(const RenderLayerModelObject* repaintCo
return;
}
- o->computeRectForRepaint(repaintContainer, rect, fixed);
+ o->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, fixed);
}
}
-void RenderObject::computeFloatRectForRepaint(const RenderLayerModelObject*, FloatRect&, bool) const
+void RenderObject::computeFloatRectForPaintInvalidation(const RenderLayerModelObject*, FloatRect&, bool) const
{
ASSERT_NOT_REACHED();
}
@@ -1714,7 +1912,7 @@ void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, cons
if (!this)
return;
- for (const RenderObject* child = firstChild(); child; child = child->nextSibling())
+ for (const RenderObject* child = slowFirstChild(); child; child = child->nextSibling())
child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1);
}
@@ -1727,19 +1925,14 @@ bool RenderObject::isSelectable() const
Color RenderObject::selectionBackgroundColor() const
{
- Color backgroundColor;
- if (isSelectable()) {
- RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
- if (pseudoStyle && resolveColor(pseudoStyle.get(), CSSPropertyBackgroundColor).isValid()) {
- backgroundColor = resolveColor(pseudoStyle.get(), CSSPropertyBackgroundColor).blendWithWhite();
- } else {
- backgroundColor = frame()->selection().isFocusedAndActive() ?
- RenderTheme::theme().activeSelectionBackgroundColor() :
- RenderTheme::theme().inactiveSelectionBackgroundColor();
- }
- }
+ if (!isSelectable())
+ return Color::transparent;
- return backgroundColor;
+ if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost())
+ return resolveColor(pseudoStyle.get(), CSSPropertyBackgroundColor).blendWithWhite();
+ return frame()->selection().isFocusedAndActive() ?
+ RenderTheme::theme().activeSelectionBackgroundColor() :
+ RenderTheme::theme().inactiveSelectionBackgroundColor();
}
Color RenderObject::selectionColor(int colorProperty) const
@@ -1747,19 +1940,15 @@ 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 Color::transparent;
+ return resolveColor(colorProperty);
- Color color;
- if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION))) {
- Color selectionColor = resolveColor(pseudoStyle.get(), colorProperty);
- color = selectionColor.isValid() ? selectionColor : resolveColor(pseudoStyle.get(), CSSPropertyColor);
- } else {
- color = frame()->selection().isFocusedAndActive() ?
- RenderTheme::theme().activeSelectionForegroundColor() :
- RenderTheme::theme().inactiveSelectionForegroundColor();
- }
-
- return color;
+ if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyleFromParentOrShadowHost())
+ return resolveColor(pseudoStyle.get(), colorProperty);
+ if (!RenderTheme::theme().supportsSelectionForegroundColors())
+ return resolveColor(colorProperty);
+ return frame()->selection().isFocusedAndActive() ?
+ RenderTheme::theme().activeSelectionForegroundColor() :
+ RenderTheme::theme().inactiveSelectionForegroundColor();
}
Color RenderObject::selectionForegroundColor() const
@@ -1796,65 +1985,57 @@ void RenderObject::handleDynamicFloatPositionChange()
}
}
-void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style)
-{
- if (!isText() && style && !RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
- setStyle(animation().updateAnimations(*this, *style));
- return;
- }
- setStyle(style);
-}
-
StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsigned contextSensitiveProperties) const
{
- // If transform changed, and the layer does not paint into its own separate backing, then we need to do a layout.
- // FIXME: The comment above is what the code does, but it is technically not following spec. This means we will
- // not to layout for 3d transforms, but we should be invoking a simplified relayout. Is it possible we are avoiding
- // doing this for some performance reason at this time?
+ if (contextSensitiveProperties & ContextSensitivePropertyTransform && isSVG())
+ diff.setNeedsFullLayout();
+
+ // If transform changed, and the layer does not paint into its own separate backing, then we need to invalidate paints.
if (contextSensitiveProperties & ContextSensitivePropertyTransform) {
// Text nodes share style with their parents but transforms don't apply to them,
// hence the !isText() check.
- // FIXME: when transforms are taken into account for overflow, we will need to do a layout.
- if (!isText() && (!hasLayer() || toRenderLayerModelObject(this)->layer()->compositingState() != PaintsIntoOwnBacking)) {
- // We need to set at least SimplifiedLayout, but if PositionedMovementOnly is already set
- // then we actually need SimplifiedLayoutAndPositionedMovement.
- if (!hasLayer())
- diff = StyleDifferenceLayout; // FIXME: Do this for now since SimplifiedLayout cannot handle updating floating objects lists.
- else if (diff < StyleDifferenceLayoutPositionedMovementOnly)
- diff = StyleDifferenceSimplifiedLayout;
- else if (diff < StyleDifferenceSimplifiedLayout)
- diff = StyleDifferenceSimplifiedLayoutAndPositionedMovement;
- } else if (diff < StyleDifferenceRecompositeLayer)
- diff = StyleDifferenceRecompositeLayer;
- }
-
- // If opacity or filters changed, and the layer does not paint into its own separate backing, then we need to repaint (also
+ if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->styleDeterminedCompositingReasons()))
+ diff.setNeedsRepaintLayer();
+ else
+ diff.setNeedsRecompositeLayer();
+ }
+
+ // 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 (contextSensitiveProperties & ContextSensitivePropertyOpacity && diff <= StyleDifferenceRepaintLayer) {
- if (!isText() && (!hasLayer() || toRenderLayerModelObject(this)->layer()->compositingState() != PaintsIntoOwnBacking))
- diff = StyleDifferenceRepaintLayer;
- else if (diff < StyleDifferenceRecompositeLayer)
- diff = StyleDifferenceRecompositeLayer;
+ if (contextSensitiveProperties & (ContextSensitivePropertyOpacity | ContextSensitivePropertyZIndex)) {
+ if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->styleDeterminedCompositingReasons()))
+ diff.setNeedsRepaintLayer();
+ else
+ diff.setNeedsRecompositeLayer();
}
- if ((contextSensitiveProperties & ContextSensitivePropertyFilter) && hasLayer() && diff <= StyleDifferenceRepaintLayer) {
+
+ // 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 ((contextSensitiveProperties & ContextSensitivePropertyFilter) && hasLayer()) {
RenderLayer* layer = toRenderLayerModelObject(this)->layer();
- if (layer->compositingState() != PaintsIntoOwnBacking || layer->paintsWithFilters())
- diff = StyleDifferenceRepaintLayer;
- else if (diff < StyleDifferenceRecompositeLayer)
- diff = StyleDifferenceRecompositeLayer;
+ if (!layer->styleDeterminedCompositingReasons() || layer->paintsWithFilters())
+ diff.setNeedsRepaintLayer();
+ else
+ diff.setNeedsRecompositeLayer();
}
- // The answer to requiresLayer() for plugins, iframes, and canvas can change without the actual
+ if ((contextSensitiveProperties & ContextSensitivePropertyTextOrColor) && !diff.needsRepaint()
+ && hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor())
+ diff.setNeedsRepaintObject();
+
+ // 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 == StyleDifferenceEqual && style() && isLayerModelObject()) {
- if (hasLayer() != toRenderLayerModelObject(this)->requiresLayer())
- diff = StyleDifferenceLayout;
+ if (!diff.needsFullLayout() && style() && isLayerModelObject()) {
+ bool requiresLayer = toRenderLayerModelObject(this)->layerTypeRequired() != NoLayer;
+ if (hasLayer() != requiresLayer)
+ diff.setNeedsFullLayout();
}
- // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
- if (diff == StyleDifferenceRepaintLayer && !hasLayer())
- diff = StyleDifferenceRepaint;
+ // If we have no layer(), just treat a RepaintLayer hint as a normal paint invalidation.
+ if (diff.needsRepaintLayer() && !hasLayer()) {
+ diff.clearNeedsRepaint();
+ diff.setNeedsRepaintObject();
+ }
return diff;
}
@@ -1884,7 +2065,9 @@ void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle)
inline bool RenderObject::hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor() const
{
- for (const RenderObject* r = firstChild(); r; r = r->nextSibling()) {
+ if (style()->hasBorder() || style()->hasOutline())
+ return true;
+ for (const RenderObject* r = slowFirstChild(); r; r = r->nextSibling()) {
if (r->isText() && !toRenderText(r)->isAllCollapsibleWhitespace())
return true;
if (r->style()->hasOutline() || r->style()->hasBorder())
@@ -1893,13 +2076,24 @@ inline bool RenderObject::hasImmediateNonWhitespaceTextChildOrPropertiesDependen
return false;
}
-inline bool RenderObject::shouldRepaintForStyleDifference(StyleDifference diff) const
+void RenderObject::markContainingBlocksForOverflowRecalc()
{
- return diff == StyleDifferenceRepaint || (diff == StyleDifferenceRepaintIfTextOrColorChange && hasImmediateNonWhitespaceTextChildOrPropertiesDependentOnColor());
+ 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.
@@ -1907,14 +2101,14 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
return;
}
- StyleDifference diff = StyleDifferenceEqual;
+ StyleDifference diff;
unsigned contextSensitiveProperties = ContextSensitivePropertyNone;
if (m_style)
- diff = m_style->diff(style.get(), contextSensitiveProperties);
+ diff = m_style->visualInvalidationDiff(*style, contextSensitiveProperties);
diff = adjustStyleDifference(diff, contextSensitiveProperties);
- styleWillChange(diff, style.get());
+ styleWillChange(diff, *style);
RefPtr<RenderStyle> oldStyle = m_style.release();
setStyleInternal(style);
@@ -1925,15 +2119,8 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style ? m_style->borderImage().image() : 0);
updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style ? m_style->maskBoxImage().image() : 0);
- updateShapeImage(oldStyle ? oldStyle->shapeInside() : 0, m_style ? m_style->shapeInside() : 0);
updateShapeImage(oldStyle ? oldStyle->shapeOutside() : 0, m_style ? m_style->shapeOutside() : 0);
- // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen
- // during styleDidChange (it's used by clippedOverflowRectForRepaint()).
- // FIXME: Do this more cleanly. http://crbug.com/273904
- if (m_style->outlineWidth() > 0 && m_style->outlineSize() > view()->maximalOutlineSize())
- view()->setMaximalOutlineSize(m_style->outlineSize());
-
bool doesNotNeedLayout = !m_parent || isText();
styleDidChange(diff, oldStyle.get());
@@ -1946,25 +2133,28 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
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 repaint.
+ // check whether we should layout now, and decide if we need to invalidate paints.
StyleDifference updatedDiff = adjustStyleDifference(diff, contextSensitiveProperties);
- if (diff <= StyleDifferenceLayoutPositionedMovementOnly) {
- if (updatedDiff == StyleDifferenceLayout)
+ if (!diff.needsFullLayout()) {
+ if (updatedDiff.needsFullLayout())
setNeedsLayoutAndPrefWidthsRecalc();
- else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly)
- setNeedsPositionedMovementLayout();
- else if (updatedDiff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
+ else if (updatedDiff.needsPositionedMovementLayout())
setNeedsPositionedMovementLayout();
- setNeedsSimplifiedNormalFlowLayout();
- } else if (updatedDiff == StyleDifferenceSimplifiedLayout)
- setNeedsSimplifiedNormalFlowLayout();
}
- if (updatedDiff == StyleDifferenceRepaintLayer || shouldRepaintForStyleDifference(updatedDiff)) {
- // Do a repaint with the new style now, e.g., for example if we go from
- // not having an outline to having an outline.
- repaint();
+ if (contextSensitiveProperties & ContextSensitivePropertyTransform && !needsLayout()) {
+ if (RenderBlock* container = containingBlock())
+ container->setNeedsOverflowRecalcAfterStyleChange();
+ }
+
+ if (updatedDiff.needsRepaint()) {
+ // Invalidate paints with the new style, e.g., for example if we go from not having
+ // an outline to having an outline.
+ if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && needsLayout())
+ setShouldDoFullPaintInvalidationAfterLayout(true);
+ else if (!selfNeedsLayout())
+ paintInvalidationForWholeRenderer();
}
}
@@ -1973,76 +2163,80 @@ static inline bool rendererHasBackground(const RenderObject* renderer)
return renderer && renderer->hasBackground();
}
-void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
+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.
- if (newStyle) {
- 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());
- }
+ 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()) {
- if (RenderLayer* l = enclosingLayer()) {
- if (newStyle->visibility() == VISIBLE)
- l->setHasVisibleContent();
- else if (l->hasVisibleContent() && (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) {
- l->dirtyVisibleContentStatus();
- if (diff > StyleDifferenceRepaintLayer)
- repaint();
- }
+ // 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 (RenderLayer* layer = enclosingLayer()) {
+ if (newStyle.visibility() == VISIBLE) {
+ layer->setHasVisibleContent();
+ } else if (layer->hasVisibleContent() && (this == layer->renderer() || layer->renderer()->style()->visibility() != VISIBLE)) {
+ layer->dirtyVisibleContentStatus();
+ if (diff.needsLayout())
+ paintInvalidationForWholeRenderer();
}
}
}
- if (m_parent && (newStyle->outlineSize() < m_style->outlineSize() || shouldRepaintForStyleDifference(diff)))
- repaint();
- if (isFloating() && (m_style->floating() != newStyle->floating()))
+ if (m_parent && diff.needsRepaintObject()) {
+ if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled() && (diff.needsLayout() || needsLayout()))
+ setShouldDoFullPaintInvalidationAfterLayout(true);
+ else if (!diff.needsFullLayout() && !selfNeedsLayout())
+ paintInvalidationForWholeRenderer();
+ }
+
+ 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()))
+ 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())
+ && (!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 == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) {
+ if (diff.needsLayout()) {
setFloating(false);
clearPositionedState();
}
- } else
+ } else {
s_affectsParentBlock = false;
+ }
if (view()->frameView()) {
bool shouldBlitOnFixedBackgroundImage = false;
-#if ENABLE(FAST_MOBILE_SCROLLING)
- // 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;
-#endif
-
- bool newStyleSlowScroll = newStyle && !shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage();
+ 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 = isRoot() || (isBody() && !rendererHasBackground(document().documentElement()->renderer()));
+ bool drawsRootBackground = isDocumentElement() || (isBody() && !rendererHasBackground(document().documentElement()->renderer()));
if (drawsRootBackground && !shouldBlitOnFixedBackgroundImage) {
if (view()->compositor()->supportsFixedRootBackgroundCompositing()) {
- if (newStyleSlowScroll && newStyle->hasEntirelyFixedBackground())
+ if (newStyleSlowScroll && newStyle.hasEntirelyFixedBackground())
newStyleSlowScroll = false;
if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground())
@@ -2057,6 +2251,20 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS
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)) {
+ if (newStyle.touchAction() != TouchActionAuto)
+ document().didAddTouchEventHandler(node());
+ else
+ document().didRemoveTouchEventHandler(node());
+ }
}
static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b)
@@ -2078,7 +2286,7 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
if (!m_parent)
return;
- if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
+ if (diff.needsFullLayout()) {
RenderCounter::rendererStyleChanged(*this, oldStyle, m_style.get());
// If the object already needs layout, then setNeedsLayout won't do
@@ -2089,21 +2297,20 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
if (needsLayout() && oldStyle->position() != m_style->position())
markContainingBlocksForLayout();
- if (diff == StyleDifferenceLayout)
+ // Ditto.
+ if (needsOverflowRecalcAfterStyleChange() && oldStyle->position() != m_style->position())
+ markContainingBlocksForOverflowRecalc();
+
+ if (diff.needsFullLayout())
setNeedsLayoutAndPrefWidthsRecalc();
- else
- setNeedsSimplifiedNormalFlowLayout();
- } else if (diff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
- setNeedsPositionedMovementLayout();
- setNeedsSimplifiedNormalFlowLayout();
- } else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
+ } else if (diff.needsPositionedMovementLayout())
setNeedsPositionedMovementLayout();
- // Don't check for repaint here; we need to wait until the layer has been
- // updated by subclasses before we know if we have to repaint (in setStyle()).
+ // 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 (Frame* frame = this->frame())
+ if (LocalFrame* frame = this->frame())
frame->eventHandler().scheduleCursorUpdate();
}
}
@@ -2111,7 +2318,7 @@ void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldSt
void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly)
{
// FIXME: We could save this call when the change only affected non-inherited properties.
- for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
+ for (RenderObject* child = slowFirstChild(); child; child = child->nextSibling()) {
if (!child->isAnonymous() || child->style()->styleType() != NOPSEUDO)
continue;
@@ -2203,9 +2410,9 @@ FloatQuad RenderObject::absoluteToLocalQuad(const FloatQuad& quad, MapCoordinate
return transformState.lastPlanarQuad();
}
-void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
+void RenderObject::mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
{
- if (repaintContainer == this)
+ if (paintInvalidationContainer == this)
return;
RenderObject* o = parent();
@@ -2220,15 +2427,12 @@ void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintCont
mode &= ~ApplyContainerFlip;
}
- LayoutSize columnOffset;
- o->adjustForColumns(columnOffset, roundedLayoutPoint(transformState.mappedPoint()));
- if (!columnOffset.isZero())
- transformState.move(columnOffset);
+ transformState.move(o->columnOffset(roundedLayoutPoint(transformState.mappedPoint())));
if (o->hasOverflowClip())
transformState.move(-toRenderBox(o)->scrolledContentOffset());
- o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
+ o->mapLocalToContainer(paintInvalidationContainer, transformState, mode, wasFixed);
}
const RenderObject* RenderObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
@@ -2269,7 +2473,7 @@ bool RenderObject::shouldUseTransformFromContainer(const RenderObject* container
void RenderObject::getTransformFromContainer(const RenderObject* containerObject, const LayoutSize& offsetInContainer, TransformationMatrix& transform) const
{
transform.makeIdentity();
- transform.translate(offsetInContainer.width(), offsetInContainer.height());
+ transform.translate(offsetInContainer.width().toFloat(), offsetInContainer.height().toFloat());
RenderLayer* layer;
if (hasLayer() && (layer = toRenderLayerModelObject(this)->layer()) && layer->transform())
transform.multiply(layer->currentTransform());
@@ -2288,33 +2492,31 @@ void RenderObject::getTransformFromContainer(const RenderObject* containerObject
}
}
-FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags mode, bool* wasFixed) const
+FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const RenderLayerModelObject* 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(repaintContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
+ mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
transformState.flatten();
return transformState.lastPlanarQuad();
}
-FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags mode, bool* wasFixed) const
+FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const RenderLayerModelObject* paintInvalidationContainer, MapCoordinatesFlags mode, bool* wasFixed) const
{
TransformState transformState(TransformState::ApplyTransformDirection, localPoint);
- mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
+ mapLocalToContainer(paintInvalidationContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed);
transformState.flatten();
return transformState.lastPlanarPoint();
}
-LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
+LayoutSize RenderObject::offsetFromContainer(const RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const
{
ASSERT(o == container());
- LayoutSize offset;
-
- o->adjustForColumns(offset, point);
+ LayoutSize offset = o->columnOffset(point);
if (o->hasOverflowClip())
offset -= toRenderBox(o)->scrolledContentOffset();
@@ -2325,13 +2527,13 @@ LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint&
return offset;
}
-LayoutSize RenderObject::offsetFromAncestorContainer(RenderObject* container) const
+LayoutSize RenderObject::offsetFromAncestorContainer(const RenderObject* container) const
{
LayoutSize offset;
LayoutPoint referencePoint;
const RenderObject* currContainer = this;
do {
- RenderObject* nextContainer = currContainer->container();
+ const RenderObject* nextContainer = currContainer->container();
ASSERT(nextContainer); // This means we reached the top without finding container.
if (!nextContainer)
break;
@@ -2362,21 +2564,15 @@ void RenderObject::computeLayerHitTestRects(LayerHitTestRects& layerRects) const
if (!hasLayer()) {
RenderObject* container = this->container();
- if (container) {
- currentLayer = container->enclosingLayer();
- if (currentLayer && 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());
- }
- } else {
- currentLayer = enclosingLayer();
+ 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());
}
- if (!currentLayer)
- return;
}
this->addLayerHitTestRects(layerRects, currentLayer, layerOffset, LayoutRect());
@@ -2401,12 +2597,15 @@ void RenderObject::addLayerHitTestRects(LayerHitTestRects& layerRects, const Ren
const size_t maxRectsPerLayer = 100;
LayerHitTestRects::iterator iter = layerRects.find(currentLayer);
+ Vector<WebCore::LayoutRect>* iterValue;
if (iter == layerRects.end())
- iter = layerRects.add(currentLayer, Vector<LayoutRect>()).iterator;
+ 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])) {
- iter->value.append(ownRects[i]);
- if (iter->value.size() > maxRectsPerLayer) {
+ 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);
@@ -2428,31 +2627,26 @@ void RenderObject::addLayerHitTestRects(LayerHitTestRects& layerRects, const Ren
// 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 = firstChild(); curr; curr = curr->nextSibling()) {
+ for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling()) {
curr->addLayerHitTestRects(layerRects, currentLayer, layerOffset, newContainerRect);
}
}
}
-bool RenderObject::isRooted(RenderView** view) const
+bool RenderObject::isRooted() const
{
- const RenderObject* o = this;
- while (o->parent())
- o = o->parent();
-
- if (!o->isRenderView())
- return false;
-
- if (view)
- *view = const_cast<RenderView*>(toRenderView(o));
-
- return true;
+ const RenderObject* object = this;
+ while (object->parent() && !object->hasLayer())
+ object = object->parent();
+ if (object->hasLayer())
+ return toRenderLayerModelObject(object)->layer()->root()->isRootLayer();
+ return false;
}
RenderObject* RenderObject::rendererForRootBackground()
{
- ASSERT(isRoot());
- if (!hasBackground() && node() && isHTMLHtmlElement(node())) {
+ 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>
@@ -2471,7 +2665,7 @@ 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() && node() && node()->hasTagName(HTMLNames::imgTag)) ? RespectImageOrientation : DoNotRespectImageOrientation;
+ || (document().settings() && document().settings()->shouldRespectImageOrientation() && isHTMLImageElement(node())) ? RespectImageOrientation : DoNotRespectImageOrientation;
}
bool RenderObject::hasOutlineAnnotation() const
@@ -2484,10 +2678,10 @@ bool RenderObject::hasEntirelyFixedBackground() const
return m_style->hasEntirelyFixedBackground();
}
-RenderObject* RenderObject::container(const RenderLayerModelObject* repaintContainer, bool* repaintContainerSkipped) const
+RenderObject* RenderObject::container(const RenderLayerModelObject* paintInvalidationContainer, bool* paintInvalidationContainerSkipped) const
{
- if (repaintContainerSkipped)
- *repaintContainerSkipped = false;
+ if (paintInvalidationContainerSkipped)
+ *paintInvalidationContainerSkipped = false;
// This method is extremely similar to containingBlock(), but with a few notable
// exceptions.
@@ -2505,7 +2699,7 @@ RenderObject* RenderObject::container(const RenderLayerModelObject* repaintConta
EPosition pos = m_style->position();
if (pos == FixedPosition) {
- return containerForFixedPosition(repaintContainer, repaintContainerSkipped);
+ 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
@@ -2517,8 +2711,8 @@ RenderObject* RenderObject::container(const RenderLayerModelObject* repaintConta
if (o->canContainFixedPositionObjects())
break;
- if (repaintContainerSkipped && o == repaintContainer)
- *repaintContainerSkipped = true;
+ if (paintInvalidationContainerSkipped && o == paintInvalidationContainer)
+ *paintInvalidationContainerSkipped = true;
o = o->parent();
}
@@ -2543,7 +2737,7 @@ inline void RenderObject::clearLayoutRootIfNeeded() const
// 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->clearLayoutRoot();
+ view->clearLayoutSubtreeRoot();
}
}
}
@@ -2557,10 +2751,9 @@ void RenderObject::willBeDestroyed()
children->destroyLeftoverChildren();
// If this renderer is being autoscrolled, stop the autoscrolling.
- if (Frame* frame = this->frame()) {
+ if (LocalFrame* frame = this->frame()) {
if (frame->page())
frame->page()->autoscrollController().stopAutoscrollIfNeeded(this);
- frame->animation().cancelAnimations(this);
}
// For accessibility management, notify the parent of the imminent change to its child set.
@@ -2575,18 +2768,6 @@ void RenderObject::willBeDestroyed()
if (AXObjectCache* cache = document().existingAXObjectCache())
cache->remove(this);
-#ifndef NDEBUG
- if (!documentBeingDestroyed() && view() && view()->hasRenderNamedFlowThreads()) {
- // After remove, the object and the associated information should not be in any flow thread.
- const RenderNamedFlowThreadList* flowThreadList = view()->flowThreadController()->renderNamedFlowThreadList();
- for (RenderNamedFlowThreadList::const_iterator iter = flowThreadList->begin(); iter != flowThreadList->end(); ++iter) {
- const RenderNamedFlowThread* renderFlowThread = *iter;
- ASSERT(!renderFlowThread->hasChild(this));
- ASSERT(!renderFlowThread->hasChildInfo(this));
- }
- }
-#endif
-
// 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
@@ -2595,6 +2776,13 @@ void RenderObject::willBeDestroyed()
if (hasCounterNodeMap())
RenderCounter::destroyCounterNodes(*this);
+ // Remove the handler if node had touch-action set. Don't call when
+ // document is being destroyed as all handlers will have been cleared
+ // previously. 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.
+ if (!documentBeingDestroyed() && node() && !node()->isTextNode() && m_style && m_style->touchAction() != TouchActionAuto)
+ document().didRemoveTouchEventHandler(node());
+
setAncestorLineBoxDirty(false);
clearLayoutRootIfNeeded();
@@ -2607,7 +2795,7 @@ void RenderObject::insertedIntoTree()
// 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.
RenderLayer* layer = 0;
- if (firstChild() || hasLayer()) {
+ if (slowFirstChild() || hasLayer()) {
layer = parent()->enclosingLayer();
addLayers(layer);
}
@@ -2623,9 +2811,6 @@ void RenderObject::insertedIntoTree()
if (!isFloating() && parent()->childrenInline())
parent()->dirtyLinesFromChangedChild(this);
-
- if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper())
- containerFlowThread->addFlowChild(this);
}
void RenderObject::willBeRemovedFromTree()
@@ -2635,12 +2820,13 @@ void RenderObject::willBeRemovedFromTree()
// If we remove a visible child from an invisible parent, we don't know the layer visibility any more.
RenderLayer* layer = 0;
if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
- if ((layer = parent()->enclosingLayer()))
+ layer = parent()->enclosingLayer();
+ if (layer)
layer->dirtyVisibleContentStatus();
}
// Keep our layer hierarchy updated.
- if (firstChild() || hasLayer()) {
+ if (slowFirstChild() || hasLayer()) {
if (!layer)
layer = parent()->enclosingLayer();
removeLayers(layer);
@@ -2651,11 +2837,9 @@ void RenderObject::willBeRemovedFromTree()
removeFromRenderFlowThread();
- if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper())
- containerFlowThread->removeFlowChild(this);
-
// Update cached boundaries in SVG renderers if a child is removed.
- parent()->setNeedsBoundariesUpdate();
+ if (parent()->isSVG())
+ parent()->setNeedsBoundariesUpdate();
}
void RenderObject::removeFromRenderFlowThread()
@@ -2677,11 +2861,6 @@ void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderF
child->removeFromRenderFlowThreadRecursive(renderFlowThread);
}
- RenderFlowThread* localFlowThread = renderFlowThread;
- if (flowThreadState() == InsideInFlowThread)
- localFlowThread = flowThreadContainingBlock(); // We have to ask. We can't just assume we are in the same flow thread.
- if (localFlowThread)
- localFlowThread->removeFlowChildInfo(this);
setFlowThreadState(NotInsideFlowThread);
}
@@ -2703,7 +2882,7 @@ void RenderObject::destroyAndCleanupAnonymousWrappers()
if (destroyRootParent->isRenderFlowThread() || destroyRootParent->isAnonymousColumnSpanBlock())
break;
- if (destroyRootParent->firstChild() != this || destroyRootParent->lastChild() != this)
+ if (destroyRootParent->slowFirstChild() != this || destroyRootParent->slowLastChild() != this)
break;
}
@@ -2712,6 +2891,12 @@ void RenderObject::destroyAndCleanupAnonymousWrappers()
// WARNING: |this| is deleted here.
}
+void RenderObject::destroy()
+{
+ willBeDestroyed();
+ postDestroy();
+}
+
void RenderObject::removeShapeImageClient(ShapeValue* shapeValue)
{
if (!shapeValue)
@@ -2720,12 +2905,6 @@ void RenderObject::removeShapeImageClient(ShapeValue* shapeValue)
shapeImage->removeClient(this);
}
-void RenderObject::destroy()
-{
- willBeDestroyed();
- postDestroy();
-}
-
void RenderObject::postDestroy()
{
// It seems ugly that this is not in willBeDestroyed().
@@ -2746,7 +2925,6 @@ void RenderObject::postDestroy()
if (StyleImage* maskBoxImage = m_style->maskBoxImage().image())
maskBoxImage->removeClient(this);
- removeShapeImageClient(m_style->shapeInside());
removeShapeImageClient(m_style->shapeOutside());
}
@@ -2762,9 +2940,13 @@ void RenderObject::updateDragState(bool dragOn)
{
bool valueChanged = (dragOn != isDragging());
setIsDragging(dragOn);
- if (valueChanged && node() && (style()->affectedByDrag() || (node()->isElementNode() && toElement(node())->childrenAffectedByDrag())))
- node()->setNeedsStyleRecalc();
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ if (valueChanged && node()) {
+ if (node()->isElementNode() && toElement(node())->childrenOrSiblingsAffectedByDrag())
+ node()->setNeedsStyleRecalc(SubtreeStyleChange);
+ else if (style()->affectedByDrag())
+ node()->setNeedsStyleRecalc(LocalStyleChange);
+ }
+ for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
curr->updateDragState(dragOn);
}
@@ -2773,6 +2955,11 @@ CompositingState RenderObject::compositingState() const
return hasLayer() ? toRenderLayerModelObject(this)->layer()->compositingState() : NotComposited;
}
+CompositingReasons RenderObject::additionalCompositingReasons(CompositingTriggerFlags) const
+{
+ return CompositingReasonNone;
+}
+
bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter)
{
bool inside = false;
@@ -2839,35 +3026,10 @@ void RenderObject::scheduleRelayout()
}
}
-void RenderObject::layout()
-{
- ASSERT(needsLayout());
- LayoutRectRecorder recorder(*this);
- RenderObject* child = firstChild();
- while (child) {
- child->layoutIfNeeded();
- ASSERT(!child->needsLayout());
- child = child->nextSibling();
- }
- clearNeedsLayout();
-}
-
-void RenderObject::didLayout(ResourceLoadPriorityOptimizer& priorityModifier)
-{
- for (RenderObject* child = firstChild(); child; child = child->nextSibling())
- child->didLayout(priorityModifier);
-}
-
-void RenderObject::didScroll(ResourceLoadPriorityOptimizer& priorityModifier)
-{
- for (RenderObject* child = firstChild(); child; child = child->nextSibling())
- child->didScroll(priorityModifier);
-}
-
void RenderObject::forceLayout()
{
setSelfNeedsLayout(true);
- setShouldDoFullRepaintAfterLayout(true);
+ setShouldDoFullPaintInvalidationAfterLayout(true);
layout();
}
@@ -2907,13 +3069,13 @@ static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheSta
return rendererForFirstLineStyle->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), parentStyle, style);
}
}
- return 0;
+ return nullptr;
}
PassRefPtr<RenderStyle> RenderObject::uncachedFirstLineStyle(RenderStyle* style) const
{
if (!document().styleEngine()->usesFirstLineRules())
- return 0;
+ return nullptr;
ASSERT(!isText());
@@ -2948,20 +3110,19 @@ RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* pa
PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const
{
if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId))
- return 0;
+ return nullptr;
if (!parentStyle) {
ASSERT(!ownStyle);
parentStyle = style();
}
- // FIXME: This "find nearest element parent" should be a helper function.
- Node* n = node();
- while (n && !n->isElementNode())
- n = n->parentNode();
- if (!n)
- return 0;
- Element* element = toElement(n);
+ 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);
@@ -2972,54 +3133,56 @@ PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRe
return document().ensureStyleResolver().pseudoStyleForElement(element, pseudoStyleRequest, parentStyle);
}
-bool RenderObject::hasBlendMode() const
+PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyleFromParentOrShadowHost() const
{
- return RuntimeEnabledFeatures::cssCompositingEnabled() && style() && style()->hasBlendMode();
-}
+ if (!node())
+ return nullptr;
-static Color decorationColor(const RenderObject* object, RenderStyle* style)
-{
- Color result;
- // Check for text decoration color first.
- result = object->resolveColor(style, CSSPropertyTextDecorationColor);
- if (result.isValid())
- return result;
- if (style->textStrokeWidth() > 0) {
- // Prefer stroke color if possible but not if it's fully transparent.
- result = object->resolveColor(style, CSSPropertyWebkitTextStrokeColor);
- if (result.alpha())
- return result;
+ if (ShadowRoot* root = node()->containingShadowRoot()) {
+ if (root->type() == ShadowRoot::UserAgentShadowRoot) {
+ if (Element* shadowHost = node()->shadowHost()) {
+ return shadowHost->renderer()->getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
+ }
+ }
}
- result = object->resolveColor(style, CSSPropertyWebkitTextFillColor);
- return result;
+ return getUncachedPseudoStyle(PseudoStyleRequest(SELECTION));
+}
+
+bool RenderObject::hasBlendMode() const
+{
+ return RuntimeEnabledFeatures::cssCompositingEnabled() && style() && style()->hasBlendMode();
}
-void RenderObject::getTextDecorationColors(unsigned decorations, Color& underline, Color& overline,
- Color& linethrough, bool quirksMode, bool firstlineStyle)
+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 = decorationColor(this, styleToUse);
+ resultColor = styleToUse->visitedDependentDecorationColor();
+ resultStyle = styleToUse->textDecorationStyle();
// Parameter 'decorations' is cast as an int to enable the bitwise operations below.
if (currDecs) {
if (currDecs & TextDecorationUnderline) {
decorations &= ~TextDecorationUnderline;
- underline = resultColor;
+ underline.color = resultColor;
+ underline.style = resultStyle;
}
if (currDecs & TextDecorationOverline) {
decorations &= ~TextDecorationOverline;
- overline = resultColor;
+ overline.color = resultColor;
+ overline.style = resultStyle;
}
if (currDecs & TextDecorationLineThrough) {
decorations &= ~TextDecorationLineThrough;
- linethrough = resultColor;
+ linethrough.color = resultColor;
+ linethrough.style = resultStyle;
}
}
if (curr->isRubyText())
@@ -3027,18 +3190,24 @@ void RenderObject::getTextDecorationColors(unsigned decorations, Color& underlin
curr = curr->parent();
if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation())
curr = toRenderBlock(curr)->continuation();
- } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(curr->node()) && !curr->node()->hasTagName(fontTag))));
+ } 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 = decorationColor(this, styleToUse);
- if (decorations & TextDecorationUnderline)
- underline = resultColor;
- if (decorations & TextDecorationOverline)
- overline = resultColor;
- if (decorations & TextDecorationLineThrough)
- linethrough = resultColor;
+ resultColor = styleToUse->visitedDependentDecorationColor();
+ 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;
+ }
}
}
@@ -3052,7 +3221,7 @@ void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
return;
RenderBox* box = toRenderBox(this);
- FloatRect localBounds(FloatPoint(), FloatSize(box->width(), box->height()));
+ FloatRect localBounds(FloatPoint(), FloatSize(box->width().toFloat(), box->height().toFloat()));
FloatRect absBounds = localToAbsoluteQuad(localBounds).boundingBox();
AnnotatedRegionValue region;
@@ -3069,7 +3238,7 @@ void RenderObject::collectAnnotatedRegions(Vector<AnnotatedRegionValue>& regions
return;
addAnnotatedRegions(regions);
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
+ for (RenderObject* curr = slowFirstChild(); curr; curr = curr->nextSibling())
curr->collectAnnotatedRegions(regions);
}
@@ -3085,14 +3254,7 @@ bool RenderObject::willRenderImage(ImageResource*)
// 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()->isOffscreen();
-}
-
-int RenderObject::maximalOutlineSize(PaintPhase p) const
-{
- if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines)
- return 0;
- return view()->maximalOutlineSize();
+ return document().view()->isVisible();
}
int RenderObject::caretMinOffset() const
@@ -3103,7 +3265,7 @@ int RenderObject::caretMinOffset() const
int RenderObject::caretMaxOffset() const
{
if (isReplaced())
- return node() ? max(1U, node()->childNodeCount()) : 1;
+ return node() ? max(1U, node()->countChildren()) : 1;
if (isHR())
return 1;
return 0;
@@ -3124,22 +3286,6 @@ int RenderObject::nextOffset(int current) const
return current + 1;
}
-void RenderObject::adjustRectForOutlineAndShadow(LayoutRect& rect) const
-{
- int outlineSize = outlineStyleForRepaint()->outlineSize();
- if (const ShadowList* boxShadow = style()->boxShadow()) {
- boxShadow->adjustRectForShadow(rect, outlineSize);
- return;
- }
-
- rect.inflate(outlineSize);
-}
-
-AnimationController& RenderObject::animation() const
-{
- return frame()->animation();
-}
-
bool RenderObject::isInert() const
{
const RenderObject* renderer = this;
@@ -3148,41 +3294,28 @@ bool RenderObject::isInert() const
return renderer->node()->isInert();
}
-void RenderObject::imageChanged(ImageResource* image, const IntRect* rect)
+// 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
{
- imageChanged(static_cast<WrappedImagePtr>(image), rect);
+ if (isInline() && !isReplaced())
+ return false;
+ if (isTableRow() || isRenderTableCol())
+ return false;
+
+ return true;
}
-RenderObject* RenderObject::hoverAncestor() const
+void RenderObject::imageChanged(ImageResource* image, const IntRect* rect)
{
- // When searching for the hover ancestor and encountering a named flow thread,
- // the search will continue with the DOM ancestor of the top-most element
- // in the named flow thread.
- // See https://code.google.com/p/chromium/issues/detail?id=243278
- RenderObject* hoverAncestor = parent();
-
- // Skip anonymous blocks directly flowed into flow threads as it would
- // prevent us from continuing the search on the DOM tree when reaching the named flow thread.
- if (hoverAncestor && hoverAncestor->isAnonymousBlock() && hoverAncestor->parent() && hoverAncestor->parent()->isRenderNamedFlowThread())
- hoverAncestor = hoverAncestor->parent();
-
- if (hoverAncestor && hoverAncestor->isRenderNamedFlowThread()) {
- hoverAncestor = 0;
-
- Node* node = this->node();
- if (node) {
- Node* domAncestorNode = node->parentNode();
- if (domAncestorNode)
- hoverAncestor = domAncestorNode->renderer();
- }
- }
-
- return hoverAncestor;
+ imageChanged(static_cast<WrappedImagePtr>(image), rect);
}
Element* RenderObject::offsetParent() const
{
- if (isRoot() || isBody())
+ if (isDocumentElement() || isBody())
return 0;
if (isOutOfFlowPositioned() && style()->position() == FixedPosition)
@@ -3197,10 +3330,6 @@ Element* RenderObject::offsetParent() const
for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
// Spec: http://www.w3.org/TR/cssom-view/#offset-attributes
- // CSS regions specification says that region flows should return the body element as their offsetParent.
- if (ancestor->isRenderNamedFlowThread())
- return document().body();
-
node = ancestor->node();
if (!node)
@@ -3209,10 +3338,10 @@ Element* RenderObject::offsetParent() const
if (ancestor->isPositioned())
break;
- if (node->hasTagName(HTMLNames::bodyTag))
+ if (isHTMLBodyElement(*node))
break;
- if (!isPositioned() && (isHTMLTableElement(node) || node->hasTagName(tdTag) || node->hasTagName(thTag)))
+ if (!isPositioned() && (isHTMLTableElement(*node) || isHTMLTableCellElement(*node)))
break;
// Webkit specific extension where offsetParent stops at zoom level changes.
@@ -3329,7 +3458,7 @@ FloatRect RenderObject::strokeBoundingBox() const
// Returns the smallest rectangle enclosing all of the painted content
// respecting clipping, masking, filters, opacity, stroke-width and markers
-FloatRect RenderObject::repaintRectInLocalCoordinates() const
+FloatRect RenderObject::paintInvalidationRectInLocalCoordinates() const
{
ASSERT_NOT_REACHED();
return FloatRect();
@@ -3353,25 +3482,35 @@ bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const
return false;
}
-// FIXME: This should really use local coords
-// Works on absolute coords - expensive to call
-bool RenderObject::isContainedInParentBoundingBox() const
+bool RenderObject::isRelayoutBoundaryForInspector() const
{
- if (!parent())
- return false;
+ return objectIsRelayoutBoundary(this);
+}
+
+void RenderObject::clearPaintInvalidationState()
+{
+ setShouldDoFullPaintInvalidationAfterLayout(false);
+ setShouldDoFullPaintInvalidationIfSelfPaintingLayer(false);
+ setOnlyNeededPositionedMovementLayout(false);
+ setShouldInvalidateOverflowForPaint(false);
+ setLayoutDidGetCalled(false);
+ setMayNeedPaintInvalidation(false);
+}
- IntRect parentRect = parent()->absoluteBoundingBoxRect();
- return parentRect.contains(absoluteBoundingBoxRect());
+bool RenderObject::isAllowedToModifyRenderTreeStructure(Document& document)
+{
+ return DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState()
+ || document.lifecycle().stateAllowsRenderTreeMutations();
}
-bool RenderObject::isRelayoutBoundaryForInspector() const
+DeprecatedDisableModifyRenderTreeStructureAsserts::DeprecatedDisableModifyRenderTreeStructureAsserts()
+ : m_disabler(gModifyRenderTreeStructureAnyState, true)
{
- return objectIsRelayoutBoundary(this);
}
-bool RenderObject::isRenderNamedFlowFragmentContainer() const
+bool DeprecatedDisableModifyRenderTreeStructureAsserts::canModifyRenderTreeStateInAnyState()
{
- return isRenderBlockFlow() && toRenderBlockFlow(this)->renderNamedFlowFragment();
+ return gModifyRenderTreeStructureAnyState;
}
} // namespace WebCore