Merge inbound to central, a=merge

MozReview-Commit-ID: 5Ytu9rQ8iD5
This commit is contained in:
Wes Kocher 2016-12-19 16:46:20 -08:00
commit cc2a84852b
49 changed files with 938 additions and 84 deletions

View File

@ -231,7 +231,6 @@ window:not([chromehidden~="toolbar"]) #urlbar-wrapper {
}
/* No extra vertical padding for nav bar */
#nav-bar-customization-target,
#nav-bar {
padding-top: 0;
padding-bottom: 0;

View File

@ -98,7 +98,7 @@
}
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
#main-window {
background-color: transparent;
}
@ -225,7 +225,7 @@
background-color: hsl(355, 82%, 69%);
}
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
.titlebar-button {
background-color: -moz-field;
}
@ -444,7 +444,7 @@
}
/* Aero Basic */
@media not all and (-moz-windows-compositor) {
@media (-moz-windows-compositor: 0) {
@media (-moz-windows-default-theme) {
#main-window {
background-color: rgb(185,209,234);

View File

@ -187,8 +187,8 @@ toolbar:-moz-lwtheme {
transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
}
@media not all and (-moz-windows-compositor),
not all and (-moz-windows-default-theme) {
@media (-moz-windows-compositor: 0),
(-moz-windows-default-theme: 0) {
/* Please keep the menu text colors in this media block in sync with
* devedition.css, minus the :not(:-moz-lwtheme) condition - see Bug 1165718.
*/
@ -203,7 +203,7 @@ toolbar:-moz-lwtheme {
}
}
@media not all and (-moz-windows-compositor) {
@media (-moz-windows-compositor: 0) {
#main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
visibility: hidden;
}
@ -383,7 +383,7 @@ toolbar:-moz-lwtheme {
border-top: 1px solid @toolbarShadowColor@ !important;
box-shadow: 0 1px 0 @toolbarHighlight@ inset;
}
@media not all and (-moz-windows-compositor) {
@media (-moz-windows-compositor: 0) {
#TabsToolbar[collapsed="true"] + #nav-bar {
border-top-style: none !important;
}
@ -1614,7 +1614,7 @@ html|span.ac-emphasize-text-url {
font-weight: 600;
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
.autocomplete-richlistitem[selected=true] {
background-color: Highlight;
}
@ -2560,7 +2560,7 @@ notification.pluginVulnerable > .notification-inner > .messageCloseButton {
* window caption buttons, and therefore needs to be special-cased.
*/
@media (-moz-windows-default-theme) {
@media not all and (-moz-windows-compositor) {
@media (-moz-windows-compositor: 0) {
#main-window[sizemode="normal"] > #titlebar > #titlebar-content > #titlebar-buttonbox-container > #private-browsing-indicator-titlebar > .private-browsing-indicator {
background-image: url("chrome://browser/skin/privatebrowsing-mask-titlebar-XPVista7-tall.png");
height: 28px;

View File

@ -120,7 +120,7 @@ menu[disabled="true"].subviewbutton > .menu-right {
list-style-image: url(chrome://browser/skin/customizableui/menu-arrow.svg#arrow-disabled);
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
menu[_moz-menuactive].subviewbutton > .menu-right {
list-style-image: url(chrome://browser/skin/customizableui/menu-arrow.svg#arrow-hover);
}

View File

@ -19,7 +19,7 @@
(Win XP or 7 in classic / basic theme), or else dragging and focus become
broken. So instead just show the normal titlebar in that case, and override
the window color as transparent when the compositor is available. */
@media not all and (-moz-windows-compositor) {
@media (-moz-windows-compositor: 0) {
#main-window[tabsintitlebar] #titlebar:-moz-lwtheme {
visibility: visible;
}
@ -191,8 +191,8 @@
}
/* Use proper menu text styling in Win7 classic mode (copied from browser.css) */
@media not all and (-moz-windows-compositor),
not all and (-moz-windows-default-theme) {
@media (-moz-windows-compositor: 0),
(-moz-windows-default-theme: 0) {
#main-window[tabsintitlebar]:not([inFullscreen]) #toolbar-menubar,
#main-window[tabsintitlebar]:not([inFullscreen]) #TabsToolbar {
color: CaptionText;

View File

@ -4,7 +4,7 @@
%include ../../../shared/incontentprefs/preferences.inc.css
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
#category-general > .category-icon {
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#general-native");
}

View File

@ -3570,6 +3570,11 @@ nsresult nsContentUtils::FormatLocalizedString(PropertiesFile aFile,
NS_ENSURE_SUCCESS(rv, rv);
nsIStringBundle *bundle = sStringBundles[aFile];
if (!aParams || !aParamsLength) {
return bundle->GetStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
getter_Copies(aResult));
}
return bundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aKey).get(),
aParams, aParamsLength,
getter_Copies(aResult));

View File

@ -568,6 +568,34 @@ Event::SetEventType(const nsAString& aEventTypeArg)
mEvent->SetDefaultComposedInNativeAnonymousContent();
}
already_AddRefed<EventTarget>
Event::EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget)
{
nsCOMPtr<EventTarget> relatedTarget = aRelatedTarget;
if (relatedTarget) {
nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
nsCOMPtr<nsIContent> currentTarget =
do_QueryInterface(mEvent->mCurrentTarget);
if (content && content->ChromeOnlyAccess() &&
!nsContentUtils::CanAccessNativeAnon()) {
content = content->FindFirstNonChromeOnlyAccessContent();
relatedTarget = do_QueryInterface(content);
}
nsIContent* shadowRelatedTarget =
GetShadowRelatedTarget(currentTarget, content);
if (shadowRelatedTarget) {
relatedTarget = shadowRelatedTarget;
}
if (relatedTarget) {
relatedTarget = relatedTarget->GetTargetForDOMEvent();
}
}
return relatedTarget.forget();
}
void
Event::InitEvent(const nsAString& aEventTypeArg,
bool aCanBubbleArg,

View File

@ -284,6 +284,9 @@ protected:
mEvent->SetComposed(aComposed);
}
already_AddRefed<EventTarget>
EnsureWebAccessibleRelatedTarget(EventTarget* aRelatedTarget);
mozilla::WidgetEvent* mEvent;
RefPtr<nsPresContext> mPresContext;
nsCOMPtr<EventTarget> mExplicitOriginalTarget;

View File

@ -31,14 +31,15 @@ NS_IMETHODIMP
FocusEvent::GetRelatedTarget(nsIDOMEventTarget** aRelatedTarget)
{
NS_ENSURE_ARG_POINTER(aRelatedTarget);
NS_IF_ADDREF(*aRelatedTarget = GetRelatedTarget());
*aRelatedTarget = GetRelatedTarget().take();
return NS_OK;
}
EventTarget*
already_AddRefed<EventTarget>
FocusEvent::GetRelatedTarget()
{
return mEvent->AsFocusEvent()->mRelatedTarget;
return
EnsureWebAccessibleRelatedTarget(mEvent->AsFocusEvent()->mRelatedTarget);
}
void

View File

@ -33,7 +33,7 @@ public:
nsPresContext* aPresContext,
InternalFocusEvent* aEvent);
EventTarget* GetRelatedTarget();
already_AddRefed<EventTarget> GetRelatedTarget();
static already_AddRefed<FocusEvent> Constructor(const GlobalObject& aGlobal,
const nsAString& aType,

View File

@ -302,27 +302,7 @@ MouseEvent::GetRelatedTarget()
break;
}
if (relatedTarget) {
nsCOMPtr<nsIContent> content = do_QueryInterface(relatedTarget);
nsCOMPtr<nsIContent> currentTarget =
do_QueryInterface(mEvent->mCurrentTarget);
nsIContent* shadowRelatedTarget = GetShadowRelatedTarget(currentTarget, content);
if (shadowRelatedTarget) {
relatedTarget = shadowRelatedTarget;
}
if (content && content->ChromeOnlyAccess() &&
!nsContentUtils::CanAccessNativeAnon()) {
relatedTarget = do_QueryInterface(content->FindFirstNonChromeOnlyAccessContent());
}
if (relatedTarget) {
relatedTarget = relatedTarget->GetTargetForDOMEvent();
}
return relatedTarget.forget();
}
return nullptr;
return EnsureWebAccessibleRelatedTarget(relatedTarget);
}
void

View File

@ -423,6 +423,7 @@ support-files =
[test_bug1146116.html]
[test_bug1264157.html]
[test_bug1287321.html]
[test_bug1323815.html]
[test_change_crossorigin.html]
[test_checked.html]
[test_dir_attributes_reflection.html]

View File

@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1323815
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1323815</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 1323815 **/
SimpleTest.waitForExplicitFinish();
function test() {
var n = document.getElementById("number");
var t = document.getElementById("text");
t.focus();
var gotBlur = false;
t.onblur = function(e) {
try {
is(e.relatedTarget.localName, "input");
} catch(ex) {
ok(false, "Accessing properties on the relatedTarget shouldn't throw! " + ex);
}
gotBlur = true;
}
n.focus();
ok(gotBlur);
SimpleTest.finish();
}
SimpleTest.waitForFocus(test);
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1323815">Mozilla Bug 1323815</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<input type="number" id="number"><input type="text" id="text">
</body>
</html>

View File

@ -229,6 +229,8 @@ ServiceWorkerRegisterNetworkError=Failed to register/update a ServiceWorker for
ServiceWorkerRegisterMimeTypeError=Failed to register/update a ServiceWorker for scope %1$S: Bad Content-Type of %2$S received for script %3$S. Must be text/javascript, application/x-javascript, or application/javascript.
# LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is a URL representing the scope of the ServiceWorker.
ServiceWorkerGraceTimeoutTermination=Terminating ServiceWorker for scope %1$S with pending waitUntil/respondWith promises because of grace timeout.
# LOCALIZATION NOTE (ServiceWorkerNoFetchHandler): Do not translate "Fetch".
ServiceWorkerNoFetchHandler=Fetch event handlers must be added during the worker scripts initial evaluation.
ExecCommandCutCopyDeniedNotInputDriven=document.execCommand(cut/copy) was denied because it was not called from inside a short running user-generated event handler.
ManifestShouldBeObject=Manifest should be an object.
ManifestScopeURLInvalid=The scope URL is invalid.

View File

@ -118,7 +118,7 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName,
return GMPGenericErr;
}
Log("cdm: 0x%x", cdm);
RefPtr<CDMWrapper> wrapper(new CDMWrapper(cdm));
RefPtr<CDMWrapper> wrapper(new CDMWrapper(cdm, decryptor));
decryptor->SetCDM(wrapper, aDecryptorId);
*aPluginAPI = decryptor;

View File

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WidevineUtils.h"
#include "WidevineDecryptor.h"
#include "gmp-api/gmp-errors.h"
#include <stdarg.h>
@ -76,4 +77,19 @@ void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto,
aInputBuffer.timestamp = aTimestamp;
}
CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_8* aCDM,
WidevineDecryptor* aDecryptor)
: mCDM(aCDM)
, mDecryptor(aDecryptor)
{
MOZ_ASSERT(mCDM);
}
CDMWrapper::~CDMWrapper()
{
Log("CDMWrapper destroying CDM=%p", mCDM);
mCDM->Destroy();
mCDM = nullptr;
}
} // namespace mozilla

View File

@ -42,23 +42,19 @@ Log(const char* aFormat, ...);
GMPErr
ToGMPErr(cdm::Status aStatus);
class WidevineDecryptor;
class CDMWrapper {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMWrapper)
explicit CDMWrapper(cdm::ContentDecryptionModule_8* aCDM)
: mCDM(aCDM)
{
MOZ_ASSERT(mCDM);
}
explicit CDMWrapper(cdm::ContentDecryptionModule_8* aCDM,
WidevineDecryptor* aDecryptor);
cdm::ContentDecryptionModule_8* GetCDM() const { return mCDM; }
private:
~CDMWrapper();
cdm::ContentDecryptionModule_8* mCDM;
~CDMWrapper() {
Log("CDMWrapper destroying CDM=%p", mCDM);
mCDM->Destroy();
mCDM = nullptr;
}
RefPtr<WidevineDecryptor> mDecryptor;
};
void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto,

View File

@ -180,6 +180,7 @@ ServiceWorkerInfo::ServiceWorkerInfo(nsIPrincipal* aPrincipal,
, mServiceWorkerID(GetNextID())
, mServiceWorkerPrivate(new ServiceWorkerPrivate(this))
, mSkipWaitingFlag(false)
, mHandlesFetch(Unknown)
{
MOZ_ASSERT(mPrincipal);
// cache origin attributes so we can use them off main thread

View File

@ -46,6 +46,12 @@ private:
RefPtr<ServiceWorkerPrivate> mServiceWorkerPrivate;
bool mSkipWaitingFlag;
enum {
Unknown,
Enabled,
Disabled
} mHandlesFetch;
~ServiceWorkerInfo();
// Generates a unique id for the service worker, with zero being treated as
@ -134,6 +140,22 @@ public:
mState = aState;
}
void
SetHandlesFetch(bool aHandlesFetch)
{
AssertIsOnMainThread();
MOZ_DIAGNOSTIC_ASSERT(mHandlesFetch == Unknown);
mHandlesFetch = aHandlesFetch ? Enabled : Disabled;
}
bool
HandlesFetch() const
{
AssertIsOnMainThread();
MOZ_DIAGNOSTIC_ASSERT(mHandlesFetch != Unknown);
return mHandlesFetch != Disabled;
}
void
AppendWorker(ServiceWorker* aWorker);

View File

@ -184,6 +184,7 @@ PopulateRegistrationData(nsIPrincipal* aPrincipal,
if (aRegistration->GetActive()) {
aData.currentWorkerURL() = aRegistration->GetActive()->ScriptSpec();
aData.cacheName() = aRegistration->GetActive()->CacheName();
aData.currentWorkerHandlesFetch() = aRegistration->GetActive()->HandlesFetch();
}
return NS_OK;
@ -1697,6 +1698,8 @@ ServiceWorkerManager::LoadRegistration(
registration->SetActive(
new ServiceWorkerInfo(registration->mPrincipal, registration->mScope,
currentWorkerURL, aRegistration.cacheName()));
registration->GetActive()->SetHandlesFetch(aRegistration.currentWorkerHandlesFetch());
registration->GetActive()->SetActivateStateUncheckedWithoutEvent(ServiceWorkerState::Activated);
}
}

View File

@ -107,19 +107,26 @@ namespace {
class CheckScriptEvaluationWithCallback final : public WorkerRunnable
{
nsMainThreadPtrHandle<ServiceWorkerPrivate> mServiceWorkerPrivate;
nsMainThreadPtrHandle<KeepAliveToken> mKeepAliveToken;
RefPtr<LifeCycleEventCallback> mCallback;
// The script evaluation result must be reported even if the runnable
// is cancelled.
RefPtr<LifeCycleEventCallback> mScriptEvaluationCallback;
#ifdef DEBUG
bool mDone;
#endif
public:
CheckScriptEvaluationWithCallback(WorkerPrivate* aWorkerPrivate,
ServiceWorkerPrivate* aServiceWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
LifeCycleEventCallback* aCallback)
LifeCycleEventCallback* aScriptEvaluationCallback)
: WorkerRunnable(aWorkerPrivate)
, mServiceWorkerPrivate(new nsMainThreadPtrHolder<ServiceWorkerPrivate>(aServiceWorkerPrivate))
, mKeepAliveToken(new nsMainThreadPtrHolder<KeepAliveToken>(aKeepAliveToken))
, mCallback(aCallback)
, mScriptEvaluationCallback(aScriptEvaluationCallback)
#ifdef DEBUG
, mDone(false)
#endif
@ -136,42 +143,55 @@ public:
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
aWorkerPrivate->AssertIsOnWorkerThread();
Done(aWorkerPrivate->WorkerScriptExecutedSuccessfully());
bool fetchHandlerWasAdded = aWorkerPrivate->FetchHandlerWasAdded();
nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<bool>(this,
&CheckScriptEvaluationWithCallback::ReportFetchFlag, fetchHandlerWasAdded);
aWorkerPrivate->DispatchToMainThread(runnable.forget());
ReportScriptEvaluationResult(aWorkerPrivate->WorkerScriptExecutedSuccessfully());
return true;
}
void
ReportFetchFlag(bool aFetchHandlerWasAdded)
{
AssertIsOnMainThread();
mServiceWorkerPrivate->SetHandlesFetch(aFetchHandlerWasAdded);
}
nsresult
Cancel() override
{
Done(false);
ReportScriptEvaluationResult(false);
return WorkerRunnable::Cancel();
}
private:
void
Done(bool aResult)
ReportScriptEvaluationResult(bool aScriptEvaluationResult)
{
#ifdef DEBUG
mDone = true;
#endif
mCallback->SetResult(aResult);
MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(mCallback));
mScriptEvaluationCallback->SetResult(aScriptEvaluationResult);
MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(mScriptEvaluationCallback));
}
};
} // anonymous namespace
nsresult
ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aCallback)
ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aScriptEvaluationCallback)
{
nsresult rv = SpawnWorkerIfNeeded(LifeCycleEvent, nullptr);
NS_ENSURE_SUCCESS(rv, rv);
RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
RefPtr<WorkerRunnable> r = new CheckScriptEvaluationWithCallback(mWorkerPrivate,
token,
aCallback);
this, token,
aScriptEvaluationCallback);
if (NS_WARN_IF(!r->Dispatch())) {
return NS_ERROR_FAILURE;
}
@ -1682,6 +1702,28 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
{
AssertIsOnMainThread();
if (NS_WARN_IF(!mInfo)) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
RefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetRegistration(mInfo->GetPrincipal(), mInfo->Scope());
// Handle Fetch algorithm - step 16. If the service worker didn't register
// any fetch event handlers, then abort the interception and maybe trigger
// the soft update algorithm.
if (!mInfo->HandlesFetch()) {
aChannel->ResetInterception();
// Trigger soft updates if necessary.
registration->MaybeScheduleTimeCheckAndUpdate();
return NS_OK;
}
// if the ServiceWorker script fails to load for some reason, just resume
// the original channel.
nsCOMPtr<nsIRunnable> failRunnable =
@ -1693,16 +1735,6 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel,
nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
if (NS_WARN_IF(!mInfo)) {
return NS_ERROR_FAILURE;
}
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
MOZ_ASSERT(swm);
RefPtr<ServiceWorkerRegistrationInfo> registration =
swm->GetRegistration(mInfo->GetPrincipal(), mInfo->Scope());
nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> regInfo(
new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(registration, false));
@ -2120,4 +2152,16 @@ ServiceWorkerPrivate::Observe(nsISupports* aSubject, const char* aTopic, const c
return NS_OK;
}
void
ServiceWorkerPrivate::SetHandlesFetch(bool aValue)
{
AssertIsOnMainThread();
if (NS_WARN_IF(!mInfo)) {
return;
}
mInfo->SetHandlesFetch(aValue);
}
END_WORKERS_NAMESPACE

View File

@ -153,6 +153,9 @@ public:
void
AddPendingWindow(Runnable* aPendingWindow);
void
SetHandlesFetch(bool aValue);
private:
enum WakeUpReason {
FetchEvent = 0,

View File

@ -41,6 +41,7 @@ namespace {
static const char* gSupportedRegistrarVersions[] = {
SERVICEWORKERREGISTRAR_VERSION,
"4",
"3",
"2"
};
@ -351,6 +352,40 @@ ServiceWorkerRegistrar::ReadData()
GET_LINE(entry->currentWorkerURL());
nsAutoCString fetchFlag;
GET_LINE(fetchFlag);
if (!fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE) &&
!fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_FALSE)) {
return NS_ERROR_INVALID_ARG;
}
entry->currentWorkerHandlesFetch() =
fetchFlag.EqualsLiteral(SERVICEWORKERREGISTRAR_TRUE);
nsAutoCString cacheName;
GET_LINE(cacheName);
CopyUTF8toUTF16(cacheName, entry->cacheName());
} else if (version.EqualsLiteral("4")) {
overwrite = true;
dedupe = true;
nsAutoCString suffix;
GET_LINE(suffix);
PrincipalOriginAttributes attrs;
if (!attrs.PopulateFromSuffix(suffix)) {
return NS_ERROR_INVALID_ARG;
}
GET_LINE(entry->scope());
entry->principal() =
mozilla::ipc::ContentPrincipalInfo(attrs, entry->scope());
GET_LINE(entry->currentWorkerURL());
// default handlesFetch flag to Enabled
entry->currentWorkerHandlesFetch() = true;
nsAutoCString cacheName;
GET_LINE(cacheName);
CopyUTF8toUTF16(cacheName, entry->cacheName());
@ -376,6 +411,9 @@ ServiceWorkerRegistrar::ReadData()
GET_LINE(entry->currentWorkerURL());
// default handlesFetch flag to Enabled
entry->currentWorkerHandlesFetch() = true;
nsAutoCString cacheName;
GET_LINE(cacheName);
CopyUTF8toUTF16(cacheName, entry->cacheName());
@ -404,6 +442,9 @@ ServiceWorkerRegistrar::ReadData()
GET_LINE(entry->currentWorkerURL());
// default handlesFetch flag to Enabled
entry->currentWorkerHandlesFetch() = true;
nsAutoCString cacheName;
GET_LINE(cacheName);
CopyUTF8toUTF16(cacheName, entry->cacheName());
@ -699,6 +740,10 @@ ServiceWorkerRegistrar::WriteData()
buffer.Append(data[i].currentWorkerURL());
buffer.Append('\n');
buffer.Append(data[i].currentWorkerHandlesFetch() ?
SERVICEWORKERREGISTRAR_TRUE : SERVICEWORKERREGISTRAR_FALSE);
buffer.Append('\n');
buffer.Append(NS_ConvertUTF16toUTF8(data[i].cacheName()));
buffer.Append('\n');

View File

@ -16,7 +16,7 @@
#include "nsTArray.h"
#define SERVICEWORKERREGISTRAR_FILE "serviceworker.txt"
#define SERVICEWORKERREGISTRAR_VERSION "4"
#define SERVICEWORKERREGISTRAR_VERSION "5"
#define SERVICEWORKERREGISTRAR_TERMINATOR "#"
#define SERVICEWORKERREGISTRAR_TRUE "true"
#define SERVICEWORKERREGISTRAR_FALSE "false"

View File

@ -13,6 +13,7 @@ struct ServiceWorkerRegistrationData
{
nsCString scope;
nsCString currentWorkerURL;
bool currentWorkerHandlesFetch;
nsString cacheName;

View File

@ -4019,6 +4019,7 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
, mPeriodicGCTimerRunning(false)
, mIdleGCTimerRunning(false)
, mWorkerScriptExecutedSuccessfully(false)
, mFetchHandlerWasAdded(false)
, mOnLine(false)
{
MOZ_ASSERT_IF(!IsDedicatedWorker(), !aWorkerName.IsVoid());

View File

@ -973,6 +973,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
bool mPeriodicGCTimerRunning;
bool mIdleGCTimerRunning;
bool mWorkerScriptExecutedSuccessfully;
bool mFetchHandlerWasAdded;
bool mPreferences[WORKERPREF_COUNT];
bool mOnLine;
@ -1211,6 +1212,22 @@ public:
void
MemoryPressureInternal();
void
SetFetchHandlerWasAdded()
{
MOZ_ASSERT(IsServiceWorker());
AssertIsOnWorkerThread();
mFetchHandlerWasAdded = true;
}
bool
FetchHandlerWasAdded() const
{
MOZ_ASSERT(IsServiceWorker());
AssertIsOnWorkerThread();
return mFetchHandlerWasAdded;
}
JSContext*
GetJSContext() const
{

View File

@ -611,6 +611,89 @@ ServiceWorkerGlobalScope::Registration()
return mRegistration;
}
EventHandlerNonNull*
ServiceWorkerGlobalScope::GetOnfetch()
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
return GetEventHandler(nullptr, NS_LITERAL_STRING("fetch"));
}
namespace {
class ReportFetchListenerWarningRunnable final : public Runnable
{
const nsCString mScope;
nsCString mSourceSpec;
uint32_t mLine;
uint32_t mColumn;
public:
explicit ReportFetchListenerWarningRunnable(const nsString& aScope)
: mScope(NS_ConvertUTF16toUTF8(aScope))
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
JSContext* cx = workerPrivate->GetJSContext();
MOZ_ASSERT(cx);
nsJSUtils::GetCallingLocation(cx, mSourceSpec, &mLine, &mColumn);
}
NS_IMETHOD
Run() override
{
AssertIsOnMainThread();
ServiceWorkerManager::LocalizeAndReportToAllClients(mScope, "ServiceWorkerNoFetchHandler",
nsTArray<nsString>{}, nsIScriptError::warningFlag, NS_ConvertUTF8toUTF16(mSourceSpec),
EmptyString(), mLine, mColumn);
return NS_OK;
}
};
} // anonymous namespace
void
ServiceWorkerGlobalScope::SetOnfetch(mozilla::dom::EventHandlerNonNull* aCallback)
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
if (aCallback) {
if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope);
mWorkerPrivate->DispatchToMainThread(r.forget());
}
mWorkerPrivate->SetFetchHandlerWasAdded();
}
SetEventHandler(nullptr, NS_LITERAL_STRING("fetch"), aCallback);
}
void
ServiceWorkerGlobalScope::AddEventListener(
const nsAString& aType,
dom::EventListener* aListener,
const dom::AddEventListenerOptionsOrBoolean& aOptions,
const dom::Nullable<bool>& aWantsUntrusted,
ErrorResult& aRv)
{
MOZ_ASSERT(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread();
if (mWorkerPrivate->WorkerScriptExecutedSuccessfully()) {
RefPtr<Runnable> r = new ReportFetchListenerWarningRunnable(mScope);
mWorkerPrivate->DispatchToMainThread(r.forget());
}
DOMEventTargetHelper::AddEventListener(aType, aListener, aOptions,
aWantsUntrusted, aRv);
if (!aRv.Failed()) {
mWorkerPrivate->SetFetchHandlerWasAdded();
}
}
namespace {
class SkipWaitingResultRunnable final : public WorkerRunnable

View File

@ -281,13 +281,25 @@ public:
SkipWaiting(ErrorResult& aRv);
IMPL_EVENT_HANDLER(activate)
IMPL_EVENT_HANDLER(fetch)
IMPL_EVENT_HANDLER(install)
IMPL_EVENT_HANDLER(message)
IMPL_EVENT_HANDLER(push)
IMPL_EVENT_HANDLER(pushsubscriptionchange)
EventHandlerNonNull*
GetOnfetch();
void
SetOnfetch(mozilla::dom::EventHandlerNonNull* aCallback);
using DOMEventTargetHelper::AddEventListener;
virtual void
AddEventListener(const nsAString& aType,
dom::EventListener* aListener,
const dom::AddEventListenerOptionsOrBoolean& aOptions,
const dom::Nullable<bool>& aWantsUntrusted,
ErrorResult& aRv) override;
};
class WorkerDebuggerGlobalScope final : public DOMEventTargetHelper,

View File

@ -148,11 +148,15 @@ TEST(ServiceWorkerRegistrar, TestReadData)
nsAutoCString buffer(SERVICEWORKERREGISTRAR_VERSION "\n");
buffer.Append("^appId=123&inBrowser=1\n");
buffer.Append("scope 0\ncurrentWorkerURL 0\ncacheName 0\n");
buffer.Append("scope 0\ncurrentWorkerURL 0\n");
buffer.Append(SERVICEWORKERREGISTRAR_TRUE "\n");
buffer.Append("cacheName 0\n");
buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
buffer.Append("\n");
buffer.Append("scope 1\ncurrentWorkerURL 1\ncacheName 1\n");
buffer.Append("scope 1\ncurrentWorkerURL 1\n");
buffer.Append(SERVICEWORKERREGISTRAR_FALSE "\n");
buffer.Append("cacheName 1\n");
buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail";
@ -176,6 +180,7 @@ TEST(ServiceWorkerRegistrar, TestReadData)
ASSERT_STREQ("scope 0", cInfo0.spec().get());
ASSERT_STREQ("scope 0", data[0].scope().get());
ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get());
ASSERT_TRUE(data[0].currentWorkerHandlesFetch());
ASSERT_STREQ("cacheName 0", NS_ConvertUTF16toUTF8(data[0].cacheName()).get());
const mozilla::ipc::PrincipalInfo& info1 = data[1].principal();
@ -189,6 +194,7 @@ TEST(ServiceWorkerRegistrar, TestReadData)
ASSERT_STREQ("scope 1", cInfo1.spec().get());
ASSERT_STREQ("scope 1", data[1].scope().get());
ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get());
ASSERT_FALSE(data[1].currentWorkerHandlesFetch());
ASSERT_STREQ("cacheName 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get());
}
@ -370,6 +376,59 @@ TEST(ServiceWorkerRegistrar, TestVersion3Migration)
ASSERT_STREQ("cacheName 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get());
}
TEST(ServiceWorkerRegistrar, TestVersion4Migration)
{
nsAutoCString buffer("4" "\n");
buffer.Append("^appId=123&inBrowser=1\n");
buffer.Append("scope 0\ncurrentWorkerURL 0\ncacheName 0\n");
buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
buffer.Append("\n");
buffer.Append("scope 1\ncurrentWorkerURL 1\ncacheName 1\n");
buffer.Append(SERVICEWORKERREGISTRAR_TERMINATOR "\n");
ASSERT_TRUE(CreateFile(buffer)) << "CreateFile should not fail";
RefPtr<ServiceWorkerRegistrarTest> swr = new ServiceWorkerRegistrarTest;
nsresult rv = swr->TestReadData();
ASSERT_EQ(NS_OK, rv) << "ReadData() should not fail";
const nsTArray<ServiceWorkerRegistrationData>& data = swr->TestGetData();
ASSERT_EQ((uint32_t)2, data.Length()) << "2 entries should be found";
const mozilla::ipc::PrincipalInfo& info0 = data[0].principal();
ASSERT_EQ(info0.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content";
const mozilla::ipc::ContentPrincipalInfo& cInfo0 = data[0].principal();
nsAutoCString suffix0;
cInfo0.attrs().CreateSuffix(suffix0);
ASSERT_STREQ("^appId=123&inBrowser=1", suffix0.get());
ASSERT_STREQ("scope 0", cInfo0.spec().get());
ASSERT_STREQ("scope 0", data[0].scope().get());
ASSERT_STREQ("currentWorkerURL 0", data[0].currentWorkerURL().get());
// default is true
ASSERT_EQ(true, data[1].currentWorkerHandlesFetch());
ASSERT_STREQ("cacheName 0", NS_ConvertUTF16toUTF8(data[0].cacheName()).get());
const mozilla::ipc::PrincipalInfo& info1 = data[1].principal();
ASSERT_EQ(info1.type(), mozilla::ipc::PrincipalInfo::TContentPrincipalInfo) << "First principal must be content";
const mozilla::ipc::ContentPrincipalInfo& cInfo1 = data[1].principal();
nsAutoCString suffix1;
cInfo1.attrs().CreateSuffix(suffix1);
ASSERT_STREQ("", suffix1.get());
ASSERT_STREQ("scope 1", cInfo1.spec().get());
ASSERT_STREQ("scope 1", data[1].scope().get());
ASSERT_STREQ("currentWorkerURL 1", data[1].currentWorkerURL().get());
// default is true
ASSERT_EQ(true, data[1].currentWorkerHandlesFetch());
ASSERT_STREQ("cacheName 1", NS_ConvertUTF16toUTF8(data[1].cacheName()).get());
}
TEST(ServiceWorkerRegistrar, TestDedupeRead)
{
nsAutoCString buffer("3" "\n");

View File

@ -214,6 +214,7 @@ support-files =
sharedWorker_fetch.js
async_waituntil_worker.js
lazy_worker.js
nofetch_handler_worker.js
[test_bug1151916.html]
[test_bug1240436.html]
@ -319,3 +320,4 @@ tags = openwindow
[test_xslt.html]
[test_async_waituntil.html]
[test_worker_reference_gc_timeout.html]
[test_nofetch_handler.html]

View File

@ -0,0 +1,8 @@
function handleFetch(event) {
event.respondWith(new Response('intercepted'));
}
self.oninstall = function(event) {
addEventListener('fetch', handleFetch);
self.onfetch = handleFetch;
}

View File

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 1181127</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/SpawnTask.js"></script>
<script src="error_reporting_helpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
</head>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1181127">Mozilla Bug 1181127</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script class="testbody" type="text/javascript">
add_task(function setupPrefs() {
return SpecialPowers.pushPrefEnv({"set": [
["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
// Make sure the event handler during the install event persists. This ensures
// the reason for which the interception doesn't occur is because of the
// handlesFetch=false flag from ServiceWorkerInfo.
["dom.serviceWorkers.idle_timeout", 299999],
]});
});
var iframeg;
function create_iframe(url) {
return new Promise(function(res) {
iframe = document.createElement('iframe');
iframe.src = url;
iframe.onload = function() { res(iframe) }
document.body.appendChild(iframe);
iframeg = iframe;
})
}
add_task(function* test_nofetch_worker() {
let registration = yield navigator.serviceWorker.register(
"nofetch_handler_worker.js", { scope: "./nofetch_handler_worker/"} )
.then(function(registration) {
var worker = registration.installing;
return new Promise(function(resolve) {
worker.addEventListener('statechange', function() {
if (worker.state === 'activated') {
resolve(registration);
}
});
});
});
let iframe = yield create_iframe("./nofetch_handler_worker/doesnt_exist.html");
ok(!iframe.contentDocument.body.innerHTML.includes("intercepted"), "Request was not intercepted.");
yield SpecialPowers.popPrefEnv();
yield registration.unregister();
});
</script>
</body>
</html>

View File

@ -94,7 +94,7 @@ public:
nsresult rv = GetShutdownBarrier()->AddBlocker(
this, NS_LITERAL_STRING(__FILE__), __LINE__,
NS_LITERAL_STRING("Minidump analysis"));
MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
Unused << NS_WARN_IF(NS_FAILED(rv));
}
NS_IMETHOD Run() override

View File

@ -4518,6 +4518,12 @@ nsIPresShell::RestyleForCSSRuleChanges()
}
RestyleManagerHandle restyleManager = mPresContext->RestyleManager();
if (mStyleSet->IsServo()) {
// Tell Servo that the contents of style sheets have changed.
mStyleSet->AsServo()->NoteStyleSheetsChanged();
}
if (scopeRoots.IsEmpty()) {
// If scopeRoots is empty, we know that mStylesHaveChanged was true at
// the beginning of this function, and that we need to restyle the whole
@ -4550,7 +4556,6 @@ PresShell::RecordStyleSheetChange(StyleSheet* aStyleSheet)
}
} else {
NS_WARNING("stylo: ServoStyleSheets don't support <style scoped>");
return;
}
mStylesHaveChanged = true;

View File

@ -59,6 +59,16 @@ ServoRestyleManager::PostRestyleEvent(Element* aElement,
aRestyleHint |= eRestyle_Self | eRestyle_Subtree;
}
// XXX For now, convert eRestyle_Subtree into (eRestyle_Self |
// eRestyle_SomeDescendants), which Servo will interpret as
// RESTYLE_SELF | RESTYLE_DESCENDANTS, since this is a commonly
// posted restyle hint that doesn't yet align with RestyleHint's
// bits.
if (aRestyleHint & eRestyle_Subtree) {
aRestyleHint &= ~eRestyle_Subtree;
aRestyleHint |= eRestyle_Self | eRestyle_SomeDescendants;
}
if (aRestyleHint || aMinChangeHint) {
Servo_NoteExplicitHints(aElement, aRestyleHint, aMinChangeHint);
}

View File

@ -47,6 +47,8 @@ SERVO_BINDING_FUNC(Servo_StyleSet_RemoveStyleSheet, void,
SERVO_BINDING_FUNC(Servo_StyleSet_InsertStyleSheetBefore, void,
RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet,
RawServoStyleSheetBorrowed reference)
SERVO_BINDING_FUNC(Servo_StyleSet_NoteStyleSheetsChanged, void,
RawServoStyleSetBorrowed set)
// CSSRuleList
SERVO_BINDING_FUNC(Servo_CssRules_ListTypes, void,

View File

@ -474,6 +474,12 @@ ServoStyleSet::StyleNewChildren(Element* aParent)
TraversalRootBehavior::UnstyledChildrenOnly);
}
void
ServoStyleSet::NoteStyleSheetsChanged()
{
Servo_StyleSet_NoteStyleSheetsChanged(mRawSet.get());
}
#ifdef DEBUG
void
ServoStyleSet::AssertTreeIsClean()

View File

@ -142,6 +142,13 @@ public:
*/
void StyleNewChildren(Element* aParent);
/**
* Records that the contents of style sheets have changed since the last
* restyle. Calling this will ensure that the Stylist rebuilds its
* selector maps.
*/
void NoteStyleSheetsChanged();
#ifdef DEBUG
void AssertTreeIsClean();
#else

View File

@ -628,7 +628,11 @@ pref("media.decoder.recycle.enabled", true);
pref("media.android-media-codec.enabled", true);
pref("media.android-media-codec.preferred", true);
// Run decoder in seperate process.
#ifdef NIGHTLY_BUILD
pref("media.android-remote-codec.enabled", true);
#else
pref("media.android-remote-codec.enabled", false);
#endif
// Enable MSE
pref("media.mediasource.enabled", true);

View File

@ -22,6 +22,9 @@ SPHINX_TREES['telemetry'] = 'docs'
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wno-error=shadow']
if CONFIG['ENABLE_TESTS']:
DIRS += ['tests/gtest']
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']

View File

@ -0,0 +1,65 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#ifndef TelemetryFixture_h_
#define TelemetryFixture_h_
#include "mozilla/CycleCollectedJSContext.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/SimpleGlobalObject.h"
using namespace mozilla;
class TelemetryTestFixture: public ::testing::Test {
protected:
TelemetryTestFixture() : mCleanGlobal(nullptr) {}
virtual void SetUp();
JSObject* mCleanGlobal;
nsCOMPtr<nsITelemetry> mTelemetry;
};
void
TelemetryTestFixture::SetUp()
{
mTelemetry = do_GetService("@mozilla.org/base/telemetry;1");
mCleanGlobal =
dom::SimpleGlobalObject::Create(dom::SimpleGlobalObject::GlobalType::BindingDetail);
// The test must fail if we failed getting the global.
ASSERT_NE(mCleanGlobal, nullptr) << "SimpleGlobalObject must return a valid global object.";
}
// AutoJSAPI is annotated with MOZ_STACK_CLASS and thus cannot be
// used as a member of TelemetryTestFixture, since gtest instantiates
// that on the heap. To work around the problem, use the following class
// at the beginning of each Telemetry test.
// Note: this is very similar to AutoJSContext, but it allows to pass a
// global JS object in.
class MOZ_RAII AutoJSContextWithGlobal {
public:
explicit AutoJSContextWithGlobal(JSObject* aGlobalObject);
JSContext* GetJSContext() const;
protected:
dom::AutoJSAPI mJsAPI;
JSContext* mCx;
};
AutoJSContextWithGlobal::AutoJSContextWithGlobal(JSObject* aGlobalObject)
: mCx(nullptr)
{
// The JS API must initialize correctly.
MOZ_ALWAYS_TRUE(mJsAPI.Init(aGlobalObject));
}
JSContext* AutoJSContextWithGlobal::GetJSContext() const
{
return mJsAPI.cx();
}
#endif //TelemetryFixture_h_

View File

@ -0,0 +1,288 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#include "gtest/gtest.h"
#include "js/Conversions.h"
#include "mozilla/Unused.h"
#include "nsJSUtils.h" // nsAutoJSString
#include "nsITelemetry.h"
#include "Telemetry.h"
#include "TelemetryFixture.h"
using namespace mozilla;
#define EXPECTED_STRING "Nice, expected and creative string."
namespace {
void
CheckUintScalar(const char* aName, JSContext* aCx, JS::HandleValue aSnapshot, uint32_t expectedValue)
{
// Validate the value of the test scalar.
JS::RootedValue value(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &value)) << "The test scalar must be reported.";
ASSERT_TRUE(value.isInt32()) << "The scalar value must be of the correct type.";
ASSERT_TRUE(value.toInt32() >= 0) << "The uint scalar type must contain a value >= 0.";
ASSERT_EQ(static_cast<uint32_t>(value.toInt32()), expectedValue) << "The scalar value must match the expected value.";
}
void
CheckBoolScalar(const char* aName, JSContext* aCx, JS::HandleValue aSnapshot, bool expectedValue)
{
// Validate the value of the test scalar.
JS::RootedValue value(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &value)) << "The test scalar must be reported.";
ASSERT_TRUE(value.isBoolean()) << "The scalar value must be of the correct type.";
ASSERT_EQ(static_cast<bool>(value.toBoolean()), expectedValue) << "The scalar value must match the expected value.";
}
void
CheckStringScalar(const char* aName, JSContext* aCx, JS::HandleValue aSnapshot, const char* expectedValue)
{
// Validate the value of the test scalar.
JS::RootedValue value(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &value)) << "The test scalar must be reported.";
ASSERT_TRUE(value.isString()) << "The scalar value must be of the correct type.";
bool sameString;
ASSERT_TRUE(JS_StringEqualsAscii(aCx, value.toString(), expectedValue, &sameString)) << "JS String comparison failed";
ASSERT_TRUE(sameString) << "The scalar value must match the expected string";
}
void
CheckKeyedUintScalar(const char* aName, const char* aKey, JSContext* aCx, JS::HandleValue aSnapshot,
uint32_t expectedValue)
{
JS::RootedValue keyedScalar(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
// Get the aName keyed scalar object from the scalars snapshot.
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &keyedScalar))
<< "The keyed scalar must be reported.";
CheckUintScalar(aKey, aCx, keyedScalar, expectedValue);
}
void
CheckKeyedBoolScalar(const char* aName, const char* aKey, JSContext* aCx, JS::HandleValue aSnapshot,
bool expectedValue)
{
JS::RootedValue keyedScalar(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
// Get the aName keyed scalar object from the scalars snapshot.
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &keyedScalar))
<< "The keyed scalar must be reported.";
CheckBoolScalar(aKey, aCx, keyedScalar, expectedValue);
}
void
CheckNumberOfProperties(const char* aName, JSContext* aCx, JS::HandleValue aSnapshot,
uint32_t expectedNumProperties)
{
JS::RootedValue keyedScalar(aCx);
JS::RootedObject scalarObj(aCx, &aSnapshot.toObject());
// Get the aName keyed scalar object from the scalars snapshot.
ASSERT_TRUE(JS_GetProperty(aCx, scalarObj, aName, &keyedScalar))
<< "The keyed scalar must be reported.";
JS::RootedObject keyedScalarObj(aCx, &keyedScalar.toObject());
JS::Rooted<JS::IdVector> ids(aCx, JS::IdVector(aCx));
ASSERT_TRUE(JS_Enumerate(aCx, keyedScalarObj, &ids))
<< "We must be able to get keyed scalar members.";
ASSERT_EQ(expectedNumProperties, ids.length())
<< "The scalar must report the expected number of properties.";
}
void
GetScalarsSnapshot(bool aKeyed, JSContext* aCx, JS::MutableHandle<JS::Value> aResult)
{
nsCOMPtr<nsITelemetry> telemetry = do_GetService("@mozilla.org/base/telemetry;1");
// Get a snapshot of the scalars.
JS::RootedValue scalarsSnapshot(aCx);
nsresult rv;
if (aKeyed) {
rv = telemetry->SnapshotKeyedScalars(nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN,
false, aCx, 0, &scalarsSnapshot);
} else {
rv = telemetry->SnapshotScalars(nsITelemetry::DATASET_RELEASE_CHANNEL_OPTIN,
false, aCx, 0, &scalarsSnapshot);
}
// Validate the snapshot.
ASSERT_EQ(rv, NS_OK) << "Creating a snapshot of the data must not fail.";
ASSERT_TRUE(scalarsSnapshot.isObject()) << "The snapshot must be an object.";
aResult.set(scalarsSnapshot);
}
} // Anonymous namespace.
// Test that we can properly write unsigned scalars using the C++ API.
TEST_F(TelemetryTestFixture, ScalarUnsigned) {
AutoJSContextWithGlobal cx(mCleanGlobal);
// Make sure we don't get scalars from other tests.
Unused << mTelemetry->ClearScalars();
// Set the test scalar to a known value.
const uint32_t kInitialValue = 1172015;
const uint32_t kExpectedUint = 1172017;
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND, kInitialValue);
Telemetry::ScalarAdd(Telemetry::ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND, kExpectedUint - kInitialValue);
// Check the recorded value.
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
GetScalarsSnapshot(false, cx.GetJSContext(), &scalarsSnapshot);
CheckUintScalar("telemetry.test.unsigned_int_kind", cx.GetJSContext(), scalarsSnapshot, kExpectedUint);
// Try to use SetMaximum.
const uint32_t kExpectedUintMaximum = kExpectedUint * 2;
Telemetry::ScalarSetMaximum(Telemetry::ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND, kExpectedUintMaximum);
// Make sure that calls of the unsupported type don't corrupt the stored value.
// Don't run this part in debug builds as that intentionally asserts.
#ifndef DEBUG
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND, false);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_UNSIGNED_INT_KIND, NS_LITERAL_STRING("test"));
#endif
// Check the recorded value.
GetScalarsSnapshot(false, cx.GetJSContext(), &scalarsSnapshot);
CheckUintScalar("telemetry.test.unsigned_int_kind", cx.GetJSContext(), scalarsSnapshot, kExpectedUintMaximum);
}
// Test that we can properly write boolean scalars using the C++ API.
TEST_F(TelemetryTestFixture, ScalarBoolean) {
AutoJSContextWithGlobal cx(mCleanGlobal);
Unused << mTelemetry->ClearScalars();
// Set the test scalar to a known value.
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, true);
// Make sure that calls of the unsupported type don't corrupt the stored value.
// Don't run this part in debug builds as that intentionally asserts.
#ifndef DEBUG
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, static_cast<uint32_t>(12));
Telemetry::ScalarSetMaximum(Telemetry::ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, 20);
Telemetry::ScalarAdd(Telemetry::ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, 2);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_BOOLEAN_KIND, NS_LITERAL_STRING("test"));
#endif
// Check the recorded value.
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
GetScalarsSnapshot(false, cx.GetJSContext(), &scalarsSnapshot);
CheckBoolScalar("telemetry.test.boolean_kind", cx.GetJSContext(), scalarsSnapshot, true);
}
// Test that we can properly write string scalars using the C++ API.
TEST_F(TelemetryTestFixture, ScalarString) {
AutoJSContextWithGlobal cx(mCleanGlobal);
Unused << mTelemetry->ClearScalars();
// Set the test scalar to a known value.
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_STRING_KIND, NS_LITERAL_STRING(EXPECTED_STRING));
// Make sure that calls of the unsupported type don't corrupt the stored value.
// Don't run this part in debug builds as that intentionally asserts.
#ifndef DEBUG
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_STRING_KIND, static_cast<uint32_t>(12));
Telemetry::ScalarSetMaximum(Telemetry::ScalarID::TELEMETRY_TEST_STRING_KIND, 20);
Telemetry::ScalarAdd(Telemetry::ScalarID::TELEMETRY_TEST_STRING_KIND, 2);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_STRING_KIND, true);
#endif
// Check the recorded value.
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
GetScalarsSnapshot(false, cx.GetJSContext(), &scalarsSnapshot);
CheckStringScalar("telemetry.test.string_kind", cx.GetJSContext(), scalarsSnapshot, EXPECTED_STRING);
}
// Test that we can properly write keyed unsigned scalars using the C++ API.
TEST_F(TelemetryTestFixture, KeyedScalarUnsigned) {
AutoJSContextWithGlobal cx(mCleanGlobal);
Unused << mTelemetry->ClearScalars();
// Set the test scalar to a known value.
const char* kScalarName = "telemetry.test.keyed_unsigned_int";
const uint32_t kKey1Value = 1172015;
const uint32_t kKey2Value = 1172017;
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT,
NS_LITERAL_STRING("key1"), kKey1Value);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT,
NS_LITERAL_STRING("key2"), kKey1Value);
Telemetry::ScalarAdd(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT,
NS_LITERAL_STRING("key2"), 2);
// Make sure that calls of the unsupported type don't corrupt the stored value.
// Don't run this part in debug builds as that intentionally asserts.
#ifndef DEBUG
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT,
NS_LITERAL_STRING("key1"), false);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT, NS_LITERAL_STRING("test"));
#endif
// Check the recorded value.
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
// Check the keyed scalar we're interested in.
CheckKeyedUintScalar(kScalarName, "key1", cx.GetJSContext(), scalarsSnapshot, kKey1Value);
CheckKeyedUintScalar(kScalarName, "key2", cx.GetJSContext(), scalarsSnapshot, kKey2Value);
CheckNumberOfProperties(kScalarName, cx.GetJSContext(), scalarsSnapshot, 2);
// Try to use SetMaximum.
const uint32_t kExpectedUintMaximum = kKey1Value * 2;
Telemetry::ScalarSetMaximum(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_UNSIGNED_INT,
NS_LITERAL_STRING("key1"), kExpectedUintMaximum);
GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
// The first key should be different and te second is expected to be the same.
CheckKeyedUintScalar(kScalarName, "key1", cx.GetJSContext(), scalarsSnapshot, kExpectedUintMaximum);
CheckKeyedUintScalar(kScalarName, "key2", cx.GetJSContext(), scalarsSnapshot, kKey2Value);
CheckNumberOfProperties(kScalarName, cx.GetJSContext(), scalarsSnapshot, 2);
}
TEST_F(TelemetryTestFixture, KeyedScalarBoolean) {
AutoJSContextWithGlobal cx(mCleanGlobal);
Unused << mTelemetry->ClearScalars();
// Set the test scalar to a known value.
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_BOOLEAN_KIND,
NS_LITERAL_STRING("key1"), false);
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_BOOLEAN_KIND,
NS_LITERAL_STRING("key2"), true);
// Make sure that calls of the unsupported type don't corrupt the stored value.
// Don't run this part in debug builds as that intentionally asserts.
#ifndef DEBUG
Telemetry::ScalarSet(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_BOOLEAN_KIND,
NS_LITERAL_STRING("key1"), static_cast<uint32_t>(12));
Telemetry::ScalarSetMaximum(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_BOOLEAN_KIND,
NS_LITERAL_STRING("key1"), 20);
Telemetry::ScalarAdd(Telemetry::ScalarID::TELEMETRY_TEST_KEYED_BOOLEAN_KIND,
NS_LITERAL_STRING("key1"), 2);
#endif
// Check the recorded value.
JS::RootedValue scalarsSnapshot(cx.GetJSContext());
GetScalarsSnapshot(true, cx.GetJSContext(), &scalarsSnapshot);
// Make sure that the keys contain the expected values.
const char* kScalarName = "telemetry.test.keyed_boolean_kind";
CheckKeyedBoolScalar(kScalarName, "key1", cx.GetJSContext(), scalarsSnapshot, false);
CheckKeyedBoolScalar(kScalarName, "key2", cx.GetJSContext(), scalarsSnapshot, true);
CheckNumberOfProperties(kScalarName, cx.GetJSContext(), scalarsSnapshot, 2);
}

View File

@ -0,0 +1,17 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at http://mozilla.org/MPL/2.0/.
Library('telemetrytest')
LOCAL_INCLUDES += [
'../..',
]
UNIFIED_SOURCES = [
'TestScalars.cpp',
]
FINAL_LIBRARY = 'xul-gtest'

View File

@ -59,7 +59,7 @@ button[default="true"] {
-moz-border-left-colors: ThreeDDarkShadow ThreeDHighlight ThreeDLightShadow;
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
@media (-moz-windows-compositor) {
/* This is for high-contrast themes on Windows 8 and later */
button[default="true"],

View File

@ -24,7 +24,7 @@ xul|checkbox {
padding-inline-start: 0;
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
xul|*.checkbox-check {
background-image: none !important;
}
@ -40,7 +40,7 @@ xul|radio {
padding-inline-start: 0;
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
xul|*.radio-check {
background-image: none;
}
@ -74,7 +74,7 @@ xul|checkbox:-moz-focusring > xul|*.checkbox-label-box {
/* Use a 2px border so that selected row highlight is still visible behind
an existing high-contrast border that uses the background color */
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
xul|treechildren::-moz-tree-row(selected),
xul|listbox xul|listitem[selected="true"] {
border: 2px dotted Highlight;

View File

@ -97,7 +97,7 @@ toolbarbutton[checked="true"]:not([disabled="true"]) {
}
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
toolbarbutton:-moz-lwtheme {
-moz-appearance: none;
}

View File

@ -9,7 +9,7 @@
margin-inline-end: 16px;
}
@media not all and (-moz-windows-default-theme) {
@media (-moz-windows-default-theme: 0) {
#header-utils-btn {
list-style-image: url("chrome://mozapps/skin/extensions/utilities.svg#utilities-native");
}