1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2005 Allan Sandfeld Jensen (kde (at) carewolf.com) 5 * (C) 2005, 2006 Samuel Weinig (sam.weinig (at) 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/rendering/RenderLayer.h" 29 #include "core/rendering/RenderView.h" 30 31 using namespace std; 32 33 namespace WebCore { 34 35 bool RenderLayerModelObject::s_wasFloating = false; 36 bool RenderLayerModelObject::s_hadLayer = false; 37 bool RenderLayerModelObject::s_hadTransform = false; 38 bool RenderLayerModelObject::s_layerWasSelfPainting = false; 39 40 RenderLayerModelObject::RenderLayerModelObject(ContainerNode* node) 41 : RenderObject(node) 42 , m_layer(0) 43 { 44 } 45 46 RenderLayerModelObject::~RenderLayerModelObject() 47 { 48 // Our layer should have been destroyed and cleared by now 49 ASSERT(!hasLayer()); 50 ASSERT(!m_layer); 51 } 52 53 void RenderLayerModelObject::destroyLayer() 54 { 55 ASSERT(!hasLayer()); // Callers should have already called setHasLayer(false) 56 ASSERT(m_layer); 57 delete m_layer; 58 m_layer = 0; 59 } 60 61 void RenderLayerModelObject::ensureLayer() 62 { 63 if (m_layer) 64 return; 65 66 m_layer = new RenderLayer(this); 67 setHasLayer(true); 68 m_layer->insertOnlyThisLayer(); 69 } 70 71 bool RenderLayerModelObject::hasSelfPaintingLayer() const 72 { 73 return m_layer && m_layer->isSelfPaintingLayer(); 74 } 75 76 void RenderLayerModelObject::willBeDestroyed() 77 { 78 if (isPositioned()) { 79 // Don't use this->view() because the document's renderView has been set to 0 during destruction. 80 if (Frame* frame = this->frame()) { 81 if (FrameView* frameView = frame->view()) { 82 if (style()->hasViewportConstrainedPosition()) 83 frameView->removeViewportConstrainedObject(this); 84 } 85 } 86 } 87 88 // RenderObject::willBeDestroyed calls back to destroyLayer() for layer destruction 89 RenderObject::willBeDestroyed(); 90 } 91 92 void RenderLayerModelObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) 93 { 94 s_wasFloating = isFloating(); 95 s_hadLayer = hasLayer(); 96 s_hadTransform = hasTransform(); 97 if (s_hadLayer) 98 s_layerWasSelfPainting = layer()->isSelfPaintingLayer(); 99 100 // If our z-index changes value or our visibility changes, 101 // we need to dirty our stacking context's z-order list. 102 RenderStyle* oldStyle = style(); 103 if (oldStyle && newStyle) { 104 if (parent()) { 105 // Do a repaint with the old style first, e.g., for example if we go from 106 // having an outline to not having an outline. 107 if (diff == StyleDifferenceRepaintLayer) { 108 layer()->repaintIncludingDescendants(); 109 if (!(oldStyle->clip() == newStyle->clip())) 110 layer()->clearClipRectsIncludingDescendants(); 111 } else if (diff == StyleDifferenceRepaint || newStyle->outlineSize() < oldStyle->outlineSize()) 112 repaint(); 113 } 114 115 if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) { 116 // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could 117 // end up being destroyed. 118 if (hasLayer()) { 119 if (oldStyle->position() != newStyle->position() 120 || oldStyle->zIndex() != newStyle->zIndex() 121 || oldStyle->hasAutoZIndex() != newStyle->hasAutoZIndex() 122 || !(oldStyle->clip() == newStyle->clip()) 123 || oldStyle->hasClip() != newStyle->hasClip() 124 || oldStyle->opacity() != newStyle->opacity() 125 || oldStyle->transform() != newStyle->transform() 126 || oldStyle->filter() != newStyle->filter() 127 ) 128 layer()->repaintIncludingDescendants(); 129 } else if (newStyle->hasTransform() || newStyle->opacity() < 1 || newStyle->hasFilter()) { 130 // If we don't have a layer yet, but we are going to get one because of transform or opacity, 131 // then we need to repaint the old position of the object. 132 repaint(); 133 } 134 } 135 } 136 137 RenderObject::styleWillChange(diff, newStyle); 138 } 139 140 void RenderLayerModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 141 { 142 RenderObject::styleDidChange(diff, oldStyle); 143 updateFromStyle(); 144 145 if (requiresLayer()) { 146 if (!layer() && layerCreationAllowedForSubtree()) { 147 if (s_wasFloating && isFloating()) 148 setChildNeedsLayout(); 149 ensureLayer(); 150 if (parent() && !needsLayout() && containingBlock()) { 151 layer()->setRepaintStatus(NeedsFullRepaint); 152 // There is only one layer to update, it is not worth using |cachedOffset| since 153 // we are not sure the value will be used. 154 layer()->updateLayerPositions(0); 155 } 156 } 157 } else if (layer() && layer()->parent()) { 158 setHasTransform(false); // Either a transform wasn't specified or the object doesn't support transforms, so just null out the bit. 159 setHasReflection(false); 160 layer()->removeOnlyThisLayer(); // calls destroyLayer() which clears m_layer 161 if (s_wasFloating && isFloating()) 162 setChildNeedsLayout(); 163 if (s_hadTransform) 164 setNeedsLayoutAndPrefWidthsRecalc(); 165 } 166 167 if (layer()) { 168 layer()->styleChanged(diff, oldStyle); 169 if (s_hadLayer && layer()->isSelfPaintingLayer() != s_layerWasSelfPainting) 170 setChildNeedsLayout(); 171 } 172 173 if (FrameView *frameView = view()->frameView()) { 174 bool newStyleIsViewportConstained = style()->hasViewportConstrainedPosition(); 175 bool oldStyleIsViewportConstrained = oldStyle && oldStyle->hasViewportConstrainedPosition(); 176 if (newStyleIsViewportConstained != oldStyleIsViewportConstrained) { 177 if (newStyleIsViewportConstained && layer()) 178 frameView->addViewportConstrainedObject(this); 179 else 180 frameView->removeViewportConstrainedObject(this); 181 } 182 } 183 } 184 185 void RenderLayerModelObject::addLayerHitTestRects(LayerHitTestRects& rects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const 186 { 187 if (hasLayer()) { 188 if (isRenderView()) { 189 // RenderView is handled with a special fast-path, but it needs to know the current layer. 190 RenderObject::addLayerHitTestRects(rects, layer(), LayoutPoint(), LayoutRect()); 191 } else { 192 // Since a RenderObject never lives outside it's container RenderLayer, we can switch 193 // to marking entire layers instead. This may sometimes mark more than necessary (when 194 // a layer is made of disjoint objects) but in practice is a significant performance 195 // savings. 196 layer()->addLayerHitTestRects(rects); 197 } 198 } else { 199 RenderObject::addLayerHitTestRects(rects, currentLayer, layerOffset, containerRect); 200 } 201 } 202 203 } // namespace WebCore 204 205