📄 khtml_text_operations.cpp
字号:
m_positionEndOffset = subrunEnd; m_textCharacters = str.unicode() + runStart; m_textLength = subrunEnd - runStart; m_lastCharacter = str[subrunEnd - 1]; } // If we are doing a subrun that doesn't go to the end of the text box, // come back again to finish handling this text box; don't advance to the next one. if (m_positionEndOffset < runEnd) { return; } // Advance to the next text box. InlineTextBox *nextTextBox = m_textBox->nextTextBox(); long nextRunStart = nextTextBox ? nextTextBox->m_start : str.length(); if (nextRunStart > runEnd) { m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end } m_textBox = nextTextBox; return; } }}bool TextIterator::handleReplacedElement(){ if (m_lastTextNodeEndedWithCollapsedSpace) { long offset = m_lastTextNode->nodeIndex(); emitCharacter(' ', m_lastTextNode->parentNode(), offset + 1, offset + 1); return false; } 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 TextIterator::handleNonTextNode(){ switch (m_node->id()) { case ID_BR: { long offset = m_node->nodeIndex(); emitCharacter('\n', m_node->parentNode(), offset, offset + 1); break; } case ID_TD: case ID_TH: if (m_lastCharacter != '\n' && m_lastTextNode) { long offset = m_lastTextNode->nodeIndex(); emitCharacter('\t', m_lastTextNode->parentNode(), offset, offset + 1); } break; 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_LI: case ID_OL: case ID_P: case ID_PRE: case ID_TR: case ID_UL: if (m_lastCharacter != '\n' && m_lastTextNode) { long offset = m_lastTextNode->nodeIndex(); emitCharacter('\n', m_lastTextNode->parentNode(), offset, offset + 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; addNewline = true; break; } if (endLine && m_lastCharacter != '\n' && m_lastTextNode) { long offset = m_lastTextNode->nodeIndex(); emitCharacter('\n', m_lastTextNode->parentNode(), offset, offset + 1); m_needAnotherNewline = addNewline; } else if (addNewline && m_lastTextNode) { long offset = m_node->childNodeCount(); emitCharacter('\n', m_node, offset, offset); }}void TextIterator::emitCharacter(QChar c, NodeImpl *textNode, long textStartOffset, long textEndOffset){ m_singleCharacterBuffer = c; m_positionNode = textNode; m_positionStartOffset = textStartOffset; m_positionEndOffset = textEndOffset; m_textCharacters = &m_singleCharacterBuffer; m_textLength = 1; m_lastTextNodeEndedWithCollapsedSpace = false; m_lastCharacter = c;}Range TextIterator::position() const{ assert(m_positionNode); return Range(m_positionNode, m_positionStartOffset, m_positionNode, m_positionEndOffset);}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){ while (!atEnd() && m_textIterator.textLength() == 0) { m_textIterator.advance(); }}Range CharacterIterator::position() const{ Range r = m_textIterator.position(); if (m_textIterator.textLength() <= 1) { assert(m_runOffset == 0); } else { Node n = r.startContainer(); assert(n == r.endContainer()); long offset = r.startOffset() + m_runOffset; r.setStart(n, offset); r.setEnd(n, offset + 1); } return r;}void CharacterIterator::advance(long count){ assert(!atEnd()); m_atBreak = false; long remaining = m_textIterator.textLength() - m_runOffset; if (count < remaining) { m_runOffset += count; m_offset += count; return; } count -= remaining; m_offset += remaining; for (m_textIterator.advance(); !atEnd(); m_textIterator.advance()) { long runLength = m_textIterator.textLength(); if (runLength == 0) { m_atBreak = true; } else { if (count < runLength) { m_runOffset = count; m_offset += count; return; } count -= runLength; m_offset += runLength; } } m_atBreak = true; m_runOffset = 0;}CircularSearchBuffer::CircularSearchBuffer(const QString &s, bool isCaseSensitive) : m_target(s){ assert(!s.isEmpty()); if (!isCaseSensitive) { m_target = s.lower(); } m_target.replace(nonBreakingSpace, ' '); m_isCaseSensitive = isCaseSensitive; m_buffer = static_cast<QChar *>(malloc(s.length() * sizeof(QChar))); m_cursor = m_buffer; m_bufferFull = false;}void CircularSearchBuffer::append(const QChar &c){ if (m_isCaseSensitive) { *m_cursor++ = c.unicode() == nonBreakingSpace ? ' ' : c.unicode(); } else { *m_cursor++ = c.unicode() == nonBreakingSpace ? ' ' : c.lower().unicode(); } if (m_cursor == m_buffer + length()) { m_cursor = m_buffer; m_bufferFull = true; }}// This function can only be used when the buffer is not yet full,// and when then count is small enough to fit in the buffer.// No need for a more general version for the search algorithm.void CircularSearchBuffer::append(long count, const QChar *characters){ long tailSpace = m_buffer + length() - m_cursor; assert(!m_bufferFull); assert(count <= tailSpace); if (m_isCaseSensitive) { for (long i = 0; i != count; ++i) { QChar c = characters[i]; m_cursor[i] = c.unicode() == nonBreakingSpace ? ' ' : c.unicode(); } } else { for (long i = 0; i != count; ++i) { QChar c = characters[i]; m_cursor[i] = c.unicode() == nonBreakingSpace ? ' ' : c.lower().unicode(); } } if (count < tailSpace) { m_cursor += count; } else { m_bufferFull = true; m_cursor = m_buffer; }}long CircularSearchBuffer::neededCharacters() const{ return m_bufferFull ? 0 : m_buffer + length() - m_cursor;}bool CircularSearchBuffer::isMatch() const{ assert(m_bufferFull); long headSpace = m_cursor - m_buffer; long tailSpace = length() - headSpace; return memcmp(m_cursor, m_target.unicode(), tailSpace * sizeof(QChar)) == 0 && memcmp(m_buffer, m_target.unicode() + tailSpace, headSpace * sizeof(QChar)) == 0;}QString plainText(const Range &r){ // Allocate string at the right size, rather than building it up by successive append calls. long length = 0; for (TextIterator it(r); !it.atEnd(); it.advance()) { length += it.textLength(); }#if KWIQ QString result("", length);#else QString result(""); result.reserve(length);#endif for (TextIterator it(r); !it.atEnd(); it.advance()) { result.append(it.textCharacters(), it.textLength()); } return result;}Range findPlainText(const Range &r, const QString &s, bool forward, bool caseSensitive){ // FIXME: Can we do Boyer-Moore or equivalent instead for speed? // FIXME: This code does not allow \n at the moment because of issues with <br>. // Once we fix those, we can remove this check. if (s.isEmpty() || s.find('\n') != -1) { Range result = r; result.collapse(forward); return result; } CircularSearchBuffer buffer(s, caseSensitive); bool found = false; CharacterIterator rangeEnd; { CharacterIterator it(r); while (!it.atEnd()) { // Fill the buffer. while (long needed = buffer.neededCharacters()) { long available = it.numCharacters(); long runLength = kMin(needed, available); buffer.append(runLength, it.characters()); it.advance(runLength); if (it.atBreak()) { if (it.atEnd()) { goto done; } buffer.clear(); } } // Do the search. do { if (buffer.isMatch()) { // Compute the range for the result. found = true; rangeEnd = it; // If searching forward, stop on the first match. // If searching backward, don't stop, so we end up with the last match. if (forward) { goto done; } } buffer.append(it.characters()[0]); it.advance(1); } while (!it.atBreak()); buffer.clear(); } }done: Range result = r; if (!found) { result.collapse(!forward); } else { CharacterIterator it(r); it.advance(rangeEnd.characterOffset() - buffer.length()); result.setStart(it.position().startContainer(), it.position().startOffset()); it.advance(buffer.length() - 1); result.setEnd(it.position().endContainer(), it.position().endOffset()); } return result;}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -