void PendingSelection::commitAlgorithm(LayoutView& layoutView)
{
    if (!hasPendingSelection())
        return;
    ASSERT(!layoutView.needsLayout());
    m_hasPendingSelection = false;

    const VisibleSelectionTemplate<Strategy> originalSelection = m_frameSelection->visibleSelection<Strategy>();

    // Skip if pending VisibilePositions became invalid before we reach here.
    if (!isSelectionInDocument(originalSelection, layoutView.document()))
        return;

    // Construct a new VisibleSolution, since visibleSelection() is not necessarily
    // valid, and the following steps assume a valid selection.
    // See <https://bugs.webkit.org/show_bug.cgi?id=69563> and
    // <rdar://problem/10232866>.
    const VisibleSelectionTemplate<Strategy> selection = calcVisibleSelectionAlgorithm<Strategy>(originalSelection);

    if (!selection.isRange()) {
        layoutView.clearSelection();
        return;
    }

    // Use the rightmost candidate for the start of the selection, and the
    // leftmost candidate for the end of the selection. Example: foo <a>bar</a>.
    // Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.
    // If we pass [foo, 3] as the start of the selection, the selection painting
    // code will think that content on the line containing 'foo' is selected
    // and will fill the gap before 'bar'.
    PositionTemplate<Strategy> startPos = selection.start();
    PositionTemplate<Strategy> candidate = mostForwardCaretPosition(startPos);
    if (isVisuallyEquivalentCandidate(candidate))
        startPos = candidate;
    PositionTemplate<Strategy> endPos = selection.end();
    candidate = mostBackwardCaretPosition(endPos);
    if (isVisuallyEquivalentCandidate(candidate))
        endPos = candidate;

    // We can get into a state where the selection endpoints map to the same
    // |VisiblePosition| when a selection is deleted because we don't yet notify
    // the |FrameSelection| of text removal.
    if (startPos.isNull() || endPos.isNull() || selection.visibleStart().deepEquivalent() == selection.visibleEnd().deepEquivalent())
        return;
    LayoutObject* startLayoutObject = startPos.anchorNode()->layoutObject();
    LayoutObject* endLayoutObject = endPos.anchorNode()->layoutObject();
    if (!startLayoutObject || !endLayoutObject)
        return;
    ASSERT(layoutView == startLayoutObject->view() && layoutView == endLayoutObject->view());
    layoutView.setSelection(startLayoutObject, startPos.computeEditingOffset(), endLayoutObject, endPos.computeEditingOffset());
}
Exemple #2
0
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());
}