bool TextIterator::handleTextNode() { RenderText* renderer = static_cast<RenderText*>(m_node->renderer()); if (renderer->style()->visibility() != VISIBLE) return false; m_lastTextNode = m_node; String str = renderer->text(); // handle pre-formatted text if (!renderer->style()->collapseWhiteSpace()) { int runStart = m_offset; if (m_lastTextNodeEndedWithCollapsedSpace) { emitCharacter(' ', m_node, 0, runStart, runStart); return false; } int strLength = str.length(); int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX; int runEnd = min(strLength, end); if (runStart >= runEnd) return true; emitText(m_node, runStart, runEnd); return true; } if (!renderer->firstTextBox() && str.length() > 0) { m_lastTextNodeEndedWithCollapsedSpace = true; // entire block is collapsed space return true; } // Used when text boxes are out of order (Hebrew/Arabic w/ embeded LTR text) if (renderer->containsReversedText()) { m_sortedTextBoxes.clear(); for (InlineTextBox * textBox = renderer->firstTextBox(); textBox; textBox = textBox->nextTextBox()) { m_sortedTextBoxes.append(textBox); } std::sort(m_sortedTextBoxes.begin(), m_sortedTextBoxes.end(), compareBoxStart); m_sortedTextBoxesPosition = 0; } m_textBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox(); handleTextBox(); return true; }
bool RenderTextLineBoxes::containsOffset(const RenderText& renderer, unsigned offset, OffsetType type) const { for (auto box = m_first; box; box = box->nextTextBox()) { if (offset < box->start() && !renderer.containsReversedText()) return false; unsigned boxEnd = box->start() + box->len(); if (offset >= box->start() && offset <= boxEnd) { if (offset == boxEnd && (type == CharacterOffset || box->isLineBreak())) continue; if (type == CharacterOffset) return true; // Return false for offsets inside composed characters. return !offset || offset == static_cast<unsigned>(renderer.nextOffset(renderer.previousOffset(offset))); } } return false; }
bool Position::isRenderedCharacter() const { if (isNull() || !node()->isTextNode()) return false; RenderObject *renderer = node()->renderer(); if (!renderer) return false; RenderText *textRenderer = static_cast<RenderText *>(renderer); for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { if (offset() < box->m_start && !textRenderer->containsReversedText()) { // The offset we're looking for is before this node // this means the offset must be in content that is // not rendered. Return false. return false; } if (offset() >= box->m_start && offset() < box->m_start + box->m_len) return true; } return false; }
bool Position::inRenderedText() const { if (isNull() || !node()->isTextNode()) return false; RenderObject *renderer = node()->renderer(); if (!renderer) return false; RenderText *textRenderer = static_cast<RenderText *>(renderer); for (InlineTextBox *box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { if (offset() < box->m_start && !textRenderer->containsReversedText()) { // The offset we're looking for is before this node // this means the offset must be in content that is // not rendered. Return false. return false; } if (box->containsCaretOffset(offset())) // Return false for offsets inside composed characters. return offset() == 0 || offset() == textRenderer->nextOffset(textRenderer->previousOffset(offset())); } return false; }
void TextIterator::handleTextBox() { RenderText *renderer = static_cast<RenderText *>(m_node->renderer()); String str = renderer->text(); int start = m_offset; int end = (m_node == m_endContainer) ? m_endOffset : INT_MAX; while (m_textBox) { int textBoxStart = m_textBox->m_start; int runStart = max(textBoxStart, start); // Check for collapsed space at the start of this run. InlineTextBox *firstTextBox = renderer->containsReversedText() ? m_sortedTextBoxes[0] : renderer->firstTextBox(); bool needSpace = m_lastTextNodeEndedWithCollapsedSpace || (m_textBox == firstTextBox && textBoxStart == runStart && runStart > 0); if (needSpace && !isCollapsibleWhitespace(m_lastCharacter) && m_lastCharacter) { emitCharacter(' ', m_node, 0, runStart, runStart); return; } int textBoxEnd = textBoxStart + m_textBox->m_len; int runEnd = min(textBoxEnd, end); // Determine what the next text box will be, but don't advance yet InlineTextBox *nextTextBox = 0; if (renderer->containsReversedText()) { if (m_sortedTextBoxesPosition + 1 < m_sortedTextBoxes.size()) nextTextBox = m_sortedTextBoxes[m_sortedTextBoxesPosition + 1]; } else nextTextBox = m_textBox->nextTextBox(); 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, 0, runStart, runStart + 1); m_offset = runStart + 1; } else { int subrunEnd = str.find('\n', runStart); if (subrunEnd == -1 || subrunEnd > runEnd) subrunEnd = runEnd; m_offset = subrunEnd; emitText(m_node, runStart, subrunEnd); } // 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 < textBoxEnd) return; // Advance and return int nextRunStart = nextTextBox ? nextTextBox->m_start : str.length(); if (nextRunStart > runEnd) m_lastTextNodeEndedWithCollapsedSpace = true; // collapsed space between runs or at the end m_textBox = nextTextBox; if (renderer->containsReversedText()) ++m_sortedTextBoxesPosition; return; } // Advance and continue m_textBox = nextTextBox; if (renderer->containsReversedText()) ++m_sortedTextBoxesPosition; } }