📄 render_layer.cpp
字号:
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
// z-index. We paint after we painted the background/border, so that the scrollbars will
// sit above the background/border.
paintScrollbars(p, damageRect);
#endif
// Restore the clip.
restoreClip(p, paintDirtyRect, damageRect);
}
// Now walk the sorted list of children with negative z-indices.
if (m_negZOrderList) {
uint count = m_negZOrderList->count();
for (uint i = 0; i < count; i++) {
RenderLayer* child = m_negZOrderList->at(i);
child->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, selectionOnly, paintingRoot);
}
}
// Now establish the appropriate clip and paint our child RenderObjects.
if (shouldPaint && !clipRectToApply.isEmpty()) {
#if APPLE_CHANGES
// Begin transparency layers lazily now that we know we have to paint something.
if (haveTransparency)
beginTransparencyLayers(p);
#endif
// Set up the clip used when painting our children.
setClip(p, paintDirtyRect, clipRectToApply);
int tx = x - renderer()->xPos();
int ty = y - renderer()->yPos() + renderer()->borderTopExtra();
RenderObject::PaintInfo info(p, clipRectToApply,
selectionOnly ? PaintActionSelection : PaintActionChildBlockBackgrounds,
paintingRootForRenderer);
renderer()->paint(info, tx, ty);
if (!selectionOnly) {
info.phase = PaintActionFloat;
renderer()->paint(info, tx, ty);
info.phase = PaintActionForeground;
renderer()->paint(info, tx, ty);
info.phase = PaintActionOutline;
renderer()->paint(info, tx, ty);
}
// Now restore our clip.
restoreClip(p, paintDirtyRect, clipRectToApply);
}
// Now walk the sorted list of children with positive z-indices.
if (m_posZOrderList) {
uint count = m_posZOrderList->count();
for (uint i = 0; i < count; i++) {
RenderLayer* child = m_posZOrderList->at(i);
child->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, selectionOnly, paintingRoot);
}
}
#if APPLE_CHANGES
// End our transparency layer
if (isTransparent() && m_usedTransparency) {
p->endTransparencyLayer();
m_usedTransparency = false;
}
#endif
}
bool
RenderLayer::hitTest(RenderObject::NodeInfo& info, int x, int y)
{
#if APPLE_CHANGES
// Clear our our scrollbar variable
RenderLayer::gScrollBar = 0;
#endif
renderer()->document()->updateLayout();
QRect damageRect(m_x, m_y, width(), height());
RenderLayer* insideLayer = hitTestLayer(this, info, x, y, damageRect);
// Now determine if the result is inside an anchor; make sure an image map wins if
// it already set URLElement and only use the innermost.
NodeImpl* node = info.innerNode();
while (node) {
if (node->hasAnchor() && !info.URLElement())
info.setURLElement(node);
node = node->parentNode();
}
// 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;
}
RenderLayer*
RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
int xMousePos, int yMousePos, const QRect& hitTestRect)
{
// Calculate the clip rects we should use.
QRect layerBounds, bgRect, fgRect;
calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect);
// Ensure our z-order lists are up-to-date.
updateZOrderLists();
// This variable tracks which layer the mouse ends up being inside. The minute we find an insideLayer,
// we are done and can return it.
RenderLayer* insideLayer = 0;
// Begin by walking our list of positive layers from highest z-index down to the lowest
// z-index.
if (m_posZOrderList) {
uint count = m_posZOrderList->count();
for (int i = count-1; i >= 0; i--) {
RenderLayer* child = m_posZOrderList->at(i);
insideLayer = child->hitTestLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
if (insideLayer)
return insideLayer;
}
}
// Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
if (containsPoint(xMousePos, yMousePos, fgRect) &&
renderer()->hitTest(info, xMousePos, yMousePos,
layerBounds.x() - renderer()->xPos(),
layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(), HitTestDescendants)) {
// for positioned generated content, we might still not have a
// node by the time we get to the layer level, since none of
// the content in the layer has an element. So just walk up
// the tree.
if (!info.innerNode()) {
for (RenderObject *r = renderer(); r != NULL; r = r->parent()) {
if (r->element()) {
info.setInnerNode(r->element());
break;
}
}
}
if (!info.innerNonSharedNode()) {
for (RenderObject *r = renderer(); r != NULL; r = r->parent()) {
if (r->element()) {
info.setInnerNonSharedNode(r->element());
break;
}
}
}
return this;
}
// Now check our negative z-index children.
if (m_negZOrderList) {
uint count = m_negZOrderList->count();
for (int i = count-1; i >= 0; i--) {
RenderLayer* child = m_negZOrderList->at(i);
insideLayer = child->hitTestLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
if (insideLayer)
return insideLayer;
}
}
// Next we want to see if the mouse pos is inside this layer but not any of its children.
if (containsPoint(xMousePos, yMousePos, bgRect) &&
renderer()->hitTest(info, xMousePos, yMousePos,
layerBounds.x() - renderer()->xPos(),
layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
HitTestSelf))
return this;
// No luck.
return 0;
}
void RenderLayer::calculateClipRects(const RenderLayer* rootLayer)
{
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.
if (m_object->style()->position() == FIXED) {
posClipRect = fixedClipRect;
overflowClipRect = fixedClipRect;
}
else if (m_object->style()->position() == RELATIVE)
posClipRect = overflowClipRect;
else if (m_object->style()->position() == ABSOLUTE)
overflowClipRect = posClipRect;
// Update the clip rects that will be passed to child layers.
if (m_object->hasOverflowClip() || m_object->hasClip()) {
// This layer establishes a clip of some kind.
int x = 0;
int y = 0;
convertToLayerCoords(rootLayer, x, y);
if (m_object->hasOverflowClip()) {
QRect newOverflowClip = m_object->getOverflowClipRect(x,y);
overflowClipRect = newOverflowClip.intersect(overflowClipRect);
if (m_object->isPositioned() || m_object->isRelPositioned())
posClipRect = newOverflowClip.intersect(posClipRect);
}
if (m_object->hasClip()) {
QRect newPosClip = m_object->getClipRect(x,y);
posClipRect = posClipRect.intersect(newPosClip);
overflowClipRect = overflowClipRect.intersect(newPosClip);
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)
{
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());
// Update the clip rects that will be passed to child layers.
if (m_object->hasOverflowClip() || m_object->hasClip()) {
// This layer establishes a clip of some kind.
if (m_object->hasOverflowClip())
foregroundRect = foregroundRect.intersect(m_object->getOverflowClipRect(x,y));
if (m_object->hasClip()) {
// Clip applies to *us* as well, so go ahead and update the damageRect.
QRect newPosClip = m_object->getClipRect(x,y);
backgroundRect = backgroundRect.intersect(newPosClip);
foregroundRect = foregroundRect.intersect(newPosClip);
}
// If we establish a clip at all, then go ahead and make sure our background
// rect is intersected with our layer's bounds.
backgroundRect = backgroundRect.intersect(layerBounds);
}
}
static bool mustExamineRenderer(RenderObject* renderer)
{
if (renderer->isCanvas() || renderer->isRoot() || renderer->isInlineFlow())
return true;
QRect bbox = renderer->borderBox();
QRect overflowRect = renderer->overflowRect(false);
if (bbox != overflowRect)
return true;
QRect floatRect = renderer->floatRect();
if (bbox != floatRect)
return true;
return false;
}
bool RenderLayer::intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const
{
return mustExamineRenderer(renderer()) || layerBounds.intersects(damageRect);
}
bool RenderLayer::containsPoint(int x, int y, const QRect& damageRect) const
{
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)
{
return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent();
}
static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
{
if (!obj1 || !obj2)
return 0;
for (RenderObject* currObj1 = obj1; currObj1; currObj1 = hoverAncestor(currObj1))
for (RenderObject* currObj2 = obj2; currObj2; currObj2 = hoverAncestor(currObj2))
if (currObj1 == currObj2)
return currObj1;
return 0;
}
void RenderLayer::updateHoverActiveState(RenderObject::NodeInfo& info)
{
// We don't update :hover/:active state when the info is marked as readonly.
if (info.readonly())
return;
DocumentImpl* doc = renderer()->document();
if (!doc) return;
NodeImpl* activeNode = doc->activeNode();
if (activeNode && !info.active()) {
// We are clearing the :active chain because the mouse has been released.
for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
if (curr->element() && !curr->isText())
curr->element()->setInActiveChain(false);
}
doc->setActiveNode(0);
} else {
NodeImpl* newActiveNode = info.innerNode();
if (!activeNode && newActiveNode && info.active()) {
// We are setting the :active chain and freezing it. If future moves happen, they
// will need to reference this chain.
for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -