String CreateMarkupAlgorithm<Strategy>::createMarkup( const PositionTemplate<Strategy>& startPosition, const PositionTemplate<Strategy>& endPosition, EAnnotateForInterchange shouldAnnotate, ConvertBlocksToInlines convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs, Node* constrainingAncestor) { if (startPosition.isNull() || endPosition.isNull()) return emptyString(); RELEASE_ASSERT(startPosition.compareTo(endPosition) <= 0); bool collapsed = startPosition == endPosition; if (collapsed) return emptyString(); Node* commonAncestor = Strategy::commonAncestor(*startPosition.computeContainerNode(), *endPosition.computeContainerNode()); if (!commonAncestor) return emptyString(); Document* document = startPosition.document(); DCHECK(!document->needsLayoutTreeUpdate()); DocumentLifecycle::DisallowTransitionScope disallowTransition( document->lifecycle()); HTMLElement* specialCommonAncestor = highestAncestorToWrapMarkup<Strategy>( startPosition, endPosition, shouldAnnotate, constrainingAncestor); StyledMarkupSerializer<Strategy> serializer( shouldResolveURLs, shouldAnnotate, startPosition, endPosition, specialCommonAncestor, convertBlocksToInlines); return serializer.createMarkup(); }
String DOMSelection::toString() { if (!isAvailable()) return String(); // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. See http://crbug.com/590369 for more details. frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); DocumentLifecycle::DisallowTransitionScope disallowTransition( frame()->document()->lifecycle()); const EphemeralRange range = frame()->selection().selection().toNormalizedEphemeralRange(); return plainText(range, TextIteratorForSelectionToString); }
IntRect FrameCaret::absoluteCaretBounds() { DCHECK_NE(m_frame->document()->lifecycle().state(), DocumentLifecycle::InPaintInvalidation); DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); DocumentLifecycle::DisallowTransitionScope disallowTransition( m_frame->document()->lifecycle()); if (!isActive()) { clearCaretRect(); } else { if (enclosingTextFormControl(caretPosition().position())) { if (isVisuallyEquivalentCandidate(caretPosition().position())) updateCaretRect(caretPosition()); else updateCaretRect(createVisiblePosition(caretPosition())); } else { updateCaretRect(createVisiblePosition(caretPosition())); } } return absoluteBoundsForLocalRect(caretPosition().anchorNode(), localCaretRectWithoutUpdate()); }
void WebSurroundingText::initialize(const WebNode& webNode, const WebPoint& nodePoint, size_t maxLength) { const Node* node = webNode.constUnwrap<Node>(); if (!node) return; // VisiblePosition and SurroundingText must be created with clean layout. node->document().updateStyleAndLayoutIgnorePendingStylesheets(); DocumentLifecycle::DisallowTransitionScope disallowTransition( node->document().lifecycle()); if (!node->layoutObject()) return; // TODO(xiaochengh): The followinng SurroundingText can hold a null Range, // in which case we should prevent it from being stored in |m_private|. m_private.reset(new SurroundingText( createVisiblePosition(node->layoutObject()->positionForPoint( static_cast<IntPoint>(nodePoint))) .deepEquivalent() .parentAnchoredEquivalent(), maxLength)); }
bool SelectionModifier::modifyWithPageGranularity(EAlteration alter, unsigned verticalDistance, VerticalDirection direction) { if (!verticalDistance) return false; DCHECK(!frame()->document()->needsLayoutTreeUpdate()); DocumentLifecycle::DisallowTransitionScope disallowTransition( frame()->document()->lifecycle()); willBeModified(alter, direction == FrameSelection::DirectionUp ? DirectionBackward : DirectionForward); VisiblePosition pos; LayoutUnit xPos; switch (alter) { case FrameSelection::AlterationMove: pos = createVisiblePosition(direction == FrameSelection::DirectionUp ? m_selection.start() : m_selection.end(), m_selection.affinity()); xPos = lineDirectionPointForBlockDirectionNavigation( direction == FrameSelection::DirectionUp ? START : END); m_selection.setAffinity(direction == FrameSelection::DirectionUp ? TextAffinity::Upstream : TextAffinity::Downstream); break; case FrameSelection::AlterationExtend: pos = createVisiblePosition(m_selection.extent(), m_selection.affinity()); xPos = lineDirectionPointForBlockDirectionNavigation(EXTENT); m_selection.setAffinity(TextAffinity::Downstream); break; } int startY; if (!absoluteCaretY(pos, startY)) return false; if (direction == FrameSelection::DirectionUp) startY = -startY; int lastY = startY; VisiblePosition result; VisiblePosition next; for (VisiblePosition p = pos;; p = next) { if (direction == FrameSelection::DirectionUp) next = previousLinePosition(p, xPos); else next = nextLinePosition(p, xPos); if (next.isNull() || next.deepEquivalent() == p.deepEquivalent()) break; int nextY; if (!absoluteCaretY(next, nextY)) break; if (direction == FrameSelection::DirectionUp) nextY = -nextY; if (nextY - startY > static_cast<int>(verticalDistance)) break; if (nextY >= lastY) { lastY = nextY; result = next; } } if (result.isNull()) return false; switch (alter) { case FrameSelection::AlterationMove: m_selection = createVisibleSelection( SelectionInDOMTree::Builder() .collapse(result.toPositionWithAffinity()) .setIsDirectional(m_selection.isDirectional()) .build()); break; case FrameSelection::AlterationExtend: m_selection.setExtent(result); break; } m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(frame()) || alter == FrameSelection::AlterationExtend); return true; }
bool SelectionModifier::modify(EAlteration alter, SelectionDirection direction, TextGranularity granularity) { DCHECK(!frame()->document()->needsLayoutTreeUpdate()); DocumentLifecycle::DisallowTransitionScope disallowTransition( frame()->document()->lifecycle()); willBeModified(alter, direction); bool wasRange = m_selection.isRange(); VisiblePosition originalStartPosition = m_selection.visibleStart(); VisiblePosition position; switch (direction) { case DirectionRight: if (alter == FrameSelection::AlterationMove) position = modifyMovingRight(granularity); else position = modifyExtendingRight(granularity); break; case DirectionForward: if (alter == FrameSelection::AlterationExtend) position = modifyExtendingForward(granularity); else position = modifyMovingForward(granularity); break; case DirectionLeft: if (alter == FrameSelection::AlterationMove) position = modifyMovingLeft(granularity); else position = modifyExtendingLeft(granularity); break; case DirectionBackward: if (alter == FrameSelection::AlterationExtend) position = modifyExtendingBackward(granularity); else position = modifyMovingBackward(granularity); break; } if (position.isNull()) return false; if (isSpatialNavigationEnabled(frame())) { if (!wasRange && alter == FrameSelection::AlterationMove && position.deepEquivalent() == originalStartPosition.deepEquivalent()) return false; } // Some of the above operations set an xPosForVerticalArrowNavigation. // Setting a selection will clear it, so save it to possibly restore later. // Note: the START position type is arbitrary because it is unused, it would // be the requested position type if there were no // xPosForVerticalArrowNavigation set. LayoutUnit x = lineDirectionPointForBlockDirectionNavigation(START); m_selection.setIsDirectional(shouldAlwaysUseDirectionalSelection(frame()) || alter == FrameSelection::AlterationExtend); switch (alter) { case FrameSelection::AlterationMove: m_selection = createVisibleSelection( SelectionInDOMTree::Builder() .collapse(position.toPositionWithAffinity()) .setIsDirectional(m_selection.isDirectional()) .build()); break; case FrameSelection::AlterationExtend: if (!m_selection.isCaret() && (granularity == WordGranularity || granularity == ParagraphGranularity || granularity == LineGranularity) && frame() && !frame() ->editor() .behavior() .shouldExtendSelectionByWordOrLineAcrossCaret()) { // Don't let the selection go across the base position directly. Needed // to match mac behavior when, for instance, word-selecting backwards // starting with the caret in the middle of a word and then // word-selecting forward, leaving the caret in the same place where it // was, instead of directly selecting to the end of the word. VisibleSelection newSelection = m_selection; newSelection.setExtent(position); if (m_selection.isBaseFirst() != newSelection.isBaseFirst()) position = m_selection.visibleBase(); } // Standard Mac behavior when extending to a boundary is grow the // selection rather than leaving the base in place and moving the // extent. Matches NSTextView. if (!frame() || !frame() ->editor() .behavior() .shouldAlwaysGrowSelectionWhenExtendingToBoundary() || m_selection.isCaret() || !isBoundary(granularity)) { m_selection.setExtent(position); } else { TextDirection textDirection = directionOfEnclosingBlock(); if (direction == DirectionForward || (textDirection == LTR && direction == DirectionRight) || (textDirection == RTL && direction == DirectionLeft)) setSelectionEnd(&m_selection, position); else setSelectionStart(&m_selection, position); } break; } if (granularity == LineGranularity || granularity == ParagraphGranularity) m_xPosForVerticalArrowNavigation = x; return true; }