diff --git a/examples/quick/quicknanobrowser/quickwindow.qml b/examples/quick/quicknanobrowser/quickwindow.qml
index 88fc9f8a0dbe5ffecb82fd2041623a55b56a76ba..d72c300215948b91432d38f1c4ece88297cde1ba 100644
--- a/examples/quick/quicknanobrowser/quickwindow.qml
+++ b/examples/quick/quicknanobrowser/quickwindow.qml
@@ -44,6 +44,7 @@ import QtWebEngine.experimental 1.0
 import QtQuick.Controls 1.0
 import QtQuick.Controls.Styles 1.0
 import QtQuick.Layouts 1.0
+import QtQuick.Window 2.1
 import QtQuick.Controls.Private 1.0
 
 ApplicationWindow {
@@ -51,11 +52,21 @@ ApplicationWindow {
     function load(url) { tabs.currentView.url = url }
     function adoptHandle(viewHandle) { tabs.currentView.adoptHandle(viewHandle) }
 
+    property bool isFullScreen: visibility == Window.FullScreen
+    onIsFullScreenChanged: {
+        // This is for the case where the system forces us to leave fullscreen.
+        if (!isFullScreen && tabs.currentView.state == "FullScreen")
+            tabs.currentView.state = ""
+    }
+
     height: 600
     width: 800
     visible: true
     title: tabs.currentView && tabs.currentView.title
 
+    // Make sure the Qt.WindowFullscreenButtonHint is set on Mac.
+    Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint
+
     // Create a styleItem to determine the platform.
     // When using style "mac", ToolButtons are not supposed to accept focus.
     StyleItem { id: styleItem }
@@ -92,6 +103,14 @@ ApplicationWindow {
         }
     }
 
+    Action {
+        shortcut: "Escape"
+        onTriggered: {
+            if (browserWindow.isFullScreen)
+                browserWindow.showNormal()
+        }
+    }
+
     toolBar: ToolBar {
         id: navigationBar
             RowLayout {
@@ -174,11 +193,38 @@ ApplicationWindow {
         Component {
             id: tabComponent
             WebEngineView {
+                id: webEngineView
                 function adoptHandle(viewHandle) { experimental.adoptHandle(viewHandle) }
 
                 focus: true
 
+                states: [
+                    State {
+                        name: "FullScreen"
+                        PropertyChanges {
+                            target: tabs
+                            frameVisible: false
+                            tabsVisible: false
+                        }
+                        PropertyChanges {
+                            target: navigationBar
+                            visible: false
+                        }
+                    }
+                ]
+
                 experimental {
+                    isFullScreen: webEngineView.state == "FullScreen" && browserWindow.isFullScreen
+                    onFullScreenRequested: {
+                        if (fullScreen) {
+                            webEngineView.state = "FullScreen"
+                            browserWindow.showFullScreen();
+                        } else {
+                            webEngineView.state = ""
+                            browserWindow.showNormal();
+                        }
+                    }
+
                     onCreateWindow: {
                         if (newViewDisposition == "popup")
                             print("Warning: Ignored a popup window.")
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index 077e21500ad452f4be00689107f274336573daba..5a11fc8d85484c49fe0cc48c10db39b4978a36be 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -127,6 +127,8 @@ public:
     virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, const QRect & initialGeometry) = 0;
     virtual void close() = 0;
     virtual bool contextMenuRequested(const WebEngineContextMenuData&) = 0;
+    virtual void requestFullScreen(bool) = 0;
+    virtual bool isFullScreen() const = 0;
     virtual void javascriptDialog(QSharedPointer<JavaScriptDialogController>) = 0;
     virtual void runFileChooser(FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) = 0;
     virtual void didRunJavaScript(const QVariant& result, quint64 requestId) = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 232bb95ef514524018881163dd677da249be946c..16ec54afdd0ade6ce2da302ed293224015cf42dd 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -133,6 +133,19 @@ content::JavaScriptDialogManager *WebContentsDelegateQt::GetJavaScriptDialogMana
     return JavaScriptDialogManagerQt::GetInstance();
 }
 
+void WebContentsDelegateQt::ToggleFullscreenModeForTab(content::WebContents* web_contents, bool enter_fullscreen)
+{
+    if (m_viewClient->isFullScreen() != enter_fullscreen) {
+        m_viewClient->requestFullScreen(enter_fullscreen);
+        web_contents->GetRenderViewHost()->WasResized();
+    }
+}
+
+bool WebContentsDelegateQt::IsFullscreenForTabOrPending(const content::WebContents* web_contents) const
+{
+    return m_viewClient->isFullScreen();
+}
+
 Q_STATIC_ASSERT_X(static_cast<int>(WebContentsAdapterClient::Open) == static_cast<int>(content::FileChooserParams::Open), "Enums out of sync");
 Q_STATIC_ASSERT_X(static_cast<int>(WebContentsAdapterClient::Save) == static_cast<int>(content::FileChooserParams::Save), "Enums out of sync");
 
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 01999824181264e76788cd037a9e35404a0dec2c..460bb9ec20f4aa902e0b7e56ed463222002718b7 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -73,6 +73,8 @@ public:
     virtual void DidUpdateFaviconURL(int32 page_id, const std::vector<content::FaviconURL>& candidates) Q_DECL_OVERRIDE;
     virtual void DidFailProvisionalLoad(int64 frame_id, bool is_main_frame, const GURL& validated_url, int error_code, const string16& error_description, content::RenderViewHost* render_view_host) Q_DECL_OVERRIDE;
     virtual content::JavaScriptDialogManager *GetJavaScriptDialogManager() Q_DECL_OVERRIDE;
+    virtual void ToggleFullscreenModeForTab(content::WebContents* web_contents, bool enter_fullscreen) Q_DECL_OVERRIDE;
+    virtual bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) const Q_DECL_OVERRIDE;
     virtual void RunFileChooser(content::WebContents *, const content::FileChooserParams &params) Q_DECL_OVERRIDE;
     virtual bool AddMessageToConsole(content::WebContents* source, int32 level, const string16& message, int32 line_no, const string16& source_id) Q_DECL_OVERRIDE;
 
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 2f5d868ea19c99de99574937c22aa89669dc6668..e91f2ee752236b170976a8a04a0687a2b0055079 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -70,6 +70,7 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate()
     , loadProgress(0)
     , inspectable(false)
     , m_isLoading(false)
+    , m_isFullScreen(false)
     , devicePixelRatio(QGuiApplication::primaryScreen()->devicePixelRatio())
     , m_dpiScale(1.0)
 {
@@ -324,6 +325,16 @@ void QQuickWebEngineViewPrivate::close()
     Q_UNREACHABLE();
 }
 
+void QQuickWebEngineViewPrivate::requestFullScreen(bool fullScreen)
+{
+    Q_EMIT e->fullScreenRequested(fullScreen);
+}
+
+bool QQuickWebEngineViewPrivate::isFullScreen() const
+{
+    return e->isFullScreen();
+}
+
 void QQuickWebEngineViewPrivate::javaScriptConsoleMessage(int level, const QString& message, int lineNumber, const QString& sourceID)
 {
     Q_Q(QQuickWebEngineView);
@@ -438,6 +449,17 @@ void QQuickWebEngineView::setInspectable(bool enable)
     d->adapter->enableInspector(enable);
 }
 
+void QQuickWebEngineViewExperimental::setIsFullScreen(bool fullscreen)
+{
+    d_ptr->m_isFullScreen = fullscreen;
+    emit isFullScreenChanged();
+}
+
+bool QQuickWebEngineViewExperimental::isFullScreen() const
+{
+    return d_ptr->m_isFullScreen;
+}
+
 void QQuickWebEngineViewExperimental::setExtraContextMenuEntriesComponent(QQmlComponent *contextMenuExtras)
 {
     if (d_ptr->contextMenuExtraItems == contextMenuExtras)
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 3de5974690ad1104512fb7d4459932e74e92561c..d35758d70c05a3d2277752237e60b8fd108af11b 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -93,8 +93,13 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineViewExperimental : public QObjec
     Q_OBJECT
     Q_PROPERTY(QQuickWebEngineViewport *viewport READ viewport)
     Q_PROPERTY(QQmlComponent *extraContextMenuEntriesComponent READ extraContextMenuEntriesComponent WRITE setExtraContextMenuEntriesComponent NOTIFY extraContextMenuEntriesComponentChanged)
+    Q_PROPERTY(bool isFullScreen READ isFullScreen WRITE setIsFullScreen NOTIFY isFullScreenChanged)
 
 public:
+    void setIsFullScreen(bool fullscreen);
+    bool isFullScreen() const;
+
+public Q_SLOTS:
     QQuickWebEngineViewport *viewport() const;
     Q_INVOKABLE void adoptHandle(QQuickWebEngineViewHandle *viewHandle);
     void setExtraContextMenuEntriesComponent(QQmlComponent *);
@@ -102,6 +107,8 @@ public:
 
 Q_SIGNALS:
     void createWindow(const QJSValue &newViewHandle, const QString &newViewDisposition);
+    void fullScreenRequested(bool fullScreen);
+    void isFullScreenChanged();
     void extraContextMenuEntriesComponentChanged();
 
 private:
@@ -135,6 +142,8 @@ public:
     virtual void focusContainer() Q_DECL_OVERRIDE;
     virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, const QRect &) Q_DECL_OVERRIDE;
     virtual void close() Q_DECL_OVERRIDE;
+    virtual void requestFullScreen(bool) Q_DECL_OVERRIDE;
+    virtual bool isFullScreen() const Q_DECL_OVERRIDE;
     virtual bool contextMenuRequested(const WebEngineContextMenuData &) Q_DECL_OVERRIDE;
     virtual void javascriptDialog(QSharedPointer<JavaScriptDialogController>) Q_DECL_OVERRIDE;
     virtual void runFileChooser(FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) Q_DECL_OVERRIDE;
@@ -154,6 +163,7 @@ public:
     int loadProgress;
     bool inspectable;
     bool m_isLoading;
+    bool m_isFullScreen;
     qreal devicePixelRatio;
 
 private:
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index 0a90eda0787d1f376cbc0fdeb9f043eb01d15179..0fa4299d8a0e3e422066e1cf9cd299c4be49622f 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -78,6 +78,8 @@ public:
     virtual void adoptNewWindow(WebContentsAdapter *newWebContents, WindowOpenDisposition disposition, const QRect &initialGeometry) Q_DECL_OVERRIDE;
     virtual void close() Q_DECL_OVERRIDE;
     virtual bool contextMenuRequested(const WebEngineContextMenuData &data) Q_DECL_OVERRIDE;
+    virtual void requestFullScreen(bool) Q_DECL_OVERRIDE { };
+    virtual bool isFullScreen() const Q_DECL_OVERRIDE { return false; };
     virtual void javascriptDialog(QSharedPointer<JavaScriptDialogController>) Q_DECL_OVERRIDE;
     virtual void runFileChooser(FileChooserMode, const QString &defaultFileName, const QStringList &acceptedMimeTypes) Q_DECL_OVERRIDE;
     virtual void didRunJavaScript(const QVariant& result, quint64 requestId) Q_DECL_OVERRIDE;