bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event) { if (!isHTMLInputElement(element)) return false; WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0); if (!getActionTypeForKeyEvent(event, actionType)) return false; WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame()); ASSERT(webFrame); return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, toHTMLInputElement(element), toInputFieldAction(actionType), webFrame); }
void WebEditorClient::textDidChangeInTextField(Element* element) { if (!isHTMLInputElement(element)) return; bool initiatedByUserTyping = UserTypingGestureIndicator::processingUserTypingGesture() && UserTypingGestureIndicator::focusedElementAtGestureStart() == element; WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame()); ASSERT(webFrame); #if ENABLE(INJECT_BUNDLE) m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, toHTMLInputElement(element), webFrame, initiatedByUserTyping); #endif }
void WebEditorClient::textDidChangeInTextField(Element* element) { if (!isHTMLInputElement(element)) return; if (!UserTypingGestureIndicator::processingUserTypingGesture() || UserTypingGestureIndicator::focusedElementAtGestureStart() != element) return; WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(element->document().frame()->loader().client()); WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0; ASSERT(webFrame); m_page->injectedBundleFormClient().textDidChangeInTextField(m_page, toHTMLInputElement(element), webFrame); }
void WebChromeClient::focusedElementChanged(Element* element) { if (!element) return; if (!isHTMLInputElement(element)) return; HTMLInputElement* inputElement = toHTMLInputElement(element); if (!inputElement->isText()) return; WebFrame* webFrame = WebFrame::fromCoreFrame(*element->document().frame()); ASSERT(webFrame); m_page->injectedBundleFormClient().didFocusTextField(m_page, inputElement, webFrame); }
bool WebEditorClient::doTextFieldCommandFromEvent(Element* element, KeyboardEvent* event) { if (!isHTMLInputElement(element)) return false; WKInputFieldActionType actionType = static_cast<WKInputFieldActionType>(0); if (!getActionTypeForKeyEvent(event, actionType)) return false; WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(element->document()->frame()->loader()->client()); WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0; ASSERT(webFrame); return m_page->injectedBundleFormClient().shouldPerformActionInTextField(m_page, toHTMLInputElement(element), actionType, webFrame); }
static URL getURLForImageElement(Element& element) { // FIXME: Later this code should be shared with Chromium somehow. Chances are all platforms want it. AtomicString urlString; if (isHTMLImageElement(element) || isHTMLInputElement(element)) urlString = element.getAttribute(HTMLNames::srcAttr); #if ENABLE(SVG) else if (element.hasTagName(SVGNames::imageTag)) urlString = element.getAttribute(XLinkNames::hrefAttr); #endif else if (element.hasTagName(HTMLNames::embedTag) || isHTMLObjectElement(element)) urlString = element.imageSourceURL(); return urlString.isEmpty() ? URL() : element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); }
void WebChromeClient::focusedElementChanged(Element* element) { if (!element) return; if (!isHTMLInputElement(element)) return; HTMLInputElement* inputElement = toHTMLInputElement(element); if (!inputElement->isText()) return; WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(element->document().frame()->loader().client()); WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0; ASSERT(webFrame); m_page->injectedBundleFormClient().didFocusTextField(m_page, inputElement, webFrame); }
static KURL getURLForImageNode(Node* node) { // FIXME: Later this code should be shared with Chromium somehow. Chances are all platforms want it. AtomicString urlString; if (isHTMLImageElement(node) || isHTMLInputElement(node)) urlString = toElement(node)->getAttribute(HTMLNames::srcAttr); #if ENABLE(SVG) else if (node->hasTagName(SVGNames::imageTag)) urlString = toElement(node)->getAttribute(XLinkNames::hrefAttr); #endif else if (node->hasTagName(HTMLNames::embedTag) || node->hasTagName(HTMLNames::objectTag)) { Element* element = toElement(node); urlString = element->imageSourceURL(); } return urlString.isEmpty() ? KURL() : node->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); }
bool WebFrame::containsAnyFormControls() const { if (!m_coreFrame) return false; Document* document = m_coreFrame->document(); if (!document) return false; for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) { if (!node->isElementNode()) continue; if (isHTMLInputElement(node) || isHTMLSelectElement(node) || isHTMLTextAreaElement(node)) return true; } return false; }
void findPasswordFormFields(HTMLFormElement* form, PasswordFormFields* fields) { ASSERT(form); ASSERT(fields); HTMLInputElement* latestInputElement = 0; const Vector<FormAssociatedElement*>& formElements = form->associatedElements(); for (size_t i = 0; i < formElements.size(); i++) { if (!formElements[i]->isFormControlElement()) continue; HTMLFormControlElement* control = toHTMLFormControlElement(formElements[i]); if (control->isActivatedSubmit()) fields->submit = control; if (!isHTMLInputElement(*control)) continue; HTMLInputElement& inputElement = toHTMLInputElement(*control); if (inputElement.isDisabledFormControl()) continue; if ((fields->passwords.size() < maxPasswords) && inputElement.isPasswordField()) { // We assume that the username is the input element before the // first password element. if (fields->passwords.isEmpty() && latestInputElement) { fields->userName = latestInputElement; // Remove the selected username from alternateUserNames. if (!fields->alternateUserNames.isEmpty() && !latestInputElement->value().isEmpty()) fields->alternateUserNames.removeLast(); } fields->passwords.append(&inputElement); } // Various input types such as text, url, email can be a username field. if (inputElement.isTextField() && !inputElement.isPasswordField()) { latestInputElement = &inputElement; // We ignore elements that have no value. Unlike userName, alternateUserNames // is used only for autofill, not for form identification, and blank autofill // entries are not useful. if (!inputElement.value().isEmpty()) fields->alternateUserNames.append(inputElement.value()); } } }
static bool isSpellCheckingEnabledFor(const Position& position) { if (position.isNull()) return false; // TODO(tkent): The following password type check should be done in // HTMLElement::spellcheck(). crbug.com/371567 if (HTMLTextFormControlElement* textControl = enclosingTextFormControl(position)) { if (isHTMLInputElement(textControl) && toHTMLInputElement(textControl)->type() == InputTypeNames::password) return false; } if (HTMLElement* element = Traversal<HTMLElement>::firstAncestorOrSelf(*position.anchorNode())) { if (element->isSpellCheckingEnabled()) return true; } return false; }
TextDirection HTMLElement::directionality(Node** strongDirectionalityTextNode) const { if (isHTMLInputElement(*this)) { HTMLInputElement* inputElement = toHTMLInputElement(const_cast<HTMLElement*>(this)); bool hasStrongDirectionality; TextDirection textDirection = determineDirectionality(inputElement->value(), &hasStrongDirectionality); if (strongDirectionalityTextNode) *strongDirectionalityTextNode = hasStrongDirectionality ? inputElement : 0; return textDirection; } Node* node = ComposedTreeTraversal::firstChild(*this); while (node) { // Skip bdi, script, style and text form controls. if (equalIgnoringCase(node->nodeName(), "bdi") || isHTMLScriptElement(*node) || isHTMLStyleElement(*node) || (node->isElementNode() && toElement(node)->isTextFormControl())) { node = ComposedTreeTraversal::nextSkippingChildren(*node, this); continue; } // Skip elements with valid dir attribute if (node->isElementNode()) { AtomicString dirAttributeValue = toElement(node)->fastGetAttribute(dirAttr); if (isValidDirAttribute(dirAttributeValue)) { node = ComposedTreeTraversal::nextSkippingChildren(*node, this); continue; } } if (node->isTextNode()) { bool hasStrongDirectionality; TextDirection textDirection = determineDirectionality(node->textContent(true), &hasStrongDirectionality); if (hasStrongDirectionality) { if (strongDirectionalityTextNode) *strongDirectionalityTextNode = node; return textDirection; } } node = ComposedTreeTraversal::next(*node, this); } if (strongDirectionalityTextNode) *strongDirectionalityTextNode = 0; return LTR; }
AtomicString getInputModeAttribute(Element* element) { if (!element) return AtomicString(); bool queryAttribute = false; if (isHTMLInputElement(*element)) { queryAttribute = toHTMLInputElement(*element).supportsInputModeAttribute(); } else if (isHTMLTextAreaElement(*element)) { queryAttribute = true; } else { element->document().updateStyleAndLayoutTree(); if (hasEditableStyle(*element)) queryAttribute = true; } if (!queryAttribute) return AtomicString(); // TODO(dtapuska): We may wish to restrict this to a yet to be proposed // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016. return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); }
static bool allowsAuthorShadowRoot(Element* element) { #if ENABLE(SHADOW_DOM) if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled()) return true; #endif // FIXME: The elements in Shadow DOM of an input element assumes that they have renderer if the input // element has a renderer. However, this does not hold until input elemnet is AuthorShadowDOM-ready. // So we would like to prohibit having a AuthorShadowDOM for a while. The same thing happens to // textarea element also. // https://bugs.webkit.org/show_bug.cgi?id=92608 if (isHTMLInputElement(element)) return false; // FIXME: We disable multiple shadow subtrees for SVG for while, because there will be problems to support it. // https://bugs.webkit.org/show_bug.cgi?id=78205 // Especially SVG TREF recreates shadow root dynamically. // https://bugs.webkit.org/show_bug.cgi?id=77938 if (element->isSVGElement()) return false; return true; }
void WebFormControlElement::setAutofillValue(const WebString& value) { // The input and change events will be sent in setValue. if (isHTMLInputElement(*m_private) || isHTMLTextAreaElement(*m_private)) { if (!focused()) unwrap<Element>()->dispatchFocusEvent(nullptr, WebFocusTypeForward, nullptr); unwrap<Element>()->dispatchScopedEvent( Event::createBubble(EventTypeNames::keydown)); unwrap<TextControlElement>()->setValue(value, DispatchInputAndChangeEvent); unwrap<Element>()->dispatchScopedEvent( Event::createBubble(EventTypeNames::keyup)); if (!focused()) unwrap<Element>()->dispatchBlurEvent(nullptr, WebFocusTypeForward, nullptr); } else if (isHTMLSelectElement(*m_private)) { if (!focused()) unwrap<Element>()->dispatchFocusEvent(nullptr, WebFocusTypeForward, nullptr); unwrap<HTMLSelectElement>()->setValue(value, true); if (!focused()) unwrap<Element>()->dispatchBlurEvent(nullptr, WebFocusTypeForward, nullptr); } }
bool LayoutTheme::isChecked(const LayoutObject& o) { if (!isHTMLInputElement(o.node())) return false; return toHTMLInputElement(o.node())->shouldAppearChecked(); }
void WebFormControlElement::setSelectionRange(int start, int end) { if (isHTMLInputElement(*m_private)) unwrap<HTMLInputElement>()->setSelectionRange(start, end); else if (isHTMLTextAreaElement(*m_private)) unwrap<HTMLTextAreaElement>()->setSelectionRange(start, end); }
bool LayoutTheme::isIndeterminate(const LayoutObject& o) { if (!isHTMLInputElement(o.node())) return false; return toHTMLInputElement(o.node())->shouldAppearIndeterminate(); }
void ContextMenuClientImpl::showContextMenu(const WebCore::ContextMenu* defaultMenu) { // Displaying the context menu in this function is a big hack as we don't // have context, i.e. whether this is being invoked via a script or in // response to user input (Mouse event WM_RBUTTONDOWN, // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked // in response to the above input events before popping up the context menu. if (!m_webView->contextMenuAllowed()) return; HitTestResult r = m_webView->page()->contextMenuController().hitTestResult(); LocalFrame* selectedFrame = r.innerNodeFrame(); WebContextMenuData data; IntPoint mousePoint = selectedFrame->view()->contentsToWindow(r.roundedPointInInnerNodeFrame()); // FIXME(bokan): crbug.com/371902 - We shouldn't be making these scale // related coordinate transformatios in an ad hoc way. PinchViewport& pinchViewport = selectedFrame->host()->pinchViewport(); mousePoint -= flooredIntSize(pinchViewport.visibleRect().location()); mousePoint.scale(m_webView->pageScaleFactor(), m_webView->pageScaleFactor()); data.mousePosition = mousePoint; // Compute edit flags. data.editFlags = WebContextMenuData::CanDoNone; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canUndo()) data.editFlags |= WebContextMenuData::CanUndo; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canRedo()) data.editFlags |= WebContextMenuData::CanRedo; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canCut()) data.editFlags |= WebContextMenuData::CanCut; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canCopy()) data.editFlags |= WebContextMenuData::CanCopy; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canPaste()) data.editFlags |= WebContextMenuData::CanPaste; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canDelete()) data.editFlags |= WebContextMenuData::CanDelete; // We can always select all... data.editFlags |= WebContextMenuData::CanSelectAll; data.editFlags |= WebContextMenuData::CanTranslate; // Links, Images, Media tags, and Image/Media-Links take preference over // all else. data.linkURL = r.absoluteLinkURL(); if (isHTMLCanvasElement(r.innerNonSharedNode())) { data.mediaType = WebContextMenuData::MediaTypeCanvas; } else if (!r.absoluteImageURL().isEmpty()) { data.srcURL = r.absoluteImageURL(); data.mediaType = WebContextMenuData::MediaTypeImage; data.mediaFlags |= WebContextMenuData::MediaCanPrint; } else if (!r.absoluteMediaURL().isEmpty()) { data.srcURL = r.absoluteMediaURL(); // We know that if absoluteMediaURL() is not empty, then this // is a media element. HTMLMediaElement* mediaElement = toHTMLMediaElement(r.innerNonSharedNode()); if (isHTMLVideoElement(*mediaElement)) data.mediaType = WebContextMenuData::MediaTypeVideo; else if (isHTMLAudioElement(*mediaElement)) data.mediaType = WebContextMenuData::MediaTypeAudio; if (mediaElement->error()) data.mediaFlags |= WebContextMenuData::MediaInError; if (mediaElement->paused()) data.mediaFlags |= WebContextMenuData::MediaPaused; if (mediaElement->muted()) data.mediaFlags |= WebContextMenuData::MediaMuted; if (mediaElement->loop()) data.mediaFlags |= WebContextMenuData::MediaLoop; if (mediaElement->supportsSave()) data.mediaFlags |= WebContextMenuData::MediaCanSave; if (mediaElement->hasAudio()) data.mediaFlags |= WebContextMenuData::MediaHasAudio; // Media controls can be toggled only for video player. If we toggle // controls for audio then the player disappears, and there is no way to // return it back. Don't set this bit for fullscreen video, since // toggling is ignored in that case. if (mediaElement->hasVideo() && !mediaElement->isFullscreen()) data.mediaFlags |= WebContextMenuData::MediaCanToggleControls; if (mediaElement->controls()) data.mediaFlags |= WebContextMenuData::MediaControls; } else if (isHTMLObjectElement(*r.innerNonSharedNode()) || isHTMLEmbedElement(*r.innerNonSharedNode())) { RenderObject* object = r.innerNonSharedNode()->renderer(); if (object && object->isWidget()) { Widget* widget = toRenderWidget(object)->widget(); if (widget && widget->isPluginContainer()) { data.mediaType = WebContextMenuData::MediaTypePlugin; WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget); WebString text = plugin->plugin()->selectionAsText(); if (!text.isEmpty()) { data.selectedText = text; data.editFlags |= WebContextMenuData::CanCopy; } data.editFlags &= ~WebContextMenuData::CanTranslate; data.linkURL = plugin->plugin()->linkAtPosition(data.mousePosition); if (plugin->plugin()->supportsPaginatedPrint()) data.mediaFlags |= WebContextMenuData::MediaCanPrint; HTMLPlugInElement* pluginElement = toHTMLPlugInElement(r.innerNonSharedNode()); data.srcURL = pluginElement->document().completeURL(pluginElement->url()); data.mediaFlags |= WebContextMenuData::MediaCanSave; // Add context menu commands that are supported by the plugin. if (plugin->plugin()->canRotateView()) data.mediaFlags |= WebContextMenuData::MediaCanRotate; } } } // An image can to be null for many reasons, like being blocked, no image // data received from server yet. data.hasImageContents = (data.mediaType == WebContextMenuData::MediaTypeImage) && r.image() && !(r.image()->isNull()); // If it's not a link, an image, a media element, or an image/media link, // show a selection menu or a more generic page menu. if (selectedFrame->document()->loader()) data.frameEncoding = selectedFrame->document()->encodingName(); // Send the frame and page URLs in any case. data.pageURL = urlFromFrame(m_webView->mainFrameImpl()->frame()); if (selectedFrame != m_webView->mainFrameImpl()->frame()) { data.frameURL = urlFromFrame(selectedFrame); RefPtr<HistoryItem> historyItem = selectedFrame->loader().currentItem(); if (historyItem) data.frameHistoryItem = WebHistoryItem(historyItem); } if (r.isSelected()) { if (!isHTMLInputElement(*r.innerNonSharedNode()) || !toHTMLInputElement(r.innerNonSharedNode())->isPasswordField()) data.selectedText = selectedFrame->selectedText().stripWhiteSpace(); } if (r.isContentEditable()) { data.isEditable = true; // When Chrome enables asynchronous spellchecking, its spellchecker adds spelling markers to misspelled // words and attaches suggestions to these markers in the background. Therefore, when a user right-clicks // a mouse on a word, Chrome just needs to find a spelling marker on the word instead of spellchecking it. if (selectedFrame->settings() && selectedFrame->settings()->asynchronousSpellCheckingEnabled()) { DocumentMarker marker; data.misspelledWord = selectMisspellingAsync(selectedFrame, marker); data.misspellingHash = marker.hash(); if (marker.description().length()) { Vector<String> suggestions; marker.description().split('\n', suggestions); data.dictionarySuggestions = suggestions; } else if (m_webView->spellCheckClient()) { int misspelledOffset, misspelledLength; m_webView->spellCheckClient()->spellCheck(data.misspelledWord, misspelledOffset, misspelledLength, &data.dictionarySuggestions); } } else { data.isSpellCheckingEnabled = toLocalFrame(m_webView->focusedWebCoreFrame())->spellChecker().isContinuousSpellCheckingEnabled(); // Spellchecking might be enabled for the field, but could be disabled on the node. if (toLocalFrame(m_webView->focusedWebCoreFrame())->spellChecker().isSpellCheckingEnabledInFocusedNode()) { data.misspelledWord = selectMisspelledWord(selectedFrame); if (m_webView->spellCheckClient()) { int misspelledOffset, misspelledLength; m_webView->spellCheckClient()->spellCheck( data.misspelledWord, misspelledOffset, misspelledLength, &data.dictionarySuggestions); if (!misspelledLength) data.misspelledWord.reset(); } } } HTMLFormElement* form = selectedFrame->selection().currentForm(); if (form && isHTMLInputElement(*r.innerNonSharedNode())) { HTMLInputElement& selectedElement = toHTMLInputElement(*r.innerNonSharedNode()); WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(&selectedElement)); if (ws.url().isValid()) data.keywordURL = ws.url(); } } if (selectedFrame->editor().selectionHasStyle(CSSPropertyDirection, "ltr") != FalseTriState) data.writingDirectionLeftToRight |= WebContextMenuData::CheckableMenuItemChecked; if (selectedFrame->editor().selectionHasStyle(CSSPropertyDirection, "rtl") != FalseTriState) data.writingDirectionRightToLeft |= WebContextMenuData::CheckableMenuItemChecked; // Now retrieve the security info. DocumentLoader* dl = selectedFrame->loader().documentLoader(); WebDataSource* ds = WebDataSourceImpl::fromDocumentLoader(dl); if (ds) data.securityInfo = ds->response().securityInfo(); data.referrerPolicy = static_cast<WebReferrerPolicy>(selectedFrame->document()->referrerPolicy()); // Filter out custom menu elements and add them into the data. populateCustomMenuItems(defaultMenu, &data); // Extract suggested filename for saving file. if (isHTMLAnchorElement(r.URLElement())) { HTMLAnchorElement* anchor = toHTMLAnchorElement(r.URLElement()); data.suggestedFilename = anchor->fastGetAttribute(HTMLNames::downloadAttr); } data.node = r.innerNonSharedNode(); WebLocalFrameImpl* selectedWebFrame = WebLocalFrameImpl::fromFrame(selectedFrame); if (selectedWebFrame->client()) selectedWebFrame->client()->showContextMenu(data); }