Beispiel #1
0
static VisiblePosition visiblePositionForHitTestResult(const HitTestResult& hitTestResult)
{
    Node* innerNode = hitTestResult.innerNode();
    VisiblePosition position(innerNode->renderer()->positionForPoint(hitTestResult.localPoint()));
    if (!position.isNull())
        return position;
    return VisiblePosition(firstPositionInOrBeforeNode(innerNode), DOWNSTREAM);
}
Beispiel #2
0
// Neighbor-anchored positions are invalid DOM positions, so they need to be
// fixed up before handing them off to the Range object.
Position Position::parentAnchoredEquivalent() const
{
    if (!m_anchorNode)
        return Position();
    
    // FIXME: This should only be necessary for legacy positions, but is also needed for positions before and after Tables
    if (m_offset <= 0 && m_anchorType != PositionIsAfterAnchor) {
        if (m_anchorNode->parentNode() && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get())))
            return positionInParentBeforeNode(m_anchorNode.get());
        return firstPositionInOrBeforeNode(m_anchorNode.get());
    }
    if (!m_anchorNode->offsetInCharacters() && (m_anchorType == PositionIsAfterAnchor || static_cast<unsigned>(m_offset) == m_anchorNode->childNodeCount())
        && (editingIgnoresContent(m_anchorNode.get()) || isTableElement(m_anchorNode.get()))
        && containerNode()) {
        return positionInParentAfterNode(m_anchorNode.get());
    }

    return Position(containerNode(), computeOffsetInContainerNode(), PositionIsOffsetInAnchor);
}
// Currenntly ignoring TextCheckingResult::details but should be handled. See Bug 56368.
void SpellChecker::didCheck(int sequence, const Vector<TextCheckingResult>& results)
{
    if (!isValid(sequence))
        return;

    if (!m_requestNode->renderer()) {
        clearRequest();
        return;
    }

    int startOffset = 0;
    PositionIterator start = firstPositionInOrBeforeNode(m_requestNode.get());
    for (size_t i = 0; i < results.size(); ++i) {
        if (results[i].type != TextCheckingTypeSpelling && results[i].type != TextCheckingTypeGrammar)
            continue;

        // To avoid moving the position backward, we assume the given results are sorted with
        // startOffset as the ones returned by [NSSpellChecker requestCheckingOfString:].
        ASSERT(startOffset <= results[i].location);
        if (!forwardIterator(start, results[i].location - startOffset))
            break;
        PositionIterator end = start;
        if (!forwardIterator(end, results[i].length))
            break;

        // Users or JavaScript applications may change text while a spell-checker checks its
        // spellings in the background. To avoid adding markers to the words modified by users or
        // JavaScript applications, retrieve the words in the specified region and compare them with
        // the original ones.
        RefPtr<Range> range = Range::create(m_requestNode->document(), start, end);
        // FIXME: Use textContent() compatible string conversion.
        String destination = range->text();
        String source = m_requestText.substring(results[i].location, results[i].length);
        if (destination == source)
            m_requestNode->document()->markers()->addMarker(range.get(), toMarkerType(results[i].type));

        startOffset = results[i].location;
    }

    clearRequest();
}
Beispiel #4
0
VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint)
{
    if (!contentRenderer() || !view() || !view()->didFirstLayout())
      return VisiblePosition();

    LayoutSize padding = LayoutSize();
    HitTestResult result(framePoint, padding.height(), padding.width(), padding.height(), padding.width());
    HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
    contentRenderer()->hitTest(request, result);

    Node* node = result.innerNonSharedNode();
    if (!node)
        return VisiblePosition();
    RenderObject* renderer = node->renderer();
    if (!renderer)
        return VisiblePosition();
    VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint()));
    if (visiblePos.isNull())
        visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node));
    return visiblePos;
}
void VisibleSelection::adjustSelectionToAvoidCrossingShadowBoundaries()
{
    if (m_base.isNull() || m_start.isNull() || m_end.isNull())
        return;

    Node* startRootNode = m_start.anchorNode()->nonBoundaryShadowTreeRootNode();
    Node* endRootNode = m_end.anchorNode()->nonBoundaryShadowTreeRootNode();

    if (!startRootNode && !endRootNode)
        return;

    if (startRootNode == endRootNode)
        return;

    if (m_baseIsFirst) {
        m_extent = startRootNode ? lastPositionInOrAfterNode(startRootNode) : positionBeforeNode(endRootNode->shadowAncestorNode());
        m_end = m_extent;
    } else {
        m_extent = endRootNode ? firstPositionInOrBeforeNode(endRootNode) : positionAfterNode(startRootNode->shadowAncestorNode());
        m_start = m_extent;
    }

    ASSERT(m_start.anchorNode()->treeScope() == m_end.anchorNode()->treeScope());
}
Beispiel #6
0
static HTMLElement* highestAncestorToWrapMarkup(
    const PositionTemplate<Strategy>& startPosition,
    const PositionTemplate<Strategy>& endPosition,
    EAnnotateForInterchange shouldAnnotate,
    Node* constrainingAncestor) {
  Node* firstNode = startPosition.nodeAsRangeFirstNode();
  // For compatibility reason, we use container node of start and end
  // positions rather than first node and last node in selection.
  Node* commonAncestor =
      Strategy::commonAncestor(*startPosition.computeContainerNode(),
                               *endPosition.computeContainerNode());
  DCHECK(commonAncestor);
  HTMLElement* specialCommonAncestor = nullptr;
  if (shouldAnnotate == AnnotateForInterchange) {
    // Include ancestors that aren't completely inside the range but are
    // required to retain the structure and appearance of the copied markup.
    specialCommonAncestor =
        ancestorToRetainStructureAndAppearance(commonAncestor);
    if (Node* parentListNode = enclosingNodeOfType(
            firstPositionInOrBeforeNode(firstNode), isListItem)) {
      EphemeralRangeTemplate<Strategy> markupRange =
          EphemeralRangeTemplate<Strategy>(startPosition, endPosition);
      EphemeralRangeTemplate<Strategy> nodeRange = normalizeRange(
          EphemeralRangeTemplate<Strategy>::rangeOfContents(*parentListNode));
      if (nodeRange == markupRange) {
        ContainerNode* ancestor = parentListNode->parentNode();
        while (ancestor && !isHTMLListElement(ancestor))
          ancestor = ancestor->parentNode();
        specialCommonAncestor = toHTMLElement(ancestor);
      }
    }

    // Retain the Mail quote level by including all ancestor mail block quotes.
    if (HTMLQuoteElement* highestMailBlockquote =
            toHTMLQuoteElement(highestEnclosingNodeOfType(
                firstPositionInOrBeforeNode(firstNode),
                isMailHTMLBlockquoteElement, CanCrossEditingBoundary)))
      specialCommonAncestor = highestMailBlockquote;
  }

  Node* checkAncestor =
      specialCommonAncestor ? specialCommonAncestor : commonAncestor;
  if (checkAncestor->layoutObject()) {
    HTMLElement* newSpecialCommonAncestor =
        toHTMLElement(highestEnclosingNodeOfType(
            Position::firstPositionInNode(checkAncestor),
            &isPresentationalHTMLElement, CanCrossEditingBoundary,
            constrainingAncestor));
    if (newSpecialCommonAncestor)
      specialCommonAncestor = newSpecialCommonAncestor;
  }

  // If a single tab is selected, commonAncestor will be a text node inside a
  // tab span. If two or more tabs are selected, commonAncestor will be the tab
  // span. In either case, if there is a specialCommonAncestor already, it will
  // necessarily be above any tab span that needs to be included.
  if (!specialCommonAncestor && isTabHTMLSpanElementTextNode(commonAncestor))
    specialCommonAncestor =
        toHTMLSpanElement(Strategy::parent(*commonAncestor));
  if (!specialCommonAncestor && isTabHTMLSpanElement(commonAncestor))
    specialCommonAncestor = toHTMLSpanElement(commonAncestor);

  if (HTMLAnchorElement* enclosingAnchor =
          toHTMLAnchorElement(enclosingElementWithTag(
              Position::firstPositionInNode(specialCommonAncestor
                                                ? specialCommonAncestor
                                                : commonAncestor),
              aTag)))
    specialCommonAncestor = enclosingAnchor;

  return specialCommonAncestor;
}
Beispiel #7
0
static inline HTMLElement*
ancestorToRetainStructureAndAppearanceWithNoLayoutObject(Node* commonAncestor) {
  HTMLElement* commonAncestorBlock = toHTMLElement(enclosingNodeOfType(
      firstPositionInOrBeforeNode(commonAncestor), isHTMLBlockElement));
  return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock);
}