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

📄 visible_text.cpp

📁 手机浏览器源码程序,功能强大
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        case ID_TR:
        case ID_UL:
            if (m_lastCharacter != '\n' && m_lastTextNode) {
                emitCharacter('\n', m_lastTextNode->parentNode(), m_lastTextNode, 0, 1);
            }
            break;
    }

    return true;
}

void TextIterator::exitNode()
{
    bool endLine = false;
    bool addNewline = false;

    switch (m_node->id()) {
        case ID_BLOCKQUOTE:
        case ID_DD:
        case ID_DIV:
        case ID_DL:
        case ID_DT:
        case ID_HR:
        case ID_LI:
        case ID_OL:
        case ID_PRE:
        case ID_TR:
        case ID_UL:
            endLine = true;
            break;

        case ID_H1:
        case ID_H2:
        case ID_H3:
        case ID_H4:
        case ID_H5:
        case ID_H6:
        case ID_P: {
            endLine = true;

            // In certain cases, emit a new newline character for this node
            // regardless of whether we emit another one.
            // FIXME: Some day we could do this for other tags.
            // However, doing it just for the tags above makes it more likely
            // we'll end up getting the right result without margin collapsing.
            // For example: <div><p>text</p></div> will work right even if both
            // the <div> and the <p> have bottom margins.
            RenderObject *renderer = m_node->renderer();
            if (renderer) {
                RenderStyle *style = renderer->style();
                if (style) {
                    int bottomMargin = renderer->collapsedMarginBottom();
                    int fontSize = style->htmlFont().getFontDef().computedPixelSize();
                    if (bottomMargin * 2 >= fontSize) {
                        addNewline = true;
                    }
                }
            }
            break;
        }
    }

    // emit character(s) iff there is an earlier text node and we need at least one newline
    if (m_lastTextNode && endLine) {
        if (m_lastCharacter != '\n') {
            // insert a newline with a position following this block
            emitCharacter('\n', m_node->parentNode(), m_node, 1, 1);

            //...and, if needed, set flag to later add a newline for the current node
            assert(!m_needAnotherNewline);
            m_needAnotherNewline = addNewline;
        } else if (addNewline) {
            // insert a newline with a position following this block
            emitCharacter('\n', m_node->parentNode(), m_node, 1, 1);
        }
    }
}

void TextIterator::emitCharacter(QChar c, NodeImpl *textNode, NodeImpl *offsetBaseNode, long textStartOffset, long textEndOffset)
{
    // remember information with which to construct the TextIterator::range()
    // NOTE: textNode is often not a text node, so the range will specify child nodes of positionNode
    m_positionNode = textNode;
    m_positionOffsetBaseNode = offsetBaseNode;
    m_positionStartOffset = textStartOffset;
    m_positionEndOffset = textEndOffset;
 
    // remember information with which to construct the TextIterator::characters() and length()
    m_singleCharacterBuffer = c;
    m_textCharacters = &m_singleCharacterBuffer;
    m_textLength = 1;

    // remember some iteration state
    m_lastTextNodeEndedWithCollapsedSpace = false;
    m_lastCharacter = c;
}

Range TextIterator::range() const
{
    // use the current run information, if we have it
    if (m_positionNode) {
        if (m_positionOffsetBaseNode) {
            long index = m_positionOffsetBaseNode->nodeIndex();
            m_positionStartOffset += index;
            m_positionEndOffset += index;
            m_positionOffsetBaseNode = 0;
        }
        return Range(m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
    }

    // otherwise, return the end of the overall range we were given
    if (m_endContainer)
        return Range(m_endContainer, m_endOffset, m_endContainer, m_endOffset);
        
    return Range();
}

SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator() : m_positionNode(0)
{
}

SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range &r)
{
    if (r.isNull()) {
        m_positionNode = 0;
        return;
    }

    NodeImpl *startNode = r.startContainer().handle();
    NodeImpl *endNode = r.endContainer().handle();
    long startOffset = r.startOffset();
    long endOffset = r.endOffset();

    if (!offsetInCharacters(startNode->nodeType())) {
        if (startOffset >= 0 && startOffset < static_cast<long>(startNode->childNodeCount())) {
            startNode = startNode->childNode(startOffset);
            startOffset = 0;
        }
    }
    if (!offsetInCharacters(endNode->nodeType())) {
        if (endOffset > 0 && endOffset <= static_cast<long>(endNode->childNodeCount())) {
            endNode = endNode->childNode(endOffset - 1);
            endOffset = endNode->hasChildNodes() ? endNode->childNodeCount() : endNode->maxOffset();
        }
    }

    m_node = endNode;
    m_offset = endOffset;
    m_handledNode = false;
    m_handledChildren = endOffset == 0;

    m_startNode = startNode;
    m_startOffset = startOffset;

#ifndef NDEBUG
    // Need this just because of the assert.
    m_positionNode = endNode;
#endif

    m_lastTextNode = 0;
    m_lastCharacter = '\n';

    advance();
}

void SimplifiedBackwardsTextIterator::advance()
{
    assert(m_positionNode);

    m_positionNode = 0;
    m_textLength = 0;

    while (m_node) {
        if (!m_handledNode) {
            RenderObject *renderer = m_node->renderer();
            if (renderer && renderer->isText() && m_node->nodeType() == Node::TEXT_NODE) {
                // FIXME: What about CDATA_SECTION_NODE?
                if (renderer->style()->visibility() == VISIBLE && m_offset > 0) {
                    m_handledNode = handleTextNode();
                }
            } else if (renderer && (renderer->isImage() || renderer->isWidget())) {
                if (renderer->style()->visibility() == VISIBLE && m_offset > 0) {
                    m_handledNode = handleReplacedElement();
                }
            } else {
                m_handledNode = handleNonTextNode();
            }
            if (m_positionNode) {
                return;
            }
        }

        if (m_node == m_startNode)
            return;

        NodeImpl *next = 0;
        if (!m_handledChildren) {
            next = m_node->lastChild();
            while (next && next->lastChild())
                next = next->lastChild();
            m_handledChildren = true;
        }
        if (!next && m_node != m_startNode) {
            next = m_node->previousSibling();
            if (next) {
                exitNode();
                while (next->lastChild())
                    next = next->lastChild();
            }
            else if (m_node->parentNode()) {
                next = m_node->parentNode();
                exitNode();
            }
        }
        
        // Check for leaving a node and iterating backwards
        // into a different block that is an descendent of the
        // block containing the node (as in leaving
        // the "bar" node in this example: <p>foo</p>bar).
        // Must emit newline when leaving node containing "bar".
        if (next && m_node->renderer() && m_node->renderer()->style()->visibility() == VISIBLE) {
            NodeImpl *block = m_node->enclosingBlockFlowElement();
            if (block) {
                NodeImpl *nextBlock = next->enclosingBlockFlowElement();
                if (nextBlock && nextBlock->isAncestor(block))
                    emitNewlineForBROrText();
            }
        }
        
        m_node = next;
        if (m_node)
            m_offset = m_node->caretMaxOffset();
        else
            m_offset = 0;
        m_handledNode = false;
        
        if (m_positionNode) {
            return;
        }
    }
}

bool SimplifiedBackwardsTextIterator::handleTextNode()
{
    m_lastTextNode = m_node;

    RenderText *renderer = static_cast<RenderText *>(m_node->renderer());
    DOMString str = m_node->nodeValue();

    if (!renderer->firstTextBox() && str.length() > 0) {
        return true;
    }

    m_positionEndOffset = m_offset;

    m_offset = (m_node == m_startNode) ? m_startOffset : 0;
    m_positionNode = m_node;
    m_positionStartOffset = m_offset;
    m_textLength = m_positionEndOffset - m_positionStartOffset;
    m_textCharacters = str.unicode() + m_positionStartOffset;

    m_lastCharacter = str[m_positionEndOffset - 1];

    return true;
}

bool SimplifiedBackwardsTextIterator::handleReplacedElement()
{
    long offset = m_node->nodeIndex();

    m_positionNode = m_node->parentNode();
    m_positionStartOffset = offset;
    m_positionEndOffset = offset + 1;

    m_textCharacters = 0;
    m_textLength = 0;

    m_lastCharacter = 0;

    return true;
}

bool SimplifiedBackwardsTextIterator::handleNonTextNode()
{
    switch (m_node->id()) {
        case ID_BR:
            emitNewlineForBROrText();
            break;
        case ID_TD:
        case ID_TH:
        case ID_BLOCKQUOTE:
        case ID_DD:
        case ID_DIV:
        case ID_DL:
        case ID_DT:
        case ID_H1:
        case ID_H2:
        case ID_H3:
        case ID_H4:
        case ID_H5:
        case ID_H6:
        case ID_HR:
        case ID_P:
        case ID_PRE:
        case ID_TR:
        case ID_OL:
        case ID_UL:
        case ID_LI:
            // Emit a space to "break up" content. Any word break
            // character will do.
            emitCharacter(' ', m_node, 0, 0);
            break;
    }

    return true;
}

void SimplifiedBackwardsTextIterator::exitNode()
{
    // Left this function in so that the name and usage patters remain similar to 
    // TextIterator. However, the needs of this iterator are much simpler, and
    // the handleNonTextNode() function does just what we want (i.e. insert a
    // space for certain node types to "break up" text so that it does not seem
    // like content is next to other text when it really isn't). 
    handleNonTextNode();
}

void SimplifiedBackwardsTextIterator::emitCharacter(QChar c, NodeImpl *node, long startOffset, long endOffset)
{
    m_singleCharacterBuffer = c;
    m_positionNode = node;
    m_positionStartOffset = startOffset;
    m_positionEndOffset = endOffset;
    m_textCharacters = &m_singleCharacterBuffer;
    m_textLength = 1;
    m_lastCharacter = c;
}

void SimplifiedBackwardsTextIterator::emitNewlineForBROrText()
{
    long offset;
    
    if (m_lastTextNode) {
        offset = m_lastTextNode->nodeIndex();
        emitCharacter('\n', m_lastTextNode->parentNode(), offset, offset + 1);
    } else {
        offset = m_node->nodeIndex();
        emitCharacter('\n', m_node->parentNode(), offset, offset + 1);
    }
}

Range SimplifiedBackwardsTextIterator::range() const
{
    if (m_positionNode) {
        return Range(m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);
    } else {
        return Range(m_startNode, m_startOffset, m_startNode, m_startOffset);
    }
}

CharacterIterator::CharacterIterator()
    : m_offset(0), m_runOffset(0), m_atBreak(true)
{
}

CharacterIterator::CharacterIterator(const Range &r)
    : m_offset(0), m_runOffset(0), m_atBreak(true), m_textIterator(r, RUNFINDER)
{
    while (!atEnd() && m_textIterator.length() == 0) {
        m_textIterator.advance();
    }
}

Range CharacterIterator::range() const

⌨️ 快捷键说明

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