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

📄 khtml_text_operations.cpp

📁 khtml在gtk上的移植版本
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */#include "khtml_text_operations.h"#include <misc/htmltags.h>#include <rendering/render_text.h>#include <xml/dom_nodeimpl.h>using DOM::DOMString;using DOM::Node;using DOM::NodeImpl;using DOM::Range;namespace khtml {const unsigned short nonBreakingSpace = 0xA0;// Iterates through the DOM range, returning all the text, and 0-length boundaries// at points where replaced elements break up the text flow.class TextIterator{public:    TextIterator();    explicit TextIterator(const DOM::Range &);    bool atEnd() const { return !m_positionNode; }    void advance();    long textLength() const { return m_textLength; }    const QChar *textCharacters() const { return m_textCharacters; }    DOM::Range position() const;private:    void exitNode();    bool handleTextNode();    bool handleReplacedElement();    bool handleNonTextNode();    void handleTextBox();    void emitCharacter(QChar, DOM::NodeImpl *textNode, long textStartOffset, long textEndOffset);    // Current position, not necessarily of the text being returned, but position    // as we walk through the DOM tree.    DOM::NodeImpl *m_node;    long m_offset;    bool m_handledNode;    bool m_handledChildren;    // End of the range.    DOM::NodeImpl *m_endNode;    long m_endOffset;    // The current text and its position, in the form to be returned from the iterator.    DOM::NodeImpl *m_positionNode;    long m_positionStartOffset;    long m_positionEndOffset;    const QChar *m_textCharacters;    long m_textLength;    // Used when there is still some pending text from the current node; when these    // are false and 0, we go back to normal iterating.    bool m_needAnotherNewline;    InlineTextBox *m_textBox;    // Used to do the whitespace collapsing logic.    DOM::NodeImpl *m_lastTextNode;        bool m_lastTextNodeEndedWithCollapsedSpace;    QChar m_lastCharacter;    // Used for whitespace characters that aren't in the DOM, so we can point at them.    QChar m_singleCharacterBuffer;};// Builds on the text iterator, adding a character position so we can walk one// character at a time, or faster, as needed. Useful for searching.class CharacterIterator {public:    CharacterIterator();    explicit CharacterIterator(const DOM::Range &r);    void advance(long numCharacters);    bool atBreak() const { return m_atBreak; }    bool atEnd() const { return m_textIterator.atEnd(); }    long numCharacters() const { return m_textIterator.textLength() - m_runOffset; }    const QChar *characters() const { return m_textIterator.textCharacters() + m_runOffset; }    long characterOffset() const { return m_offset; }    Range position() const;private:    long m_offset;    long m_runOffset;    bool m_atBreak;    TextIterator m_textIterator;};// Buffer that knows how to compare with a search target.// Keeps enough of the previous text to be able to search in the future,// but no more.class CircularSearchBuffer {public:    CircularSearchBuffer(const QString &target, bool isCaseSensitive);    ~CircularSearchBuffer() { free(m_buffer); }    void clear() { m_cursor = m_buffer; m_bufferFull = false; }    void append(long length, const QChar *characters);    void append(const QChar &);    long neededCharacters() const;    bool isMatch() const;    long length() const { return m_target.length(); }private:    QString m_target;    bool m_isCaseSensitive;    QChar *m_buffer;    QChar *m_cursor;    bool m_bufferFull;    CircularSearchBuffer(const CircularSearchBuffer&);    CircularSearchBuffer &operator=(const CircularSearchBuffer&);};TextIterator::TextIterator() : m_positionNode(0){}inline bool offsetInCharacters(unsigned short type){    switch (type) {        case Node::ATTRIBUTE_NODE:        case Node::DOCUMENT_FRAGMENT_NODE:        case Node::DOCUMENT_NODE:        case Node::ELEMENT_NODE:        case Node::ENTITY_REFERENCE_NODE:            return false;        case Node::CDATA_SECTION_NODE:        case Node::COMMENT_NODE:        case Node::PROCESSING_INSTRUCTION_NODE:        case Node::TEXT_NODE:            return true;        case Node::DOCUMENT_TYPE_NODE:        case Node::ENTITY_NODE:        case Node::NOTATION_NODE:            assert(false); // should never be reached            return false;    }    assert(false); // should never be reached    return false;}TextIterator::TextIterator(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 = LONG_MAX;        }    }    m_node = startNode;    m_offset = startOffset;    m_handledNode = false;    m_handledChildren = false;    m_endNode = endNode;    m_endOffset = endOffset;    m_needAnotherNewline = false;    m_textBox = 0;    m_lastTextNode = 0;    m_lastTextNodeEndedWithCollapsedSpace = false;    m_lastCharacter = '\n';#ifndef NDEBUG    // Need this just because of the assert.    m_positionNode = startNode;#endif    advance();}void TextIterator::advance(){    assert(m_positionNode);    m_positionNode = 0;    m_textLength = 0;    if (m_needAnotherNewline) {        // Emit the newline, with position a collapsed range at the end of current node.        long offset = m_node->nodeIndex();        emitCharacter('\n', m_node->parentNode(), offset + 1, offset + 1);        m_needAnotherNewline = false;        return;    }    if (m_textBox) {        handleTextBox();        if (m_positionNode) {            return;        }    }    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_handledNode = handleTextNode();                }            } else if (renderer && (renderer->isImage() || renderer->isWidget())) {                if (renderer->style()->visibility() == VISIBLE) {                    m_handledNode = handleReplacedElement();                }            } else {                m_handledNode = handleNonTextNode();            }            if (m_positionNode) {                return;            }        }        NodeImpl *next = m_handledChildren ? 0 : m_node->firstChild();        m_offset = 0;        if (!next && m_node != m_endNode) {            next = m_node->nextSibling();            while (!next && m_node->parentNode()) {                m_node = m_node->parentNode();                exitNode();                if (m_positionNode) {                    m_handledNode = true;                    m_handledChildren = true;                    return;                }                if (m_node == m_endNode) {                    break;                }                next = m_node->nextSibling();            }        }        m_node = next;        m_handledNode = false;        m_handledChildren = false;        if (m_positionNode) {            return;        }    }}bool TextIterator::handleTextNode(){    m_lastTextNode = m_node;    RenderText *renderer = static_cast<RenderText *>(m_node->renderer());    DOMString str = m_node->nodeValue();    if (renderer->style()->whiteSpace() == khtml::PRE) {        long runStart = m_offset;        if (m_lastTextNodeEndedWithCollapsedSpace) {            emitCharacter(' ', m_node, runStart, runStart);            return false;        }        long strLength = str.length();        long end = (m_node == m_endNode) ? m_endOffset : LONG_MAX;        long runEnd = kMin(strLength, end);        m_positionNode = m_node;        m_positionStartOffset = runStart;        m_positionEndOffset = runEnd;        m_textCharacters = str.unicode() + runStart;        m_textLength = runEnd - runStart;        m_lastCharacter = str[runEnd - 1];        return true;    }    if (!renderer->firstTextBox() && str.length() > 0) {        m_lastTextNodeEndedWithCollapsedSpace = true; // entire block is collapsed space        return true;    }    m_textBox = renderer->firstTextBox();    handleTextBox();    return true;}void TextIterator::handleTextBox(){        RenderText *renderer = static_cast<RenderText *>(m_node->renderer());    DOMString str = m_node->nodeValue();    long start = m_offset;    long end = (m_node == m_endNode) ? m_endOffset : LONG_MAX;    for (; m_textBox; m_textBox = m_textBox->nextTextBox()) {        long textBoxStart = m_textBox->m_start;        long runStart = kMax(textBoxStart, start);        // Check for collapsed space at the start of this run.        bool needSpace = m_lastTextNodeEndedWithCollapsedSpace            || (m_textBox == renderer->firstTextBox() && textBoxStart == runStart && runStart > 0);        if (needSpace && !m_lastCharacter.isSpace()) {            emitCharacter(' ', m_node, runStart, runStart);            return;        }        long textBoxEnd = textBoxStart + m_textBox->m_len;        long runEnd = kMin(textBoxEnd, end);        if (runStart < runEnd) {            // Handle either a single newline character (which becomes a space),            // or a run of characters that does not include a newline.            // This effectively translates newlines to spaces without copying the text.            if (str[runStart] == '\n') {                emitCharacter(' ', m_node, runStart, runStart + 1);                m_offset = runStart + 1;            } else {                long subrunEnd = str.find('\n', runStart);                if (subrunEnd == -1 || subrunEnd > runEnd) {                    subrunEnd = runEnd;                }                m_offset = subrunEnd;                m_positionNode = m_node;                m_positionStartOffset = runStart;

⌨️ 快捷键说明

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