1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7 * Copyright (C) 2010, 2012 Google Inc. All rights reserved.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public License
20 * along with this library; see the file COPYING.LIB.  If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24
25#include "config.h"
26#include "core/rendering/RenderLayerModelObject.h"
27
28#include "core/frame/LocalFrame.h"
29#include "core/rendering/RenderLayer.h"
30#include "core/rendering/RenderView.h"
31#include "core/rendering/compositing/CompositedLayerMapping.h"
32
33namespace blink {
34
35bool RenderLayerModelObject::s_wasFloating = false;
36
37RenderLayerModelObject::RenderLayerModelObject(ContainerNode* node)
38    : RenderObject(node)
39{
40}
41
42RenderLayerModelObject::~RenderLayerModelObject()
43{
44    // Our layer should have been destroyed and cleared by now
45    ASSERT(!hasLayer());
46    ASSERT(!m_layer);
47}
48
49void RenderLayerModelObject::destroyLayer()
50{
51    setHasLayer(false);
52    m_layer = nullptr;
53}
54
55void RenderLayerModelObject::createLayer(LayerType type)
56{
57    ASSERT(!m_layer);
58    m_layer = adoptPtr(new RenderLayer(this, type));
59    setHasLayer(true);
60    m_layer->insertOnlyThisLayer();
61}
62
63bool RenderLayerModelObject::hasSelfPaintingLayer() const
64{
65    return m_layer && m_layer->isSelfPaintingLayer();
66}
67
68ScrollableArea* RenderLayerModelObject::scrollableArea() const
69{
70    return m_layer ? m_layer->scrollableArea() : 0;
71}
72
73void RenderLayerModelObject::willBeDestroyed()
74{
75    if (isPositioned()) {
76        // Don't use this->view() because the document's renderView has been set to 0 during destruction.
77        if (LocalFrame* frame = this->frame()) {
78            if (FrameView* frameView = frame->view()) {
79                if (style()->hasViewportConstrainedPosition())
80                    frameView->removeViewportConstrainedObject(this);
81            }
82        }
83    }
84
85    RenderObject::willBeDestroyed();
86
87    destroyLayer();
88}
89
90void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
91{
92    s_wasFloating = isFloating();
93
94    if (RenderStyle* oldStyle = style()) {
95        if (parent() && diff.needsPaintInvalidationLayer()) {
96            if (oldStyle->hasAutoClip() != newStyle.hasAutoClip()
97                || oldStyle->clip() != newStyle.clip())
98                layer()->clipper().clearClipRectsIncludingDescendants();
99        }
100    }
101
102    RenderObject::styleWillChange(diff, newStyle);
103}
104
105void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
106{
107    bool hadTransform = hasTransform();
108    bool hadLayer = hasLayer();
109    bool layerWasSelfPainting = hadLayer && layer()->isSelfPaintingLayer();
110
111    RenderObject::styleDidChange(diff, oldStyle);
112    updateFromStyle();
113
114    LayerType type = layerTypeRequired();
115    if (type != NoLayer) {
116        if (!layer() && layerCreationAllowedForSubtree()) {
117            if (s_wasFloating && isFloating())
118                setChildNeedsLayout();
119            createLayer(type);
120            if (parent() && !needsLayout()) {
121                // FIXME: We should call a specialized version of this function.
122                layer()->updateLayerPositionsAfterLayout();
123            }
124        }
125    } else if (layer() && layer()->parent()) {
126        setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit.
127        setHasReflection(false);
128        layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer
129        if (s_wasFloating && isFloating())
130            setChildNeedsLayout();
131        if (hadTransform)
132            setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation();
133    }
134
135    if (layer()) {
136        // FIXME: Ideally we shouldn't need this setter but we can't easily infer an overflow-only layer
137        // from the style.
138        layer()->setLayerType(type);
139
140        layer()->styleChanged(diff, oldStyle);
141        if (hadLayer && layer()->isSelfPaintingLayer() != layerWasSelfPainting)
142            setChildNeedsLayout();
143    }
144
145    if (FrameView *frameView = view()->frameView()) {
146        bool newStyleIsViewportConstained = style()->hasViewportConstrainedPosition();
147        bool oldStyleIsViewportConstrained = oldStyle && oldStyle->hasViewportConstrainedPosition();
148        if (newStyleIsViewportConstained != oldStyleIsViewportConstrained) {
149            if (newStyleIsViewportConstained && layer())
150                frameView->addViewportConstrainedObject(this);
151            else
152                frameView->removeViewportConstrainedObject(this);
153        }
154    }
155}
156
157void RenderLayerModelObject::addLayerHitTestRects(LayerHitTestRects& rects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
158{
159    if (hasLayer()) {
160        if (isRenderView()) {
161            // RenderView is handled with a special fast-path, but it needs to know the current layer.
162            RenderObject::addLayerHitTestRects(rects, layer(), LayoutPoint(), LayoutRect());
163        } else {
164            // Since a RenderObject never lives outside it's container RenderLayer, we can switch
165            // to marking entire layers instead. This may sometimes mark more than necessary (when
166            // a layer is made of disjoint objects) but in practice is a significant performance
167            // savings.
168            layer()->addLayerHitTestRects(rects);
169        }
170    } else {
171        RenderObject::addLayerHitTestRects(rects, currentLayer, layerOffset, containerRect);
172    }
173}
174
175void RenderLayerModelObject::invalidateTreeIfNeeded(const PaintInvalidationState& paintInvalidationState)
176{
177    ASSERT(!needsLayout());
178
179    if (!shouldCheckForPaintInvalidation(paintInvalidationState))
180        return;
181
182    bool establishesNewPaintInvalidationContainer = isPaintInvalidationContainer();
183    const RenderLayerModelObject& newPaintInvalidationContainer = *adjustCompositedContainerForSpecialAncestors(establishesNewPaintInvalidationContainer ? this : &paintInvalidationState.paintInvalidationContainer());
184    // FIXME: This assert should be re-enabled when we move paint invalidation to after compositing update. crbug.com/360286
185    // ASSERT(&newPaintInvalidationContainer == containerForPaintInvalidation());
186
187    InvalidationReason reason = invalidatePaintIfNeeded(paintInvalidationState, newPaintInvalidationContainer);
188    clearPaintInvalidationState(paintInvalidationState);
189
190    PaintInvalidationState childTreeWalkState(paintInvalidationState, *this, newPaintInvalidationContainer);
191    if (reason == InvalidationLocationChange || reason == InvalidationFull)
192        childTreeWalkState.setForceCheckForPaintInvalidation();
193    invalidatePaintOfSubtreesIfNeeded(childTreeWalkState);
194}
195
196void RenderLayerModelObject::setBackingNeedsPaintInvalidationInRect(const LayoutRect& r) const
197{
198    // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible crash here,
199    // so assert but check that the layer is composited.
200    ASSERT(compositingState() != NotComposited);
201
202    WebInvalidationDebugAnnotations annotations = WebInvalidationDebugAnnotationsNone;
203    if (!hadPaintInvalidation())
204        annotations = WebInvalidationDebugAnnotationsFirstPaint;
205    // FIXME: The callers assume they are calling a const function but this function has a side effect.
206    const_cast<RenderLayerModelObject*>(this)->setHadPaintInvalidation();
207
208    // FIXME: generalize accessors to backing GraphicsLayers so that this code is squashing-agnostic.
209    if (layer()->groupedMapping()) {
210        LayoutRect paintInvalidationRect = r;
211        if (GraphicsLayer* squashingLayer = layer()->groupedMapping()->squashingLayer()) {
212            // Note: the subpixel accumulation of layer() does not need to be added here. It is already taken into account.
213            squashingLayer->setNeedsDisplayInRect(pixelSnappedIntRect(paintInvalidationRect), annotations);
214        }
215    } else {
216        layer()->compositedLayerMapping()->setContentsNeedDisplayInRect(r, annotations);
217    }
218}
219
220} // namespace blink
221
222