void DOMSelection::addRange(Range& range) { if (!m_frame) return; FrameSelection& selection = m_frame->selection(); if (selection.isNone()) { selection.moveTo(&range); return; } RefPtr<Range> normalizedRange = selection.selection().toNormalizedRange(); if (!normalizedRange) return; if (range.compareBoundaryPoints(Range::START_TO_START, *normalizedRange, IGNORE_EXCEPTION) == -1) { // We don't support discontiguous selection. We don't do anything if r and range don't intersect. if (range.compareBoundaryPoints(Range::START_TO_END, *normalizedRange, IGNORE_EXCEPTION) > -1) { if (range.compareBoundaryPoints(Range::END_TO_END, *normalizedRange, IGNORE_EXCEPTION) == -1) { // The original range and r intersect. selection.moveTo(range.startPosition(), normalizedRange->endPosition(), DOWNSTREAM); } else { // r contains the original range. selection.moveTo(&range); } } } else { // We don't support discontiguous selection. We don't do anything if r and range don't intersect. ExceptionCode ec = 0; if (range.compareBoundaryPoints(Range::END_TO_START, *normalizedRange, ec) < 1 && !ec) { if (range.compareBoundaryPoints(Range::END_TO_END, *normalizedRange, IGNORE_EXCEPTION) == -1) { // The original range contains r. selection.moveTo(normalizedRange.get()); } else { // The original range and r intersect. selection.moveTo(normalizedRange->startPosition(), range.endPosition(), DOWNSTREAM); } } } }
JSValue* jsRangePrototypeFunctionCompareBoundaryPoints(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) { if (!thisValue->isObject(&JSRange::s_info)) return throwError(exec, TypeError); JSRange* castedThisObj = static_cast<JSRange*>(thisValue); Range* imp = static_cast<Range*>(castedThisObj->impl()); ExceptionCode ec = 0; Range::CompareHow how = static_cast<Range::CompareHow>(args[0]->toInt32(exec)); Range* sourceRange = toRange(args[1]); KJS::JSValue* result = jsNumber(exec, imp->compareBoundaryPoints(how, sourceRange, ec)); setDOMException(exec, ec); return result; }
void DOMSelection::addRange(Range* newRange) { DCHECK(newRange); if (!isAvailable()) return; if (newRange->ownerDocument() != frame()->document()) return; if (!newRange->isConnected()) { addConsoleError("The given range isn't in document."); return; } FrameSelection& selection = frame()->selection(); if (newRange->ownerDocument() != selection.document()) { // "editing/selection/selection-in-iframe-removed-crash.html" goes here. return; } // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets // needs to be audited. See http://crbug.com/590369 for more details. // In the long term, we should change FrameSelection::setSelection to take a // parameter that does not require clean layout, so that modifying selection // no longer performs synchronous layout by itself. frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); if (selection.isNone()) { selection.setSelectedRange(EphemeralRange(newRange), VP_DEFAULT_AFFINITY); return; } Range* originalRange = selection.firstRange(); if (originalRange->startContainer()->document() != newRange->startContainer()->document()) { addConsoleError( "The given range does not belong to the current selection's document."); return; } if (originalRange->startContainer()->treeScope() != newRange->startContainer()->treeScope()) { addConsoleError( "The given range and the current selection belong to two different " "document fragments."); return; } if (originalRange->compareBoundaryPoints(Range::kStartToEnd, newRange, ASSERT_NO_EXCEPTION) < 0 || newRange->compareBoundaryPoints(Range::kStartToEnd, originalRange, ASSERT_NO_EXCEPTION) < 0) { addConsoleError("Discontiguous selection is not supported."); return; } // FIXME: "Merge the ranges if they intersect" is Blink-specific behavior; // other browsers supporting discontiguous selection (obviously) keep each // Range added and return it in getRangeAt(). But it's unclear if we can // really do the same, since we don't support discontiguous selection. Further // discussions at // <https://code.google.com/p/chromium/issues/detail?id=353069>. Range* start = originalRange->compareBoundaryPoints( Range::kStartToStart, newRange, ASSERT_NO_EXCEPTION) < 0 ? originalRange : newRange; Range* end = originalRange->compareBoundaryPoints(Range::kEndToEnd, newRange, ASSERT_NO_EXCEPTION) < 0 ? newRange : originalRange; const EphemeralRange merged = EphemeralRange(start->startPosition(), end->endPosition()); TextAffinity affinity = selection.selection().affinity(); selection.setSelectedRange(merged, affinity); }
JSValue* JSRangePrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args) { if (!thisObj->inherits(&JSRange::info)) return throwError(exec, TypeError); Range* imp = static_cast<Range*>(static_cast<JSRange*>(thisObj)->impl()); switch (id) { case JSRange::SetStartFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } imp->setStart(refNode, offset, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetEndFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } imp->setEnd(refNode, offset, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetStartBeforeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setStartBefore(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetStartAfterFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setStartAfter(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetEndBeforeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setEndBefore(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SetEndAfterFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->setEndAfter(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CollapseFuncNum: { ExceptionCode ec = 0; bool toStart = args[0]->toBoolean(exec); imp->collapse(toStart, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SelectNodeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->selectNode(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SelectNodeContentsFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); imp->selectNodeContents(refNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CompareBoundaryPointsFuncNum: { ExceptionCode ec = 0; Range::CompareHow how = static_cast<Range::CompareHow>(args[0]->toInt32(exec)); Range* sourceRange = toRange(args[1]); KJS::JSValue* result = jsNumber(imp->compareBoundaryPoints(how, sourceRange, ec)); setDOMException(exec, ec); return result; } case JSRange::DeleteContentsFuncNum: { ExceptionCode ec = 0; imp->deleteContents(ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::ExtractContentsFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->extractContents(ec))); setDOMException(exec, ec); return result; } case JSRange::CloneContentsFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->cloneContents(ec))); setDOMException(exec, ec); return result; } case JSRange::InsertNodeFuncNum: { ExceptionCode ec = 0; Node* newNode = toNode(args[0]); imp->insertNode(newNode, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::SurroundContentsFuncNum: { ExceptionCode ec = 0; Node* newParent = toNode(args[0]); imp->surroundContents(newParent, ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CloneRangeFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->cloneRange(ec))); setDOMException(exec, ec); return result; } case JSRange::ToStringFuncNum: { ExceptionCode ec = 0; KJS::JSValue* result = jsString(imp->toString(ec)); setDOMException(exec, ec); return result; } case JSRange::DetachFuncNum: { ExceptionCode ec = 0; imp->detach(ec); setDOMException(exec, ec); return jsUndefined(); } case JSRange::CreateContextualFragmentFuncNum: { ExceptionCode ec = 0; String html = args[0]->toString(exec); KJS::JSValue* result = toJS(exec, WTF::getPtr(imp->createContextualFragment(html, ec))); setDOMException(exec, ec); return result; } case JSRange::IntersectsNodeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); KJS::JSValue* result = jsBoolean(imp->intersectsNode(refNode, ec)); setDOMException(exec, ec); return result; } case JSRange::CompareNodeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); KJS::JSValue* result = jsNumber(imp->compareNode(refNode, ec)); setDOMException(exec, ec); return result; } case JSRange::ComparePointFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } KJS::JSValue* result = jsNumber(imp->comparePoint(refNode, offset, ec)); setDOMException(exec, ec); return result; } case JSRange::IsPointInRangeFuncNum: { ExceptionCode ec = 0; Node* refNode = toNode(args[0]); bool offsetOk; int offset = args[1]->toInt32(exec, offsetOk); if (!offsetOk) { setDOMException(exec, TYPE_MISMATCH_ERR); return jsUndefined(); } KJS::JSValue* result = jsBoolean(imp->isPointInRange(refNode, offset, ec)); setDOMException(exec, ec); return result; } } return 0; }