Example #1
0
bool FocusController::advanceFocusInDocumentOrder(FocusDirection direction, KeyboardEvent* event, bool initialFocus)
{
    Frame* frame = focusedOrMainFrame();
    ASSERT(frame);
    Document* document = frame->document();

    Node* currentNode = document->focusedNode();
    // FIXME: Not quite correct when it comes to focus transitions leaving/entering the WebView itself
    bool caretBrowsing = focusedOrMainFrame()->settings()->caretBrowsingEnabled();

    if (caretBrowsing && !currentNode)
        currentNode = frame->selection()->start().deprecatedNode();

    document->updateLayoutIgnorePendingStylesheets();

    RefPtr<Node> node = (direction == FocusDirectionForward)
        ? document->nextFocusableNode(currentNode, event)
        : document->previousFocusableNode(currentNode, event);
            
    // If there's no focusable node to advance to, move up the frame tree until we find one.
    while (!node && frame) {
        Frame* parentFrame = frame->tree()->parent();
        if (!parentFrame)
            break;

        Document* parentDocument = parentFrame->document();

        HTMLFrameOwnerElement* owner = frame->ownerElement();
        if (!owner)
            break;

        node = (direction == FocusDirectionForward)
            ? parentDocument->nextFocusableNode(owner, event)
            : parentDocument->previousFocusableNode(owner, event);

        frame = parentFrame;
    }

    node = deepFocusableNode(direction, node.get(), event);

    if (!node) {
        // We didn't find a node to focus, so we should try to pass focus to Chrome.
        if (!initialFocus && m_page->chrome()->canTakeFocus(direction)) {
            document->setFocusedNode(0);
            setFocusedFrame(0);
            m_page->chrome()->takeFocus(direction);
            return true;
        }

        // Chrome doesn't want focus, so we should wrap focus.
        Document* d = m_page->mainFrame()->document();
        node = (direction == FocusDirectionForward)
            ? d->nextFocusableNode(0, event)
            : d->previousFocusableNode(0, event);

        node = deepFocusableNode(direction, node.get(), event);

        if (!node)
            return false;
    }

    ASSERT(node);

    if (node == document->focusedNode())
        // Focus wrapped around to the same node.
        return true;

    if (!node->isElementNode())
        // FIXME: May need a way to focus a document here.
        return false;

    if (node->isFrameOwnerElement()) {
        // We focus frames rather than frame owners.
        // FIXME: We should not focus frames that have no scrollbars, as focusing them isn't useful to the user.
        HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(node.get());
        if (!owner->contentFrame())
            return false;

        document->setFocusedNode(0);
        setFocusedFrame(owner->contentFrame());
        return true;
    }
    
    // FIXME: It would be nice to just be able to call setFocusedNode(node) here, but we can't do
    // that because some elements (e.g. HTMLInputElement and HTMLTextAreaElement) do extra work in
    // their focus() methods.

    Document* newDocument = node->document();

    if (newDocument != document)
        // Focus is going away from this document, so clear the focused node.
        document->setFocusedNode(0);

    if (newDocument)
        setFocusedFrame(newDocument->frame());

    if (caretBrowsing) {
        Position position = firstPositionInOrBeforeNode(node.get());
        VisibleSelection newSelection(position, position, DOWNSTREAM);
        if (frame->selection()->shouldChangeSelection(newSelection))
            frame->selection()->setSelection(newSelection);
    }

    static_cast<Element*>(node.get())->focus(false);
    return true;
}
Example #2
0
void EditorClientQt::handleKeyboardEvent(KeyboardEvent* event)
{
    Frame* frame = m_page->d->page->focusController()->focusedOrMainFrame();
    if (!frame || !frame->document()->focusedNode())
        return;

    const PlatformKeyboardEvent* kevent = event->keyEvent();
    if (!kevent || kevent->type() == PlatformKeyboardEvent::KeyUp)
        return;

    Node* start = frame->selection()->start().node();
    if (!start)
        return;

    // FIXME: refactor all of this to use Actions or something like them
    if (start->isContentEditable()) {
#ifndef QT_NO_SHORTCUT
        QWebPage::WebAction action = QWebPagePrivate::editorActionForKeyEvent(kevent->qtEvent());
        if (action != QWebPage::NoWebAction) {
            const char* cmd = QWebPagePrivate::editorCommandForWebActions(action);
            // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
            // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
            // (e.g. Tab that inserts a Tab character, or Enter).
            if (cmd && frame->editor()->command(cmd).isTextInsertion()
                && kevent->type() == PlatformKeyboardEvent::RawKeyDown)
                return;

            m_page->triggerAction(action);
        } else
#endif // QT_NO_SHORTCUT
        switch (kevent->windowsVirtualKeyCode()) {
#if QT_VERSION < 0x040500
            case VK_RETURN:
#ifdef QT_WS_MAC
                if (kevent->shiftKey() || kevent->metaKey())
#else
                if (kevent->shiftKey())
#endif
                    frame->editor()->command("InsertLineBreak").execute();
                else
                    frame->editor()->command("InsertNewline").execute();
                break;
#endif
            case VK_BACK:
                frame->editor()->deleteWithDirection(SelectionController::BACKWARD,
                        CharacterGranularity, false, true);
                break;
            case VK_DELETE:
                frame->editor()->deleteWithDirection(SelectionController::FORWARD,
                        CharacterGranularity, false, true);
                break;
            case VK_LEFT:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveLeftAndModifySelection").execute();
                else frame->editor()->command("MoveLeft").execute();
                break;
            case VK_RIGHT:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveRightAndModifySelection").execute();
                else frame->editor()->command("MoveRight").execute();
                break;
            case VK_UP:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveUpAndModifySelection").execute();
                else frame->editor()->command("MoveUp").execute();
                break;
            case VK_DOWN:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveDownAndModifySelection").execute();
                else frame->editor()->command("MoveDown").execute();
                break;
            case VK_PRIOR:  // PageUp
                frame->editor()->command("MovePageUp").execute();
                break;
            case VK_NEXT:  // PageDown
                frame->editor()->command("MovePageDown").execute();
                break;
            case VK_TAB:
                return;
            default:
                if (kevent->type() != PlatformKeyboardEvent::KeyDown && !kevent->ctrlKey()
#ifndef Q_WS_MAC
                    // We need to exclude checking for Alt because it is just a different Shift
                    && !kevent->altKey()
#endif
                    && !kevent->text().isEmpty()) {
                    frame->editor()->insertText(kevent->text(), event);
                } else if (kevent->ctrlKey()) {
                    switch (kevent->windowsVirtualKeyCode()) {
                        case VK_A:
                            frame->editor()->command("SelectAll").execute();
                            break;
                        case VK_B:
                            frame->editor()->command("ToggleBold").execute();
                            break;
                        case VK_I:
                            frame->editor()->command("ToggleItalic").execute();
                            break;
                        default:
                            // catch combination AltGr+key or Ctrl+Alt+key
                            if (kevent->type() != PlatformKeyboardEvent::KeyDown && kevent->altKey() && !kevent->text().isEmpty()) {
                                frame->editor()->insertText(kevent->text(), event);
                                break;
                            }
                            return;
                    }
                } else return;
        }
    } else {
#ifndef QT_NO_SHORTCUT
        if (kevent->qtEvent() == QKeySequence::Copy) {
            m_page->triggerAction(QWebPage::Copy);
        } else
#endif // QT_NO_SHORTCUT
        switch (kevent->windowsVirtualKeyCode()) {
            case VK_UP:
                frame->editor()->command("MoveUp").execute();
                break;
            case VK_DOWN:
                frame->editor()->command("MoveDown").execute();
                break;
            case VK_PRIOR:  // PageUp
                frame->editor()->command("MovePageUp").execute();
                break;
            case VK_NEXT:  // PageDown
                frame->editor()->command("MovePageDown").execute();
                break;
            case VK_HOME:
                if (kevent->ctrlKey())
                    frame->editor()->command("MoveToBeginningOfDocument").execute();
                break;
            case VK_END:
                if (kevent->ctrlKey())
                    frame->editor()->command("MoveToEndOfDocument").execute();
                break;
            default:
                if (kevent->ctrlKey()) {
                    switch (kevent->windowsVirtualKeyCode()) {
                        case VK_A:
                            frame->editor()->command("SelectAll").execute();
                            break;
                        default:
                            return;
                    }
                } else return;
        }
    }
    event->setDefaultHandled();
}
static bool initializeIndicator(TextIndicatorData& data, Frame& frame, const Range& range, FloatSize margin, bool indicatesCurrentSelection)
{
    Vector<FloatRect> textRects;

    // FIXME (138888): Ideally we wouldn't remove the margin in this case, but we need to
    // ensure that the indicator and indicator-with-highlight overlap precisely, and
    // we can't add a margin to the indicator-with-highlight.
    if (indicatesCurrentSelection && !(data.options & TextIndicatorOptionIncludeMarginIfRangeMatchesSelection))
        margin = FloatSize();

    FrameSelection::TextRectangleHeight textRectHeight = (data.options & TextIndicatorOptionTightlyFitContent) ? FrameSelection::TextRectangleHeight::TextHeight : FrameSelection::TextRectangleHeight::SelectionHeight;

    if ((data.options & TextIndicatorOptionUseBoundingRectAndPaintAllContentForComplexRanges) && hasNonInlineOrReplacedElements(range))
        data.options |= TextIndicatorOptionPaintAllContent;
    else {
        if (data.options & TextIndicatorOptionDoNotClipToVisibleRect)
            frame.selection().getTextRectangles(textRects, textRectHeight);
        else
            frame.selection().getClippedVisibleTextRectangles(textRects, textRectHeight);
    }

    if (textRects.isEmpty()) {
        RenderView* renderView = frame.contentRenderer();
        if (!renderView)
            return false;
        FloatRect boundingRect = range.absoluteBoundingRect();
        if (data.options & TextIndicatorOptionDoNotClipToVisibleRect)
            textRects.append(boundingRect);
        else {
            // Clip to the visible rect, just like getClippedVisibleTextRectangles does.
            // FIXME: We really want to clip to the unobscured rect in both cases, I think.
            // (this seems to work on Mac, but maybe not iOS?)
            FloatRect visibleContentRect = frame.view()->visibleContentRect(ScrollableArea::LegacyIOSDocumentVisibleRect);
            textRects.append(intersection(visibleContentRect, boundingRect));
        }
    }

    FloatRect textBoundingRectInRootViewCoordinates;
    FloatRect textBoundingRectInDocumentCoordinates;
    Vector<FloatRect> textRectsInRootViewCoordinates;
    for (const FloatRect& textRect : textRects) {
        FloatRect textRectInDocumentCoordinatesIncludingMargin = textRect;
        textRectInDocumentCoordinatesIncludingMargin.inflateX(margin.width());
        textRectInDocumentCoordinatesIncludingMargin.inflateY(margin.height());
        textBoundingRectInDocumentCoordinates.unite(textRectInDocumentCoordinatesIncludingMargin);

        FloatRect textRectInRootViewCoordinates = frame.view()->contentsToRootView(enclosingIntRect(textRectInDocumentCoordinatesIncludingMargin));
        textRectsInRootViewCoordinates.append(textRectInRootViewCoordinates);
        textBoundingRectInRootViewCoordinates.unite(textRectInRootViewCoordinates);
    }

    Vector<FloatRect> textRectsInBoundingRectCoordinates;
    for (auto rect : textRectsInRootViewCoordinates) {
        rect.moveBy(-textBoundingRectInRootViewCoordinates.location());
        textRectsInBoundingRectCoordinates.append(rect);
    }

    // Store the selection rect in window coordinates, to be used subsequently
    // to determine if the indicator and selection still precisely overlap.
    data.selectionRectInRootViewCoordinates = frame.view()->contentsToRootView(enclosingIntRect(frame.selection().selectionBounds()));
    data.textBoundingRectInRootViewCoordinates = textBoundingRectInRootViewCoordinates;
    data.textRectsInBoundingRectCoordinates = textRectsInBoundingRectCoordinates;

    return takeSnapshots(data, frame, enclosingIntRect(textBoundingRectInDocumentCoordinates), textRects);
}
Example #4
0
bool EditorClientEfl::handleEditingKeyboardEvent(KeyboardEvent* event)
{
    Node* node = event->target()->toNode();
    ASSERT(node);
    Frame* frame = node->document()->frame();
    ASSERT(frame);

    const PlatformKeyboardEvent* keyEvent = event->keyEvent();
    if (!keyEvent)
        return false;

    if (!frame->settings())
        return false;

    bool caretBrowsing = frame->settings()->caretBrowsingEnabled();
    if (caretBrowsing) {
        switch (keyEvent->windowsVirtualKeyCode()) {
        case VK_LEFT:
            frame->selection()->modify(keyEvent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionLeft,
                                       keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
                                       UserTriggered);
            return true;
        case VK_RIGHT:
            frame->selection()->modify(keyEvent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionRight,
                                       keyEvent->ctrlKey() ? WordGranularity : CharacterGranularity,
                                       UserTriggered);
            return true;
        case VK_UP:
            frame->selection()->modify(keyEvent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionBackward,
                                       keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
                                       UserTriggered);
            return true;
        case VK_DOWN:
            frame->selection()->modify(keyEvent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionForward,
                                       keyEvent->ctrlKey() ? ParagraphGranularity : LineGranularity,
                                       UserTriggered);
            return true;
        }
    }

    Editor::Command command = frame->editor().command(interpretKeyEvent(event));

    if (keyEvent->type() == PlatformEvent::RawKeyDown) {
        // WebKit doesn't have enough information about mode to decide how commands that just insert text if executed via Editor should be treated,
        // so we leave it upon WebCore to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
        // (e.g. Tab that inserts a Tab character, or Enter).
        return !command.isTextInsertion() && command.execute(event);
    }

    if (command.execute(event))
        return true;

    // Don't allow text insertion for nodes that cannot edit.
    if (!frame->editor().canEdit())
        return false;

    // Don't insert null or control characters as they can result in unexpected behaviour
    if (event->charCode() < ' ')
        return false;

    // Don't insert anything if a modifier is pressed
    if (keyEvent->ctrlKey() || keyEvent->altKey())
        return false;

    return frame->editor().insertText(event->keyEvent()->text(), event);
}
Example #5
0
void FindController::updateFindUIAfterPageScroll(bool found, const String& string, FindOptions options, unsigned maxMatchCount)
{
    Frame* selectedFrame = frameWithSelection(m_webPage->corePage());
    
    PluginView* pluginView = pluginViewForFrame(m_webPage->mainFrame());

    bool shouldShowOverlay = false;

    if (!found) {
        if (!pluginView)
            m_webPage->corePage()->unmarkAllTextMatches();

        if (selectedFrame)
            selectedFrame->selection()->clear();

        hideFindIndicator();

        m_webPage->send(Messages::WebPageProxy::DidFailToFindString(string));
    } else {
        shouldShowOverlay = options & FindOptionsShowOverlay;
        bool shouldShowHighlight = options & FindOptionsShowHighlight;
        unsigned matchCount = 1;

        if (shouldShowOverlay || shouldShowHighlight) {
            if (maxMatchCount == std::numeric_limits<unsigned>::max())
                --maxMatchCount;

            if (pluginView) {
                matchCount = pluginView->countFindMatches(string, core(options), maxMatchCount + 1);
                shouldShowOverlay = false;
            } else {
                m_webPage->corePage()->unmarkAllTextMatches();
                matchCount = m_webPage->corePage()->markAllMatchesForText(string, core(options), shouldShowHighlight, maxMatchCount + 1);
            }

            // If we have a large number of matches, we don't want to take the time to paint the overlay.
            if (matchCount > maxMatchCount) {
                shouldShowOverlay = false;
                matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
            }
        }

        m_webPage->send(Messages::WebPageProxy::DidFindString(string, matchCount));

        if (!(options & FindOptionsShowFindIndicator) || !updateFindIndicator(selectedFrame, shouldShowOverlay))
            hideFindIndicator();
    }

    if (!shouldShowOverlay) {
        if (m_findPageOverlay)
            m_webPage->uninstallPageOverlay(m_findPageOverlay, true);
    } else {
        if (!m_findPageOverlay) {
            RefPtr<PageOverlay> findPageOverlay = PageOverlay::create(this);
            m_findPageOverlay = findPageOverlay.get();
            m_webPage->installPageOverlay(findPageOverlay.release(), true);
            m_findPageOverlay->setNeedsDisplay();
        } else
            m_findPageOverlay->setNeedsDisplay();
    }
}
void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const
{
    if (item.type() == SeparatorType)
        return;
    
    Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
    if (!frame)
        return;

    bool shouldEnable = true;
    bool shouldCheck = false; 

    switch (item.action()) {
        case ContextMenuItemTagCheckSpelling:
            shouldEnable = frame->editor()->canEdit();
            break;
        case ContextMenuItemTagDefaultDirection:
            shouldCheck = false;
            shouldEnable = false;
            break;
        case ContextMenuItemTagLeftToRight:
        case ContextMenuItemTagRightToLeft: {
            ExceptionCode ec = 0;
            RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
            String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
            style->setProperty(CSSPropertyDirection, direction, false, ec);
            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
            shouldEnable = true;
            break;
        }
        case ContextMenuItemTagTextDirectionDefault: {
            Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural");
            shouldCheck = command.state() == TrueTriState;
            shouldEnable = command.isEnabled();
            break;
        }
        case ContextMenuItemTagTextDirectionLeftToRight: {
            Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight");
            shouldCheck = command.state() == TrueTriState;
            shouldEnable = command.isEnabled();
            break;
        }
        case ContextMenuItemTagTextDirectionRightToLeft: {
            Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft");
            shouldCheck = command.state() == TrueTriState;
            shouldEnable = command.isEnabled();
            break;
        }
        case ContextMenuItemTagCopy:
            shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
            break;
        case ContextMenuItemTagCut:
            shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut();
            break;
        case ContextMenuItemTagIgnoreSpelling:
        case ContextMenuItemTagLearnSpelling:
            shouldEnable = frame->selection()->isRange();
            break;
        case ContextMenuItemTagPaste:
            shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste();
            break;
#if PLATFORM(GTK)
        case ContextMenuItemTagDelete:
            shouldEnable = frame->editor()->canDelete();
            break;
        case ContextMenuItemTagSelectAll:
        case ContextMenuItemTagInputMethods:
        case ContextMenuItemTagUnicode:
            shouldEnable = true;
            break;
#endif
        case ContextMenuItemTagUnderline: {
            ExceptionCode ec = 0;
            RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
            style->setProperty(CSSPropertyWebkitTextDecorationsInEffect, "underline", false, ec);
            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
            shouldEnable = frame->editor()->canEditRichly();
            break;
        }
        case ContextMenuItemTagLookUpInDictionary:
            shouldEnable = frame->selection()->isRange();
            break;
        case ContextMenuItemTagCheckGrammarWithSpelling:
#ifndef BUILDING_ON_TIGER
            if (frame->editor()->isGrammarCheckingEnabled())
                shouldCheck = true;
            shouldEnable = true;
#endif
            break;
        case ContextMenuItemTagItalic: {
            ExceptionCode ec = 0;
            RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
            style->setProperty(CSSPropertyFontStyle, "italic", false, ec);
            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
            shouldEnable = frame->editor()->canEditRichly();
            break;
        }
        case ContextMenuItemTagBold: {
            ExceptionCode ec = 0;
            RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
            style->setProperty(CSSPropertyFontWeight, "bold", false, ec);
            shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
            shouldEnable = frame->editor()->canEditRichly();
            break;
        }
        case ContextMenuItemTagOutline:
            shouldEnable = false;
            break;
        case ContextMenuItemTagShowSpellingPanel:
#ifndef BUILDING_ON_TIGER
            if (frame->editor()->spellingPanelIsShowing())
                item.setTitle(contextMenuItemTagShowSpellingPanel(false));
            else
                item.setTitle(contextMenuItemTagShowSpellingPanel(true));
#endif
            shouldEnable = frame->editor()->canEdit();
            break;
        case ContextMenuItemTagNoGuessesFound:
            shouldEnable = false;
            break;
        case ContextMenuItemTagCheckSpellingWhileTyping:
            shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled();
            break;
#if PLATFORM(MAC)
        case ContextMenuItemTagSubstitutionsMenu:
        case ContextMenuItemTagTransformationsMenu:
            break;
        case ContextMenuItemTagShowSubstitutions:
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            if (frame->editor()->substitutionsPanelIsShowing())
                item.setTitle(contextMenuItemTagShowSubstitutions(false));
            else
                item.setTitle(contextMenuItemTagShowSubstitutions(true));
            shouldEnable = frame->editor()->canEdit();
#endif
            break;
        case ContextMenuItemTagMakeUpperCase:
        case ContextMenuItemTagMakeLowerCase:
        case ContextMenuItemTagCapitalize:
        case ContextMenuItemTagChangeBack:
            shouldEnable = frame->editor()->canEdit();
            break;
        case ContextMenuItemTagCorrectSpellingAutomatically:
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled();
#endif
            break;
        case ContextMenuItemTagSmartCopyPaste:
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            shouldCheck = frame->editor()->smartInsertDeleteEnabled();
#endif
            break;
        case ContextMenuItemTagSmartQuotes:
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled();
#endif
            break;
        case ContextMenuItemTagSmartDashes:
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled();
#endif
            break;
        case ContextMenuItemTagSmartLinks:
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled();
#endif
            break;
        case ContextMenuItemTagTextReplacement:
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled();
#endif
            break;
#endif
#if PLATFORM(GTK)
        case ContextMenuItemTagGoBack:
            shouldEnable = frame->loader()->canGoBackOrForward(-1);
            break;
        case ContextMenuItemTagGoForward:
            shouldEnable = frame->loader()->canGoBackOrForward(1);
            break;
        case ContextMenuItemTagStop:
            shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense();
            break;
        case ContextMenuItemTagReload:
            shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense();
            break;
        case ContextMenuItemTagFontMenu:
            shouldEnable = frame->editor()->canEditRichly();
            break;
#else
        case ContextMenuItemTagGoBack:
        case ContextMenuItemTagGoForward:
        case ContextMenuItemTagStop:
        case ContextMenuItemTagReload:
        case ContextMenuItemTagFontMenu:
#endif
        case ContextMenuItemTagNoAction:
        case ContextMenuItemTagOpenLinkInNewWindow:
        case ContextMenuItemTagDownloadLinkToDisk:
        case ContextMenuItemTagCopyLinkToClipboard:
        case ContextMenuItemTagOpenImageInNewWindow:
        case ContextMenuItemTagDownloadImageToDisk:
        case ContextMenuItemTagCopyImageToClipboard:
        case ContextMenuItemTagOpenFrameInNewWindow:
        case ContextMenuItemTagSpellingGuess:
        case ContextMenuItemTagOther:
        case ContextMenuItemTagSearchInSpotlight:
        case ContextMenuItemTagSearchWeb:
        case ContextMenuItemTagOpenWithDefaultApplication:
        case ContextMenuItemPDFActualSize:
        case ContextMenuItemPDFZoomIn:
        case ContextMenuItemPDFZoomOut:
        case ContextMenuItemPDFAutoSize:
        case ContextMenuItemPDFSinglePage:
        case ContextMenuItemPDFFacingPages:
        case ContextMenuItemPDFContinuous:
        case ContextMenuItemPDFNextPage:
        case ContextMenuItemPDFPreviousPage:
        case ContextMenuItemTagOpenLink:
        case ContextMenuItemTagIgnoreGrammar:
        case ContextMenuItemTagSpellingMenu:
        case ContextMenuItemTagShowFonts:
        case ContextMenuItemTagStyles:
        case ContextMenuItemTagShowColors:
        case ContextMenuItemTagSpeechMenu:
        case ContextMenuItemTagStartSpeaking:
        case ContextMenuItemTagStopSpeaking:
        case ContextMenuItemTagWritingDirectionMenu:
        case ContextMenuItemTagTextDirectionMenu:
        case ContextMenuItemTagPDFSinglePageScrolling:
        case ContextMenuItemTagPDFFacingPagesScrolling:
        case ContextMenuItemTagInspectElement:
        case ContextMenuItemBaseApplicationTag:
            break;
    }

    item.setChecked(shouldCheck);
    item.setEnabled(shouldEnable);
}
Example #7
0
void WebViewPrivate::onKeyDown(BalEventKey event)
{
    Frame* frame = m_webView->page()->focusController()->focusedOrMainFrame();
    if (!frame)
        return;
    PlatformKeyboardEvent keyboardEvent(&event);

    if (frame->eventHandler()->keyEvent(keyboardEvent))
        return;

    FrameView* view = frame->view();
    SelectionController::EAlteration alteration;
    if (event.keysym.sym == SDLK_LSHIFT)
        alteration = SelectionController::EXTEND;
    else
        alteration = SelectionController::MOVE;

    switch (event.keysym.sym) {
    case SDLK_DOWN:
        view->scrollBy(IntSize(0, (int)cMouseWheelPixelsPerLineStep));
        return;
    case SDLK_UP:
        view->scrollBy(IntSize(0, (int)-cMouseWheelPixelsPerLineStep));
        return;
    case SDLK_RIGHT:
        view->scrollBy(IntSize((int)cMouseWheelPixelsPerLineStep, 0));
        return;
    case SDLK_LEFT:
        view->scrollBy(IntSize((int)-cMouseWheelPixelsPerLineStep, 0));
        return;
    case SDLK_PAGEDOWN:
        view->scrollBy(IntSize(0, m_rect.height()));
        return;
    case SDLK_PAGEUP:
        view->scrollBy(IntSize(0, -m_rect.height()));
        return;
    case SDLK_HOME:
        frame->selection()->modify(alteration, SelectionController::BACKWARD, DocumentBoundary, true);
        return;
    case SDLK_END:
        frame->selection()->modify(alteration, SelectionController::FORWARD, DocumentBoundary, true);
        return;
    case SDLK_ESCAPE:
        SDL_Event ev;
        ev.type = SDL_QUIT;
        SDL_PushEvent(&ev);
        return;
    case SDLK_F1:
    {
        m_webView->goBack();
        GraphicsContext ctx(m_webView->viewWindow());
        if (frame->contentRenderer() && frame->view()) {
            frame->view()->layoutIfNeededRecursive();
            IntRect dirty(0, 0, m_rect.width(), m_rect.height());
            frame->view()->paint(&ctx, dirty);
	}
        return;
    }
    case SDLK_F2:
    {
        m_webView->goForward();
        GraphicsContext ctx(m_webView->viewWindow());
        if (frame->contentRenderer() && frame->view()) {
            frame->view()->layoutIfNeededRecursive();
            IntRect dirty(0, 0, m_rect.width(), m_rect.height());
            frame->view()->paint(&ctx, dirty);
	}
        return;
    }
    case SDLK_F3:
        if (m_webView->canZoomPageIn())
            m_webView->zoomPageIn();
        return;
    case SDLK_F4:
        if (m_webView->canZoomPageOut())
            m_webView->zoomPageOut();
        return;
    default:
        break;
    }
}
Example #8
0
PlatformMenuDescription ContextMenuClientImpl::getCustomMenuFromDefaultItems(
    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 0;

    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 =
            static_cast<HTMLMediaElement*>(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 = static_cast<HTMLPlugInImageElement*>(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) || !static_cast<HTMLInputElement*>(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 = 
                static_cast<HTMLInputElement*>(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);
            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(defaultMenu, 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 && form->checkValidity() && r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag)) {
            HTMLInputElement* selectedElement = static_cast<HTMLInputElement*>(r.innerNonSharedNode());
            if (selectedElement) {
                WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(selectedElement));
                if (ws.url().isValid())
                    data.keywordURL = ws.url();
            }
        }
    }

#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);

    return 0;
}
void ContextMenu::populate()
{
    ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink());
    ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, 
        contextMenuItemTagOpenLinkInNewWindow());
    ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, 
        contextMenuItemTagDownloadLinkToDisk());
    ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, 
        contextMenuItemTagCopyLinkToClipboard());
    ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, 
        contextMenuItemTagOpenImageInNewWindow());
    ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, 
        contextMenuItemTagDownloadImageToDisk());
    ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, 
        contextMenuItemTagCopyImageToClipboard());
#if PLATFORM(MAC)
    ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, 
        contextMenuItemTagSearchInSpotlight());
    ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, 
        contextMenuItemTagLookUpInDictionary());
#endif
    ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb());
    ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy());
    ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack());
    ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward,  contextMenuItemTagGoForward());
    ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop());
    ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload());
    ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, 
        contextMenuItemTagOpenFrameInNewWindow());
    ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, 
        contextMenuItemTagNoGuessesFound());
    ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, 
        contextMenuItemTagIgnoreSpelling());
    ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, 
        contextMenuItemTagLearnSpelling());
    ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, 
        contextMenuItemTagIgnoreGrammar());
    ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut());
    ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
#if PLATFORM(GTK)
    ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
    ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
#endif
    
    HitTestResult result = hitTestResult();
    
    Node* node = m_hitTestResult.innerNonSharedNode();
    if (!node)
        return;
#if PLATFORM(GTK)
    if (!result.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
        return;
#endif
    Frame* frame = node->document()->frame();
    if (!frame)
        return;

    if (!result.isContentEditable()) {
        FrameLoader* loader = frame->loader();
        KURL linkURL = result.absoluteLinkURL();
        if (!linkURL.isEmpty()) {
            if (loader->canHandleRequest(ResourceRequest(linkURL))) {
                appendItem(OpenLinkItem);
                appendItem(OpenLinkInNewWindowItem);
                appendItem(DownloadFileItem);
            }
            appendItem(CopyLinkItem);
        }

        KURL imageURL = result.absoluteImageURL();
        if (!imageURL.isEmpty()) {
            if (!linkURL.isEmpty())
                appendItem(*separatorItem());

            appendItem(OpenImageInNewWindowItem);
            appendItem(DownloadImageItem);
            if (imageURL.isLocalFile() || m_hitTestResult.image())
                appendItem(CopyImageItem);
        }

        if (imageURL.isEmpty() && linkURL.isEmpty()) {
            if (result.isSelected()) {
                if (selectionContainsPossibleWord(frame)) {
#if PLATFORM(MAC)
                    appendItem(SearchSpotlightItem);
#endif
                    appendItem(SearchWebItem);
                    appendItem(*separatorItem());
#if PLATFORM(MAC)
                    appendItem(LookInDictionaryItem);
                    appendItem(*separatorItem());
#endif
                }
                appendItem(CopyItem);
            } else {
#if PLATFORM(GTK)
                appendItem(BackItem);
                appendItem(ForwardItem);
                appendItem(StopItem);
                appendItem(ReloadItem);
#else
                if (loader->canGoBackOrForward(-1))
                    appendItem(BackItem);

                if (loader->canGoBackOrForward(1))
                    appendItem(ForwardItem);

                // use isLoadingInAPISense rather than isLoading because Stop/Reload are
                // intended to match WebKit's API, not WebCore's internal notion of loading status
                if (loader->documentLoader()->isLoadingInAPISense())
                    appendItem(StopItem);
                else
                    appendItem(ReloadItem);
#endif

                if (frame->page() && frame != frame->page()->mainFrame())
                    appendItem(OpenFrameItem);
            }
        }
    } else { // Make an editing context menu
        SelectionController* selection = frame->selection();
        bool inPasswordField = selection->isInPasswordField();
        
        if (!inPasswordField) {
            // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
            // is never considered a misspelling and bad grammar at the same time)
            bool misspelling;
            bool badGrammar;
            Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
            if (misspelling || badGrammar) {
                size_t size = guesses.size();
                if (size == 0) {
                    // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
                    // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit)
                    if (misspelling) {
                        appendItem(NoGuessesItem);
                        appendItem(*separatorItem());
                    }
                } else {
                    for (unsigned i = 0; i < size; i++) {
                        const String &guess = guesses[i];
                        if (!guess.isEmpty()) {
                            ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
                            appendItem(item);
                        }
                    }
                    appendItem(*separatorItem());                    
                }
                
                if (misspelling) {
                    appendItem(IgnoreSpellingItem);
                    appendItem(LearnSpellingItem);
                } else
                    appendItem(IgnoreGrammarItem);
                appendItem(*separatorItem());
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            } else {
                // If the string was autocorrected, generate a contextual menu item allowing it to be changed back.
                String replacedString = result.replacedString();
                if (!replacedString.isEmpty()) {
                    ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString));
                    appendItem(item);
                    appendItem(*separatorItem());
                }
#endif
            }
        }

        FrameLoader* loader = frame->loader();
        KURL linkURL = result.absoluteLinkURL();
        if (!linkURL.isEmpty()) {
            if (loader->canHandleRequest(ResourceRequest(linkURL))) {
                appendItem(OpenLinkItem);
                appendItem(OpenLinkInNewWindowItem);
                appendItem(DownloadFileItem);
            }
            appendItem(CopyLinkItem);
            appendItem(*separatorItem());
        }

        if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) {
#if PLATFORM(MAC)
            appendItem(SearchSpotlightItem);
#endif
            appendItem(SearchWebItem);
            appendItem(*separatorItem());
     
#if PLATFORM(MAC)
            appendItem(LookInDictionaryItem);
            appendItem(*separatorItem());
#endif
        }

        appendItem(CutItem);
        appendItem(CopyItem);
        appendItem(PasteItem);
#if PLATFORM(GTK)
        appendItem(DeleteItem);
        appendItem(*separatorItem());
        appendItem(SelectAllItem);
#endif

        if (!inPasswordField) {
            appendItem(*separatorItem());
#ifndef BUILDING_ON_TIGER
            ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, 
                contextMenuItemTagSpellingMenu());
            createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem);
            appendItem(SpellingAndGrammarMenuItem);
#else
            ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, 
                contextMenuItemTagSpellingMenu());
            createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem);
            appendItem(SpellingMenuItem);
#endif
#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
            ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, 
                contextMenuItemTagSubstitutionsMenu());
            createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem);
            appendItem(substitutionsMenuItem);
            ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, 
                contextMenuItemTagTransformationsMenu());
            createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem);
            appendItem(transformationsMenuItem);
#endif
            ContextMenuItem  FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, 
                contextMenuItemTagFontMenu());
            createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem);
            appendItem(FontMenuItem);
#if PLATFORM(MAC)
            ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, 
                contextMenuItemTagSpeechMenu());
            createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem);
            appendItem(SpeechMenuItem);
#endif
#if !PLATFORM(GTK)
            ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, 
                contextMenuItemTagWritingDirectionMenu());
            createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem);
            appendItem(WritingDirectionMenuItem);
            if (Page* page = frame->page()) {
                if (Settings* settings = page->settings()) {
                    bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
                        || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
                    if (includeTextDirectionSubmenu) {
                        ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, 
                            contextMenuItemTagTextDirectionMenu());
                        createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem);
                        appendItem(TextDirectionMenuItem);
                    }
                }
            }
#endif
        }
    }
}
Example #10
0
void EditorClient::handleKeyboardEvent(KeyboardEvent* event)
{
    Frame* frame = core(m_webView)->focusController()->focusedOrMainFrame();
    if (!frame || !frame->document()->focusedNode())
        return;

    const PlatformKeyboardEvent* kevent = event->keyEvent();
    if (!kevent || kevent->type() == PlatformKeyboardEvent::KeyUp)
        return;

    Node* start = frame->selection()->start().node();
    if (!start)
        return;

    // FIXME: Use GtkBindingSet instead of this hard-coded switch
    // http://bugs.webkit.org/show_bug.cgi?id=15911

    if (start->isContentEditable()) {
        switch (kevent->windowsVirtualKeyCode()) {
            case VK_BACK:
                frame->editor()->deleteWithDirection(SelectionController::BACKWARD,
                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity, false, true);
                break;
            case VK_DELETE:
                frame->editor()->deleteWithDirection(SelectionController::FORWARD,
                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity, false, true);
                break;
            case VK_LEFT:
                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
                        SelectionController::LEFT,
                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
                        true);
                break;
            case VK_RIGHT:
                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
                        SelectionController::RIGHT,
                        kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
                        true);
                break;
            case VK_UP:
                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
                        SelectionController::BACKWARD,
                        kevent->ctrlKey() ? ParagraphGranularity : LineGranularity,
                        true);
                break;
            case VK_DOWN:
                frame->selection()->modify(kevent->shiftKey() ? SelectionController::EXTEND : SelectionController::MOVE,
                        SelectionController::FORWARD,
                        kevent->ctrlKey() ? ParagraphGranularity : LineGranularity,
                        true);
                break;
            case VK_PRIOR:  // PageUp
                frame->editor()->command(kevent->shiftKey() ? "MovePageUpAndModifySelection" : "MovePageUp").execute();
                break;
            case VK_NEXT:  // PageDown
                frame->editor()->command(kevent->shiftKey() ? "MovePageDownAndModifySelection" : "MovePageDown").execute();
                break;
            case VK_HOME:
                if (kevent->ctrlKey() && kevent->shiftKey())
                    frame->editor()->command("MoveToBeginningOfDocumentAndModifySelection").execute();
                else if (kevent->ctrlKey())
                    frame->editor()->command("MoveToBeginningOfDocument").execute();
                else if (kevent->shiftKey())
                    frame->editor()->command("MoveToBeginningOfLineAndModifySelection").execute();
                else
                    frame->editor()->command("MoveToBeginningOfLine").execute();
                break;
            case VK_END:
                if (kevent->ctrlKey() && kevent->shiftKey())
                    frame->editor()->command("MoveToEndOfDocumentAndModifySelection").execute();
                else if (kevent->ctrlKey())
                    frame->editor()->command("MoveToEndOfDocument").execute();
                else if (kevent->shiftKey())
                    frame->editor()->command("MoveToEndOfLineAndModifySelection").execute();
                else
                    frame->editor()->command("MoveToEndOfLine").execute();
                break;
            case VK_RETURN:
                frame->editor()->command("InsertLineBreak").execute();
                break;
            case VK_TAB:
                return;
            default:
                if (!kevent->ctrlKey() && !kevent->altKey() && !kevent->text().isEmpty()) {
                    if (kevent->text().length() == 1) {
                        UChar ch = kevent->text()[0];
                        // Don't insert null or control characters as they can result in unexpected behaviour
                        if (ch < ' ')
                            break;
                    }
                    frame->editor()->insertText(kevent->text(), event);
                } else if (kevent->ctrlKey()) {
                    switch (kevent->windowsVirtualKeyCode()) {
                        case VK_B:
                            frame->editor()->command("ToggleBold").execute();
                            break;
                        case VK_I:
                            frame->editor()->command("ToggleItalic").execute();
                            break;
                        case VK_Y:
                            frame->editor()->command("Redo").execute();
                            break;
                        case VK_Z:
                            frame->editor()->command("Undo").execute();
                            break;
                        default:
                            return;
                    }
                } else return;
        }
    } else {
        switch (kevent->windowsVirtualKeyCode()) {
            case VK_UP:
                frame->editor()->command("MoveUp").execute();
                break;
            case VK_DOWN:
                frame->editor()->command("MoveDown").execute();
                break;
            case VK_PRIOR:  // PageUp
                frame->editor()->command("MovePageUp").execute();
                break;
            case VK_NEXT:  // PageDown
                frame->editor()->command("MovePageDown").execute();
                break;
            case VK_HOME:
                if (kevent->ctrlKey())
                    frame->editor()->command("MoveToBeginningOfDocument").execute();
                break;
            case VK_END:
                if (kevent->ctrlKey())
                    frame->editor()->command("MoveToEndOfDocument").execute();
                break;
            default:
                return;
        }
    }
    event->setDefaultHandled();
}
Example #11
0
bool DragController::concludeEditDrag(DragData* dragData)
{
    ASSERT(dragData);
    ASSERT(!m_isHandlingDrag);
    
    if (!m_document)
        return false;
    
    IntPoint point = m_document->view()->windowToContents(dragData->clientPosition());
    Element* element =  m_document->elementFromPoint(point.x(), point.y());
    ASSERT(element);
    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_document->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->isEnabled())
            return false;
        
        if (!dragData->containsFiles())
            return false;
        
        Vector<String> filenames;
        dragData->asFilenames(filenames);
        if (filenames.isEmpty())
            return false;
        
        // Ugly.  For security none of the API's available to us to 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 = static_cast<RenderFileUploadControl*>(fileInput->renderer());
        
        if (!renderer)
            return false;
        
        renderer->receiveDroppedFiles(filenames);
        return true;
    }

    Selection 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_document, 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_document, createFragmentFromText(range.get(), text), true, false, true)); 
    }
    loader->setAllowStaleResources(false);

    return true;
}
Example #12
0
void EditorClientHaiku::handleKeyboardEvent(KeyboardEvent* event)
{
    Frame* frame = m_page->focusController()->focusedOrMainFrame();
    if (!frame || !frame->document()->focusedNode())
        return;

    const PlatformKeyboardEvent* kevent = event->keyEvent();
    if (!kevent || kevent->type() == PlatformKeyboardEvent::KeyUp)
        return;

    Node* start = frame->selection()->start().containerNode();
    if (!start)
        return;

    if (start->isContentEditable()) {
        switch (kevent->windowsVirtualKeyCode()) {
        case VK_BACK:
            frame->editor()->deleteWithDirection(DirectionBackward,
                                                 kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
                                                 false, true);
            break;
        case VK_DELETE:
            frame->editor()->deleteWithDirection(DirectionForward,
                                                 kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
                                                 false, true);
            break;
        case VK_LEFT:
            frame->selection()->modify(kevent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionLeft,
                                       kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
                                       true);
            break;
        case VK_RIGHT:
            frame->selection()->modify(kevent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionRight,
                                       kevent->ctrlKey() ? WordGranularity : CharacterGranularity,
                                       true);
            break;
        case VK_UP:
            frame->selection()->modify(kevent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionBackward,
                                       kevent->ctrlKey() ? ParagraphGranularity : LineGranularity,
                                       true);
            break;
        case VK_DOWN:
            frame->selection()->modify(kevent->shiftKey() ? FrameSelection::AlterationExtend : FrameSelection::AlterationMove,
                                       DirectionForward,
                                       kevent->ctrlKey() ? ParagraphGranularity : LineGranularity,
                                       true);
            break;
        case VK_PRIOR: // PageUp
            frame->editor()->command("MoveUpByPageAndModifyCaret");
            break;
        case VK_NEXT: // PageDown
            frame->editor()->command("MoveDownByPageAndModifyCaret");
            break;
        case VK_RETURN:
            frame->editor()->command("InsertLineBreak");
            break;
        case VK_TAB:
            return;
        default:
            if (!kevent->ctrlKey() && !kevent->altKey() && !kevent->text().isEmpty()) {
                if (kevent->text().length() == 1) {
                    UChar ch = kevent->text()[0];
                    // Don't insert null or control characters as they can result in unexpected behaviour
                    if (ch < ' ')
                        break;
                }
                frame->editor()->insertText(kevent->text(), event);
            } else if (kevent->ctrlKey()) {
                switch (kevent->windowsVirtualKeyCode()) {
                case VK_A:
                    frame->editor()->command("SelectAll");
                    break;
                case VK_B:
                    frame->editor()->command("ToggleBold");
                    break;
                case VK_C:
                    frame->editor()->command("Copy");
                    break;
                case VK_I:
                    frame->editor()->command("ToggleItalic");
                    break;
                case VK_V:
                    frame->editor()->command("Paste");
                    break;
                case VK_X:
                    frame->editor()->command("Cut");
                    break;
                case VK_Y:
                    frame->editor()->command("Redo");
                    break;
                case VK_Z:
                    frame->editor()->command("Undo");
                    break;
                default:
                    return;
                }
            } else
                return;
        }
    } else {
        switch (kevent->windowsVirtualKeyCode()) {
        case VK_UP:
            frame->editor()->command("MoveUp");
            break;
        case VK_DOWN:
            frame->editor()->command("MoveDown");
            break;
        case VK_PRIOR: // PageUp
            frame->editor()->command("MoveUpByPageAndModifyCaret");
            break;
        case VK_NEXT: // PageDown
            frame->editor()->command("MoveDownByPageAndModifyCaret");
            break;
        case VK_HOME:
            if (kevent->ctrlKey())
                frame->editor()->command("MoveToBeginningOfDocument");
            break;
        case VK_END:
            if (kevent->ctrlKey())
                frame->editor()->command("MoveToEndOfDocument");
            break;
        default:
            if (kevent->ctrlKey()) {
                switch (kevent->windowsVirtualKeyCode()) {
                case VK_A:
                    frame->editor()->command("SelectAll");
                    break;
                case VK_C: case VK_X:
                    frame->editor()->command("Copy");
                    break;
                default:
                    return;
                }
            } else
                return;
        }
    }
    event->setDefaultHandled();
}
void FindController::findString(const String& string, FindOptions options, unsigned maxMatchCount)
{
    m_webPage->corePage()->unmarkAllTextMatches();

    bool found = m_webPage->corePage()->findString(string, core(options));

    Frame* selectedFrame = frameWithSelection(m_webPage->corePage());

    bool shouldShowOverlay = false;

    if (!found) {
        // Clear the selection.
        if (selectedFrame)
            selectedFrame->selection()->clear();

        hideFindIndicator();

        m_webPage->send(Messages::WebPageProxy::DidFailToFindString(string));
    } else {
        shouldShowOverlay = options & FindOptionsShowOverlay;

        if (shouldShowOverlay) {
            if (maxMatchCount == numeric_limits<unsigned>::max())
                --maxMatchCount;
            
            unsigned matchCount = m_webPage->corePage()->markAllMatchesForText(string, core(options), false, maxMatchCount + 1);

            // Check if we have more matches than allowed.
            if (matchCount > maxMatchCount) {
                shouldShowOverlay = false;
                matchCount = static_cast<unsigned>(kWKMoreThanMaximumMatchCount);
            }

            m_webPage->send(Messages::WebPageProxy::DidFindString(string, matchCount));
        }

        if (!(options & FindOptionsShowFindIndicator) || !updateFindIndicator(selectedFrame, shouldShowOverlay)) {
            // Either we shouldn't show the find indicator, or we couldn't update it.
            hideFindIndicator();
        }
    }

    if (!shouldShowOverlay) {
        if (m_findPageOverlay) {
            // Get rid of the overlay.
            m_webPage->uninstallPageOverlay(m_findPageOverlay);
        }
        
        ASSERT(!m_findPageOverlay);
        return;
    }

    if (!m_findPageOverlay) {
        RefPtr<PageOverlay> findPageOverlay = PageOverlay::create(this);
        m_findPageOverlay = findPageOverlay.get();
        m_webPage->installPageOverlay(findPageOverlay.release());
    } else {
        // The page overlay needs to be repainted.
        m_findPageOverlay->setNeedsDisplay();
    }
}
Example #14
0
void EditorClientQt::handleKeyboardEvent(KeyboardEvent* event)
{
    Frame* frame = m_page->d->page->focusController()->focusedOrMainFrame();
    if (!frame || !frame->document()->focusedNode())
        return;

    const PlatformKeyboardEvent* kevent = event->keyEvent();
    if (!kevent || kevent->type() == PlatformKeyboardEvent::KeyUp)
        return;

    Node* start = frame->selection()->start().node();
    if (!start)
        return;

    // FIXME: refactor all of this to use Actions or something like them
    if (start->isContentEditable()) {
        switch (kevent->windowsVirtualKeyCode()) {
#if QT_VERSION < 0x040500
            case VK_RETURN:
#ifdef QT_WS_MAC
                if (kevent->shiftKey() || kevent->metaKey())
#else
                if (kevent->shiftKey())
#endif
                    frame->editor()->command("InsertLineBreak").execute();
                else
                    frame->editor()->command("InsertNewline").execute();
                break;
#endif
            case VK_BACK:
                frame->editor()->deleteWithDirection(SelectionController::BACKWARD,
                        CharacterGranularity, false, true);
                break;
            case VK_DELETE:
                frame->editor()->deleteWithDirection(SelectionController::FORWARD,
                        CharacterGranularity, false, true);
                break;
            case VK_LEFT:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveLeftAndModifySelection").execute();
                else frame->editor()->command("MoveLeft").execute();
                break;
            case VK_RIGHT:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveRightAndModifySelection").execute();
                else frame->editor()->command("MoveRight").execute();
                break;
            case VK_UP:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveUpAndModifySelection").execute();
                else frame->editor()->command("MoveUp").execute();
                break;
            case VK_DOWN:
                if (kevent->shiftKey())
                    frame->editor()->command("MoveDownAndModifySelection").execute();
                else frame->editor()->command("MoveDown").execute();
                break;
            case VK_PRIOR:  // PageUp
                frame->editor()->command("MovePageUp").execute();
                break;
            case VK_NEXT:  // PageDown
                frame->editor()->command("MovePageDown").execute();
                break;
            case VK_TAB:
                return;
            default:
                if (kevent->type() != PlatformKeyboardEvent::KeyDown
                        && !kevent->ctrlKey() && !kevent->altKey() && !kevent->text().isEmpty()) {
                    frame->editor()->insertText(kevent->text(), event);
                } else if (kevent->ctrlKey()) {
                    switch (kevent->windowsVirtualKeyCode()) {
                        case VK_A:
                            frame->editor()->command("SelectAll").execute();
                            break;
                        case VK_B:
                            frame->editor()->command("ToggleBold").execute();
                            break;
                        case VK_C:
                            frame->editor()->command("Copy").execute();
                            break;
                        case VK_I:
                            frame->editor()->command("ToggleItalic").execute();
                            break;
                        case VK_V:
                            frame->editor()->command("Paste").execute();
                            break;
                        case VK_X:
                            frame->editor()->command("Cut").execute();
                            break;
                        case VK_Y:
                            frame->editor()->command("Redo").execute();
                            break;
                        case VK_Z:
                            frame->editor()->command("Undo").execute();
                            break;
                        default:
                            // catch combination AltGr+key or Ctrl+Alt+key
                            if (kevent->type() != PlatformKeyboardEvent::KeyDown && kevent->altKey() && !kevent->text().isEmpty()) {
                                frame->editor()->insertText(kevent->text(), event);
                                break;
                            }
                            return;
                    }
                } else return;
        }
    } else {
        switch (kevent->windowsVirtualKeyCode()) {
            case VK_UP:
                frame->editor()->command("MoveUp").execute();
                break;
            case VK_DOWN:
                frame->editor()->command("MoveDown").execute();
                break;
            case VK_PRIOR:  // PageUp
                frame->editor()->command("MovePageUp").execute();
                break;
            case VK_NEXT:  // PageDown
                frame->editor()->command("MovePageDown").execute();
                break;
            case VK_HOME:
                if (kevent->ctrlKey())
                    frame->editor()->command("MoveToBeginningOfDocument").execute();
                break;
            case VK_END:
                if (kevent->ctrlKey())
                    frame->editor()->command("MoveToEndOfDocument").execute();
                break;
            default:
                if (kevent->ctrlKey()) {
                    switch (kevent->windowsVirtualKeyCode()) {
                        case VK_A:
                            frame->editor()->command("SelectAll").execute();
                            break;
                        case VK_C: case VK_X:
                            frame->editor()->command("Copy").execute();
                            break;
                        default:
                            return;
                    }
                } else return;
        }
    }
    event->setDefaultHandled();
}