Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(169)

Side by Side Diff: third_party/WebKit/Source/core/editing/DOMSelection.cpp

Issue 2709983005: Selection API: Do not change focus by Selection functions. (Closed)
Patch Set: . Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. 2 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Google Inc. All rights reserved. 3 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 25 matching lines...) Expand all
36 #include "core/dom/Node.h" 36 #include "core/dom/Node.h"
37 #include "core/dom/Range.h" 37 #include "core/dom/Range.h"
38 #include "core/dom/TreeScope.h" 38 #include "core/dom/TreeScope.h"
39 #include "core/editing/EditingUtilities.h" 39 #include "core/editing/EditingUtilities.h"
40 #include "core/editing/FrameSelection.h" 40 #include "core/editing/FrameSelection.h"
41 #include "core/editing/iterators/TextIterator.h" 41 #include "core/editing/iterators/TextIterator.h"
42 #include "core/frame/Deprecation.h" 42 #include "core/frame/Deprecation.h"
43 #include "core/frame/LocalFrame.h" 43 #include "core/frame/LocalFrame.h"
44 #include "core/frame/UseCounter.h" 44 #include "core/frame/UseCounter.h"
45 #include "core/inspector/ConsoleMessage.h" 45 #include "core/inspector/ConsoleMessage.h"
46 #include "platform/EventDispatchForbiddenScope.h"
46 #include "wtf/text/WTFString.h" 47 #include "wtf/text/WTFString.h"
47 48
48 namespace blink { 49 namespace blink {
49 50
51 const FrameSelection::SetSelectionOptions kSetSelectionOptions =
52 FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle |
53 FrameSelection::DoNotSetFocus;
54
50 static Node* selectionShadowAncestor(LocalFrame* frame) { 55 static Node* selectionShadowAncestor(LocalFrame* frame) {
51 Node* node = frame->selection() 56 Node* node = frame->selection()
52 .computeVisibleSelectionInDOMTreeDeprecated() 57 .computeVisibleSelectionInDOMTreeDeprecated()
53 .base() 58 .base()
54 .anchorNode(); 59 .anchorNode();
55 if (!node) 60 if (!node)
56 return 0; 61 return 0;
57 62
58 if (!node->isInShadowTree()) 63 if (!node->isInShadowTree())
59 return 0; 64 return 0;
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 249
245 // 5. Set ([DOM4]) the start and the end of newRange to (node, offset). 250 // 5. Set ([DOM4]) the start and the end of newRange to (node, offset).
246 newRange->setStart(node, offset, exceptionState); 251 newRange->setStart(node, offset, exceptionState);
247 if (exceptionState.hadException()) 252 if (exceptionState.hadException())
248 return; 253 return;
249 newRange->setEnd(node, offset, exceptionState); 254 newRange->setEnd(node, offset, exceptionState);
250 if (exceptionState.hadException()) 255 if (exceptionState.hadException())
251 return; 256 return;
252 257
253 // 6. Set the context object's range to newRange. 258 // 6. Set the context object's range to newRange.
259 EventDispatchForbiddenScope noEvents;
254 frame()->selection().setSelection( 260 frame()->selection().setSelection(
255 SelectionInDOMTree::Builder() 261 SelectionInDOMTree::Builder()
256 .collapse(Position(node, offset)) 262 .collapse(Position(node, offset))
257 .setIsDirectional(frame()->selection().isDirectional()) 263 .setIsDirectional(frame()->selection().isDirectional())
258 .build()); 264 .build(),
265 kSetSelectionOptions);
259 cacheRangeIfSelectionOfDocument(newRange); 266 cacheRangeIfSelectionOfDocument(newRange);
260 } 267 }
261 268
262 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetoend 269 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetoend
263 void DOMSelection::collapseToEnd(ExceptionState& exceptionState) { 270 void DOMSelection::collapseToEnd(ExceptionState& exceptionState) {
264 if (!isAvailable()) 271 if (!isAvailable())
265 return; 272 return;
266 273
267 // The method must throw InvalidStateError exception if the context object is 274 // The method must throw InvalidStateError exception if the context object is
268 // empty. 275 // empty.
269 if (rangeCount() == 0) { 276 if (rangeCount() == 0) {
270 exceptionState.throwDOMException(InvalidStateError, 277 exceptionState.throwDOMException(InvalidStateError,
271 "there is no selection."); 278 "there is no selection.");
272 return; 279 return;
273 } 280 }
274 281
275 // Otherwise, it must create a new range, set both its start and end to the 282 // Otherwise, it must create a new range, set both its start and end to the
276 // end of the context object's range, 283 // end of the context object's range,
284 EventDispatchForbiddenScope noEvents;
277 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange(); 285 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange();
278 newRange->collapse(false); 286 newRange->collapse(false);
279 287
280 // and then set the context object's range to the newly-created range. 288 // and then set the context object's range to the newly-created range.
281 SelectionInDOMTree::Builder builder; 289 SelectionInDOMTree::Builder builder;
282 builder.collapse(newRange->endPosition()); 290 builder.collapse(newRange->endPosition());
283 frame()->selection().setSelection(builder.build()); 291 frame()->selection().setSelection(builder.build(), kSetSelectionOptions);
284 cacheRangeIfSelectionOfDocument(newRange); 292 cacheRangeIfSelectionOfDocument(newRange);
285 } 293 }
286 294
287 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetostart 295 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetostart
288 void DOMSelection::collapseToStart(ExceptionState& exceptionState) { 296 void DOMSelection::collapseToStart(ExceptionState& exceptionState) {
289 if (!isAvailable()) 297 if (!isAvailable())
290 return; 298 return;
291 299
292 // The method must throw InvalidStateError ([DOM4]) exception if the context 300 // The method must throw InvalidStateError ([DOM4]) exception if the context
293 // object is empty. 301 // object is empty.
294 if (rangeCount() == 0) { 302 if (rangeCount() == 0) {
295 exceptionState.throwDOMException(InvalidStateError, 303 exceptionState.throwDOMException(InvalidStateError,
296 "there is no selection."); 304 "there is no selection.");
297 return; 305 return;
298 } 306 }
299 307
300 // Otherwise, it must create a new range, set both its start and end to the 308 // Otherwise, it must create a new range, set both its start and end to the
301 // start of the context object's range, 309 // start of the context object's range,
310 EventDispatchForbiddenScope noEvents;
302 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange(); 311 Range* newRange = getRangeAt(0, ASSERT_NO_EXCEPTION)->cloneRange();
303 newRange->collapse(true); 312 newRange->collapse(true);
304 313
305 // and then set the context object's range to the newly-created range. 314 // and then set the context object's range to the newly-created range.
306 SelectionInDOMTree::Builder builder; 315 SelectionInDOMTree::Builder builder;
307 builder.collapse(newRange->startPosition()); 316 builder.collapse(newRange->startPosition());
308 frame()->selection().setSelection(builder.build()); 317 frame()->selection().setSelection(builder.build(), kSetSelectionOptions);
309 cacheRangeIfSelectionOfDocument(newRange); 318 cacheRangeIfSelectionOfDocument(newRange);
310 } 319 }
311 320
312 void DOMSelection::empty() { 321 void DOMSelection::empty() {
313 if (!isAvailable()) 322 if (!isAvailable())
314 return; 323 return;
315 frame()->selection().clear(); 324 frame()->selection().clear();
316 } 325 }
317 326
318 void DOMSelection::setBaseAndExtent(Node* baseNode, 327 void DOMSelection::setBaseAndExtent(Node* baseNode,
(...skipping 29 matching lines...) Expand all
348 return; 357 return;
349 358
350 clearCachedRangeIfSelectionOfDocument(); 359 clearCachedRangeIfSelectionOfDocument();
351 360
352 // TODO(editing-dev): Once SVG USE element doesn't modify DOM tree, we 361 // TODO(editing-dev): Once SVG USE element doesn't modify DOM tree, we
353 // should get rid of this update layout call. 362 // should get rid of this update layout call.
354 // See http://crbug.com/566281 363 // See http://crbug.com/566281
355 // See "svg/text/textpath-reference-crash.html" 364 // See "svg/text/textpath-reference-crash.html"
356 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); 365 frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
357 366
367 EventDispatchForbiddenScope noEvents;
358 Position basePosition(baseNode, baseOffset); 368 Position basePosition(baseNode, baseOffset);
359 Position extentPosition(extentNode, extentOffset); 369 Position extentPosition(extentNode, extentOffset);
360 frame()->selection().setSelection( 370 frame()->selection().setSelection(
361 SelectionInDOMTree::Builder() 371 SelectionInDOMTree::Builder()
362 .setBaseAndExtentDeprecated(basePosition, extentPosition) 372 .setBaseAndExtentDeprecated(basePosition, extentPosition)
363 .setIsDirectional(true) 373 .setIsDirectional(true)
364 .build()); 374 .build(),
375 kSetSelectionOptions);
365 376
366 Range* newRange = Range::create(baseNode->document()); 377 Range* newRange = Range::create(baseNode->document());
367 if (extentPosition.isNull()) { 378 if (extentPosition.isNull()) {
368 newRange->setStart(baseNode, baseOffset); 379 newRange->setStart(baseNode, baseOffset);
369 newRange->setEnd(baseNode, baseOffset); 380 newRange->setEnd(baseNode, baseOffset);
370 } else if (basePosition < extentPosition) { 381 } else if (basePosition < extentPosition) {
371 newRange->setStart(baseNode, baseOffset); 382 newRange->setStart(baseNode, baseOffset);
372 newRange->setEnd(extentNode, extentOffset); 383 newRange->setEnd(extentNode, extentOffset);
373 } else { 384 } else {
374 newRange->setStart(extentNode, extentOffset); 385 newRange->setStart(extentNode, extentOffset);
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 granularity = LineBoundary; 429 granularity = LineBoundary;
419 else if (equalIgnoringCase(granularityString, "sentenceboundary")) 430 else if (equalIgnoringCase(granularityString, "sentenceboundary"))
420 granularity = SentenceBoundary; 431 granularity = SentenceBoundary;
421 else if (equalIgnoringCase(granularityString, "paragraphboundary")) 432 else if (equalIgnoringCase(granularityString, "paragraphboundary"))
422 granularity = ParagraphBoundary; 433 granularity = ParagraphBoundary;
423 else if (equalIgnoringCase(granularityString, "documentboundary")) 434 else if (equalIgnoringCase(granularityString, "documentboundary"))
424 granularity = DocumentBoundary; 435 granularity = DocumentBoundary;
425 else 436 else
426 return; 437 return;
427 438
428 frame()->selection().modify(alter, direction, granularity); 439 EventDispatchForbiddenScope noEvents;
440 frame()->selection().modify(alter, direction, granularity,
441 EUserTriggered::NotUserTriggered,
442 FrameSelection::DoNotSetFocus);
429 } 443 }
430 444
431 // https://www.w3.org/TR/selection-api/#dom-selection-extend 445 // https://www.w3.org/TR/selection-api/#dom-selection-extend
432 void DOMSelection::extend(Node* node, 446 void DOMSelection::extend(Node* node,
433 unsigned offset, 447 unsigned offset,
434 ExceptionState& exceptionState) { 448 ExceptionState& exceptionState) {
435 DCHECK(node); 449 DCHECK(node);
436 if (!isAvailable()) 450 if (!isAvailable())
437 return; 451 return;
438 452
439 // 1. If node's root is not the document associated with the context object, 453 // 1. If node's root is not the document associated with the context object,
440 // abort these steps. 454 // abort these steps.
441 if (!isValidForPosition(node)) 455 if (!isValidForPosition(node))
442 return; 456 return;
443 457
444 // 2. If the context object is empty, throw an InvalidStateError exception and 458 // 2. If the context object is empty, throw an InvalidStateError exception and
445 // abort these steps. 459 // abort these steps.
446 if (rangeCount() == 0) { 460 if (rangeCount() == 0) {
447 exceptionState.throwDOMException( 461 exceptionState.throwDOMException(
448 InvalidStateError, "This Selection object doesn't have any Ranges."); 462 InvalidStateError, "This Selection object doesn't have any Ranges.");
449 return; 463 return;
450 } 464 }
451 465
452 Range::checkNodeWOffset(node, offset, exceptionState); 466 Range::checkNodeWOffset(node, offset, exceptionState);
453 if (exceptionState.hadException()) 467 if (exceptionState.hadException())
454 return; 468 return;
455 469
470 EventDispatchForbiddenScope noEvents;
456 // 3. Let oldAnchor and oldFocus be the context object's anchor and focus, and 471 // 3. Let oldAnchor and oldFocus be the context object's anchor and focus, and
457 // let newFocus be the boundary point (node, offset). 472 // let newFocus be the boundary point (node, offset).
458 const Position& oldAnchor = anchorPosition(); 473 const Position& oldAnchor = anchorPosition();
459 // TODO(tkent): Diagnostic checks for crbug.com/693578. They should be 474 // TODO(tkent): Diagnostic checks for crbug.com/693578. They should be
460 // removed before M58 branch. 475 // removed before M58 branch.
461 if (oldAnchor.isNull()) { 476 if (oldAnchor.isNull()) {
462 if (Range* range = documentCachedRange()) { 477 if (Range* range = documentCachedRange()) {
463 LOG(FATAL) 478 LOG(FATAL)
464 << "Selection has a cached Range, but anchorPosition is null. start=" 479 << "Selection has a cached Range, but anchorPosition is null. start="
465 << range->startContainer() << " end=" << range->endContainer(); 480 << range->startContainer() << " end=" << range->endContainer();
(...skipping 29 matching lines...) Expand all
495 newRange->setStart(node, offset); 510 newRange->setStart(node, offset);
496 newRange->setEnd(oldAnchor.anchorNode(), oldAnchor.offsetInContainerNode()); 511 newRange->setEnd(oldAnchor.anchorNode(), oldAnchor.offsetInContainerNode());
497 } 512 }
498 513
499 // 8. Set the context object's range to newRange. 514 // 8. Set the context object's range to newRange.
500 SelectionInDOMTree::Builder builder; 515 SelectionInDOMTree::Builder builder;
501 if (newRange->collapsed()) 516 if (newRange->collapsed())
502 builder.collapse(newFocus); 517 builder.collapse(newFocus);
503 else 518 else
504 builder.collapse(oldAnchor).extend(newFocus); 519 builder.collapse(oldAnchor).extend(newFocus);
505 frame()->selection().setSelection(builder.setIsDirectional(true).build()); 520 frame()->selection().setSelection(builder.setIsDirectional(true).build(),
521 kSetSelectionOptions);
506 cacheRangeIfSelectionOfDocument(newRange); 522 cacheRangeIfSelectionOfDocument(newRange);
507 } 523 }
508 524
509 Range* DOMSelection::getRangeAt(unsigned index, 525 Range* DOMSelection::getRangeAt(unsigned index,
510 ExceptionState& exceptionState) const { 526 ExceptionState& exceptionState) const {
511 if (!isAvailable()) 527 if (!isAvailable())
512 return nullptr; 528 return nullptr;
513 529
514 if (index >= rangeCount()) { 530 if (index >= rangeCount()) {
515 exceptionState.throwDOMException( 531 exceptionState.throwDOMException(
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
595 } 611 }
596 612
597 FrameSelection& selection = frame()->selection(); 613 FrameSelection& selection = frame()->selection();
598 614
599 if (newRange->ownerDocument() != selection.document()) { 615 if (newRange->ownerDocument() != selection.document()) {
600 // "editing/selection/selection-in-iframe-removed-crash.html" goes here. 616 // "editing/selection/selection-in-iframe-removed-crash.html" goes here.
601 return; 617 return;
602 } 618 }
603 619
604 if (rangeCount() == 0) { 620 if (rangeCount() == 0) {
605 selection.setSelectedRange(EphemeralRange(newRange), VP_DEFAULT_AFFINITY); 621 EventDispatchForbiddenScope noEvents;
622 selection.setSelectedRange(EphemeralRange(newRange), VP_DEFAULT_AFFINITY,
623 SelectionDirectionalMode::NonDirectional,
624 kSetSelectionOptions);
606 cacheRangeIfSelectionOfDocument(newRange); 625 cacheRangeIfSelectionOfDocument(newRange);
607 return; 626 return;
608 } 627 }
609 628
610 Range* originalRange = primaryRangeOrNull(); 629 Range* originalRange = primaryRangeOrNull();
611 DCHECK(originalRange); 630 DCHECK(originalRange);
612 631
613 if (originalRange->startContainer()->treeScope() != 632 if (originalRange->startContainer()->treeScope() !=
614 newRange->startContainer()->treeScope()) { 633 newRange->startContainer()->treeScope()) {
615 return; 634 return;
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
800 m_treeScope->document().addConsoleMessage( 819 m_treeScope->document().addConsoleMessage(
801 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message)); 820 ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, message));
802 } 821 }
803 822
804 DEFINE_TRACE(DOMSelection) { 823 DEFINE_TRACE(DOMSelection) {
805 visitor->trace(m_treeScope); 824 visitor->trace(m_treeScope);
806 ContextClient::trace(visitor); 825 ContextClient::trace(visitor);
807 } 826 }
808 827
809 } // namespace blink 828 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698