summaryrefslogtreecommitdiffstats
path: root/WebCore/editing
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-04-27 16:31:00 +0100
committerSteve Block <steveblock@google.com>2010-05-11 14:42:12 +0100
commitdcc8cf2e65d1aa555cce12431a16547e66b469ee (patch)
tree92a8d65cd5383bca9749f5327fb5e440563926e6 /WebCore/editing
parentccac38a6b48843126402088a309597e682f40fe6 (diff)
downloadexternal_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebCore/editing')
-rw-r--r--WebCore/editing/CompositeEditCommand.cpp9
-rw-r--r--WebCore/editing/DeleteSelectionCommand.cpp18
-rw-r--r--WebCore/editing/DeleteSelectionCommand.h1
-rw-r--r--WebCore/editing/Editor.cpp2
-rw-r--r--WebCore/editing/EditorCommand.cpp2
-rw-r--r--WebCore/editing/InsertListCommand.cpp9
-rw-r--r--WebCore/editing/MoveSelectionCommand.cpp8
-rw-r--r--WebCore/editing/MoveSelectionCommand.h9
-rw-r--r--WebCore/editing/ReplaceSelectionCommand.cpp49
-rw-r--r--WebCore/editing/SelectionController.cpp186
-rw-r--r--WebCore/editing/SelectionController.h22
-rw-r--r--WebCore/editing/TextAffinity.h2
-rw-r--r--WebCore/editing/TextIterator.cpp49
-rw-r--r--WebCore/editing/TextIterator.h14
-rw-r--r--WebCore/editing/VisiblePosition.cpp19
-rw-r--r--WebCore/editing/VisibleSelection.cpp20
-rw-r--r--WebCore/editing/VisibleSelection.h10
-rw-r--r--WebCore/editing/htmlediting.cpp10
-rw-r--r--WebCore/editing/htmlediting.h2
-rw-r--r--WebCore/editing/markup.cpp8
-rw-r--r--WebCore/editing/visible_units.cpp42
21 files changed, 339 insertions, 152 deletions
diff --git a/WebCore/editing/CompositeEditCommand.cpp b/WebCore/editing/CompositeEditCommand.cpp
index e9b6971..9dc918d 100644
--- a/WebCore/editing/CompositeEditCommand.cpp
+++ b/WebCore/editing/CompositeEditCommand.cpp
@@ -930,8 +930,11 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
// FIXME: This is an inefficient way to preserve style on nodes in the paragraph to move. It
// shouldn't matter though, since moved paragraphs will usually be quite small.
- RefPtr<DocumentFragment> fragment = startOfParagraphToMove != endOfParagraphToMove ? createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotAnnotateForInterchange, true), "") : 0;
-
+ RefPtr<DocumentFragment> fragment;
+ // This used to use a ternary for initialization, but that confused some versions of GCC, see bug 37912
+ if (startOfParagraphToMove != endOfParagraphToMove)
+ fragment = createFragmentFromMarkup(document(), createMarkup(range.get(), 0, DoNotAnnotateForInterchange, true), "");
+
// A non-empty paragraph's style is moved when we copy and move it. We don't move
// anything if we're given an empty paragraph, but an empty paragraph can have style
// too, <div><b><br></b></div> for example. Save it so that we can preserve it later.
@@ -950,6 +953,7 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
ASSERT(destination.deepEquivalent().node()->inDocument());
cleanupAfterDeletion();
+ ASSERT(destination.deepEquivalent().node()->inDocument());
// Add a br if pruning an empty block level element caused a collapse. For example:
// foo^
@@ -971,6 +975,7 @@ void CompositeEditCommand::moveParagraphs(const VisiblePosition& startOfParagrap
destinationIndex = TextIterator::rangeLength(startToDestinationRange.get(), true);
setEndingSelection(destination);
+ ASSERT(endingSelection().isCaretOrRange());
applyCommandToComposite(ReplaceSelectionCommand::create(document(), fragment, true, false, !preserveStyle, false, true));
// If the selection is in an empty paragraph, restore styles from the old empty paragraph to the new empty paragraph.
diff --git a/WebCore/editing/DeleteSelectionCommand.cpp b/WebCore/editing/DeleteSelectionCommand.cpp
index d3d9cc9..5e81d50 100644
--- a/WebCore/editing/DeleteSelectionCommand.cpp
+++ b/WebCore/editing/DeleteSelectionCommand.cpp
@@ -161,6 +161,20 @@ void DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end)
}
}
+void DeleteSelectionCommand::setStartingSelectionOnSmartDelete(const Position& start, const Position& end)
+{
+ VisiblePosition newBase;
+ VisiblePosition newExtent;
+ if (startingSelection().isBaseFirst()) {
+ newBase = start;
+ newExtent = end;
+ } else {
+ newBase = end;
+ newExtent = start;
+ }
+ setStartingSelection(VisibleSelection(newBase, newExtent));
+}
+
void DeleteSelectionCommand::initializePositionData()
{
Position start, end;
@@ -230,6 +244,8 @@ void DeleteSelectionCommand::initializePositionData()
m_upstreamStart = pos.upstream();
m_downstreamStart = pos.downstream();
m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(visiblePos.affinity());
+
+ setStartingSelectionOnSmartDelete(m_upstreamStart, m_upstreamEnd);
}
// trailing whitespace is only considered for smart delete if there is no leading
@@ -241,6 +257,8 @@ void DeleteSelectionCommand::initializePositionData()
m_upstreamEnd = pos.upstream();
m_downstreamEnd = pos.downstream();
m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT_AFFINITY);
+
+ setStartingSelectionOnSmartDelete(m_downstreamStart, m_downstreamEnd);
}
}
diff --git a/WebCore/editing/DeleteSelectionCommand.h b/WebCore/editing/DeleteSelectionCommand.h
index c8872ef..20f52f4 100644
--- a/WebCore/editing/DeleteSelectionCommand.h
+++ b/WebCore/editing/DeleteSelectionCommand.h
@@ -51,6 +51,7 @@ private:
virtual bool preservesTypingStyle() const;
void initializeStartEnd(Position&, Position&);
+ void setStartingSelectionOnSmartDelete(const Position&, const Position&);
void initializePositionData();
void saveTypingStyleState();
void insertPlaceholderForAncestorBlockContent();
diff --git a/WebCore/editing/Editor.cpp b/WebCore/editing/Editor.cpp
index 1061dd2..e171ac1 100644
--- a/WebCore/editing/Editor.cpp
+++ b/WebCore/editing/Editor.cpp
@@ -2703,7 +2703,7 @@ void Editor::addToKillRing(Range* range, bool prepend)
if (m_shouldStartNewKillRingSequence)
startNewKillRingSequence();
- String text = m_frame->displayStringModifiedByEncoding(plainText(range));
+ String text = plainText(range);
if (prepend)
prependToKillRing(text);
else
diff --git a/WebCore/editing/EditorCommand.cpp b/WebCore/editing/EditorCommand.cpp
index 437d584..34fa46d 100644
--- a/WebCore/editing/EditorCommand.cpp
+++ b/WebCore/editing/EditorCommand.cpp
@@ -257,7 +257,7 @@ static int verticalScrollDistance(Frame* frame)
RenderStyle* style = renderer->style();
if (!style)
return 0;
- if (!(style->overflowY() == OSCROLL || style->overflowY() == OAUTO || renderer->isTextArea()))
+ if (!(style->overflowY() == OSCROLL || style->overflowY() == OAUTO || focusedNode->isContentEditable()))
return 0;
int height = toRenderBox(renderer)->clientHeight();
return max(max<int>(height * Scrollbar::minFractionToStepWhenPaging(), height - Scrollbar::maxOverlapBetweenPages()), 1);
diff --git a/WebCore/editing/InsertListCommand.cpp b/WebCore/editing/InsertListCommand.cpp
index beb5d08..cd6838b 100644
--- a/WebCore/editing/InsertListCommand.cpp
+++ b/WebCore/editing/InsertListCommand.cpp
@@ -259,9 +259,16 @@ void InsertListCommand::doApply()
// Update the start of content, so we don't try to move the list into itself. bug 19066
if (insertionPos == start.deepEquivalent())
start = startOfParagraph(originalStart);
+ previousList = outermostEnclosingList(previousPosition.deepEquivalent().node(), enclosingList(listElement.get()));
+ nextList = outermostEnclosingList(nextPosition.deepEquivalent().node(), enclosingList(listElement.get()));
}
moveParagraph(start, end, VisiblePosition(Position(placeholder.get(), 0)), true);
- if (nextList && previousList)
+ if (m_listElement) {
+ if (canMergeLists(previousList, m_listElement.get()))
+ mergeIdenticalElements(previousList, m_listElement.get());
+ if (canMergeLists(m_listElement.get(), nextList))
+ mergeIdenticalElements(m_listElement.get(), nextList);
+ } else if (canMergeLists(nextList, previousList))
mergeIdenticalElements(previousList, nextList);
}
}
diff --git a/WebCore/editing/MoveSelectionCommand.cpp b/WebCore/editing/MoveSelectionCommand.cpp
index 0a2d3f4..62f638f 100644
--- a/WebCore/editing/MoveSelectionCommand.cpp
+++ b/WebCore/editing/MoveSelectionCommand.cpp
@@ -31,8 +31,8 @@
namespace WebCore {
-MoveSelectionCommand::MoveSelectionCommand(PassRefPtr<DocumentFragment> fragment, const Position& position, bool smartMove)
- : CompositeEditCommand(position.node()->document()), m_fragment(fragment), m_position(position), m_smartMove(smartMove)
+MoveSelectionCommand::MoveSelectionCommand(PassRefPtr<DocumentFragment> fragment, const Position& position, bool smartInsert, bool smartDelete)
+ : CompositeEditCommand(position.node()->document()), m_fragment(fragment), m_position(position), m_smartInsert(smartInsert), m_smartDelete(smartDelete)
{
ASSERT(m_fragment);
}
@@ -60,7 +60,7 @@ void MoveSelectionCommand::doApply()
pos = Position(positionNode, positionOffset);
}
- deleteSelection(m_smartMove);
+ deleteSelection(m_smartDelete);
// If the node for the destination has been removed as a result of the deletion,
// set the destination to the ending point after the deletion.
@@ -74,7 +74,7 @@ void MoveSelectionCommand::doApply()
// Document was modified out from under us.
return;
}
- applyCommandToComposite(ReplaceSelectionCommand::create(positionNode->document(), m_fragment, true, m_smartMove));
+ applyCommandToComposite(ReplaceSelectionCommand::create(positionNode->document(), m_fragment, true, m_smartInsert));
}
EditAction MoveSelectionCommand::editingAction() const
diff --git a/WebCore/editing/MoveSelectionCommand.h b/WebCore/editing/MoveSelectionCommand.h
index 253c02c..6780caa 100644
--- a/WebCore/editing/MoveSelectionCommand.h
+++ b/WebCore/editing/MoveSelectionCommand.h
@@ -34,20 +34,21 @@ class DocumentFragment;
class MoveSelectionCommand : public CompositeEditCommand {
public:
- static PassRefPtr<MoveSelectionCommand> create(PassRefPtr<DocumentFragment> fragment, const Position& position, bool smartMove = false)
+ static PassRefPtr<MoveSelectionCommand> create(PassRefPtr<DocumentFragment> fragment, const Position& position, bool smartInsert = false, bool smartDelete = false)
{
- return adoptRef(new MoveSelectionCommand(fragment, position, smartMove));
+ return adoptRef(new MoveSelectionCommand(fragment, position, smartInsert, smartDelete));
}
private:
- MoveSelectionCommand(PassRefPtr<DocumentFragment>, const Position&, bool smartMove);
+ MoveSelectionCommand(PassRefPtr<DocumentFragment>, const Position&, bool smartInsert, bool smartDelete);
virtual void doApply();
virtual EditAction editingAction() const;
RefPtr<DocumentFragment> m_fragment;
Position m_position;
- bool m_smartMove;
+ bool m_smartInsert;
+ bool m_smartDelete;
};
} // namespace WebCore
diff --git a/WebCore/editing/ReplaceSelectionCommand.cpp b/WebCore/editing/ReplaceSelectionCommand.cpp
index bac090c..e4acf85 100644
--- a/WebCore/editing/ReplaceSelectionCommand.cpp
+++ b/WebCore/editing/ReplaceSelectionCommand.cpp
@@ -104,6 +104,22 @@ static bool isInterchangeConvertedSpaceSpan(const Node *node)
static_cast<const HTMLElement *>(node)->getAttribute(classAttr) == convertedSpaceSpanClassString;
}
+static Position positionAvoidingPrecedingNodes(Position pos)
+{
+ // If we're already on a break, it's probably a placeholder and we shouldn't change our position.
+ if (pos.node()->hasTagName(brTag))
+ return pos;
+
+ // We also stop when changing block flow elements because even though the visual position is the
+ // same. E.g.,
+ // <div>foo^</div>^
+ // The two positions above are the same visual position, but we want to stay in the same block.
+ Node* stopNode = pos.node()->enclosingBlockFlowElement();
+ while (stopNode != pos.node() && VisiblePosition(pos) == VisiblePosition(pos.next()))
+ pos = pos.next();
+ return pos;
+}
+
ReplacementFragment::ReplacementFragment(Document* document, DocumentFragment* fragment, bool matchStyle, const VisibleSelection& selection)
: m_document(document),
m_fragment(fragment),
@@ -885,7 +901,12 @@ void ReplaceSelectionCommand::doApply()
frame->clearTypingStyle();
bool handledStyleSpans = handleStyleSpansBeforeInsertion(fragment, insertionPos);
-
+
+ // We don't want the destination to end up inside nodes that weren't selected. To avoid that, we move the
+ // position forward without changing the visible position so we're still at the same visible location, but
+ // outside of preceding tags.
+ insertionPos = positionAvoidingPrecedingNodes(insertionPos);
+
// FIXME: When pasting rich content we're often prevented from heading down the fast path by style spans. Try
// again here if they've been removed.
@@ -1170,26 +1191,34 @@ Node* ReplaceSelectionCommand::insertAsListItems(PassRefPtr<Node> listElement, N
bool isStart = isStartOfParagraph(insertPos);
bool isEnd = isEndOfParagraph(insertPos);
-
+ bool isMiddle = !isStart && !isEnd;
Node* lastNode = insertionBlock;
+
+ // If we're in the middle of a list item, we should split it into two separate
+ // list items and insert these nodes between them.
+ if (isMiddle) {
+ int textNodeOffset = insertPos.offsetInContainerNode();
+ if (insertPos.node()->isTextNode() && textNodeOffset > 0)
+ splitTextNode(static_cast<Text*>(insertPos.node()), textNodeOffset);
+ splitTreeToNode(insertPos.node(), lastNode, true);
+ }
+
while (RefPtr<Node> listItem = listElement->firstChild()) {
ExceptionCode ec = 0;
listElement->removeChild(listItem.get(), ec);
ASSERT(!ec);
- if (isStart)
+ if (isStart || isMiddle)
insertNodeBefore(listItem, lastNode);
else if (isEnd) {
insertNodeAfter(listItem, lastNode);
lastNode = listItem.get();
- } else {
- // FIXME: If we're in the middle of a list item, we should split it into two separate
- // list items and insert these nodes between them. For now, just append the nodes.
- insertNodeAfter(listItem, lastNode);
- lastNode = listItem.get();
- }
+ } else
+ ASSERT_NOT_REACHED();
}
- if (isStart)
+ if (isStart || isMiddle)
lastNode = lastNode->previousSibling();
+ if (isMiddle)
+ insertNodeAfter(createListItemElement(document()), lastNode);
updateNodesInserted(lastNode);
return lastNode;
}
diff --git a/WebCore/editing/SelectionController.cpp b/WebCore/editing/SelectionController.cpp
index 25982d4..002226d 100644
--- a/WebCore/editing/SelectionController.cpp
+++ b/WebCore/editing/SelectionController.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "SelectionController.h"
-#include "CString.h"
#include "DeleteSelectionCommand.h"
#include "Document.h"
#include "Editor.h"
@@ -47,12 +46,14 @@
#include "Range.h"
#include "RenderTheme.h"
#include "RenderView.h"
+#include "SecureTextInput.h"
#include "Settings.h"
#include "TextIterator.h"
#include "TypingCommand.h"
#include "htmlediting.h"
#include "visible_units.h"
#include <stdio.h>
+#include <wtf/text/CString.h>
#define EDIT_DEBUG 0
@@ -65,16 +66,17 @@ const int NoXPosForVerticalArrowNavigation = INT_MIN;
SelectionController::SelectionController(Frame* frame, bool isDragCaretController)
: m_frame(frame)
, m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation)
+ , m_granularity(CharacterGranularity)
, m_caretBlinkTimer(this, &SelectionController::caretBlinkTimerFired)
, m_needsLayout(true)
, m_absCaretBoundsDirty(true)
- , m_lastChangeWasHorizontalExtension(false)
, m_isDragCaretController(isDragCaretController)
, m_isCaretBlinkingSuspended(false)
, m_focused(frame && frame->page() && frame->page()->focusController()->focusedFrame() == frame)
, m_caretVisible(isDragCaretController)
, m_caretPaint(true)
{
+ setIsDirectional(false);
}
void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered)
@@ -103,9 +105,11 @@ void SelectionController::moveTo(const Position &base, const Position &extent, E
setSelection(VisibleSelection(base, extent, affinity), true, true, userTriggered);
}
-void SelectionController::setSelection(const VisibleSelection& s, bool closeTyping, bool clearTypingStyle, bool userTriggered)
+void SelectionController::setSelection(const VisibleSelection& s, bool closeTyping, bool clearTypingStyle, bool userTriggered, TextGranularity granularity)
{
- m_lastChangeWasHorizontalExtension = false;
+ m_granularity = granularity;
+
+ setIsDirectional(false);
if (m_isDragCaretController) {
invalidateCaretRect();
@@ -228,18 +232,35 @@ void SelectionController::nodeWillBeRemoved(Node *node)
if (clearDOMTreeSelection)
setSelection(VisibleSelection(), false, false);
}
+
+void SelectionController::setIsDirectional(bool isDirectional)
+{
+ Settings* settings = m_frame ? m_frame->settings() : 0;
+ m_isDirectional = !settings || settings->editingBehavior() != EditingMacBehavior || isDirectional;
+}
void SelectionController::willBeModified(EAlteration alter, EDirection direction)
{
if (alter != EXTEND)
return;
- if (m_lastChangeWasHorizontalExtension)
- return;
Position start = m_selection.start();
Position end = m_selection.end();
- // FIXME: This is probably not correct for right and left when the direction is RTL.
- switch (direction) {
+
+ if (m_isDirectional) {
+ // Make base and extent match start and end so we extend the user-visible selection.
+ // This only matters for cases where base and extend point to different positions than
+ // start and end (e.g. after a double-click to select a word).
+ if (m_selection.isBaseFirst()) {
+ m_selection.setBase(start);
+ m_selection.setExtent(end);
+ } else {
+ m_selection.setBase(end);
+ m_selection.setExtent(start);
+ }
+ } else {
+ // FIXME: This is probably not correct for right and left when the direction is RTL.
+ switch (direction) {
case RIGHT:
case FORWARD:
m_selection.setBase(start);
@@ -250,6 +271,7 @@ void SelectionController::willBeModified(EAlteration alter, EDirection direction
m_selection.setBase(end);
m_selection.setExtent(start);
break;
+ }
}
}
@@ -350,7 +372,9 @@ VisiblePosition SelectionController::modifyExtendingForward(TextGranularity gran
pos = endOfSentence(endForPlatform());
break;
case LineBoundary:
- pos = logicalEndOfLine(endForPlatform());
+ pos = endForPlatform();
+ pos.setAffinity(UPSTREAM);
+ pos = logicalEndOfLine(pos);
break;
case ParagraphBoundary:
pos = endOfParagraph(endForPlatform());
@@ -588,53 +612,61 @@ VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granul
bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranularity granularity, bool userTriggered)
{
+ Settings* settings = m_frame ? m_frame->settings() : 0;
+ return modify(alter, dir, granularity, userTriggered, settings);
+}
+
+static bool isBoundary(TextGranularity granularity)
+{
+ return granularity == LineBoundary || granularity == ParagraphBoundary || granularity == DocumentBoundary;
+}
+
+bool SelectionController::modify(EAlteration alter, EDirection direction, TextGranularity granularity, bool userTriggered, Settings* settings)
+{
if (userTriggered) {
SelectionController trialSelectionController;
trialSelectionController.setSelection(m_selection);
- trialSelectionController.setLastChangeWasHorizontalExtension(m_lastChangeWasHorizontalExtension);
- trialSelectionController.modify(alter, dir, granularity, false);
+ trialSelectionController.setIsDirectional(m_isDirectional);
+ trialSelectionController.modify(alter, direction, granularity, false, settings);
bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
if (!change)
return false;
}
- if (m_frame)
- m_frame->setSelectionGranularity(granularity);
-
- willBeModified(alter, dir);
+ willBeModified(alter, direction);
- VisiblePosition pos;
- switch (dir) {
+ VisiblePosition position;
+ switch (direction) {
case RIGHT:
if (alter == MOVE)
- pos = modifyMovingRight(granularity);
+ position = modifyMovingRight(granularity);
else
- pos = modifyExtendingRight(granularity);
+ position = modifyExtendingRight(granularity);
break;
case FORWARD:
if (alter == EXTEND)
- pos = modifyExtendingForward(granularity);
+ position = modifyExtendingForward(granularity);
else
- pos = modifyMovingForward(granularity);
+ position = modifyMovingForward(granularity);
break;
case LEFT:
if (alter == MOVE)
- pos = modifyMovingLeft(granularity);
+ position = modifyMovingLeft(granularity);
else
- pos = modifyExtendingLeft(granularity);
+ position = modifyExtendingLeft(granularity);
break;
case BACKWARD:
if (alter == EXTEND)
- pos = modifyExtendingBackward(granularity);
+ position = modifyExtendingBackward(granularity);
else
- pos = modifyMovingBackward(granularity);
+ position = modifyMovingBackward(granularity);
break;
}
- if (pos.isNull())
+ if (position.isNull())
return false;
-
+
// Some of the above operations set an xPosForVerticalArrowNavigation.
// Setting a selection will clear it, so save it to possibly restore later.
// Note: the START position type is arbitrary because it is unused, it would be
@@ -643,28 +675,31 @@ bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranular
switch (alter) {
case MOVE:
- moveTo(pos, userTriggered);
+ moveTo(position, userTriggered);
break;
case EXTEND:
- setExtent(pos, userTriggered);
- break;
+ if (!settings || settings->editingBehavior() != EditingMacBehavior || m_selection.isCaret() || !isBoundary(granularity))
+ setExtent(position, userTriggered);
+ else {
+ // Standard Mac behavior when extending to a boundary is grow the selection rather
+ // than leaving the base in place and moving the extent. Matches NSTextView.
+ if (direction == FORWARD || direction == RIGHT)
+ setEnd(position, userTriggered);
+ else
+ setStart(position, userTriggered);
+ }
}
if (granularity == LineGranularity || granularity == ParagraphGranularity)
m_xPosForVerticalArrowNavigation = x;
- if (userTriggered) {
- // User modified selection change also sets the granularity back to character.
- // NOTE: The one exception is that we need to keep word granularity to
- // preserve smart delete behavior when extending by word (e.g. double-click),
- // then shift-option-right arrow, then delete needs to smart delete, per TextEdit.
- if (!(alter == EXTEND && granularity == WordGranularity && m_frame->selectionGranularity() == WordGranularity))
- m_frame->setSelectionGranularity(CharacterGranularity);
- }
+ if (userTriggered)
+ m_granularity = CharacterGranularity;
+
setNeedsLayout();
- m_lastChangeWasHorizontalExtension = alter == EXTEND;
+ setIsDirectional(alter == EXTEND);
return true;
}
@@ -687,7 +722,7 @@ bool SelectionController::modify(EAlteration alter, int verticalDistance, bool u
if (userTriggered) {
SelectionController trialSelectionController;
trialSelectionController.setSelection(m_selection);
- trialSelectionController.setLastChangeWasHorizontalExtension(m_lastChangeWasHorizontalExtension);
+ trialSelectionController.setIsDirectional(m_isDirectional);
trialSelectionController.modify(alter, verticalDistance, false);
bool change = m_frame->shouldChangeSelection(trialSelectionController.selection());
@@ -755,20 +790,10 @@ bool SelectionController::modify(EAlteration alter, int verticalDistance, bool u
}
if (userTriggered)
- m_frame->setSelectionGranularity(CharacterGranularity);
-
- m_lastChangeWasHorizontalExtension = alter == EXTEND;
-
- return true;
-}
+ m_granularity = CharacterGranularity;
-bool SelectionController::expandUsingGranularity(TextGranularity granularity)
-{
- if (isNone())
- return false;
+ setIsDirectional(alter == EXTEND);
- m_selection.expandUsingGranularity(granularity);
- m_needsLayout = true;
return true;
}
@@ -814,9 +839,26 @@ int SelectionController::xPosForVerticalArrowNavigation(EPositionType type)
void SelectionController::clear()
{
+ m_granularity = CharacterGranularity;
setSelection(VisibleSelection());
}
+void SelectionController::setStart(const VisiblePosition &pos, bool userTriggered)
+{
+ if (m_selection.isBaseFirst())
+ setBase(pos, userTriggered);
+ else
+ setExtent(pos, userTriggered);
+}
+
+void SelectionController::setEnd(const VisiblePosition &pos, bool userTriggered)
+{
+ if (m_selection.isBaseFirst())
+ setExtent(pos, userTriggered);
+ else
+ setBase(pos, userTriggered);
+}
+
void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered)
{
setSelection(VisibleSelection(pos.deepEquivalent(), m_selection.extent(), pos.affinity()), true, true, userTriggered);
@@ -969,16 +1011,26 @@ bool SelectionController::recomputeCaretRect()
IntRect oldAbsoluteCaretRepaintBounds = m_absoluteCaretRepaintBounds;
// We believe that we need to inflate the local rect before transforming it to obtain the repaint bounds.
m_absoluteCaretRepaintBounds = caretRepaintRect();
-
+
+#if ENABLE(TEXT_CARET)
if (RenderView* view = toRenderView(m_frame->document()->renderer())) {
// FIXME: make caret repainting container-aware.
view->repaintRectangleInViewAndCompositedLayers(oldAbsoluteCaretRepaintBounds, false);
- view->repaintRectangleInViewAndCompositedLayers(m_absoluteCaretRepaintBounds, false);
+ if (shouldRepaintCaret(view))
+ view->repaintRectangleInViewAndCompositedLayers(m_absoluteCaretRepaintBounds, false);
}
-
+#endif
return true;
}
+bool SelectionController::shouldRepaintCaret(const RenderView* view) const
+{
+ ASSERT(view);
+ Frame* frame = view->frameView() ? view->frameView()->frame() : 0; // The frame where the selection started.
+ bool caretBrowsing = frame && frame->settings() && frame->settings()->caretBrowsingEnabled();
+ return (caretBrowsing || isContentEditable());
+}
+
void SelectionController::invalidateCaretRect()
{
if (!isCaret())
@@ -1004,7 +1056,8 @@ void SelectionController::invalidateCaretRect()
m_needsLayout = true;
if (!caretRectChanged) {
- if (RenderView* view = toRenderView(d->renderer()))
+ RenderView* view = toRenderView(d->renderer());
+ if (view && shouldRepaintCaret(view))
view->repaintRectangleInViewAndCompositedLayers(caretRepaintRect(), false);
}
}
@@ -1034,6 +1087,11 @@ void SelectionController::paintCaret(GraphicsContext* context, int tx, int ty, c
}
context->fillRect(caret, caretColor, colorSpace);
+#else
+ UNUSED_PARAM(context);
+ UNUSED_PARAM(tx);
+ UNUSED_PARAM(ty);
+ UNUSED_PARAM(clipRect);
#endif
}
@@ -1311,7 +1369,7 @@ void SelectionController::focusedOrActiveStateChanged()
// Secure keyboard entry is set by the active frame.
if (m_frame->document()->useSecureKeyboardEntryWhenActive())
- m_frame->setUseSecureKeyboardEntry(activeAndFocused);
+ setUseSecureKeyboardEntry(activeAndFocused);
}
void SelectionController::pageActivationChanged()
@@ -1319,6 +1377,20 @@ void SelectionController::pageActivationChanged()
focusedOrActiveStateChanged();
}
+void SelectionController::updateSecureKeyboardEntryIfActive()
+{
+ if (m_frame->document() && isFocusedAndActive())
+ setUseSecureKeyboardEntry(m_frame->document()->useSecureKeyboardEntryWhenActive());
+}
+
+void SelectionController::setUseSecureKeyboardEntry(bool enable)
+{
+ if (enable)
+ enableSecureTextInput();
+ else
+ disableSecureTextInput();
+}
+
void SelectionController::setFocused(bool flag)
{
if (m_focused == flag)
diff --git a/WebCore/editing/SelectionController.h b/WebCore/editing/SelectionController.h
index 6849cb6..9a407fc 100644
--- a/WebCore/editing/SelectionController.h
+++ b/WebCore/editing/SelectionController.h
@@ -37,6 +37,8 @@ namespace WebCore {
class Frame;
class GraphicsContext;
class RenderObject;
+class RenderView;
+class Settings;
class VisiblePosition;
class SelectionController : public Noncopyable {
@@ -58,7 +60,8 @@ public:
void moveTo(const Position&, const Position&, EAffinity, bool userTriggered = false);
const VisibleSelection& selection() const { return m_selection; }
- void setSelection(const VisibleSelection&, bool closeTyping = true, bool clearTypingStyle = true, bool userTriggered = false);
+ void setSelection(const VisibleSelection&, bool closeTyping = true, bool clearTypingStyle = true, bool userTriggered = false, TextGranularity = CharacterGranularity);
+ void setSelection(const VisibleSelection& selection, TextGranularity granularity) { setSelection(selection, true, true, false, granularity); }
bool setSelectedRange(Range*, EAffinity, bool closeTyping);
void selectAll();
void clear();
@@ -74,8 +77,11 @@ public:
bool modify(EAlteration, EDirection, TextGranularity, bool userTriggered = false);
bool modify(EAlteration, int verticalDistance, bool userTriggered = false);
- bool expandUsingGranularity(TextGranularity);
+ TextGranularity granularity() const { return m_granularity; }
+ void setStart(const VisiblePosition &, bool userTriggered = false);
+ void setEnd(const VisiblePosition &, bool userTriggered = false);
+
void setBase(const VisiblePosition&, bool userTriggered = false);
void setBase(const Position&, EAffinity, bool userTriggered = false);
void setExtent(const VisiblePosition&, bool userTriggered = false);
@@ -95,7 +101,7 @@ public:
IntRect absoluteCaretBounds();
void setNeedsLayout(bool flag = true);
- void setLastChangeWasHorizontalExtension(bool b) { m_lastChangeWasHorizontalExtension = b; }
+ void setIsDirectional(bool);
void willBeModified(EAlteration, EDirection);
bool isNone() const { return m_selection.isNone(); }
@@ -130,6 +136,8 @@ public:
// Painting.
void updateAppearance();
+ void updateSecureKeyboardEntryIfActive();
+
#ifndef NDEBUG
void formatForDebugger(char* buffer, unsigned length) const;
void showTreeForThis() const;
@@ -144,6 +152,8 @@ private:
VisiblePosition startForPlatform() const;
VisiblePosition endForPlatform() const;
+ bool modify(EAlteration, EDirection, TextGranularity, bool userTriggered, Settings*);
+
VisiblePosition modifyExtendingRight(TextGranularity);
VisiblePosition modifyExtendingForward(TextGranularity);
VisiblePosition modifyMovingRight(TextGranularity);
@@ -155,6 +165,7 @@ private:
void layout();
IntRect caretRepaintRect() const;
+ bool shouldRepaintCaret(const RenderView* view) const;
int xPosForVerticalArrowNavigation(EPositionType);
@@ -167,11 +178,14 @@ private:
void caretBlinkTimerFired(Timer<SelectionController>*);
+ void setUseSecureKeyboardEntry(bool);
+
Frame* m_frame;
int m_xPosForVerticalArrowNavigation;
VisibleSelection m_selection;
+ TextGranularity m_granularity;
Timer<SelectionController> m_caretBlinkTimer;
@@ -181,7 +195,7 @@ private:
bool m_needsLayout; // true if m_caretRect and m_absCaretBounds need to be calculated
bool m_absCaretBoundsDirty;
- bool m_lastChangeWasHorizontalExtension;
+ bool m_isDirectional;
bool m_isDragCaretController;
bool m_isCaretBlinkingSuspended;
bool m_focused;
diff --git a/WebCore/editing/TextAffinity.h b/WebCore/editing/TextAffinity.h
index a5565c7..5310ca9 100644
--- a/WebCore/editing/TextAffinity.h
+++ b/WebCore/editing/TextAffinity.h
@@ -26,8 +26,6 @@
#ifndef TextAffinity_h
#define TextAffinity_h
-#include <wtf/Platform.h>
-
#ifdef __OBJC__
#include <AppKit/NSTextView.h>
#endif
diff --git a/WebCore/editing/TextIterator.cpp b/WebCore/editing/TextIterator.cpp
index 923f537..e022e3b 100644
--- a/WebCore/editing/TextIterator.cpp
+++ b/WebCore/editing/TextIterator.cpp
@@ -256,10 +256,11 @@ TextIterator::TextIterator()
, m_lastCharacter(0)
, m_emitCharactersBetweenAllVisiblePositions(false)
, m_enterTextControls(false)
+ , m_emitsTextWithoutTranscoding(false)
{
}
-TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
+TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisiblePositions, bool enterTextControls)
: m_startContainer(0)
, m_startOffset(0)
, m_endContainer(0)
@@ -269,6 +270,27 @@ TextIterator::TextIterator(const Range* r, bool emitCharactersBetweenAllVisibleP
, m_textLength(0)
, m_emitCharactersBetweenAllVisiblePositions(emitCharactersBetweenAllVisiblePositions)
, m_enterTextControls(enterTextControls)
+ , m_emitsTextWithoutTranscoding(false)
+{
+ init(r);
+}
+
+TextIterator::TextIterator(const Range* r, TextIteratorBehavior behavior)
+ : m_startContainer(0)
+ , m_startOffset(0)
+ , m_endContainer(0)
+ , m_endOffset(0)
+ , m_positionNode(0)
+ , m_textCharacters(0)
+ , m_textLength(0)
+ , m_emitCharactersBetweenAllVisiblePositions(behavior & TextIteratorBehaviorEmitCharactersBetweenAllVisiblePositions)
+ , m_enterTextControls(behavior & TextIteratorBehaviorEnterTextControls)
+ , m_emitsTextWithoutTranscoding(behavior & TextIteratorBehaviorEmitsTextsWithoutTranscoding)
+{
+ init(r);
+}
+
+void TextIterator::init(const Range* r)
{
if (!r)
return;
@@ -889,7 +911,7 @@ void TextIterator::emitCharacter(UChar c, Node* textNode, Node* offsetBaseNode,
void TextIterator::emitText(Node* textNode, int textStartOffset, int textEndOffset)
{
RenderText* renderer = toRenderText(m_node->renderer());
- String str = renderer->text();
+ String str = m_emitsTextWithoutTranscoding ? renderer->textWithoutTranscoding() : renderer->text();
ASSERT(str.characters());
m_positionNode = textNode;
@@ -2037,16 +2059,25 @@ PassRefPtr<Range> TextIterator::rangeFromLocationAndLength(Element* scope, int r
// Fix textRunRange->endPosition(), but only if foundStart || foundEnd, because it is only
// in those cases that textRunRange is used.
- if (foundStart || foundEnd) {
+ if (foundEnd) {
// FIXME: This is a workaround for the fact that the end of a run is often at the wrong
// position for emitted '\n's.
if (len == 1 && it.characters()[0] == '\n') {
- Position runStart = textRunRange->startPosition();
- Position runEnd = VisiblePosition(runStart).next().deepEquivalent();
- if (runEnd.isNotNull()) {
+ scope->document()->updateLayoutIgnorePendingStylesheets();
+ it.advance();
+ if (!it.atEnd()) {
+ RefPtr<Range> range = it.range();
ExceptionCode ec = 0;
- textRunRange->setEnd(runEnd.node(), runEnd.deprecatedEditingOffset(), ec);
+ textRunRange->setEnd(range->startContainer(), range->startOffset(), ec);
ASSERT(!ec);
+ } else {
+ Position runStart = textRunRange->startPosition();
+ Position runEnd = VisiblePosition(runStart).next().deepEquivalent();
+ if (runEnd.isNotNull()) {
+ ExceptionCode ec = 0;
+ textRunRange->setEnd(runEnd.node(), runEnd.deprecatedEditingOffset(), ec);
+ ASSERT(!ec);
+ }
}
}
}
@@ -2095,7 +2126,7 @@ PassRefPtr<Range> TextIterator::rangeFromLocationAndLength(Element* scope, int r
// --------
-UChar* plainTextToMallocAllocatedBuffer(const Range* r, unsigned& bufferLength, bool isDisplayString)
+UChar* plainTextToMallocAllocatedBuffer(const Range* r, unsigned& bufferLength, bool isDisplayString)
{
UChar* result = 0;
@@ -2107,7 +2138,7 @@ UChar* plainTextToMallocAllocatedBuffer(const Range* r, unsigned& bufferLength,
Vector<TextSegment>* textSegments = 0;
Vector<UChar> textBuffer;
textBuffer.reserveInitialCapacity(cMaxSegmentSize);
- for (TextIterator it(r); !it.atEnd(); it.advance()) {
+ for (TextIterator it(r, isDisplayString ? TextIteratorBehaviorDefault : TextIteratorBehaviorEmitsTextsWithoutTranscoding); !it.atEnd(); it.advance()) {
if (textBuffer.size() && textBuffer.size() + it.length() > cMaxSegmentSize) {
UChar* newSegmentBuffer = static_cast<UChar*>(malloc(textBuffer.size() * sizeof(UChar)));
if (!newSegmentBuffer)
diff --git a/WebCore/editing/TextIterator.h b/WebCore/editing/TextIterator.h
index 44af3e5..abd8161 100644
--- a/WebCore/editing/TextIterator.h
+++ b/WebCore/editing/TextIterator.h
@@ -68,11 +68,19 @@ private:
// at points where replaced elements break up the text flow. The text comes back in
// chunks so as to optimize for performance of the iteration.
+enum TextIteratorBehavior {
+ TextIteratorBehaviorDefault = 0,
+ TextIteratorBehaviorEmitCharactersBetweenAllVisiblePositions = 1 << 0,
+ TextIteratorBehaviorEnterTextControls = 1 << 1,
+ TextIteratorBehaviorEmitsTextsWithoutTranscoding = 1 << 2,
+};
+
class TextIterator {
public:
TextIterator();
explicit TextIterator(const Range*, bool emitCharactersBetweenAllVisiblePositions = false, bool enterTextControls = false);
-
+ TextIterator(const Range*, TextIteratorBehavior);
+
bool atEnd() const { return !m_positionNode; }
void advance();
@@ -87,6 +95,7 @@ public:
static PassRefPtr<Range> subrange(Range* entireRange, int characterOffset, int characterCount);
private:
+ void init(const Range*);
void exitNode();
bool shouldRepresentNodeOffsetZero();
bool shouldEmitSpaceBeforeAndAfterNode(Node*);
@@ -147,6 +156,9 @@ private:
// moveParagraphs to not clone/destroy moved content.
bool m_emitCharactersBetweenAllVisiblePositions;
bool m_enterTextControls;
+
+ // Used when we want texts for copying, pasting, and transposing.
+ bool m_emitsTextWithoutTranscoding;
};
// Iterates through the DOM range, returning all the text, and 0-length boundaries
diff --git a/WebCore/editing/VisiblePosition.cpp b/WebCore/editing/VisiblePosition.cpp
index 2db6d31..1b4a514 100644
--- a/WebCore/editing/VisiblePosition.cpp
+++ b/WebCore/editing/VisiblePosition.cpp
@@ -26,7 +26,6 @@
#include "config.h"
#include "VisiblePosition.h"
-#include "CString.h"
#include "Document.h"
#include "FloatQuad.h"
#include "HTMLElement.h"
@@ -38,6 +37,7 @@
#include "htmlediting.h"
#include "visible_units.h"
#include <stdio.h>
+#include <wtf/text/CString.h>
namespace WebCore {
@@ -110,13 +110,7 @@ Position VisiblePosition::leftVisuallyDistinctCandidate() const
return Position();
Position downstreamStart = p.downstream();
- TextDirection primaryDirection = LTR;
- for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
- if (r->isBlockFlow()) {
- primaryDirection = r->style()->direction();
- break;
- }
- }
+ TextDirection primaryDirection = p.primaryDirection();
while (true) {
InlineBox* box;
@@ -252,13 +246,7 @@ Position VisiblePosition::rightVisuallyDistinctCandidate() const
return Position();
Position downstreamStart = p.downstream();
- TextDirection primaryDirection = LTR;
- for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
- if (r->isBlockFlow()) {
- primaryDirection = r->style()->direction();
- break;
- }
- }
+ TextDirection primaryDirection = p.primaryDirection();
while (true) {
InlineBox* box;
@@ -462,6 +450,7 @@ Position VisiblePosition::canonicalPosition(const Position& position)
if (!node)
return Position();
+ ASSERT(node->document());
node->document()->updateLayoutIgnorePendingStylesheets();
Position candidate = position.upstream();
diff --git a/WebCore/editing/VisibleSelection.cpp b/WebCore/editing/VisibleSelection.cpp
index baef2b5..6784631 100644
--- a/WebCore/editing/VisibleSelection.cpp
+++ b/WebCore/editing/VisibleSelection.cpp
@@ -27,7 +27,6 @@
#include "VisibleSelection.h"
#include "CharacterNames.h"
-#include "CString.h"
#include "Document.h"
#include "Element.h"
#include "htmlediting.h"
@@ -37,13 +36,13 @@
#include "Range.h"
#include <wtf/Assertions.h>
+#include <wtf/text/CString.h>
#include <stdio.h>
namespace WebCore {
VisibleSelection::VisibleSelection()
: m_affinity(DOWNSTREAM)
- , m_granularity(CharacterGranularity)
, m_selectionType(NoSelection)
, m_baseIsFirst(true)
{
@@ -53,7 +52,6 @@ VisibleSelection::VisibleSelection(const Position& pos, EAffinity affinity)
: m_base(pos)
, m_extent(pos)
, m_affinity(affinity)
- , m_granularity(CharacterGranularity)
{
validate();
}
@@ -62,7 +60,6 @@ VisibleSelection::VisibleSelection(const Position& base, const Position& extent,
: m_base(base)
, m_extent(extent)
, m_affinity(affinity)
- , m_granularity(CharacterGranularity)
{
validate();
}
@@ -71,7 +68,6 @@ VisibleSelection::VisibleSelection(const VisiblePosition& pos)
: m_base(pos.deepEquivalent())
, m_extent(pos.deepEquivalent())
, m_affinity(pos.affinity())
- , m_granularity(CharacterGranularity)
{
validate();
}
@@ -80,7 +76,6 @@ VisibleSelection::VisibleSelection(const VisiblePosition& base, const VisiblePos
: m_base(base.deepEquivalent())
, m_extent(extent.deepEquivalent())
, m_affinity(base.affinity())
- , m_granularity(CharacterGranularity)
{
validate();
}
@@ -89,7 +84,6 @@ VisibleSelection::VisibleSelection(const Range* range, EAffinity affinity)
: m_base(range->startPosition())
, m_extent(range->endPosition())
, m_affinity(affinity)
- , m_granularity(CharacterGranularity)
{
validate();
}
@@ -190,8 +184,7 @@ bool VisibleSelection::expandUsingGranularity(TextGranularity granularity)
if (isNone())
return false;
- m_granularity = granularity;
- validate();
+ validate(granularity);
return true;
}
@@ -268,7 +261,7 @@ void VisibleSelection::setBaseAndExtentToDeepEquivalents()
m_baseIsFirst = comparePositions(m_base, m_extent) <= 0;
}
-void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity()
+void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity granularity)
{
if (m_baseIsFirst) {
m_start = m_base;
@@ -278,7 +271,7 @@ void VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity()
m_end = m_base;
}
- switch (m_granularity) {
+ switch (granularity) {
case CharacterGranularity:
// Don't do any expansion.
break;
@@ -408,10 +401,10 @@ void VisibleSelection::updateSelectionType()
m_affinity = DOWNSTREAM;
}
-void VisibleSelection::validate()
+void VisibleSelection::validate(TextGranularity granularity)
{
setBaseAndExtentToDeepEquivalents();
- setStartAndEndFromBaseAndExtentRespectingGranularity();
+ setStartAndEndFromBaseAndExtentRespectingGranularity(granularity);
adjustSelectionToAvoidCrossingEditingBoundaries();
updateSelectionType();
@@ -441,7 +434,6 @@ void VisibleSelection::setWithoutValidation(const Position& base, const Position
ASSERT(!extent.isNull());
ASSERT(base != extent);
ASSERT(m_affinity == DOWNSTREAM);
- ASSERT(m_granularity == CharacterGranularity);
m_base = base;
m_extent = extent;
m_baseIsFirst = comparePositions(base, extent) <= 0;
diff --git a/WebCore/editing/VisibleSelection.h b/WebCore/editing/VisibleSelection.h
index bbcecf2..4ce2b92 100644
--- a/WebCore/editing/VisibleSelection.h
+++ b/WebCore/editing/VisibleSelection.h
@@ -81,8 +81,7 @@ public:
void appendTrailingWhitespace();
bool expandUsingGranularity(TextGranularity granularity);
- TextGranularity granularity() const { return m_granularity; }
-
+
// We don't yet support multi-range selections, so we only ever have one range to return.
PassRefPtr<Range> firstRange() const;
@@ -106,11 +105,11 @@ public:
void setWithoutValidation(const Position&, const Position&);
private:
- void validate();
+ void validate(TextGranularity = CharacterGranularity);
// Support methods for validate()
void setBaseAndExtentToDeepEquivalents();
- void setStartAndEndFromBaseAndExtentRespectingGranularity();
+ void setStartAndEndFromBaseAndExtentRespectingGranularity(TextGranularity);
void adjustSelectionToAvoidCrossingEditingBoundaries();
void updateSelectionType();
@@ -125,7 +124,6 @@ private:
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()
SelectionType m_selectionType; // None, Caret, Range
@@ -134,7 +132,7 @@ private:
inline bool operator==(const VisibleSelection& a, const VisibleSelection& b)
{
- return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity() && a.granularity() == b.granularity() && a.isBaseFirst() == b.isBaseFirst();
+ return a.start() == b.start() && a.end() == b.end() && a.affinity() == b.affinity() && a.isBaseFirst() == b.isBaseFirst();
}
inline bool operator!=(const VisibleSelection& a, const VisibleSelection& b)
diff --git a/WebCore/editing/htmlediting.cpp b/WebCore/editing/htmlediting.cpp
index c0a9b63..b7a062b 100644
--- a/WebCore/editing/htmlediting.cpp
+++ b/WebCore/editing/htmlediting.cpp
@@ -489,6 +489,7 @@ bool validBlockTag(const AtomicString& blockTag)
blockTags.add(h5Tag.localName());
blockTags.add(h6Tag.localName());
blockTags.add(headerTag.localName());
+ blockTags.add(hgroupTag.localName());
blockTags.add(navTag.localName());
blockTags.add(pTag.localName());
blockTags.add(preTag.localName());
@@ -811,13 +812,18 @@ Node* enclosingEmptyListItem(const VisiblePosition& visiblePos)
return listChildNode;
}
-HTMLElement* outermostEnclosingList(Node* node)
+HTMLElement* outermostEnclosingList(Node* node, Node* rootList)
{
HTMLElement* list = enclosingList(node);
if (!list)
return 0;
- while (HTMLElement* nextList = enclosingList(list))
+
+ while (HTMLElement* nextList = enclosingList(list)) {
+ if (nextList == rootList)
+ break;
list = nextList;
+ }
+
return list;
}
diff --git a/WebCore/editing/htmlediting.h b/WebCore/editing/htmlediting.h
index 1559fa5..e60ada9 100644
--- a/WebCore/editing/htmlediting.h
+++ b/WebCore/editing/htmlediting.h
@@ -195,7 +195,7 @@ PassRefPtr<HTMLElement> createHTMLElement(Document*, const QualifiedName&);
PassRefPtr<HTMLElement> createHTMLElement(Document*, const AtomicString&);
HTMLElement* enclosingList(Node*);
-HTMLElement* outermostEnclosingList(Node*);
+HTMLElement* outermostEnclosingList(Node*, Node* rootList = 0);
HTMLElement* enclosingListChild(Node*);
// -------------------------------------------------------------------------
diff --git a/WebCore/editing/markup.cpp b/WebCore/editing/markup.cpp
index dc6cbc2..a2363e6 100644
--- a/WebCore/editing/markup.cpp
+++ b/WebCore/editing/markup.cpp
@@ -970,7 +970,7 @@ String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
Node* body = enclosingNodeWithTag(Position(commonAncestor, 0), bodyTag);
// FIXME: Do this for all fully selected blocks, not just the body.
- Node* fullySelectedRoot = body && *VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange() == *updatedRange ? body : 0;
+ Node* fullySelectedRoot = body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), updatedRange.get()) ? body : 0;
RefPtr<CSSMutableStyleDeclaration> fullySelectedRootStyle = fullySelectedRoot ? styleFromMatchedRulesAndInlineDecl(fullySelectedRoot) : 0;
if (annotate && fullySelectedRoot) {
if (shouldIncludeWrapperForFullySelectedRoot(fullySelectedRoot, fullySelectedRootStyle.get()))
@@ -1058,11 +1058,7 @@ String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterc
PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document* document, const String& markup, const String& baseURL, FragmentScriptingPermission scriptingPermission)
{
- ASSERT(document->documentElement()->isHTMLElement());
- // FIXME: What if the document element is not an HTML element?
- HTMLElement *element = static_cast<HTMLElement*>(document->documentElement());
-
- RefPtr<DocumentFragment> fragment = element->createContextualFragment(markup, scriptingPermission);
+ RefPtr<DocumentFragment> fragment = document->documentElement()->createContextualFragment(markup, scriptingPermission);
if (fragment && !baseURL.isEmpty() && baseURL != blankURL() && baseURL != document->baseURL())
completeURLs(fragment.get(), baseURL);
diff --git a/WebCore/editing/visible_units.cpp b/WebCore/editing/visible_units.cpp
index 84ace83..3d85ad1 100644
--- a/WebCore/editing/visible_units.cpp
+++ b/WebCore/editing/visible_units.cpp
@@ -31,6 +31,7 @@
#include "HTMLNames.h"
#include "RenderBlock.h"
#include "RenderLayer.h"
+#include "RenderObject.h"
#include "TextBoundaries.h"
#include "TextBreakIterator.h"
#include "TextIterator.h"
@@ -253,6 +254,12 @@ static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunc
return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
}
+static bool canHaveCursor(RenderObject* o)
+{
+ return (o->isText() && toRenderText(o)->linesBoundingBox().height())
+ || (o->isBox() && toRenderBox(o)->borderBoundingBox().height());
+}
+
// ---------
static unsigned startWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
@@ -569,8 +576,12 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
if (box) {
root = box->root()->prevRootBox();
- if (root)
+ // We want to skip zero height boxes.
+ // This could happen in case it is a TrailingFloatsRootInlineBox.
+ if (root && root->height())
containingBlock = renderer->containingBlock();
+ else
+ root = 0;
}
if (!root) {
@@ -586,17 +597,20 @@ VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int
break;
Position pos(n, caretMinOffset(n));
if (pos.isCandidate()) {
- ASSERT(n->renderer());
- Position maxPos(n, caretMaxOffset(n));
- maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
- if (box) {
- // previous root line box found
- root = box->root();
- containingBlock = n->renderer()->containingBlock();
- break;
+ RenderObject* o = n->renderer();
+ ASSERT(o);
+ if (canHaveCursor(o)) {
+ Position maxPos(n, caretMaxOffset(n));
+ maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
+ if (box) {
+ // previous root line box found
+ root = box->root();
+ containingBlock = n->renderer()->containingBlock();
+ break;
+ }
+
+ return VisiblePosition(pos, DOWNSTREAM);
}
-
- return VisiblePosition(pos, DOWNSTREAM);
}
n = previousLeafWithSameEditability(n);
}
@@ -671,8 +685,12 @@ VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
if (box) {
root = box->root()->nextRootBox();
- if (root)
+ // We want to skip zero height boxes.
+ // This could happen in case it is a TrailingFloatsRootInlineBox.
+ if (root && root->height())
containingBlock = renderer->containingBlock();
+ else
+ root = 0;
}
if (!root) {