From f20e4d1ec029e009e2f7e9c9a431e012143e7e7b Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 23 Feb 2016 17:10: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 | 52 ++++++++++ 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 ++ widget/windows/nsWindow.cpp | 4 +- xpfe/appshell/nsWebShellWindow.cpp | 5 + 16 files changed, 284 insertions(+), 12 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 eb2f3b50598..035502691e5 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -308,6 +308,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 b183dd08d7f..9d953f913a6 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -520,7 +520,8 @@ child: TextureFactoryIdentifier textureFactoryIdentifier, uint64_t layersId, nullable PRenderFrame renderFrame, - bool parentIsActive); + bool parentIsActive, + nsSizeMode sizeMode); async LoadURL(nsCString uri, BrowserConfiguration config, ShowInfo info); @@ -528,10 +529,12 @@ 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 SizeModeChanged(nsSizeMode sizeMode); + /** * Sending an activate message moves focus to the child. */ diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 018df60e1a9..124f739b200 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1482,7 +1482,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; } @@ -1594,10 +1594,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); @@ -1633,7 +1635,6 @@ TabChild::RecvShow(const ScreenIntSize& aSize, bool TabChild::RecvUpdateDimensions(const CSSRect& rect, const CSSSize& size, - const nsSizeMode& sizeMode, const ScreenOrientationInternal& orientation, const LayoutDeviceIntPoint& chromeDisp) { @@ -1660,7 +1661,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); @@ -1668,6 +1668,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::UpdateFrame(const FrameMetrics& aFrameMetrics) { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index af69cf0b17c..f98bf516adb 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -326,14 +326,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 RecvActivate() override; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 4e90264c384..87ba05fa411 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::UIResolutionChanged() { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 205e104e428..e07bd5b3501 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -337,6 +337,8 @@ public: void UpdateDimensions(const nsIntRect& aRect, const ScreenIntSize& aSize); + void SizeModeChanged(const nsSizeMode& aSizeMode); + void UIResolutionChanged(); void ThemeChanged(); @@ -600,6 +602,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 f901e557247..41a904ccdc1 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -2051,6 +2051,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) @@ -2157,6 +2190,25 @@ nsPresContext::HandleMediaFeatureValuesChangedEvent() } } +static void +NotifyTabSizeModeChanged(TabParent* aTab, void* aArg) +{ + nsSizeMode* sizeMode = static_cast(aArg); + aTab->SizeModeChanged(*sizeMode); +} + +void +nsPresContext::SizeModeChanged(nsSizeMode aSizeMode) +{ + if (HasCachedStyleData()) { + 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 31e05a71db4..48b1a68914e 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" @@ -279,6 +280,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() { @@ -286,6 +295,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 05a0f0ada6e..d1dc7f43fc6 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) @@ -706,6 +709,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 7678772443a..0bd1b0cfefe 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" #include "nsContentUtils.h" #include "mozilla/StyleSheetHandle.h" @@ -36,6 +37,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; @@ -304,6 +313,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) @@ -533,6 +570,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 cd9c98fc80d..25b8634b174 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/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 73f117f818e..db38461d817 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -6159,6 +6159,8 @@ void nsWindow::OnWindowPosChanged(WINDOWPOS* wp) pl.length = sizeof(pl); ::GetWindowPlacement(mWnd, &pl); + nsSizeMode previousSizeMode = mSizeMode; + // Windows has just changed the size mode of this window. The call to // SizeModeChanged will trigger a call into SetSizeMode where we will // set the min/max window state again or for nsSizeMode_Normal, call @@ -6203,7 +6205,7 @@ void nsWindow::OnWindowPosChanged(WINDOWPOS* wp) } #endif - if (mWidgetListener) + if (mWidgetListener && mSizeMode != previousSizeMode) mWidgetListener->SizeModeChanged(mSizeMode); // If window was restored, window activation was bypassed during the diff --git a/xpfe/appshell/nsWebShellWindow.cpp b/xpfe/appshell/nsWebShellWindow.cpp index 4aa96857f87..b44a9bf3f33 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; + if ((presShell = GetPresShell())) { + 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