⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 render_layer.cpp

📁 手机浏览器源码程序,功能强大
💻 CPP
📖 第 1 页 / 共 5 页
字号:
        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 + -