⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 selectioncontroller.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2004, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */  #include "config.h"#include "SelectionController.h"#include "CString.h"#include "DeleteSelectionCommand.h"#include "Document.h"#include "Editor.h"#include "Element.h"#include "EventHandler.h"#include "EventNames.h"#include "ExceptionCode.h"#include "FocusController.h"#include "FloatQuad.h"#include "Frame.h"#include "FrameTree.h"#include "FrameView.h"#include "GraphicsContext.h"#include "HTMLInputElement.h"#include "HTMLNames.h"#include "HitTestRequest.h"#include "HitTestResult.h"#include "Page.h"#include "Range.h"#include "RenderTheme.h"#include "RenderView.h"#include "TextIterator.h"#include "TypingCommand.h"#include "htmlediting.h"#include "visible_units.h"#include <stdio.h>#define EDIT_DEBUG 0namespace WebCore {using namespace HTMLNames;const int NoXPosForVerticalArrowNavigation = INT_MIN;SelectionController::SelectionController(Frame* frame, bool isDragCaretController)    : m_frame(frame)    , m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation)    , m_needsLayout(true)    , m_absCaretBoundsDirty(true)    , m_lastChangeWasHorizontalExtension(false)    , m_isDragCaretController(isDragCaretController)    , m_isCaretBlinkingSuspended(false)    , m_focused(false){}void SelectionController::moveTo(const VisiblePosition &pos, bool userTriggered){    setSelection(VisibleSelection(pos.deepEquivalent(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);}void SelectionController::moveTo(const VisiblePosition &base, const VisiblePosition &extent, bool userTriggered){    setSelection(VisibleSelection(base.deepEquivalent(), extent.deepEquivalent(), base.affinity()), true, true, userTriggered);}void SelectionController::moveTo(const Position &pos, EAffinity affinity, bool userTriggered){    setSelection(VisibleSelection(pos, affinity), true, true, userTriggered);}void SelectionController::moveTo(const Range *r, EAffinity affinity, bool userTriggered){    setSelection(VisibleSelection(startPosition(r), endPosition(r), affinity), true, true, userTriggered);}void SelectionController::moveTo(const Position &base, const Position &extent, EAffinity affinity, bool userTriggered){    setSelection(VisibleSelection(base, extent, affinity), true, true, userTriggered);}void SelectionController::setSelection(const VisibleSelection& s, bool closeTyping, bool clearTypingStyle, bool userTriggered){    if (m_isDragCaretController) {        invalidateCaretRect();        m_sel = s;        m_needsLayout = true;        invalidateCaretRect();        return;    }    if (!m_frame) {        m_sel = s;        return;    }    Node* baseNode = s.base().node();    Document* document = 0;    if (baseNode)        document = baseNode->document();        // <http://bugs.webkit.org/show_bug.cgi?id=23464>: Infinite recursion at SelectionController::setSelection    // if document->frame() == m_frame we can get into an infinite loop    if (document && document->frame() != m_frame && document != m_frame->document()) {        document->frame()->selection()->setSelection(s, closeTyping, clearTypingStyle, userTriggered);        return;    }        if (closeTyping)        TypingCommand::closeTyping(m_frame->editor()->lastEditCommand());    if (clearTypingStyle)        m_frame->clearTypingStyle();            if (m_sel == s)        return;        VisibleSelection oldSelection = m_sel;    m_sel = s;        m_needsLayout = true;        if (!s.isNone())        m_frame->setFocusedNodeIfNeeded();        m_frame->selectionLayoutChanged();    // Always clear the x position used for vertical arrow navigation.    // It will be restored by the vertical arrow navigation code if necessary.    m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation;    selectFrameElementInParentIfFullySelected();    m_frame->notifyRendererOfSelectionChange(userTriggered);    m_frame->respondToChangedSelection(oldSelection, closeTyping);    if (userTriggered)        m_frame->revealCaret(ScrollAlignment::alignToEdgeIfNeeded);    notifyAccessibilityForSelectionChange();}static bool removingNodeRemovesPosition(Node* node, const Position& position){    if (!position.node())        return false;            if (position.node() == node)        return true;        if (!node->isElementNode())        return false;        Element* element = static_cast<Element*>(node);    return element->contains(position.node()) || element->contains(position.node()->shadowAncestorNode());}void SelectionController::nodeWillBeRemoved(Node *node){    if (isNone())        return;            // There can't be a selection inside a fragment, so if a fragment's node is being removed,    // the selection in the document that created the fragment needs no adjustment.    if (node && highestAncestor(node)->nodeType() == Node::DOCUMENT_FRAGMENT_NODE)        return;        bool baseRemoved = removingNodeRemovesPosition(node, m_sel.base());    bool extentRemoved = removingNodeRemovesPosition(node, m_sel.extent());    bool startRemoved = removingNodeRemovesPosition(node, m_sel.start());    bool endRemoved = removingNodeRemovesPosition(node, m_sel.end());        bool clearRenderTreeSelection = false;    bool clearDOMTreeSelection = false;    if (startRemoved || endRemoved) {        // FIXME: When endpoints are removed, we should just alter the selection, instead of blowing it away.        clearRenderTreeSelection = true;        clearDOMTreeSelection = true;    } else if (baseRemoved || extentRemoved) {        // The base and/or extent are about to be removed, but the start and end aren't.        // Change the base and extent to the start and end, but don't re-validate the        // selection, since doing so could move the start and end into the node        // that is about to be removed.        if (m_sel.isBaseFirst())            m_sel.setWithoutValidation(m_sel.start(), m_sel.end());        else            m_sel.setWithoutValidation(m_sel.end(), m_sel.start());    // FIXME: This could be more efficient if we had an isNodeInRange function on Ranges.    } else if (Range::compareBoundaryPoints(m_sel.start(), Position(node, 0)) == -1 &&               Range::compareBoundaryPoints(m_sel.end(), Position(node, 0)) == 1) {        // If we did nothing here, when this node's renderer was destroyed, the rect that it         // occupied would be invalidated, but, selection gaps that change as a result of         // the removal wouldn't be invalidated.        // FIXME: Don't do so much unnecessary invalidation.        clearRenderTreeSelection = true;    }    if (clearRenderTreeSelection) {        RefPtr<Document> document = m_sel.start().node()->document();        document->updateRendering();        if (RenderView* view = toRenderView(document->renderer()))            view->clearSelection();    }    if (clearDOMTreeSelection)        setSelection(VisibleSelection(), false, false);}void SelectionController::willBeModified(EAlteration alter, EDirection direction){    switch (alter) {        case MOVE:            m_lastChangeWasHorizontalExtension = false;            break;        case EXTEND:            if (!m_lastChangeWasHorizontalExtension) {                m_lastChangeWasHorizontalExtension = true;                Position start = m_sel.start();                Position end = m_sel.end();                switch (direction) {                    // FIXME: right for bidi?                    case RIGHT:                    case FORWARD:                        m_sel.setBase(start);                        m_sel.setExtent(end);                        break;                    case LEFT:                    case BACKWARD:                        m_sel.setBase(end);                        m_sel.setExtent(start);                        break;                }            }            break;    }}VisiblePosition SelectionController::modifyExtendingRightForward(TextGranularity granularity){    VisiblePosition pos(m_sel.extent(), m_sel.affinity());    switch (granularity) {        case CharacterGranularity:            pos = pos.next(true);            break;        case WordGranularity:            pos = nextWordPosition(pos);            break;        case SentenceGranularity:            pos = nextSentencePosition(pos);            break;        case LineGranularity:            pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));            break;        case ParagraphGranularity:            pos = nextParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));            break;        case SentenceBoundary:            pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));            break;        case LineBoundary:            pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));            break;        case ParagraphBoundary:            pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));            break;        case DocumentBoundary:            pos = VisiblePosition(m_sel.end(), m_sel.affinity());            if (isEditablePosition(pos.deepEquivalent()))                pos = endOfEditableContent(pos);            else                pos = endOfDocument(pos);            break;    }        return pos;}VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity){    VisiblePosition pos;    switch (granularity) {        case CharacterGranularity:            if (isRange())                 pos = VisiblePosition(m_sel.end(), m_sel.affinity());            else                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).right(true);            break;        case WordGranularity:        case SentenceGranularity:        case LineGranularity:        case ParagraphGranularity:        case SentenceBoundary:        case LineBoundary:        case ParagraphBoundary:        case DocumentBoundary:            // FIXME: Implement all of the above.            pos = modifyMovingForward(granularity);            break;    }    return pos;}VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity){    VisiblePosition pos;    // FIXME: Stay in editable content for the less common granularities.    switch (granularity) {        case CharacterGranularity:            if (isRange())                 pos = VisiblePosition(m_sel.end(), m_sel.affinity());            else                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).next(true);            break;        case WordGranularity:            pos = nextWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));            break;        case SentenceGranularity:            pos = nextSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity()));            break;        case LineGranularity: {            // down-arrowing from a range selection that ends at the start of a line needs            // to leave the selection at that line start (no need to call nextLinePosition!)            pos = VisiblePosition(m_sel.end(), m_sel.affinity());            if (!isRange() || !isStartOfLine(pos))                pos = nextLinePosition(pos, xPosForVerticalArrowNavigation(START));            break;        }        case ParagraphGranularity:            pos = nextParagraphPosition(VisiblePosition(m_sel.end(), m_sel.affinity()), xPosForVerticalArrowNavigation(START));            break;        case SentenceBoundary:            pos = endOfSentence(VisiblePosition(m_sel.end(), m_sel.affinity()));            break;        case LineBoundary:            pos = endOfLine(VisiblePosition(m_sel.end(), m_sel.affinity()));            break;        case ParagraphBoundary:            pos = endOfParagraph(VisiblePosition(m_sel.end(), m_sel.affinity()));            break;        case DocumentBoundary:            pos = VisiblePosition(m_sel.end(), m_sel.affinity());            if (isEditablePosition(pos.deepEquivalent()))                pos = endOfEditableContent(pos);            else                pos = endOfDocument(pos);            break;                }    return pos;}VisiblePosition SelectionController::modifyExtendingLeftBackward(TextGranularity granularity){    VisiblePosition pos(m_sel.extent(), m_sel.affinity());            // Extending a selection backward by word or character from just after a table selects    // the table.  This "makes sense" from the user perspective, esp. when deleting.    // It was done here instead of in VisiblePosition because we want VPs to iterate    // over everything.    switch (granularity) {        case CharacterGranularity:            pos = pos.previous(true);            break;        case WordGranularity:            pos = previousWordPosition(pos);            break;        case SentenceGranularity:            pos = previousSentencePosition(pos);            break;        case LineGranularity:            pos = previousLinePosition(pos, xPosForVerticalArrowNavigation(EXTENT));            break;        case ParagraphGranularity:            pos = previousParagraphPosition(pos, xPosForVerticalArrowNavigation(EXTENT));            break;        case SentenceBoundary:            pos = startOfSentence(VisiblePosition(m_sel.start(), m_sel.affinity()));            break;        case LineBoundary:            pos = startOfLine(VisiblePosition(m_sel.start(), m_sel.affinity()));            break;        case ParagraphBoundary:            pos = startOfParagraph(VisiblePosition(m_sel.start(), m_sel.affinity()));            break;        case DocumentBoundary:            pos = VisiblePosition(m_sel.start(), m_sel.affinity());            if (isEditablePosition(pos.deepEquivalent()))                pos = startOfEditableContent(pos);            else                 pos = startOfDocument(pos);            break;    }    return pos;}VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity){    VisiblePosition pos;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -