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

📄 textiterator.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 4 页
字号:
        return false;    }    m_haveEmitted = true;    if (m_emitCharactersBetweenAllVisiblePositions) {        // We want replaced elements to behave like punctuation for boundary         // finding, and to simply take up space for the selection preservation         // code in moveParagraphs, so we use a comma.        emitCharacter(',', m_node->parentNode(), m_node, 0, 1);        return true;    }    m_positionNode = m_node->parentNode();    m_positionOffsetBaseNode = m_node;    m_positionStartOffset = 0;    m_positionEndOffset = 1;    m_textCharacters = 0;    m_textLength = 0;    m_lastCharacter = 0;    return true;}static bool shouldEmitTabBeforeNode(Node* node){    RenderObject* r = node->renderer();        // Table cells are delimited by tabs.    if (!r || !isTableCell(node))        return false;        // Want a tab before every cell other than the first one    RenderTableCell* rc = static_cast<RenderTableCell*>(r);    RenderTable* t = rc->table();    return t && (t->cellBefore(rc) || t->cellAbove(rc));}static bool shouldEmitNewlineForNode(Node* node){    // br elements are represented by a single newline.    RenderObject* r = node->renderer();    if (!r)        return node->hasTagName(brTag);            return r->isBR();}static bool shouldEmitNewlinesBeforeAndAfterNode(Node* node){    // Block flow (versus inline flow) is represented by having    // a newline both before and after the element.    RenderObject* r = node->renderer();    if (!r) {        return (node->hasTagName(blockquoteTag)                || node->hasTagName(ddTag)                || node->hasTagName(divTag)                || node->hasTagName(dlTag)                || node->hasTagName(dtTag)                || node->hasTagName(h1Tag)                || node->hasTagName(h2Tag)                || node->hasTagName(h3Tag)                || node->hasTagName(h4Tag)                || node->hasTagName(h5Tag)                || node->hasTagName(h6Tag)                || node->hasTagName(hrTag)                || node->hasTagName(liTag)                || node->hasTagName(listingTag)                || node->hasTagName(olTag)                || node->hasTagName(pTag)                || node->hasTagName(preTag)                || node->hasTagName(trTag)                || node->hasTagName(ulTag));    }        // Need to make an exception for table cells, because they are blocks, but we    // want them tab-delimited rather than having newlines before and after.    if (isTableCell(node))        return false;        // Need to make an exception for table row elements, because they are neither    // "inline" or "RenderBlock", but we want newlines for them.    if (r->isTableRow()) {        RenderTable* t = static_cast<RenderTableRow*>(r)->table();        if (t && !t->isInline())            return true;    }        return !r->isInline() && r->isRenderBlock() && !r->isFloatingOrPositioned() && !r->isBody();}static bool shouldEmitNewlineAfterNode(Node* node){    // FIXME: It should be better but slower to create a VisiblePosition here.    if (!shouldEmitNewlinesBeforeAndAfterNode(node))        return false;    // Check if this is the very last renderer in the document.    // If so, then we should not emit a newline.    while ((node = node->traverseNextSibling()))        if (node->renderer())            return true;    return false;}static bool shouldEmitNewlineBeforeNode(Node* node){    return shouldEmitNewlinesBeforeAndAfterNode(node); }static bool shouldEmitExtraNewlineForNode(Node* node){    // When there is a significant collapsed bottom margin, emit an extra    // newline for a more realistic result.  We end up getting the right    // result even 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* r = node->renderer();    if (!r || !r->isBox())        return false;        // NOTE: We only do this for a select set of nodes, and fwiw WinIE appears    // not to do this at all    if (node->hasTagName(h1Tag)        || node->hasTagName(h2Tag)        || node->hasTagName(h3Tag)        || node->hasTagName(h4Tag)        || node->hasTagName(h5Tag)        || node->hasTagName(h6Tag)        || node->hasTagName(pTag)) {        RenderStyle* style = r->style();        if (style) {            int bottomMargin = toRenderBox(r)->collapsedMarginBottom();            int fontSize = style->fontDescription().computedPixelSize();            if (bottomMargin * 2 >= fontSize)                return true;        }    }        return false;}// Whether or not we should emit a character as we enter m_node (if it's a container) or as we hit it (if it's atomic).bool TextIterator::shouldRepresentNodeOffsetZero(){    if (m_emitCharactersBetweenAllVisiblePositions && m_node->renderer() && m_node->renderer()->isTable())        return true;            // Leave element positioned flush with start of a paragraph    // (e.g. do not insert tab before a table cell at the start of a paragraph)    if (m_lastCharacter == '\n')        return false;        // Otherwise, show the position if we have emitted any characters    if (m_haveEmitted)        return true;        // We've not emitted anything yet. Generally, there is no need for any positioning then.    // The only exception is when the element is visually not in the same line as    // the start of the range (e.g. the range starts at the end of the previous paragraph).    // NOTE: Creating VisiblePositions and comparing them is relatively expensive, so we    // make quicker checks to possibly avoid that. Another check that we could make is    // is whether the inline vs block flow changed since the previous visible element.    // I think we're already in a special enough case that that won't be needed, tho.    // No character needed if this is the first node in the range.    if (m_node == m_startContainer)        return false;        // If we are outside the start container's subtree, assume we need to emit.    // FIXME: m_startContainer could be an inline block    if (!m_node->isDescendantOf(m_startContainer))        return true;    // If we started as m_startContainer offset 0 and the current node is a descendant of    // the start container, we already had enough context to correctly decide whether to    // emit after a preceding block. We chose not to emit (m_haveEmitted is false),    // so don't second guess that now.    // NOTE: Is this really correct when m_node is not a leftmost descendant? Probably    // immaterial since we likely would have already emitted something by now.    if (m_startOffset == 0)        return false;            // If this node is unrendered or invisible the VisiblePosition checks below won't have much meaning.    // Additionally, if the range we are iterating over contains huge sections of unrendered content,     // we would create VisiblePositions on every call to this function without this check.    if (!m_node->renderer() || m_node->renderer()->style()->visibility() != VISIBLE)        return false;        // The currPos.isNotNull() check is needed because positions in non-html content    // (like svg) do not have visible positions, and we don't want to emit for them either.    VisiblePosition startPos = VisiblePosition(m_startContainer, m_startOffset, DOWNSTREAM);    VisiblePosition currPos = VisiblePosition(m_node, 0, DOWNSTREAM);    return currPos.isNotNull() && !inSameLine(startPos, currPos);}bool TextIterator::shouldEmitSpaceBeforeAndAfterNode(Node* node){    return node->renderer() && node->renderer()->isTable() && (node->renderer()->isInline() || m_emitCharactersBetweenAllVisiblePositions);}void TextIterator::representNodeOffsetZero(){    // Emit a character to show the positioning of m_node.        // When we haven't been emitting any characters, shouldRepresentNodeOffsetZero() can     // create VisiblePositions, which is expensive.  So, we perform the inexpensive checks    // on m_node to see if it necessitates emitting a character first and will early return     // before encountering shouldRepresentNodeOffsetZero()s worse case behavior.    if (shouldEmitTabBeforeNode(m_node)) {        if (shouldRepresentNodeOffsetZero())            emitCharacter('\t', m_node->parentNode(), m_node, 0, 0);    } else if (shouldEmitNewlineBeforeNode(m_node)) {        if (shouldRepresentNodeOffsetZero())            emitCharacter('\n', m_node->parentNode(), m_node, 0, 0);    } else if (shouldEmitSpaceBeforeAndAfterNode(m_node)) {        if (shouldRepresentNodeOffsetZero())            emitCharacter(' ', m_node->parentNode(), m_node, 0, 0);    }}bool TextIterator::handleNonTextNode(){    if (shouldEmitNewlineForNode(m_node))        emitCharacter('\n', m_node->parentNode(), m_node, 0, 1);    else if (m_emitCharactersBetweenAllVisiblePositions && m_node->renderer() && m_node->renderer()->isHR())        emitCharacter(' ', m_node->parentNode(), m_node, 0, 1);    else        representNodeOffsetZero();    return true;}void TextIterator::exitNode(){    // prevent emitting a newline when exiting a collapsed block at beginning of the range    // FIXME: !m_haveEmitted does not necessarily mean there was a collapsed block... it could    // have been an hr (e.g.). Also, a collapsed block could have height (e.g. a table) and    // therefore look like a blank line.    if (!m_haveEmitted)        return;            // Emit with a position *inside* m_node, after m_node's contents, in     // case it is a block, because the run should start where the     // emitted character is positioned visually.    Node* baseNode = m_node->lastChild() ? m_node->lastChild() : m_node;    // FIXME: This shouldn't require the m_lastTextNode to be true, but we can't change that without making    // the logic in _web_attributedStringFromRange match.  We'll get that for free when we switch to use    // TextIterator in _web_attributedStringFromRange.    // See <rdar://problem/5428427> for an example of how this mismatch will cause problems.    if (m_lastTextNode && shouldEmitNewlineAfterNode(m_node)) {        // use extra newline to represent margin bottom, as needed        bool addNewline = shouldEmitExtraNewlineForNode(m_node);                // FIXME: We need to emit a '\n' as we leave an empty block(s) that        // contain a VisiblePosition when doing selection preservation.        if (m_lastCharacter != '\n') {            // insert a newline with a position following this block's contents.            emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);            // remember whether 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's contents.            emitCharacter('\n', baseNode->parentNode(), baseNode, 1, 1);    }        // If nothing was emitted, see if we need to emit a space.    if (!m_positionNode && shouldEmitSpaceBeforeAndAfterNode(m_node))        emitCharacter(' ', baseNode->parentNode(), baseNode, 1, 1);}void TextIterator::emitCharacter(UChar c, Node *textNode, Node *offsetBaseNode, int textStartOffset, int textEndOffset){    m_haveEmitted = true;        // 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;}void TextIterator::emitText(Node* textNode, int textStartOffset, int textEndOffset){    RenderText* renderer = toRenderText(m_node->renderer());    String str = renderer->text();    ASSERT(str.characters());    m_positionNode = textNode;    m_positionOffsetBaseNode = 0;    m_positionStartOffset = textStartOffset;    m_positionEndOffset = textEndOffset;    m_textCharacters = str.characters() + textStartOffset;    m_textLength = textEndOffset - textStartOffset;    m_lastCharacter = str[textEndOffset - 1];    m_lastTextNodeEndedWithCollapsedSpace = false;    m_haveEmitted = true;}PassRefPtr<Range> TextIterator::range() const{    // use the current run information, if we have it    if (m_positionNode) {        if (m_positionOffsetBaseNode) {            int index = m_positionOffsetBaseNode->nodeIndex();            m_positionStartOffset += index;            m_positionEndOffset += index;            m_positionOffsetBaseNode = 0;        }        return Range::create(m_positionNode->document(), m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);    }    // otherwise, return the end of the overall range we were given    if (m_endContainer)        return Range::create(m_endContainer->document(), m_endContainer, m_endOffset, m_endContainer, m_endOffset);            return 0;}    Node* TextIterator::node() const{    RefPtr<Range> textRange = range();    if (!textRange)        return 0;    Node* node = textRange->startContainer();    if (!node)        return 0;    if (node->offsetInCharacters())        return node;        return node->childNode(textRange->startOffset());}// --------SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator() : m_positionNode(0){}SimplifiedBackwardsTextIterator::SimplifiedBackwardsTextIterator(const Range *r){    m_positionNode = 0;    if (!r)        return;    Node* startNode = r->startContainer();    if (!startNode)        return;    Node* endNode = r->endContainer();    int startOffset = r->startOffset();    int endOffset = r->endOffset();    if (!startNode->offsetInCharacters()) {        if (startOffset >= 0 && startOffset < static_cast<int>(startNode->childNodeCount())) {            startNode = startNode->childNode(startOffset);            startOffset = 0;        }    }    if (!endNode->offsetInCharacters()) {        if (endOffset > 0 && endOffset <= static_cast<int>(endNode->childNodeCount())) {            endNode = endNode->childNode(endOffset - 1);            endOffset = endNode->offsetInCharacters() ? endNode->maxCharacterOffset() : endNode->childNodeCount();        }    }    m_node = endNode;    m_offset = endOffset;    m_handledNode = false;    m_handledChildren = endOffset == 0;    m_startNode = startNode;    m_startOffset = startOffset;    m_endNode = endNode;    m_endOffset = endOffset;    #ifndef NDEBUG    // Need this just because of the assert.    m_positionNode = endNode;#endif    m_lastTextNode = 0;    m_lastCharacter = '\n';        if (startOffset == 0 || !startNode->firstChild()) {        m_pastStartNode = startNode->previousSibling();        while (!m_pastStartNode && startNode->parentNode()) {            startNode = startNode->parentNode();            m_pastStartNode = startNode->previousSibling();        }    } else        m_pastStartNode = startNode->childNode(startOffset - 1);    advance();}void SimplifiedBackwardsTextIterator::advance(){    ASSERT(m_positionNode);    m_positionNode = 0;    m_textLength = 0;    while (m_node && m_node != m_pastStartNode) {        // Don't handle node if we start iterating at [node, 0].        if (!m_handledNode && !(m_node == m_endNode && m_endOffset == 0)) {            RenderObject *renderer = m_node->renderer();            if (renderer && renderer->isText() && m_node->nodeType() == Node::TEXT_NODE) {                // FIXME: What about CDATA_SECTION_NODE?

⌨️ 快捷键说明

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