📄 render_layer.cpp
字号:
// 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, selectionOnly); } }#ifdef BOX_DEBUG { int ax=0; int ay=0; renderer()->absolutePosition( ax, ay ); p->setPen(QPen(QColor("yellow"), 1, Qt::DotLine)); p->setBrush( Qt::NoBrush ); p->drawRect(ax, ay, width(), height()); }#endif#ifdef APPLE_CHANGES // End our transparency layer if (isTransparent()) p->endTransparencyLayer();#endif}bool RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y){#ifdef APPLE_CHANGES // Clear our our scrollbar variable RenderLayer::gScrollBar = 0;#endif int stx = m_x; int sty = m_y;#ifdef __GNUC__#warning HACK#endif if (renderer()->isCanvas()) { stx += static_cast<RenderCanvas*>(renderer())->view()->contentsX(); sty += static_cast<RenderCanvas*>(renderer())->view()->contentsY(); } QRect damageRect(stx,sty, width(), height()); RenderLayer* insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect); // Now determine if the result is inside an anchor. DOM::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::nodeAtPointForLayer(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->nodeAtPointForLayer(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()->nodeAtPoint(info, xMousePos, yMousePos, layerBounds.x() - renderer()->xPos(), layerBounds.y() - renderer()->yPos(), HitTestChildrenOnly)) { if (info.innerNode() != m_object->element()) 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->nodeAtPointForLayer(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()->nodeAtPoint(info, xMousePos, yMousePos, layerBounds.x() - renderer()->xPos(), layerBounds.y() - renderer()->yPos(), HitTestSelfOnly)) return this; // No luck. return 0;}void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect, QRect& posClipRect, QRect& fixedClipRect){ if (parent()) parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect); switch (m_object->style()->position()) { // 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. case FIXED: posClipRect = fixedClipRect; overflowClipRect = fixedClipRect; break; case ABSOLUTE: overflowClipRect = posClipRect; break; case RELATIVE: posClipRect = overflowClipRect; break; default: break; } // 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); } }}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); 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()) { // 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); }}bool RenderLayer::intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const{ return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() || (renderer()->hasOverhangingFloats() && !renderer()->hasOverflowClip()) || (renderer()->isInline() && !renderer()->isReplaced()) || layerBounds.intersects(damageRect));}bool RenderLayer::containsPoint(int x, int y, const QRect& damageRect) const{ return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() || renderer()->hasOverhangingFloats() || (renderer()->isInline() && !renderer()->isReplaced()) || damageRect.contains(x, y));}// 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::NodeImpl *e = m_object->element(); DOM::DocumentImpl *doc = e ? e->getDocument() : 0; if (!doc) return; DOM::NodeImpl* oldHoverNode = doc->hoverNode(); DOM::NodeImpl* newHoverNode = info.innerNode(); if (oldHoverNode == newHoverNode && (!oldHoverNode || oldHoverNode->active() == info.active())) return; // Update our current hover node. 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); // 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()) { bool oldActive = curr->element()->active(); curr->element()->NodeImpl::setActive(false); if (!curr->isText() && (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()) { bool oldActive = curr->element()->active(); curr->element()->NodeImpl::setActive(info.active()); if (!curr->isText() && (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()); } if (m_negZOrderList) { QPtrVector<RenderLayer> mergeBuffer; sortByZOrder(m_negZOrderList, &mergeBuffer, 0, m_negZOrderList->count()); } m_zOrderListsDirty = false;}void RenderLayer::collectLayers(QPtrVector<RenderLayer>*& posBuffer, QPtrVector<RenderLayer>*& negBuffer){ // FIXME: A child render object or layer could override visibility. Don't remove this // optimization though until RenderObject's nodeAtPoint is patched to understand what to do // when visibility is overridden by a child. if (renderer()->style()->visibility() != VISIBLE) return; // Determine which buffer the child should be in. QPtrVector<RenderLayer>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; // Create the buffer if it doesn't exist yet.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -