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

📄 dom_position.cpp

📁 最新Nokia手机浏览器全套源代码完美版。
💻 CPP
📖 第 1 页 / 共 3 页
字号:

    NodeImpl *fromRootEditableElement = node()->rootEditableElement();

    bool atEndOfLine = isLastVisiblePositionOnLine(VisiblePosition(*this, affinity));
    bool rendered = inRenderedContent();
    
    Position currentPos = *this;
    while (!currentPos.atEnd()) {
        currentPos = currentPos.next();

        if (currentPos.node()->rootEditableElement() != fromRootEditableElement)
            return *this;

        if (atEndOfLine || !rendered) {
            if (currentPos.inRenderedContent())
                return currentPos;
        } else if (rendersInDifferentPosition(currentPos))
            return currentPos;
    }
    
    return *this;
}

// upstream() and downstream() want to return positions that are either in a
// text node or at just before a non-text node.  This method checks for that.
static bool     isStreamer (Position pos)
{
    NodeImpl *currentNode = pos.node();
    if (!currentNode)
        return true;
        
    if (currentNode->isAtomicNode())
        return true;
        
    return (pos.offset() == 0);
}

// AFAIK no one has a clear, complete definition for this method and how it is used.
// Here is what I have come to understand from re-working the code after fixing PositionIterator
// for <rdar://problem/4103339>.  See also Ken's comments in the header.  Fundamentally, upstream()
// scans backward in the DOM starting at "this" to return a visible DOM position that is either in
// a text node, or just after a replaced or BR element (btw downstream() also considers empty blocks).
// If "stayInBlock" is specified, the search stops when it would have entered into a part of the DOM
// with a different enclosing block, including a nested one.  Otherwise, the search stops at the start
// of the entire DOM tree.  If "stayInBlock" stops the search, this method returns the highest previous
// position that is either in an atomic node (i.e. text) or is the end of a non-atomic node
// (_regardless_ of visibility).  If the end-of-DOM stopped the search, this method returns the 
// highest previous visible node that is either in an atomic node (i.e. text) or is the end of a
// non-atomic node.
Position Position::upstream(EStayInBlock stayInBlock) const
{
    // start at equivalent deep position
    Position start = equivalentDeepPosition();
    NodeImpl *startNode = start.node();
    if (!startNode)
        return Position();
    
    // iterate backward from there, looking for a qualified position
    NodeImpl *block = stayInBlock ? startNode->enclosingBlockFlowOrTableElement() : 0;
    Position lastVisible = *this;
    Position lastStreamer = *this;
    Position currentPos = start;
    for (; !currentPos.atStart(); currentPos = currentPos.previous()) {
        NodeImpl *currentNode = currentPos.node();
        int currentOffset = currentPos.offset();

        // limit traversal to block or table enclosing the original element
        // NOTE: This includes not going into nested blocks
        if (stayInBlock && block != currentNode->enclosingBlockFlowOrTableElement())
            return lastStreamer;

        // track last streamer position (regardless of visibility)
        if (isStreamer(currentPos))
            lastStreamer = currentPos;

        // skip position in unrendered or invisible node
        RenderObject *renderer = currentNode->renderer();
        if (!renderer || renderer->style()->visibility() != VISIBLE)
            continue;

        // track last visible streamer position
        if (isStreamer(currentPos))
            lastVisible = currentPos;

        // return position after replaced or BR elements
        if (renderer->isReplaced() || renderer->isBR()) {
            if (currentOffset >= renderer->caretMaxOffset())
                return Position(currentNode, renderer->caretMaxOffset());

            // we could not have iterated here because we would have returned
            // this node, caretMaxOffset, so we must have started here
//            assert(currentPos == start);
            continue;
        }

        // return current position if it is in rendered text
        if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
            if (currentNode != startNode) {
                assert(currentOffset >= renderer->caretMaxOffset());
                return Position(currentNode, renderer->caretMaxOffset());
            }

            if (currentOffset < 0)
                continue;

            uint textOffset = currentOffset;
            RenderText *textRenderer = static_cast<RenderText *>(renderer);
            for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
                if (textOffset > box->start() && textOffset <= box->start() + box->len())
                    return currentPos;
                    
                if (box != textRenderer->lastTextBox() && 
                    !box->nextOnLine() && 
                    textOffset == box->start() + box->len() + 1)
                    return currentPos;
            }
        }
    }

    return lastVisible;
}

// AFAIK no one has a clear, complete definition for this method and how it is used.
// Here is what I have come to understand from re-working the code after fixing PositionIterator
// for <rdar://problem/4103339>.  See also Ken's comments in the header.  Fundamentally, downstream()
// scans forward in the DOM starting at "this" to return the first visible DOM position that is
// either in a text node, or just before a replaced, BR element, or empty block flow element (i.e.
// non-text nodes with no children).  If "stayInBlock" is specified, the search stops when it would
// have entered into a part of the DOM with a different enclosing block, including a nested one.
// Otherwise, the search stops at the end of the entire DOM tree.  If "stayInBlock" stops the search,
// this method returns the first previous position that is either in an atomic node (i.e. text) or is
// at offset 0 (_regardless_ of visibility).  If the end-of-DOM stopped the search, this method returns
// the first previous visible node that is either in an atomic node (i.e. text) or is at offset 0.
Position Position::downstream(EStayInBlock stayInBlock) const
{
    // start at equivalent deep position
    Position start = equivalentDeepPosition();
    NodeImpl *startNode = start.node();
    if (!startNode)
        return Position();

    // iterate forward from there, looking for a qualified position
    NodeImpl *block = stayInBlock ? startNode->enclosingBlockFlowOrTableElement() : 0;
    Position lastVisible = *this;
    Position lastStreamer = *this;
    Position currentPos = start;
    for (; !currentPos.atEnd(); currentPos = currentPos.next()) {   
        NodeImpl *currentNode = currentPos.node();
        int currentOffset = currentPos.offset();

        // stop before going above the body, up into the head
        // return the last visible streamer position
        if (currentNode->id() == ID_BODY && currentOffset >= (int) currentNode->childNodeCount())
            break;
            
        // limit traversal to block or table enclosing the original element
        // return the last streamer position regardless of visibility
        // NOTE: This includes not going into nested blocks
        if (stayInBlock && block != currentNode->enclosingBlockFlowOrTableElement())
            return lastStreamer;
        
        // track last streamer position (regardless of visibility)
        if (isStreamer(currentPos))
            lastStreamer = currentPos;

        // skip position in unrendered or invisible node
        RenderObject *renderer = currentNode->renderer();
        if (!renderer || renderer->style()->visibility() != VISIBLE)
            continue;
        
        // track last visible streamer position
        if (isStreamer(currentPos))
            lastVisible = currentPos;

        // if now at a offset 0 of a rendered block flow element...
        //      - return current position if the element has no children (i.e. is a leaf)
        //      - return child node, offset 0, if the first visible child is not a block flow element
        //      - otherwise, skip this position (first visible child is a block, and we will
        //          get there eventually via the iterator)
        if ((currentNode != startNode && renderer->isBlockFlow()) && (currentOffset == 0)) {
            if (!currentNode->firstChild())
                return currentPos;
                
            for (NodeImpl *child = currentNode->firstChild(); child; child = child->nextSibling()) {
                RenderObject *r = child->renderer();
                if (r && r->style()->visibility() == VISIBLE) {
                    if (r->isBlockFlow())
                        break; // break causes continue code below to run.

                    return Position(child, 0);
                }
            }

            continue;
        }

        // return position before replaced or BR elements
        if (renderer->isReplaced() || renderer->isBR()) {
            if (currentOffset <= renderer->caretMinOffset())
                return Position(currentNode, renderer->caretMinOffset());
            
            // we could not have iterated here because we would have returned
            // this node, offset 0, so we must have started here
//            assert(currentPos == start);
            continue;
        }

        // return current position if it is in rendered text
        if (renderer->isText() && static_cast<RenderText *>(renderer)->firstTextBox()) {
            if (currentNode != startNode) {
                assert(currentOffset == 0);
                return Position(currentNode, renderer->caretMinOffset());
            }

            if (currentOffset < 0)
                continue;

            uint textOffset = currentOffset;

            RenderText *textRenderer = static_cast<RenderText *>(renderer);
            for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) {
                if (textOffset >= box->start() && textOffset <= box->end())
                    return currentPos;
                
                if (box != textRenderer->lastTextBox() && 
                     !box->nextOnLine() && 
                     textOffset == box->start() + box->len()) {
                    return currentPos;
                }
            }
        }
    }
    
    return lastVisible;
}

Position Position::equivalentRangeCompliantPosition() const
{
    if (isNull())
        return Position();

    // Make sure that 0 <= constrainedOffset <= num kids, otherwise using this Position
    // in DOM calls can result in exceptions.
    long maxOffset = node()->isTextNode() ? static_cast<TextImpl *>(node())->length(): node()->childNodeCount();
    long constrainedOffset = offset() <= 0 ? 0 : kMin(maxOffset, offset());

    if (!node()->parentNode())
        return Position(node(), constrainedOffset);

    RenderObject *renderer = node()->renderer();
    if (!renderer)
        return Position(node(), constrainedOffset);
        
    if (!renderer->isReplaced() && !renderer->isBR())
        return Position(node(), constrainedOffset);
    
    long o = offset();
    const NodeImpl *n = node();
    while ((n = n->previousSibling()))
        o++;
    
    // Make sure that 0 <= constrainedOffset <= num kids, as above.
    NodeImpl *parent = node()->parentNode();
    maxOffset = parent->isTextNode() ? static_cast<TextImpl *>(parent)->length(): parent->childNodeCount();
    constrainedOffset = o <= 0 ? 0 : kMin(maxOffset, o);
    return Position(parent, constrainedOffset);
}

Position Position::equivalentDeepPosition() const
{
    if (isNull() || node()->isAtomicNode())
        return *this;

    NodeImpl *child = 0;
    Position pos(*this);
    if (offset() >= (int)node()->childNodeCount()) {
        child = node()->lastChild();
        pos = Position(child, child->caretMaxOffset());
        ASSERT(child);
        while (!child->isAtomicNode() && pos.node()->hasChildNodes()) {
            child = pos.node()->lastChild();
            ASSERT(child);
            pos = Position(child, child->caretMaxOffset());
        }
    }
    else {
        child = node()->childNode(offset());
        ASSERT(child);
        pos = Position(child, 0);
        while (!child->isAtomicNode() && pos.node()->hasChildNodes()) {
            child = pos.node()->firstChild();
            ASSERT(child);
            pos = Position(child, 0);
        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -