Commit 00d9f74f authored by yosin@chromium.org's avatar yosin@chromium.org

Move canonicalPosition() for VisiblePosition to VisibleUnits.cpp

This patch moves |canonicalPosition()| for |VisiblePosition| to
"VisibleUnits.cpp" form "VisiblePosition.cpp" to make "VisiblePosition.cpp"
to simpler for improving code health and ease of templatizing |VisiblePosition|
class to introduce composed tree version.

This patch is a preparation of making selection to handle granularity for web
component, http://crrev.com/1277863002

BUG=513568
TEST=n/a; no behavior changes

Review URL: https://codereview.chromium.org/1314033005

git-svn-id: svn://svn.chromium.org/blink/trunk@201526 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 09ace5e7
......@@ -463,105 +463,10 @@ VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition& pos, const
return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
}
template <typename PositionType>
static PositionType canonicalizeCandidate(const PositionType& candidate)
{
if (candidate.isNull())
return PositionType();
ASSERT(isVisuallyEquivalentCandidate(candidate));
PositionType upstream = mostBackwardCaretPosition(candidate);
if (isVisuallyEquivalentCandidate(upstream))
return upstream;
return candidate;
}
template <typename PositionType>
static PositionType canonicalPosition(const PositionType& passedPosition)
{
// Sometimes updating selection positions can be extremely expensive and occur
// frequently. Often calling preventDefault on mousedown events can avoid
// doing unnecessary text selection work. http://crbug.com/472258.
TRACE_EVENT0("blink", "VisiblePosition::canonicalPosition");
// The updateLayout call below can do so much that even the position passed
// in to us might get changed as a side effect. Specifically, there are code
// paths that pass selection endpoints, and updateLayout can change the selection.
PositionType position = passedPosition;
// FIXME (9535): Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will
// ask layoutObjects to paint downstream carets for other layoutObjects.
// To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
// the appropriate layoutObject for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
// unless the affinity is upstream.
if (position.isNull())
return PositionType();
ASSERT(position.document());
position.document()->updateLayoutIgnorePendingStylesheets();
Node* node = position.computeContainerNode();
PositionType candidate = mostBackwardCaretPosition(position);
if (isVisuallyEquivalentCandidate(candidate))
return candidate;
candidate = mostForwardCaretPosition(position);
if (isVisuallyEquivalentCandidate(candidate))
return candidate;
// When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave
// blocks or enter new ones), we search forward and backward until we find one.
PositionType next = canonicalizeCandidate(nextCandidate(position));
PositionType prev = canonicalizeCandidate(previousCandidate(position));
Node* nextNode = next.anchorNode();
Node* prevNode = prev.anchorNode();
// The new position must be in the same editable element. Enforce that first.
// Unless the descent is from a non-editable html element to an editable body.
if (isHTMLHtmlElement(node) && !node->hasEditableStyle() && node->document().body() && node->document().body()->hasEditableStyle())
return next.isNotNull() ? next : prev;
Element* editingRoot = editableRootForPosition(position);
// If the html element is editable, descending into its body will look like a descent
// from non-editable to editable content since rootEditableElement() always stops at the body.
if (isHTMLHtmlElement(editingRoot) || position.anchorNode()->isDocumentNode())
return next.isNotNull() ? next : prev;
bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
return prev;
if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
return next;
if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
return PositionType();
// The new position should be in the same block flow element. Favor that.
Element* originalBlock = node ? enclosingBlockFlowElement(*node) : 0;
bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
return prev;
return next;
}
Position canonicalPositionOf(const Position& position)
{
return canonicalPosition(position);
}
PositionInComposedTree canonicalPositionOf(const PositionInComposedTree& position)
{
return canonicalPosition(position);
}
template<typename Strategy>
static PositionWithAffinityTemplate<Strategy> visiblePositionOfAlgorithm(const PositionAlgorithm<Strategy>& position, TextAffinity affinity)
{
const PositionAlgorithm<Strategy> deepPosition = canonicalPosition(position);
const PositionAlgorithm<Strategy> deepPosition = canonicalPositionOf(position);
if (deepPosition.isNull())
return PositionWithAffinityTemplate<Strategy>();
if (affinity == TextAffinity::Downstream)
......
......@@ -121,9 +121,6 @@ CORE_EXPORT IntRect absoluteCaretBoundsOf(const VisiblePosition&);
VisiblePosition leftPositionOf(const VisiblePosition&);
VisiblePosition rightPositionOf(const VisiblePosition&);
CORE_EXPORT Position canonicalPositionOf(const Position&);
CORE_EXPORT PositionInComposedTree canonicalPositionOf(const PositionInComposedTree&);
// TODO(yosin) We should move |honorEditingBoundaryAtOr{Before,After} to
// "VisibleUnits.cpp" as static function.
// next() and previous() will increment/decrement by a character cluster.
......
......@@ -6,6 +6,7 @@
#include "core/editing/VisiblePosition.h"
#include "core/editing/EditingTestBase.h"
#include "core/editing/VisibleUnits.h"
namespace blink {
......
......@@ -66,6 +66,106 @@ namespace blink {
using namespace HTMLNames;
using namespace WTF::Unicode;
template <typename PositionType>
static PositionType canonicalizeCandidate(const PositionType& candidate)
{
if (candidate.isNull())
return PositionType();
ASSERT(isVisuallyEquivalentCandidate(candidate));
PositionType upstream = mostBackwardCaretPosition(candidate);
if (isVisuallyEquivalentCandidate(upstream))
return upstream;
return candidate;
}
template <typename PositionType>
static PositionType canonicalPosition(const PositionType& passedPosition)
{
// Sometimes updating selection positions can be extremely expensive and
// occur frequently. Often calling preventDefault on mousedown events can
// avoid doing unnecessary text selection work. http://crbug.com/472258.
TRACE_EVENT0("blink", "VisiblePosition::canonicalPosition");
// The updateLayout call below can do so much that even the position passed
// in to us might get changed as a side effect. Specifically, there are code
// paths that pass selection endpoints, and updateLayout can change the
// selection.
PositionType position = passedPosition;
// FIXME (9535): Canonicalizing to the leftmost candidate means that if
// we're at a line wrap, we will ask layoutObjects to paint downstream
// carets for other layoutObjects. To fix this, we need to either a) add
// code to all paintCarets to pass the responsibility off to the appropriate
// layoutObject for VisiblePosition's like these, or b) canonicalize to the
// rightmost candidate unless the affinity is upstream.
if (position.isNull())
return PositionType();
ASSERT(position.document());
position.document()->updateLayoutIgnorePendingStylesheets();
Node* node = position.computeContainerNode();
PositionType candidate = mostBackwardCaretPosition(position);
if (isVisuallyEquivalentCandidate(candidate))
return candidate;
candidate = mostForwardCaretPosition(position);
if (isVisuallyEquivalentCandidate(candidate))
return candidate;
// When neither upstream or downstream gets us to a candidate
// (upstream/downstream won't leave blocks or enter new ones), we search
// forward and backward until we find one.
PositionType next = canonicalizeCandidate(nextCandidate(position));
PositionType prev = canonicalizeCandidate(previousCandidate(position));
Node* nextNode = next.anchorNode();
Node* prevNode = prev.anchorNode();
// The new position must be in the same editable element. Enforce that
// first. Unless the descent is from a non-editable html element to an
// editable body.
if (isHTMLHtmlElement(node) && !node->hasEditableStyle() && node->document().body() && node->document().body()->hasEditableStyle())
return next.isNotNull() ? next : prev;
Element* editingRoot = editableRootForPosition(position);
// If the html element is editable, descending into its body will look like
// a descent from non-editable to editable content since
// |rootEditableElementOf()| always stops at the body.
if (isHTMLHtmlElement(editingRoot) || position.anchorNode()->isDocumentNode())
return next.isNotNull() ? next : prev;
bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
return prev;
if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
return next;
if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
return PositionType();
// The new position should be in the same block flow element. Favor that.
Element* originalBlock = node ? enclosingBlockFlowElement(*node) : 0;
bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
return prev;
return next;
}
Position canonicalPositionOf(const Position& position)
{
return canonicalPosition(position);
}
PositionInComposedTree canonicalPositionOf(const PositionInComposedTree& position)
{
return canonicalPosition(position);
}
static Node* previousLeafWithSameEditability(Node* node, EditableType editableType)
{
bool editable = node->hasEditableStyle(editableType);
......
......@@ -85,6 +85,9 @@ CORE_EXPORT PositionInComposedTree mostForwardCaretPosition(const PositionInComp
CORE_EXPORT bool isVisuallyEquivalentCandidate(const Position&);
CORE_EXPORT bool isVisuallyEquivalentCandidate(const PositionInComposedTree&);
CORE_EXPORT Position canonicalPositionOf(const Position&);
CORE_EXPORT PositionInComposedTree canonicalPositionOf(const PositionInComposedTree&);
UChar32 characterAfter(const VisiblePosition&);
UChar32 characterBefore(const VisiblePosition&);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment