📄 render_layer.cpp
字号:
renderer()->hitTest(info, xMousePos, yMousePos,
layerBounds.x() - renderer()->xPos(),
layerBounds.y() - renderer()->yPos(), 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(),
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;
// 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;
// Check to see if the hovered node has changed. If not, then we don't need to
// do anything. An exception is if we just went from :hover into :hover:active,
// in which case we need to update to get the new :active state.
DOM::DocumentImpl* doc = renderer()->document();
DOM::NodeImpl* oldHoverNode = doc ? doc->hoverNode() : 0;
DOM::NodeImpl* newHoverNode = info.innerNode();
// Update our current hover node.
if (doc)
doc->setHoverNode(newHoverNode);
// We have two different objects. Fetch their renderers.
RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
// Locate the common ancestor render object for the two renderers.
RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
if (oldHoverObj != newHoverObj) {
// The old hover path only needs to be cleared up to (and not including) the common ancestor;
for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = hoverAncestor(curr)) {
curr->setMouseInside(false);
if (curr->element() && !curr->isText()) {
bool oldActive = curr->element()->active();
curr->element()->setActive(false);
if (curr->style()->affectedByHoverRules() ||
(curr->style()->affectedByActiveRules() && oldActive))
curr->element()->setChanged();
}
}
}
// Now set the hover state for our new object up to the root.
for (RenderObject* curr = newHoverObj; curr; curr = hoverAncestor(curr)) {
bool oldInside = curr->mouseInside();
curr->setMouseInside(true);
if (curr->element() && !curr->isText()) {
bool oldActive = curr->element()->active();
curr->element()->setActive(info.active());
if ((curr->style()->affectedByHoverRules() && !oldInside) ||
(curr->style()->affectedByActiveRules() && oldActive != info.active()))
curr->element()->setChanged();
}
}
}
// Sort the buffer from lowest z-index to highest. The common scenario will have
// most z-indices equal, so we optimize for that case (i.e., the list will be mostly
// sorted already).
static void sortByZOrder(QPtrVector<RenderLayer>* buffer,
QPtrVector<RenderLayer>* mergeBuffer,
uint start, uint end)
{
if (start >= end)
return; // Sanity check.
if (end - start <= 6) {
// Apply a bubble sort for smaller lists.
for (uint i = end-1; i > start; i--) {
bool sorted = true;
for (uint j = start; j < i; j++) {
RenderLayer* elt = buffer->at(j);
RenderLayer* elt2 = buffer->at(j+1);
if (elt->zIndex() > elt2->zIndex()) {
sorted = false;
buffer->insert(j, elt2);
buffer->insert(j+1, elt);
}
}
if (sorted)
return;
}
}
else {
// Peform a merge sort for larger lists.
uint mid = (start+end)/2;
sortByZOrder(buffer, mergeBuffer, start, mid);
sortByZOrder(buffer, mergeBuffer, mid, end);
RenderLayer* elt = buffer->at(mid-1);
RenderLayer* elt2 = buffer->at(mid);
// Handle the fast common case (of equal z-indices). The list may already
// be completely sorted.
if (elt->zIndex() <= elt2->zIndex())
return;
// We have to merge sort. Ensure our merge buffer is big enough to hold
// all the items.
mergeBuffer->resize(end - start);
uint i1 = start;
uint i2 = mid;
elt = buffer->at(i1);
elt2 = buffer->at(i2);
while (i1 < mid || i2 < end) {
if (i1 < mid && (i2 == end || elt->zIndex() <= elt2->zIndex())) {
mergeBuffer->insert(mergeBuffer->count(), elt);
i1++;
if (i1 < mid)
elt = buffer->at(i1);
}
else {
mergeBuffer->insert(mergeBuffer->count(), elt2);
i2++;
if (i2 < end)
elt2 = buffer->at(i2);
}
}
for (uint i = start; i < end; i++)
buffer->insert(i, mergeBuffer->at(i-start));
mergeBuffer->clear();
}
}
void RenderLayer::dirtyZOrderLists()
{
if (m_posZOrderList)
m_posZOrderList->clear();
if (m_negZOrderList)
m_negZOrderList->clear();
m_zOrderListsDirty = true;
}
void RenderLayer::updateZOrderLists()
{
if (!isStackingContext() || !m_zOrderListsDirty)
return;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->collectLayers(m_posZOrderList, m_negZOrderList);
// Sort the two lists.
if (m_posZOrderList) {
QPtrVector<RenderLayer> mergeBuffer;
sortByZOrder(m_posZOrderList, &mergeBuffer, 0, m_posZOrderList->count());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -