summaryrefslogtreecommitdiffstats
path: root/WebKit/chromium/src/WebViewImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'WebKit/chromium/src/WebViewImpl.cpp')
-rw-r--r--WebKit/chromium/src/WebViewImpl.cpp1434
1 files changed, 1032 insertions, 402 deletions
diff --git a/WebKit/chromium/src/WebViewImpl.cpp b/WebKit/chromium/src/WebViewImpl.cpp
index ce03523..7bec254 100644
--- a/WebKit/chromium/src/WebViewImpl.cpp
+++ b/WebKit/chromium/src/WebViewImpl.cpp
@@ -32,35 +32,44 @@
#include "WebViewImpl.h"
#include "AutoFillPopupMenuClient.h"
-#include "AutocompletePopupMenuClient.h"
#include "AXObjectCache.h"
+#include "BackForwardListImpl.h"
#include "Chrome.h"
+#include "ChromiumBridge.h"
+#include "ColorSpace.h"
+#include "CompositionUnderlineVectorBuilder.h"
#include "ContextMenu.h"
#include "ContextMenuController.h"
#include "ContextMenuItem.h"
#include "CSSStyleSelector.h"
#include "CSSValueKeywords.h"
#include "Cursor.h"
+#include "DeviceOrientationClientProxy.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "DOMUtilitiesPrivate.h"
#include "DragController.h"
+#include "DragScrollTimer.h"
#include "DragData.h"
#include "Editor.h"
#include "EventHandler.h"
+#include "Extensions3D.h"
#include "FocusController.h"
#include "FontDescription.h"
#include "FrameLoader.h"
#include "FrameTree.h"
#include "FrameView.h"
#include "GraphicsContext.h"
-#include "HitTestResult.h"
+#include "GraphicsContext3D.h"
+#include "GraphicsContext3DInternal.h"
#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
+#include "HitTestResult.h"
#include "HTMLNames.h"
#include "Image.h"
+#include "ImageBuffer.h"
+#include "ImageData.h"
#include "InspectorController.h"
-#include "IntRect.h"
#include "KeyboardCodes.h"
#include "KeyboardEvent.h"
#include "MIMETypeRegistry.h"
@@ -72,8 +81,8 @@
#include "PlatformContextSkia.h"
#include "PlatformKeyboardEvent.h"
#include "PlatformMouseEvent.h"
+#include "PlatformThemeChromiumGtk.h"
#include "PlatformWheelEvent.h"
-#include "PluginInfoStore.h"
#include "PopupMenuChromium.h"
#include "PopupMenuClient.h"
#include "ProgressTracker.h"
@@ -82,31 +91,46 @@
#include "SecurityOrigin.h"
#include "SelectionController.h"
#include "Settings.h"
+#include "SpeechInputClientImpl.h"
+#include "Timer.h"
#include "TypingCommand.h"
+#include "UserGestureIndicator.h"
+#include "Vector.h"
#include "WebAccessibilityObject.h"
#include "WebDevToolsAgentPrivate.h"
+#include "WebDevToolsAgentImpl.h"
#include "WebDragData.h"
#include "WebFrameImpl.h"
+#include "WebImage.h"
+#include "WebInputElement.h"
#include "WebInputEvent.h"
#include "WebInputEventConversion.h"
+#include "WebKit.h"
+#include "WebKitClient.h"
#include "WebMediaPlayerAction.h"
#include "WebNode.h"
+#include "WebPlugin.h"
+#include "WebPluginContainerImpl.h"
#include "WebPoint.h"
#include "WebPopupMenuImpl.h"
#include "WebRect.h"
+#include "WebRuntimeFeatures.h"
#include "WebSettingsImpl.h"
#include "WebString.h"
#include "WebVector.h"
#include "WebViewClient.h"
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(CG)
+#include <CoreGraphics/CGContext.h>
+#endif
#if OS(WINDOWS)
-#include "KeyboardCodesWin.h"
#include "RenderThemeChromiumWin.h"
#else
-#if OS(LINUX)
+#if OS(LINUX) || OS(FREEBSD)
#include "RenderThemeChromiumLinux.h"
#endif
-#include "KeyboardCodesPosix.h"
#include "RenderTheme.h"
#endif
@@ -116,15 +140,37 @@
using namespace WebCore;
+namespace {
+
+GraphicsContext3D::Attributes getCompositorContextAttributes()
+{
+ // Explicitly disable antialiasing for the compositor. As of the time of
+ // this writing, the only platform that supported antialiasing for the
+ // compositor was Mac OS X, because the on-screen OpenGL context creation
+ // code paths on Windows and Linux didn't yet have multisampling support.
+ // Mac OS X essentially always behaves as though it's rendering offscreen.
+ // Multisampling has a heavy cost especially on devices with relatively low
+ // fill rate like most notebooks, and the Mac implementation would need to
+ // be optimized to resolve directly into the IOSurface shared between the
+ // GPU and browser processes. For these reasons and to avoid platform
+ // disparities we explicitly disable antialiasing.
+ GraphicsContext3D::Attributes attributes;
+ attributes.antialias = false;
+ return attributes;
+}
+
+} // anonymous namespace
+
namespace WebKit {
// Change the text zoom level by kTextSizeMultiplierRatio each time the user
// zooms text in or out (ie., change by 20%). The min and max values limit
// text zoom to half and 3x the original text size. These three values match
// those in Apple's port in WebKit/WebKit/WebView/WebView.mm
-static const double textSizeMultiplierRatio = 1.2;
-static const double minTextSizeMultiplier = 0.5;
-static const double maxTextSizeMultiplier = 3.0;
+const double WebView::textSizeMultiplierRatio = 1.2;
+const double WebView::minTextSizeMultiplier = 0.5;
+const double WebView::maxTextSizeMultiplier = 3.0;
+
// The group name identifies a namespace of pages. Page group is used on OSX
// for some programs that use HTML views to display things that don't seem like
@@ -133,8 +179,8 @@ static const double maxTextSizeMultiplier = 3.0;
const char* pageGroupName = "default";
// Used to defer all page activity in cases where the embedder wishes to run
-// a nested event loop.
-static PageGroupLoadDeferrer* pageGroupLoadDeferrer;
+// a nested event loop. Using a stack enables nesting of message loop invocations.
+static Vector<PageGroupLoadDeferrer*> pageGroupLoadDeferrerStack;
// Ensure that the WebDragOperation enum values stay in sync with the original
// DragOperation constants.
@@ -149,26 +195,34 @@ COMPILE_ASSERT_MATCHING_ENUM(DragOperationMove);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationDelete);
COMPILE_ASSERT_MATCHING_ENUM(DragOperationEvery);
-// Note that focusOnShow is false so that the suggestions popup is shown not
-// activated. We need the page to still have focus so the user can keep typing
-// while the popup is showing.
-static const PopupContainerSettings suggestionsPopupSettings = {
- false, // focusOnShow
- false, // setTextOnIndexChange
- false, // acceptOnAbandon
- true, // loopSelectionNavigation
- true, // restrictWidthOfListBox. Same as other browser (Fx, IE, and safari)
+static const PopupContainerSettings autoFillPopupSettings = {
+ false, // setTextOnIndexChange
+ false, // acceptOnAbandon
+ true, // loopSelectionNavigation
+ false, // restrictWidthOfListBox (For security reasons show the entire entry
+ // so the user doesn't enter information he did not intend to.)
// For suggestions, we use the direction of the input field as the direction
// of the popup items. The main reason is to keep the display of items in
// drop-down the same as the items in the input field.
PopupContainerSettings::DOMElementDirection,
};
+static bool shouldUseExternalPopupMenus = false;
+
// WebView ----------------------------------------------------------------
-WebView* WebView::create(WebViewClient* client)
+WebView* WebView::create(WebViewClient* client, WebDevToolsAgentClient* devToolsClient)
+{
+ // Keep runtime flag for device motion turned off until it's implemented.
+ WebRuntimeFeatures::enableDeviceMotion(false);
+
+ // Pass the WebViewImpl's self-reference to the caller.
+ return adoptRef(new WebViewImpl(client, devToolsClient)).leakRef();
+}
+
+void WebView::setUseExternalPopupMenus(bool useExternalPopupMenus)
{
- return new WebViewImpl(client);
+ shouldUseExternalPopupMenus = useExternalPopupMenus;
}
void WebView::updateVisitedLinkState(unsigned long long linkHash)
@@ -183,24 +237,23 @@ void WebView::resetVisitedLinkState()
void WebView::willEnterModalLoop()
{
- // It is not valid to nest more than once.
- ASSERT(!pageGroupLoadDeferrer);
-
PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
ASSERT(pageGroup);
- ASSERT(!pageGroup->pages().isEmpty());
- // Pick any page in the page group since we are deferring all pages.
- pageGroupLoadDeferrer = new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true);
+ if (pageGroup->pages().isEmpty())
+ pageGroupLoadDeferrerStack.append(static_cast<PageGroupLoadDeferrer*>(0));
+ else {
+ // Pick any page in the page group since we are deferring all pages.
+ pageGroupLoadDeferrerStack.append(new PageGroupLoadDeferrer(*pageGroup->pages().begin(), true));
+ }
}
void WebView::didExitModalLoop()
{
- // The embedder must have called willEnterNestedEventLoop.
- ASSERT(pageGroupLoadDeferrer);
+ ASSERT(pageGroupLoadDeferrerStack.size());
- delete pageGroupLoadDeferrer;
- pageGroupLoadDeferrer = 0;
+ delete pageGroupLoadDeferrerStack.last();
+ pageGroupLoadDeferrerStack.removeLast();
}
void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
@@ -216,7 +269,7 @@ void WebViewImpl::initializeMainFrame(WebFrameClient* frameClient)
SecurityOrigin::setLocalLoadPolicy(SecurityOrigin::AllowLocalLoadsForLocalOnly);
}
-WebViewImpl::WebViewImpl(WebViewClient* client)
+WebViewImpl::WebViewImpl(WebViewClient* client, WebDevToolsAgentClient* devToolsClient)
: m_client(client)
, m_backForwardListClientImpl(this)
, m_chromeClientImpl(this)
@@ -229,6 +282,8 @@ WebViewImpl::WebViewImpl(WebViewClient* client)
, m_newNavigationLoader(0)
#endif
, m_zoomLevel(0)
+ , m_minimumZoomLevel(zoomFactorToZoomLevel(minTextSizeMultiplier))
+ , m_maximumZoomLevel(zoomFactorToZoomLevel(maxTextSizeMultiplier))
, m_contextMenuAllowed(false)
, m_doingDragAndDrop(false)
, m_ignoreInputEvents(false)
@@ -240,31 +295,51 @@ WebViewImpl::WebViewImpl(WebViewClient* client)
, m_dropEffect(DropEffectDefault)
, m_operationsAllowed(WebDragOperationNone)
, m_dragOperation(WebDragOperationNone)
- , m_suggestionsPopupShowing(false)
- , m_suggestionsPopupClient(0)
- , m_suggestionsPopup(0)
+ , m_autoFillPopupShowing(false)
+ , m_autoFillPopupClient(0)
+ , m_autoFillPopup(0)
, m_isTransparent(false)
, m_tabsToLinks(false)
+ , m_dragScrollTimer(new DragScrollTimer())
+#if USE(ACCELERATED_COMPOSITING)
+ , m_layerRenderer(0)
+ , m_isAcceleratedCompositingActive(false)
+ , m_compositorCreationFailed(false)
+#endif
+#if ENABLE(INPUT_SPEECH)
+ , m_speechInputClient(SpeechInputClientImpl::create(client))
+#endif
+ , m_deviceOrientationClientProxy(new DeviceOrientationClientProxy(client ? client->deviceOrientationClient() : 0))
{
// WebKit/win/WebView.cpp does the same thing, except they call the
// KJS specific wrapper around this method. We need to have threading
// initialized because CollatorICU requires it.
WTF::initializeThreading();
+ WTF::initializeMainThread();
// set to impossible point so we always get the first mouse pos
m_lastMousePosition = WebPoint(-1, -1);
- // the page will take ownership of the various clients
- m_page.set(new Page(&m_chromeClientImpl,
- &m_contextMenuClientImpl,
- &m_editorClientImpl,
- &m_dragClientImpl,
- &m_inspectorClientImpl,
- 0,
- 0));
+ if (devToolsClient)
+ m_devToolsAgent = new WebDevToolsAgentImpl(this, devToolsClient);
+
+ Page::PageClients pageClients;
+ pageClients.chromeClient = &m_chromeClientImpl;
+ pageClients.contextMenuClient = &m_contextMenuClientImpl;
+ pageClients.editorClient = &m_editorClientImpl;
+ pageClients.dragClient = &m_dragClientImpl;
+ pageClients.inspectorClient = &m_inspectorClientImpl;
+#if ENABLE(INPUT_SPEECH)
+ pageClients.speechInputClient = m_speechInputClient.get();
+#endif
+ pageClients.deviceOrientationClient = m_deviceOrientationClientProxy.get();
+
+ m_page.set(new Page(pageClients));
- m_page->backForwardList()->setClient(&m_backForwardListClientImpl);
+ static_cast<BackForwardListImpl*>(m_page->backForwardList())->setClient(&m_backForwardListClientImpl);
m_page->setGroupName(pageGroupName);
+
+ m_inspectorSettingsMap.set(new SettingsMap);
}
WebViewImpl::~WebViewImpl()
@@ -326,19 +401,34 @@ void WebViewImpl::mouseDown(const WebMouseEvent& event)
if (!mainFrameImpl() || !mainFrameImpl()->frameView())
return;
+ // If there is a select popup open, close it as the user is clicking on
+ // the page (outside of the popup). We also save it so we can prevent a
+ // click on the select element from immediately reopening the popup.
+ RefPtr<WebCore::PopupContainer> selectPopup;
+ if (event.button == WebMouseEvent::ButtonLeft) {
+ selectPopup = m_selectPopup;
+ hideSelectPopup();
+ ASSERT(!m_selectPopup);
+ }
+
m_lastMouseDownPoint = WebPoint(event.x, event.y);
- // If a text field that has focus is clicked again, we should display the
- // suggestions popup.
RefPtr<Node> clickedNode;
if (event.button == WebMouseEvent::ButtonLeft) {
+ IntPoint point(event.x, event.y);
+ point = m_page->mainFrame()->view()->windowToContents(point);
+ HitTestResult result(m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false));
+ Node* hitNode = result.innerNonSharedNode();
+
+ // Take capture on a mouse down on a plugin so we can send it mouse events.
+ if (hitNode && hitNode->renderer() && hitNode->renderer()->isEmbeddedObject())
+ m_mouseCaptureNode = hitNode;
+
+ // If a text field that has focus is clicked again, we should display the
+ // AutoFill popup.
RefPtr<Node> focusedNode = focusedWebCoreNode();
if (focusedNode.get() && toHTMLInputElement(focusedNode.get())) {
- IntPoint point(event.x, event.y);
- point = m_page->mainFrame()->view()->windowToContents(point);
- HitTestResult result(point);
- result = m_page->mainFrame()->eventHandler()->hitTestResultAtPoint(point, false);
- if (result.innerNonSharedNode() == focusedNode) {
+ if (hitNode == focusedNode) {
// Already focused text field was clicked, let's remember this. If
// focus has not changed after the mouse event is processed, we'll
// trigger the autocomplete.
@@ -347,14 +437,23 @@ void WebViewImpl::mouseDown(const WebMouseEvent& event)
}
}
+ mainFrameImpl()->frame()->loader()->resetMultipleFormSubmissionProtection();
+
mainFrameImpl()->frame()->eventHandler()->handleMousePressEvent(
PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
if (clickedNode.get() && clickedNode == focusedWebCoreNode()) {
- // Focus has not changed, show the suggestions popup.
+ // Focus has not changed, show the AutoFill popup.
static_cast<EditorClientImpl*>(m_page->editorClient())->
showFormAutofillForNode(clickedNode.get());
}
+ if (m_selectPopup && m_selectPopup == selectPopup) {
+ // That click triggered a select popup which is the same as the one that
+ // was showing before the click. It means the user clicked the select
+ // while the popup was showing, and as a result we first closed then
+ // immediately reopened the select popup. It needs to be closed.
+ hideSelectPopup();
+ }
// Dispatch the contextmenu event regardless of if the click was swallowed.
// On Windows, we handle it on mouse up, not down.
@@ -363,7 +462,7 @@ void WebViewImpl::mouseDown(const WebMouseEvent& event)
|| (event.button == WebMouseEvent::ButtonLeft
&& event.modifiers & WebMouseEvent::ControlKey))
mouseContextMenu(event);
-#elif OS(LINUX)
+#elif OS(LINUX) || OS(FREEBSD)
if (event.button == WebMouseEvent::ButtonRight)
mouseContextMenu(event);
#endif
@@ -402,7 +501,7 @@ void WebViewImpl::mouseUp(const WebMouseEvent& event)
if (!mainFrameImpl() || !mainFrameImpl()->frameView())
return;
-#if OS(LINUX)
+#if OS(LINUX) || OS(FREEBSD)
// If the event was a middle click, attempt to copy text into the focused
// frame. We execute this before we let the page have a go at the event
// because the page may change what is focused during in its event handler.
@@ -426,7 +525,7 @@ void WebViewImpl::mouseUp(const WebMouseEvent& event)
IntPoint contentPoint = view->windowToContents(clickPoint);
HitTestResult hitTestResult = focused->eventHandler()->hitTestResultAtPoint(contentPoint, false, false, ShouldHitTestScrollbars);
// We don't want to send a paste when middle clicking a scroll bar or a
- // link (which will navigate later in the code). The main scrollbars
+ // link (which will navigate later in the code). The main scrollbars
// have to be handled separately.
if (!hitTestResult.scrollbar() && !hitTestResult.isLiveLink() && focused && !view->scrollbarAtPoint(clickPoint)) {
Editor* editor = focused->editor();
@@ -439,7 +538,6 @@ void WebViewImpl::mouseUp(const WebMouseEvent& event)
}
#endif
- mouseCaptureLost();
mainFrameImpl()->frame()->eventHandler()->handleMouseReleaseEvent(
PlatformMouseEventBuilder(mainFrameImpl()->frameView(), event));
@@ -451,10 +549,10 @@ void WebViewImpl::mouseUp(const WebMouseEvent& event)
#endif
}
-void WebViewImpl::mouseWheel(const WebMouseWheelEvent& event)
+bool WebViewImpl::mouseWheel(const WebMouseWheelEvent& event)
{
PlatformWheelEventBuilder platformEvent(mainFrameImpl()->frameView(), event);
- mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent);
+ return mainFrameImpl()->frame()->eventHandler()->handleWheelEvent(platformEvent);
}
bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
@@ -471,6 +569,10 @@ bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
// event.
m_suppressNextKeypressEvent = false;
+ // Give any select popup a chance at consuming the key event.
+ if (selectPopupHandleKeyEvent(event))
+ return true;
+
// Give Autocomplete a chance to consume the key events it is interested in.
if (autocompleteHandleKeyEvent(event))
return true;
@@ -483,21 +585,21 @@ bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
if (!handler)
return keyEventDefault(event);
-#if OS(WINDOWS) || OS(LINUX)
+#if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
const WebInputEvent::Type contextMenuTriggeringEventType =
#if OS(WINDOWS)
WebInputEvent::KeyUp;
-#elif OS(LINUX)
+#elif OS(LINUX) || OS(FREEBSD)
WebInputEvent::RawKeyDown;
#endif
- if (((!event.modifiers && (event.windowsKeyCode == VKEY_APPS))
- || ((event.modifiers == WebInputEvent::ShiftKey) && (event.windowsKeyCode == VKEY_F10)))
- && event.type == contextMenuTriggeringEventType) {
+ bool isUnmodifiedMenuKey = !(event.modifiers & WebInputEvent::InputModifiers) && event.windowsKeyCode == VKEY_APPS;
+ bool isShiftF10 = event.modifiers == WebInputEvent::ShiftKey && event.windowsKeyCode == VKEY_F10;
+ if ((isUnmodifiedMenuKey || isShiftF10) && event.type == contextMenuTriggeringEventType) {
sendContextMenuEvent(event);
return true;
}
-#endif
+#endif // OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
// It's not clear if we should continue after detecting a capslock keypress.
// I'll err on the side of continuing, which is the pre-existing behaviour.
@@ -507,17 +609,30 @@ bool WebViewImpl::keyEvent(const WebKeyboardEvent& event)
PlatformKeyboardEventBuilder evt(event);
if (handler->keyEvent(evt)) {
- if (WebInputEvent::RawKeyDown == event.type)
- m_suppressNextKeypressEvent = true;
+ if (WebInputEvent::RawKeyDown == event.type) {
+ // Suppress the next keypress event unless the focused node is a plug-in node.
+ // (Flash needs these keypress events to handle non-US keyboards.)
+ Node* node = frame->document()->focusedNode();
+ if (!node || !node->renderer() || !node->renderer()->isEmbeddedObject())
+ m_suppressNextKeypressEvent = true;
+ }
return true;
}
return keyEventDefault(event);
}
+bool WebViewImpl::selectPopupHandleKeyEvent(const WebKeyboardEvent& event)
+{
+ if (!m_selectPopup)
+ return false;
+
+ return m_selectPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event));
+}
+
bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
{
- if (!m_suggestionsPopupShowing
+ if (!m_autoFillPopupShowing
// Home and End should be left to the text field to process.
|| event.windowsKeyCode == VKEY_HOME
|| event.windowsKeyCode == VKEY_END)
@@ -525,7 +640,7 @@ bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
// Pressing delete triggers the removal of the selected suggestion from the DB.
if (event.windowsKeyCode == VKEY_DELETE
- && m_suggestionsPopup->selectedIndex() != -1) {
+ && m_autoFillPopup->selectedIndex() != -1) {
Node* node = focusedWebCoreNode();
if (!node || (node->nodeType() != Node::ELEMENT_NODE)) {
ASSERT_NOT_REACHED();
@@ -537,22 +652,25 @@ bool WebViewImpl::autocompleteHandleKeyEvent(const WebKeyboardEvent& event)
return false;
}
- int selectedIndex = m_suggestionsPopup->selectedIndex();
- HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(element);
- WebString name = inputElement->name();
- WebString value = m_autocompletePopupClient->itemText(selectedIndex);
+ int selectedIndex = m_autoFillPopup->selectedIndex();
+
+ if (!m_autoFillPopupClient->canRemoveSuggestionAtIndex(selectedIndex))
+ return false;
+
+ WebString name = WebInputElement(static_cast<HTMLInputElement*>(element)).nameForAutofill();
+ WebString value = m_autoFillPopupClient->itemText(selectedIndex);
m_client->removeAutofillSuggestions(name, value);
// Update the entries in the currently showing popup to reflect the
// deletion.
- m_autocompletePopupClient->removeSuggestionAtIndex(selectedIndex);
- refreshSuggestionsPopup();
+ m_autoFillPopupClient->removeSuggestionAtIndex(selectedIndex);
+ refreshAutoFillPopup();
return false;
}
- if (!m_suggestionsPopup->isInterestedInEventForKey(event.windowsKeyCode))
+ if (!m_autoFillPopup->isInterestedInEventForKey(event.windowsKeyCode))
return false;
- if (m_suggestionsPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
+ if (m_autoFillPopup->handleKeyEvent(PlatformKeyboardEventBuilder(event))) {
// We need to ignore the next Char event after this otherwise pressing
// enter when selecting an item in the menu will go to the page.
if (WebInputEvent::RawKeyDown == event.type)
@@ -604,62 +722,21 @@ bool WebViewImpl::charEvent(const WebKeyboardEvent& event)
return true;
}
-// The WebViewImpl::SendContextMenuEvent function is based on the Webkit
-// function
-// bool WebView::handleContextMenuEvent(WPARAM wParam, LPARAM lParam) in
-// webkit\webkit\win\WebView.cpp. The only significant change in this
-// function is the code to convert from a Keyboard event to the Right
-// Mouse button up event.
-//
-// This function is an ugly copy/paste and should be cleaned up when the
-// WebKitWin version is cleaned: https://bugs.webkit.org/show_bug.cgi?id=20438
-#if OS(WINDOWS) || OS(LINUX)
-// FIXME: implement on Mac
-bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
+#if ENABLE(TOUCH_EVENTS)
+bool WebViewImpl::touchEvent(const WebTouchEvent& event)
{
- static const int kContextMenuMargin = 1;
- Frame* mainFrameImpl = page()->mainFrame();
- FrameView* view = mainFrameImpl->view();
- if (!view)
+ if (!mainFrameImpl() || !mainFrameImpl()->frameView())
return false;
- IntPoint coords(-1, -1);
-#if OS(WINDOWS)
- int rightAligned = ::GetSystemMetrics(SM_MENUDROPALIGNMENT);
-#else
- int rightAligned = 0;
+ PlatformTouchEventBuilder touchEventBuilder(mainFrameImpl()->frameView(), event);
+ return mainFrameImpl()->frame()->eventHandler()->handleTouchEvent(touchEventBuilder);
+}
#endif
- IntPoint location;
-
-
- Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
- Node* focusedNode = focusedFrame->document()->focusedNode();
- Position start = mainFrameImpl->selection()->selection().start();
-
- if (focusedFrame->editor() && focusedFrame->editor()->canEdit() && start.node()) {
- RenderObject* renderer = start.node()->renderer();
- if (!renderer)
- return false;
-
- RefPtr<Range> selection = mainFrameImpl->selection()->toNormalizedRange();
- IntRect firstRect = mainFrameImpl->firstRectForRange(selection.get());
-
- int x = rightAligned ? firstRect.right() : firstRect.x();
- location = IntPoint(x, firstRect.bottom());
- } else if (focusedNode)
- location = focusedNode->getRect().bottomLeft();
- else {
- location = IntPoint(
- rightAligned ? view->contentsWidth() - kContextMenuMargin : kContextMenuMargin,
- kContextMenuMargin);
- }
-
- location = view->contentsToWindow(location);
- // FIXME: The IntSize(0, -1) is a hack to get the hit-testing to result in
- // the selected element. Ideally we'd have the position of a context menu
- // event be separate from its target node.
- coords = location + IntSize(0, -1);
+#if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
+// Mac has no way to open a context menu based on a keyboard event.
+bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
+{
// The contextMenuController() holds onto the last context menu that was
// popped up on the page until a new one is created. We need to clear
// this menu before propagating the event through the DOM so that we can
@@ -668,17 +745,9 @@ bool WebViewImpl::sendContextMenuEvent(const WebKeyboardEvent& event)
// not run.
page()->contextMenuController()->clearContextMenu();
- focusedFrame->view()->setCursor(pointerCursor());
- WebMouseEvent mouseEvent;
- mouseEvent.button = WebMouseEvent::ButtonRight;
- mouseEvent.x = coords.x();
- mouseEvent.y = coords.y();
- mouseEvent.type = WebInputEvent::MouseUp;
-
- PlatformMouseEventBuilder platformEvent(view, mouseEvent);
-
m_contextMenuAllowed = true;
- bool handled = focusedFrame->eventHandler()->sendContextMenuEvent(platformEvent);
+ Frame* focusedFrame = page()->focusController()->focusedOrMainFrame();
+ bool handled = focusedFrame->eventHandler()->sendContextMenuEventForKey();
m_contextMenuAllowed = false;
return handled;
}
@@ -733,45 +802,59 @@ bool WebViewImpl::scrollViewWithKeyboard(int keyCode, int modifiers)
{
ScrollDirection scrollDirection;
ScrollGranularity scrollGranularity;
+ if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity))
+ return false;
+ return propagateScroll(scrollDirection, scrollGranularity);
+}
+bool WebViewImpl::mapKeyCodeForScroll(int keyCode,
+ WebCore::ScrollDirection* scrollDirection,
+ WebCore::ScrollGranularity* scrollGranularity)
+{
switch (keyCode) {
case VKEY_LEFT:
- scrollDirection = ScrollLeft;
- scrollGranularity = ScrollByLine;
+ *scrollDirection = ScrollLeft;
+ *scrollGranularity = ScrollByLine;
break;
case VKEY_RIGHT:
- scrollDirection = ScrollRight;
- scrollGranularity = ScrollByLine;
+ *scrollDirection = ScrollRight;
+ *scrollGranularity = ScrollByLine;
break;
case VKEY_UP:
- scrollDirection = ScrollUp;
- scrollGranularity = ScrollByLine;
+ *scrollDirection = ScrollUp;
+ *scrollGranularity = ScrollByLine;
break;
case VKEY_DOWN:
- scrollDirection = ScrollDown;
- scrollGranularity = ScrollByLine;
+ *scrollDirection = ScrollDown;
+ *scrollGranularity = ScrollByLine;
break;
case VKEY_HOME:
- scrollDirection = ScrollUp;
- scrollGranularity = ScrollByDocument;
+ *scrollDirection = ScrollUp;
+ *scrollGranularity = ScrollByDocument;
break;
case VKEY_END:
- scrollDirection = ScrollDown;
- scrollGranularity = ScrollByDocument;
+ *scrollDirection = ScrollDown;
+ *scrollGranularity = ScrollByDocument;
break;
case VKEY_PRIOR: // page up
- scrollDirection = ScrollUp;
- scrollGranularity = ScrollByPage;
+ *scrollDirection = ScrollUp;
+ *scrollGranularity = ScrollByPage;
break;
case VKEY_NEXT: // page down
- scrollDirection = ScrollDown;
- scrollGranularity = ScrollByPage;
+ *scrollDirection = ScrollDown;
+ *scrollGranularity = ScrollByPage;
break;
default:
return false;
}
- return propagateScroll(scrollDirection, scrollGranularity);
+ return true;
+}
+
+void WebViewImpl::hideSelectPopup()
+{
+ if (m_selectPopup.get())
+ m_selectPopup->hidePopup();
}
bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
@@ -781,18 +864,39 @@ bool WebViewImpl::propagateScroll(ScrollDirection scrollDirection,
if (!frame)
return false;
- bool scrollHandled =
- frame->eventHandler()->scrollOverflow(scrollDirection,
- scrollGranularity);
+ bool scrollHandled = frame->eventHandler()->scrollOverflow(scrollDirection, scrollGranularity);
Frame* currentFrame = frame;
while (!scrollHandled && currentFrame) {
- scrollHandled = currentFrame->view()->scroll(scrollDirection,
- scrollGranularity);
+ scrollHandled = currentFrame->view()->scroll(scrollDirection, scrollGranularity);
currentFrame = currentFrame->tree()->parent();
}
return scrollHandled;
}
+void WebViewImpl::popupOpened(WebCore::PopupContainer* popupContainer)
+{
+ if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
+ ASSERT(!m_selectPopup);
+ m_selectPopup = popupContainer;
+ }
+}
+
+void WebViewImpl::popupClosed(WebCore::PopupContainer* popupContainer)
+{
+ if (popupContainer->popupType() == WebCore::PopupContainer::Select) {
+ ASSERT(m_selectPopup.get());
+ m_selectPopup = 0;
+ }
+}
+
+void WebViewImpl::hideAutoFillPopup()
+{
+ if (m_autoFillPopupShowing) {
+ m_autoFillPopup->hidePopup();
+ m_autoFillPopupShowing = false;
+ }
+}
+
Frame* WebViewImpl::focusedWebCoreFrame()
{
return m_page.get() ? m_page->focusController()->focusedOrMainFrame() : 0;
@@ -846,8 +950,20 @@ void WebViewImpl::resize(const WebSize& newSize)
if (m_client) {
WebRect damagedRect(0, 0, m_size.width, m_size.height);
- m_client->didInvalidateRect(damagedRect);
+ if (isAcceleratedCompositingActive()) {
+#if USE(ACCELERATED_COMPOSITING)
+ invalidateRootLayerRect(damagedRect);
+#endif
+ } else
+ m_client->didInvalidateRect(damagedRect);
+ }
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_layerRenderer && isAcceleratedCompositingActive()) {
+ m_layerRenderer->resizeOnscreenContent(IntSize(std::max(1, m_size.width),
+ std::max(1, m_size.height)));
}
+#endif
}
void WebViewImpl::layout()
@@ -871,19 +987,99 @@ void WebViewImpl::layout()
}
}
+#if USE(ACCELERATED_COMPOSITING)
+void WebViewImpl::doPixelReadbackToCanvas(WebCanvas* canvas, const IntRect& rect)
+{
+ ASSERT(rect.right() <= m_layerRenderer->rootLayerTextureSize().width()
+ && rect.bottom() <= m_layerRenderer->rootLayerTextureSize().height());
+
+#if PLATFORM(SKIA)
+ PlatformContextSkia context(canvas);
+
+ // PlatformGraphicsContext is actually a pointer to PlatformContextSkia
+ GraphicsContext gc(reinterpret_cast<PlatformGraphicsContext*>(&context));
+ int bitmapHeight = canvas->getDevice()->accessBitmap(false).height();
+#elif PLATFORM(CG)
+ GraphicsContext gc(canvas);
+ int bitmapHeight = CGBitmapContextGetHeight(reinterpret_cast<CGContextRef>(canvas));
+#else
+ notImplemented();
+#endif
+ // Compute rect to sample from inverted GPU buffer.
+ IntRect invertRect(rect.x(), bitmapHeight - rect.bottom(), rect.width(), rect.height());
+
+ OwnPtr<ImageBuffer> imageBuffer(ImageBuffer::create(rect.size()));
+ RefPtr<ImageData> imageData(ImageData::create(rect.width(), rect.height()));
+ if (imageBuffer.get() && imageData.get()) {
+ m_layerRenderer->getFramebufferPixels(imageData->data()->data()->data(), invertRect);
+ imageBuffer->putPremultipliedImageData(imageData.get(), IntRect(IntPoint(), rect.size()), IntPoint());
+ gc.save();
+ gc.translate(FloatSize(0.0f, bitmapHeight));
+ gc.scale(FloatSize(1.0f, -1.0f));
+ // Use invertRect in next line, so that transform above inverts it back to
+ // desired destination rect.
+ gc.drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, invertRect.location());
+ gc.restore();
+ }
+}
+#endif
+
void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect)
{
- WebFrameImpl* webframe = mainFrameImpl();
- if (webframe)
- webframe->paint(canvas, rect);
+ if (isAcceleratedCompositingActive()) {
+#if USE(ACCELERATED_COMPOSITING)
+ doComposite();
+
+ // If a canvas was passed in, we use it to grab a copy of the
+ // freshly-rendered pixels.
+ if (canvas) {
+ // Clip rect to the confines of the rootLayerTexture.
+ IntRect resizeRect(rect);
+ resizeRect.intersect(IntRect(IntPoint(), m_layerRenderer->rootLayerTextureSize()));
+ doPixelReadbackToCanvas(canvas, resizeRect);
+ }
+#endif
+ } else {
+ WebFrameImpl* webframe = mainFrameImpl();
+ if (webframe)
+ webframe->paint(canvas, rect);
+ }
+}
+
+void WebViewImpl::themeChanged()
+{
+ if (!page())
+ return;
+ FrameView* view = page()->mainFrame()->view();
+
+ WebRect damagedRect(0, 0, m_size.width, m_size.height);
+ view->invalidateRect(damagedRect);
+}
+
+void WebViewImpl::composite(bool finish)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ doComposite();
+
+ // Finish if requested.
+ if (finish)
+ m_layerRenderer->finish();
+
+ // Put result onscreen.
+ m_layerRenderer->present();
+
+ GraphicsContext3D* context = m_layerRenderer->context();
+ if (context->getExtensions()->getGraphicsResetStatusARB() != GraphicsContext3D::NO_ERROR)
+ reallocateRenderer();
+#endif
}
-// FIXME: m_currentInputEvent should be removed once ChromeClient::show() can
-// get the current-event information from WebCore.
const WebInputEvent* WebViewImpl::m_currentInputEvent = 0;
bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
{
+ UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
+
// If we've started a drag and drop operation, ignore input events until
// we're done.
if (m_doingDragAndDrop)
@@ -892,14 +1088,41 @@ bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
if (m_ignoreInputEvents)
return true;
- // FIXME: Remove m_currentInputEvent.
- // This only exists to allow ChromeClient::show() to know which mouse button
- // triggered a window.open event.
- // Safari must perform a similar hack, ours is in our WebKit glue layer
- // theirs is in the application. This should go when WebCore can be fixed
- // to pass more event information to ChromeClient::show()
m_currentInputEvent = &inputEvent;
+ if (m_mouseCaptureNode.get() && WebInputEvent::isMouseEventType(inputEvent.type)) {
+ // Save m_mouseCaptureNode since mouseCaptureLost() will clear it.
+ RefPtr<Node> node = m_mouseCaptureNode;
+
+ // Not all platforms call mouseCaptureLost() directly.
+ if (inputEvent.type == WebInputEvent::MouseUp)
+ mouseCaptureLost();
+
+ AtomicString eventType;
+ switch (inputEvent.type) {
+ case WebInputEvent::MouseMove:
+ eventType = eventNames().mousemoveEvent;
+ break;
+ case WebInputEvent::MouseLeave:
+ eventType = eventNames().mouseoutEvent;
+ break;
+ case WebInputEvent::MouseDown:
+ eventType = eventNames().mousedownEvent;
+ break;
+ case WebInputEvent::MouseUp:
+ eventType = eventNames().mouseupEvent;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ node->dispatchMouseEvent(
+ PlatformMouseEventBuilder(mainFrameImpl()->frameView(), *static_cast<const WebMouseEvent*>(&inputEvent)),
+ eventType, static_cast<const WebMouseEvent*>(&inputEvent)->clickCount);
+ m_currentInputEvent = 0;
+ return true;
+ }
+
bool handled = true;
// FIXME: WebKit seems to always return false on mouse events processing
@@ -915,7 +1138,7 @@ bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
break;
case WebInputEvent::MouseWheel:
- mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
+ handled = mouseWheel(*static_cast<const WebMouseWheelEvent*>(&inputEvent));
break;
case WebInputEvent::MouseDown:
@@ -936,6 +1159,15 @@ bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
handled = charEvent(*static_cast<const WebKeyboardEvent*>(&inputEvent));
break;
+#if ENABLE(TOUCH_EVENTS)
+ case WebInputEvent::TouchStart:
+ case WebInputEvent::TouchMove:
+ case WebInputEvent::TouchEnd:
+ case WebInputEvent::TouchCancel:
+ handled = touchEvent(*static_cast<const WebTouchEvent*>(&inputEvent));
+ break;
+#endif
+
default:
handled = false;
}
@@ -947,6 +1179,7 @@ bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent)
void WebViewImpl::mouseCaptureLost()
{
+ m_mouseCaptureNode = 0;
}
void WebViewImpl::setFocus(bool enable)
@@ -981,7 +1214,8 @@ void WebViewImpl::setFocus(bool enable)
}
m_imeAcceptEvents = true;
} else {
- hideSuggestionsPopup();
+ hideAutoFillPopup();
+ hideSelectPopup();
// Clear focus on the currently focused frame if any.
if (!m_page.get())
@@ -1002,11 +1236,11 @@ void WebViewImpl::setFocus(bool enable)
}
}
-bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command,
- int cursorPosition,
- int targetStart,
- int targetEnd,
- const WebString& imeString)
+bool WebViewImpl::setComposition(
+ const WebString& text,
+ const WebVector<WebCompositionUnderline>& underlines,
+ int selectionStart,
+ int selectionEnd)
{
Frame* focused = focusedWebCoreFrame();
if (!focused || !m_imeAcceptEvents)
@@ -1014,13 +1248,12 @@ bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command,
Editor* editor = focused->editor();
if (!editor)
return false;
- if (!editor->canEdit()) {
- // The input focus has been moved to another WebWidget object.
- // We should use this |editor| object only to complete the ongoing
- // composition.
- if (!editor->hasComposition())
- return false;
- }
+
+ // The input focus has been moved to another WebWidget object.
+ // We should use this |editor| object only to complete the ongoing
+ // composition.
+ if (!editor->canEdit() && !editor->hasComposition())
+ return false;
// We should verify the parent node of this IME composition node are
// editable because JavaScript may delete a parent node of the composition
@@ -1033,7 +1266,9 @@ bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command,
return false;
}
- if (command == WebCompositionCommandDiscard) {
+ // If we're not going to fire a keypress event, then the keydown event was
+ // canceled. In that case, cancel any existing composition.
+ if (text.isEmpty() || m_suppressNextKeypressEvent) {
// A browser process sent an IPC message which does not contain a valid
// string, which means an ongoing composition has been canceled.
// If the ongoing composition has been canceled, replace the ongoing
@@ -1041,81 +1276,102 @@ bool WebViewImpl::handleCompositionEvent(WebCompositionCommand command,
String emptyString;
Vector<CompositionUnderline> emptyUnderlines;
editor->setComposition(emptyString, emptyUnderlines, 0, 0);
- } else {
- // A browser process sent an IPC message which contains a string to be
- // displayed in this Editor object.
- // To display the given string, set the given string to the
- // m_compositionNode member of this Editor object and display it.
- if (targetStart < 0)
- targetStart = 0;
- if (targetEnd < 0)
- targetEnd = static_cast<int>(imeString.length());
- String compositionString(imeString);
- // Create custom underlines.
- // To emphasize the selection, the selected region uses a solid black
- // for its underline while other regions uses a pale gray for theirs.
- Vector<CompositionUnderline> underlines(3);
- underlines[0].startOffset = 0;
- underlines[0].endOffset = targetStart;
- underlines[0].thick = true;
- underlines[0].color.setRGB(0xd3, 0xd3, 0xd3);
- underlines[1].startOffset = targetStart;
- underlines[1].endOffset = targetEnd;
- underlines[1].thick = true;
- underlines[1].color.setRGB(0x00, 0x00, 0x00);
- underlines[2].startOffset = targetEnd;
- underlines[2].endOffset = static_cast<int>(imeString.length());
- underlines[2].thick = true;
- underlines[2].color.setRGB(0xd3, 0xd3, 0xd3);
- // When we use custom underlines, WebKit ("InlineTextBox.cpp" Line 282)
- // prevents from writing a text in between 'selectionStart' and
- // 'selectionEnd' somehow.
- // Therefore, we use the 'cursorPosition' for these arguments so that
- // there are not any characters in the above region.
- editor->setComposition(compositionString, underlines,
- cursorPosition, cursorPosition);
- // The given string is a result string, which means the ongoing
- // composition has been completed. I have to call the
- // Editor::confirmCompletion() and complete this composition.
- if (command == WebCompositionCommandConfirm)
- editor->confirmComposition();
+ return text.isEmpty();
}
+ // When the range of composition underlines overlap with the range between
+ // selectionStart and selectionEnd, WebKit somehow won't paint the selection
+ // at all (see InlineTextBox::paint() function in InlineTextBox.cpp).
+ // But the selection range actually takes effect.
+ editor->setComposition(String(text),
+ CompositionUnderlineVectorBuilder(underlines),
+ selectionStart, selectionEnd);
+
return editor->hasComposition();
}
-bool WebViewImpl::queryCompositionStatus(bool* enableIME, WebRect* caretRect)
+bool WebViewImpl::confirmComposition()
+{
+ Frame* focused = focusedWebCoreFrame();
+ if (!focused || !m_imeAcceptEvents)
+ return false;
+ Editor* editor = focused->editor();
+ if (!editor || !editor->hasComposition())
+ return false;
+
+ // We should verify the parent node of this IME composition node are
+ // editable because JavaScript may delete a parent node of the composition
+ // node. In this case, WebKit crashes while deleting texts from the parent
+ // node, which doesn't exist any longer.
+ PassRefPtr<Range> range = editor->compositionRange();
+ if (range) {
+ const Node* node = range->startPosition().node();
+ if (!node || !node->isContentEditable())
+ return false;
+ }
+
+ editor->confirmComposition();
+ return true;
+}
+
+WebTextInputType WebViewImpl::textInputType()
{
- // Store whether the selected node needs IME and the caret rectangle.
- // This process consists of the following four steps:
- // 1. Retrieve the selection controller of the focused frame;
- // 2. Retrieve the caret rectangle from the controller;
- // 3. Convert the rectangle, which is relative to the parent view, to the
- // one relative to the client window, and;
- // 4. Store the converted rectangle.
+ WebTextInputType type = WebTextInputTypeNone;
const Frame* focused = focusedWebCoreFrame();
if (!focused)
- return false;
+ return type;
const Editor* editor = focused->editor();
if (!editor || !editor->canEdit())
- return false;
+ return type;
SelectionController* controller = focused->selection();
if (!controller)
- return false;
+ return type;
const Node* node = controller->start().node();
if (!node)
- return false;
+ return type;
+
+ // FIXME: Support more text input types when necessary, eg. Number,
+ // Date, Email, URL, etc.
+ if (controller->isInPasswordField())
+ type = WebTextInputTypePassword;
+ else if (node->shouldUseInputMethod())
+ type = WebTextInputTypeText;
- *enableIME = node->shouldUseInputMethod() && !controller->isInPasswordField();
- const FrameView* view = node->document()->view();
+ return type;
+}
+
+WebRect WebViewImpl::caretOrSelectionBounds()
+{
+ WebRect rect;
+ const Frame* focused = focusedWebCoreFrame();
+ if (!focused)
+ return rect;
+
+ SelectionController* controller = focused->selection();
+ if (!controller)
+ return rect;
+
+ const FrameView* view = focused->view();
if (!view)
- return false;
+ return rect;
- *caretRect = view->contentsToWindow(controller->absoluteCaretBounds());
- return true;
+ const Node* node = controller->start().node();
+ if (!node || !node->renderer())
+ return rect;
+
+ if (controller->isCaret())
+ rect = view->contentsToWindow(controller->absoluteCaretBounds());
+ else if (controller->isRange()) {
+ node = controller->end().node();
+ if (!node || !node->renderer())
+ return rect;
+ RefPtr<Range> range = controller->toNormalizedRange();
+ rect = view->contentsToWindow(focused->editor()->firstRectForRange(range.get()));
+ }
+ return rect;
}
void WebViewImpl::setTextDirection(WebTextDirection direction)
@@ -1151,6 +1407,15 @@ void WebViewImpl::setTextDirection(WebTextDirection direction)
}
}
+bool WebViewImpl::isAcceleratedCompositingActive() const
+{
+#if USE(ACCELERATED_COMPOSITING)
+ return m_isAcceleratedCompositingActive;
+#else
+ return false;
+#endif
+}
+
// WebView --------------------------------------------------------------------
WebSettings* WebViewImpl::settings()
@@ -1166,7 +1431,7 @@ WebString WebViewImpl::pageEncoding() const
if (!m_page.get())
return WebString();
- return m_page->mainFrame()->loader()->encoding();
+ return m_page->mainFrame()->loader()->writer()->encoding();
}
void WebViewImpl::setPageEncoding(const WebString& encodingName)
@@ -1191,7 +1456,7 @@ bool WebViewImpl::dispatchBeforeUnloadEvent()
if (!frame)
return true;
- return frame->shouldClose();
+ return frame->loader()->shouldClose();
}
void WebViewImpl::dispatchUnloadEvent()
@@ -1249,6 +1514,10 @@ void WebViewImpl::setInitialFocus(bool reverse)
keyboardEvent.windowsKeyCode = 0x09;
PlatformKeyboardEventBuilder platformEvent(keyboardEvent);
RefPtr<KeyboardEvent> webkitEvent = KeyboardEvent::create(platformEvent, 0);
+
+ Frame* frame = page()->focusController()->focusedOrMainFrame();
+ if (Document* document = frame->document())
+ document->setFocusedNode(0);
page()->focusController()->setInitialFocus(
reverse ? FocusDirectionBackward : FocusDirectionForward,
webkitEvent.get());
@@ -1288,25 +1557,71 @@ void WebViewImpl::clearFocusedNode()
}
}
-int WebViewImpl::zoomLevel()
+void WebViewImpl::scrollFocusedNodeIntoView()
+{
+ Node* focusedNode = focusedWebCoreNode();
+ if (focusedNode && focusedNode->isElementNode()) {
+ Element* elementNode = static_cast<Element*>(focusedNode);
+ elementNode->scrollIntoViewIfNeeded(true);
+ }
+}
+
+double WebViewImpl::zoomLevel()
{
return m_zoomLevel;
}
-int WebViewImpl::setZoomLevel(bool textOnly, int zoomLevel)
+double WebViewImpl::setZoomLevel(bool textOnly, double zoomLevel)
{
- float zoomFactor = static_cast<float>(
- std::max(std::min(std::pow(textSizeMultiplierRatio, zoomLevel),
- maxTextSizeMultiplier),
- minTextSizeMultiplier));
- Frame* frame = mainFrameImpl()->frame();
- if (zoomFactor != frame->zoomFactor()) {
+ if (zoomLevel < m_minimumZoomLevel)
+ m_zoomLevel = m_minimumZoomLevel;
+ else if (zoomLevel > m_maximumZoomLevel)
+ m_zoomLevel = m_maximumZoomLevel;
+ else
m_zoomLevel = zoomLevel;
- frame->setZoomFactor(zoomFactor, textOnly);
+
+ Frame* frame = mainFrameImpl()->frame();
+ WebPluginContainerImpl* pluginContainer = WebFrameImpl::pluginContainerFromFrame(frame);
+ if (pluginContainer)
+ pluginContainer->plugin()->setZoomLevel(m_zoomLevel, textOnly);
+ else {
+ double zoomFactor = zoomLevelToZoomFactor(m_zoomLevel);
+ if (textOnly)
+ frame->setPageAndTextZoomFactors(1, zoomFactor);
+ else
+ frame->setPageAndTextZoomFactors(zoomFactor, 1);
}
return m_zoomLevel;
}
+void WebViewImpl::zoomLimitsChanged(double minimumZoomLevel,
+ double maximumZoomLevel)
+{
+ m_minimumZoomLevel = minimumZoomLevel;
+ m_maximumZoomLevel = maximumZoomLevel;
+ m_client->zoomLimitsChanged(m_minimumZoomLevel, m_maximumZoomLevel);
+}
+
+void WebViewImpl::fullFramePluginZoomLevelChanged(double zoomLevel)
+{
+ if (zoomLevel == m_zoomLevel)
+ return;
+
+ m_zoomLevel = std::max(std::min(zoomLevel, m_maximumZoomLevel), m_minimumZoomLevel);
+ m_client->zoomLevelChanged();
+}
+
+double WebView::zoomLevelToZoomFactor(double zoomLevel)
+{
+ return std::pow(textSizeMultiplierRatio, zoomLevel);
+}
+
+double WebView::zoomFactorToZoomLevel(double factor)
+{
+ // Since factor = 1.2^level, level = log(factor) / log(1.2)
+ return log(factor) / log(textSizeMultiplierRatio);
+}
+
void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
const WebPoint& location)
{
@@ -1331,6 +1646,9 @@ void WebViewImpl::performMediaPlayerAction(const WebMediaPlayerAction& action,
case WebMediaPlayerAction::Loop:
mediaElement->setLoop(action.enable);
break;
+ case WebMediaPlayerAction::Controls:
+ mediaElement->setControls(action.enable);
+ break;
default:
ASSERT_NOT_REACHED();
}
@@ -1368,6 +1686,15 @@ void WebViewImpl::dragSourceEndedAt(
false, 0);
m_page->mainFrame()->eventHandler()->dragSourceEndedAt(pme,
static_cast<DragOperation>(operation));
+ m_dragScrollTimer->stop();
+}
+
+void WebViewImpl::dragSourceMovedTo(
+ const WebPoint& clientPoint,
+ const WebPoint& screenPoint,
+ WebDragOperation operation)
+{
+ m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
}
void WebViewImpl::dragSourceSystemDragEnded()
@@ -1392,26 +1719,22 @@ WebDragOperation WebViewImpl::dragTargetDragEnter(
m_dragIdentity = identity;
m_operationsAllowed = operationsAllowed;
- DragData dragData(
- m_currentDragData.get(),
- clientPoint,
- screenPoint,
- static_cast<DragOperation>(operationsAllowed));
+ return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter);
+}
- m_dropEffect = DropEffectDefault;
- m_dragTargetDispatch = true;
- DragOperation effect = m_page->dragController()->dragEntered(&dragData);
- // Mask the operation against the drag source's allowed operations.
- if ((effect & dragData.draggingSourceOperationMask()) != effect)
- effect = DragOperationNone;
- m_dragTargetDispatch = false;
+WebDragOperation WebViewImpl::dragTargetDragEnterNew(
+ int identity,
+ const WebPoint& clientPoint,
+ const WebPoint& screenPoint,
+ WebDragOperationsMask operationsAllowed)
+{
+ ASSERT(!m_currentDragData.get());
- if (m_dropEffect != DropEffectDefault) {
- m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
- : WebDragOperationNone;
- } else
- m_dragOperation = static_cast<WebDragOperation>(effect);
- return m_dragOperation;
+ m_currentDragData = ChromiumDataObject::createReadable(Clipboard::DragAndDrop);
+ m_dragIdentity = identity;
+ m_operationsAllowed = operationsAllowed;
+
+ return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragEnter);
}
WebDragOperation WebViewImpl::dragTargetDragOver(
@@ -1419,29 +1742,9 @@ WebDragOperation WebViewImpl::dragTargetDragOver(
const WebPoint& screenPoint,
WebDragOperationsMask operationsAllowed)
{
- ASSERT(m_currentDragData.get());
-
m_operationsAllowed = operationsAllowed;
- DragData dragData(
- m_currentDragData.get(),
- clientPoint,
- screenPoint,
- static_cast<DragOperation>(operationsAllowed));
-
- m_dropEffect = DropEffectDefault;
- m_dragTargetDispatch = true;
- DragOperation effect = m_page->dragController()->dragUpdated(&dragData);
- // Mask the operation against the drag source's allowed operations.
- if ((effect & dragData.draggingSourceOperationMask()) != effect)
- effect = DragOperationNone;
- m_dragTargetDispatch = false;
- if (m_dropEffect != DropEffectDefault) {
- m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
- : WebDragOperationNone;
- } else
- m_dragOperation = static_cast<WebDragOperation>(effect);
- return m_dragOperation;
+ return dragTargetDragEnterOrOver(clientPoint, screenPoint, DragOver);
}
void WebViewImpl::dragTargetDragLeave()
@@ -1495,6 +1798,7 @@ void WebViewImpl::dragTargetDrop(const WebPoint& clientPoint,
m_dropEffect = DropEffectDefault;
m_dragOperation = WebDragOperationNone;
m_dragIdentity = 0;
+ m_dragScrollTimer->stop();
}
int WebViewImpl::dragIdentity()
@@ -1504,7 +1808,42 @@ int WebViewImpl::dragIdentity()
return 0;
}
-unsigned long WebViewImpl::createUniqueIdentifierForRequest() {
+WebDragOperation WebViewImpl::dragTargetDragEnterOrOver(const WebPoint& clientPoint, const WebPoint& screenPoint, DragAction dragAction)
+{
+ ASSERT(m_currentDragData.get());
+
+ DragData dragData(
+ m_currentDragData.get(),
+ clientPoint,
+ screenPoint,
+ static_cast<DragOperation>(m_operationsAllowed));
+
+ m_dropEffect = DropEffectDefault;
+ m_dragTargetDispatch = true;
+ DragOperation effect = dragAction == DragEnter ? m_page->dragController()->dragEntered(&dragData)
+ : m_page->dragController()->dragUpdated(&dragData);
+ // Mask the operation against the drag source's allowed operations.
+ if (!(effect & dragData.draggingSourceOperationMask()))
+ effect = DragOperationNone;
+ m_dragTargetDispatch = false;
+
+ if (m_dropEffect != DropEffectDefault) {
+ m_dragOperation = (m_dropEffect != DropEffectNone) ? WebDragOperationCopy
+ : WebDragOperationNone;
+ } else
+ m_dragOperation = static_cast<WebDragOperation>(effect);
+
+ if (dragAction == DragOver)
+ m_dragScrollTimer->triggerScroll(mainFrameImpl()->frameView(), clientPoint);
+ else
+ m_dragScrollTimer->stop();
+
+
+ return m_dragOperation;
+}
+
+unsigned long WebViewImpl::createUniqueIdentifierForRequest()
+{
if (m_page)
return m_page->progress()->createUniqueIdentifier();
return 0;
@@ -1537,15 +1876,24 @@ void WebViewImpl::setInspectorSettings(const WebString& settings)
m_inspectorSettings = settings;
}
-WebDevToolsAgent* WebViewImpl::devToolsAgent()
+bool WebViewImpl::inspectorSetting(const WebString& key, WebString* value) const
{
- return m_devToolsAgent.get();
+ if (!m_inspectorSettingsMap->contains(key))
+ return false;
+ *value = m_inspectorSettingsMap->get(key);
+ return true;
}
-void WebViewImpl::setDevToolsAgent(WebDevToolsAgent* devToolsAgent)
+void WebViewImpl::setInspectorSetting(const WebString& key,
+ const WebString& value)
{
- ASSERT(!m_devToolsAgent.get()); // May only set once!
- m_devToolsAgent.set(static_cast<WebDevToolsAgentPrivate*>(devToolsAgent));
+ m_inspectorSettingsMap->set(key, value);
+ client()->didUpdateInspectorSetting(key, value);
+}
+
+WebDevToolsAgent* WebViewImpl::devToolsAgent()
+{
+ return m_devToolsAgent.get();
}
WebAccessibilityObject WebViewImpl::accessibilityObject()
@@ -1558,25 +1906,31 @@ WebAccessibilityObject WebViewImpl::accessibilityObject()
document->axObjectCache()->getOrCreate(document->renderer()));
}
-void WebViewImpl::applyAutofillSuggestions(
+void WebViewImpl::applyAutoFillSuggestions(
const WebNode& node,
- const WebVector<WebString>& suggestions,
- int defaultSuggestionIndex)
+ const WebVector<WebString>& names,
+ const WebVector<WebString>& labels,
+ const WebVector<int>& uniqueIDs,
+ int separatorIndex)
{
- applyAutocompleteSuggestions(node, suggestions, defaultSuggestionIndex);
+ WebVector<WebString> icons(names.size());
+ applyAutoFillSuggestions(node, names, labels, icons, uniqueIDs, separatorIndex);
}
void WebViewImpl::applyAutoFillSuggestions(
const WebNode& node,
const WebVector<WebString>& names,
const WebVector<WebString>& labels,
- int defaultSuggestionIndex)
+ const WebVector<WebString>& icons,
+ const WebVector<int>& uniqueIDs,
+ int separatorIndex)
{
ASSERT(names.size() == labels.size());
- ASSERT(defaultSuggestionIndex < static_cast<int>(names.size()));
+ ASSERT(names.size() == uniqueIDs.size());
+ ASSERT(separatorIndex < static_cast<int>(names.size()));
if (names.isEmpty()) {
- hideSuggestionsPopup();
+ hideAutoFillPopup();
return;
}
@@ -1585,7 +1939,7 @@ void WebViewImpl::applyAutoFillSuggestions(
// focused node, then we have nothing to do. FIXME: also check the
// caret is at the end and that the text has not changed.
if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
- hideSuggestionsPopup();
+ hideAutoFillPopup();
return;
}
@@ -1597,98 +1951,51 @@ void WebViewImpl::applyAutoFillSuggestions(
if (!m_autoFillPopupClient.get())
m_autoFillPopupClient.set(new AutoFillPopupMenuClient);
- m_autoFillPopupClient->initialize(inputElem, names, labels,
- defaultSuggestionIndex);
-
- if (m_suggestionsPopupClient != m_autoFillPopupClient.get()) {
- hideSuggestionsPopup();
- m_suggestionsPopupClient = m_autoFillPopupClient.get();
- }
+ m_autoFillPopupClient->initialize(
+ inputElem, names, labels, icons, uniqueIDs, separatorIndex);
if (!m_autoFillPopup.get()) {
- m_autoFillPopup = PopupContainer::create(m_suggestionsPopupClient,
- suggestionsPopupSettings);
+ m_autoFillPopup = PopupContainer::create(m_autoFillPopupClient.get(),
+ PopupContainer::Suggestion,
+ autoFillPopupSettings);
}
- if (m_suggestionsPopup != m_autoFillPopup.get())
- m_suggestionsPopup = m_autoFillPopup.get();
-
- if (m_suggestionsPopupShowing) {
- m_autoFillPopupClient->setSuggestions(names, labels);
- refreshSuggestionsPopup();
+ if (m_autoFillPopupShowing) {
+ refreshAutoFillPopup();
} else {
- m_suggestionsPopup->show(focusedNode->getRect(),
- focusedNode->ownerDocument()->view(), 0);
- m_suggestionsPopupShowing = true;
+ m_autoFillPopup->show(focusedNode->getRect(), focusedNode->ownerDocument()->view(), 0);
+ m_autoFillPopupShowing = true;
}
+
+ // DEPRECATED: This special mode will go away once AutoFill and Autocomplete
+ // merge is complete.
+ if (m_autoFillPopupClient)
+ m_autoFillPopupClient->setAutocompleteMode(false);
}
+// DEPRECATED: replacing with applyAutoFillSuggestions.
void WebViewImpl::applyAutocompleteSuggestions(
const WebNode& node,
const WebVector<WebString>& suggestions,
int defaultSuggestionIndex)
{
- ASSERT(defaultSuggestionIndex < static_cast<int>(suggestions.size()));
+ WebVector<WebString> names(suggestions.size());
+ WebVector<WebString> labels(suggestions.size());
+ WebVector<WebString> icons(suggestions.size());
+ WebVector<int> uniqueIDs(suggestions.size());
- if (!m_page.get() || suggestions.isEmpty()) {
- hideSuggestionsPopup();
- return;
- }
+ for (size_t i = 0; i < suggestions.size(); ++i)
+ names[i] = suggestions[i];
- RefPtr<Node> focusedNode = focusedWebCoreNode();
- // If the node for which we queried the Autocomplete suggestions is not the
- // focused node, then we have nothing to do. FIXME: also check the
- // caret is at the end and that the text has not changed.
- if (!focusedNode || focusedNode != PassRefPtr<Node>(node)) {
- hideSuggestionsPopup();
- return;
- }
-
- HTMLInputElement* inputElem =
- static_cast<HTMLInputElement*>(focusedNode.get());
-
- // The first time the Autocomplete is shown we'll create the client and the
- // popup.
- if (!m_autocompletePopupClient.get())
- m_autocompletePopupClient.set(new AutocompletePopupMenuClient);
-
- m_autocompletePopupClient->initialize(inputElem, suggestions,
- defaultSuggestionIndex);
-
- if (m_suggestionsPopupClient != m_autocompletePopupClient.get()) {
- hideSuggestionsPopup();
- m_suggestionsPopupClient = m_autocompletePopupClient.get();
- }
-
- if (!m_autocompletePopup.get()) {
- m_autocompletePopup = PopupContainer::create(m_suggestionsPopupClient,
- suggestionsPopupSettings);
- }
-
- if (m_suggestionsPopup != m_autocompletePopup.get())
- m_suggestionsPopup = m_autocompletePopup.get();
-
- if (m_suggestionsPopupShowing) {
- m_autocompletePopupClient->setSuggestions(suggestions);
- refreshSuggestionsPopup();
- } else {
- m_suggestionsPopup->show(focusedNode->getRect(),
- focusedNode->ownerDocument()->view(), 0);
- m_suggestionsPopupShowing = true;
- }
+ applyAutoFillSuggestions(node, names, labels, icons, uniqueIDs, -1);
+ if (m_autoFillPopupClient)
+ m_autoFillPopupClient->setAutocompleteMode(true);
}
-void WebViewImpl::hideAutofillPopup()
+void WebViewImpl::hidePopups()
{
- hideSuggestionsPopup();
-}
-
-void WebViewImpl::hideSuggestionsPopup()
-{
- if (m_suggestionsPopupShowing) {
- m_suggestionsPopup->hidePopup();
- m_suggestionsPopupShowing = false;
- }
+ hideSelectPopup();
+ hideAutoFillPopup();
}
void WebViewImpl::performCustomContextMenuAction(unsigned action)
@@ -1744,11 +2051,16 @@ bool WebViewImpl::isActive() const
return (page() && page()->focusController()) ? page()->focusController()->isActive() : false;
}
+void WebViewImpl::setDomainRelaxationForbidden(bool forbidden, const WebString& scheme)
+{
+ SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(forbidden, String(scheme));
+}
+
void WebViewImpl::setScrollbarColors(unsigned inactiveColor,
unsigned activeColor,
unsigned trackColor) {
-#if OS(LINUX)
- RenderThemeChromiumLinux::setScrollbarColors(inactiveColor,
+#if OS(LINUX) || OS(FREEBSD)
+ PlatformThemeChromiumGtk::setScrollbarColors(inactiveColor,
activeColor,
trackColor);
#endif
@@ -1758,7 +2070,7 @@ void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
unsigned activeForegroundColor,
unsigned inactiveBackgroundColor,
unsigned inactiveForegroundColor) {
-#if OS(LINUX)
+#if OS(LINUX) || OS(FREEBSD)
RenderThemeChromiumLinux::setSelectionColors(activeBackgroundColor,
activeForegroundColor,
inactiveBackgroundColor,
@@ -1767,15 +2079,45 @@ void WebViewImpl::setSelectionColors(unsigned activeBackgroundColor,
#endif
}
-void WebViewImpl::addUserScript(const WebString& sourceCode, bool runAtStart)
+void WebView::addUserScript(const WebString& sourceCode,
+ const WebVector<WebString>& patternsIn,
+ WebView::UserScriptInjectAt injectAt,
+ WebView::UserContentInjectIn injectIn)
+{
+ OwnPtr<Vector<String> > patterns(new Vector<String>);
+ for (size_t i = 0; i < patternsIn.size(); ++i)
+ patterns->append(patternsIn[i]);
+
+ PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
+ RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
+ pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
+ static_cast<UserScriptInjectionTime>(injectAt),
+ static_cast<UserContentInjectedFrames>(injectIn));
+}
+
+void WebView::addUserStyleSheet(const WebString& sourceCode,
+ const WebVector<WebString>& patternsIn,
+ WebView::UserContentInjectIn injectIn,
+ WebView::UserStyleInjectionTime injectionTime)
{
+ OwnPtr<Vector<String> > patterns(new Vector<String>);
+ for (size_t i = 0; i < patternsIn.size(); ++i)
+ patterns->append(patternsIn[i]);
+
PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
RefPtr<DOMWrapperWorld> world(DOMWrapperWorld::create());
- pageGroup->addUserScriptToWorld(world.get(), sourceCode, WebURL(), 0, 0,
- runAtStart ? InjectAtDocumentStart : InjectAtDocumentEnd);
+
+ // FIXME: Current callers always want the level to be "author". It probably makes sense to let
+ // callers specify this though, since in other cases the caller will probably want "user" level.
+ //
+ // FIXME: It would be nice to populate the URL correctly, instead of passing an empty URL.
+ pageGroup->addUserStyleSheetToWorld(world.get(), sourceCode, WebURL(), patterns.release(), 0,
+ static_cast<UserContentInjectedFrames>(injectIn),
+ UserStyleAuthorLevel,
+ static_cast<WebCore::UserStyleInjectionTime>(injectionTime));
}
-void WebViewImpl::removeAllUserContent()
+void WebView::removeAllUserContent()
{
PageGroup* pageGroup = PageGroup::pageGroup(pageGroupName);
pageGroup->removeAllUserContent();
@@ -1794,12 +2136,17 @@ void WebViewImpl::didCommitLoad(bool* isNewNavigation)
m_observedNewNavigation = false;
}
+bool WebViewImpl::useExternalPopupMenus()
+{
+ return shouldUseExternalPopupMenus;
+}
+
bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
bool ctrl, bool shift,
bool alt, bool meta,
WebNavigationPolicy* policy)
{
-#if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD)
+#if OS(WINDOWS) || OS(LINUX) || OS(FREEBSD) || OS(SOLARIS)
const bool newTabModifier = (button == 1) || ctrl;
#elif OS(DARWIN)
const bool newTabModifier = (button == 1) || meta;
@@ -1822,15 +2169,16 @@ bool WebViewImpl::navigationPolicyFromMouseEvent(unsigned short button,
return true;
}
-void WebViewImpl::startDragging(const WebPoint& eventPos,
- const WebDragData& dragData,
- WebDragOperationsMask mask)
+void WebViewImpl::startDragging(const WebDragData& dragData,
+ WebDragOperationsMask mask,
+ const WebImage& dragImage,
+ const WebPoint& dragImageOffset)
{
if (!m_client)
return;
ASSERT(!m_doingDragAndDrop);
m_doingDragAndDrop = true;
- m_client->startDragging(eventPos, dragData, mask);
+ m_client->startDragging(dragData, mask, dragImage, dragImageOffset);
}
void WebViewImpl::setCurrentHistoryItem(HistoryItem* item)
@@ -1866,24 +2214,25 @@ NotificationPresenterImpl* WebViewImpl::notificationPresenterImpl()
}
#endif
-void WebViewImpl::refreshSuggestionsPopup()
+void WebViewImpl::refreshAutoFillPopup()
{
- ASSERT(m_suggestionsPopupShowing);
+ ASSERT(m_autoFillPopupShowing);
// Hide the popup if it has become empty.
- if (!m_autocompletePopupClient->listSize()) {
- hideSuggestionsPopup();
+ if (!m_autoFillPopupClient->listSize()) {
+ hideAutoFillPopup();
return;
}
- IntRect oldBounds = m_suggestionsPopup->boundsRect();
- m_suggestionsPopup->refresh();
- IntRect newBounds = m_suggestionsPopup->boundsRect();
+ IntRect oldBounds = m_autoFillPopup->boundsRect();
+ m_autoFillPopup->refresh();
+ IntRect newBounds = m_autoFillPopup->boundsRect();
// Let's resize the backing window if necessary.
if (oldBounds != newBounds) {
WebPopupMenuImpl* popupMenu =
- static_cast<WebPopupMenuImpl*>(m_suggestionsPopup->client());
- popupMenu->client()->setWindowRect(newBounds);
+ static_cast<WebPopupMenuImpl*>(m_autoFillPopup->client());
+ if (popupMenu)
+ popupMenu->client()->setWindowRect(newBounds);
}
}
@@ -1916,4 +2265,285 @@ bool WebViewImpl::tabsToLinks() const
return m_tabsToLinks;
}
+#if USE(ACCELERATED_COMPOSITING)
+bool WebViewImpl::allowsAcceleratedCompositing()
+{
+ return !m_compositorCreationFailed;
+}
+
+void WebViewImpl::setRootGraphicsLayer(WebCore::PlatformLayer* layer)
+{
+ setIsAcceleratedCompositingActive(layer ? true : false);
+ if (m_layerRenderer)
+ m_layerRenderer->setRootLayer(layer);
+
+ IntRect damagedRect(0, 0, m_size.width, m_size.height);
+ if (m_isAcceleratedCompositingActive)
+ invalidateRootLayerRect(damagedRect);
+ else
+ m_client->didInvalidateRect(damagedRect);
+}
+
+void WebViewImpl::setRootLayerNeedsDisplay()
+{
+ m_client->scheduleComposite();
+}
+
+
+void WebViewImpl::scrollRootLayerRect(const IntSize& scrollDelta, const IntRect& clipRect)
+{
+ ASSERT(m_layerRenderer);
+ // Compute the damage rect in viewport space.
+ WebFrameImpl* webframe = mainFrameImpl();
+ if (!webframe)
+ return;
+ FrameView* view = webframe->frameView();
+ if (!view)
+ return;
+
+ IntRect contentRect = view->visibleContentRect(false);
+ IntRect screenRect = view->contentsToWindow(contentRect);
+
+ // We support fast scrolling in one direction at a time.
+ if (scrollDelta.width() && scrollDelta.height()) {
+ invalidateRootLayerRect(WebRect(screenRect));
+ return;
+ }
+
+ // Compute the region we will expose by scrolling. We use the
+ // content rect for invalidation. Using this space for damage
+ // rects allows us to intermix invalidates with scrolls.
+ IntRect damagedContentsRect;
+ if (scrollDelta.width()) {
+ int dx = scrollDelta.width();
+ damagedContentsRect.setY(screenRect.y());
+ damagedContentsRect.setHeight(screenRect.height());
+ if (dx > 0) {
+ damagedContentsRect.setX(screenRect.x());
+ damagedContentsRect.setWidth(dx);
+ } else {
+ damagedContentsRect.setX(screenRect.right() + dx);
+ damagedContentsRect.setWidth(-dx);
+ }
+ } else {
+ int dy = scrollDelta.height();
+ damagedContentsRect.setX(screenRect.x());
+ damagedContentsRect.setWidth(screenRect.width());
+ if (dy > 0) {
+ damagedContentsRect.setY(screenRect.y());
+ damagedContentsRect.setHeight(dy);
+ } else {
+ damagedContentsRect.setY(screenRect.bottom() + dy);
+ damagedContentsRect.setHeight(-dy);
+ }
+ }
+
+ // Move the previous damage
+ m_rootLayerScrollDamage.move(scrollDelta.width(), scrollDelta.height());
+ // Union with the new damage rect.
+ m_rootLayerScrollDamage.unite(damagedContentsRect);
+
+ // Scroll any existing damage that intersects with clip rect
+ if (clipRect.intersects(m_rootLayerDirtyRect)) {
+ // Find the inner damage
+ IntRect innerDamage(clipRect);
+ innerDamage.intersect(m_rootLayerDirtyRect);
+
+ // Move the damage
+ innerDamage.move(scrollDelta.width(), scrollDelta.height());
+
+ // Merge it back into the damaged rect
+ m_rootLayerDirtyRect.unite(innerDamage);
+ }
+
+ setRootLayerNeedsDisplay();
+}
+
+void WebViewImpl::invalidateRootLayerRect(const IntRect& rect)
+{
+ ASSERT(m_layerRenderer);
+
+ if (!page())
+ return;
+
+ // FIXME: add a smarter damage aggregation logic and/or unify with
+ // LayerChromium's damage logic
+ m_rootLayerDirtyRect.unite(rect);
+ setRootLayerNeedsDisplay();
+}
+
+
+void WebViewImpl::setIsAcceleratedCompositingActive(bool active)
+{
+ ChromiumBridge::histogramEnumeration("GPU.setIsAcceleratedCompositingActive", active * 2 + m_isAcceleratedCompositingActive, 4);
+
+ if (m_isAcceleratedCompositingActive == active)
+ return;
+
+ if (!active) {
+ m_isAcceleratedCompositingActive = false;
+ if (m_layerRenderer)
+ m_layerRenderer->finish(); // finish all GL rendering before we hide the window?
+ m_client->didActivateAcceleratedCompositing(false);
+ return;
+ }
+
+ if (m_layerRenderer) {
+ m_isAcceleratedCompositingActive = true;
+ m_layerRenderer->resizeOnscreenContent(WebCore::IntSize(std::max(1, m_size.width),
+ std::max(1, m_size.height)));
+
+ m_client->didActivateAcceleratedCompositing(true);
+ return;
+ }
+
+ RefPtr<GraphicsContext3D> context = m_temporaryOnscreenGraphicsContext3D.release();
+ if (!context) {
+ context = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
+ if (context)
+ context->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
+ }
+ m_layerRenderer = LayerRendererChromium::create(context.release());
+ if (m_layerRenderer) {
+ m_client->didActivateAcceleratedCompositing(true);
+ m_isAcceleratedCompositingActive = true;
+ m_compositorCreationFailed = false;
+ } else {
+ m_isAcceleratedCompositingActive = false;
+ m_client->didActivateAcceleratedCompositing(false);
+ m_compositorCreationFailed = true;
+ }
+}
+
+void WebViewImpl::updateRootLayerContents(const IntRect& rect)
+{
+ if (!isAcceleratedCompositingActive())
+ return;
+
+ WebFrameImpl* webframe = mainFrameImpl();
+ if (!webframe)
+ return;
+ FrameView* view = webframe->frameView();
+ if (!view)
+ return;
+
+ LayerChromium* rootLayer = m_layerRenderer->rootLayer();
+ if (rootLayer) {
+ IntRect visibleRect = view->visibleContentRect(true);
+
+ m_layerRenderer->setRootLayerCanvasSize(IntSize(rect.width(), rect.height()));
+ GraphicsContext* rootLayerContext = m_layerRenderer->rootLayerGraphicsContext();
+
+#if PLATFORM(SKIA)
+ PlatformContextSkia* skiaContext = rootLayerContext->platformContext();
+ skia::PlatformCanvas* platformCanvas = skiaContext->canvas();
+
+ platformCanvas->save();
+
+ // Bring the canvas into the coordinate system of the paint rect.
+ platformCanvas->translate(static_cast<SkScalar>(-rect.x()), static_cast<SkScalar>(-rect.y()));
+
+ rootLayerContext->save();
+
+ webframe->paintWithContext(*rootLayerContext, rect);
+ rootLayerContext->restore();
+
+ platformCanvas->restore();
+#elif PLATFORM(CG)
+ CGContextRef cgContext = rootLayerContext->platformContext();
+
+ CGContextSaveGState(cgContext);
+
+ // Bring the CoreGraphics context into the coordinate system of the paint rect.
+ CGContextTranslateCTM(cgContext, -rect.x(), -rect.y());
+
+ rootLayerContext->save();
+
+ webframe->paintWithContext(*rootLayerContext, rect);
+ rootLayerContext->restore();
+
+ CGContextRestoreGState(cgContext);
+#else
+#error Must port to your platform
+#endif
+ }
+}
+
+void WebViewImpl::doComposite()
+{
+ ASSERT(isAcceleratedCompositingActive());
+ if (!page())
+ return;
+ FrameView* view = page()->mainFrame()->view();
+
+ // The visibleRect includes scrollbars whereas the contentRect doesn't.
+ IntRect visibleRect = view->visibleContentRect(true);
+ IntRect contentRect = view->visibleContentRect(false);
+ IntRect viewPort = IntRect(0, 0, m_size.width, m_size.height);
+
+ // Give the compositor a chance to setup/resize the root texture handle and perform scrolling.
+ m_layerRenderer->prepareToDrawLayers(visibleRect, contentRect, IntPoint(view->scrollX(), view->scrollY()));
+
+ // Draw the contents of the root layer.
+ Vector<IntRect> damageRects;
+ damageRects.append(m_rootLayerScrollDamage);
+ damageRects.append(m_rootLayerDirtyRect);
+ for (size_t i = 0; i < damageRects.size(); ++i) {
+ IntRect damagedRect = damageRects[i];
+
+ // Intersect this rectangle with the viewPort.
+ damagedRect.intersect(viewPort);
+
+ // Now render it.
+ if (damagedRect.width() && damagedRect.height()) {
+ updateRootLayerContents(damagedRect);
+ m_layerRenderer->updateRootLayerTextureRect(damagedRect);
+ }
+ }
+ m_rootLayerDirtyRect = IntRect();
+ m_rootLayerScrollDamage = IntRect();
+
+ // Draw the actual layers...
+ m_layerRenderer->drawLayers(visibleRect, contentRect);
+}
+
+void WebViewImpl::reallocateRenderer()
+{
+ GraphicsContext3D* context = m_layerRenderer->context();
+ RefPtr<GraphicsContext3D> newContext = GraphicsContext3D::create(context->getContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
+ // GraphicsContext3D::create might fail and return 0, in that case LayerRendererChromium::create will also return 0.
+ RefPtr<LayerRendererChromium> layerRenderer = LayerRendererChromium::create(newContext);
+
+ // Reattach the root layer. Child layers will get reattached as a side effect of updateLayersRecursive.
+ if (layerRenderer)
+ m_layerRenderer->transferRootLayer(layerRenderer.get());
+ m_layerRenderer = layerRenderer;
+
+ // Enable or disable accelerated compositing and request a refresh.
+ setRootGraphicsLayer(m_layerRenderer ? m_layerRenderer->rootLayer() : 0);
+}
+#endif
+
+
+WebGraphicsContext3D* WebViewImpl::graphicsContext3D()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_page->settings()->acceleratedCompositingEnabled() && allowsAcceleratedCompositing()) {
+ GraphicsContext3D* context = 0;
+ if (m_layerRenderer)
+ context = m_layerRenderer->context();
+ else if (m_temporaryOnscreenGraphicsContext3D)
+ context = m_temporaryOnscreenGraphicsContext3D.get();
+ else {
+ m_temporaryOnscreenGraphicsContext3D = GraphicsContext3D::create(getCompositorContextAttributes(), m_page->chrome(), GraphicsContext3D::RenderDirectlyToHostWindow);
+ if (m_temporaryOnscreenGraphicsContext3D)
+ m_temporaryOnscreenGraphicsContext3D->reshape(std::max(1, m_size.width), std::max(1, m_size.height));
+ context = m_temporaryOnscreenGraphicsContext3D.get();
+ }
+ return GraphicsContext3DInternal::extractWebGraphicsContext3D(context);
+ }
+#endif
+ return 0;
+}
+
} // namespace WebKit