static Node*
findLastFocusableNode(Frame* frame, const IntRect* specificRect)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    Node* node = frame->document()->lastChild();
    while (node) {
        if (!isNodeInSpecificRect(node, specificRect)) {
            node = node->traversePreviousNodePostOrder();
            continue;
        }
        if (node->isFrameOwnerElement()) {
            HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node);
            if (owner->contentFrame()) {
                node = findLastFocusableNode(owner->contentFrame(), specificRect);
                if (node)
                    break;
                node = owner;
            }
        } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) {
            node = node->lastChild();
        }
        if (node->isFocusable() && !node->isFrameOwnerElement()) {
            break;
        }
        node = node->traversePreviousNodePostOrder();
    }

    if (node) {
        return node->isFocusable() ? node : 0;
    }
    return 0;
}
Пример #2
0
NodePrivate::~NodePrivate()
{
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
    delete m_renderer;

    if (m_document)
        delete m_document;
    if (m_parentElement)
        delete m_parentElement;
    if (m_parent)
        delete m_parent;
    if (m_parentNode)
        delete m_parentNode;
    if (m_firstChild)
        delete m_firstChild;
    if (m_traverseNextNode)
        delete m_traverseNextNode;
    if (m_traverseNextSibling)
        delete m_traverseNextSibling;
    if (m_shadowHost)
        delete m_shadowHost;
    if (m_parentNamedNodeMap)
        delete m_parentNamedNodeMap;
    if (m_HTMLElement)
        delete m_HTMLElement;
    if (m_parentOrShadowHostElement)
        delete m_parentOrShadowHostElement;
    if (m_querySelectorElement)
        delete m_querySelectorElement;
}
void RenderView::repaintViewRectangle(const IntRect& ur, bool immediate)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    if (!shouldRepaint(ur))
        return;

    // We always just invalidate the root view, since we could be an iframe that is clipped out
    // or even invisible.
    Element* elt = document()->ownerElement();
    if (!elt)
        m_frameView->repaintContentRectangle(ur, immediate);
    else if (RenderBox* obj = elt->renderBox()) {
        IntRect vr = viewRect();
        IntRect r = intersection(ur, vr);
        
        // Subtract out the contentsX and contentsY offsets to get our coords within the viewing
        // rectangle.
        r.move(-vr.x(), -vr.y());
        
        // FIXME: Hardcoded offsets here are not good.
        r.move(obj->borderLeft() + obj->paddingLeft(),
               obj->borderTop() + obj->paddingTop());
        obj->repaintRectangle(r, immediate);
    }
}
void FocusController::findHorizontallyFocusableNodeInRect(FocusDirection direction, Node* start, KeyboardEvent* event, const IntRect* rect, Node** candidateNode, IntRect& candidateNodeRect)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
//    ASSERT(direction == FocusDirectionLeft || direction == FocusDirectionRight);
    if (!start)
        return ;

    Node* node = start;
    HTMLFrameOwnerElement* owner;
    Document* document;
    IntRect nodeRect;

    while (node) {
        if (!isNodeInSpecificRect(node, rect)) {
            node = getClosestNode(node, direction);
            continue;
        }
        owner = 0;
        if (node->isFrameOwnerElement()) {
            owner = static_cast<HTMLFrameOwnerElement*>(node);
            if (!owner->contentFrame()) {
                *candidateNode = 0;
                return;
            }
            document = owner->contentFrame()->document();
            findHorizontallyFocusableNodeInRect(direction, document, event, rect, candidateNode, candidateNodeRect);
        } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) {
            findHorizontallyFocusableNodeInRect(direction, node->firstChild(), event, rect, candidateNode, candidateNodeRect);
        } else {
            if (node->isFocusable() && !node->isFrameOwnerElement()) {
                nodeRect = node->renderer()->absoluteBoundingBoxRect();
                FrameView* frameView = node->document()->view();
                if (!frameView) {
                    *candidateNode = 0;
                    return;
                }                
                nodeRect = frameView->contentsToWindow(nodeRect);
                nodeRect.intersect(*rect);
                if (!nodeRect.isEmpty()) {
                    if (candidateNodeRect.isEmpty()) {
                        *candidateNode = node;
                        candidateNodeRect = nodeRect;
                    }
                    if (direction == FocusDirectionRight && candidateNodeRect.x() > nodeRect.x()) {
                        *candidateNode = node;
                        candidateNodeRect = nodeRect;
                    } else if (direction == FocusDirectionLeft && candidateNodeRect.x() < nodeRect.x()) {
                        *candidateNode = node;
                        candidateNodeRect = nodeRect;
                    }
                }
            }
        }
        node = getClosestNode(node, direction);
    }
}
void RenderView::paint(PaintInfo& paintInfo, int tx, int ty)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    // If we ever require layout but receive a paint anyway, something has gone horribly wrong.
    ASSERT(!needsLayout());

    // Cache the print rect because the dirty rect could get changed during painting.
    if (printing())
        setPrintRect(paintInfo.rect);
    else
        setPrintRect(IntRect());
    paintObject(paintInfo, tx, ty);
}
void RenderView::paintBoxDecorations(PaintInfo& paintInfo, int, int)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    // Check to see if we are enclosed by a layer that requires complex painting rules.  If so, we cannot blit
    // when scrolling, and we need to use slow repaints.  Examples of layers that require this are transparent layers,
    // layers with reflections, or transformed layers.
    // FIXME: This needs to be dynamic.  We should be able to go back to blitting if we ever stop being inside
    // a transform, transparency layer, etc.
    Element* elt;
    for (elt = document()->ownerElement(); view() && elt && elt->renderer(); elt = elt->document()->ownerElement()) {
        RenderLayer* layer = elt->renderer()->enclosingLayer();
        if (layer->requiresSlowRepaints()) {
            frameView()->setUseSlowRepaints();
            break;
        }
    }

    // If painting will entirely fill the view, no need to fill the background.
    if (elt || rendererObscuresBackground(firstChild()) || !view())
        return;

    // This code typically only executes if the root element's visibility has been set to hidden,
    // or there is a transform on the <html>.
    // Only fill with the base background color (typically white) if we're the root document, 
    // since iframes/frames with no background in the child document should show the parent's background.
    if (view()->isTransparent()) // FIXME: This needs to be dynamic.  We should be able to go back to blitting if we ever stop being transparent.
        frameView()->setUseSlowRepaints(); // The parent must show behind the child.
    else {
        Color baseColor = frameView()->baseBackgroundColor();
        if (baseColor.alpha() > 0) {
            paintInfo.context->save();
            paintInfo.context->setCompositeOperation(CompositeCopy);
            paintInfo.context->fillRect(paintInfo.rect, baseColor, style()->colorSpace());
            paintInfo.context->restore();
        } else
            paintInfo.context->clearRect(paintInfo.rect);
    }
}
Node* FocusController::findNextFocusableNodeInRect(const FocusDirection direction, Frame* frame, const IntRect* rect)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    ASSERT(frame);
    ASSERT(rect);

    Node* start;
    if (direction == FocusDirectionUp) {
        Node* last = 0;
        for (last = frame->document()->lastChild(); last && last->lastChild(); last = last->lastChild())
            ; // Empty loop.
        start = last;
    } else {
        ASSERT(direction == FocusDirectionDown || direction == FocusDirectionLeft || direction == FocusDirectionRight);
        start = frame->document()->firstChild();
    }

    frame->document()->updateLayoutIgnorePendingStylesheets();

    Node* node = 0;
    IntRect candidateNodeRect;
    switch (direction) {
    case FocusDirectionUp:
    case FocusDirectionDown:
        node = findVerticallyFocusableNodeInRect(direction, start, 0, rect);
        break;
    case FocusDirectionRight:
    case FocusDirectionLeft:
        findHorizontallyFocusableNodeInRect(direction, start, 0, rect, &node, candidateNodeRect);
        break;
    default:
        node = 0;
        break;
    }
    return node;
}
Node* FocusController::findNextFocusableNode(const FocusDirection direction, const IntRect* specificRect)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    Frame* frame = focusedOrMainFrame();
    ASSERT(frame);
    Document* focusedDocument = frame->document();
    if (!focusedDocument)
        return 0;

    focusedDocument->updateLayoutIgnorePendingStylesheets();

    Node* focusedNode = focusedDocument->focusedNode();
    if (!focusedNode) {
        if (direction == FocusDirectionUp) {
            return findLastFocusableNode(m_page->mainFrame(), specificRect);
        } else {
            return findFirstFocusableNode(m_page->mainFrame(), specificRect);
        }
    }

    frame = frame->tree()->top();

    FocusCandidate focusCandidate;
    findFocusableNodeInDirection(frame->document()->firstChild(), focusedNode, direction, 0, focusCandidate, FocusCandidate(), specificRect);

    Node* node = focusCandidate.node;
    if (!node || !node->isElementNode()) {
        return 0;
    }

    if (hasOffscreenRect(node)) {
        return 0;
    }

    return node;
}
Node* FocusController::findVerticallyFocusableNodeInRect(FocusDirection direction, Node* start, KeyboardEvent* event, const IntRect* rect)
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    ASSERT(direction == FocusDirectionUp || direction == FocusDirectionDown);
    if (!start)
        return 0;

    Node* node = start;
    HTMLFrameOwnerElement* owner;
    Document* document;

    while (node) {
        if (!isNodeInSpecificRect(node, rect)) {
            node = getClosestNode(node, direction);
            continue;
        }

        owner = 0;
        if (node->isFrameOwnerElement()) {
            owner = static_cast<HTMLFrameOwnerElement*>(node);
            if (!owner->contentFrame()) {
                node = 0;
                break;
            }
            document = owner->contentFrame()->document();
            if (direction == FocusDirectionUp) {
                node = findVerticallyFocusableNodeInRect(direction, document->lastChild(), event, rect);
            } else {
                node = findVerticallyFocusableNodeInRect(direction, document->firstChild(), event, rect);
            }
            if (node)
                break;
            node = getClosestNode(owner, direction);
            continue;
        } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) {
            Node* childNode = 0;
            if (direction == FocusDirectionUp) {
                childNode = findVerticallyFocusableNodeInRect(direction, node->lastChild(), event, rect);
            } else {
                ASSERT(direction == FocusDirectionDown);
                childNode = findVerticallyFocusableNodeInRect(direction, node->firstChild(), event, rect);
            }
            if (!childNode) {
                node = getClosestNode(node, direction, true);
                if (!node)
                    break;
            } else {
                node = childNode;
                break;
            }
        }

        if (node->isFocusable() && !node->isFrameOwnerElement()) {
            break;
        }
        if (owner) {
            node = owner;
        }
        node = getClosestNode(node, direction);
    }
    return node;
}
void FocusController::findFocusableNodeInDirection(Node* outer, Node* focusedNode,
                                                   FocusDirection direction, KeyboardEvent* event,
                                                   FocusCandidate& closest, const FocusCandidate& candidateParent)
#endif
{
#if PLATFORM(WKC)
    CRASH_IF_STACK_OVERFLOW(WKC_STACK_MARGIN_DEFAULT);
#endif
    ASSERT(outer);
    ASSERT(candidateParent.isNull()
        || candidateParent.node->isFrameOwnerElement()
        || isScrollableContainerNode(candidateParent.node));

    // Walk all the child nodes and update closest if we find a nearer node.
    Node* node = outer;
    while (node) {

        // Inner documents case.
        if (node->isFrameOwnerElement()) {
            deepFindFocusableNodeInDirection(node, focusedNode, direction, event, closest, specificRect);
        // Scrollable block elements (e.g. <div>, etc) case.
        } else if (isScrollableContainerNode(node) && !node->renderer()->isTextArea()) {
            deepFindFocusableNodeInDirection(node, focusedNode, direction, event, closest, specificRect);
            node = node->traverseNextSibling();
            continue;

#if PLATFORM(WKC)
        } else if (node != focusedNode && node->isFocusable() && isNodeInSpecificRect(node, specificRect)) {
#else
        } else if (node != focusedNode && node->isKeyboardFocusable(event)) {
#endif
            FocusCandidate candidate(node);

            // There are two ways to identify we are in a recursive call from deepFindFocusableNodeInDirection
            // (i.e. processing an element in an iframe, frame or a scrollable block element):

            // 1) If candidateParent is not null, and it holds the distance and alignment data of the
            // parent container element itself;
            // 2) Parent of outer is <frame> or <iframe>;
            // 3) Parent is any other scrollable block element.
            if (!candidateParent.isNull()) {
                candidate.parentAlignment = candidateParent.alignment;
                candidate.parentDistance = candidateParent.distance;
                candidate.enclosingScrollableBox = candidateParent.node;

            } else if (!isInRootDocument(outer)) {
#if PLATFORM(WKC)
                if (outer->parent() && outer->parent()->isDocumentNode()) {
                    Document* document = static_cast<Document*>(outer->parent());
                    candidate.enclosingScrollableBox = static_cast<Node*>(document->ownerElement());
                }
#else
                if (Document* document = static_cast<Document*>(outer->parent()))
                    candidate.enclosingScrollableBox = static_cast<Node*>(document->ownerElement());
#endif

            } else if (isScrollableContainerNode(outer->parent()))
                candidate.enclosingScrollableBox = outer->parent();

            // Get distance and alignment from current candidate.
            distanceDataForNode(direction, focusedNode, candidate);

            // Bail out if distance is maximum.
            if (candidate.distance == maxDistance()) {
                node = node->traverseNextNode(outer->parent());
                continue;
            }

            updateFocusCandidateIfCloser(focusedNode, candidate, closest);
        }

        node = node->traverseNextNode(outer->parent());
    }
}