static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode) { if (!oldFocusedFrame || !newFocusedFrame) return; if (oldFocusedFrame->document() != newFocusedFrame->document()) return; SelectionController* s = oldFocusedFrame->selection(); if (s->isNone()) return; bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled(); if (caretBrowsing) return; Node* selectionStartNode = s->selection().start().node(); if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode) return; if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) if (Node* root = s->rootEditableElement()) if (Node* shadowAncestorNode = root->shadowAncestorNode()) // Don't do this for textareas and text fields, when they lose focus their selections should be cleared // and then restored when they regain focus, to match other browsers. if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag)) return; s->clear(); }
bool DOMSelection::containsNode(const Node* n, bool allowPartial) const { if (!m_frame) return false; SelectionController* selection = m_frame->selection(); if (!n || selection->isNone()) return false; Node* parentNode = n->parentNode(); unsigned nodeIndex = n->nodeIndex(); RefPtr<Range> selectedRange = selection->selection().toNormalizedRange(); if (!parentNode) return false; ExceptionCode ec = 0; bool nodeFullySelected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) >= 0 && Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) <= 0; ASSERT(!ec); if (nodeFullySelected) return true; bool nodeFullyUnselected = Range::compareBoundaryPoints(parentNode, nodeIndex, selectedRange->endContainer(ec), selectedRange->endOffset(ec)) > 0 || Range::compareBoundaryPoints(parentNode, nodeIndex + 1, selectedRange->startContainer(ec), selectedRange->startOffset(ec)) < 0; ASSERT(!ec); if (nodeFullyUnselected) return false; return allowPartial || n->isTextNode(); }
String DOMSelection::type() const { if (!m_frame) return String(); SelectionController* selection = m_frame->selection(); // This is a WebKit DOM extension, incompatible with an IE extension // IE has this same attribute, but returns "none", "text" and "control" // http://msdn.microsoft.com/en-us/library/ms534692(VS.85).aspx if (selection->isNone()) return "None"; if (selection->isCaret()) return "Caret"; return "Range"; }
void DOMSelection::deleteFromDocument() { if (!m_frame) return; SelectionController* selection = m_frame->selection(); if (selection->isNone()) return; if (isCollapsed()) selection->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity); RefPtr<Range> selectedRange = selection->selection().toNormalizedRange(); ExceptionCode ec = 0; selectedRange->deleteContents(ec); ASSERT(!ec); setBaseAndExtent(selectedRange->startContainer(ec), selectedRange->startOffset(ec), selectedRange->startContainer(ec), selectedRange->startOffset(ec), ec); ASSERT(!ec); }
void DOMSelection::addRange(Range* r) { if (!m_frame) return; if (!r) return; SelectionController* selection = m_frame->selection(); if (selection->isNone()) { selection->setSelection(VisibleSelection(r)); return; } RefPtr<Range> range = selection->selection().toNormalizedRange(); ExceptionCode ec = 0; if (r->compareBoundaryPoints(Range::START_TO_START, range.get(), ec) == -1) { // We don't support discontiguous selection. We don't do anything if r and range don't intersect. if (r->compareBoundaryPoints(Range::START_TO_END, range.get(), ec) > -1) { if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1) // The original range and r intersect. selection->setSelection(VisibleSelection(r->startPosition(), range->endPosition(), DOWNSTREAM)); else // r contains the original range. selection->setSelection(VisibleSelection(r)); } } else { // We don't support discontiguous selection. We don't do anything if r and range don't intersect. if (r->compareBoundaryPoints(Range::END_TO_START, range.get(), ec) < 1) { if (r->compareBoundaryPoints(Range::END_TO_END, range.get(), ec) == -1) // The original range contains r. selection->setSelection(VisibleSelection(range.get())); else // The original range and r intersect. selection->setSelection(VisibleSelection(range->startPosition(), r->endPosition(), DOWNSTREAM)); } } }
static void clearSelectionIfNeeded(Frame* oldFocusedFrame, Frame* newFocusedFrame, Node* newFocusedNode) { if (!oldFocusedFrame || !newFocusedFrame) return; if (oldFocusedFrame->document() != newFocusedFrame->document()) return; SelectionController* s = oldFocusedFrame->selection(); if (s->isNone()) return; bool caretBrowsing = oldFocusedFrame->settings()->caretBrowsingEnabled(); if (caretBrowsing) return; Node* selectionStartNode = s->selection().start().deprecatedNode(); if (selectionStartNode == newFocusedNode || selectionStartNode->isDescendantOf(newFocusedNode) || selectionStartNode->shadowAncestorNode() == newFocusedNode) return; if (Node* mousePressNode = newFocusedFrame->eventHandler()->mousePressNode()) { if (mousePressNode->renderer() && !mousePressNode->canStartSelection()) { // Don't clear the selection for contentEditable elements, but do clear it for input and textarea. See bug 38696. Node * root = s->rootEditableElement(); if (!root) return; if (Node* shadowAncestorNode = root->shadowAncestorNode()) { if (!shadowAncestorNode->hasTagName(inputTag) && !shadowAncestorNode->hasTagName(textareaTag)) return; } } } s->clear(); }