📄 selectioncontroller.cpp
字号:
switch (granularity) { case CharacterGranularity: if (isRange()) pos = VisiblePosition(m_sel.start(), m_sel.affinity()); else pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).left(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 = modifyMovingBackward(granularity); break; } return pos;}VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity){ VisiblePosition pos; switch (granularity) { case CharacterGranularity: if (isRange()) pos = VisiblePosition(m_sel.start(), m_sel.affinity()); else pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).previous(true); break; case WordGranularity: pos = previousWordPosition(VisiblePosition(m_sel.extent(), m_sel.affinity())); break; case SentenceGranularity: pos = previousSentencePosition(VisiblePosition(m_sel.extent(), m_sel.affinity())); break; case LineGranularity: pos = previousLinePosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START)); break; case ParagraphGranularity: pos = previousParagraphPosition(VisiblePosition(m_sel.start(), m_sel.affinity()), xPosForVerticalArrowNavigation(START)); 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;}bool SelectionController::modify(EAlteration alter, EDirection dir, TextGranularity granularity, bool userTriggered){ if (userTriggered) { SelectionController trialSelectionController; trialSelectionController.setLastChangeWasHorizontalExtension(m_lastChangeWasHorizontalExtension); trialSelectionController.setSelection(m_sel); trialSelectionController.modify(alter, dir, granularity, false); bool change = m_frame->shouldChangeSelection(trialSelectionController.selection()); if (!change) return false; } if (m_frame) m_frame->setSelectionGranularity(granularity); willBeModified(alter, dir); VisiblePosition pos; switch (dir) { case RIGHT: if (alter == MOVE) pos = modifyMovingRight(granularity); else pos = modifyExtendingRightForward(granularity); break; case FORWARD: if (alter == EXTEND) pos = modifyExtendingRightForward(granularity); else pos = modifyMovingForward(granularity); break; case LEFT: if (alter == MOVE) pos = modifyMovingLeft(granularity); else pos = modifyExtendingLeftBackward(granularity); break; case BACKWARD: if (alter == EXTEND) pos = modifyExtendingLeftBackward(granularity); else pos = modifyMovingBackward(granularity); break; } if (pos.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 // the requested position type if there were no xPosForVerticalArrowNavigation set. int x = xPosForVerticalArrowNavigation(START); switch (alter) { case MOVE: moveTo(pos, userTriggered); break; case EXTEND: setExtent(pos, userTriggered); break; } 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); } setNeedsLayout(); return true;}// FIXME: Maybe baseline would be better?static bool absoluteCaretY(const VisiblePosition &c, int &y){ IntRect rect = c.absoluteCaretBounds(); if (rect.isEmpty()) return false; y = rect.y() + rect.height() / 2; return true;}bool SelectionController::modify(EAlteration alter, int verticalDistance, bool userTriggered){ if (verticalDistance == 0) return false; if (userTriggered) { SelectionController trialSelectionController; trialSelectionController.setSelection(m_sel); trialSelectionController.modify(alter, verticalDistance, false); bool change = m_frame->shouldChangeSelection(trialSelectionController.selection()); if (!change) return false; } bool up = verticalDistance < 0; if (up) verticalDistance = -verticalDistance; willBeModified(alter, up ? BACKWARD : FORWARD); VisiblePosition pos; int xPos = 0; switch (alter) { case MOVE: pos = VisiblePosition(up ? m_sel.start() : m_sel.end(), m_sel.affinity()); xPos = xPosForVerticalArrowNavigation(up ? START : END); m_sel.setAffinity(up ? UPSTREAM : DOWNSTREAM); break; case EXTEND: pos = VisiblePosition(m_sel.extent(), m_sel.affinity()); xPos = xPosForVerticalArrowNavigation(EXTENT); m_sel.setAffinity(DOWNSTREAM); break; } int startY; if (!absoluteCaretY(pos, startY)) return false; if (up) startY = -startY; int lastY = startY; VisiblePosition result; VisiblePosition next; for (VisiblePosition p = pos; ; p = next) { next = (up ? previousLinePosition : nextLinePosition)(p, xPos); if (next.isNull() || next == p) break; int nextY; if (!absoluteCaretY(next, nextY)) break; if (up) nextY = -nextY; if (nextY - startY > verticalDistance) break; if (nextY >= lastY) { lastY = nextY; result = next; } } if (result.isNull()) return false; switch (alter) { case MOVE: moveTo(result, userTriggered); break; case EXTEND: setExtent(result, userTriggered); break; } if (userTriggered) m_frame->setSelectionGranularity(CharacterGranularity); return true;}bool SelectionController::expandUsingGranularity(TextGranularity granularity){ if (isNone()) return false; m_sel.expandUsingGranularity(granularity); m_needsLayout = true; return true;}int SelectionController::xPosForVerticalArrowNavigation(EPositionType type){ int x = 0; if (isNone()) return x; Position pos; switch (type) { case START: pos = m_sel.start(); break; case END: pos = m_sel.end(); break; case BASE: pos = m_sel.base(); break; case EXTENT: pos = m_sel.extent(); break; } Frame *frame = pos.node()->document()->frame(); if (!frame) return x; if (m_xPosForVerticalArrowNavigation == NoXPosForVerticalArrowNavigation) { VisiblePosition visiblePosition(pos, m_sel.affinity()); // VisiblePosition creation can fail here if a node containing the selection becomes visibility:hidden // after the selection is created and before this function is called. x = visiblePosition.isNotNull() ? visiblePosition.xOffsetForVerticalNavigation() : 0; m_xPosForVerticalArrowNavigation = x; } else x = m_xPosForVerticalArrowNavigation; return x;}void SelectionController::clear(){ setSelection(VisibleSelection());}void SelectionController::setBase(const VisiblePosition &pos, bool userTriggered){ setSelection(VisibleSelection(pos.deepEquivalent(), m_sel.extent(), pos.affinity()), true, true, userTriggered);}void SelectionController::setExtent(const VisiblePosition &pos, bool userTriggered){ setSelection(VisibleSelection(m_sel.base(), pos.deepEquivalent(), pos.affinity()), true, true, userTriggered);}void SelectionController::setBase(const Position &pos, EAffinity affinity, bool userTriggered){ setSelection(VisibleSelection(pos, m_sel.extent(), affinity), true, true, userTriggered);}void SelectionController::setExtent(const Position &pos, EAffinity affinity, bool userTriggered){ setSelection(VisibleSelection(m_sel.base(), pos, affinity), true, true, userTriggered);}void SelectionController::setNeedsLayout(bool flag){ m_needsLayout = flag;}void SelectionController::layout(){ if (isNone() || !m_sel.start().node()->inDocument() || !m_sel.end().node()->inDocument()) { m_caretRect = IntRect(); return; } m_sel.start().node()->document()->updateRendering(); m_caretRect = IntRect(); if (isCaret()) { VisiblePosition pos(m_sel.start(), m_sel.affinity()); if (pos.isNotNull()) { ASSERT(pos.deepEquivalent().node()->renderer()); // First compute a rect local to the renderer at the selection start RenderObject* renderer; IntRect localRect = pos.localCaretRect(renderer); // Get the renderer that will be responsible for painting the caret (which // is either the renderer we just found, or one of its containers) RenderObject* caretPainter = caretRenderer(); // Compute an offset between the renderer and the caretPainter IntSize offsetFromPainter; bool unrooted = false; while (renderer != caretPainter) { RenderObject* containerObject = renderer->container(); if (!containerObject) { unrooted = true; break; } offsetFromPainter += renderer->offsetFromContainer(containerObject); renderer = containerObject; } if (!unrooted) { // Move the caret rect to the coords of the painter localRect.move(offsetFromPainter); m_caretRect = localRect; } m_absCaretBoundsDirty = true; } } m_needsLayout = false;}RenderObject* SelectionController::caretRenderer() const{ Node* node = m_sel.start().node(); if (!node) return 0; RenderObject* renderer = node->renderer(); if (!renderer) return 0; // if caretNode is a block and caret is inside it then caret should be painted by that block bool paintedByBlock = renderer->isBlockFlow() && caretRendersInsideNode(node); return paintedByBlock ? renderer : renderer->containingBlock();}IntRect SelectionController::localCaretRect() const{ if (m_needsLayout) const_cast<SelectionController *>(this)->layout(); return m_caretRect;}IntRect SelectionController::absoluteCaretBounds(){ recomputeCaretRect(); return m_absCaretBounds;}static IntRect repaintRectForCaret(IntRect caret){ if (caret.isEmpty()) return IntRect(); // Ensure that the dirty rect intersects the block that paints the caret even in the case where // the caret itself is just outside the block. See <https://bugs.webkit.org/show_bug.cgi?id=19086>. caret.inflateX(1); return caret;}IntRect SelectionController::caretRepaintRect() const{ IntRect localRect = repaintRectForCaret(localCaretRect()); RenderObject* caretPainter = caretRenderer(); if (caretPainter) return caretPainter->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox(); return IntRect();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -