Bug 1104916 - Implement CSS media query display-mode. r=cam

This commit is contained in:
Brendan Dahl 2016-02-04 13:34:00 +01:00
parent ec8ee84b85
commit 79e271901d
15 changed files with 277 additions and 11 deletions

View File

@ -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")

View File

@ -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.

View File

@ -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<nsIDocument> document(GetDocument());
nsCOMPtr<nsIPresShell> 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)
{

View File

@ -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;

View File

@ -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<nsISupports> container = mFrameElement->OwnerDoc()->GetContainer();
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
nsCOMPtr<nsIWidget> 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<nsIWidget> widget = GetWidget();
NS_ENSURE_TRUE(mFrameElement, true);
nsCOMPtr<nsIDocShell> 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)
{

View File

@ -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:

View File

@ -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<MediaFeatureHints*>(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<nsSizeMode*>(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
{

View File

@ -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.

View File

@ -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)

View File

@ -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<nsISupports> container = aPresContext->GetRootPresContext()->
Document()->GetContainer();
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
if (!baseWindow) {
aResult.SetIntValue(NS_STYLE_DISPLAY_MODE_BROWSER, eCSSUnit_Enumerated);
return NS_OK;
}
nsCOMPtr<nsIWidget> 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):

View File

@ -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___ */

View File

@ -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]

View File

@ -0,0 +1,94 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1104916
-->
<head>
<meta charset="utf-8">
<title>Test for Display Mode</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Display Mode **/
SimpleTest.waitForExplicitFinish();
Components.utils.import("resource://gre/modules/Services.jsm");
function waitOneEvent(element, name) {
return new Promise(function(resolve, reject) {
element.addEventListener(name, function listener() {
element.removeEventListener(name, listener);
resolve();
});
});
}
add_task(function* () {
yield waitOneEvent(window, "load");
var iframe = document.getElementById("subdoc");
var subdoc = iframe.contentDocument;
var style = subdoc.getElementById("style");
var bodyComputedStyled = subdoc.defaultView.getComputedStyle(subdoc.body, "");
var win = Services.wm.getMostRecentWindow("navigator:browser");
function queryApplies(q) {
style.setAttribute("media", q);
return bodyComputedStyled.getPropertyValue("text-decoration") == "underline";
}
function shouldApply(q) {
ok(queryApplies(q), q + " should apply");
}
function shouldNotApply(q) {
ok(!queryApplies(q), q + " should not apply");
}
shouldApply("all and (display-mode: browser)");
shouldNotApply("all and (display-mode: fullscreen)");
shouldNotApply("all and (display-mode: standalone)");
shouldNotApply("all and (display-mode: minimal-ui)");
// Test entering the OS's fullscreen mode.
var fullScreenEntered = waitOneEvent(win, "sizemodechange");
synthesizeKey("VK_F11", {});
yield fullScreenEntered;
shouldApply("all and (display-mode: fullscreen)");
shouldNotApply("all and (display-mode: browser)");
var fullScreenExited = waitOneEvent(win, "sizemodechange");
synthesizeKey("VK_F11", {});
yield fullScreenExited;
shouldNotApply("all and (display-mode: fullscreen)");
shouldApply("all and (display-mode: browser)");
// Test entering fullscreen through document requestFullScreen.
fullScreenEntered = waitOneEvent(document, "mozfullscreenchange");
document.body.mozRequestFullScreen();
yield fullScreenEntered
ok(document.mozFullScreenElement, "window entered fullscreen");
shouldApply("all and (display-mode: fullscreen)");
shouldNotApply("all and (display-mode: browser)");
fullScreenExited = waitOneEvent(document, "mozfullscreenchange");
document.mozCancelFullScreen();
yield fullScreenExited;
ok(!document.mozFullScreenElement, "window exited fullscreen");
shouldNotApply("all and (display-mode: fullscreen)");
shouldApply("all and (display-mode: browser)");
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1104916">Mozilla Bug 1104916</a>
<iframe id="subdoc" src="http://mochi.test:8888/tests/layout/style/test/media_queries_iframe.html"></iframe>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -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 =

View File

@ -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