Commit 5a6383eb authored by eric@webkit.org's avatar eric@webkit.org

Reviewed by Justin Garcia.

        Minor refactoring and cleanup to Selection code
        https://bugs.webkit.org/show_bug.cgi?id=23774

        No functional changes, thus no tests.

        * editing/Editor.cpp:
        (WebCore::Editor::applyStyle):
        (WebCore::Editor::applyParagraphStyle):
        * editing/Selection.cpp:
        (WebCore::Selection::Selection):
        (WebCore::Selection::setBaseAndExtentToDeepEquivalents):
        (WebCore::Selection::setStartAndEndFromBaseAndExtentRespectingGranularity):
        (WebCore::Selection::updateSelectionType):
        (WebCore::Selection::validate):
        (WebCore::Selection::setWithoutValidation):
        (WebCore::Selection::adjustSelectionToAvoidCrossingEditingBoundaries):
        * editing/Selection.h:
        (WebCore::Selection::):
        (WebCore::Selection::selectionType):
        (WebCore::Selection::extent):
        (WebCore::Selection::isNone):
        (WebCore::Selection::isCaret):
        (WebCore::Selection::isRange):
        (WebCore::Selection::isCaretOrRange):
        * editing/SelectionController.h:
        (WebCore::SelectionController::selectionType):
        * editing/TypingCommand.cpp:
        (WebCore::TypingCommand::deleteKeyPressed):
        (WebCore::TypingCommand::forwardDeleteKeyPressed):
        * page/Frame.cpp:
        (WebCore::Frame::revealSelection):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@40738 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 35f68f75
2009-02-06 Eric Seidel <eric@webkit.org>
Reviewed by Justin Garcia.
Minor refactoring and cleanup to Selection code
https://bugs.webkit.org/show_bug.cgi?id=23774
No functional changes, thus no tests.
* editing/Editor.cpp:
(WebCore::Editor::applyStyle):
(WebCore::Editor::applyParagraphStyle):
* editing/Selection.cpp:
(WebCore::Selection::Selection):
(WebCore::Selection::setBaseAndExtentToDeepEquivalents):
(WebCore::Selection::setStartAndEndFromBaseAndExtentRespectingGranularity):
(WebCore::Selection::updateSelectionType):
(WebCore::Selection::validate):
(WebCore::Selection::setWithoutValidation):
(WebCore::Selection::adjustSelectionToAvoidCrossingEditingBoundaries):
* editing/Selection.h:
(WebCore::Selection::):
(WebCore::Selection::selectionType):
(WebCore::Selection::extent):
(WebCore::Selection::isNone):
(WebCore::Selection::isCaret):
(WebCore::Selection::isRange):
(WebCore::Selection::isCaretOrRange):
* editing/SelectionController.h:
(WebCore::SelectionController::selectionType):
* editing/TypingCommand.cpp:
(WebCore::TypingCommand::deleteKeyPressed):
(WebCore::TypingCommand::forwardDeleteKeyPressed):
* page/Frame.cpp:
(WebCore::Frame::revealSelection):
2009-02-06 Dimitri Glazkov <dglazkov@chromium.org>
Reviewed by Eric Seidel.
......@@ -710,14 +710,14 @@ bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPoli
void Editor::applyStyle(CSSStyleDeclaration* style, EditAction editingAction)
{
switch (m_frame->selection()->state()) {
case Selection::NONE:
switch (m_frame->selection()->selectionType()) {
case Selection::NoSelection:
// do nothing
break;
case Selection::CARET:
case Selection::CaretSelection:
m_frame->computeAndSetTypingStyle(style, editingAction);
break;
case Selection::RANGE:
case Selection::RangeSelection:
if (m_frame->document() && style)
applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction));
break;
......@@ -731,12 +731,12 @@ bool Editor::shouldApplyStyle(CSSStyleDeclaration* style, Range* range)
void Editor::applyParagraphStyle(CSSStyleDeclaration* style, EditAction editingAction)
{
switch (m_frame->selection()->state()) {
case Selection::NONE:
switch (m_frame->selection()->selectionType()) {
case Selection::NoSelection:
// do nothing
break;
case Selection::CARET:
case Selection::RANGE:
case Selection::CaretSelection:
case Selection::RangeSelection:
if (m_frame->document() && style)
applyCommand(ApplyStyleCommand::create(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
break;
......
......@@ -43,7 +43,7 @@ namespace WebCore {
Selection::Selection()
: m_affinity(DOWNSTREAM)
, m_granularity(CharacterGranularity)
, m_state(NONE)
, m_selectionType(NoSelection)
, m_baseIsFirst(true)
{
}
......@@ -238,7 +238,7 @@ void Selection::appendTrailingWhitespace()
}
}
void Selection::validate()
void Selection::setBaseAndExtentToDeepEquivalents()
{
// Move the selection to rendered positions, if possible.
bool baseAndExtentEqual = m_base == m_extent;
......@@ -259,10 +259,12 @@ void Selection::validate()
} else if (m_extent.isNull()) {
m_extent = m_base;
m_baseIsFirst = true;
} else {
} else
m_baseIsFirst = comparePositions(m_base, m_extent) <= 0;
}
}
void Selection::setStartAndEndFromBaseAndExtentRespectingGranularity()
{
if (m_baseIsFirst) {
m_start = m_base;
m_end = m_extent;
......@@ -271,7 +273,6 @@ void Selection::validate()
m_end = m_base;
}
// Expand the selection if requested.
switch (m_granularity) {
case CharacterGranularity:
// Don't do any expansion.
......@@ -385,26 +386,31 @@ void Selection::validate()
m_start = m_end;
if (m_end.isNull())
m_end = m_start;
adjustForEditableContent();
}
// adjust the state
void Selection::updateSelectionType()
{
if (m_start.isNull()) {
ASSERT(m_end.isNull());
m_state = NONE;
// enforce downstream affinity if not caret, as affinity only
// makes sense for caret
m_affinity = DOWNSTREAM;
m_selectionType = NoSelection;
} else if (m_start == m_end || m_start.upstream() == m_end.upstream()) {
m_state = CARET;
} else {
m_state = RANGE;
m_selectionType = CaretSelection;
} else
m_selectionType = RangeSelection;
// enforce downstream affinity if not caret, as affinity only
// makes sense for caret
// Affinity only makes sense for a caret
if (m_selectionType != CaretSelection)
m_affinity = DOWNSTREAM;
}
void Selection::validate()
{
setBaseAndExtentToDeepEquivalents();
setStartAndEndFromBaseAndExtentRespectingGranularity();
adjustSelectionToAvoidCrossingEditingBoundaries();
updateSelectionType();
if (selectionType() == RangeSelection) {
// "Constrain" the selection to be the smallest equivalent range of nodes.
// This is a somewhat arbitrary choice, but experience shows that it is
// useful to make to make the selection "canonical" (if only for
......@@ -441,10 +447,10 @@ void Selection::setWithoutValidation(const Position& base, const Position& exten
m_start = extent;
m_end = base;
}
m_state = RANGE;
m_selectionType = RangeSelection;
}
void Selection::adjustForEditableContent()
void Selection::adjustSelectionToAvoidCrossingEditingBoundaries()
{
if (m_base.isNull() || m_start.isNull() || m_end.isNull())
return;
......@@ -505,8 +511,10 @@ void Selection::adjustForEditableContent()
p = Position(shadowAncestor, maxDeepOffset(shadowAncestor));
}
VisiblePosition previous(p);
if (previous.isNull()) {
// The selection crosses an Editing boundary. This is a
// programmer error in the editing code. Happy debugging!
ASSERT_NOT_REACHED();
m_base = Position();
m_extent = Position();
......@@ -534,6 +542,8 @@ void Selection::adjustForEditableContent()
VisiblePosition next(p);
if (next.isNull()) {
// The selection crosses an Editing boundary. This is a
// programmer error in the editing code. Happy debugging!
ASSERT_NOT_REACHED();
m_base = Position();
m_extent = Position();
......
......@@ -37,8 +37,7 @@ const EAffinity SEL_DEFAULT_AFFINITY = DOWNSTREAM;
class Selection {
public:
enum EState { NONE, CARET, RANGE };
enum EDirection { FORWARD, BACKWARD, RIGHT, LEFT };
enum SelectionType { NoSelection, CaretSelection, RangeSelection };
Selection();
......@@ -52,7 +51,7 @@ public:
static Selection selectionFromContentsOfNode(Node*);
EState state() const { return m_state; }
SelectionType selectionType() const { return m_selectionType; }
void setAffinity(EAffinity affinity) { m_affinity = affinity; }
EAffinity affinity() const { return m_affinity; }
......@@ -63,17 +62,17 @@ public:
void setExtent(const VisiblePosition&);
Position base() const { return m_base; }
Position extent() const { return m_extent; }
Position extent() const { return m_extent; }
Position start() const { return m_start; }
Position end() const { return m_end; }
VisiblePosition visibleStart() const { return VisiblePosition(m_start, isRange() ? DOWNSTREAM : affinity()); }
VisiblePosition visibleEnd() const { return VisiblePosition(m_end, isRange() ? UPSTREAM : affinity()); }
bool isNone() const { return state() == NONE; }
bool isCaret() const { return state() == CARET; }
bool isRange() const { return state() == RANGE; }
bool isCaretOrRange() const { return state() != NONE; }
bool isNone() const { return selectionType() == NoSelection; }
bool isCaret() const { return selectionType() == CaretSelection; }
bool isRange() const { return selectionType() == RangeSelection; }
bool isCaretOrRange() const { return selectionType() != NoSelection; }
bool isBaseFirst() const { return m_baseIsFirst; }
......@@ -100,18 +99,23 @@ public:
private:
void validate();
void adjustForEditableContent();
Position m_base; // base position for the selection
Position m_extent; // extent position for the selection
Position m_start; // start position for the selection
Position m_end; // end position for the selection
// Support methods for validate()
void setBaseAndExtentToDeepEquivalents();
void setStartAndEndFromBaseAndExtentRespectingGranularity();
void adjustSelectionToAvoidCrossingEditingBoundaries();
void updateSelectionType();
EAffinity m_affinity; // the upstream/downstream affinity of the caret
TextGranularity m_granularity; // granularity of start/end selection
Position m_base; // Where the first click happened
Position m_extent; // Where the end click happened
Position m_start; // Leftmost position when expanded to respect granularity
Position m_end; // Rightmost position when expanded to respect granularity
EAffinity m_affinity; // the upstream/downstream affinity of the caret
TextGranularity m_granularity; // granularity of start/end selection
// these are cached, can be recalculated by validate()
EState m_state; // the state of the selection
SelectionType m_selectionType; // None, Caret, Range
bool m_baseIsFirst; // true if base is before the extent
};
......
......@@ -67,7 +67,7 @@ public:
bool contains(const IntPoint&);
Selection::EState state() const { return m_sel.state(); }
Selection::SelectionType selectionType() const { return m_sel.selectionType(); }
EAffinity affinity() const { return m_sel.affinity(); }
......
......@@ -373,12 +373,12 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
Selection selectionToDelete;
Selection selectionAfterUndo;
switch (endingSelection().state()) {
case Selection::RANGE:
switch (endingSelection().selectionType()) {
case Selection::RangeSelection:
selectionToDelete = endingSelection();
selectionAfterUndo = selectionToDelete;
break;
case Selection::CARET: {
case Selection::CaretSelection: {
if (breakOutOfEmptyMailBlockquotedParagraph()) {
typingAddedToOpenCommand();
return;
......@@ -431,7 +431,7 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool killRing)
selectionAfterUndo.setWithoutValidation(startingSelection().end(), selectionToDelete.extent());
break;
}
case Selection::NONE:
case Selection::NoSelection:
ASSERT_NOT_REACHED();
break;
}
......@@ -455,12 +455,12 @@ void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool ki
Selection selectionToDelete;
Selection selectionAfterUndo;
switch (endingSelection().state()) {
case Selection::RANGE:
switch (endingSelection().selectionType()) {
case Selection::RangeSelection:
selectionToDelete = endingSelection();
selectionAfterUndo = selectionToDelete;
break;
case Selection::CARET: {
case Selection::CaretSelection: {
m_smartDelete = false;
// Handle delete at beginning-of-block case.
......@@ -509,7 +509,7 @@ void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool ki
}
break;
}
case Selection::NONE:
case Selection::NoSelection:
ASSERT_NOT_REACHED();
break;
}
......
......@@ -1250,32 +1250,28 @@ HTMLFormElement *Frame::currentForm() const
return start ? scanForForm(start) : 0;
}
// FIXME: should this go in SelectionController?
void Frame::revealSelection(const RenderLayer::ScrollAlignment& alignment) const
{
IntRect rect;
switch (selection()->state()) {
case Selection::NONE:
switch (selection()->selectionType()) {
case Selection::NoSelection:
return;
case Selection::CARET:
case Selection::CaretSelection:
rect = selection()->absoluteCaretBounds();
break;
case Selection::RANGE:
case Selection::RangeSelection:
rect = enclosingIntRect(selectionBounds(false));
break;
}
Position start = selection()->start();
ASSERT(start.node());
if (start.node() && start.node()->renderer()) {
// FIXME: This code only handles scrolling the startContainer's layer, but
// the selection rect could intersect more than just that.
// See <rdar://problem/4799899>.
if (RenderLayer *layer = start.node()->renderer()->enclosingLayer())
if (RenderLayer* layer = start.node()->renderer()->enclosingLayer())
layer->scrollRectToVisible(rect, false, alignment, alignment);
}
}
......
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