| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) | 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
| 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 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 { | 115 { |
| 116 frame().selection().updateIfNeeded(); | 116 frame().selection().updateIfNeeded(); |
| 117 VisibleSelection selection = frame().selection().selection(); | 117 VisibleSelection selection = frame().selection().selection(); |
| 118 if (!event) | 118 if (!event) |
| 119 return selection; | 119 return selection; |
| 120 // If the target is a text control, and the current selection is outside of
its shadow tree, | 120 // If the target is a text control, and the current selection is outside of
its shadow tree, |
| 121 // then use the saved selection for that text control. | 121 // then use the saved selection for that text control. |
| 122 HTMLTextFormControlElement* textFormControlOfSelectionStart = enclosingTextF
ormControl(selection.start()); | 122 HTMLTextFormControlElement* textFormControlOfSelectionStart = enclosingTextF
ormControl(selection.start()); |
| 123 HTMLTextFormControlElement* textFromControlOfTarget = isHTMLTextFormControlE
lement(*event->target()->toNode()) ? toHTMLTextFormControlElement(event->target(
)->toNode()) : 0; | 123 HTMLTextFormControlElement* textFromControlOfTarget = isHTMLTextFormControlE
lement(*event->target()->toNode()) ? toHTMLTextFormControlElement(event->target(
)->toNode()) : 0; |
| 124 if (textFromControlOfTarget && (selection.start().isNull() || textFromContro
lOfTarget != textFormControlOfSelectionStart)) { | 124 if (textFromControlOfTarget && (selection.start().isNull() || textFromContro
lOfTarget != textFormControlOfSelectionStart)) { |
| 125 if (RefPtrWillBeRawPtr<Range> range = textFromControlOfTarget->selection
()) | 125 if (RawPtr<Range> range = textFromControlOfTarget->selection()) |
| 126 return VisibleSelection(EphemeralRange(range.get()), TextAffinity::D
ownstream, selection.isDirectional()); | 126 return VisibleSelection(EphemeralRange(range.get()), TextAffinity::D
ownstream, selection.isDirectional()); |
| 127 } | 127 } |
| 128 return selection; | 128 return selection; |
| 129 } | 129 } |
| 130 | 130 |
| 131 // Function considers Mac editing behavior a fallback when Page or Settings is n
ot available. | 131 // Function considers Mac editing behavior a fallback when Page or Settings is n
ot available. |
| 132 EditingBehavior Editor::behavior() const | 132 EditingBehavior Editor::behavior() const |
| 133 { | 133 { |
| 134 if (!frame().settings()) | 134 if (!frame().settings()) |
| 135 return EditingBehavior(EditingMacBehavior); | 135 return EditingBehavior(EditingMacBehavior); |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 } | 346 } |
| 347 | 347 |
| 348 void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace) | 348 void Editor::pasteAsPlainText(const String& pastingText, bool smartReplace) |
| 349 { | 349 { |
| 350 Element* target = findEventTargetFromSelection(); | 350 Element* target = findEventTargetFromSelection(); |
| 351 if (!target) | 351 if (!target) |
| 352 return; | 352 return; |
| 353 target->dispatchEvent(TextEvent::createForPlainTextPaste(frame().domWindow()
, pastingText, smartReplace)); | 353 target->dispatchEvent(TextEvent::createForPlainTextPaste(frame().domWindow()
, pastingText, smartReplace)); |
| 354 } | 354 } |
| 355 | 355 |
| 356 void Editor::pasteAsFragment(PassRefPtrWillBeRawPtr<DocumentFragment> pastingFra
gment, bool smartReplace, bool matchStyle) | 356 void Editor::pasteAsFragment(RawPtr<DocumentFragment> pastingFragment, bool smar
tReplace, bool matchStyle) |
| 357 { | 357 { |
| 358 Element* target = findEventTargetFromSelection(); | 358 Element* target = findEventTargetFromSelection(); |
| 359 if (!target) | 359 if (!target) |
| 360 return; | 360 return; |
| 361 target->dispatchEvent(TextEvent::createForFragmentPaste(frame().domWindow(),
pastingFragment, smartReplace, matchStyle)); | 361 target->dispatchEvent(TextEvent::createForFragmentPaste(frame().domWindow(),
pastingFragment, smartReplace, matchStyle)); |
| 362 } | 362 } |
| 363 | 363 |
| 364 bool Editor::tryDHTMLCopy() | 364 bool Editor::tryDHTMLCopy() |
| 365 { | 365 { |
| 366 if (frame().selection().isInPasswordField()) | 366 if (frame().selection().isInPasswordField()) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 383 } | 383 } |
| 384 | 384 |
| 385 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard) | 385 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard* pasteboard) |
| 386 { | 386 { |
| 387 String text = pasteboard->plainText(); | 387 String text = pasteboard->plainText(); |
| 388 pasteAsPlainText(text, canSmartReplaceWithPasteboard(pasteboard)); | 388 pasteAsPlainText(text, canSmartReplaceWithPasteboard(pasteboard)); |
| 389 } | 389 } |
| 390 | 390 |
| 391 void Editor::pasteWithPasteboard(Pasteboard* pasteboard) | 391 void Editor::pasteWithPasteboard(Pasteboard* pasteboard) |
| 392 { | 392 { |
| 393 RefPtrWillBeRawPtr<DocumentFragment> fragment = nullptr; | 393 RawPtr<DocumentFragment> fragment = nullptr; |
| 394 bool chosePlainText = false; | 394 bool chosePlainText = false; |
| 395 | 395 |
| 396 if (pasteboard->isHTMLAvailable()) { | 396 if (pasteboard->isHTMLAvailable()) { |
| 397 unsigned fragmentStart = 0; | 397 unsigned fragmentStart = 0; |
| 398 unsigned fragmentEnd = 0; | 398 unsigned fragmentEnd = 0; |
| 399 KURL url; | 399 KURL url; |
| 400 String markup = pasteboard->readHTML(url, fragmentStart, fragmentEnd); | 400 String markup = pasteboard->readHTML(url, fragmentStart, fragmentEnd); |
| 401 if (!markup.isEmpty()) { | 401 if (!markup.isEmpty()) { |
| 402 ASSERT(frame().document()); | 402 ASSERT(frame().document()); |
| 403 fragment = createFragmentFromMarkupWithContext(*frame().document(),
markup, fragmentStart, fragmentEnd, url, DisallowScriptingAndPluginContent); | 403 fragment = createFragmentFromMarkupWithContext(*frame().document(),
markup, fragmentStart, fragmentEnd, url, DisallowScriptingAndPluginContent); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 if (!target) | 478 if (!target) |
| 479 return true; | 479 return true; |
| 480 | 480 |
| 481 DataTransfer* dataTransfer = DataTransfer::create( | 481 DataTransfer* dataTransfer = DataTransfer::create( |
| 482 DataTransfer::CopyAndPaste, | 482 DataTransfer::CopyAndPaste, |
| 483 policy, | 483 policy, |
| 484 policy == DataTransferWritable | 484 policy == DataTransferWritable |
| 485 ? DataObject::create() | 485 ? DataObject::create() |
| 486 : DataObject::createFromPasteboard(pasteMode)); | 486 : DataObject::createFromPasteboard(pasteMode)); |
| 487 | 487 |
| 488 RefPtrWillBeRawPtr<Event> evt = ClipboardEvent::create(eventType, true, true
, dataTransfer); | 488 RawPtr<Event> evt = ClipboardEvent::create(eventType, true, true, dataTransf
er); |
| 489 target->dispatchEvent(evt); | 489 target->dispatchEvent(evt); |
| 490 bool noDefaultProcessing = evt->defaultPrevented(); | 490 bool noDefaultProcessing = evt->defaultPrevented(); |
| 491 if (noDefaultProcessing && policy == DataTransferWritable) | 491 if (noDefaultProcessing && policy == DataTransferWritable) |
| 492 Pasteboard::generalPasteboard()->writeDataObject(dataTransfer->dataObjec
t()); | 492 Pasteboard::generalPasteboard()->writeDataObject(dataTransfer->dataObjec
t()); |
| 493 | 493 |
| 494 // invalidate clipboard here for security | 494 // invalidate clipboard here for security |
| 495 dataTransfer->setAccessPolicy(DataTransferNumb); | 495 dataTransfer->setAccessPolicy(DataTransferNumb); |
| 496 | 496 |
| 497 return !noDefaultProcessing; | 497 return !noDefaultProcessing; |
| 498 } | 498 } |
| 499 | 499 |
| 500 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard) | 500 bool Editor::canSmartReplaceWithPasteboard(Pasteboard* pasteboard) |
| 501 { | 501 { |
| 502 return smartInsertDeleteEnabled() && pasteboard->canSmartReplace(); | 502 return smartInsertDeleteEnabled() && pasteboard->canSmartReplace(); |
| 503 } | 503 } |
| 504 | 504 |
| 505 void Editor::replaceSelectionWithFragment(PassRefPtrWillBeRawPtr<DocumentFragmen
t> fragment, bool selectReplacement, bool smartReplace, bool matchStyle) | 505 void Editor::replaceSelectionWithFragment(RawPtr<DocumentFragment> fragment, boo
l selectReplacement, bool smartReplace, bool matchStyle) |
| 506 { | 506 { |
| 507 if (frame().selection().isNone() || !frame().selection().isContentEditable()
|| !fragment) | 507 if (frame().selection().isNone() || !frame().selection().isContentEditable()
|| !fragment) |
| 508 return; | 508 return; |
| 509 | 509 |
| 510 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::P
reventNesting | ReplaceSelectionCommand::SanitizeFragment; | 510 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::P
reventNesting | ReplaceSelectionCommand::SanitizeFragment; |
| 511 if (selectReplacement) | 511 if (selectReplacement) |
| 512 options |= ReplaceSelectionCommand::SelectReplacement; | 512 options |= ReplaceSelectionCommand::SelectReplacement; |
| 513 if (smartReplace) | 513 if (smartReplace) |
| 514 options |= ReplaceSelectionCommand::SmartReplace; | 514 options |= ReplaceSelectionCommand::SmartReplace; |
| 515 if (matchStyle) | 515 if (matchStyle) |
| 516 options |= ReplaceSelectionCommand::MatchStyle; | 516 options |= ReplaceSelectionCommand::MatchStyle; |
| 517 ASSERT(frame().document()); | 517 ASSERT(frame().document()); |
| 518 ReplaceSelectionCommand::create(*frame().document(), fragment, options, Edit
ActionPaste)->apply(); | 518 ReplaceSelectionCommand::create(*frame().document(), fragment, options, Edit
ActionPaste)->apply(); |
| 519 revealSelectionAfterEditingOperation(); | 519 revealSelectionAfterEditingOperation(); |
| 520 } | 520 } |
| 521 | 521 |
| 522 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement
, bool smartReplace) | 522 void Editor::replaceSelectionWithText(const String& text, bool selectReplacement
, bool smartReplace) |
| 523 { | 523 { |
| 524 replaceSelectionWithFragment(createFragmentFromText(selectedRange(), text),
selectReplacement, smartReplace, true); | 524 replaceSelectionWithFragment(createFragmentFromText(selectedRange(), text),
selectReplacement, smartReplace, true); |
| 525 } | 525 } |
| 526 | 526 |
| 527 // TODO(xiaochengh): Merge it with |replaceSelectionWithFragment()|. | 527 // TODO(xiaochengh): Merge it with |replaceSelectionWithFragment()|. |
| 528 void Editor::replaceSelectionAfterDragging(PassRefPtrWillBeRawPtr<DocumentFragme
nt> fragment, bool smartReplace, bool plainText) | 528 void Editor::replaceSelectionAfterDragging(RawPtr<DocumentFragment> fragment, bo
ol smartReplace, bool plainText) |
| 529 { | 529 { |
| 530 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S
electReplacement | ReplaceSelectionCommand::PreventNesting; | 530 ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::S
electReplacement | ReplaceSelectionCommand::PreventNesting; |
| 531 if (smartReplace) | 531 if (smartReplace) |
| 532 options |= ReplaceSelectionCommand::SmartReplace; | 532 options |= ReplaceSelectionCommand::SmartReplace; |
| 533 if (plainText) | 533 if (plainText) |
| 534 options |= ReplaceSelectionCommand::MatchStyle; | 534 options |= ReplaceSelectionCommand::MatchStyle; |
| 535 ASSERT(frame().document()); | 535 ASSERT(frame().document()); |
| 536 ReplaceSelectionCommand::create(*frame().document(), fragment, options, Edit
ActionDrag)->apply(); | 536 ReplaceSelectionCommand::create(*frame().document(), fragment, options, Edit
ActionDrag)->apply(); |
| 537 } | 537 } |
| 538 | 538 |
| 539 void Editor::moveSelectionAfterDragging(PassRefPtrWillBeRawPtr<DocumentFragment>
fragment, const Position& pos, bool smartInsert, bool smartDelete) | 539 void Editor::moveSelectionAfterDragging(RawPtr<DocumentFragment> fragment, const
Position& pos, bool smartInsert, bool smartDelete) |
| 540 { | 540 { |
| 541 MoveSelectionCommand::create(fragment, pos, smartInsert, smartDelete)->apply
(); | 541 MoveSelectionCommand::create(fragment, pos, smartInsert, smartDelete)->apply
(); |
| 542 } | 542 } |
| 543 | 543 |
| 544 EphemeralRange Editor::selectedRange() | 544 EphemeralRange Editor::selectedRange() |
| 545 { | 545 { |
| 546 return frame().selection().selection().toNormalizedEphemeralRange(); | 546 return frame().selection().selection().toNormalizedEphemeralRange(); |
| 547 } | 547 } |
| 548 | 548 |
| 549 bool Editor::shouldDeleteRange(const EphemeralRange& range) const | 549 bool Editor::shouldDeleteRange(const EphemeralRange& range) const |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 645 EditingStyle::styleAtSelectionStart(frame().selection().selection(), pro
pertyID == CSSPropertyBackgroundColor).get()); | 645 EditingStyle::styleAtSelectionStart(frame().selection().selection(), pro
pertyID == CSSPropertyBackgroundColor).get()); |
| 646 } | 646 } |
| 647 | 647 |
| 648 TriState Editor::selectionHasStyle(CSSPropertyID propertyID, const String& value
) const | 648 TriState Editor::selectionHasStyle(CSSPropertyID propertyID, const String& value
) const |
| 649 { | 649 { |
| 650 return EditingStyle::create(propertyID, value)->triStateOfStyle(frame().sele
ction().selection()); | 650 return EditingStyle::create(propertyID, value)->triStateOfStyle(frame().sele
ction().selection()); |
| 651 } | 651 } |
| 652 | 652 |
| 653 String Editor::selectionStartCSSPropertyValue(CSSPropertyID propertyID) | 653 String Editor::selectionStartCSSPropertyValue(CSSPropertyID propertyID) |
| 654 { | 654 { |
| 655 RefPtrWillBeRawPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelec
tionStart(frame().selection().selection(), | 655 RawPtr<EditingStyle> selectionStyle = EditingStyle::styleAtSelectionStart(fr
ame().selection().selection(), |
| 656 propertyID == CSSPropertyBackgroundColor); | 656 propertyID == CSSPropertyBackgroundColor); |
| 657 if (!selectionStyle || !selectionStyle->style()) | 657 if (!selectionStyle || !selectionStyle->style()) |
| 658 return String(); | 658 return String(); |
| 659 | 659 |
| 660 if (propertyID == CSSPropertyFontSize) | 660 if (propertyID == CSSPropertyFontSize) |
| 661 return String::number(selectionStyle->legacyFontSize(frame().document())
); | 661 return String::number(selectionStyle->legacyFontSize(frame().document())
); |
| 662 return selectionStyle->style()->getPropertyValue(propertyID); | 662 return selectionStyle->style()->getPropertyValue(propertyID); |
| 663 } | 663 } |
| 664 | 664 |
| 665 static void dispatchEditableContentChangedEvents(PassRefPtrWillBeRawPtr<Element>
startRoot, PassRefPtrWillBeRawPtr<Element> endRoot) | 665 static void dispatchEditableContentChangedEvents(RawPtr<Element> startRoot, RawP
tr<Element> endRoot) |
| 666 { | 666 { |
| 667 if (startRoot) | 667 if (startRoot) |
| 668 startRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableCon
tentChanged)); | 668 startRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableCon
tentChanged)); |
| 669 if (endRoot && endRoot != startRoot) | 669 if (endRoot && endRoot != startRoot) |
| 670 endRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableConte
ntChanged)); | 670 endRoot->dispatchEvent(Event::create(EventTypeNames::webkitEditableConte
ntChanged)); |
| 671 } | 671 } |
| 672 | 672 |
| 673 void Editor::requestSpellcheckingAfterApplyingCommand(CompositeEditCommand* cmd) | 673 void Editor::requestSpellcheckingAfterApplyingCommand(CompositeEditCommand* cmd) |
| 674 { | 674 { |
| 675 // Note: Request spell checking for and only for |ReplaceSelectionCommand|s | 675 // Note: Request spell checking for and only for |ReplaceSelectionCommand|s |
| 676 // created in |Editor::replaceSelectionWithFragment()|. | 676 // created in |Editor::replaceSelectionWithFragment()|. |
| 677 // TODO(xiaochengh): May also need to do this after dragging crbug.com/29804
6. | 677 // TODO(xiaochengh): May also need to do this after dragging crbug.com/29804
6. |
| 678 if (cmd->editingAction() != EditActionPaste) | 678 if (cmd->editingAction() != EditActionPaste) |
| 679 return; | 679 return; |
| 680 if (!spellChecker().isContinuousSpellCheckingEnabled()) | 680 if (!spellChecker().isContinuousSpellCheckingEnabled()) |
| 681 return; | 681 return; |
| 682 if (!SpellChecker::isSpellCheckingEnabledFor(cmd->endingSelection())) | 682 if (!SpellChecker::isSpellCheckingEnabledFor(cmd->endingSelection())) |
| 683 return; | 683 return; |
| 684 ASSERT(cmd->isReplaceSelectionCommand()); | 684 ASSERT(cmd->isReplaceSelectionCommand()); |
| 685 const EphemeralRange& insertedRange = toReplaceSelectionCommand(cmd)->insert
edRange(); | 685 const EphemeralRange& insertedRange = toReplaceSelectionCommand(cmd)->insert
edRange(); |
| 686 if (insertedRange.isNull()) | 686 if (insertedRange.isNull()) |
| 687 return; | 687 return; |
| 688 spellChecker().chunkAndMarkAllMisspellingsAndBadGrammar(cmd->endingSelection
().rootEditableElement(), insertedRange); | 688 spellChecker().chunkAndMarkAllMisspellingsAndBadGrammar(cmd->endingSelection
().rootEditableElement(), insertedRange); |
| 689 } | 689 } |
| 690 | 690 |
| 691 void Editor::appliedEditing(PassRefPtrWillBeRawPtr<CompositeEditCommand> cmd) | 691 void Editor::appliedEditing(RawPtr<CompositeEditCommand> cmd) |
| 692 { | 692 { |
| 693 EventQueueScope scope; | 693 EventQueueScope scope; |
| 694 frame().document()->updateLayout(); | 694 frame().document()->updateLayout(); |
| 695 | 695 |
| 696 // Request spell checking after pasting before any further DOM change. | 696 // Request spell checking after pasting before any further DOM change. |
| 697 requestSpellcheckingAfterApplyingCommand(cmd.get()); | 697 requestSpellcheckingAfterApplyingCommand(cmd.get()); |
| 698 | 698 |
| 699 EditCommandComposition* composition = cmd->composition(); | 699 EditCommandComposition* composition = cmd->composition(); |
| 700 ASSERT(composition); | 700 ASSERT(composition); |
| 701 dispatchEditableContentChangedEvents(composition->startingRootEditableElemen
t(), composition->endingRootEditableElement()); | 701 dispatchEditableContentChangedEvents(composition->startingRootEditableElemen
t(), composition->endingRootEditableElement()); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 714 // Only register a new undo command if the command passed in is | 714 // Only register a new undo command if the command passed in is |
| 715 // different from the last command | 715 // different from the last command |
| 716 m_lastEditCommand = cmd; | 716 m_lastEditCommand = cmd; |
| 717 if (UndoStack* undoStack = this->undoStack()) | 717 if (UndoStack* undoStack = this->undoStack()) |
| 718 undoStack->registerUndoStep(m_lastEditCommand->ensureComposition()); | 718 undoStack->registerUndoStep(m_lastEditCommand->ensureComposition()); |
| 719 } | 719 } |
| 720 | 720 |
| 721 respondToChangedContents(newSelection); | 721 respondToChangedContents(newSelection); |
| 722 } | 722 } |
| 723 | 723 |
| 724 void Editor::unappliedEditing(PassRefPtrWillBeRawPtr<EditCommandComposition> cmd
) | 724 void Editor::unappliedEditing(RawPtr<EditCommandComposition> cmd) |
| 725 { | 725 { |
| 726 EventQueueScope scope; | 726 EventQueueScope scope; |
| 727 frame().document()->updateLayout(); | 727 frame().document()->updateLayout(); |
| 728 | 728 |
| 729 dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd
->endingRootEditableElement()); | 729 dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd
->endingRootEditableElement()); |
| 730 | 730 |
| 731 VisibleSelection newSelection(cmd->startingSelection()); | 731 VisibleSelection newSelection(cmd->startingSelection()); |
| 732 newSelection.validatePositionsIfNeeded(); | 732 newSelection.validatePositionsIfNeeded(); |
| 733 if (newSelection.start().document() == frame().document() && newSelection.en
d().document() == frame().document()) | 733 if (newSelection.start().document() == frame().document() && newSelection.en
d().document() == frame().document()) |
| 734 changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping |
FrameSelection::ClearTypingStyle); | 734 changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping |
FrameSelection::ClearTypingStyle); |
| 735 | 735 |
| 736 m_lastEditCommand = nullptr; | 736 m_lastEditCommand = nullptr; |
| 737 if (UndoStack* undoStack = this->undoStack()) | 737 if (UndoStack* undoStack = this->undoStack()) |
| 738 undoStack->registerRedoStep(cmd); | 738 undoStack->registerRedoStep(cmd); |
| 739 respondToChangedContents(newSelection); | 739 respondToChangedContents(newSelection); |
| 740 } | 740 } |
| 741 | 741 |
| 742 void Editor::reappliedEditing(PassRefPtrWillBeRawPtr<EditCommandComposition> cmd
) | 742 void Editor::reappliedEditing(RawPtr<EditCommandComposition> cmd) |
| 743 { | 743 { |
| 744 EventQueueScope scope; | 744 EventQueueScope scope; |
| 745 frame().document()->updateLayout(); | 745 frame().document()->updateLayout(); |
| 746 | 746 |
| 747 dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd
->endingRootEditableElement()); | 747 dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd
->endingRootEditableElement()); |
| 748 | 748 |
| 749 VisibleSelection newSelection(cmd->endingSelection()); | 749 VisibleSelection newSelection(cmd->endingSelection()); |
| 750 changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | Fram
eSelection::ClearTypingStyle); | 750 changeSelectionAfterCommand(newSelection, FrameSelection::CloseTyping | Fram
eSelection::ClearTypingStyle); |
| 751 | 751 |
| 752 m_lastEditCommand = nullptr; | 752 m_lastEditCommand = nullptr; |
| 753 if (UndoStack* undoStack = this->undoStack()) | 753 if (UndoStack* undoStack = this->undoStack()) |
| 754 undoStack->registerUndoStep(cmd); | 754 undoStack->registerUndoStep(cmd); |
| 755 respondToChangedContents(newSelection); | 755 respondToChangedContents(newSelection); |
| 756 } | 756 } |
| 757 | 757 |
| 758 PassOwnPtrWillBeRawPtr<Editor> Editor::create(LocalFrame& frame) | 758 RawPtr<Editor> Editor::create(LocalFrame& frame) |
| 759 { | 759 { |
| 760 return adoptPtrWillBeNoop(new Editor(frame)); | 760 return new Editor(frame); |
| 761 } | 761 } |
| 762 | 762 |
| 763 Editor::Editor(LocalFrame& frame) | 763 Editor::Editor(LocalFrame& frame) |
| 764 : m_frame(&frame) | 764 : m_frame(&frame) |
| 765 , m_preventRevealSelection(0) | 765 , m_preventRevealSelection(0) |
| 766 , m_shouldStartNewKillRingSequence(false) | 766 , m_shouldStartNewKillRingSequence(false) |
| 767 // This is off by default, since most editors want this behavior (this match
es IE but not FF). | 767 // This is off by default, since most editors want this behavior (this match
es IE but not FF). |
| 768 , m_shouldStyleWithCSS(false) | 768 , m_shouldStyleWithCSS(false) |
| 769 , m_killRing(adoptPtr(new KillRing)) | 769 , m_killRing(adoptPtr(new KillRing)) |
| 770 , m_areMarkedTextMatchesHighlighted(false) | 770 , m_areMarkedTextMatchesHighlighted(false) |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 Element* focusedElement = frame().document()->focusedElement(); | 1025 Element* focusedElement = frame().document()->focusedElement(); |
| 1026 if (isHTMLTextFormControlElement(focusedElement)) { | 1026 if (isHTMLTextFormControlElement(focusedElement)) { |
| 1027 if (direction == NaturalWritingDirection) | 1027 if (direction == NaturalWritingDirection) |
| 1028 return; | 1028 return; |
| 1029 focusedElement->setAttribute(dirAttr, direction == LeftToRightWritingDir
ection ? "ltr" : "rtl"); | 1029 focusedElement->setAttribute(dirAttr, direction == LeftToRightWritingDir
ection ? "ltr" : "rtl"); |
| 1030 focusedElement->dispatchInputEvent(); | 1030 focusedElement->dispatchInputEvent(); |
| 1031 frame().document()->updateLayoutTree(); | 1031 frame().document()->updateLayoutTree(); |
| 1032 return; | 1032 return; |
| 1033 } | 1033 } |
| 1034 | 1034 |
| 1035 RefPtrWillBeRawPtr<MutableStylePropertySet> style = MutableStylePropertySet:
:create(HTMLQuirksMode); | 1035 RawPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(HTML
QuirksMode); |
| 1036 style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDire
ction ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", fa
lse); | 1036 style->setProperty(CSSPropertyDirection, direction == LeftToRightWritingDire
ction ? "ltr" : direction == RightToLeftWritingDirection ? "rtl" : "inherit", fa
lse); |
| 1037 applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection); | 1037 applyParagraphStyleToSelection(style.get(), EditActionSetWritingDirection); |
| 1038 } | 1038 } |
| 1039 | 1039 |
| 1040 void Editor::revealSelectionAfterEditingOperation(const ScrollAlignment& alignme
nt, RevealExtentOption revealExtentOption) | 1040 void Editor::revealSelectionAfterEditingOperation(const ScrollAlignment& alignme
nt, RevealExtentOption revealExtentOption) |
| 1041 { | 1041 { |
| 1042 if (m_preventRevealSelection) | 1042 if (m_preventRevealSelection) |
| 1043 return; | 1043 return; |
| 1044 | 1044 |
| 1045 frame().selection().revealSelection(alignment, revealExtentOption); | 1045 frame().selection().revealSelection(alignment, revealExtentOption); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1148 } | 1148 } |
| 1149 | 1149 |
| 1150 void Editor::computeAndSetTypingStyle(StylePropertySet* style, EditAction editin
gAction) | 1150 void Editor::computeAndSetTypingStyle(StylePropertySet* style, EditAction editin
gAction) |
| 1151 { | 1151 { |
| 1152 if (!style || style->isEmpty()) { | 1152 if (!style || style->isEmpty()) { |
| 1153 frame().selection().clearTypingStyle(); | 1153 frame().selection().clearTypingStyle(); |
| 1154 return; | 1154 return; |
| 1155 } | 1155 } |
| 1156 | 1156 |
| 1157 // Calculate the current typing style. | 1157 // Calculate the current typing style. |
| 1158 RefPtrWillBeRawPtr<EditingStyle> typingStyle = nullptr; | 1158 RawPtr<EditingStyle> typingStyle = nullptr; |
| 1159 if (frame().selection().typingStyle()) { | 1159 if (frame().selection().typingStyle()) { |
| 1160 typingStyle = frame().selection().typingStyle()->copy(); | 1160 typingStyle = frame().selection().typingStyle()->copy(); |
| 1161 typingStyle->overrideWithStyle(style); | 1161 typingStyle->overrideWithStyle(style); |
| 1162 } else { | 1162 } else { |
| 1163 typingStyle = EditingStyle::create(style); | 1163 typingStyle = EditingStyle::create(style); |
| 1164 } | 1164 } |
| 1165 | 1165 |
| 1166 typingStyle->prepareToApplyAt(frame().selection().selection().visibleStart()
.deepEquivalent(), EditingStyle::PreserveWritingDirection); | 1166 typingStyle->prepareToApplyAt(frame().selection().selection().visibleStart()
.deepEquivalent(), EditingStyle::PreserveWritingDirection); |
| 1167 | 1167 |
| 1168 // Handle block styles, substracting these from the typing style. | 1168 // Handle block styles, substracting these from the typing style. |
| 1169 RefPtrWillBeRawPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveB
lockProperties(); | 1169 RawPtr<EditingStyle> blockStyle = typingStyle->extractAndRemoveBlockProperti
es(); |
| 1170 if (!blockStyle->isEmpty()) { | 1170 if (!blockStyle->isEmpty()) { |
| 1171 ASSERT(frame().document()); | 1171 ASSERT(frame().document()); |
| 1172 ApplyStyleCommand::create(*frame().document(), blockStyle.get(), editing
Action)->apply(); | 1172 ApplyStyleCommand::create(*frame().document(), blockStyle.get(), editing
Action)->apply(); |
| 1173 } | 1173 } |
| 1174 | 1174 |
| 1175 // Set the remaining style as the typing style. | 1175 // Set the remaining style as the typing style. |
| 1176 frame().selection().setTypingStyle(typingStyle); | 1176 frame().selection().setTypingStyle(typingStyle); |
| 1177 } | 1177 } |
| 1178 | 1178 |
| 1179 bool Editor::findString(const String& target, FindOptions options) | 1179 bool Editor::findString(const String& target, FindOptions options) |
| 1180 { | 1180 { |
| 1181 VisibleSelection selection = frame().selection().selection(); | 1181 VisibleSelection selection = frame().selection().selection(); |
| 1182 | 1182 |
| 1183 // TODO(yosin) We should make |findRangeOfString()| to return | 1183 // TODO(yosin) We should make |findRangeOfString()| to return |
| 1184 // |EphemeralRange| rather than|Range| object. | 1184 // |EphemeralRange| rather than|Range| object. |
| 1185 RefPtrWillBeRawPtr<Range> resultRange = findRangeOfString(target, EphemeralR
ange(selection.start(), selection.end()), static_cast<FindOptions>(options | Fin
dAPICall)); | 1185 RawPtr<Range> resultRange = findRangeOfString(target, EphemeralRange(selecti
on.start(), selection.end()), static_cast<FindOptions>(options | FindAPICall)); |
| 1186 | 1186 |
| 1187 if (!resultRange) | 1187 if (!resultRange) |
| 1188 return false; | 1188 return false; |
| 1189 | 1189 |
| 1190 frame().selection().setSelection(VisibleSelection(EphemeralRange(resultRange
.get()))); | 1190 frame().selection().setSelection(VisibleSelection(EphemeralRange(resultRange
.get()))); |
| 1191 frame().selection().revealSelection(); | 1191 frame().selection().revealSelection(); |
| 1192 return true; | 1192 return true; |
| 1193 } | 1193 } |
| 1194 | 1194 |
| 1195 PassRefPtrWillBeRawPtr<Range> Editor::findStringAndScrollToVisible(const String&
target, Range* previousMatch, FindOptions options) | 1195 RawPtr<Range> Editor::findStringAndScrollToVisible(const String& target, Range*
previousMatch, FindOptions options) |
| 1196 { | 1196 { |
| 1197 RefPtrWillBeRawPtr<Range> nextMatch = findRangeOfString(target, EphemeralRan
geInFlatTree(previousMatch), options); | 1197 RawPtr<Range> nextMatch = findRangeOfString(target, EphemeralRangeInFlatTree
(previousMatch), options); |
| 1198 if (!nextMatch) | 1198 if (!nextMatch) |
| 1199 return nullptr; | 1199 return nullptr; |
| 1200 | 1200 |
| 1201 Node* firstNode = nextMatch->firstNode(); | 1201 Node* firstNode = nextMatch->firstNode(); |
| 1202 firstNode->layoutObject()->scrollRectToVisible(LayoutRect(nextMatch->boundin
gBox()), | 1202 firstNode->layoutObject()->scrollRectToVisible(LayoutRect(nextMatch->boundin
gBox()), |
| 1203 ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeed
ed, UserScroll); | 1203 ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeed
ed, UserScroll); |
| 1204 firstNode->document().setSequentialFocusNavigationStartingPoint(firstNode); | 1204 firstNode->document().setSequentialFocusNavigationStartingPoint(firstNode); |
| 1205 | 1205 |
| 1206 return nextMatch.release(); | 1206 return nextMatch.release(); |
| 1207 } | 1207 } |
| 1208 | 1208 |
| 1209 // TODO(yosin) We should return |EphemeralRange| rather than |Range|. We use | 1209 // TODO(yosin) We should return |EphemeralRange| rather than |Range|. We use |
| 1210 // |Range| object for checking whether start and end position crossing shadow | 1210 // |Range| object for checking whether start and end position crossing shadow |
| 1211 // boundaries, however we can do it without |Range| object. | 1211 // boundaries, however we can do it without |Range| object. |
| 1212 template <typename Strategy> | 1212 template <typename Strategy> |
| 1213 static PassRefPtrWillBeRawPtr<Range> findStringBetweenPositions(const String& ta
rget, const EphemeralRangeTemplate<Strategy>& referenceRange, FindOptions option
s) | 1213 static RawPtr<Range> findStringBetweenPositions(const String& target, const Ephe
meralRangeTemplate<Strategy>& referenceRange, FindOptions options) |
| 1214 { | 1214 { |
| 1215 EphemeralRangeTemplate<Strategy> searchRange(referenceRange); | 1215 EphemeralRangeTemplate<Strategy> searchRange(referenceRange); |
| 1216 | 1216 |
| 1217 bool forward = !(options & Backwards); | 1217 bool forward = !(options & Backwards); |
| 1218 | 1218 |
| 1219 while (true) { | 1219 while (true) { |
| 1220 EphemeralRangeTemplate<Strategy> resultRange = findPlainText(searchRange
, target, options); | 1220 EphemeralRangeTemplate<Strategy> resultRange = findPlainText(searchRange
, target, options); |
| 1221 if (resultRange.isCollapsed()) | 1221 if (resultRange.isCollapsed()) |
| 1222 return nullptr; | 1222 return nullptr; |
| 1223 | 1223 |
| 1224 RefPtrWillBeRawPtr<Range> rangeObject = Range::create(resultRange.docume
nt(), toPositionInDOMTree(resultRange.startPosition()), toPositionInDOMTree(resu
ltRange.endPosition())); | 1224 RawPtr<Range> rangeObject = Range::create(resultRange.document(), toPosi
tionInDOMTree(resultRange.startPosition()), toPositionInDOMTree(resultRange.endP
osition())); |
| 1225 if (!rangeObject->collapsed()) | 1225 if (!rangeObject->collapsed()) |
| 1226 return rangeObject.release(); | 1226 return rangeObject.release(); |
| 1227 | 1227 |
| 1228 // Found text spans over multiple TreeScopes. Since it's impossible to | 1228 // Found text spans over multiple TreeScopes. Since it's impossible to |
| 1229 // return such section as a Range, we skip this match and seek for the | 1229 // return such section as a Range, we skip this match and seek for the |
| 1230 // next occurrence. | 1230 // next occurrence. |
| 1231 // TODO(yosin) Handle this case. | 1231 // TODO(yosin) Handle this case. |
| 1232 if (forward) { | 1232 if (forward) { |
| 1233 // TODO(yosin) We should use |PositionMoveType::Character| | 1233 // TODO(yosin) We should use |PositionMoveType::Character| |
| 1234 // for |nextPositionOf()|. | 1234 // for |nextPositionOf()|. |
| 1235 searchRange = EphemeralRangeTemplate<Strategy>(nextPositionOf(result
Range.startPosition(), PositionMoveType::CodePoint), searchRange.endPosition()); | 1235 searchRange = EphemeralRangeTemplate<Strategy>(nextPositionOf(result
Range.startPosition(), PositionMoveType::CodePoint), searchRange.endPosition()); |
| 1236 } else { | 1236 } else { |
| 1237 // TODO(yosin) We should use |PositionMoveType::Character| | 1237 // TODO(yosin) We should use |PositionMoveType::Character| |
| 1238 // for |previousPositionOf()|. | 1238 // for |previousPositionOf()|. |
| 1239 searchRange = EphemeralRangeTemplate<Strategy>(searchRange.startPosi
tion(), previousPositionOf(resultRange.endPosition(), PositionMoveType::CodePoin
t)); | 1239 searchRange = EphemeralRangeTemplate<Strategy>(searchRange.startPosi
tion(), previousPositionOf(resultRange.endPosition(), PositionMoveType::CodePoin
t)); |
| 1240 } | 1240 } |
| 1241 } | 1241 } |
| 1242 | 1242 |
| 1243 ASSERT_NOT_REACHED(); | 1243 ASSERT_NOT_REACHED(); |
| 1244 return nullptr; | 1244 return nullptr; |
| 1245 } | 1245 } |
| 1246 | 1246 |
| 1247 template <typename Strategy> | 1247 template <typename Strategy> |
| 1248 static PassRefPtrWillBeRawPtr<Range> findRangeOfStringAlgorithm(Document& docume
nt, const String& target, const EphemeralRangeTemplate<Strategy>& referenceRange
, FindOptions options) | 1248 static RawPtr<Range> findRangeOfStringAlgorithm(Document& document, const String
& target, const EphemeralRangeTemplate<Strategy>& referenceRange, FindOptions op
tions) |
| 1249 { | 1249 { |
| 1250 if (target.isEmpty()) | 1250 if (target.isEmpty()) |
| 1251 return nullptr; | 1251 return nullptr; |
| 1252 | 1252 |
| 1253 // Start from an edge of the reference range. Which edge is used depends on | 1253 // Start from an edge of the reference range. Which edge is used depends on |
| 1254 // whether we're searching forward or backward, and whether startInSelection | 1254 // whether we're searching forward or backward, and whether startInSelection |
| 1255 // is set. | 1255 // is set. |
| 1256 EphemeralRangeTemplate<Strategy> documentRange = EphemeralRangeTemplate<Stra
tegy>::rangeOfContents(document); | 1256 EphemeralRangeTemplate<Strategy> documentRange = EphemeralRangeTemplate<Stra
tegy>::rangeOfContents(document); |
| 1257 EphemeralRangeTemplate<Strategy> searchRange(documentRange); | 1257 EphemeralRangeTemplate<Strategy> searchRange(documentRange); |
| 1258 | 1258 |
| 1259 bool forward = !(options & Backwards); | 1259 bool forward = !(options & Backwards); |
| 1260 bool startInReferenceRange = false; | 1260 bool startInReferenceRange = false; |
| 1261 if (referenceRange.isNotNull()) { | 1261 if (referenceRange.isNotNull()) { |
| 1262 startInReferenceRange = options & StartInSelection; | 1262 startInReferenceRange = options & StartInSelection; |
| 1263 if (forward && startInReferenceRange) | 1263 if (forward && startInReferenceRange) |
| 1264 searchRange = EphemeralRangeTemplate<Strategy>(referenceRange.startP
osition(), documentRange.endPosition()); | 1264 searchRange = EphemeralRangeTemplate<Strategy>(referenceRange.startP
osition(), documentRange.endPosition()); |
| 1265 else if (forward) | 1265 else if (forward) |
| 1266 searchRange = EphemeralRangeTemplate<Strategy>(referenceRange.endPos
ition(), documentRange.endPosition()); | 1266 searchRange = EphemeralRangeTemplate<Strategy>(referenceRange.endPos
ition(), documentRange.endPosition()); |
| 1267 else if (startInReferenceRange) | 1267 else if (startInReferenceRange) |
| 1268 searchRange = EphemeralRangeTemplate<Strategy>(documentRange.startPo
sition(), referenceRange.endPosition()); | 1268 searchRange = EphemeralRangeTemplate<Strategy>(documentRange.startPo
sition(), referenceRange.endPosition()); |
| 1269 else | 1269 else |
| 1270 searchRange = EphemeralRangeTemplate<Strategy>(documentRange.startPo
sition(), referenceRange.startPosition()); | 1270 searchRange = EphemeralRangeTemplate<Strategy>(documentRange.startPo
sition(), referenceRange.startPosition()); |
| 1271 } | 1271 } |
| 1272 | 1272 |
| 1273 RefPtrWillBeRawPtr<Range> resultRange = findStringBetweenPositions(target, s
earchRange, options); | 1273 RawPtr<Range> resultRange = findStringBetweenPositions(target, searchRange,
options); |
| 1274 | 1274 |
| 1275 // If we started in the reference range and the found range exactly matches | 1275 // If we started in the reference range and the found range exactly matches |
| 1276 // the reference range, find again. Build a selection with the found range | 1276 // the reference range, find again. Build a selection with the found range |
| 1277 // to remove collapsed whitespace. Compare ranges instead of selection | 1277 // to remove collapsed whitespace. Compare ranges instead of selection |
| 1278 // objects to ignore the way that the current selection was made. | 1278 // objects to ignore the way that the current selection was made. |
| 1279 if (resultRange && startInReferenceRange && normalizeRange(EphemeralRangeTem
plate<Strategy>(resultRange.get())) == referenceRange) { | 1279 if (resultRange && startInReferenceRange && normalizeRange(EphemeralRangeTem
plate<Strategy>(resultRange.get())) == referenceRange) { |
| 1280 if (forward) | 1280 if (forward) |
| 1281 searchRange = EphemeralRangeTemplate<Strategy>(fromPositionInDOMTree
<Strategy>(resultRange->endPosition()), searchRange.endPosition()); | 1281 searchRange = EphemeralRangeTemplate<Strategy>(fromPositionInDOMTree
<Strategy>(resultRange->endPosition()), searchRange.endPosition()); |
| 1282 else | 1282 else |
| 1283 searchRange = EphemeralRangeTemplate<Strategy>(searchRange.startPosi
tion(), fromPositionInDOMTree<Strategy>(resultRange->startPosition())); | 1283 searchRange = EphemeralRangeTemplate<Strategy>(searchRange.startPosi
tion(), fromPositionInDOMTree<Strategy>(resultRange->startPosition())); |
| 1284 resultRange = findStringBetweenPositions(target, searchRange, options); | 1284 resultRange = findStringBetweenPositions(target, searchRange, options); |
| 1285 } | 1285 } |
| 1286 | 1286 |
| 1287 if (!resultRange && options & WrapAround) | 1287 if (!resultRange && options & WrapAround) |
| 1288 return findStringBetweenPositions(target, documentRange, options); | 1288 return findStringBetweenPositions(target, documentRange, options); |
| 1289 | 1289 |
| 1290 return resultRange.release(); | 1290 return resultRange.release(); |
| 1291 } | 1291 } |
| 1292 | 1292 |
| 1293 PassRefPtrWillBeRawPtr<Range> Editor::findRangeOfString(const String& target, co
nst EphemeralRange& reference, FindOptions options) | 1293 RawPtr<Range> Editor::findRangeOfString(const String& target, const EphemeralRan
ge& reference, FindOptions options) |
| 1294 { | 1294 { |
| 1295 return findRangeOfStringAlgorithm<EditingStrategy>(*frame().document(), targ
et, reference, options); | 1295 return findRangeOfStringAlgorithm<EditingStrategy>(*frame().document(), targ
et, reference, options); |
| 1296 } | 1296 } |
| 1297 | 1297 |
| 1298 PassRefPtrWillBeRawPtr<Range> Editor::findRangeOfString(const String& target, co
nst EphemeralRangeInFlatTree& reference, FindOptions options) | 1298 RawPtr<Range> Editor::findRangeOfString(const String& target, const EphemeralRan
geInFlatTree& reference, FindOptions options) |
| 1299 { | 1299 { |
| 1300 return findRangeOfStringAlgorithm<EditingInFlatTreeStrategy>(*frame().docume
nt(), target, reference, options); | 1300 return findRangeOfStringAlgorithm<EditingInFlatTreeStrategy>(*frame().docume
nt(), target, reference, options); |
| 1301 } | 1301 } |
| 1302 | 1302 |
| 1303 void Editor::setMarkedTextMatchesAreHighlighted(bool flag) | 1303 void Editor::setMarkedTextMatchesAreHighlighted(bool flag) |
| 1304 { | 1304 { |
| 1305 if (flag == m_areMarkedTextMatchesHighlighted) | 1305 if (flag == m_areMarkedTextMatchesHighlighted) |
| 1306 return; | 1306 return; |
| 1307 | 1307 |
| 1308 m_areMarkedTextMatchesHighlighted = flag; | 1308 m_areMarkedTextMatchesHighlighted = flag; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1327 frame().selection().setShouldShowBlockCursor(m_overwriteModeEnabled); | 1327 frame().selection().setShouldShowBlockCursor(m_overwriteModeEnabled); |
| 1328 } | 1328 } |
| 1329 | 1329 |
| 1330 void Editor::tidyUpHTMLStructure(Document& document) | 1330 void Editor::tidyUpHTMLStructure(Document& document) |
| 1331 { | 1331 { |
| 1332 // hasEditableStyle() needs up-to-date ComputedStyle. | 1332 // hasEditableStyle() needs up-to-date ComputedStyle. |
| 1333 document.updateLayoutTree(); | 1333 document.updateLayoutTree(); |
| 1334 bool needsValidStructure = document.hasEditableStyle() || (document.document
Element() && document.documentElement()->hasEditableStyle()); | 1334 bool needsValidStructure = document.hasEditableStyle() || (document.document
Element() && document.documentElement()->hasEditableStyle()); |
| 1335 if (!needsValidStructure) | 1335 if (!needsValidStructure) |
| 1336 return; | 1336 return; |
| 1337 RefPtrWillBeRawPtr<Element> existingHead = nullptr; | 1337 RawPtr<Element> existingHead = nullptr; |
| 1338 RefPtrWillBeRawPtr<Element> existingBody = nullptr; | 1338 RawPtr<Element> existingBody = nullptr; |
| 1339 Element* currentRoot = document.documentElement(); | 1339 Element* currentRoot = document.documentElement(); |
| 1340 if (currentRoot) { | 1340 if (currentRoot) { |
| 1341 if (isHTMLHtmlElement(currentRoot)) | 1341 if (isHTMLHtmlElement(currentRoot)) |
| 1342 return; | 1342 return; |
| 1343 if (isHTMLHeadElement(currentRoot)) | 1343 if (isHTMLHeadElement(currentRoot)) |
| 1344 existingHead = currentRoot; | 1344 existingHead = currentRoot; |
| 1345 else if (isHTMLBodyElement(currentRoot)) | 1345 else if (isHTMLBodyElement(currentRoot)) |
| 1346 existingBody = currentRoot; | 1346 existingBody = currentRoot; |
| 1347 else if (isHTMLFrameSetElement(currentRoot)) | 1347 else if (isHTMLFrameSetElement(currentRoot)) |
| 1348 existingBody = currentRoot; | 1348 existingBody = currentRoot; |
| 1349 } | 1349 } |
| 1350 // We ensure only "the root is <html>." | 1350 // We ensure only "the root is <html>." |
| 1351 // documentElement as rootEditableElement is problematic. So we move | 1351 // documentElement as rootEditableElement is problematic. So we move |
| 1352 // non-<html> root elements under <body>, and the <body> works as | 1352 // non-<html> root elements under <body>, and the <body> works as |
| 1353 // rootEditableElement. | 1353 // rootEditableElement. |
| 1354 document.addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMe
ssageLevel, "document.execCommand() doesn't work with an invalid HTML structure.
It is corrected automatically.")); | 1354 document.addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMe
ssageLevel, "document.execCommand() doesn't work with an invalid HTML structure.
It is corrected automatically.")); |
| 1355 | 1355 |
| 1356 RefPtrWillBeRawPtr<Element> root = HTMLHtmlElement::create(document); | 1356 RawPtr<Element> root = HTMLHtmlElement::create(document); |
| 1357 if (existingHead) | 1357 if (existingHead) |
| 1358 root->appendChild(existingHead.release()); | 1358 root->appendChild(existingHead.release()); |
| 1359 RefPtrWillBeRawPtr<Element> body = nullptr; | 1359 RawPtr<Element> body = nullptr; |
| 1360 if (existingBody) | 1360 if (existingBody) |
| 1361 body = existingBody.release(); | 1361 body = existingBody.release(); |
| 1362 else | 1362 else |
| 1363 body = HTMLBodyElement::create(document); | 1363 body = HTMLBodyElement::create(document); |
| 1364 if (document.documentElement() && body != document.documentElement()) | 1364 if (document.documentElement() && body != document.documentElement()) |
| 1365 body->appendChild(document.documentElement()); | 1365 body->appendChild(document.documentElement()); |
| 1366 root->appendChild(body.release()); | 1366 root->appendChild(body.release()); |
| 1367 ASSERT(!document.documentElement()); | 1367 ASSERT(!document.documentElement()); |
| 1368 document.appendChild(root.release()); | 1368 document.appendChild(root.release()); |
| 1369 | 1369 |
| 1370 // TODO(tkent): Should we check and move Text node children of <html>? | 1370 // TODO(tkent): Should we check and move Text node children of <html>? |
| 1371 } | 1371 } |
| 1372 | 1372 |
| 1373 DEFINE_TRACE(Editor) | 1373 DEFINE_TRACE(Editor) |
| 1374 { | 1374 { |
| 1375 visitor->trace(m_frame); | 1375 visitor->trace(m_frame); |
| 1376 visitor->trace(m_lastEditCommand); | 1376 visitor->trace(m_lastEditCommand); |
| 1377 visitor->trace(m_mark); | 1377 visitor->trace(m_mark); |
| 1378 } | 1378 } |
| 1379 | 1379 |
| 1380 } // namespace blink | 1380 } // namespace blink |
| OLD | NEW |