diff options
Diffstat (limited to 'WebCore/editing')
-rw-r--r-- | WebCore/editing/CompositeEditCommand.cpp | 9 | ||||
-rw-r--r-- | WebCore/editing/DeleteSelectionCommand.cpp | 18 | ||||
-rw-r--r-- | WebCore/editing/DeleteSelectionCommand.h | 1 | ||||
-rw-r--r-- | WebCore/editing/Editor.cpp | 2 | ||||
-rw-r--r-- | WebCore/editing/EditorCommand.cpp | 2 | ||||
-rw-r--r-- | WebCore/editing/InsertListCommand.cpp | 9 | ||||
-rw-r--r-- | WebCore/editing/MoveSelectionCommand.cpp | 8 | ||||
-rw-r--r-- | WebCore/editing/MoveSelectionCommand.h | 9 | ||||
-rw-r--r-- | WebCore/editing/ReplaceSelectionCommand.cpp | 49 | ||||
-rw-r--r-- | WebCore/editing/SelectionController.cpp | 186 | ||||
-rw-r--r-- | WebCore/editing/SelectionController.h | 22 | ||||
-rw-r--r-- | WebCore/editing/TextAffinity.h | 2 | ||||
-rw-r--r-- | WebCore/editing/TextIterator.cpp | 49 | ||||
-rw-r--r-- | WebCore/editing/TextIterator.h | 14 | ||||
-rw-r--r-- | WebCore/editing/VisiblePosition.cpp | 19 | ||||
-rw-r--r-- | WebCore/editing/VisibleSelection.cpp | 20 | ||||
-rw-r--r-- | WebCore/editing/VisibleSelection.h | 10 | ||||
-rw-r--r-- | WebCore/editing/htmlediting.cpp | 10 | ||||
-rw-r--r-- | WebCore/editing/htmlediting.h | 2 | ||||
-rw-r--r-- | WebCore/editing/markup.cpp | 8 | ||||
-rw-r--r-- | WebCore/editing/visible_units.cpp | 42 |
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) { |