From 79e271901d65a588683e4c32e788c062de4ed2c2 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 4 Feb 2016 13:34:00 +0100 Subject: [PATCH] Bug 1104916 - Implement CSS media query display-mode. r=cam --- dom/base/nsGkAtomList.h | 1 + dom/ipc/PBrowser.ipdl | 7 +- dom/ipc/TabChild.cpp | 24 ++++- dom/ipc/TabChild.h | 6 +- dom/ipc/TabParent.cpp | 20 +++- dom/ipc/TabParent.h | 3 + layout/base/nsPresContext.cpp | 48 ++++++++++ layout/base/nsPresContext.h | 16 ++++ layout/style/nsCSSKeywordList.h | 4 + layout/style/nsMediaFeatures.cpp | 45 +++++++++ layout/style/nsStyleConsts.h | 6 ++ layout/style/test/chrome/chrome.ini | 1 + .../style/test/chrome/test_display_mode.html | 94 +++++++++++++++++++ layout/style/test/test_media_queries.html | 8 ++ xpfe/appshell/nsWebShellWindow.cpp | 5 + 15 files changed, 277 insertions(+), 11 deletions(-) create mode 100644 layout/style/test/chrome/test_display_mode.html diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 2c8f91a2c4a..69dde410a57 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -309,6 +309,7 @@ GK_ATOM(disableOutputEscaping, "disable-output-escaping") GK_ATOM(disabled, "disabled") GK_ATOM(disablehistory, "disablehistory") GK_ATOM(display, "display") +GK_ATOM(displayMode, "display-mode") GK_ATOM(distinct, "distinct") GK_ATOM(div, "div") GK_ATOM(dl, "dl") diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index db35c241ba4..c44694261ae 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -564,7 +564,8 @@ child: TextureFactoryIdentifier textureFactoryIdentifier, uint64_t layersId, nullable PRenderFrame renderFrame, - bool parentIsActive); + bool parentIsActive, + nsSizeMode sizeMode); async LoadURL(nsCString uri, BrowserConfiguration config, ShowInfo info); @@ -572,12 +573,14 @@ child: async CacheFileDescriptor(nsString path, FileDescriptor fd); - async UpdateDimensions(CSSRect rect, CSSSize size, nsSizeMode sizeMode, + async UpdateDimensions(CSSRect rect, CSSSize size, ScreenOrientationInternal orientation, LayoutDeviceIntPoint chromeDisp) compressall; async UpdateFrame(FrameMetrics frame); + async SizeModeChanged(nsSizeMode sizeMode); + // The following methods correspond to functions on the GeckoContentController // interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation // in that file for these functions. diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index a002f707a8f..5f828055306 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1448,7 +1448,7 @@ TabChild::DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier, PRenderFrameChild* aRenderFrame, const ShowInfo& aShowInfo) { RecvShow(ScreenIntSize(0, 0), aShowInfo, aTextureFactoryIdentifier, - aLayersId, aRenderFrame, mParentIsActive); + aLayersId, aRenderFrame, mParentIsActive, nsSizeMode_Normal); mDidFakeShow = true; } @@ -1560,10 +1560,12 @@ TabChild::RecvShow(const ScreenIntSize& aSize, const TextureFactoryIdentifier& aTextureFactoryIdentifier, const uint64_t& aLayersId, PRenderFrameChild* aRenderFrame, - const bool& aParentIsActive) + const bool& aParentIsActive, + const nsSizeMode& aSizeMode) { MOZ_ASSERT((!mDidFakeShow && aRenderFrame) || (mDidFakeShow && !aRenderFrame)); + mPuppetWidget->SetSizeMode(aSizeMode); if (mDidFakeShow) { ApplyShowInfo(aInfo); RecvParentActivated(aParentIsActive); @@ -1599,7 +1601,6 @@ TabChild::RecvShow(const ScreenIntSize& aSize, bool TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, - const nsSizeMode& sizeMode, const ScreenOrientationInternal& orientation, const LayoutDeviceIntPoint& chromeDisp) { @@ -1626,7 +1627,6 @@ TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, baseWin->SetPositionAndSize(0, 0, screenSize.width, screenSize.height, true); - mPuppetWidget->SetSizeMode(sizeMode); mPuppetWidget->Resize(screenRect.x + chromeDisp.x, screenRect.y + chromeDisp.y, screenSize.width, screenSize.height, true); @@ -1634,6 +1634,22 @@ TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, return true; } +bool +TabChild::RecvSizeModeChanged(const nsSizeMode& aSizeMode) +{ + mPuppetWidget->SetSizeMode(aSizeMode); + nsCOMPtr document(GetDocument()); + nsCOMPtr presShell = document->GetShell(); + if (presShell) { + nsPresContext* presContext = presShell->GetPresContext(); + if (presContext) { + presContext->MediaFeatureValuesChangedAllDocuments(eRestyle_Subtree, + NS_STYLE_HINT_REFLOW); + } + } + return true; +} + bool TabChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 42af6977f05..08dfb703079 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -323,14 +323,16 @@ public: const TextureFactoryIdentifier& aTextureFactoryIdentifier, const uint64_t& aLayersId, PRenderFrameChild* aRenderFrame, - const bool& aParentIsActive) override; + const bool& aParentIsActive, + const nsSizeMode& aSizeMode) override; virtual bool RecvUpdateDimensions(const CSSRect& aRect, const CSSSize& aSize, - const nsSizeMode& aSizeMode, const ScreenOrientationInternal& aOrientation, const LayoutDeviceIntPoint& aChromeDisp) override; + virtual bool + RecvSizeModeChanged(const nsSizeMode& aSizeMode) override; virtual bool RecvUpdateFrame(const layers::FrameMetrics& aFrameMetrics) override; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 3b0928980d4..501afec7ab5 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -279,6 +279,7 @@ TabParent::TabParent(nsIContentParent* aManager, , mDPI(0) , mDefaultScale(0) , mUpdatedDimensions(false) + , mSizeMode(nsSizeMode_Normal) , mManager(aManager) , mDocShellIsActive(false) , mMarkedDestroying(false) @@ -894,8 +895,14 @@ TabParent::Show(const ScreenIntSize& size, bool aParentIsActive) } } + nsCOMPtr container = mFrameElement->OwnerDoc()->GetContainer(); + nsCOMPtr baseWindow = do_QueryInterface(container); + nsCOMPtr mainWidget; + baseWindow->GetMainWidget(getter_AddRefs(mainWidget)); + mSizeMode = mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal; + Unused << SendShow(size, GetShowInfo(), textureFactoryIdentifier, - layersId, renderFrame, aParentIsActive); + layersId, renderFrame, aParentIsActive, mSizeMode); } bool @@ -906,7 +913,6 @@ TabParent::RecvSetDimensions(const uint32_t& aFlags, MOZ_ASSERT(!(aFlags & nsIEmbeddingSiteWindow::DIM_FLAGS_SIZE_INNER), "We should never see DIM_FLAGS_SIZE_INNER here!"); - nsCOMPtr widget = GetWidget(); NS_ENSURE_TRUE(mFrameElement, true); nsCOMPtr docShell = mFrameElement->OwnerDoc()->GetDocShell(); NS_ENSURE_TRUE(docShell, true); @@ -990,11 +996,19 @@ TabParent::UpdateDimensions(const nsIntRect& rect, const ScreenIntSize& size) CSSRect unscaledRect = devicePixelRect / widgetScale; CSSSize unscaledSize = devicePixelSize / widgetScale; Unused << SendUpdateDimensions(unscaledRect, unscaledSize, - widget->SizeMode(), orientation, chromeOffset); } } +void +TabParent::SizeModeChanged(const nsSizeMode& aSizeMode) +{ + if (!mIsDestroyed && aSizeMode != mSizeMode) { + mSizeMode = aSizeMode; + Unused << SendSizeModeChanged(aSizeMode); + } +} + void TabParent::UpdateFrame(const FrameMetrics& aFrameMetrics) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 080ff547c29..29f2332c94b 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -365,6 +365,8 @@ public: void UpdateDimensions(const nsIntRect& aRect, const ScreenIntSize& aSize); + void SizeModeChanged(const nsSizeMode& aSizeMode); + void UpdateFrame(const layers::FrameMetrics& aFrameMetrics); void UIResolutionChanged(); @@ -670,6 +672,7 @@ protected: float mDPI; CSSToLayoutDeviceScale mDefaultScale; bool mUpdatedDimensions; + nsSizeMode mSizeMode; LayoutDeviceIntPoint mChromeOffset; private: diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 8bedc64f72f..50ebea7c8d5 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2045,6 +2045,39 @@ nsPresContext::PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint, RestyleManager()->PostRebuildAllStyleDataEvent(aExtraHint, aRestyleHint); } +struct MediaFeatureHints +{ + nsRestyleHint restyleHint; + nsChangeHint changeHint; +}; + +static bool +MediaFeatureValuesChangedAllDocumentsCallback(nsIDocument* aDocument, void* aHints) +{ + MediaFeatureHints* hints = static_cast(aHints); + if (nsIPresShell* shell = aDocument->GetShell()) { + if (nsPresContext* pc = shell->GetPresContext()) { + pc->MediaFeatureValuesChangedAllDocuments(hints->restyleHint, + hints->changeHint); + } + } + return true; +} + +void +nsPresContext::MediaFeatureValuesChangedAllDocuments(nsRestyleHint aRestyleHint, + nsChangeHint aChangeHint) +{ + MediaFeatureValuesChanged(aRestyleHint, aChangeHint); + MediaFeatureHints hints = { + aRestyleHint, + aChangeHint + }; + + mDocument->EnumerateSubDocuments(MediaFeatureValuesChangedAllDocumentsCallback, + &hints); +} + void nsPresContext::MediaFeatureValuesChanged(nsRestyleHint aRestyleHint, nsChangeHint aChangeHint) @@ -2142,6 +2175,21 @@ nsPresContext::HandleMediaFeatureValuesChangedEvent() } } +static void +NotifyTabSizeModeChanged(TabParent* aTab, void* aArg) +{ + nsSizeMode* count = static_cast(aArg); + aTab->SizeModeChanged(*count); +} + +void +nsPresContext::SizeModeChanged(nsSizeMode aSizeMode) +{ + nsContentUtils::CallOnAllRemoteChildren(mDocument->GetWindow(), + NotifyTabSizeModeChanged, &aSizeMode); + MediaFeatureValuesChangedAllDocuments(eRestyle_Subtree, NS_STYLE_HINT_REFLOW); +} + nsCompatibility nsPresContext::CompatibilityMode() const { diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index d86246ce365..813a0466a38 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -21,6 +21,7 @@ #include "nsIObserver.h" #include "nsITimer.h" #include "nsCRT.h" +#include "nsIWidgetListener.h" #include "FramePropertyTable.h" #include "nsGkAtoms.h" #include "nsCycleCollectionParticipant.h" @@ -278,6 +279,14 @@ public: */ void MediaFeatureValuesChanged(nsRestyleHint aRestyleHint, nsChangeHint aChangeHint = nsChangeHint(0)); + /** + * Calls MediaFeatureValuesChanged for this pres context and all descendant + * subdocuments that have a pres context. This should be used for media + * features that must be updated in all subdocuments e.g. display-mode. + */ + void MediaFeatureValuesChangedAllDocuments(nsRestyleHint aRestyleHint, + nsChangeHint aChangeHint = nsChangeHint(0)); + void PostMediaFeatureValuesChangedEvent(); void HandleMediaFeatureValuesChangedEvent(); void FlushPendingMediaFeatureValuesChanged() { @@ -285,6 +294,13 @@ public: MediaFeatureValuesChanged(nsRestyleHint(0)); } + /** + * Updates the size mode on all remote children and recursively notifies this + * document and all subdocuments (including remote children) that a media + * feature value has changed. + */ + void SizeModeChanged(nsSizeMode aSizeMode); + /** * Access compatibility mode for this context. This is the same as * our document's compatibility mode. diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 86d716e7f4b..fbde7c5b83b 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -169,6 +169,7 @@ CSS_KEY(bottom-outside, bottom_outside) CSS_KEY(break-all, break_all) CSS_KEY(break-word, break_word) CSS_KEY(brightness, brightness) +CSS_KEY(browser, browser) CSS_KEY(bullets, bullets) CSS_KEY(button, button) CSS_KEY(buttonface, buttonface) @@ -280,6 +281,7 @@ CSS_KEY(forwards, forwards) CSS_KEY(fraktur, fraktur) CSS_KEY(from-image, from_image) CSS_KEY(full-width, full_width) +CSS_KEY(fullscreen, fullscreen) CSS_KEY(grab, grab) CSS_KEY(grabbing, grabbing) CSS_KEY(grad, grad) @@ -535,6 +537,7 @@ CSS_KEY(square, square) CSS_KEY(stacked-fractions, stacked_fractions) CSS_KEY(start, start) CSS_KEY(static, static) +CSS_KEY(standalone, standalone) CSS_KEY(status-bar, status_bar) CSS_KEY(step-end, step_end) CSS_KEY(step-start, step_start) @@ -707,6 +710,7 @@ CSS_KEY(menulist-text, menulist_text) CSS_KEY(menulist-textfield, menulist_textfield) CSS_KEY(meterbar, meterbar) CSS_KEY(meterchunk, meterchunk) +CSS_KEY(minimal-ui, minimal_ui) CSS_KEY(range, range) CSS_KEY(range-thumb, range_thumb) CSS_KEY(sans-serif, sans_serif) diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp index 22966c192b8..6cc37bd6848 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -17,6 +17,7 @@ #endif #include "nsCSSRuleProcessor.h" #include "nsDeviceContext.h" +#include "nsIBaseWindow.h" #include "nsIDocument.h" using namespace mozilla; @@ -33,6 +34,14 @@ static const nsCSSProps::KTableEntry kScanKeywords[] = { { eCSSKeyword_UNKNOWN, -1 } }; +static const nsCSSProps::KTableEntry kDisplayModeKeywords[] = { + { eCSSKeyword_browser, NS_STYLE_DISPLAY_MODE_BROWSER }, + { eCSSKeyword_minimal_ui, NS_STYLE_DISPLAY_MODE_MINIMAL_UI }, + { eCSSKeyword_standalone, NS_STYLE_DISPLAY_MODE_STANDALONE }, + { eCSSKeyword_fullscreen, NS_STYLE_DISPLAY_MODE_FULLSCREEN }, + { eCSSKeyword_UNKNOWN, -1 } +}; + #ifdef XP_WIN struct WindowsThemeName { LookAndFeel::WindowsTheme id; @@ -301,6 +310,34 @@ GetScan(nsPresContext* aPresContext, const nsMediaFeature*, return NS_OK; } +static nsresult +GetDisplayMode(nsPresContext* aPresContext, const nsMediaFeature*, + nsCSSValue& aResult) +{ + nsCOMPtr container = aPresContext->GetRootPresContext()-> + Document()->GetContainer(); + nsCOMPtr baseWindow = do_QueryInterface(container); + if (!baseWindow) { + aResult.SetIntValue(NS_STYLE_DISPLAY_MODE_BROWSER, eCSSUnit_Enumerated); + return NS_OK; + } + nsCOMPtr mainWidget; + baseWindow->GetMainWidget(getter_AddRefs(mainWidget)); + int32_t displayMode; + nsSizeMode mode = mainWidget ? mainWidget->SizeMode() : nsSizeMode_Normal; + switch (mode) { + case nsSizeMode_Fullscreen: + displayMode = NS_STYLE_DISPLAY_MODE_FULLSCREEN; + break; + default: + displayMode = NS_STYLE_DISPLAY_MODE_BROWSER; + break; + } + + aResult.SetIntValue(displayMode, eCSSUnit_Enumerated); + return NS_OK; +} + static nsresult GetGrid(nsPresContext* aPresContext, const nsMediaFeature*, nsCSSValue& aResult) @@ -530,6 +567,14 @@ nsMediaFeatures::features[] = { { nullptr }, GetGrid }, + { + &nsGkAtoms::displayMode, + nsMediaFeature::eMinMaxNotAllowed, + nsMediaFeature::eEnumerated, + nsMediaFeature::eNoRequirements, + { kDisplayModeKeywords }, + GetDisplayMode + }, // Webkit extensions that we support for de-facto web compatibility // -webkit-{min|max}-device-pixel-ratio (controlled with its own pref): diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index ffa27adf5d5..74b33387a24 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -1205,6 +1205,12 @@ enum class FillMode : uint32_t; #define NS_STYLE_SCAN_PROGRESSIVE 0 #define NS_STYLE_SCAN_INTERLACE 1 +// display-mode +#define NS_STYLE_DISPLAY_MODE_BROWSER 0 +#define NS_STYLE_DISPLAY_MODE_MINIMAL_UI 1 +#define NS_STYLE_DISPLAY_MODE_STANDALONE 2 +#define NS_STYLE_DISPLAY_MODE_FULLSCREEN 3 + } // namespace mozilla #endif /* nsStyleConsts_h___ */ diff --git a/layout/style/test/chrome/chrome.ini b/layout/style/test/chrome/chrome.ini index 6064cce12b2..37f498d9c7b 100644 --- a/layout/style/test/chrome/chrome.ini +++ b/layout/style/test/chrome/chrome.ini @@ -16,6 +16,7 @@ support-files = [test_bug1157097.html] [test_bug1160724.xul] [test_bug535806.xul] +[test_display_mode.html] [test_hover.html] skip-if = buildapp == 'mulet' [test_moz_document_rules.html] diff --git a/layout/style/test/chrome/test_display_mode.html b/layout/style/test/chrome/test_display_mode.html new file mode 100644 index 00000000000..244eefea272 --- /dev/null +++ b/layout/style/test/chrome/test_display_mode.html @@ -0,0 +1,94 @@ + + + + + + Test for Display Mode + + + + + + + + +Mozilla Bug 1104916 + +

+ +
+
+ + diff --git a/layout/style/test/test_media_queries.html b/layout/style/test/test_media_queries.html index 5f900d79840..85c7dca8b2e 100644 --- a/layout/style/test/test_media_queries.html +++ b/layout/style/test/test_media_queries.html @@ -253,6 +253,14 @@ function run() { expression_should_not_be_parseable("max-" + feature); } + var mediatypes = ["browser", "minimal-ui", "standalone", "fullscreen"]; + + mediatypes.forEach(function(type) { + expression_should_be_parseable("display-mode: " + type); + }); + + expression_should_not_be_parseable("display-mode: invalid") + var content_div = document.getElementById("content"); content_div.style.font = "initial"; var em_size = diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp index 4aa96857f87..b8c102e2ab8 100644 --- a/xpfe/appshell/nsWebShellWindow.cpp +++ b/xpfe/appshell/nsWebShellWindow.cpp @@ -365,6 +365,11 @@ nsWebShellWindow::SizeModeChanged(nsSizeMode sizeMode) ourWindow->DispatchCustomEvent(NS_LITERAL_STRING("sizemodechange")); } + nsIPresShell* presShell = GetPresShell(); + if (presShell) { + presShell->GetPresContext()->SizeModeChanged(sizeMode); + } + // Note the current implementation of SetSizeMode just stores // the new state; it doesn't actually resize. So here we store // the state and pass the event on to the OS. The day is coming