Position HTMLTextFormControlElement::startOfSentence(const Position& position) { HTMLTextFormControlElement* textFormControl = enclosingTextFormControl(position); ASSERT(textFormControl); HTMLElement* innerEditor = textFormControl->innerEditorElement(); if (!innerEditor->childNodes()->length()) return startOfInnerText(textFormControl); const Position innerPosition = position.anchorNode() == innerEditor ? innerNodePosition(position) : position; const Position pivotPosition = previousIfPositionIsAfterLineBreak(innerPosition, innerEditor); if (pivotPosition.isNull()) return startOfInnerText(textFormControl); for (Node* node = pivotPosition.anchorNode(); node; node = NodeTraversal::previous(*node, innerEditor)) { bool isPivotNode = (node == pivotPosition.anchorNode()); if (isHTMLBRElement(node) && (!isPivotNode || pivotPosition.isAfterAnchor())) return Position(node, PositionAnchorType::AfterAnchor); if (node->isTextNode()) { Text* textNode = toText(node); size_t lastLineBreak = textNode->data().substring(0, isPivotNode ? pivotPosition.offsetInContainerNode() : textNode->length()).reverseFind('\n'); if (lastLineBreak != kNotFound) return Position(textNode, lastLineBreak + 1); } } return startOfInnerText(textFormControl); }
String Internals::visiblePlaceholder(Element* element) { HTMLTextFormControlElement* textControl = toTextFormControl(element); if (textControl && textControl->placeholderShouldBeVisible()) return textControl->placeholderElement()->textContent(); return String(); }
Position HTMLTextFormControlElement::endOfSentence(const Position& position) { HTMLTextFormControlElement* textFormControl = enclosingTextFormControl(position); ASSERT(textFormControl); HTMLElement* innerEditor = textFormControl->innerEditorElement(); if (innerEditor->childNodes()->length() == 0) return startOfInnerText(textFormControl); const Position pivotPosition = position.anchorNode() == innerEditor ? innerNodePosition(position) : position; if (pivotPosition.isNull()) return startOfInnerText(textFormControl); for (Node* node = pivotPosition.anchorNode(); node; node = NodeTraversal::next(*node, innerEditor)) { bool isPivotNode = node == pivotPosition.anchorNode(); if (isHTMLBRElement(node)) return Position(node, PositionAnchorType::AfterAnchor); if (node->isTextNode()) { Text* textNode = toText(node); size_t firstLineBreak = textNode->data().find('\n', isPivotNode ? pivotPosition.offsetInContainerNode() : 0); if (firstLineBreak != kNotFound) return Position(textNode, firstLineBreak + 1); } } return endOfInnerText(textFormControl); }
void testBoundary(Document& document, HTMLTextFormControlElement& textControl) { document.updateStyleAndLayout(); for (unsigned i = 0; i < textControl.innerEditorValue().length(); i++) { textControl.setSelectionRange(i, i); Position position = document.frame()->selection().start(); SCOPED_TRACE(::testing::Message() << "offset " << position.computeEditingOffset() << " of " << nodePositionAsStringForTesting(position.anchorNode()) .ascii() .data()); { SCOPED_TRACE("HTMLTextFormControlElement::startOfWord"); testFunctionEquivalence(position, HTMLTextFormControlElement::startOfWord, startOfWord); } { SCOPED_TRACE("HTMLTextFormControlElement::endOfWord"); testFunctionEquivalence(position, HTMLTextFormControlElement::endOfWord, endOfWord); } { SCOPED_TRACE("HTMLTextFormControlElement::startOfSentence"); testFunctionEquivalence(position, HTMLTextFormControlElement::startOfSentence, startOfSentence); } { SCOPED_TRACE("HTMLTextFormControlElement::endOfSentence"); testFunctionEquivalence( position, HTMLTextFormControlElement::endOfSentence, endOfSentence); } } }
static inline bool updateUserModifyProperty(const HTMLTextFormControlElement& element, RenderStyle* style) { bool isDisabled = element.isDisabledFormControl(); bool isReadOnlyControl = element.isReadOnly(); style->setUserModify((isReadOnlyControl || isDisabled) ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); return isDisabled; }
TextDirection HTMLElement::directionality(Node** strongDirectionalityTextNode) const { if (isHTMLTextFormControlElement(this)) { HTMLTextFormControlElement* textElement = toHTMLTextFormControlElement(const_cast<HTMLElement*>(this)); bool hasStrongDirectionality; Unicode::Direction textDirection = textElement->value().defaultWritingDirection(&hasStrongDirectionality); if (strongDirectionalityTextNode) *strongDirectionalityTextNode = hasStrongDirectionality ? textElement : 0; return (textDirection == Unicode::LeftToRight) ? LTR : RTL; } Node* node = firstChild(); while (node) { // Skip bdi, script, style and text form controls. if (equalIgnoringCase(node->nodeName(), "bdi") || node->hasTagName(scriptTag) || node->hasTagName(styleTag) || (node->isElementNode() && toElement(node)->isTextFormControl())) { node = NodeTraversal::nextSkippingChildren(node, this); continue; } // Skip elements with valid dir attribute if (node->isElementNode()) { AtomicString dirAttributeValue = toElement(node)->fastGetAttribute(dirAttr); if (equalIgnoringCase(dirAttributeValue, "rtl") || equalIgnoringCase(dirAttributeValue, "ltr") || equalIgnoringCase(dirAttributeValue, "auto")) { node = NodeTraversal::nextSkippingChildren(node, this); continue; } } if (node->isTextNode()) { bool hasStrongDirectionality; WTF::Unicode::Direction textDirection = node->textContent(true).defaultWritingDirection(&hasStrongDirectionality); if (hasStrongDirectionality) { if (strongDirectionalityTextNode) *strongDirectionalityTextNode = node; return (textDirection == WTF::Unicode::LeftToRight) ? LTR : RTL; } } node = NodeTraversal::next(node, this); } if (strongDirectionalityTextNode) *strongDirectionalityTextNode = 0; return LTR; }
static inline void updateUserModifyProperty(HTMLTextFormControlElement& node, ComputedStyle& style) { style.setUserModify(node.isDisabledOrReadOnly() ? READ_ONLY : READ_WRITE_PLAINTEXT_ONLY); }
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(); Frame* selectedFrame = r.innerNodeFrame(); WebContextMenuData data; data.mousePosition = selectedFrame->view()->contentsToWindow(r.roundedPointInInnerNodeFrame()); // Compute edit flags. data.editFlags = WebContextMenuData::CanDoNone; if (m_webView->focusedWebCoreFrame()->editor()->canUndo()) data.editFlags |= WebContextMenuData::CanUndo; if (m_webView->focusedWebCoreFrame()->editor()->canRedo()) data.editFlags |= WebContextMenuData::CanRedo; if (m_webView->focusedWebCoreFrame()->editor()->canCut()) data.editFlags |= WebContextMenuData::CanCut; if (m_webView->focusedWebCoreFrame()->editor()->canCopy()) data.editFlags |= WebContextMenuData::CanCopy; if (m_webView->focusedWebCoreFrame()->editor()->canPaste()) data.editFlags |= WebContextMenuData::CanPaste; if (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 (!r.absoluteImageURL().isEmpty()) { data.srcURL = r.absoluteImageURL(); data.mediaType = WebContextMenuData::MediaTypeImage; } 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 = toMediaElement(r.innerNonSharedNode()); if (mediaElement->hasTagName(HTMLNames::videoTag)) data.mediaType = WebContextMenuData::MediaTypeVideo; else if (mediaElement->hasTagName(HTMLNames::audioTag)) 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; if (mediaElement->hasVideo()) data.mediaFlags |= WebContextMenuData::MediaHasVideo; if (mediaElement->controls()) data.mediaFlags |= WebContextMenuData::MediaControls; } else if (r.innerNonSharedNode()->hasTagName(HTMLNames::objectTag) || r.innerNonSharedNode()->hasTagName(HTMLNames::embedTag)) { RenderObject* object = r.innerNonSharedNode()->renderer(); if (object && object->isWidget()) { Widget* widget = toRenderWidget(object)->widget(); if (widget && widget->isPluginContainer()) { data.mediaType = WebContextMenuData::MediaTypePlugin; WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(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; HTMLPlugInImageElement* pluginElement = toHTMLPlugInImageElement(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; } } } data.isImageBlocked = (data.mediaType == WebContextMenuData::MediaTypeImage) && !r.image(); // 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()->encoding(); // 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()->history()->currentItem(); if (historyItem) data.frameHistoryItem = WebHistoryItem(historyItem); } if (r.isSelected()) { if (!r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag) || !toHTMLInputElement(r.innerNonSharedNode())->isPasswordField()) data.selectedText = selectedFrame->editor()->selectedText().stripWhiteSpace(); } if (r.isContentEditable()) { data.isEditable = true; #if ENABLE(INPUT_SPEECH) if (r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag)) data.isSpeechInputEnabled = toHTMLInputElement(r.innerNonSharedNode())->isSpeechEnabled(); #endif // 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 = m_webView->focusedWebCoreFrame()->editor()->isContinuousSpellCheckingEnabled(); // Spellchecking might be enabled for the field, but could be disabled on the node. if (m_webView->focusedWebCoreFrame()->editor()->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 && r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag)) { HTMLInputElement* selectedElement = toHTMLInputElement(r.innerNonSharedNode()); if (selectedElement) { WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(selectedElement)); if (ws.url().isValid()) data.keywordURL = ws.url(); } } if (r.innerNonSharedNode()->isElementNode()) { HTMLElement* element = toHTMLElement(r.innerNonSharedNode()); if (element->isTextFormControl()) { HTMLTextFormControlElement* textElement = toHTMLTextFormControlElement(element); data.isEditFieldEmpty = textElement->value().isEmpty(); } } } #if OS(DARWIN) if (selectedFrame->editor()->selectionHasStyle(CSSPropertyDirection, "ltr") != FalseTriState) data.writingDirectionLeftToRight |= WebContextMenuData::CheckableMenuItemChecked; if (selectedFrame->editor()->selectionHasStyle(CSSPropertyDirection, "rtl") != FalseTriState) data.writingDirectionRightToLeft |= WebContextMenuData::CheckableMenuItemChecked; #endif // OS(DARWIN) // 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); data.node = r.innerNonSharedNode(); WebFrame* selected_web_frame = WebFrameImpl::fromFrame(selectedFrame); if (m_webView->client()) m_webView->client()->showContextMenu(selected_web_frame, data); }