void HTMLConstructionSite::flushPendingText() { if (m_pendingText.isEmpty()) return; PendingText pendingText; // Hold onto the current pending text on the stack so that queueTask doesn't recurse infinitely. m_pendingText.swap(pendingText); ASSERT(m_pendingText.isEmpty()); // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is necessary // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 unsigned lengthLimit = textLengthLimitForContainer(*pendingText.parent); unsigned currentPosition = 0; const StringBuilder& string = pendingText.stringBuilder; while (currentPosition < string.length()) { unsigned proposedBreakIndex = std::min(currentPosition + lengthLimit, string.length()); unsigned breakIndex = findBreakIndexBetween(string, currentPosition, proposedBreakIndex); ASSERT(breakIndex <= string.length()); String substring = string.substring(currentPosition, breakIndex - currentPosition); substring = atomizeIfAllWhitespace(substring, pendingText.whitespaceMode); HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertText); task.parent = pendingText.parent; task.child = Text::create(task.parent->document(), substring); queueTask(task); ASSERT(breakIndex > currentPosition); ASSERT(breakIndex - currentPosition == substring.length()); ASSERT(toText(task.child.get())->length() == substring.length()); currentPosition = breakIndex; } }
void HTMLConstructionSite::flushPendingText() { if (m_pendingText.isEmpty()) return; PendingText pendingText; // Hold onto the current pending text on the stack so that queueTask doesn't recurse infinitely. m_pendingText.swap(pendingText); ASSERT(m_pendingText.isEmpty()); // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is necessary // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 unsigned lengthLimit = textLengthLimitForContainer(*pendingText.parent); unsigned currentPosition = 0; const StringBuilder& string = pendingText.stringBuilder; while (currentPosition < string.length()) { unsigned proposedBreakIndex = std::min(currentPosition + lengthLimit, string.length()); unsigned breakIndex = findBreakIndexBetween(string, currentPosition, proposedBreakIndex); ASSERT(breakIndex <= string.length()); String substring = string.substring(currentPosition, breakIndex - currentPosition); ASSERT(breakIndex > currentPosition); ASSERT(breakIndex - currentPosition == substring.length()); currentPosition = breakIndex; if (isAllWhitespace(substring)) { // Ignore whitespace nodes not inside inside a <t>. If we're splitting // a text node this isn't really a whitespace node and we can't ignore // it either. if (!m_openElements.preserveWhiteSpace() && string.length() == substring.length()) continue; // Strings composed entirely of whitespace are likely to be repeated. // Turn them into AtomicString so we share a single string for each. substring = AtomicString(substring).string(); } HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertText); task.parent = pendingText.parent; task.child = Text::create(task.parent->document(), substring); queueTask(task); ASSERT(toText(task.child.get())->length() == substring.length()); } }
static inline void executeInsertTextTask(HTMLConstructionSiteTask& task) { ASSERT(task.operation == HTMLConstructionSiteTask::InsertText); ASSERT(task.child->isTextNode()); // Merge text nodes into previous ones if possible: // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#insert-a-character Text* newText = toText(task.child.get()); Node* previousChild = task.parent->lastChild(); if (previousChild && previousChild->isTextNode()) { Text* previousText = toText(previousChild); unsigned lengthLimit = textLengthLimitForContainer(*task.parent); if (previousText->length() + newText->length() < lengthLimit) { previousText->parserAppendData(newText->data()); return; } } insert(task); }