void TypingCommand::insertText(Document* document, const String& text, const Selection& selectionForInsertion, bool selectInsertedText, bool insertedTextIsComposition) { ASSERT(document); RefPtr<Frame> frame = document->frame(); ASSERT(frame); Selection currentSelection = frame->selection()->selection(); bool changeSelection = currentSelection != selectionForInsertion; String newText = text; Node* startNode = selectionForInsertion.start().node(); if (startNode && startNode->rootEditableElement() && !insertedTextIsComposition) { // Send BeforeTextInsertedEvent. The event handler will update text if necessary. ExceptionCode ec = 0; RefPtr<BeforeTextInsertedEvent> evt = BeforeTextInsertedEvent::create(text); startNode->rootEditableElement()->dispatchEvent(evt, ec, true); newText = evt->text(); } if (newText.isEmpty()) return; // Set the starting and ending selection appropriately if we are using a selection // that is different from the current selection. In the future, we should change EditCommand // to deal with custom selections in a general way that can be used by all of the commands. RefPtr<EditCommand> lastEditCommand = frame->editor()->lastEditCommand(); if (isOpenForMoreTypingCommand(lastEditCommand.get())) { TypingCommand* lastTypingCommand = static_cast<TypingCommand*>(lastEditCommand.get()); if (changeSelection) { lastTypingCommand->setStartingSelection(selectionForInsertion); lastTypingCommand->setEndingSelection(selectionForInsertion); } lastTypingCommand->insertText(newText, selectInsertedText); if (changeSelection) { lastTypingCommand->setEndingSelection(currentSelection); frame->selection()->setSelection(currentSelection); } return; } RefPtr<TypingCommand> cmd = TypingCommand::create(document, InsertText, newText, selectInsertedText); if (changeSelection) { cmd->setStartingSelection(selectionForInsertion); cmd->setEndingSelection(selectionForInsertion); } applyCommand(cmd); if (changeSelection) { cmd->setEndingSelection(currentSelection); frame->selection()->setSelection(currentSelection); } }
void TextInsertionBaseCommand::applyTextInsertionCommand(Frame* frame, PassRefPtr<TextInsertionBaseCommand> command, const VisibleSelection& selectionForInsertion, const VisibleSelection& endingSelection) { bool changeSelection = selectionForInsertion != endingSelection; if (changeSelection) { command->setStartingSelection(selectionForInsertion); command->setEndingSelection(selectionForInsertion); } applyCommand(command); if (changeSelection) { command->setEndingSelection(endingSelection); frame->selection()->setSelection(endingSelection); } }
void TypingCommand::insertParagraphSeparator(Document *document) { ASSERT(document); Frame *frame = document->frame(); ASSERT(frame); EditCommand* lastEditCommand = frame->editor()->lastEditCommand(); if (isOpenForMoreTypingCommand(lastEditCommand)) { static_cast<TypingCommand*>(lastEditCommand)->insertParagraphSeparator(); return; } applyCommand(TypingCommand::create(document, InsertParagraphSeparator)); }
void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) { ASSERT(item->type() == ActionType || item->type() == CheckableActionType); if (item->action() >= ContextMenuItemBaseApplicationTag) { m_client->contextMenuItemSelected(item, m_contextMenu.get()); return; } if (item->action() >= ContextMenuItemBaseCustomTag) { ASSERT(m_menuProvider); m_menuProvider->contextMenuItemSelected(item); return; } HitTestResult result = m_contextMenu->hitTestResult(); Frame* frame = result.innerNonSharedNode()->document()->frame(); if (!frame) return; switch (item->action()) { case ContextMenuItemTagOpenLinkInNewWindow: openNewWindow(result.absoluteLinkURL(), frame); break; case ContextMenuItemTagDownloadLinkToDisk: // FIXME: Some day we should be able to do this from within WebCore. m_client->downloadURL(result.absoluteLinkURL()); break; case ContextMenuItemTagCopyLinkToClipboard: frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent()); break; case ContextMenuItemTagOpenImageInNewWindow: openNewWindow(result.absoluteImageURL(), frame); break; case ContextMenuItemTagDownloadImageToDisk: // FIXME: Some day we should be able to do this from within WebCore. m_client->downloadURL(result.absoluteImageURL()); break; case ContextMenuItemTagCopyImageToClipboard: // FIXME: The Pasteboard class is not written yet // For now, call into the client. This is temporary! frame->editor()->copyImage(result); break; case ContextMenuItemTagOpenMediaInNewWindow: openNewWindow(result.absoluteMediaURL(), frame); break; case ContextMenuItemTagCopyMediaLinkToClipboard: frame->editor()->copyURL(result.absoluteMediaURL(), result.textContent()); break; case ContextMenuItemTagToggleMediaControls: result.toggleMediaControlsDisplay(); break; case ContextMenuItemTagToggleMediaLoop: result.toggleMediaLoopPlayback(); break; case ContextMenuItemTagEnterVideoFullscreen: result.enterFullscreenForVideo(); break; case ContextMenuItemTagMediaPlayPause: result.toggleMediaPlayState(); break; case ContextMenuItemTagMediaMute: result.toggleMediaMuteState(); break; case ContextMenuItemTagOpenFrameInNewWindow: { DocumentLoader* loader = frame->loader()->documentLoader(); if (!loader->unreachableURL().isEmpty()) openNewWindow(loader->unreachableURL(), frame); else openNewWindow(loader->url(), frame); break; } case ContextMenuItemTagCopy: frame->editor()->copy(); break; case ContextMenuItemTagGoBack: if (Page* page = frame->page()) page->goBackOrForward(-1); break; case ContextMenuItemTagGoForward: if (Page* page = frame->page()) page->goBackOrForward(1); break; case ContextMenuItemTagStop: frame->loader()->stop(); break; case ContextMenuItemTagReload: frame->loader()->reload(); break; case ContextMenuItemTagCut: frame->editor()->cut(); break; case ContextMenuItemTagPaste: frame->editor()->paste(); break; #if PLATFORM(GTK) case ContextMenuItemTagDelete: frame->editor()->performDelete(); break; case ContextMenuItemTagSelectAll: frame->editor()->command("SelectAll").execute(); break; #endif case ContextMenuItemTagSpellingGuess: ASSERT(frame->editor()->selectedText().length()); if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) { Document* document = frame->document(); RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), true, false, true); applyCommand(command); frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } break; case ContextMenuItemTagIgnoreSpelling: frame->editor()->ignoreSpelling(); break; case ContextMenuItemTagLearnSpelling: frame->editor()->learnSpelling(); break; case ContextMenuItemTagSearchWeb: m_client->searchWithGoogle(frame); break; case ContextMenuItemTagLookUpInDictionary: // FIXME: Some day we may be able to do this from within WebCore. m_client->lookUpInDictionary(frame); break; case ContextMenuItemTagOpenLink: if (Frame* targetFrame = result.targetFrame()) targetFrame->loader()->loadFrameRequest(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, SendReferrer); else openNewWindow(result.absoluteLinkURL(), frame); break; case ContextMenuItemTagBold: frame->editor()->command("ToggleBold").execute(); break; case ContextMenuItemTagItalic: frame->editor()->command("ToggleItalic").execute(); break; case ContextMenuItemTagUnderline: frame->editor()->toggleUnderline(); break; case ContextMenuItemTagOutline: // We actually never enable this because CSS does not have a way to specify an outline font, // which may make this difficult to implement. Maybe a special case of text-shadow? break; case ContextMenuItemTagStartSpeaking: { ExceptionCode ec; RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); if (!selectedRange || selectedRange->collapsed(ec)) { Document* document = result.innerNonSharedNode()->document(); selectedRange = document->createRange(); selectedRange->selectNode(document->documentElement(), ec); } m_client->speak(plainText(selectedRange.get())); break; } case ContextMenuItemTagStopSpeaking: m_client->stopSpeaking(); break; case ContextMenuItemTagDefaultDirection: frame->editor()->setBaseWritingDirection(NaturalWritingDirection); break; case ContextMenuItemTagLeftToRight: frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); break; case ContextMenuItemTagRightToLeft: frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); break; case ContextMenuItemTagTextDirectionDefault: frame->editor()->command("MakeTextWritingDirectionNatural").execute(); break; case ContextMenuItemTagTextDirectionLeftToRight: frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); break; case ContextMenuItemTagTextDirectionRightToLeft: frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); break; #if PLATFORM(MAC) case ContextMenuItemTagSearchInSpotlight: m_client->searchWithSpotlight(); break; #endif case ContextMenuItemTagShowSpellingPanel: frame->editor()->showSpellingGuessPanel(); break; case ContextMenuItemTagCheckSpelling: frame->editor()->advanceToNextMisspelling(); break; case ContextMenuItemTagCheckSpellingWhileTyping: frame->editor()->toggleContinuousSpellChecking(); break; #ifndef BUILDING_ON_TIGER case ContextMenuItemTagCheckGrammarWithSpelling: frame->editor()->toggleGrammarChecking(); break; #endif #if PLATFORM(MAC) case ContextMenuItemTagShowFonts: frame->editor()->showFontPanel(); break; case ContextMenuItemTagStyles: frame->editor()->showStylesPanel(); break; case ContextMenuItemTagShowColors: frame->editor()->showColorPanel(); break; #endif #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) case ContextMenuItemTagMakeUpperCase: frame->editor()->uppercaseWord(); break; case ContextMenuItemTagMakeLowerCase: frame->editor()->lowercaseWord(); break; case ContextMenuItemTagCapitalize: frame->editor()->capitalizeWord(); break; case ContextMenuItemTagShowSubstitutions: frame->editor()->showSubstitutionsPanel(); break; case ContextMenuItemTagSmartCopyPaste: frame->editor()->toggleSmartInsertDelete(); break; case ContextMenuItemTagSmartQuotes: frame->editor()->toggleAutomaticQuoteSubstitution(); break; case ContextMenuItemTagSmartDashes: frame->editor()->toggleAutomaticDashSubstitution(); break; case ContextMenuItemTagSmartLinks: frame->editor()->toggleAutomaticLinkDetection(); break; case ContextMenuItemTagTextReplacement: frame->editor()->toggleAutomaticTextReplacement(); break; case ContextMenuItemTagCorrectSpellingAutomatically: frame->editor()->toggleAutomaticSpellingCorrection(); break; case ContextMenuItemTagChangeBack: frame->editor()->changeBackToReplacedString(result.replacedString()); break; #endif #if ENABLE(INSPECTOR) case ContextMenuItemTagInspectElement: if (Page* page = frame->page()) page->inspectorController()->inspect(result.innerNonSharedNode()); break; #endif default: break; } }
void DecreaseSelectionListLevelCommand::decreaseSelectionListLevel(Document* document) { ASSERT(document); ASSERT(document->frame()); applyCommand(create(*document)); }
bool DragController::concludeEditDrag(DragData* dragData) { ASSERT(dragData); RefPtr<HTMLInputElement> fileInput = m_fileInputElementUnderMouse; if (m_fileInputElementUnderMouse) { m_fileInputElementUnderMouse->setCanReceiveDroppedFiles(false); m_fileInputElementUnderMouse = 0; } if (!m_documentUnderMouse) return false; IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition()); Element* element = elementUnderMouse(m_documentUnderMouse.get(), point); if (!element) return false; Frame* innerFrame = element->ownerDocument()->frame(); ASSERT(innerFrame); if (m_page->dragCaretController()->hasCaret() && !dispatchTextInputEventFor(innerFrame, dragData)) return true; if (dragData->containsColor()) { Color color = dragData->asColor(); if (!color.isValid()) return false; RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange(); RefPtr<StylePropertySet> style = StylePropertySet::create(); style->setProperty(CSSPropertyColor, color.serialized(), false); if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get())) return false; m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); innerFrame->editor()->applyStyle(style.get(), EditActionSetColor); return true; } if (dragData->containsFiles() && fileInput) { // fileInput should be the element we hit tested for, unless it was made // display:none in a drop event handler. ASSERT(fileInput == element || !fileInput->renderer()); if (fileInput->disabled()) return false; Vector<String> filenames; dragData->asFilenames(filenames); if (filenames.isEmpty()) return false; fileInput->receiveDroppedFiles(filenames); m_client->willPerformDragDestinationAction(DragDestinationActionUpload, dragData); return true; } if (!m_page->dragController()->canProcessDrag(dragData)) { m_page->dragCaretController()->clear(); return false; } VisibleSelection dragCaret = m_page->dragCaretController()->caretPosition(); m_page->dragCaretController()->clear(); RefPtr<Range> range = dragCaret.toNormalizedRange(); RefPtr<Element> rootEditableElement = innerFrame->selection()->rootEditableElement(); // For range to be null a WebKit client must have done something bad while // manually controlling drag behaviour if (!range) return false; CachedResourceLoader* cachedResourceLoader = range->ownerDocument()->cachedResourceLoader(); ResourceCacheValidationSuppressor validationSuppressor(cachedResourceLoader); if (dragIsMove(innerFrame->selection(), dragData) || dragCaret.isContentRichlyEditable()) { bool chosePlainText = false; RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, innerFrame, range, true, chosePlainText); if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { return false; } m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); if (dragIsMove(innerFrame->selection(), dragData)) { // NSTextView behavior is to always smart delete on moving a selection, // but only to smart insert if the selection granularity is word granularity. bool smartDelete = innerFrame->editor()->smartInsertDeleteEnabled(); bool smartInsert = smartDelete && innerFrame->selection()->granularity() == WordGranularity && dragData->canSmartReplace(); applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartInsert, smartDelete)); } else { if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) { ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::PreventNesting; if (dragData->canSmartReplace()) options |= ReplaceSelectionCommand::SmartReplace; if (chosePlainText) options |= ReplaceSelectionCommand::MatchStyle; applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), fragment, options)); } } } else { String text = dragData->asPlainText(innerFrame); if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) { return false; } m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse.get(), createFragmentFromText(range.get(), text), ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting)); } if (rootEditableElement) { if (Frame* frame = rootEditableElement->document()->frame()) frame->eventHandler()->updateDragStateAfterEditDragIfNeeded(rootEditableElement.get()); } return true; }
bool DragController::concludeEditDrag(DragData* dragData) { ASSERT(dragData); ASSERT(!m_isHandlingDrag); if (!m_documentUnderMouse) return false; IntPoint point = m_documentUnderMouse->view()->windowToContents(dragData->clientPosition()); Element* element = elementUnderMouse(m_documentUnderMouse, point); Frame* innerFrame = element->ownerDocument()->frame(); ASSERT(innerFrame); if (dragData->containsColor()) { Color color = dragData->asColor(); if (!color.isValid()) return false; if (!innerFrame) return false; RefPtr<Range> innerRange = innerFrame->selection()->toNormalizedRange(); RefPtr<CSSStyleDeclaration> style = m_documentUnderMouse->createCSSStyleDeclaration(); ExceptionCode ec; style->setProperty("color", color.name(), ec); if (!innerFrame->editor()->shouldApplyStyle(style.get(), innerRange.get())) return false; m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); innerFrame->editor()->applyStyle(style.get(), EditActionSetColor); return true; } if (!m_page->dragController()->canProcessDrag(dragData)) { m_page->dragCaretController()->clear(); return false; } if (HTMLInputElement* fileInput = asFileInput(element)) { if (!fileInput->isEnabledFormControl()) return false; if (!dragData->containsFiles()) return false; Vector<String> filenames; dragData->asFilenames(filenames); if (filenames.isEmpty()) return false; // Ugly. For security none of the APIs available to us can set the input value // on file inputs. Even forcing a change in HTMLInputElement doesn't work as // RenderFileUploadControl clears the file when doing updateFromElement(). RenderFileUploadControl* renderer = toRenderFileUploadControl(fileInput->renderer()); if (!renderer) return false; renderer->receiveDroppedFiles(filenames); return true; } VisibleSelection dragCaret(m_page->dragCaretController()->selection()); m_page->dragCaretController()->clear(); RefPtr<Range> range = dragCaret.toNormalizedRange(); // For range to be null a WebKit client must have done something bad while // manually controlling drag behaviour if (!range) return false; DocLoader* loader = range->ownerDocument()->docLoader(); loader->setAllowStaleResources(true); if (dragIsMove(innerFrame->selection()) || dragCaret.isContentRichlyEditable()) { bool chosePlainText = false; RefPtr<DocumentFragment> fragment = documentFragmentFromDragData(dragData, range, true, chosePlainText); if (!fragment || !innerFrame->editor()->shouldInsertFragment(fragment, range, EditorInsertActionDropped)) { loader->setAllowStaleResources(false); return false; } m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); if (dragIsMove(innerFrame->selection())) { bool smartMove = innerFrame->selectionGranularity() == WordGranularity && innerFrame->editor()->smartInsertDeleteEnabled() && dragData->canSmartReplace(); applyCommand(MoveSelectionCommand::create(fragment, dragCaret.base(), smartMove)); } else { if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, fragment, true, dragData->canSmartReplace(), chosePlainText)); } } else { String text = dragData->asPlainText(); if (text.isEmpty() || !innerFrame->editor()->shouldInsertText(text, range.get(), EditorInsertActionDropped)) { loader->setAllowStaleResources(false); return false; } m_client->willPerformDragDestinationAction(DragDestinationActionEdit, dragData); if (setSelectionToDragCaret(innerFrame, dragCaret, range, point)) applyCommand(ReplaceSelectionCommand::create(m_documentUnderMouse, createFragmentFromText(range.get(), text), true, false, true)); } loader->setAllowStaleResources(false); return true; }