+2005-02-25 David Hyatt <hyatt@apple.com>
+
+ Fix for 3975039, scrolling is slow in huge RSS views. Optimize the calculation of clip rects for overflow:hidden
+ layers. Also optimize layer movement when scrolling overflow sections.
+
+ Reviewed by darin
+
+ * khtml/rendering/render_layer.cpp:
+ (throw):
+ (ClipRects::operator delete):
+ (ClipRects::detach):
+ (RenderLayer::RenderLayer):
+ (RenderLayer::~RenderLayer):
+ (RenderLayer::updateLayerPosition):
+ (RenderLayer::removeOnlyThisLayer):
+ (RenderLayer::insertOnlyThisLayer):
+ (RenderLayer::scrollToOffset):
+ (RenderLayer::hitTest):
+ (RenderLayer::calculateClipRects):
+ (RenderLayer::calculateRects):
+ (RenderLayer::containsPoint):
+ (RenderLayer::clearClipRects):
+ (RenderLayer::clearClipRect):
+ * khtml/rendering/render_layer.h:
+ (khtml::ClipRects::m_refCnt):
+ (khtml::ClipRects::overflowClipRect):
+ (khtml::ClipRects::fixedClipRect):
+ (khtml::ClipRects::posClipRect):
+ (khtml::ClipRects::ref):
+ (khtml::ClipRects::deref):
+ (khtml::RenderLayer::clipRects):
+ * khtml/rendering/render_object.cpp:
+ (RenderObject::setStyle):
+
2005-02-24 Maciej Stachowiak <mjs@apple.com>
Reviewed by Darin and Dave a while ago.
static bool inRenderLayerDetach;
#endif
+void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw()
+{
+ return renderArena->allocate(sz);
+}
+
+void ClipRects::operator delete(void* ptr, size_t sz)
+{
+ // Stash size where detach can find it.
+ *(size_t *)ptr = sz;
+}
+
+void ClipRects::detach(RenderArena* renderArena)
+{
+ delete this;
+
+ // Recover the size left there for us by operator delete and free the memory.
+ renderArena->free(*(size_t *)this, this);
+}
+
void
RenderScrollMediator::slotValueChanged(int val)
{
m_scrollMediator( 0 ),
m_posZOrderList( 0 ),
m_negZOrderList( 0 ),
+m_clipRects( 0 ) ,
m_scrollDimensionsDirty( true ),
m_zOrderListsDirty( true ),
m_usedTransparency( false ),
delete m_posZOrderList;
delete m_negZOrderList;
delete m_marquee;
+
+ // Make sure we have no lingering clip rects.
+ clearClipRect();
}
void RenderLayer::computeRepaintRects()
void RenderLayer::updateLayerPosition()
{
+ // Clear our cached clip rect information.
+ clearClipRect();
+
// The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we
// don't need to ever update our layer position here.
if (renderer()->isCanvas())
if (!m_parent)
return;
+ // Dirty the clip rects.
+ clearClipRects();
+
// Remove us from the parent.
RenderLayer* parent = m_parent;
RenderLayer* nextSib = nextSibling();
// Remove all descendant layers from the hierarchy and add them to the new position.
for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
curr->moveLayers(m_parent, this);
+
+ // Clear out all the clip rects.
+ clearClipRects();
}
void
// Update the positions of our child layers.
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
- child->updateLayerPositions();
+ child->updateLayerPositions(false, false);
#if APPLE_CHANGES
// Move our widgets.
// Next set up the correct :hover/:active state along the new chain.
updateHoverActiveState(info);
-
+
// Now return whether we were inside this layer (this will always be true for the root
// layer).
return insideLayer;
return 0;
}
-void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
- QRect& posClipRect, QRect& fixedClipRect)
+void RenderLayer::calculateClipRects(const RenderLayer* rootLayer)
{
- if (parent())
- parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
+ if (m_clipRects)
+ return; // We have the correct cached value.
+
+ if (!parent()) {
+ // The root layer's clip rect is always just its dimensions.
+ m_clipRects = new (m_object->renderArena()) ClipRects(QRect(0,0,width(),height()));
+ m_clipRects->ref();
+ return;
+ }
+
+ // Ensure that our parent's clip has been calculated so that we can examine the values.
+ parent()->calculateClipRects(rootLayer);
+
+ // Set up our three rects to initially match the parent rects.
+ QRect posClipRect(parent()->clipRects()->posClipRect());
+ QRect overflowClipRect(parent()->clipRects()->overflowClipRect());
+ QRect fixedClipRect(parent()->clipRects()->fixedClipRect());
// A fixed object is essentially the root of its containing block hierarchy, so when
// we encounter such an object, we reset our clip rects to the fixedClipRect.
fixedClipRect = fixedClipRect.intersect(newPosClip);
}
}
+
+ // If our clip rects match our parent's clip, then we can just share its data structure and
+ // ref count.
+ if (posClipRect == parent()->clipRects()->posClipRect() &&
+ overflowClipRect == parent()->clipRects()->overflowClipRect() &&
+ fixedClipRect == parent()->clipRects()->fixedClipRect())
+ m_clipRects = parent()->clipRects();
+ else
+ m_clipRects = new (m_object->renderArena()) ClipRects(overflowClipRect, fixedClipRect, posClipRect);
+ m_clipRects->ref();
}
void RenderLayer::calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
QRect& backgroundRect, QRect& foregroundRect)
{
- QRect overflowClipRect = paintDirtyRect;
- QRect posClipRect = paintDirtyRect;
- QRect fixedClipRect = paintDirtyRect;
- if (parent())
- parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
-
+ if (parent()) {
+ parent()->calculateClipRects(rootLayer);
+ backgroundRect = m_object->style()->position() == FIXED ? parent()->clipRects()->fixedClipRect() :
+ (m_object->isPositioned() ? parent()->clipRects()->posClipRect() :
+ parent()->clipRects()->overflowClipRect());
+ backgroundRect = backgroundRect.intersect(paintDirtyRect);
+ } else
+ backgroundRect = paintDirtyRect;
+ foregroundRect = backgroundRect;
+
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
layerBounds = QRect(x,y,width(),height());
-
- backgroundRect = m_object->style()->position() == FIXED ? fixedClipRect :
- (m_object->isPositioned() ? posClipRect : overflowClipRect);
- foregroundRect = backgroundRect;
// Update the clip rects that will be passed to child layers.
if (m_object->hasOverflowClip() || m_object->hasClip()) {
return mustExamineRenderer(renderer()) || damageRect.contains(x, y);
}
+void RenderLayer::clearClipRects()
+{
+ if (!m_clipRects)
+ return;
+
+ clearClipRect();
+
+ for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
+ l->clearClipRects();
+}
+
+void RenderLayer::clearClipRect()
+{
+ if (m_clipRects) {
+ m_clipRects->deref(m_object->renderArena());
+ m_clipRects = 0;
+ }
+}
+
// This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
// content (and perhaps XBL). That's why it uses the render tree and not the DOM tree.
static RenderObject* hoverAncestor(RenderObject* obj)
RenderLayer* m_layer;
};
+class ClipRects
+{
+public:
+ ClipRects(const QRect& r) :m_overflowClipRect(r), m_fixedClipRect(r), m_posClipRect(r), m_refCnt(0) {}
+ ClipRects(const QRect& o, const QRect& f, const QRect& p)
+ :m_overflowClipRect(o), m_fixedClipRect(f), m_posClipRect(p), m_refCnt(0) {}
+
+ const QRect& overflowClipRect() { return m_overflowClipRect; }
+ const QRect& fixedClipRect() { return m_fixedClipRect; }
+ const QRect& posClipRect() { return m_posClipRect; }
+
+ void ref() { m_refCnt++; }
+ void deref(RenderArena* renderArena) { if (--m_refCnt == 0) detach(renderArena); }
+
+ void detach(RenderArena* renderArena);
+
+ // Overloaded new operator.
+ void* operator new(size_t sz, RenderArena* renderArena) throw();
+
+ // Overridden to prevent the normal delete from being called.
+ void operator delete(void* ptr, size_t sz);
+
+private:
+ // The normal operator new is disallowed on all render objects.
+ void* operator new(size_t sz) throw();
+
+private:
+ QRect m_overflowClipRect;
+ QRect m_fixedClipRect;
+ QRect m_posClipRect;
+ uint m_refCnt;
+};
+
// This class handles the auto-scrolling of layers with overflow: marquee.
class Marquee: public QObject
{
void relativePositionOffset(int& relX, int& relY) {
relX += m_relX; relY += m_relY;
}
+
+ void clearClipRects();
+ void clearClipRect();
// Get the enclosing stacking context for this layer. A stacking context is a layer
// that has a non-auto z-index.
// for painting/event handling.
void calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
QRect& backgroundRect, QRect& foregroundRect);
- void calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
- QRect& posClipRect, QRect& fixedClipRect);
+ void calculateClipRects(const RenderLayer* rootLayer);
+ ClipRects* clipRects() const { return m_clipRects; }
bool intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const;
bool containsPoint(int x, int y, const QRect& damageRect) const;
RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
int x, int y, const QRect& hitTestRect);
void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0);
-
+
protected:
RenderObject* m_object;
QPtrVector<RenderLayer>* m_posZOrderList;
QPtrVector<RenderLayer>* m_negZOrderList;
+ ClipRects* m_clipRects; // Cached clip rects used when painting and hit testing.
+
bool m_scrollDimensionsDirty : 1;
bool m_zOrderListsDirty : 1;
+
#if APPLE_CHANGES
bool m_usedTransparency : 1; // Tracks whether we need to close a transparent layer, i.e., whether
// we ended up painting this layer or any descendants (and therefore need to