/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
 *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
 * Copyright (C) 2010, 2012 Google Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include "RenderElement.h"

#include "CachedResourceLoader.h"
#include "ContentData.h"
#include "CursorList.h"
#include "DocumentTimeline.h"
#include "ElementChildIterator.h"
#include "ElementInlines.h"
#include "EventHandler.h"
#include "Frame.h"
#include "FrameSelection.h"
#include "HTMLAnchorElement.h"
#include "HTMLBodyElement.h"
#include "HTMLHtmlElement.h"
#include "HTMLNames.h"
#include "ReferencedSVGResources.h"
#include "RenderBlock.h"
#include "RenderBR.h"
#include "RenderCounter.h"
#include "RenderDescendantIterator.h"
#include "RenderDeprecatedFlexibleBox.h"
#include "RenderDescendantIterator.h"
#include "RenderFlexibleBox.h"
#include "RenderFragmentContainer.h"
#include "RenderFragmentedFlow.h"
#include "RenderGrid.h"
#include "RenderImage.h"
#include "RenderImageResourceStyleImage.h"
#include "RenderInline.h"
#include "RenderIterator.h"
#include "RenderLayer.h"
#include "RenderListItem.h"
#if !ASSERT_DISABLED
#include "RenderListMarker.h"
#endif
#include "RenderMultiColumnFlow.h"
#include "RenderMultiColumnSpannerPlaceholder.h"
#include "RenderStyle.h"
#include "RenderTableCaption.h"
#include "RenderTableCell.h"
#include "RenderTableCol.h"
#include "RenderTableRow.h"
#include "RenderText.h"
#include "RenderTheme.h"
#include "RenderTreeBuilder.h"
#include "RenderView.h"
#include "Settings.h"
#include "ShadowRoot.h"
#include "StylePendingResources.h"
#include "SVGImage.h"
#include "SVGLengthContext.h"
#include "SVGRenderSupport.h"
#include "StyleResolver.h"

#if USE(ACCELERATED_COMPOSITING)
#include "RenderLayerCompositor.h"
#endif

namespace WebCore {

#if 0
struct SameSizeAsRenderElement : public RenderObject {
    uint32_t bitfields;
    void* firstChild;
    void* lastChild;
    RenderStyle style;
#if !ASSERT_DISABLED
    bool reparentingChild;
#endif
};

static_assert(sizeof(RenderElement) == sizeof(SameSizeAsRenderElement), "RenderElement should stay small");
#endif

RenderElement::RenderElement(Element& element, PassOwnPtr<RenderStyle> style, unsigned baseTypeFlags)
    : RenderObject(element)
	, m_baseTypeFlags(baseTypeFlags)
	, m_ancestorLineBoxDirty(false)
	, m_hasInitializedStyle(false)
	, m_hasPausedImageAnimations(false)
	, m_hasCounterNodeMap(false)
	, m_hasContinuationChainNode(false)
	, m_isContinuation(false)
	, m_isFirstLetter(false)
	, m_firstChild(0)
	, m_lastChild(0)
	, m_style(style)
{
}

RenderElement::RenderElement(Document& document, PassOwnPtr<RenderStyle> style, unsigned baseTypeFlags)
    : RenderObject(document)
	, m_baseTypeFlags(baseTypeFlags)
	, m_ancestorLineBoxDirty(false)
	, m_hasInitializedStyle(false)
	, m_hasPausedImageAnimations(false)
	, m_hasCounterNodeMap(false)
	, m_hasContinuationChainNode(false)
	, m_isContinuation(false)
	, m_isFirstLetter(false)
	, m_firstChild(0)
	, m_lastChild(0)
	, m_style(style)
{
}

RenderElement::~RenderElement()
{
    // Do not add any code here. Add it to willBeDestroyed() instead.
    ASSERT(!m_firstChild);
}

bool RenderElement::isContentDataSupported(const ContentData& contentData)
{
    // Minimal support for content properties replacing an entire element.
    // Works only if we have exactly one piece of content and it's a URL.
    // Otherwise acts as if we didn't support this feature.
    return contentData.isImage() && !contentData.next();
}

RenderPtr<RenderElement> RenderElement::createFor(Element& element, PassOwnPtr<RenderStyle> style, RendererCreationType creationType)
{
    // Minimal support for content properties replacing an entire element.
    // Works only if we have exactly one piece of content and it's a URL.
    // Otherwise acts as if we didn't support this feature.
    const ContentData* contentData = style->contentData();
    if (creationType == CreateAllRenderers && contentData && isContentDataSupported(*contentData) && !element.isPseudoElement()) {
        Style::loadPendingResources(*style, element.document(), &element);
    	auto* styleImage = static_cast<const ImageContentData*>(contentData)->image();
        auto image = createRendererMaybeNull<RenderImage>(element, style, const_cast<StyleImage*>(styleImage));
        if(UNLIKELY(!image))
        	return nullptr;
        if (styleImage)
            image->setIsGeneratedContent();
        return WTFMove(image);
    }

    switch (style->display()) {
    case DisplayType::None:
    case DisplayType::Contents:
    	return nullptr;
    case DisplayType::Inline:
        if (creationType == CreateAllRenderers)
        	return createRendererMaybeNull<RenderInline>(element, style);
        FALLTHROUGH; // Fieldsets should make a block flow if display:inline is set.
    case DisplayType::Block:
    case DisplayType::FlowRoot:
    case DisplayType::InlineBlock:
    case DisplayType::Compact:
        return createRendererMaybeNull<RenderBlockFlow>(element, style);
    case DisplayType::ListItem:
        // <summary> elements with display:list-item should not be rendered as list items because
        // they'd end up with two markers before the text (one from summary element and the other as
        // a list item).
		if (creationType == OnlyCreateBlockAndFlexboxRenderers)
			return createRendererMaybeNull<RenderBlockFlow>(element, style);
		return createRendererMaybeNull<RenderListItem>(element, style);
    case DisplayType::Flex:
    case DisplayType::InlineFlex:
    case DisplayType::WebKitFlex:
    case DisplayType::WebKitInlineFlex:
        return createRendererMaybeNull<RenderFlexibleBox>(element, style);
    case DisplayType::Grid:
    case DisplayType::InlineGrid:
        return createRendererMaybeNull<RenderGrid>(element, style);
    case DisplayType::Box:
    case DisplayType::InlineBox:
        return createRendererMaybeNull<RenderDeprecatedFlexibleBox>(element, style);
    default: {
        if (creationType == OnlyCreateBlockAndFlexboxRenderers)
            return createRendererMaybeNull<RenderBlockFlow>(element, style);
        switch (style->display()) {
		case DisplayType::Table:
		case DisplayType::InlineTable:
			return createRendererMaybeNull<RenderTable>(element, style);
		case DisplayType::TableCell:
			return createRendererMaybeNull<RenderTableCell>(element, style);
		case DisplayType::TableCaption:
			return createRendererMaybeNull<RenderTableCaption>(element, style);
		case DisplayType::TableRowGroup:
		case DisplayType::TableHeaderGroup:
		case DisplayType::TableFooterGroup:
			return createRendererMaybeNull<RenderTableSection>(element, style);
		case DisplayType::TableRow:
			return createRendererMaybeNull<RenderTableRow>(element, style);
		case DisplayType::TableColumnGroup:
		case DisplayType::TableColumn:
			return createRendererMaybeNull<RenderTableCol>(element, style);
		default:
			break;
		}
		break;
	}
	}
    ASSERT_NOT_REACHED();
	return nullptr;
}

enum StyleCacheState {
    Cached,
    Uncached
};

const RenderStyle* RenderElement::firstLineStyle() const
{
    // FIXME: It would be better to just set anonymous block first-line styles correctly.
    if (isAnonymousBlock()) {
        if (!previousInFlowSibling()) {
            if (auto* firstLineStyle = parent()->style()->getCachedPseudoStyle(PseudoId::FirstLine))
                return firstLineStyle;
        }
        return style();
    }

    if (auto* firstLineStyle = style()->getCachedPseudoStyle(PseudoId::FirstLine))
        return firstLineStyle;

    return style();
}

StyleDifference RenderElement::adjustStyleDifference(StyleDifference diff, OptionSet<StyleDifferenceContextSensitiveProperty> contextSensitiveProperties) const
{
#if USE(ACCELERATED_COMPOSITING)
    // If transform changed, and we are not composited, need to do a layout.
    if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Transform) {
    	 // FIXME: when transforms are taken into account for overflow, we will need to do a layout.
		if (!hasLayer() || !toRenderLayerModelObject(*this).layer()->isComposited()) {
			if (!hasLayer())
				diff = std::max(diff, StyleDifferenceLayout);
			else {
				// We need to set at least SimplifiedLayout, but if PositionedMovementOnly is already set
				// then we actually need SimplifiedLayoutAndPositionedMovement.
				diff = std::max(diff, (diff == StyleDifferenceLayoutPositionedMovementOnly) ? StyleDifferenceSimplifiedLayoutAndPositionedMovement : StyleDifferenceSimplifiedLayout);
			}
        } else
			diff = std::max(diff, StyleDifferenceRecompositeLayer);
	}

    if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Opacity) {
        if (!hasLayer() || !toRenderLayerModelObject(this)->layer()->isComposited())
        	diff = std::max(diff, StyleDifferenceRepaintLayer);
		else
			diff = std::max(diff, StyleDifferenceRecompositeLayer);
	}

    if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::ClipPath) {
        if (hasLayer()
            && toRenderLayerModelObject(*this).layer()->isComposited()
            && hasClipPath()
            && RenderLayerCompositor::canCompositeClipPath(*toRenderLayerModelObject(*this).layer()))
            diff = std::max(diff, StyleDifferenceRecompositeLayer);
        else
            diff = std::max(diff, StyleDifferenceRepaint);
    }

    if (contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::WillChange) {
        if (style()->willChange() && style()->willChange()->canTriggerCompositing())
            diff = std::max(diff, StyleDifferenceRecompositeLayer);
    }

#if ENABLE(CSS_FILTERS)
    if ((contextSensitiveProperties & StyleDifferenceContextSensitiveProperty::Filter) && hasLayer()) {
        RenderLayer* layer = toRenderLayerModelObject(this)->layer();
        if (!layer->isComposited() || layer->paintsWithFilters())
        	diff = std::max(diff, StyleDifferenceRepaintLayer);
		else
			diff = std::max(diff, StyleDifferenceRecompositeLayer);
	}
#endif

    // The answer to requiresLayer() 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 < StyleDifferenceLayout && style() && isRenderLayerModelObject()) {
        if (hasLayer() != toRenderLayerModelObject(this)->requiresLayer())
            diff = StyleDifferenceLayout;
    }
#else
    UNUSED_PARAM(contextSensitiveProperties);
#endif

    // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
    if (diff == StyleDifferenceRepaintLayer && !hasLayer())
        diff = StyleDifferenceRepaint;

    return diff;
}

inline bool RenderElement::shouldRepaintForStyleDifference(StyleDifference diff) const
{
    auto hasImmediateNonWhitespaceTextChild = [&] {
        for (auto& child : childrenOfType<RenderText>(*this)) {
            if (!child.isAllCollapsibleWhitespace())
                return true;
        }
        return false;
    };
    return diff == StyleDifferenceRepaint || (diff == StyleDifferenceRepaintIfText && hasImmediateNonWhitespaceTextChild());
}

void RenderElement::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers)
{
    auto fillImagesAreIdentical = [](const FillLayer* layer1, const FillLayer* layer2) -> bool {
        if (layer1 == layer2)
            return true;

        for (; layer1 && layer2; layer1 = layer1->next(), layer2 = layer2->next()) {
            if (!arePointingToEqualData(layer1->image(), layer2->image()))
                return false;
            if (layer1->image() && layer1->image()->usesDataProtocol())
                return false;
            if (auto* styleImage = layer1->image()) {
                if (styleImage->errorOccurred() || !styleImage->hasImage() || styleImage->usesDataProtocol())
                    return false;
            }
        }

        return !layer1 && !layer2;
    };

    auto isRegisteredWithNewFillImages = [&]() -> bool {
        for (auto* layer = newLayers; layer; layer = layer->next()) {
            if (layer->image() && !layer->image()->hasClient(*this))
                return false;
        }
        return true;
    };

    // If images have the same characteristics and this element is already registered as a
    // client to the new images, there is nothing to do.
    if (fillImagesAreIdentical(oldLayers, newLayers) && isRegisteredWithNewFillImages())
        return;

    // Add before removing, to avoid removing all clients of an image that is in both sets.
    for (auto* layer = newLayers; layer; layer = layer->next()) {
        if (layer->image())
            layer->image()->addClient(*this);
    }
    for (auto* layer = oldLayers; layer; layer = layer->next()) {
        if (layer->image())
            layer->image()->removeClient(*this);
    }
}

void RenderElement::updateImage(StyleImage* oldImage, StyleImage* newImage)
{
    if (oldImage == newImage)
        return;
    if (oldImage)
        oldImage->removeClient(*this);
    if (newImage)
        newImage->addClient(*this);
}

#if ENABLE(CSS_SHAPES)
void RenderElement::updateShapeImage(const ShapeValue* oldShapeValue, const ShapeValue* newShapeValue)
{
    if (oldShapeValue || newShapeValue)
        updateImage(oldShapeValue ? oldShapeValue->image() : 0, newShapeValue ? newShapeValue->image() : 0);
}
#endif

bool RenderElement::repaintBeforeStyleChange(StyleDifference diff, const RenderStyle& oldStyle, const RenderStyle& newStyle)
{
    if (oldStyle.visibility() == EVisibility::HIDDEN) {
        // Repaint on hidden renderer is a no-op.
        return false;
    }
    enum class RequiredRepaint { None, RendererOnly, RendererAndDescendantsRenderersWithLayers };
    RequiredRepaint shouldRepaintBeforeStyleChange = [&]() -> RequiredRepaint {
        if (!parent()) {
            // Can't resolve absolute coordinates.
            return RequiredRepaint::None;
        }

        if (this->isRenderLayerModelObject() && hasLayer()) {
            if (diff == StyleDifference::StyleDifferenceRepaintLayer)
                return RequiredRepaint::RendererAndDescendantsRenderersWithLayers;
            if (diff == StyleDifference::StyleDifferenceLayout || diff == StyleDifference::StyleDifferenceSimplifiedLayout) {
                // Certain style changes require layer repaint, since the layer could end up being destroyed.
                auto layerMayGetDestroyed = oldStyle.position() != newStyle.position()
                    || oldStyle.usedZIndex() != newStyle.usedZIndex()
                    || oldStyle.hasAutoUsedZIndex() != newStyle.hasAutoUsedZIndex()
                    || oldStyle.clip() != newStyle.clip()
                    || oldStyle.hasClip() != newStyle.hasClip()
                    || oldStyle.hasOpacity() != newStyle.hasOpacity()
                    || oldStyle.hasTransform() != newStyle.hasTransform()
                    || oldStyle.hasFilter() != newStyle.hasFilter();
                if (layerMayGetDestroyed)
                    return RequiredRepaint::RendererAndDescendantsRenderersWithLayers;
            }
        }

        if (shouldRepaintForStyleDifference(diff))
            return RequiredRepaint::RendererOnly;

        if (newStyle.outlineSize() < oldStyle.outlineSize())
            return RequiredRepaint::RendererOnly;

        if ((*this).isRenderLayerModelObject()) {
            // If we don't have a layer yet, but we are going to get one because of transform or opacity, then we need to repaint the old position of the object.
            bool hasLayer = toRenderLayerModelObject(*this).hasLayer();
            bool willHaveLayer = newStyle.affectsTransform() || newStyle.hasOpacity() || newStyle.hasFilter() || newStyle.hasBackdropFilter();
            if (!hasLayer && willHaveLayer)
                return RequiredRepaint::RendererOnly;
        }

        if ((*this).isBox()) {
            if (diff == StyleDifference::StyleDifferenceLayout && oldStyle.position() != newStyle.position() && oldStyle.position() == PositionType::Static)
            	return RequiredRepaint::RendererOnly;
		}

        if (diff > StyleDifference::StyleDifferenceRepaintLayer && oldStyle.visibility() != newStyle.visibility()) {
            if (auto* enclosingLayer = this->enclosingLayer()) {
                auto rendererWillBeHidden = newStyle.visibility() != EVisibility::VISIBLE;
                if (rendererWillBeHidden && enclosingLayer->hasVisibleContent() && (this == &enclosingLayer->renderer() || enclosingLayer->renderer().style()->visibility() != EVisibility::VISIBLE))
                	return RequiredRepaint::RendererOnly;
			}
		}

        if (diff > StyleDifference::StyleDifferenceRepaintLayer && oldStyle.effectiveContentVisibility() != newStyle.effectiveContentVisibility() && isOutOfFlowPositioned()) {
            if (auto* enclosingLayer = this->enclosingLayer()) {
                bool rendererWillBeHidden = isSkippedContent();
                if (rendererWillBeHidden && enclosingLayer->hasVisibleContent() && (this == &enclosingLayer->renderer() || enclosingLayer->renderer().style()->visibility() != EVisibility::VISIBLE))
                    return RequiredRepaint::RendererOnly;
            }
        }

		return RequiredRepaint::None;
	}();

	if (shouldRepaintBeforeStyleChange == RequiredRepaint::RendererAndDescendantsRenderersWithLayers) {
		ASSERT(hasLayer());
		toRenderLayerModelObject(*this).layer()->repaintIncludingDescendants();
		return true;
	}

	if (shouldRepaintBeforeStyleChange == RequiredRepaint::RendererOnly) {
        if (isOutOfFlowPositioned() && toRenderLayerModelObject(*this).layer()->isSelfPaintingLayer()) {
            if (auto cachedClippedOverflowRect = toRenderLayerModelObject(*this).layer()->cachedClippedOverflowRect()) {
                repaintUsingContainer(containerForRepaint(), *cachedClippedOverflowRect);
                return true;
            }
        }
        repaint();
        return true;
    }

    return false;
}

void RenderElement::initializeStyle()
{
    Style::loadPendingResources(*m_style, document(), element());

    styleWillChange(StyleDifferenceNewStyle, style());
    m_hasInitializedStyle = true;
    styleDidChange(StyleDifferenceNewStyle, 0);

#if !ASSERT_DISABLED
    // We shouldn't have any text children that would need styleDidChange at this point.
    auto textChildren = childrenOfType<RenderText>(*this);
	ASSERT(textChildren.begin() == textChildren.end());
#endif

    // It would be nice to assert that !parent() here, but some RenderLayer subrenderers
    // have their parent set before getting a call to initializeStyle() :|
}

void RenderElement::setStyle(PassOwnPtr<RenderStyle> style, StyleDifference minimalStyleDifference)
{
    StyleDifference diff = StyleDifferenceEqual;
    OptionSet<StyleDifferenceContextSensitiveProperty> contextSensitiveProperties;
    if (m_hasInitializedStyle)
        diff = m_style->diff(style.get(), contextSensitiveProperties);

    diff = std::max(diff, minimalStyleDifference);

    diff = adjustStyleDifference(diff, contextSensitiveProperties);

    Style::loadPendingResources(*style, document(), element());

    auto didRepaint = repaintBeforeStyleChange(diff, *m_style, *style);
    styleWillChange(diff, style.get());
    OwnPtr<RenderStyle> oldStyle = m_style.release();
    m_style = style;
    bool detachedFromParent = !parent();

    adjustFragmentedFlowStateOnContainingBlockChangeIfNeeded(*oldStyle, *m_style);

    styleDidChange(diff, oldStyle.get());

    // Text renderers use their parent style. Notify them about the change.
	for (auto& child : childrenOfType<RenderText>(*this))
		child.styleDidChange(diff, oldStyle.get());

    // FIXME: |this| might be destroyed here. This can currently happen for a RenderTextFragment when
    // its first-letter block gets an update in RenderTextFragment::styleDidChange. For RenderTextFragment(s),
    // we will safely bail out with the detachedFromParent flag. We might want to broaden this condition
    // in the future as we move renderer changes out of layout and into style changes.
    if (detachedFromParent)
        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.
    StyleDifference updatedDiff = adjustStyleDifference(diff, contextSensitiveProperties);

    if (diff <= StyleDifferenceLayoutPositionedMovementOnly) {
        if (updatedDiff == StyleDifferenceLayout)
            setNeedsLayoutAndPrefWidthsRecalc();
        else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly)
            setNeedsPositionedMovementLayout(oldStyle.get());
        else if (updatedDiff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
            setNeedsPositionedMovementLayout(oldStyle.get());
            setNeedsSimplifiedNormalFlowLayout();
        } else if (updatedDiff == StyleDifferenceSimplifiedLayout)
            setNeedsSimplifiedNormalFlowLayout();
    }

    if (!didRepaint && (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();
    }
}

void RenderElement::didAttachChild(RenderObject& child, RenderObject*)
{
    if (child.isText())
        toRenderText(child).styleDidChange(StyleDifferenceEqual, 0);
    // 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
    // - when the document is painted, both layers are painted. The <body> layer doesn't
    //   know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't.
    // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree
    // and stop creating layers at all for these cases - they're not used anyways.
    if (child.hasLayer() && !layerCreationAllowedForSubtree())
    	toRenderLayerModelObject(child).layer()->removeOnlyThisLayer(RenderLayer::LayerChangeTiming::RenderTreeConstruction);
}

RenderObject* RenderElement::attachRendererInternal(RenderPtr<RenderObject> child, RenderObject* beforeChild)
{
    child->setParent(this);

    if (m_firstChild == beforeChild)
        m_firstChild = child.get();

    if (beforeChild) {
        auto* previousSibling = beforeChild->previousSibling();
        if (previousSibling)
            previousSibling->setNextSibling(child.get());
        child->setPreviousSibling(previousSibling);
        child->setNextSibling(beforeChild);
        beforeChild->setPreviousSibling(child.get());
        return child.release();
    }
    if (m_lastChild)
        m_lastChild->setNextSibling(child.get());
    child->setPreviousSibling(m_lastChild);
    m_lastChild = child.get();
    return child.release();
}

RenderPtr<RenderObject> RenderElement::detachRendererInternal(RenderObject& renderer)
{
    auto* parent = renderer.parent();
    ASSERT(parent);
    auto* nextSibling = renderer.nextSibling();

    if (renderer.previousSibling())
        renderer.previousSibling()->setNextSibling(nextSibling);
    if (nextSibling)
        nextSibling->setPreviousSibling(renderer.previousSibling());

    if (parent->firstChild() == &renderer)
        parent->m_firstChild = nextSibling;
    if (parent->lastChild() == &renderer)
        parent->m_lastChild = renderer.previousSibling();

    renderer.setPreviousSibling(nullptr);
    renderer.setNextSibling(nullptr);
    renderer.setParent(nullptr);
    return RenderPtr<RenderObject>(&renderer);
}

bool RenderElement::shouldUseTransformFromContainer(const RenderElement* containerObject) const
{
#if ENABLE(3D_RENDERING)
    if (isTransformed())
        return true;
    if (containerObject && containerObject->style()->hasPerspective()) {
        if (document().settings().css3DTransformInteroperabilityEnabled())
            return containerObject == parent();
        return true;
    }
    return false;
#else
    UNUSED_PARAM(containerObject);
    return isTransformed();
#endif
}

RenderElement& RenderElement::rendererForRootBackground()
{
    ASSERT(isDocumentElementRenderer());
    if (!hasBackground() && isHTMLHtmlElement(*element())) {
        // Locate the <body> element using the DOM. This is easier than trying
        // to crawl around a render tree with potential :before/:after content and
        // anonymous blocks created by inline <body> tags etc. We can locate the <body>
        // render object very easily via the DOM.
        if (auto* body = document().body()) {
            if (auto* renderer = body->renderer())
				return *renderer;
		}
    }

    return *this;
}

static inline void paintPhase(RenderElement& element, PaintPhase phase, PaintInfo& paintInfo, const LayoutPoint& childPoint)
{
    paintInfo.phase = phase;
    element.paint(paintInfo, childPoint);
}

void RenderElement::paintAsInlineBlock(PaintInfo& paintInfo, const LayoutPoint& childPoint)
{
    // Paint all phases atomically, as though the element established its own stacking context.
    // (See Appendix E.2, section 6.4 on inline block/table/replaced elements in the CSS2.1 specification.)
    // This is also used by other elements (e.g. flex items and grid items).
	PaintPhase paintPhaseToUse = isExcludedAndPlacedInBorder() ? paintInfo.phase : PaintPhaseForeground;
	if (paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhase::PaintPhaseTextClip)
        paint(paintInfo, childPoint);
    else if (paintInfo.phase == paintPhaseToUse) {
        paintPhase(*this, PaintPhaseBlockBackground, paintInfo, childPoint);
        paintPhase(*this, PaintPhaseChildBlockBackgrounds, paintInfo, childPoint);
        paintPhase(*this, PaintPhaseFloat, paintInfo, childPoint);
        paintPhase(*this, PaintPhaseForeground, paintInfo, childPoint);
        paintPhase(*this, PaintPhaseOutline, paintInfo, childPoint);

        // Reset |paintInfo| to the original phase.
        paintInfo.phase = paintPhaseToUse;
    }
}

void RenderElement::setNeedsPositionedMovementLayout(const RenderStyle* oldStyle)
{
    ASSERT(!isSetNeedsLayoutForbidden());
    if (needsPositionedMovementLayout())
        return;
    setNeedsPositionedMovementLayoutBit(true);
    markContainingBlocksForLayout();
    if (hasLayer()) {
        if (oldStyle && style()->diffRequiresLayerRepaint(*oldStyle, toRenderLayerModelObject(this)->layer()->isComposited()))
            setLayerNeedsFullRepaint();
        else
            setLayerNeedsFullRepaintForPositionedMovementLayout();
    }
}

void RenderElement::clearChildNeedsLayout()
{
    setNormalChildNeedsLayoutBit(false);
    setPosChildNeedsLayoutBit(false);
    setNeedsSimplifiedNormalFlowLayoutBit(false);
    setNeedsPositionedMovementLayoutBit(false);
    setOutOfFlowChildNeedsStaticPositionLayoutBit(false);
}

void RenderElement::setNeedsSimplifiedNormalFlowLayout()
{
    ASSERT(!isSetNeedsLayoutForbidden());
    if (needsSimplifiedNormalFlowLayout())
        return;
    setNeedsSimplifiedNormalFlowLayoutBit(true);
    markContainingBlocksForLayout();
    if (hasLayer())
		setLayerNeedsFullRepaint();
}

void RenderElement::setOutOfFlowChildNeedsStaticPositionLayout()
{
    // FIXME: Currently this dirty bit has a very limited useage but should be expanded to
    // optimize all kinds of out-of-flow cases.
    // It's also assumed that regular, positioned child related bits are already set.
    ASSERT(!isSetNeedsLayoutForbidden());
    ASSERT(posChildNeedsLayout() || selfNeedsLayout() || !parent());
    setOutOfFlowChildNeedsStaticPositionLayoutBit(true);
}

static RenderLayer* findNextLayer(const RenderElement& currRenderer, RenderLayer& parentLayer, const RenderObject* siblingToTraverseFrom, bool checkParent = true)
{
    // Step 1: If our layer is a child of the desired parent, then return our layer.
    auto* ourLayer = currRenderer.hasLayer() ? toRenderLayerModelObject(currRenderer).layer() : nullptr;
    if (ourLayer && ourLayer->parent() == &parentLayer)
        return ourLayer;

    // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
    // into our siblings trying to find the next layer whose parent is the desired parent.
    if (!ourLayer || ourLayer == &parentLayer) {
        for (auto* child = siblingToTraverseFrom ? siblingToTraverseFrom->nextSibling() : currRenderer.firstChild(); child; child = child->nextSibling()) {
            if (!(*child).isRenderElement())
                continue;
            if (auto* nextLayer = findNextLayer(toRenderElement(*child), parentLayer, nullptr, false))
                return nextLayer;
        }
    }

    // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
    // find anything.
    if (ourLayer == &parentLayer)
        return nullptr;

    // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
    // follow us to see if we can locate a layer.
    if (checkParent && currRenderer.parent())
        return findNextLayer(*currRenderer.parent(), parentLayer, &currRenderer, true);

    return nullptr;
}

static RenderLayer* layerNextSiblingRespectingTopLayer(const RenderElement& renderer, RenderLayer& parentLayer)
{
    //ASSERT_IMPLIES(isInTopLayerOrBackdrop(renderer.style(), renderer.element()), renderer.hasLayer());

    if (renderer.isRenderLayerModelObject() && isInTopLayerOrBackdrop(*renderer.style(), renderer.element())) {
        auto& layerModelObject = toRenderLayerModelObject(renderer);
        ASSERT(layerModelObject.hasLayer());
        auto topLayerLayers = RenderLayer::topLayerRenderLayers(renderer.view());
        auto layerIndex = topLayerLayers.find(layerModelObject.layer());
        if (layerIndex != notFound && layerIndex < topLayerLayers.size() - 1)
            return topLayerLayers[layerIndex + 1];

        return nullptr;
    }

    return findNextLayer(*renderer.parent(), parentLayer, &renderer);
}

static void addLayers(const RenderElement& insertedRenderer, RenderElement& currentRenderer, RenderLayer& parentLayer)
{
    if (currentRenderer.hasLayer()) {
        auto* layerToUse = &parentLayer;
        if (isInTopLayerOrBackdrop(*currentRenderer.style(), currentRenderer.element())) {
            // The special handling of a toplayer/backdrop content may result in trying to insert the associated
            // layer twice as we connect subtrees.
            if (auto* parentLayer = toRenderLayerModelObject(currentRenderer).layer()->parent()) {
                ASSERT(parentLayer == currentRenderer.view().layer());
                return;
            }
            layerToUse = insertedRenderer.view().layer();
        }
        auto* beforeChild = layerNextSiblingRespectingTopLayer(insertedRenderer, *layerToUse);
        layerToUse->addChild(toRenderLayerModelObject(currentRenderer).layer(), beforeChild);
        return;
    }

    for (auto& child : childrenOfType<RenderElement>(currentRenderer))
        addLayers(insertedRenderer, child, parentLayer);
}

void RenderElement::removeLayers()
{
    RenderLayer* parentLayer = layerParent();
    if (!parentLayer)
        return;

    if (hasLayer()) {
        parentLayer->removeChild(toRenderLayerModelObject(this)->layer());
        return;
    }

	for (auto& child : childrenOfType<RenderElement>(*this))
		child.removeLayers();
}

void RenderElement::moveLayers(RenderLayer& newParent)
{
    if (hasLayer()) {
        if (isInTopLayerOrBackdrop(*style(), element()))
            return;
        RenderLayer* layer = toRenderLayerModelObject(this)->layer();
        if (auto* layerParent = layer->parent())
			layerParent->removeChild(layer);
        newParent.addChild(layer);
        return;
    }

    for (auto& child : childrenOfType<RenderElement>(*this))
        child.moveLayers(newParent);
}

RenderLayer* RenderElement::layerParent() const
{
    //ASSERT_IMPLIES(isInTopLayerOrBackdrop(style(), element()), hasLayer());

    if (hasLayer() && isInTopLayerOrBackdrop(*style(), element()))
        return view().layer();

    return parent()->enclosingLayer();
}

// This answers the question "if this renderer had a layer, what would its next sibling layer be".
RenderLayer* RenderElement::layerNextSibling(RenderLayer& parentLayer) const
{
    return WebCore::layerNextSiblingRespectingTopLayer(*this, parentLayer);
}

bool RenderElement::layerCreationAllowedForSubtree() const
{
#if ENABLE(SVG)
    RenderElement* parentRenderer = parent();
    while (parentRenderer) {
        if (parentRenderer->isSVGHiddenContainer())
            return false;
        parentRenderer = parentRenderer->parent();
    }
#endif

    return true;
}

void RenderElement::propagateStyleToAnonymousChildren(StylePropagationType propagationType)
{
    // FIXME: We could save this call when the change only affected non-inherited properties.
	for (auto& child : childrenOfType<RenderElement>(*this)) {
        if (!child.isAnonymous() || child.style()->styleType() != PseudoId::None)
            continue;

        if (propagationType == PropagateToBlockChildrenOnly && !child.isRenderBlock())
            continue;

#if ENABLE(FULLSCREEN_API)
        if (child.isRenderFullScreen() || child.isRenderFullScreenPlaceholder())
            continue;
#endif

        // RenderFlowThreads are updated through the RenderView::styleDidChange function.
        if (child.isRenderFragmentedFlow())
            continue;

        OwnPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(*style(), child.style()->display());
        if (style()->specifiesColumns()) {
            if (child.style()->specifiesColumns())
                newStyle->inheritColumnPropertiesFrom(style());
            if (child.style()->columnSpan())
                newStyle->setColumnSpan(ColumnSpanAll);
        }

        // Preserve the position style of anonymous block continuations as they can have relative or sticky position when
        // they contain block descendants of relative or sticky positioned inlines.
        if (child.isInFlowPositioned() && child.isContinuation())
            newStyle->setPosition(child.style()->position());

        updateAnonymousChildStyle(*newStyle);

        child.setStyle(newStyle.release());
    }
}

static inline bool rendererHasBackground(const RenderElement* renderer)
{
    return renderer && renderer->hasBackground();
}

void RenderElement::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
{
    const RenderStyle* oldStyle = hasInitializedStyle() ? style() : nullptr;
    if (oldStyle) {
        // 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->usedZIndex() != newStyle->usedZIndex()
                || m_style->hasAutoUsedZIndex() != newStyle->hasAutoUsedZIndex();
#if ENABLE(DASHBOARD_SUPPORT)
            if (visibilityChanged)
                document().setDashboardRegionsDirty(true);
#endif

#if PLATFORM(IOS) && ENABLE(TOUCH_EVENTS)
        if (visibilityChanged)
            document().dirtyTouchEventRects();
#endif
#if HAVE(ACCESSIBILITY)
            if (visibilityChanged && AXObjectCache::accessibilityEnabled())
                document().axObjectCache()->childrenChanged(this);
#endif

            // 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 0
        auto needsInvalidateEventRegion = [&] {
            if (m_style->effectiveInert() != newStyle->effectiveInert())
                return true;
            if (m_style->pointerEvents() != newStyle->pointerEvents())
                return true;
#if ENABLE(TOUCH_ACTION_REGIONS)
            if (m_style.effectiveTouchActions() != newStyle.effectiveTouchActions())
                return true;
#endif
            if (m_style->eventListenerRegionTypes() != newStyle->eventListenerRegionTypes())
                return true;
#if ENABLE(EDITABLE_REGION)
            bool wasEditable = m_style.userModify() != UserModify::ReadOnly;
            bool isEditable = newStyle.userModify() != UserModify::ReadOnly;
            if (wasEditable != isEditable)
                return page().shouldBuildEditableRegion();
#endif
            return false;
        };

        if (needsInvalidateEventRegion()) {
            // Usually the event region gets updated as a result of paint invalidation. Here we need to request an update explicitly.
            if (auto* layer = enclosingLayer())
                layer->invalidateEventRegion(RenderLayer::EventRegionInvalidationReason::Style);
        }
#endif

        if (isFloating() && (m_style->floating() != newStyle->floating()))
            // For changes in float styles, we need to conceivably remove ourselves
            // from the floating objects list.
            toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();
        else if (isOutOfFlowPositioned() && (m_style->position() != newStyle->position()))
            // For changes in positioning styles, we need to conceivably remove ourselves
            // from the positioned objects list.
            toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists();

        // reset style flags
        if (diff == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) {
            setFloating(false);
            clearPositionedState();
        }

        setHorizontalWritingMode(true);
        setHasVisibleBoxDecorations(false);
        setHasNonVisibleOverflow(false);
        setHasTransformRelatedProperty(false);
        setHasReflection(false);
    }

    bool hadOutline = oldStyle && oldStyle->hasOutline();
    bool hasOutline = newStyle->hasOutline();
    if (hadOutline != hasOutline) {
        if (hasOutline)
            view().incrementRendersWithOutline();
        else
            view().decrementRendersWithOutline();
    }

    bool newStyleSlowScroll = false;
    if (newStyle->hasFixedBackgroundImage()&& !document().settings().fixedBackgroundsPaintRelativeToDocument()) {
        newStyleSlowScroll = true;
#if USE(ACCELERATED_COMPOSITING)
        bool drawsRootBackground = isDocumentElementRenderer() || (isBody() && !rendererHasBackground(document().documentElement()->renderer()));
        if (drawsRootBackground && newStyle->hasEntirelyFixedBackground() && view().compositor().supportsFixedRootBackgroundCompositing())
            newStyleSlowScroll = false;
#endif
    }

	if (view().frameView().hasSlowRepaintObject(*this)) {
		if (!newStyleSlowScroll)
			view().frameView().removeSlowRepaintObject(*this);
	} else if (newStyleSlowScroll)
		view().frameView().addSlowRepaintObject(*this);
}

#if !PLATFORM(IOS)
static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b)
{
    ASSERT(a->cursors() != b->cursors());
    return a->cursors() && b->cursors() && *a->cursors() == *b->cursors();
}

static inline bool areCursorsEqual(const RenderStyle* a, const RenderStyle* b)
{
    return a->cursor() == b->cursor() && (a->cursors() == b->cursors() || areNonIdenticalCursorListsEqual(a, b));
}
#endif

void RenderElement::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
{
	auto registerImages = [this](const RenderStyle* style, const RenderStyle* oldStyle) {
		if (!style && !oldStyle)
			return;
		updateFillImages(oldStyle ? &oldStyle->backgroundLayers() : nullptr, style ? &style->backgroundLayers() : nullptr);
		updateFillImages(oldStyle ? &oldStyle->maskLayers() : nullptr, style ? &style->maskLayers() : nullptr);
		updateImage(oldStyle ? oldStyle->borderImage().image() : nullptr, style ? style->borderImage().image() : nullptr);
		updateImage(oldStyle ? oldStyle->maskBoxImage().image() : nullptr, style ? style->maskBoxImage().image() : nullptr);
		updateShapeImage(oldStyle ? oldStyle->shapeOutside() : nullptr, style ? style->shapeOutside() : nullptr);
	};

	registerImages(style(), oldStyle);

	// Are there other pseudo-elements that need the resources to be registered?
	registerImages(style()->getCachedPseudoStyle(PseudoId::FirstLine), oldStyle ? oldStyle->getCachedPseudoStyle(PseudoId::FirstLine) : nullptr);

    SVGRenderSupport::styleChanged(*this, oldStyle);

    if (diff >= StyleDifferenceRepaint)
        updateReferencedSVGResources();

    if (!m_parent)
        return;

    if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) {
        RenderCounter::rendererStyleChanged(*this, oldStyle, *m_style);

        // If the object already needs layout, then setNeedsLayout won't do
        // any work. But if the containing block has changed, then we may need
        // to mark the new containing blocks for layout. The change that can
        // directly affect the containing block of this object is a change to
        // the position style.
        if (needsLayout() && oldStyle && oldStyle->position() != m_style->position())
            markContainingBlocksForLayout();

        if (diff == StyleDifferenceLayout)
            setNeedsLayoutAndPrefWidthsRecalc();
        else
            setNeedsSimplifiedNormalFlowLayout();
    } else if (diff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) {
        setNeedsPositionedMovementLayout(oldStyle);
        setNeedsSimplifiedNormalFlowLayout();
    } else if (diff == StyleDifferenceLayoutPositionedMovementOnly)
        setNeedsPositionedMovementLayout(oldStyle);

    // 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()).

#if !PLATFORM(IOS)
    if (oldStyle && !areCursorsEqual(oldStyle, style()))
        frame().eventHandler()->scheduleCursorUpdate();
#endif

    bool hadOutlineAuto = oldStyle && oldStyle->outlineStyleIsAuto();
    bool hasOutlineAuto = outlineStyleForRepaint()->outlineStyleIsAuto();
    if (hasOutlineAuto != hadOutlineAuto) {
        updateOutlineAutoAncestor(hasOutlineAuto);
        issueRepaintForOutlineAuto(hasOutlineAuto ? outlineStyleForRepaint()->outlineSize() : oldStyle->outlineSize());
    }
}

void RenderElement::insertedIntoTree(IsInternalMove isInternalMove)
{
    // 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* parentLayer = nullptr;
	if (firstChild() || hasLayer()) {
        if (auto* parentLayer = layerParent())
            addLayers(*this, *this, *parentLayer);
	}

    // If |this| is visible but this object was not, tell the layer it has some visible content
    // that needs to be drawn and layer visibility optimization can't be used
    if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
    	if (!parentLayer)
			parentLayer = layerParent();
		if (parentLayer)
			parentLayer->dirtyVisibleContentStatus();
    }

    RenderObject::insertedIntoTree(isInternalMove);
}

void RenderElement::willBeRemovedFromTree(IsInternalMove isInternalMove)
{
    // If we remove a visible child from an invisible parent, we don't know the layer visibility any more.
    if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) {
    	// FIXME: should get parent layer. Necessary?
		if (auto* enclosingLayer = parent()->enclosingLayer())
			enclosingLayer->dirtyVisibleContentStatus();
	}
    // Keep our layer hierarchy updated.
    if (firstChild() || hasLayer())
        removeLayers();

    if (isOutOfFlowPositioned() && parent()->childrenInline())
        parent()->dirtyLinesFromChangedChild(this);

    RenderObject::willBeRemovedFromTree(isInternalMove);
}

inline void RenderElement::clearSubtreeLayoutRootIfNeeded() const
{
    if (renderTreeBeingDestroyed())
        return;

    if (view().frameView().subtreeLayoutRoot() != this)
        return;

    // Normally when a renderer is detached from the tree, the appropriate dirty bits get set
    // which ensures that this renderer is no longer the layout root.
    ASSERT_NOT_REACHED();

    // This indicates a failure to layout the child, which is why
    // the layout root is still set to |this|. Make sure to clear it
    // since we are getting destroyed.
    view().frameView().clearSubtreeLayoutRoot();
}

void RenderElement::willBeDestroyed()
{
	if (m_style->hasFixedBackgroundImage() && !document().settings().fixedBackgroundsPaintRelativeToDocument())
		view().frameView().removeSlowRepaintObject(*this);

    if (hasCounterNodeMap())
        RenderCounter::destroyCounterNodes(*this);

    RenderObject::willBeDestroyed();

    clearSubtreeLayoutRootIfNeeded();

    auto unregisterImage = [this](StyleImage* image) {
        if (image)
            image->removeClient(*this);
    };

    auto unregisterImages = [&](const RenderStyle& style) {
        for (auto* backgroundLayer = &style.backgroundLayers(); backgroundLayer; backgroundLayer = backgroundLayer->next())
            unregisterImage(backgroundLayer->image());
        for (auto* maskLayer = &style.maskLayers(); maskLayer; maskLayer = maskLayer->next())
            unregisterImage(maskLayer->image());
        unregisterImage(style.borderImage().image());
        unregisterImage(style.maskBoxImage().image());
        if (auto* shapeValue = style.shapeOutside())
            unregisterImage(shapeValue->image());
    };

    if (hasInitializedStyle()) {
    	unregisterImages(*m_style);

        if (style()->hasOutline())
            view().decrementRendersWithOutline();

		if (auto* firstLineStyle = style()->getCachedPseudoStyle(PseudoId::FirstLine))
			unregisterImages(*firstLineStyle);
    }

    if (m_hasPausedImageAnimations)
        view().removeRendererWithPausedImageAnimations(*this);
}

static bool mustRepaintFillLayers(const RenderElement& renderer, const FillLayer& layer)
{
    // Nobody will use multiple layers without wanting fancy positioning.
    if (layer.next())
        return true;

    // Make sure we have a valid image.
    StyleImage* image = layer.image();
    if (!image || !image->canRender(&renderer, renderer.style()->effectiveZoom()))
        return false;

    if (!layer.xPosition().isZero() || !layer.yPosition().isZero())
        return true;

    EFillSizeType sizeType = layer.sizeType();

    if (sizeType == Contain || sizeType == Cover)
        return true;

    if (sizeType == SizeLength) {
        const LengthSize& size = layer.sizeLength();
        if (size.width().isPercentOrCalculated() || size.height().isPercentOrCalculated())
            return true;
        // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for 'contain'.
        if ((size.width().isAuto() || size.height().isAuto()) && image->isGeneratedImage())
            return true;
    } else if (image->usesImageContainerSize())
        return true;

    return false;
}

bool RenderElement::borderImageIsLoadedAndCanBeRendered() const
{
    ASSERT(style()->hasBorder());

    StyleImage* borderImage = style()->borderImage().image();
    return borderImage && borderImage->canRender(this, style()->effectiveZoom()) && borderImage->isLoaded(this);
}

bool RenderElement::mayCauseRepaintInsideViewport(const IntRect* optionalViewportRect) const
{
    auto& frameView = view().frameView();
    if (frameView.isOffscreen())
        return false;

    if (!hasNonVisibleOverflow()) {
        // FIXME: Computing the overflow rect is expensive if any descendant has
        // its own self-painting layer. As a result, we prefer to abort early in
        // this case and assume it may cause us to repaint inside the viewport.
        if (!hasLayer() || toRenderLayerModelObject(*this).layer()->firstChild())
            return true;
    }

    // Compute viewport rect if it was not provided.
    IntRect visibleRect = optionalViewportRect ? *optionalViewportRect : frameView.windowToContents(frameView.windowClipRect());
    return visibleRect.intersects(enclosingIntRect(absoluteClippedOverflowRect()));
}

static bool shouldRepaintForImageAnimation(const RenderElement& renderer, const IntRect& visibleRect)
{
    const Document& document = renderer.document();
    if (document.inPageCache())
        return false;
#if PLATFORM(IOS)
    if (frameView.timersPaused())
        return false;
#endif
    if (document.activeDOMObjectsAreSuspended())
        return false;
    if (renderer.style()->visibility() != VISIBLE)
        return false;
    if (renderer.view().frameView().isOffscreen())
        return false;

    // Use background rect if we are the root or if we are the body and the background is propagated to the root.
    // FIXME: This is overly conservative as the image may not be a background-image, in which case it will not
    // be propagated to the root. At this point, we unfortunately don't have access to the image anymore so we
    // can no longer check if it is a background image.
    bool backgroundIsPaintedByRoot = renderer.isDocumentElementRenderer() || (renderer.isBody() && !rendererHasBackground(renderer.document().documentElement()->renderer()));
    LayoutRect backgroundPaintingRect = backgroundIsPaintedByRoot ? renderer.view().backgroundRect(&renderer.view()) : renderer.absoluteClippedOverflowRect();
    if (!visibleRect.intersects(enclosingIntRect(backgroundPaintingRect)))
        return false;

    return true;
}

void RenderElement::newImageAnimationFrameAvailable(CachedImage& image, bool& canPause)
{
    if (document().inPageCache())
        return;
    auto& frameView = view().frameView();
    auto visibleRect = frameView.windowToContents(frameView.windowClipRect());
    if (!shouldRepaintForImageAnimation(*this, visibleRect)) {
        view().addRendererWithPausedImageAnimations(*this, image);
        canPause = true;
        return;
    }
    imageChanged(&image);
}

void RenderElement::notifyFinished(CachedResource* resource)
{
    document().cachedResourceLoader()->notifyFinished(*resource);
}

void RenderElement::didRemoveCachedImageClient(CachedImage& cachedImage)
{
    if (hasPausedImageAnimations())
        view().removeRendererWithPausedImageAnimations(*this, cachedImage);
}

void RenderElement::scheduleRenderingUpdate()
{
    if (auto* page = document().page())
        page->scheduleRenderingUpdate();
}

bool RenderElement::repaintForPausedImageAnimationsIfNeeded(const IntRect& visibleRect, CachedImage& cachedImage)
{
    ASSERT(m_hasPausedImageAnimations);
    if (!shouldRepaintForImageAnimation(*this, visibleRect))
        return false;

    repaint();

    if (auto* image = cachedImage.image()) {
        if ((*image).isSVGImage())
            static_cast<SVGImage&>(*image).scheduleStartAnimation();
        else
            image->startAnimation();
    }

#if USE(ACCELERATED_COMPOSITING)
    // For directly-composited animated GIFs it does not suffice to call repaint() to resume animation. We need to mark the image as changed.
    if ((*this).isBoxModelObject())
        toRenderBoxModelObject(*this).contentChanged(ImageChanged);
#endif

    return true;
}

static bool mustRepaintBackgroundOrBorder(const RenderElement& renderer)
{
    if (renderer.hasMask() && mustRepaintFillLayers(renderer, renderer.style()->maskLayers()))
        return true;

    // If we don't have a background/border/mask, then nothing to do.
    if (!renderer.hasVisibleBoxDecorations())
        return false;

    if (mustRepaintFillLayers(renderer, renderer.style()->backgroundLayers()))
        return true;

    // Our fill layers are ok.  Let's check border.
    if (renderer.style()->hasBorder() && renderer.borderImageIsLoadedAndCanBeRendered())
        return true;

    return false;
}

bool RenderElement::repaintAfterLayoutIfNeeded(RenderLayerModelObject* repaintContainer, const LayoutRect& oldClippedOverflowRect, const LayoutRect& oldOutlineAndBoxShadowBox, const LayoutRect* newClippedOverflowRectPtr, const LayoutRect* newOutlineAndBoxShadowBoxRectPtr)
{
    if (view().printing())
        return false; // Don't repaint if we're printing.

    // This ASSERT fails due to animations.  See https://bugs.webkit.org/show_bug.cgi?id=37048
    // ASSERT(!newClippedOverflowRectPtr || *newClippedOverflowRectPtr == clippedOverflowRectForRepaint(repaintContainer));
    LayoutRect newClippedOverflowRect = newClippedOverflowRectPtr ? *newClippedOverflowRectPtr : clippedOverflowRectForRepaint(repaintContainer);
    LayoutRect newOutlineAndBoxShadowBox;

    bool fullRepaint = selfNeedsLayout();

    if (!fullRepaint && oldClippedOverflowRect != newClippedOverflowRect && style()->hasBorderRadius()) {
		auto oldRadius = style()->getRoundedBorderFor(oldClippedOverflowRect).radii();
		auto newRadius = style()->getRoundedBorderFor(newClippedOverflowRect).radii();

		fullRepaint = oldRadius != newRadius;
	}

    if (!fullRepaint) {
        // This ASSERT fails due to animations.  See https://bugs.webkit.org/show_bug.cgi?id=37048
        // ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer));
    	newOutlineAndBoxShadowBox = newOutlineAndBoxShadowBoxRectPtr ? *newOutlineAndBoxShadowBoxRectPtr : outlineBoundsForRepaint(repaintContainer);
		fullRepaint = (newOutlineAndBoxShadowBox.location() != oldOutlineAndBoxShadowBox.location() || (mustRepaintBackgroundOrBorder(*this) && (newClippedOverflowRect != oldClippedOverflowRect || newOutlineAndBoxShadowBox != oldOutlineAndBoxShadowBox)));
	}

    if (!repaintContainer)
        repaintContainer = &view();

    if (fullRepaint) {
    	repaintUsingContainer(repaintContainer, oldClippedOverflowRect);
		if (newClippedOverflowRect != oldClippedOverflowRect)
			repaintUsingContainer(repaintContainer, newClippedOverflowRect);
		return true;
	}

    if (newClippedOverflowRect == oldClippedOverflowRect && newOutlineAndBoxShadowBox == oldOutlineAndBoxShadowBox)
		return false;

    if (newClippedOverflowRect.isEmpty() && !oldClippedOverflowRect.isEmpty())
        repaintUsingContainer(repaintContainer, oldClippedOverflowRect);
    else if (!newClippedOverflowRect.isEmpty() && oldClippedOverflowRect.isEmpty())
        repaintUsingContainer(repaintContainer, newClippedOverflowRect);
    else {
    	LayoutUnit deltaLeft = newClippedOverflowRect.x() - oldClippedOverflowRect.x();
		if (deltaLeft > 0)
			repaintUsingContainer(repaintContainer, LayoutRect(oldClippedOverflowRect.x(), oldClippedOverflowRect.y(), deltaLeft, oldClippedOverflowRect.height()));
		else if (deltaLeft < 0)
            repaintUsingContainer(repaintContainer, LayoutRect(newClippedOverflowRect.x(), newClippedOverflowRect.y(), -deltaLeft, newClippedOverflowRect.height()));

		LayoutUnit deltaRight = newClippedOverflowRect.maxX() - oldClippedOverflowRect.maxX();
		if (deltaRight > 0)
			repaintUsingContainer(repaintContainer, LayoutRect(oldClippedOverflowRect.maxX(), newClippedOverflowRect.y(), deltaRight, newClippedOverflowRect.height()));
		else if (deltaRight < 0)
            repaintUsingContainer(repaintContainer, LayoutRect(newClippedOverflowRect.maxX(), oldClippedOverflowRect.y(), -deltaRight, oldClippedOverflowRect.height()));

        LayoutUnit deltaTop = newClippedOverflowRect.y() - oldClippedOverflowRect.y();
		if (deltaTop > 0)
            repaintUsingContainer(repaintContainer, LayoutRect(oldClippedOverflowRect.x(), oldClippedOverflowRect.y(), oldClippedOverflowRect.width(), deltaTop));
		else if (deltaTop < 0)
            repaintUsingContainer(repaintContainer, LayoutRect(newClippedOverflowRect.x(), newClippedOverflowRect.y(), newClippedOverflowRect.width(), -deltaTop));

        LayoutUnit deltaBottom = newClippedOverflowRect.maxY() - oldClippedOverflowRect.maxY();
		if (deltaBottom > 0)
            repaintUsingContainer(repaintContainer, LayoutRect(newClippedOverflowRect.x(), oldClippedOverflowRect.maxY(), newClippedOverflowRect.width(), deltaBottom));
		else if (deltaBottom < 0)
            repaintUsingContainer(repaintContainer, LayoutRect(oldClippedOverflowRect.x(), newClippedOverflowRect.maxY(), oldClippedOverflowRect.width(), -deltaBottom));
    }

	if (newOutlineAndBoxShadowBox == oldOutlineAndBoxShadowBox)
		return false;

	// Let's figure out how much we need to repaint within the new bounds.
	// e.g. when renderer shrinks vertically it's not sufficient to repaint the "shrunk area" (to clear old content, see above) we need to take care of the area within the new bounds to make sure
	// decorations like border, outline etc get repainted as well (they are enclosed by old/new bounds).
	auto& outlineStyle = *outlineStyleForRepaint();
	auto& style = *this->style();
	auto outlineWidth = LayoutUnit(outlineStyle.outlineSize());
	auto insetShadowExtent = style.boxShadowInsetExtent();
	auto sizeDelta = LayoutSize(absoluteValue(newOutlineAndBoxShadowBox.width() - oldOutlineAndBoxShadowBox.width()), absoluteValue(newOutlineAndBoxShadowBox.height() - oldOutlineAndBoxShadowBox.height()));
	if (sizeDelta.width()) {
        auto shadowLeft = LayoutUnit { };
        auto shadowRight = LayoutUnit { };
        style.getBoxShadowHorizontalExtent(shadowLeft, shadowRight);

		auto insetExtent = [&] {
			// Inset "content" is inside the border box (e.g. border, negative outline and box shadow).
			auto borderRightExtent = [&]() -> LayoutUnit {
				if (!(*this).isBox())
					return { };
				auto& renderBox = toRenderBox(*this);
				auto borderBoxWidth = renderBox.width();
				return std::max(renderBox.borderRight(), std::max(valueForLength(style.borderTopRightRadius().width(), borderBoxWidth), valueForLength(style.borderBottomRightRadius().width(), borderBoxWidth)));
			};
			auto outlineRightInsetExtent = [&]() -> LayoutUnit {
				auto offset = LayoutUnit { outlineStyle.outlineOffset() };
				return offset < 0 ? -offset : LayoutUnit(0);
			};
			auto boxShadowRightInsetExtent = [&] {
                // Turn negative box shadow offset into inset.
                auto inset = std::min(insetShadowExtent.right(), shadowLeft);
				// Clip inset shadow at the clipped overflow rect. We would never paint outside.
				return inset < 0 ? std::min(-inset, std::min(newClippedOverflowRect.width(), oldClippedOverflowRect.width())) : LayoutUnit(0);
			};
			// Outline starts at the border box while box shadow starts at the padding box.
			return std::max(outlineRightInsetExtent(), borderRightExtent() + boxShadowRightInsetExtent());
		};
		auto outsetExtent = [&] {
			// Outset "content" is outside of the border box (e.g. regular outline and box shadow).
			return std::max(outlineWidth, shadowRight);
		};
		auto decorationRightExtent = insetExtent() + outsetExtent();
		// Both inset and outset "decorations" are within the "outline and box shadow" box.
		auto decorationLeft = newOutlineAndBoxShadowBox.x() + std::min(newOutlineAndBoxShadowBox.width(), oldOutlineAndBoxShadowBox.width()) - decorationRightExtent;
		auto clippedBoundsRight = std::min(newClippedOverflowRect.maxX(), oldClippedOverflowRect.maxX());
		auto damageExtentWithinClippedOverflow = clippedBoundsRight - decorationLeft;
		if (damageExtentWithinClippedOverflow > 0) {
			damageExtentWithinClippedOverflow = std::min(sizeDelta.width() + decorationRightExtent, damageExtentWithinClippedOverflow);
			auto damagedRect = LayoutRect { decorationLeft, newOutlineAndBoxShadowBox.y(), damageExtentWithinClippedOverflow, std::max(newOutlineAndBoxShadowBox.height(), oldOutlineAndBoxShadowBox.height()) };
			repaintUsingContainer(repaintContainer, damagedRect);
		}
	}
	if (sizeDelta.height()) {
        auto shadowTop = LayoutUnit { };
        auto shadowBottom = LayoutUnit { };
        style.getBoxShadowVerticalExtent(shadowTop, shadowBottom);

		auto insetExtent = [&] {
			// Inset "content" is inside the border box (e.g. border, negative outline and box shadow).
			auto borderBottomExtent = [&]() -> LayoutUnit {
				if (!(*this).isBox())
					return { };
				auto& renderBox = toRenderBox(*this);
				auto borderBoxHeight = renderBox.height();
				return std::max(renderBox.borderBottom(), std::max(valueForLength(style.borderBottomLeftRadius().height(), borderBoxHeight), valueForLength(style.borderBottomRightRadius().height(), borderBoxHeight)));
			};
			auto outlineBottomInsetExtent = [&]() -> LayoutUnit {
				auto offset = LayoutUnit { outlineStyle.outlineOffset() };
				return offset < 0 ? -offset : LayoutUnit(0);
			};
			auto boxShadowBottomInsetExtent = [&]() -> LayoutUnit {
				// Turn negative box shadow offset into inset.
				auto inset = std::min(insetShadowExtent.bottom(), shadowTop);
				// Clip inset shadow at the clipped overflow rect. We would never paint outside.
				return inset < 0 ? std::min(-inset, std::min(newClippedOverflowRect.height(), oldClippedOverflowRect.height())) : LayoutUnit(0);
			};
			// Outline starts at the border box while box shadow starts at the padding box.
			return std::max(outlineBottomInsetExtent(), borderBottomExtent() + boxShadowBottomInsetExtent());
		};
		auto outsetExtent = [&] {
			// Outset "content" is outside of the border box (e.g. regular outline and box shadow).
			return std::max(outlineWidth, shadowBottom);
		};
		auto decorationBottomExtent = insetExtent() + outsetExtent();
		// Both inset and outset "decorations" are within the "outline and box shadow" box.
		auto decorationTop = std::min(newOutlineAndBoxShadowBox.maxY(), oldOutlineAndBoxShadowBox.maxY()) - decorationBottomExtent;
		auto clippedBoundsBottom = std::min(newClippedOverflowRect.maxY(), oldClippedOverflowRect.maxY());
		auto damageExtentWithinClippedOverflow = clippedBoundsBottom - decorationTop;
		if (damageExtentWithinClippedOverflow > 0) {
			damageExtentWithinClippedOverflow = std::min(sizeDelta.height() + decorationBottomExtent, damageExtentWithinClippedOverflow);
			auto damagedRect = LayoutRect { newOutlineAndBoxShadowBox.x(), decorationTop, std::max(newOutlineAndBoxShadowBox.width(), oldOutlineAndBoxShadowBox.width()), damageExtentWithinClippedOverflow };
			repaintUsingContainer(repaintContainer, damagedRect);
		}
    }
    return false;
}

const RenderElement* RenderElement::enclosingRendererWithTextDecoration(TextDecoration textDecoration, bool firstLine) const
{
    const RenderElement* current = this;
    do {
        if (current->isRenderBlock())
            return current;
        if (!current->isRenderInline() || current->isRubyText())
            return 0;

        const RenderStyle& styleToUse = firstLine ? *current->firstLineStyle() : *current->style();
        if (styleToUse.textDecoration() & textDecoration)
            return current;
        current = current->parent();
    } while (current && (!current->element() || (!isHTMLAnchorElement(*current->element()) && !current->element()->hasTagName(HTMLNames::fontTag))));

    return current;
}

void RenderElement::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect)
{
    GraphicsContext* graphicsContext = paintInfo.context;
    if (graphicsContext->paintingDisabled())
        return;

    if (!hasOutline())
        return;

    auto* styleToUse = style();
    LayoutUnit outlineWidth = styleToUse->outlineWidth();

    int outlineOffset = styleToUse->outlineOffset();

    if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
        if (!theme()->supportsFocusRing(styleToUse)) {
            // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
            paintFocusRing(paintInfo, paintRect.location(), styleToUse);
        }
    }

    if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
        return;

    FloatRect outer = paintRect;
    outer.inflate(outlineOffset + outlineWidth);
    FloatRect inner = outer;
    inner.inflate(-outlineWidth);

    // FIXME: This prevents outlines from painting inside the object. See bug 12042
    if (outer.isEmpty())
        return;

    EBorderStyle outlineStyle = styleToUse->outlineStyle();
    Color outlineColor = styleToUse->visitedDependentColorWithColorFilter(CSSPropertyOutlineColor);

    bool useTransparencyLayer = outlineColor.hasAlpha();
    if (useTransparencyLayer) {
        if (outlineStyle == SOLID) {
            Path path;
            path.addRect(outer);
            path.addRect(inner);
            graphicsContext->setFillRule(RULE_EVENODD);
            graphicsContext->setFillColor(outlineColor);
            graphicsContext->fillPath(path);
            return;
        }
        graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
        outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
    }

    float leftOuter = outer.x();
    float leftInner = inner.x();
    float rightOuter = outer.maxX();
    float rightInner = std::min(inner.maxX(), rightOuter);
    float topOuter = outer.y();
    float topInner = inner.y();
    float bottomOuter = outer.maxY();
    float bottomInner = std::min(inner.maxY(), bottomOuter);

    drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(leftOuter, topOuter), FloatPoint(leftInner, bottomOuter)), BSLeft, outlineColor, outlineStyle, outlineWidth, outlineWidth);
    drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(leftOuter, topOuter), FloatPoint(rightOuter, topInner)), BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth);
    drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(rightInner, topOuter), FloatPoint(rightOuter, bottomOuter)), BSRight, outlineColor, outlineStyle, outlineWidth, outlineWidth);
    drawLineForBoxSide(graphicsContext, FloatRect(FloatPoint(leftOuter, bottomInner), FloatPoint(rightOuter, bottomOuter)), BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth);

    if (useTransparencyLayer)
        graphicsContext->endTransparencyLayer();
}

RenderStyle* RenderElement::getCachedPseudoStyle(PseudoId pseudo, const RenderStyle* parentStyle) const
{
    if (pseudo < PseudoId::FirstInternalPseudoId && !style()->hasPseudoStyle(pseudo))
        return nullptr;

    auto* cachedStyle = style()->getCachedPseudoStyle(pseudo);
    if (cachedStyle)
        return cachedStyle;

    OwnPtr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle);
    if (result)
        return const_cast<RenderStyle&>(*m_style).addCachedPseudoStyle(result.release());
    return nullptr;
}

PassOwnPtr<RenderStyle> RenderElement::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, const RenderStyle* parentStyle, const RenderStyle* ownStyle) const
{
    if (pseudoStyleRequest.pseudoId < PseudoId::FirstInternalPseudoId && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId))
        return nullptr;

    if (!parentStyle) {
        ASSERT(!ownStyle);
        parentStyle = style();
    }

    if (isAnonymous())
        return nullptr;

    auto& styleResolver = element()->styleResolver();

    OwnPtr<RenderStyle> style = styleResolver.pseudoStyleForElement(*element(), pseudoStyleRequest, Style::ResolutionContext(parentStyle));

    if (style)
        Style::loadPendingResources(*style, document(), element());

    return style.release();
}

Color RenderElement::selectionBackgroundColor() const
{
    if (style()->effectiveUserSelect() == SELECT_NONE)
    	return Color();

    if (document().selection().shouldShowBlockCursor() && document().selection().isCaret())
        return theme()->transformSelectionBackgroundColor(style()->visitedDependentColorWithColorFilter(CSSPropertyColor)/*, document().styleColorOptions()*/);

	OwnPtr<RenderStyle> pseudoStyle = selectionPseudoStyle();
	if (pseudoStyle && pseudoStyle->visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor).isValid())
		return theme()->transformSelectionBackgroundColor(pseudoStyle->visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor));

	if (document().selection().isFocusedAndActive())
		return theme()->activeSelectionBackgroundColor();
	return theme()->inactiveSelectionBackgroundColor();
}

Color RenderElement::selectionColor(CSSPropertyID colorProperty) const
{
    Color color;
    // If the element is unselectable, or we are only painting the selection,
    // don't override the foreground color with the selection foreground color.
    if (style()->effectiveUserSelect() == SELECT_NONE
        || (view().frameView().paintBehavior() & PaintBehaviorSelectionOnly))
        return color;

    if (OwnPtr<RenderStyle> pseudoStyle = selectionPseudoStyle()) {
        color = pseudoStyle->visitedDependentColorWithColorFilter(colorProperty);
        if (!color.isValid())
            color = pseudoStyle->visitedDependentColorWithColorFilter(CSSPropertyColor);
    } else
        color = document().selection().isFocusedAndActive() ?
                theme()->activeSelectionForegroundColor() :
                theme()->inactiveSelectionForegroundColor();

    return color;
}

PassOwnPtr<RenderStyle> RenderElement::selectionPseudoStyle() const
{
    if (isAnonymous())
        return nullptr;

    if (auto* root = m_node->containingShadowRoot()) {
        if (root->mode() == ShadowRootMode::UserAgent) {
            if (auto* shadowHost = m_node->shadowHost())
                return shadowHost->renderer()->getUncachedPseudoStyle(PseudoStyleRequest(PseudoId::Selection));
        }
    }

    return getUncachedPseudoStyle(PseudoStyleRequest(PseudoId::Selection));
}

Color RenderElement::selectionForegroundColor() const
{
    return selectionColor(CSSPropertyWebkitTextFillColor);
}

Color RenderElement::selectionEmphasisMarkColor() const
{
    return selectionColor(CSSPropertyWebkitTextEmphasisColor);
}

bool RenderElement::getLeadingCorner(FloatPoint& point) const
{
    if (!isInline() || isReplacedOrInlineBlock()) {
        point = localToAbsolute(FloatPoint(), UseTransforms);
        return true;
    }

    // find the next text/image child, to get a position
    const RenderObject* o = this;
    while (o) {
        const RenderObject* p = o;
        if (RenderObject* child = o->firstChildSlow())
            o = child;
        else if (o->nextSibling())
            o = o->nextSibling();
        else {
            RenderObject* next = 0;
            while (!next && o->parent()) {
                o = o->parent();
                next = o->nextSibling();
            }
            o = next;

            if (!o)
                break;
        }
        ASSERT(o);

        if (!o->isInline() || o->isReplacedOrInlineBlock()) {
            point = o->localToAbsolute(FloatPoint(), UseTransforms);
            return true;
        }

        if (p->node() && p->node() == element() && (*o).isText() && !toRenderText(*o).firstTextBox()) {
            // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor
        } else if ((*o).isText() || o->isReplacedOrInlineBlock()) {
            point = FloatPoint();
            if ((*o).isText() && toRenderText(*o).firstTextBox())
                point.move(toRenderText(*o).linesBoundingBox().x(), toRenderText(*o).topOfFirstText());
            else if ((*o).isBox())
                point.moveBy(toRenderBox(*o).location());
            point = o->container()->localToAbsolute(point, UseTransforms);
            return true;
        }
    }

    // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be
    // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling?
    if (!o && document().view()) {
        point = FloatPoint(0, document().view()->contentsHeight());
        return true;
    }
    return false;
}

bool RenderElement::getTrailingCorner(FloatPoint& point) const
{
    if (!isInline() || isReplacedOrInlineBlock()) {
        point = localToAbsolute(LayoutPoint(toRenderBox(*this).size()), UseTransforms);
        return true;
    }

    // find the last text/image child, to get a position
    const RenderObject* o = this;
    while (o) {
        if (RenderObject* child = o->lastChildSlow())
            o = child;
        else if (o->previousSibling())
            o = o->previousSibling();
        else {
            RenderObject* prev = 0;
            while (!prev) {
                o = o->parent();
                if (!o)
                    return false;
                prev = o->previousSibling();
            }
            o = prev;
        }
        ASSERT(o);
        if ((*o).isText() || o->isReplacedOrInlineBlock()) {
            point = FloatPoint();
            if ((*o).isText()) {
            	LayoutRect linesBox = toRenderText(*o).linesBoundingBox();
                if (!linesBox.maxX() && !linesBox.maxY())
                    continue;
                point.moveBy(linesBox.maxXMaxYCorner());
            } else
                point.moveBy(toRenderBox(*o).frameRect().maxXMaxYCorner());
            point = o->container()->localToAbsolute(point, UseTransforms);
            return true;
        }
    }
    return true;
}

LayoutRect RenderElement::anchorRect() const
{
    FloatPoint leading, trailing;
    bool foundLeading = getLeadingCorner(leading);
    bool foundTrailing = getTrailingCorner(trailing);

    // If we've found one corner, but not the other,
    // then we should just return a point at the corner that we did find.
    if (foundLeading != foundTrailing) {
        if (foundLeading)
            foundTrailing = foundLeading;
        else
            foundLeading = foundTrailing;
    }

    FloatPoint upperLeft = leading;
    FloatPoint lowerRight = trailing;

    // Vertical writing modes might mean the leading point is not in the top left
    if (!isInline() || isReplacedOrInlineBlock()) {
        upperLeft = FloatPoint(std::min(leading.x(), trailing.x()), std::min(leading.y(), trailing.y()));
        lowerRight = FloatPoint(std::max(leading.x(), trailing.x()), std::max(leading.y(), trailing.y()));
    } // Otherwise, it's not obvious what to do.

    return enclosingLayoutRect(FloatRect(upperLeft, lowerRight.expandedTo(upperLeft) - upperLeft));
}

void RenderElement::issueRepaintForOutlineAuto(float outlineSize)
{
    LayoutRect repaintRect;
    Vector<IntRect> focusRingRects;
    addFocusRingRects(focusRingRects, LayoutPoint(), containerForRepaint());
    for(int i = 0; i < focusRingRects.size(); ++i) {
    	IntRect rect = focusRingRects[i];
        rect.inflate(outlineSize);
        repaintRect.unite(rect);
    }
    repaintRectangle(repaintRect);
}

void RenderElement::updateOutlineAutoAncestor(bool hasOutlineAuto) const
{
    if ((*this).isRenderMultiColumnSpannerPlaceholder()) {
        if (auto* spanner = toRenderMultiColumnSpannerPlaceholder(*this).spanner()) {
        	spanner->setHasOutlineAutoAncestor(hasOutlineAuto);
        	spanner->updateOutlineAutoAncestor(hasOutlineAuto);
        }
    }
    for (auto* child = firstChild(); child; child = child->nextSibling()) {
        if (hasOutlineAuto == child->hasOutlineAutoAncestor())
            continue;
        child->setHasOutlineAutoAncestor(hasOutlineAuto);
        bool childHasOutlineAuto = child->outlineStyleForRepaint()->outlineStyleIsAuto();
        if (childHasOutlineAuto)
            continue;
        if (!child->isRenderElement())
            continue;
        toRenderElement(*child).updateOutlineAutoAncestor(hasOutlineAuto);
    }
    if ((*this).isBoxModelObject()) {
        if (auto* continuation = toRenderBoxModelObject(*this).continuation())
            continuation->updateOutlineAutoAncestor(hasOutlineAuto);
    }
}

bool RenderElement::hasOutlineAnnotation() const
{
#if ENABLE(PRINTING)
    return element() && element()->isLink() && document().printing();
#else
    return false;
#endif
}

bool RenderElement::hasSelfPaintingLayer() const
{
    if (!hasLayer())
        return false;
    auto& layerModelObject = toRenderLayerModelObject(*this);
    return layerModelObject.hasSelfPaintingLayer();
}

bool RenderElement::checkForRepaintDuringLayout() const
{
	return !document().view()->needsFullRepaint() && everHadLayout() && !hasSelfPaintingLayer();
}

void RenderElement::adjustFragmentedFlowStateOnContainingBlockChangeIfNeeded(const RenderStyle& oldStyle, const RenderStyle& newStyle)
{
    if (fragmentedFlowState() == NotInsideFragmentedFlow)
        return;

    // Make sure we invalidate the containing block cache for flows when the containing block context changes
    // so that styleDidChange can safely use RenderBlock::locateEnclosingFragmentedFlow()
    // FIXME: Share some code with RenderElement::canContain*.
    auto mayNotBeContainingBlockForDescendantsAnymore = oldStyle.position() != m_style->position()
        || oldStyle.hasTransformRelatedProperty() != m_style->hasTransformRelatedProperty()
        || oldStyle.willChange() != newStyle.willChange()
        || oldStyle.hasBackdropFilter() != newStyle.hasBackdropFilter()
        || oldStyle.containsLayout() != newStyle.containsLayout()
        || oldStyle.containsSize() != newStyle.containsSize();
    if (!mayNotBeContainingBlockForDescendantsAnymore)
        return;

    // Invalidate the containing block caches.
    if ((*this).isRenderBlock())
        toRenderBlock(*this).resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants();
    else {
        // Relatively positioned inline boxes can have absolutely positioned block descendants. We need to reset them as well.
        for (auto& descendant : descendantsOfType<RenderBlock>(*this))
			descendant.resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants();
	}

    // Adjust the flow tread state on the subtree.
    setFragmentedFlowState(RenderObject::computedFragmentedFlowState(*this));
    auto descendants = descendantsOfType<RenderObject>(*this);
    for (auto& descendant : descendantsOfType<RenderObject>(*this))
        descendant.setFragmentedFlowState(RenderObject::computedFragmentedFlowState(descendant));
}

void RenderElement::removeFromRenderFlowThread()
{
    ASSERT(fragmentedFlowState() != NotInsideFragmentedFlow);
    // Sometimes we remove the element from the flow, but it's not destroyed at that time.
    // It's only until later when we actually destroy it and remove all the children from it.
    // Currently, that happens for firstLetter elements and list markers.
    // Pass in the flow thread so that we don't have to look it up for all the children.
    removeFromRenderFlowThreadIncludingDescendants(true);
}

void RenderElement::removeFromRenderFlowThreadIncludingDescendants(bool shouldUpdateState)
{
    // Once we reach another flow thread we don't need to update the flow thread state
    // but we have to continue cleanup the flow thread info.
    if (isRenderFragmentedFlow())
        shouldUpdateState = false;

    for (auto& child : childrenOfType<RenderObject>(*this)) {
        if (child.isRenderElement()) {
            toRenderElement(child).removeFromRenderFlowThreadIncludingDescendants(shouldUpdateState);
            continue;
        }
        if (shouldUpdateState)
            child.setFragmentedFlowState(NotInsideFragmentedFlow);
    }

    // We have to ask for our containing flow thread as it may be above the removed sub-tree.
    RenderFragmentedFlow* enclosingFragmentedFlow = this->enclosingFragmentedFlow();
    while (enclosingFragmentedFlow) {
        enclosingFragmentedFlow->removeFlowChildInfo(*this);

        if (enclosingFragmentedFlow->fragmentedFlowState() == NotInsideFragmentedFlow)
            break;
        auto* parent = enclosingFragmentedFlow->parent();
        if (!parent)
            break;
        enclosingFragmentedFlow = parent->enclosingFragmentedFlow();
    }
    if ((*this).isRenderBlock())
        toRenderBlock(*this).setCachedEnclosingFragmentedFlowNeedsUpdate();

    if (shouldUpdateState)
        setFragmentedFlowState(NotInsideFragmentedFlow);
}

void RenderElement::resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants(RenderFragmentedFlow* fragmentedFlow)
{
    if (fragmentedFlow)
    	fragmentedFlow->removeFlowChildInfo(*this);

    for (auto& child : childrenOfType<RenderElement>(*this))
        child.resetEnclosingFragmentedFlowAndChildInfoIncludingDescendants(fragmentedFlow);
}

ReferencedSVGResources& RenderElement::ensureReferencedSVGResources()
{
    auto& rareData = ensureRareData();
    if (!rareData.referencedSVGResources)
        rareData.referencedSVGResources = adoptPtr(new ReferencedSVGResources(*this));

    return *rareData.referencedSVGResources;
}

void RenderElement::clearReferencedSVGResources()
{
    if (!hasRareData())
        return;

    ensureRareData().referencedSVGResources = nullptr;
}

// This needs to run when the entire render tree has been constructed, so can't be called from styleDidChange.
void RenderElement::updateReferencedSVGResources()
{
    auto referencedElementIDs = ReferencedSVGResources::referencedSVGResourceIDs(*style());
    if (!referencedElementIDs.isEmpty())
        ensureReferencedSVGResources().updateReferencedResources(treeScopeForSVGReferences(), referencedElementIDs);
    else
        clearReferencedSVGResources();
}

OwnPtr<RenderStyle> RenderElement::animatedStyle()
{
    OwnPtr<RenderStyle> result;

    if (auto* timeline = documentTimeline())
        result = timeline->animatedStyleForRenderer(*this);

    if (!result)
        result = RenderStyle::clonePtr(*style());

    return result;
}

WeakPtr<RenderBlockFlow> RenderElement::backdropRenderer() const
{
    return hasRareData() ? rareData().backdropRenderer : nullptr;
}

void RenderElement::setBackdropRenderer(RenderBlockFlow& renderer)
{
    ensureRareData().backdropRenderer = makeWeakPtr(renderer);
}

Overflow RenderElement::effectiveOverflowX() const
{
    auto overflowX = style()->overflowX();
    if (paintContainmentApplies() && overflowX == Overflow::Visible)
        return Overflow::Clip;
    return overflowX;
}

Overflow RenderElement::effectiveOverflowY() const
{
    auto overflowY = style()->overflowY();
    if (paintContainmentApplies() && overflowY == Overflow::Visible)
        return Overflow::Clip;
    return overflowY;
}

FloatRect RenderElement::referenceBoxRect(CSSBoxType boxType) const
{
    // CSS box model code is implemented in RenderBox::referenceBoxRect().

    // For the legacy SVG engine, RenderElement is the only class that's
    // present in the ancestor chain of all SVG renderers. In LBSE the
    // common class is RenderLayerModelObject. Once the legacy SVG engine
    // is removed this function should be moved to RenderLayerModelObject.
    // As this method is used by both SVG engines, we need to place it
    // here in RenderElement, as temporary solution.
    if (!isSVGElement(element()))
        return FloatRect();

    switch (boxType) {
    case CSSBoxType::BoxMissing:
    case CSSBoxType::ContentBox:
    case CSSBoxType::PaddingBox:
    case CSSBoxType::FillBox:
        return objectBoundingBox();
    case CSSBoxType::BorderBox:
    case CSSBoxType::MarginBox:
    case CSSBoxType::StrokeBox:
        return strokeBoundingBox();
    case CSSBoxType::ViewBox:
        // FIXME: [LBSE] Upstream: Cache the immutable SVGLengthContext per SVGElement, to avoid the repeated RenderSVGRoot size queries in determineViewport().
    	auto viewportSize = SVGLengthContext(toSVGElement(element())).viewportSize().value_or(FloatSize());
        return FloatRect(FloatPoint(), viewportSize);
    }

    ASSERT_NOT_REACHED();
    return FloatRect();
}

void RenderElement::markRendererDirtyAfterTopLayerChange(RenderElement* renderer, RenderBlock* containingBlockBeforeStyleResolution)
{
    auto* renderBox = dynamicDowncast<RenderBox>(renderer);
    if (!renderBox || !renderBox->parent() || !containingBlockBeforeStyleResolution)
        return;
    auto* newContainingBlock = renderBox->containingBlock();
    ASSERT(newContainingBlock);
    if (containingBlockBeforeStyleResolution == newContainingBlock)
        return;

    // Let's carry out the same set of tasks we would normally do when containing block changes for out-of-flow content in RenderBox::styleWillChange.
    if (!renderBox->isOutOfFlowPositioned())
        return;

    RenderBlock::removePositionedObject(*renderBox);
    // This is to make sure we insert the box to the correct containing block list during static position computation.
    renderBox->parent()->setChildNeedsLayout();
    newContainingBlock->setChildNeedsLayout();
    renderBox->setNeedsLayout();
}

}
