void SimplifiedBackwardsTextIteratorAlgorithm<Strategy>::advance() { ASSERT(m_positionNode); if (m_shouldStop) return; if (m_stopsOnFormControls && HTMLFormControlElement::enclosingFormControlElement(m_node)) { m_shouldStop = true; return; } m_positionNode = nullptr; m_textLength = 0; while (m_node && !m_havePassedStartNode) { // Don't handle node if we start iterating at [node, 0]. if (!m_handledNode && !(m_node == m_endNode && !m_endOffset)) { LayoutObject* layoutObject = m_node->layoutObject(); if (layoutObject && layoutObject->isText() && m_node->nodeType() == Node::TEXT_NODE) { // FIXME: What about CDATA_SECTION_NODE? if (layoutObject->style()->visibility() == VISIBLE && m_offset > 0) m_handledNode = handleTextNode(); } else if (layoutObject && (layoutObject->isLayoutPart() || TextIterator::supportsAltText(m_node))) { if (layoutObject->style()->visibility() == VISIBLE && m_offset > 0) m_handledNode = handleReplacedElement(); } else { m_handledNode = handleNonTextNode(); } if (m_positionNode) return; } if (!m_handledChildren && m_node->hasChildren()) { m_node = m_node->lastChild(); m_fullyClippedStack.pushFullyClippedState(m_node); } else { // Exit empty containers as we pass over them or containers // where [container, 0] is where we started iterating. if (!m_handledNode && canHaveChildrenForEditing(m_node) && m_node->parentNode() && (!m_node->lastChild() || (m_node == m_endNode && !m_endOffset))) { exitNode(); if (m_positionNode) { m_handledNode = true; m_handledChildren = true; return; } } // Exit all other containers. while (!m_node->previousSibling()) { if (!advanceRespectingRange(m_node->parentOrShadowHostNode())) break; m_fullyClippedStack.pop(); exitNode(); if (m_positionNode) { m_handledNode = true; m_handledChildren = true; return; } } m_fullyClippedStack.pop(); if (advanceRespectingRange(m_node->previousSibling())) m_fullyClippedStack.pushFullyClippedState(m_node); else m_node = nullptr; } // For the purpose of word boundary detection, // we should iterate all visible text and trailing (collapsed) whitespaces. m_offset = m_node ? maxOffsetIncludingCollapsedSpaces(m_node) : 0; m_handledNode = false; m_handledChildren = false; if (m_positionNode) return; } }
Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode traversalMode) { const bool shouldEmit = traversalMode == EmitString; Vector<RawPtr<ContainerNode> > ancestorsToClose; Node* next; Node* lastClosed = 0; for (Node* n = startNode; n != pastEnd; n = next) { // According to <rdar://problem/5730668>, it is possible for n to blow // past pastEnd and become null here. This shouldn't be possible. // This null check will prevent crashes (but create too much markup) // and the ASSERT will hopefully lead us to understanding the problem. ASSERT(n); if (!n) break; next = NodeTraversal::next(*n); bool openedTag = false; if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) // Don't write out empty block containers that aren't fully selected. continue; if (!n->renderer() && m_shouldAnnotate != AnnotateForNavigationTransition) { next = NodeTraversal::nextSkippingChildren(*n); // Don't skip over pastEnd. if (pastEnd && pastEnd->isDescendantOf(n)) next = pastEnd; } else { // Add the node to the markup if we're not skipping the descendants if (shouldEmit) appendStartTag(*n); // If node has no children, close the tag now. if (n->isContainerNode() && toContainerNode(n)->hasChildren()) { openedTag = true; ancestorsToClose.append(toContainerNode(n)); } else { if (shouldEmit && n->isElementNode()) appendEndTag(toElement(*n)); lastClosed = n; } } // If we didn't insert open tag and there's no more siblings or we're at the end of the traversal, take care of ancestors. // FIXME: What happens if we just inserted open tag and reached the end? if (!openedTag && (!n->nextSibling() || next == pastEnd)) { // Close up the ancestors. while (!ancestorsToClose.isEmpty()) { ContainerNode* ancestor = ancestorsToClose.last(); ASSERT(ancestor); if (next != pastEnd && next->isDescendantOf(ancestor)) break; // Not at the end of the range, close ancestors up to sibling of next node. if (shouldEmit && ancestor->isElementNode()) appendEndTag(toElement(*ancestor)); lastClosed = ancestor; ancestorsToClose.removeLast(); } // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors. ContainerNode* nextParent = next ? next->parentNode() : 0; if (next != pastEnd && n != nextParent) { Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n; for (ContainerNode* parent = lastAncestorClosedOrSelf->parentNode(); parent && parent != nextParent; parent = parent->parentNode()) { // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered: if (!parent->renderer()) continue; // or b) ancestors that we never encountered during a pre-order traversal starting at startNode: ASSERT(startNode->isDescendantOf(parent)); if (shouldEmit) wrapWithNode(*parent); lastClosed = parent; } } } } return lastClosed; }