VisiblePosition RenderReplaced::positionForPoint(const IntPoint& point)
{
    InlineBox* box = inlineBoxWrapper();
    if (!box)
        return createVisiblePosition(0, DOWNSTREAM);

    // FIXME: This code is buggy if the replaced element is relative positioned.

    RootInlineBox* root = box->root();

    int top = root->selectionTop();
    int bottom = root->selectionBottom();

    int blockDirectionPosition = box->isHorizontal() ? point.y() + y() : point.x() + x();
    int lineDirectionPosition = box->isHorizontal() ? point.x() + x() : point.y() + y();

    if (blockDirectionPosition < top)
        return createVisiblePosition(caretMinOffset(), DOWNSTREAM); // coordinates are above
    
    if (blockDirectionPosition >= bottom)
        return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); // coordinates are below
    
    if (node()) {
        if (lineDirectionPosition <= box->logicalLeft() + (box->logicalWidth() / 2))
            return createVisiblePosition(0, DOWNSTREAM);
        return createVisiblePosition(1, DOWNSTREAM);
    }

    return RenderBox::positionForPoint(point);
}
Пример #2
0
TEST_F(VisiblePositionTest, ShadowV0DistributedNodes) {
  const char* bodyContent =
      "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
  const char* shadowContent =
      "<a><span id='s4'>44</span><content select=#two></content><span "
      "id='s5'>55</span><content select=#one></content><span "
      "id='s6'>66</span></a>";
  setBodyContent(bodyContent);
  ShadowRoot* shadowRoot = setShadowContent(shadowContent, "host");

  Element* body = document().body();
  Element* one = body->querySelector("#one");
  Element* two = body->querySelector("#two");
  Element* four = shadowRoot->querySelector("#s4");
  Element* five = shadowRoot->querySelector("#s5");

  EXPECT_EQ(Position(one->firstChild(), 0),
            canonicalPositionOf(Position(one, 0)));
  EXPECT_EQ(Position(one->firstChild(), 0),
            createVisiblePosition(Position(one, 0)).deepEquivalent());
  EXPECT_EQ(Position(one->firstChild(), 2),
            canonicalPositionOf(Position(two, 0)));
  EXPECT_EQ(Position(one->firstChild(), 2),
            createVisiblePosition(Position(two, 0)).deepEquivalent());

  EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
            canonicalPositionOf(PositionInFlatTree(one, 0)));
  EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
            createVisiblePosition(PositionInFlatTree(one, 0)).deepEquivalent());
  EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
            canonicalPositionOf(PositionInFlatTree(two, 0)));
  EXPECT_EQ(PositionInFlatTree(four->firstChild(), 2),
            createVisiblePosition(PositionInFlatTree(two, 0)).deepEquivalent());
}
TEST_F(EditingUtilitiesTest, isFirstPositionAfterTable)
{
    const char* bodyContent = "<div contenteditable id=host><table id=table><tr><td>1</td></tr></table><b id=two>22</b></div>";
    const char* shadowContent = "<content select=#two></content><content select=#table></content>";
    setBodyContent(bodyContent);
    setShadowContent(shadowContent, "host");
    updateLayoutAndStyleForPainting();
    Node* host = document().getElementById("host");
    Node* table = document().getElementById("table");

    EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(Position::afterNode(table))));
    EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::afterNode(table))));

    EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(Position::lastPositionInNode(table))));
    EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::lastPositionInNode(table))));

    EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(Position(host, 2))));
    EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree(host, 2))));

    EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(Position::afterNode(host))));
    EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::afterNode(host))));

    EXPECT_EQ(nullptr, isFirstPositionAfterTable(createVisiblePosition(Position::lastPositionInNode(host))));
    EXPECT_EQ(table, isFirstPositionAfterTable(createVisiblePosition(PositionInComposedTree::lastPositionInNode(host))));
}
void GranularityStrategyTest::parseText(const TextNodeVector& textNodes)
{
    bool wordStarted = false;
    int wordStartIndex = 0;
    for (auto& text : textNodes) {
        int wordStartIndexOffset = m_letterPos.size();
        String str = text->wholeText();
        for (size_t i = 0; i < str.length(); i++) {
            m_letterPos.append(visiblePositionToContentsPoint(createVisiblePosition(Position(text, i))));
            char c = str.characterAt(i);
            if (isASCIIAlphanumeric(c) && !wordStarted) {
                wordStartIndex = i + wordStartIndexOffset;
                wordStarted = true;
            } else if (!isASCIIAlphanumeric(c) && wordStarted) {
                IntPoint wordMiddle((m_letterPos[wordStartIndex].x() + m_letterPos[i + wordStartIndexOffset].x()) / 2, m_letterPos[wordStartIndex].y());
                m_wordMiddles.append(wordMiddle);
                wordStarted = false;
            }
        }
    }
    if (wordStarted) {
        const auto& lastNode = textNodes.last();
        int xEnd = visiblePositionToContentsPoint(createVisiblePosition(Position(lastNode, lastNode->wholeText().length()))).x();
        IntPoint wordMiddle((m_letterPos[wordStartIndex].x() + xEnd) / 2, m_letterPos[wordStartIndex].y());
        m_wordMiddles.append(wordMiddle);
    }
}
Пример #5
0
void DOMSelection::setBaseAndExtent(Node* baseNode, int baseOffset, Node* extentNode, int extentOffset, ExceptionState& exceptionState)
{
    if (!m_frame)
        return;

    if (baseOffset < 0) {
        exceptionState.throwDOMException(IndexSizeError, String::number(baseOffset) + " is not a valid base offset.");
        return;
    }

    if (extentOffset < 0) {
        exceptionState.throwDOMException(IndexSizeError, String::number(extentOffset) + " is not a valid extent offset.");
        return;
    }

    if (!baseNode || !extentNode)
        UseCounter::count(m_frame, UseCounter::SelectionSetBaseAndExtentNull);

    if (!isValidForPosition(baseNode) || !isValidForPosition(extentNode))
        return;

    VisiblePosition visibleBase = createVisiblePosition(createPosition(baseNode, baseOffset));
    VisiblePosition visibleExtent = createVisiblePosition(createPosition(extentNode, extentOffset));

    m_frame->selection().moveTo(visibleBase, visibleExtent);
}
Пример #6
0
VisibleSelectionTemplate<Strategy> PendingSelection::calcVisibleSelectionAlgorithm(const VisibleSelectionTemplate<Strategy>& originalSelection) const
{
    const PositionTemplate<Strategy> start = originalSelection.start();
    const PositionTemplate<Strategy> end = originalSelection.end();
    SelectionType selectionType = originalSelection.selectionType();
    const TextAffinity affinity = originalSelection.affinity();

    bool paintBlockCursor = m_frameSelection->shouldShowBlockCursor() && selectionType == SelectionType::CaretSelection && !isLogicalEndOfLine(createVisiblePosition(end, affinity));
    VisibleSelectionTemplate<Strategy> selection;
    if (enclosingTextFormControl(start.computeContainerNode())) {
        // TODO(yosin) We should use |PositionMoveType::Character| to avoid
        // ending paint at middle of character.
        PositionTemplate<Strategy> endPosition = paintBlockCursor ? nextPositionOf(originalSelection.extent(), PositionMoveType::CodePoint) : end;
        selection.setWithoutValidation(start, endPosition);
        return selection;
    }

    const VisiblePositionTemplate<Strategy> visibleStart = createVisiblePosition(start, selectionType == SelectionType::RangeSelection ? TextAffinity::Downstream : affinity);
    if (paintBlockCursor) {
        VisiblePositionTemplate<Strategy> visibleExtent = createVisiblePosition(end, affinity);
        visibleExtent = nextPositionOf(visibleExtent, CanSkipOverEditingBoundary);
        return VisibleSelectionTemplate<Strategy>(visibleStart, visibleExtent);
    }
    const VisiblePositionTemplate<Strategy> visibleEnd = createVisiblePosition(end, selectionType == SelectionType::RangeSelection ? TextAffinity::Upstream : affinity);
    return VisibleSelectionTemplate<Strategy>(visibleStart, visibleEnd);
}
VisiblePosition RenderReplaced::positionForPoint(const IntPoint& point)
{
    InlineBox* box = inlineBoxWrapper();
    if (!box)
        return createVisiblePosition(0, DOWNSTREAM);

    // FIXME: This code is buggy if the replaced element is relative positioned.

    RootInlineBox* root = box->root();

    int top = root->topOverflow();
    int bottom = root->nextRootBox() ? root->nextRootBox()->topOverflow() : root->bottomOverflow();

    if (point.y() + y() < top)
        return createVisiblePosition(caretMinOffset(), DOWNSTREAM); // coordinates are above

    if (point.y() + y() >= bottom)
        return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); // coordinates are below

    if (node()) {
        if (point.x() <= width() / 2)
            return createVisiblePosition(0, DOWNSTREAM);
        return createVisiblePosition(1, DOWNSTREAM);
    }

    return RenderBox::positionForPoint(point);
}
Пример #8
0
VisiblePosition SelectionEditor::modifyMovingLeft(TextGranularity granularity)
{
    VisiblePosition pos;
    switch (granularity) {
    case CharacterGranularity:
        if (m_selection.isRange()) {
            if (directionOfSelection() == LTR)
                pos = createVisiblePosition(m_selection.start(), m_selection.affinity());
            else
                pos = createVisiblePosition(m_selection.end(), m_selection.affinity());
        } else {
            pos = leftPositionOf(createVisiblePosition(m_selection.extent(), m_selection.affinity()));
        }
        break;
    case WordGranularity: {
        bool skipsSpaceWhenMovingRight = frame() && frame()->editor().behavior().shouldSkipSpaceWhenMovingRight();
        pos = leftWordPosition(createVisiblePosition(m_selection.extent(), m_selection.affinity()), skipsSpaceWhenMovingRight);
        break;
    }
    case SentenceGranularity:
    case LineGranularity:
    case ParagraphGranularity:
    case SentenceBoundary:
    case ParagraphBoundary:
    case DocumentBoundary:
        // FIXME: Implement all of the above.
        pos = modifyMovingBackward(granularity);
        break;
    case LineBoundary:
        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
        break;
    }
    return pos;
}
void testFunctionEquivalence(const Position& position, PositionFunction positionFunction, VisblePositionFunction visibleFunction)
{
    VisiblePosition visiblePosition = createVisiblePosition(position);
    VisiblePosition expected = visibleFunction(visiblePosition);
    VisiblePosition actual = createVisiblePosition(positionFunction(position));
    EXPECT_EQ(expected.deepEquivalent(), actual.deepEquivalent());
}
Пример #10
0
VisiblePosition RenderReplaced::positionForPoint(const LayoutPoint& point, const RenderRegion* region)
{
    // FIXME: This code is buggy if the replaced element is relative positioned.
    InlineBox* box = inlineBoxWrapper();
    const RootInlineBox* rootBox = box ? &box->root() : 0;
    
    LayoutUnit top = rootBox ? rootBox->selectionTop() : logicalTop();
    LayoutUnit bottom = rootBox ? rootBox->selectionBottom() : logicalBottom();
    
    LayoutUnit blockDirectionPosition = isHorizontalWritingMode() ? point.y() + y() : point.x() + x();
    LayoutUnit lineDirectionPosition = isHorizontalWritingMode() ? point.x() + x() : point.y() + y();
    
    if (blockDirectionPosition < top)
        return createVisiblePosition(caretMinOffset(), DOWNSTREAM); // coordinates are above
    
    if (blockDirectionPosition >= bottom)
        return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); // coordinates are below
    
    if (element()) {
        if (lineDirectionPosition <= logicalLeft() + (logicalWidth() / 2))
            return createVisiblePosition(0, DOWNSTREAM);
        return createVisiblePosition(1, DOWNSTREAM);
    }

    return RenderBox::positionForPoint(point, region);
}
Пример #11
0
VisiblePosition SelectionModifier::modifyMovingForward(
    TextGranularity granularity) {
  VisiblePosition pos;
  // FIXME: Stay in editable content for the less common granularities.
  switch (granularity) {
    case CharacterGranularity:
      if (m_selection.isRange())
        pos = createVisiblePosition(m_selection.end(), m_selection.affinity());
      else
        pos = nextPositionOf(
            createVisiblePosition(m_selection.extent(), m_selection.affinity()),
            CanSkipOverEditingBoundary);
      break;
    case WordGranularity:
      pos = nextWordPositionForPlatform(
          createVisiblePosition(m_selection.extent(), m_selection.affinity()));
      break;
    case SentenceGranularity:
      pos = nextSentencePosition(
          createVisiblePosition(m_selection.extent(), m_selection.affinity()));
      break;
    case LineGranularity: {
      // down-arrowing from a range selection that ends at the start of a line
      // needs to leave the selection at that line start (no need to call
      // nextLinePosition!)
      pos = endForPlatform();
      if (!m_selection.isRange() || !isStartOfLine(pos))
        pos = nextLinePosition(
            pos, lineDirectionPointForBlockDirectionNavigation(START));
      break;
    }
    case ParagraphGranularity:
      pos = nextParagraphPosition(
          endForPlatform(),
          lineDirectionPointForBlockDirectionNavigation(START));
      break;
    case SentenceBoundary:
      pos = endOfSentence(endForPlatform());
      break;
    case LineBoundary:
      pos = logicalEndOfLine(endForPlatform());
      break;
    case ParagraphBoundary:
      pos = endOfParagraph(endForPlatform());
      break;
    case DocumentBoundary:
      pos = endForPlatform();
      if (isEditablePosition(pos.deepEquivalent()))
        pos = endOfEditableContent(pos);
      else
        pos = endOfDocument(pos);
      break;
  }
  return pos;
}
Пример #12
0
VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point, const RenderRegion*)
{
    if (!firstTextBox() || !textLength())
        return createVisiblePosition(0, DOWNSTREAM);

    float baseline = m_scaledFont.fontMetrics().floatAscent();

    RenderBlock* containingBlock = this->containingBlock();
    ASSERT(containingBlock);

    // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates.
    FloatPoint absolutePoint(point);
    absolutePoint.moveBy(containingBlock->location());

    float closestDistance = std::numeric_limits<float>::max();
    float closestDistancePosition = 0;
    const SVGTextFragment* closestDistanceFragment = nullptr;
    SVGInlineTextBox* closestDistanceBox = nullptr;

    AffineTransform fragmentTransform;
    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
        if (!is<SVGInlineTextBox>(*box))
            continue;

        auto& textBox = downcast<SVGInlineTextBox>(*box);
        Vector<SVGTextFragment>& fragments = textBox.textFragments();

        unsigned textFragmentsSize = fragments.size();
        for (unsigned i = 0; i < textFragmentsSize; ++i) {
            const SVGTextFragment& fragment = fragments.at(i);
            FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
            fragment.buildFragmentTransform(fragmentTransform);
            if (!fragmentTransform.isIdentity())
                fragmentRect = fragmentTransform.mapRect(fragmentRect);

            float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) +
                             powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2);

            if (distance < closestDistance) {
                closestDistance = distance;
                closestDistanceBox = &textBox;
                closestDistanceFragment = &fragment;
                closestDistancePosition = fragmentRect.x();
            }
        }
    }

    if (!closestDistanceFragment)
        return createVisiblePosition(0, DOWNSTREAM);

    int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true);
    return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
}
Пример #13
0
VisiblePosition HTMLTextFormControlElement::visiblePositionForIndex(int index) const
{
    if (index <= 0)
        return createVisiblePosition(Position::firstPositionInNode(innerEditorElement()));
    Position start, end;
    bool selected = Range::selectNodeContents(innerEditorElement(), start, end);
    if (!selected)
        return VisiblePosition();
    CharacterIterator it(start, end);
    it.advance(index - 1);
    return createVisiblePosition(it.endPosition(), TextAffinity::Upstream);
}
Пример #14
0
VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point)
{
    if (!firstTextBox() || !textLength())
        return createVisiblePosition(0, DOWNSTREAM);

    RenderStyle* style = this->style();
    ASSERT(style);
    int baseline = style->font().ascent();

    RenderBlock* containingBlock = this->containingBlock();
    ASSERT(containingBlock);

    // Map local point to absolute point, as the character origins stored in the text fragments use absolute coordinates.
    FloatPoint absolutePoint(point);
    absolutePoint.move(containingBlock->x(), containingBlock->y());

    float closestDistance = std::numeric_limits<float>::max();
    float closestDistancePosition = 0;
    const SVGTextFragment* closestDistanceFragment = 0;
    SVGInlineTextBox* closestDistanceBox = 0;

    for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
        ASSERT(box->isSVGInlineTextBox());
        SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(box);
        Vector<SVGTextFragment>& fragments = textBox->textFragments();

        unsigned textFragmentsSize = fragments.size();
        for (unsigned i = 0; i < textFragmentsSize; ++i) {
            const SVGTextFragment& fragment = fragments.at(i);
            FloatRect fragmentRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height);
            if (!fragment.transform.isIdentity())
                fragmentRect = fragment.transform.mapRect(fragmentRect);

            float distance = powf(fragmentRect.x() - absolutePoint.x(), 2) +
                             powf(fragmentRect.y() + fragmentRect.height() / 2 - absolutePoint.y(), 2);

            if (distance < closestDistance) {
                closestDistance = distance;
                closestDistanceBox = textBox;
                closestDistanceFragment = &fragment;
                closestDistancePosition = fragmentRect.x();
            }
        }
    }

    if (!closestDistanceFragment)
        return createVisiblePosition(0, DOWNSTREAM);

    int offset = closestDistanceBox->offsetForPositionInFragment(*closestDistanceFragment, absolutePoint.x() - closestDistancePosition, true);
    return createVisiblePosition(offset + closestDistanceBox->start(), offset > 0 ? VP_UPSTREAM_IF_POSSIBLE : DOWNSTREAM);
}
Пример #15
0
VisiblePosition SelectionModifier::modifyMovingBackward(
    TextGranularity granularity) {
  VisiblePosition pos;
  switch (granularity) {
    case CharacterGranularity:
      if (m_selection.isRange())
        pos =
            createVisiblePosition(m_selection.start(), m_selection.affinity());
      else
        pos = previousPositionOf(
            createVisiblePosition(m_selection.extent(), m_selection.affinity()),
            CanSkipOverEditingBoundary);
      break;
    case WordGranularity:
      pos = previousWordPosition(
          createVisiblePosition(m_selection.extent(), m_selection.affinity()));
      break;
    case SentenceGranularity:
      pos = previousSentencePosition(
          createVisiblePosition(m_selection.extent(), m_selection.affinity()));
      break;
    case LineGranularity:
      pos = previousLinePosition(
          startForPlatform(),
          lineDirectionPointForBlockDirectionNavigation(START));
      break;
    case ParagraphGranularity:
      pos = previousParagraphPosition(
          startForPlatform(),
          lineDirectionPointForBlockDirectionNavigation(START));
      break;
    case SentenceBoundary:
      pos = startOfSentence(startForPlatform());
      break;
    case LineBoundary:
      pos = logicalStartOfLine(startForPlatform());
      break;
    case ParagraphBoundary:
      pos = startOfParagraph(startForPlatform());
      break;
    case DocumentBoundary:
      pos = startForPlatform();
      if (isEditablePosition(pos.deepEquivalent()))
        pos = startOfEditableContent(pos);
      else
        pos = startOfDocument(pos);
      break;
  }
  return pos;
}
Пример #16
0
VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInContents, const RenderRegion* region)
{
    RootInlineBox* rootBox = firstRootBox();
    if (!rootBox)
        return createVisiblePosition(0, DOWNSTREAM);

    ASSERT(!rootBox->nextRootBox());
    ASSERT(childrenInline());

    InlineBox* closestBox = downcast<SVGRootInlineBox>(*rootBox).closestLeafChildForPosition(pointInContents);
    if (!closestBox)
        return createVisiblePosition(0, DOWNSTREAM);

    return closestBox->renderer().positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y()), region);
}
Пример #17
0
void FrameCaret::updateAppearance() {
  // Paint a block cursor instead of a caret in overtype mode unless the caret
  // is at the end of a line (in this case the FrameSelection will paint a
  // blinking caret as usual).
  bool paintBlockCursor = m_shouldShowBlockCursor && isActive();
  if (paintBlockCursor) {
    // TODO(editing-dev): Use of updateStyleAndLayoutIgnorePendingStylesheets
    // needs to be audited.  see http://crbug.com/590369 for more details.
    // In the long term, we should defer the update of the caret's appearance
    // to prevent synchronous layout.
    m_frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();

    if (isLogicalEndOfLine(createVisiblePosition(caretPosition())))
      paintBlockCursor = false;
  }

  bool shouldBlink = !paintBlockCursor && shouldBlinkCaret();

  // If the caret moved, stop the blink timer so we can restart with a
  // black caret in the new location.
  if (!shouldBlink || shouldStopBlinkingDueToTypingCommand(m_frame))
    stopCaretBlinkTimer();

  // Start blinking with a black caret. Be sure not to restart if we're
  // already blinking in the right location.
  if (shouldBlink)
    startBlinkCaret();
}
// Test for the default CharacterGranularityStrategy
TEST_F(GranularityStrategyTest, Character)
{
    dummyPageHolder().frame().settings()->setSelectionStrategy(SelectionStrategy::Character);
    dummyPageHolder().frame().settings()->setDefaultFontSize(12);
    // "Foo Bar Baz,"
    RefPtrWillBeRawPtr<Text> text = appendTextNode("Foo Bar Baz,");
    // "Foo B^a|>r Baz," (^ means base, | means extent, , < means start, and > means end).
    selection().setSelection(VisibleSelection(Position(text, 5), Position(text, 6)));
    EXPECT_EQ_SELECTED_TEXT("a");
    // "Foo B^ar B|>az,"
    selection().moveRangeSelectionExtent(visiblePositionToContentsPoint(createVisiblePosition(Position(text, 9))));
    EXPECT_EQ_SELECTED_TEXT("ar B");
    // "F<|oo B^ar Baz,"
    selection().moveRangeSelectionExtent(visiblePositionToContentsPoint(createVisiblePosition(Position(text, 1))));
    EXPECT_EQ_SELECTED_TEXT("oo B");
}
Пример #19
0
TEST_F(VisiblePositionTest, NonNullIsValidBeforeMutation) {
  setBodyContent("<p>one</p>");

  Element* paragraph = document().querySelector("p");
  Position position(paragraph->firstChild(), 1);
  EXPECT_TRUE(createVisiblePosition(position).isValid());
}
Пример #20
0
VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInContents, const RenderRegion* region)
{
    RootInlineBox* rootBox = firstRootBox();
    if (!rootBox)
        return createVisiblePosition(0, DOWNSTREAM);

    ASSERT_WITH_SECURITY_IMPLICATION(rootBox->isSVGRootInlineBox());
    ASSERT(!rootBox->nextRootBox());
    ASSERT(childrenInline());

    InlineBox* closestBox = toSVGRootInlineBox(rootBox)->closestLeafChildForPosition(pointInContents);
    if (!closestBox)
        return createVisiblePosition(0, DOWNSTREAM);

    return closestBox->renderer().positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y()), region);
}
Пример #21
0
VisiblePosition RenderSVGText::positionForPoint(const IntPoint& pointInContents)
{
    RootInlineBox* rootBox = firstRootBox();
    if (!rootBox)
        return createVisiblePosition(0, DOWNSTREAM);

    ASSERT(rootBox->isSVGRootInlineBox());
    ASSERT(!rootBox->nextRootBox());
    ASSERT(childrenInline());

    InlineBox* closestBox = static_cast<SVGRootInlineBox*>(rootBox)->closestLeafChildForPosition(pointInContents);
    if (!closestBox)
        return createVisiblePosition(0, DOWNSTREAM);

    return closestBox->renderer()->positionForPoint(IntPoint(pointInContents.x(), closestBox->m_y));
}
Пример #22
0
static void adjustPositionForUserSelectAll(VisiblePosition& pos,
                                           bool isForward) {
  if (Node* rootUserSelectAll = EditingStrategy::rootUserSelectAllForNode(
          pos.deepEquivalent().anchorNode()))
    pos = createVisiblePosition(
        isForward
            ? mostForwardCaretPosition(Position::afterNode(rootUserSelectAll),
                                       CanCrossEditingBoundary)
            : mostBackwardCaretPosition(Position::beforeNode(rootUserSelectAll),
                                        CanCrossEditingBoundary));
}
Пример #23
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());
}
Пример #24
0
TEST_F(VisiblePositionTest, ShadowV0DistributedNodes)
{
    const char* bodyContent = "<p id='host'>00<b id='one'>11</b><b id='two'>22</b>33</p>";
    const char* shadowContent = "<a><span id='s4'>44</span><content select=#two></content><span id='s5'>55</span><content select=#one></content><span id='s6'>66</span></a>";
    setBodyContent(bodyContent);
    RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent, "host");

    RefPtrWillBeRawPtr<Element> body = document().body();
    RefPtrWillBeRawPtr<Element> one = body->querySelector("#one", ASSERT_NO_EXCEPTION);
    RefPtrWillBeRawPtr<Element> two = body->querySelector("#two", ASSERT_NO_EXCEPTION);
    RefPtrWillBeRawPtr<Element> four = shadowRoot->querySelector("#s4", ASSERT_NO_EXCEPTION);
    RefPtrWillBeRawPtr<Element> five = shadowRoot->querySelector("#s5", ASSERT_NO_EXCEPTION);

    EXPECT_EQ(Position(one->firstChild(), 0), canonicalPositionOf(Position(one, 0)));
    EXPECT_EQ(Position(one->firstChild(), 0), createVisiblePosition(Position(one, 0)).deepEquivalent());
    EXPECT_EQ(Position(one->firstChild(), 2), canonicalPositionOf(Position(two.get(), 0)));
    EXPECT_EQ(Position(one->firstChild(), 2), createVisiblePosition(Position(two.get(), 0)).deepEquivalent());

    EXPECT_EQ(PositionInComposedTree(five->firstChild(), 2), canonicalPositionOf(PositionInComposedTree(one.get(), 0)));
    EXPECT_EQ(PositionInComposedTree(five->firstChild(), 2), createVisiblePosition(PositionInComposedTree(one.get(), 0)).deepEquivalent());
    EXPECT_EQ(PositionInComposedTree(four->firstChild(), 2), canonicalPositionOf(PositionInComposedTree(two.get(), 0)));
    EXPECT_EQ(PositionInComposedTree(four->firstChild(), 2), createVisiblePosition(PositionInComposedTree(two.get(), 0)).deepEquivalent());
}
Пример #25
0
void DOMSelection::collapseToStart(ExceptionState& exceptionState)
{
    if (!m_frame)
        return;

    const VisibleSelection& selection = m_frame->selection().selection();

    if (selection.isNone()) {
        exceptionState.throwDOMException(InvalidStateError, "there is no selection.");
        return;
    }

    m_frame->selection().moveTo(createVisiblePosition(selection.start()));
}
Пример #26
0
TEST_F(VisiblePositionTest, NonNullInvalidatedAfterStyleChange) {
  setBodyContent("<div>one</div><p>two</p>");

  Element* paragraph = document().querySelector("p");
  Element* div = document().querySelector("div");
  Position position(paragraph->firstChild(), 1);

  VisiblePosition visiblePosition1 = createVisiblePosition(position);
  div->style()->setProperty("color", "red", "important", ASSERT_NO_EXCEPTION);
  EXPECT_FALSE(visiblePosition1.isValid());

  updateAllLifecyclePhases();

  VisiblePosition visiblePosition2 = createVisiblePosition(position);
  div->style()->setProperty("display", "none", "important",
                            ASSERT_NO_EXCEPTION);
  EXPECT_FALSE(visiblePosition2.isValid());

  updateAllLifecyclePhases();

  // Invalid VisiblePosition can never become valid again.
  EXPECT_FALSE(visiblePosition1.isValid());
  EXPECT_FALSE(visiblePosition2.isValid());
}
Пример #27
0
static EphemeralRange expandEndToSentenceBoundary(const EphemeralRange& range) {
  DCHECK(range.isNotNull());
  const VisiblePosition& visibleEnd =
      createVisiblePosition(range.endPosition());
  DCHECK(visibleEnd.isNotNull());
  const Position& sentenceEnd = endOfSentence(visibleEnd).deepEquivalent();
  // TODO(xiaochengh): |sentenceEnd < range.endPosition()| is possible,
  // which would trigger a DCHECK in EphemeralRange's constructor if we return
  // it directly. However, this shouldn't happen and needs to be fixed.
  return EphemeralRange(
      range.startPosition(),
      sentenceEnd.isNotNull() && sentenceEnd > range.endPosition()
          ? sentenceEnd
          : range.endPosition());
}
Пример #28
0
VisiblePosition RenderSVGInlineText::positionForPoint(const IntPoint& point)
{
    SVGInlineTextBox* textBox = static_cast<SVGInlineTextBox*>(firstTextBox());

    if (!textBox || textLength() == 0)
        return createVisiblePosition(0, DOWNSTREAM);

    SVGRootInlineBox* rootBox = textBox->svgRootInlineBox();
    RenderBlock* object = rootBox ? rootBox->block() : 0;

    if (!object)
        return createVisiblePosition(0, DOWNSTREAM);

    int closestOffsetInBox = 0;

    // FIXME: This approach is wrong.  The correct code would first find the
    // closest SVGInlineTextBox to the point, and *then* ask only that inline box
    // what the closest text offset to that point is.  This code instead walks
    // through all boxes in order, so when you click "near" a box, you'll actually
    // end up returning the nearest offset in the last box, even if the
    // nearest offset to your click is contained in another box.
    for (SVGInlineTextBox* box = textBox; box; box = static_cast<SVGInlineTextBox*>(box->nextTextBox())) {
        if (box->svgCharacterHitsPosition(point.x() + object->x(), point.y() + object->y(), closestOffsetInBox)) {
            // If we're not at the end/start of the box, stop looking for other selected boxes.
            if (box->direction() == LTR) {
                if (closestOffsetInBox <= (int) box->end() + 1)
                    break;
            } else {
                if (closestOffsetInBox > (int) box->start())
                    break;
            }
        }
    }

    return createVisiblePosition(closestOffsetInBox, DOWNSTREAM);
}
Пример #29
0
VisiblePosition SelectionModifier::modifyExtendingBackward(
    TextGranularity granularity) {
  VisiblePosition pos =
      createVisiblePosition(m_selection.extent(), m_selection.affinity());

  // Extending a selection backward by word or character from just after a table
  // selects the table.  This "makes sense" from the user perspective, esp. when
  // deleting. It was done here instead of in VisiblePosition because we want
  // VPs to iterate over everything.
  switch (granularity) {
    case CharacterGranularity:
      pos = previousPositionOf(pos, CanSkipOverEditingBoundary);
      break;
    case WordGranularity:
      pos = previousWordPosition(pos);
      break;
    case SentenceGranularity:
      pos = previousSentencePosition(pos);
      break;
    case LineGranularity:
      pos = previousLinePosition(
          pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
      break;
    case ParagraphGranularity:
      pos = previousParagraphPosition(
          pos, lineDirectionPointForBlockDirectionNavigation(EXTENT));
      break;
    case SentenceBoundary:
      pos = startOfSentence(startForPlatform());
      break;
    case LineBoundary:
      pos = logicalStartOfLine(startForPlatform());
      break;
    case ParagraphBoundary:
      pos = startOfParagraph(startForPlatform());
      break;
    case DocumentBoundary:
      pos = startForPlatform();
      if (isEditablePosition(pos.deepEquivalent()))
        pos = startOfEditableContent(pos);
      else
        pos = startOfDocument(pos);
      break;
  }
  adjustPositionForUserSelectAll(pos, !(directionOfEnclosingBlock() == LTR));
  return pos;
}
Пример #30
0
TEST_F(VisiblePositionTest, NonNullInvalidatedAfterDOMChange) {
  setBodyContent("<p>one</p>");

  Element* paragraph = document().querySelector("p");
  Position position(paragraph->firstChild(), 1);
  VisiblePosition nullVisiblePosition;
  VisiblePosition nonNullVisiblePosition = createVisiblePosition(position);

  Element* div = document().createElement("div");
  document().body()->appendChild(div);

  EXPECT_TRUE(nullVisiblePosition.isValid());
  EXPECT_FALSE(nonNullVisiblePosition.isValid());

  updateAllLifecyclePhases();

  // Invalid VisiblePosition can never become valid again.
  EXPECT_FALSE(nonNullVisiblePosition.isValid());
}