コード例 #1
0
void SelectionAdjuster::adjustSelectionInDOMTree(VisibleSelection* selection, const VisibleSelectionInFlatTree& selectionInFlatTree)
{
    if (selectionInFlatTree.isNone()) {
        *selection = VisibleSelection();
        return;
    }

    const Position& base = toPositionInDOMTree(selectionInFlatTree.base());
    const Position& extent = toPositionInDOMTree(selectionInFlatTree.extent());

    if (isCrossingShadowBoundaries(selectionInFlatTree)) {
        *selection = VisibleSelection(base, extent);
        return;
    }

    const Position& position1 = toPositionInDOMTree(selectionInFlatTree.start());
    const Position& position2 = toPositionInDOMTree(selectionInFlatTree.end());
    selection->m_base = base;
    selection->m_extent = extent;
    selection->m_affinity = selectionInFlatTree.m_affinity;
    selection->m_isDirectional = selectionInFlatTree.m_isDirectional;
    selection->m_granularity = selectionInFlatTree.m_granularity;
    selection->m_hasTrailingWhitespace = selectionInFlatTree.m_hasTrailingWhitespace;
    selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0;
    if (position1.compareTo(position2) <= 0) {
        selection->m_start = position1;
        selection->m_end = position2;
    } else {
        selection->m_start = position2;
        selection->m_end = position1;
    }
    selection->updateSelectionType();
    selection->didChange();
}
コード例 #2
0
TEST_F(DocumentMarkerControllerTest, SetMarkerActiveTest)
{
    setBodyInnerHTML("<b>foo</b>");
    Element* bElement = toElement(document().body()->firstChild());
    EphemeralRange ephemeralRange = EphemeralRange::rangeOfContents(*bElement);
    Position startBElement = toPositionInDOMTree(ephemeralRange.startPosition());
    Position endBElement = toPositionInDOMTree(ephemeralRange.endPosition());
    Range* range = Range::create(document(), startBElement, endBElement);
    // Try to make active a marker that doesn't exist.
    EXPECT_FALSE(markerController().setMarkersActive(range, true));

    // Add a marker and try it once more.
    markerController().addTextMatchMarker(range, false);
    EXPECT_EQ(1u, markerController().markers().size());
    EXPECT_TRUE(markerController().setMarkersActive(range, true));
}
コード例 #3
0
ファイル: SelectionAdjuster.cpp プロジェクト: mirror/chromium
// TODO(yosin): We should make |adjustSelectionInDOMTree()| to return
// |VisibleSelection| once |VisibleSelection| constructor doesn't call
// |validate()|.
void SelectionAdjuster::adjustSelectionInDOMTree(
    VisibleSelection* selection,
    const VisibleSelectionInFlatTree& selectionInFlatTree) {
  if (selectionInFlatTree.isNone()) {
    *selection = VisibleSelection();
    return;
  }

  const Position& base = toPositionInDOMTree(selectionInFlatTree.base());
  const Position& extent = toPositionInDOMTree(selectionInFlatTree.extent());

  if (isCrossingShadowBoundaries(selectionInFlatTree)) {
    DCHECK(base.document());

    // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
    // needs to be audited.  See http://crbug.com/590369 for more details.
    // This layout update call cannot be hoisted out of the |if|, otherwise it's
    // going to cause performance regression (http://crbug.com/652301).
    // TODO(yosin): Implement and apply lazy visible selection validation so
    // that we don't need to update layout here.
    base.document()->updateStyleAndLayoutIgnorePendingStylesheets();

    *selection = createVisibleSelection(
        SelectionInDOMTree::Builder().setBaseAndExtent(base, extent).build());
    return;
  }

  const Position& position1 = toPositionInDOMTree(selectionInFlatTree.start());
  const Position& position2 = toPositionInDOMTree(selectionInFlatTree.end());
  selection->m_base = base;
  selection->m_extent = extent;
  selection->m_affinity = selectionInFlatTree.m_affinity;
  selection->m_isDirectional = selectionInFlatTree.m_isDirectional;
  selection->m_granularity = selectionInFlatTree.m_granularity;
  selection->m_hasTrailingWhitespace =
      selectionInFlatTree.m_hasTrailingWhitespace;
  selection->m_baseIsFirst = base.isNull() || base.compareTo(extent) <= 0;
  if (position1.compareTo(position2) <= 0) {
    selection->m_start = position1;
    selection->m_end = position2;
  } else {
    selection->m_start = position2;
    selection->m_end = position1;
  }
  selection->updateSelectionType();
}
コード例 #4
0
RenderedPosition::RenderedPosition(const PositionInComposedTree& position, TextAffinity affinity)
    : RenderedPosition(toPositionInDOMTree(position), affinity)
{
}
コード例 #5
0
ファイル: TextFinder.cpp プロジェクト: mirror/chromium
void TextFinder::scopeStringMatches(int identifier,
                                    const WebString& searchText,
                                    const WebFindOptions& options,
                                    bool reset) {
  // TODO(dglazkov): The reset/continue cases need to be untangled into two
  // separate functions. This collation of logic is unnecessary and adds to
  // overall complexity of the code.
  if (reset) {
    // This is a brand new search, so we need to reset everything.
    // Scoping is just about to begin.
    m_scopingInProgress = true;

    // Need to keep the current identifier locally in order to finish the
    // request in case the frame is detached during the process.
    m_findRequestIdentifier = identifier;

    // Clear highlighting for this frame.
    unmarkAllTextMatches();

    // Clear the tickmarks and results cache.
    clearFindMatchesCache();

    // Clear the counters from last operation.
    m_lastMatchCount = 0;
    m_nextInvalidateAfter = 0;
    m_resumeScopingFromRange = nullptr;

    // The view might be null on detached frames.
    LocalFrame* frame = ownerFrame().frame();
    if (frame && frame->page())
      m_frameScoping = true;

    // Now, defer scoping until later to allow find operation to finish quickly.
    scopeStringMatchesSoon(
        identifier, searchText, options,
        false);  // false means just reset, so don't do it again.
    return;
  }

  if (!shouldScopeMatches(searchText, options)) {
    finishCurrentScopingEffort(identifier);
    return;
  }

  PositionInFlatTree searchStart =
      PositionInFlatTree::firstPositionInNode(ownerFrame().frame()->document());
  PositionInFlatTree searchEnd =
      PositionInFlatTree::lastPositionInNode(ownerFrame().frame()->document());
  DCHECK_EQ(searchStart.document(), searchEnd.document());

  if (m_resumeScopingFromRange) {
    // This is a continuation of a scoping operation that timed out and didn't
    // complete last time around, so we should start from where we left off.
    DCHECK(m_resumeScopingFromRange->collapsed());
    searchStart = fromPositionInDOMTree<EditingInFlatTreeStrategy>(
        m_resumeScopingFromRange->endPosition());
    if (searchStart.document() != searchEnd.document())
      return;
  }

  // TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets
  // needs to be audited.  see http://crbug.com/590369 for more details.
  searchStart.document()->updateStyleAndLayoutIgnorePendingStylesheets();

  // This timeout controls how long we scope before releasing control. This
  // value does not prevent us from running for longer than this, but it is
  // periodically checked to see if we have exceeded our allocated time.
  const double maxScopingDuration = 0.1;  // seconds

  int matchCount = 0;
  bool timedOut = false;
  double startTime = currentTime();
  do {
    // Find next occurrence of the search string.
    // FIXME: (http://crbug.com/6818) This WebKit operation may run for longer
    // than the timeout value, and is not interruptible as it is currently
    // written. We may need to rewrite it with interruptibility in mind, or
    // find an alternative.
    const EphemeralRangeInFlatTree result =
        findPlainText(EphemeralRangeInFlatTree(searchStart, searchEnd),
                      searchText, options.matchCase ? 0 : CaseInsensitive);
    if (result.isCollapsed()) {
      // Not found.
      break;
    }
    Range* resultRange = Range::create(
        result.document(), toPositionInDOMTree(result.startPosition()),
        toPositionInDOMTree(result.endPosition()));
    if (resultRange->collapsed()) {
      // resultRange will be collapsed if the matched text spans over multiple
      // TreeScopes.  FIXME: Show such matches to users.
      searchStart = result.endPosition();
      continue;
    }

    ++matchCount;

    // Catch a special case where Find found something but doesn't know what
    // the bounding box for it is. In this case we set the first match we find
    // as the active rect.
    IntRect resultBounds = resultRange->boundingBox();
    IntRect activeSelectionRect;
    if (m_locatingActiveRect) {
      activeSelectionRect =
          m_activeMatch.get() ? m_activeMatch->boundingBox() : resultBounds;
    }

    // If the Find function found a match it will have stored where the
    // match was found in m_activeSelectionRect on the current frame. If we
    // find this rect during scoping it means we have found the active
    // tickmark.
    bool foundActiveMatch = false;
    if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) {
      // We have found the active tickmark frame.
      m_currentActiveMatchFrame = true;
      foundActiveMatch = true;
      // We also know which tickmark is active now.
      m_activeMatchIndex = matchCount - 1;
      // To stop looking for the active tickmark, we set this flag.
      m_locatingActiveRect = false;

      // Notify browser of new location for the selected rectangle.
      reportFindInPageSelection(
          ownerFrame().frameView()->contentsToRootFrame(resultBounds),
          m_activeMatchIndex + 1, identifier);
    }

    ownerFrame().frame()->document()->markers().addTextMatchMarker(
        EphemeralRange(resultRange), foundActiveMatch);

    m_findMatchesCache.append(
        FindMatch(resultRange, m_lastMatchCount + matchCount));

    // Set the new start for the search range to be the end of the previous
    // result range. There is no need to use a VisiblePosition here,
    // since findPlainText will use a TextIterator to go over the visible
    // text nodes.
    searchStart = result.endPosition();

    m_resumeScopingFromRange = Range::create(
        result.document(), toPositionInDOMTree(result.endPosition()),
        toPositionInDOMTree(result.endPosition()));
    timedOut = (currentTime() - startTime) >= maxScopingDuration;
  } while (!timedOut);

  // Remember what we search for last time, so we can skip searching if more
  // letters are added to the search string (and last outcome was 0).
  m_lastSearchString = searchText;

  if (matchCount > 0) {
    ownerFrame().frame()->editor().setMarkedTextMatchesAreHighlighted(true);

    m_lastMatchCount += matchCount;

    // Let the frame know how many matches we found during this pass.
    ownerFrame().increaseMatchCount(matchCount, identifier);
  }

  if (timedOut) {
    // If we found anything during this pass, we should redraw. However, we
    // don't want to spam too much if the page is extremely long, so if we
    // reach a certain point we start throttling the redraw requests.
    if (matchCount > 0)
      invalidateIfNecessary();

    // Scoping effort ran out of time, lets ask for another time-slice.
    scopeStringMatchesSoon(identifier, searchText, options,
                           false);  // don't reset.
    return;                         // Done for now, resume work later.
  }

  finishCurrentScopingEffort(identifier);
}