This commit is contained in:
Wes Kocher 2016-08-03 16:47:07 -07:00
Родитель 9605851be0 429b4cc773
Коммит ae855cdb28
53 изменённых файлов: 320 добавлений и 206 удалений

Просмотреть файл

@ -128,6 +128,7 @@ devtools/shared/*.js
!devtools/shared/css-lexer.js !devtools/shared/css-lexer.js
!devtools/shared/defer.js !devtools/shared/defer.js
!devtools/shared/event-emitter.js !devtools/shared/event-emitter.js
!devtools/shared/loader-plugin-raw.jsm
!devtools/shared/task.js !devtools/shared/task.js
devtools/shared/*.jsm devtools/shared/*.jsm
!devtools/shared/Loader.jsm !devtools/shared/Loader.jsm

Просмотреть файл

@ -13,6 +13,7 @@
<em:version>1.0</em:version> <em:version>1.0</em:version>
<em:type>2</em:type> <em:type>2</em:type>
<em:bootstrap>true</em:bootstrap> <em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<!-- Target Application this theme can install into, <!-- Target Application this theme can install into,
with minimum and maximum supported versions. --> with minimum and maximum supported versions. -->

Просмотреть файл

@ -13,6 +13,7 @@
<em:version>1.0</em:version> <em:version>1.0</em:version>
<em:type>2</em:type> <em:type>2</em:type>
<em:bootstrap>true</em:bootstrap> <em:bootstrap>true</em:bootstrap>
<em:multiprocessCompatible>true</em:multiprocessCompatible>
<!-- Target Application this theme can install into, <!-- Target Application this theme can install into,
with minimum and maximum supported versions. --> with minimum and maximum supported versions. -->

Просмотреть файл

@ -101,6 +101,12 @@ function BrowserLoaderBuilder({ baseURI, window, useOnlyShared }) {
paths: Object.assign({}, dynamicPaths, loaderOptions.paths), paths: Object.assign({}, dynamicPaths, loaderOptions.paths),
invisibleToDebugger: loaderOptions.invisibleToDebugger, invisibleToDebugger: loaderOptions.invisibleToDebugger,
requireHook: (id, require) => { requireHook: (id, require) => {
// If |id| requires special handling, simply defer to devtools
// immediately.
if (devtools.isLoaderPluginId(id)) {
return devtools.require(id);
}
const uri = require.resolve(id); const uri = require.resolve(id);
let isBrowserDir = BROWSER_BASED_DIRS.filter(dir => { let isBrowserDir = BROWSER_BASED_DIRS.filter(dir => {
return uri.startsWith(dir); return uri.startsWith(dir);

Просмотреть файл

@ -147,6 +147,7 @@ skip-if = e10s # Test intermittently fails with e10s. Bug 1124162.
[browser_poller.js] [browser_poller.js]
[browser_prefs-01.js] [browser_prefs-01.js]
[browser_prefs-02.js] [browser_prefs-02.js]
[browser_require_raw.js]
[browser_spectrum.js] [browser_spectrum.js]
[browser_theme.js] [browser_theme.js]
[browser_tableWidget_basic.js] [browser_tableWidget_basic.js]

Просмотреть файл

@ -0,0 +1,20 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { BrowserLoader } = Cu.import("resource://devtools/client/shared/browser-loader.js", {});
const { require: browserRequire } = BrowserLoader({
baseURI: "resource://devtools/client/shared/",
window: this
});
const variableFileContents = browserRequire("raw!devtools/client/themes/variables.css");
function test() {
ok(variableFileContents.length > 0, "raw browserRequire worked");
finish();
}

Просмотреть файл

@ -9,45 +9,21 @@
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors * https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
*/ */
const { Cu } = require("chrome");
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const Services = require("Services"); const Services = require("Services");
const { gDevTools } = require("devtools/client/framework/devtools"); const { gDevTools } = require("devtools/client/framework/devtools");
const VARIABLES_URI = "chrome://devtools/skin/variables.css"; const variableFileContents = require("raw!devtools/client/themes/variables.css");
const THEME_SELECTOR_STRINGS = { const THEME_SELECTOR_STRINGS = {
light: ":root.theme-light {", light: ":root.theme-light {",
dark: ":root.theme-dark {" dark: ":root.theme-dark {"
}; };
let variableFileContents;
/**
* Returns a string of the file found at URI
*/
function readURI(uri) {
let stream = NetUtil.newChannel({
uri: NetUtil.newURI(uri, "UTF-8"),
loadUsingSystemPrincipal: true}
).open2();
let count = stream.available();
let data = NetUtil.readInputStreamToString(stream, count, {
charset: "UTF-8"
});
stream.close();
return data;
}
/** /**
* Takes a theme name and returns the contents of its variable rule block. * Takes a theme name and returns the contents of its variable rule block.
* The first time this runs fetches the variables CSS file and caches it. * The first time this runs fetches the variables CSS file and caches it.
*/ */
function getThemeFile(name) { function getThemeFile(name) {
if (!variableFileContents) {
variableFileContents = readURI(VARIABLES_URI);
}
// If there's no theme expected for this name, use `light` as default. // If there's no theme expected for this name, use `light` as default.
let selector = THEME_SELECTOR_STRINGS[name] || let selector = THEME_SELECTOR_STRINGS[name] ||
THEME_SELECTOR_STRINGS.light; THEME_SELECTOR_STRINGS.light;

Просмотреть файл

@ -11,6 +11,7 @@
var { utils: Cu } = Components; var { utils: Cu } = Components;
var { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
var { Loader, descriptor, resolveURI } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {}); var { Loader, descriptor, resolveURI } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
var { requireRawId } = Cu.import("resource://devtools/shared/loader-plugin-raw.jsm", {});
this.EXPORTED_SYMBOLS = ["DevToolsLoader", "devtools", "BuiltinProvider", this.EXPORTED_SYMBOLS = ["DevToolsLoader", "devtools", "BuiltinProvider",
"require", "loader"]; "require", "loader"];
@ -59,6 +60,12 @@ BuiltinProvider.prototype = {
invisibleToDebugger: this.invisibleToDebugger, invisibleToDebugger: this.invisibleToDebugger,
sharedGlobal: true, sharedGlobal: true,
sharedGlobalBlocklist, sharedGlobalBlocklist,
requireHook: (id, require) => {
if (id.startsWith("raw!")) {
return requireRawId(id, require);
}
return require(id);
},
}); });
}, },
@ -120,6 +127,14 @@ DevToolsLoader.prototype = {
return this.require.apply(this, arguments); return this.require.apply(this, arguments);
}, },
/**
* Return true if |id| refers to something requiring help from a
* loader plugin.
*/
isLoaderPluginId: function (id) {
return id.startsWith("raw!");
},
/** /**
* Override the provider used to load the tools. * Override the provider used to load the tools.
*/ */

Просмотреть файл

@ -0,0 +1,41 @@
/* 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/. */
"use strict";
const { utils: Cu } = Components;
const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
/**
* A function that can be used as part of a require hook for a
* loader.js Loader. This function only handles webpack-style "raw!"
* requires; other requires should not be passed to this. See
* https://github.com/webpack/raw-loader.
*/
function requireRawId(id, require) {
let uri = require.resolve(id.slice(4));
// If the original string did not end with ".js", then
// require.resolve might have added the suffix. We don't want to
// add a suffix for a raw load (if needed the caller can specify it
// manually), so remove it here.
if (!id.endsWith(".js") && uri.endsWith(".js")) {
uri = uri.slice(0, -3);
}
let stream = NetUtil.newChannel({
uri: NetUtil.newURI(uri, "UTF-8"),
loadUsingSystemPrincipal: true
}).open2();
let count = stream.available();
let data = NetUtil.readInputStreamToString(stream, count, {
charset: "UTF-8"
});
stream.close();
// For the time being it doesn't seem worthwhile to cache the
// result here.
return data;
}
this.EXPORTED_SYMBOLS = ["requireRawId"];

Просмотреть файл

@ -54,6 +54,7 @@ DevToolsModules(
'dom-node-filter-constants.js', 'dom-node-filter-constants.js',
'event-emitter.js', 'event-emitter.js',
'indentation.js', 'indentation.js',
'loader-plugin-raw.jsm',
'Loader.jsm', 'Loader.jsm',
'Parser.jsm', 'Parser.jsm',
'path.js', 'path.js',

Просмотреть файл

@ -0,0 +1,12 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Test require using "raw!".
function run_test() {
let loader = new DevToolsLoader();
let require = loader.require;
let variableFileContents = require("raw!devtools/client/themes/variables.css");
ok(variableFileContents.length > 0, "raw browserRequire worked");
}

Просмотреть файл

@ -25,6 +25,7 @@ support-files =
[test_console_filtering.js] [test_console_filtering.js]
[test_prettifyCSS.js] [test_prettifyCSS.js]
[test_require_lazy.js] [test_require_lazy.js]
[test_require_raw.js]
[test_require.js] [test_require.js]
[test_stack.js] [test_stack.js]
[test_defer.js] [test_defer.js]

Просмотреть файл

@ -764,11 +764,12 @@ nsDOMWindowUtils::SendPointerEventCommon(const nsAString& aType,
event.pressure = aPressure; event.pressure = aPressure;
event.inputSource = aInputSourceArg; event.inputSource = aInputSourceArg;
event.pointerId = aPointerId; event.pointerId = aPointerId;
event.width = aWidth; event.mWidth = aWidth;
event.height = aHeight; event.mHeight = aHeight;
event.tiltX = aTiltX; event.tiltX = aTiltX;
event.tiltY = aTiltY; event.tiltY = aTiltY;
event.isPrimary = (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == aInputSourceArg) ? true : aIsPrimary; event.mIsPrimary =
(nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == aInputSourceArg) ? true : aIsPrimary;
event.mClickCount = aClickCount; event.mClickCount = aClickCount;
event.mTime = PR_IntervalNow(); event.mTime = PR_IntervalNow();
event.mFlags.mIsSynthesizedForTests = aOptionalArgCount >= 10 ? aIsSynthesized : true; event.mFlags.mIsSynthesizedForTests = aOptionalArgCount >= 10 ? aIsSynthesized : true;

Просмотреть файл

@ -3834,10 +3834,10 @@ CreateMouseOrPointerWidgetEvent(WidgetMouseEvent* aMouseEvent,
newPointerEvent = newPointerEvent =
new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage, new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
aMouseEvent->mWidget); aMouseEvent->mWidget);
newPointerEvent->isPrimary = sourcePointer->isPrimary; newPointerEvent->mIsPrimary = sourcePointer->mIsPrimary;
newPointerEvent->pointerId = sourcePointer->pointerId; newPointerEvent->pointerId = sourcePointer->pointerId;
newPointerEvent->width = sourcePointer->width; newPointerEvent->mWidth = sourcePointer->mWidth;
newPointerEvent->height = sourcePointer->height; newPointerEvent->mHeight = sourcePointer->mHeight;
newPointerEvent->inputSource = sourcePointer->inputSource; newPointerEvent->inputSource = sourcePointer->inputSource;
newPointerEvent->relatedTarget = newPointerEvent->relatedTarget =
nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId) nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)

Просмотреть файл

@ -87,13 +87,13 @@ PointerEvent::Constructor(EventTarget* aOwner,
WidgetPointerEvent* widgetEvent = e->mEvent->AsPointerEvent(); WidgetPointerEvent* widgetEvent = e->mEvent->AsPointerEvent();
widgetEvent->pointerId = aParam.mPointerId; widgetEvent->pointerId = aParam.mPointerId;
widgetEvent->width = aParam.mWidth; widgetEvent->mWidth = aParam.mWidth;
widgetEvent->height = aParam.mHeight; widgetEvent->mHeight = aParam.mHeight;
widgetEvent->pressure = aParam.mPressure; widgetEvent->pressure = aParam.mPressure;
widgetEvent->tiltX = aParam.mTiltX; widgetEvent->tiltX = aParam.mTiltX;
widgetEvent->tiltY = aParam.mTiltY; widgetEvent->tiltY = aParam.mTiltY;
widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType); widgetEvent->inputSource = ConvertStringToPointerType(aParam.mPointerType);
widgetEvent->isPrimary = aParam.mIsPrimary; widgetEvent->mIsPrimary = aParam.mIsPrimary;
widgetEvent->buttons = aParam.mButtons; widgetEvent->buttons = aParam.mButtons;
e->SetTrusted(trusted); e->SetTrusted(trusted);
@ -126,13 +126,13 @@ PointerEvent::PointerId()
int32_t int32_t
PointerEvent::Width() PointerEvent::Width()
{ {
return mEvent->AsPointerEvent()->width; return mEvent->AsPointerEvent()->mWidth;
} }
int32_t int32_t
PointerEvent::Height() PointerEvent::Height()
{ {
return mEvent->AsPointerEvent()->height; return mEvent->AsPointerEvent()->mHeight;
} }
float float
@ -156,7 +156,7 @@ PointerEvent::TiltY()
bool bool
PointerEvent::IsPrimary() PointerEvent::IsPrimary()
{ {
return mEvent->AsPointerEvent()->isPrimary; return mEvent->AsPointerEvent()->mIsPrimary;
} }
} // namespace dom } // namespace dom

Просмотреть файл

@ -369,7 +369,7 @@ HTMLButtonElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
mType == NS_FORM_BUTTON_RESET)) { mType == NS_FORM_BUTTON_RESET)) {
InternalFormEvent event(true, InternalFormEvent event(true,
(mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit); (mType == NS_FORM_BUTTON_RESET) ? eFormReset : eFormSubmit);
event.originator = this; event.mOriginator = this;
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell = nsCOMPtr<nsIPresShell> presShell =

Просмотреть файл

@ -687,7 +687,7 @@ HTMLFormElement::BuildSubmission(HTMLFormSubmission** aFormSubmission,
if (aEvent) { if (aEvent) {
InternalFormEvent* formEvent = aEvent->AsFormEvent(); InternalFormEvent* formEvent = aEvent->AsFormEvent();
if (formEvent) { if (formEvent) {
nsIContent* originator = formEvent->originator; nsIContent* originator = formEvent->mOriginator;
if (originator) { if (originator) {
if (!originator->IsHTMLElement()) { if (!originator->IsHTMLElement()) {
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;

Просмотреть файл

@ -4556,7 +4556,7 @@ HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
if (mForm) { if (mForm) {
InternalFormEvent event(true, InternalFormEvent event(true,
(mType == NS_FORM_INPUT_RESET) ? eFormReset : eFormSubmit); (mType == NS_FORM_INPUT_RESET) ? eFormReset : eFormSubmit);
event.originator = this; event.mOriginator = this;
nsEventStatus status = nsEventStatus_eIgnore; nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell = nsCOMPtr<nsIPresShell> presShell =

Просмотреть файл

@ -114,13 +114,10 @@ ProcessHandle GetCurrentProcessHandle();
bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle); bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
// Converts a PID to a process handle. On Windows the handle is opened // Converts a PID to a process handle. On Windows the handle is opened
// with more access rights and must only be used by trusted code. Parameter // with more access rights and must only be used by trusted code.
// error can be used to get the error code in opening the process handle.
// You have to close returned handle using CloseProcessHandle. Returns true // You have to close returned handle using CloseProcessHandle. Returns true
// on success. // on success.
bool OpenPrivilegedProcessHandle(ProcessId pid, bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle);
ProcessHandle* handle,
int64_t* error = nullptr);
// Closes the process handle opened by OpenProcessHandle. // Closes the process handle opened by OpenProcessHandle.
void CloseProcessHandle(ProcessHandle process); void CloseProcessHandle(ProcessHandle process);

Просмотреть файл

@ -49,14 +49,9 @@ bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
return true; return true;
} }
bool OpenPrivilegedProcessHandle(ProcessId pid, bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
ProcessHandle* handle,
int64_t* error) {
// On POSIX permissions are checked for each operation on process, // On POSIX permissions are checked for each operation on process,
// not when opening a "handle". // not when opening a "handle".
if (error) {
*error = 0;
}
return OpenProcessHandle(pid, handle); return OpenProcessHandle(pid, handle);
} }

Просмотреть файл

@ -86,9 +86,7 @@ bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
return true; return true;
} }
bool OpenPrivilegedProcessHandle(ProcessId pid, bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
ProcessHandle* handle,
int64_t* error) {
ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE | ProcessHandle result = OpenProcess(PROCESS_DUP_HANDLE |
PROCESS_TERMINATE | PROCESS_TERMINATE |
PROCESS_QUERY_INFORMATION | PROCESS_QUERY_INFORMATION |
@ -97,9 +95,6 @@ bool OpenPrivilegedProcessHandle(ProcessId pid,
FALSE, pid); FALSE, pid);
if (result == NULL) { if (result == NULL) {
if (error) {
*error = GetLastError();
}
return false; return false;
} }

Просмотреть файл

@ -1151,43 +1151,47 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
mChildTask = child_task; mChildTask = child_task;
#endif #endif
OpenPrivilegedHandle(base::GetProcId(process)); if (!OpenPrivilegedHandle(base::GetProcId(process))
{ #ifdef XP_WIN
MonitorAutoLock lock(mMonitor); // If we failed in opening the process handle, try harder by duplicating
mProcessState = PROCESS_CREATED; // one.
lock.Notify(); && !::DuplicateHandle(::GetCurrentProcess(), process,
::GetCurrentProcess(), &mChildProcessHandle,
PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ |
SYNCHRONIZE,
FALSE, 0)
#endif
) {
NS_RUNTIMEABORT("cannot open handle to child process");
} }
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CREATED;
lock.Notify();
return true; return true;
} }
void bool
GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid)
{ {
if (mChildProcessHandle) { if (mChildProcessHandle) {
MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle)); MOZ_ASSERT(aPid == base::GetProcId(mChildProcessHandle));
return; return true;
}
int64_t error = 0;
if (!base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle, &error)) {
#ifdef MOZ_CRASHREPORTER
CrashReporter::
AnnotateCrashReport(NS_LITERAL_CSTRING("LastError"),
nsPrintfCString ("%lld", error));
#endif
NS_RUNTIMEABORT("can't open handle to child process");
} }
return base::OpenPrivilegedProcessHandle(aPid, &mChildProcessHandle);
} }
void void
GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid) GeckoChildProcessHost::OnChannelConnected(int32_t peer_pid)
{ {
OpenPrivilegedHandle(peer_pid); if (!OpenPrivilegedHandle(peer_pid)) {
{ NS_RUNTIMEABORT("can't open handle to child process");
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CONNECTED;
lock.Notify();
} }
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CONNECTED;
lock.Notify();
} }
void void
@ -1254,7 +1258,9 @@ bool
GeckoExistingProcessHost::PerformAsyncLaunch(StringVector aExtraOpts, GeckoExistingProcessHost::PerformAsyncLaunch(StringVector aExtraOpts,
base::ProcessArchitecture aArch) base::ProcessArchitecture aArch)
{ {
OpenPrivilegedHandle(base::GetProcId(mExistingProcessHandle)); if (!OpenPrivilegedHandle(base::GetProcId(mExistingProcessHandle))) {
NS_RUNTIMEABORT("can't open handle to child process");
}
MonitorAutoLock lock(mMonitor); MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CREATED; mProcessState = PROCESS_CREATED;

Просмотреть файл

@ -173,7 +173,7 @@ protected:
task_t mChildTask; task_t mChildTask;
#endif #endif
void OpenPrivilegedHandle(base::ProcessId aPid); bool OpenPrivilegedHandle(base::ProcessId aPid);
private: private:
DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost); DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost);

Просмотреть файл

@ -6839,14 +6839,16 @@ PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
// In this case we have to know information about available mouse pointers // In this case we have to know information about available mouse pointers
if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
gActivePointersIds->Put(mouseEvent->pointerId, gActivePointersIds->Put(mouseEvent->pointerId,
new PointerInfo(false, mouseEvent->inputSource, true)); new PointerInfo(false, mouseEvent->inputSource,
true));
} }
break; break;
case ePointerDown: case ePointerDown:
// In this case we switch pointer to active state // In this case we switch pointer to active state
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
gActivePointersIds->Put(pointerEvent->pointerId, gActivePointersIds->Put(pointerEvent->pointerId,
new PointerInfo(true, pointerEvent->inputSource, pointerEvent->isPrimary)); new PointerInfo(true, pointerEvent->inputSource,
pointerEvent->mIsPrimary));
} }
break; break;
case ePointerUp: case ePointerUp:
@ -6854,14 +6856,17 @@ PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) {
if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
gActivePointersIds->Put(pointerEvent->pointerId, gActivePointersIds->Put(pointerEvent->pointerId,
new PointerInfo(false, pointerEvent->inputSource, pointerEvent->isPrimary)); new PointerInfo(false,
pointerEvent->inputSource,
pointerEvent->mIsPrimary));
} else { } else {
gActivePointersIds->Remove(pointerEvent->pointerId); gActivePointersIds->Remove(pointerEvent->pointerId);
} }
} }
break; break;
case eMouseExitFromWidget: case eMouseExitFromWidget:
// In this case we have to remove information about disappeared mouse pointers // In this case we have to remove information about disappeared mouse
// pointers
if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
gActivePointersIds->Remove(mouseEvent->pointerId); gActivePointersIds->Remove(mouseEvent->pointerId);
} }
@ -7205,12 +7210,12 @@ DispatchPointerFromMouseOrTouch(PresShell* aShell,
WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage, WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
touchEvent->mWidget); touchEvent->mWidget);
event.isPrimary = i == 0; event.mIsPrimary = i == 0;
event.pointerId = touch->Identifier(); event.pointerId = touch->Identifier();
event.mRefPoint = touch->mRefPoint; event.mRefPoint = touch->mRefPoint;
event.mModifiers = touchEvent->mModifiers; event.mModifiers = touchEvent->mModifiers;
event.width = touch->RadiusX(); event.mWidth = touch->RadiusX();
event.height = touch->RadiusY(); event.mHeight = touch->RadiusY();
event.tiltX = touch->tiltX; event.tiltX = touch->tiltX;
event.tiltY = touch->tiltY; event.tiltY = touch->tiltY;
event.mTime = touchEvent->mTime; event.mTime = touchEvent->mTime;

Просмотреть файл

@ -563,6 +563,9 @@ MediaPipeline::AttachTransport_s()
return res; return res;
} }
} }
transport_->Attach(this);
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -166,6 +166,7 @@ class MediaPipeline : public sigslot::has_slots<> {
: pipeline_(pipeline), : pipeline_(pipeline),
sts_thread_(pipeline->sts_thread_) {} sts_thread_(pipeline->sts_thread_) {}
void Attach(MediaPipeline *pipeline) { pipeline_ = pipeline; }
void Detach() { pipeline_ = nullptr; } void Detach() { pipeline_ = nullptr; }
MediaPipeline *pipeline() const { return pipeline_; } MediaPipeline *pipeline() const { return pipeline_; }

Просмотреть файл

@ -53,6 +53,7 @@ firefox-ui-functional-local:
treeherder-symbol: tc-Fxfn-l(en-US) treeherder-symbol: tc-Fxfn-l(en-US)
max-run-time: 5400 max-run-time: 5400
tier: 1 tier: 1
docker-image: {"in-tree": "desktop1604-test"}
mozharness: mozharness:
script: mozharness/scripts/firefox_ui_tests/functional.py script: mozharness/scripts/firefox_ui_tests/functional.py
config: config:
@ -67,6 +68,7 @@ firefox-ui-functional-remote:
treeherder-symbol: tc-Fxfn-r(en-US) treeherder-symbol: tc-Fxfn-r(en-US)
max-run-time: 5400 max-run-time: 5400
tier: 2 tier: 2
docker-image: {"in-tree": "desktop1604-test"}
mozharness: mozharness:
script: mozharness/scripts/firefox_ui_tests/functional.py script: mozharness/scripts/firefox_ui_tests/functional.py
config: config:

Просмотреть файл

@ -2,7 +2,7 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this # 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/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
from errors import MarionetteException, TimeoutException from errors import MarionetteException
from functools import wraps from functools import wraps
import socket import socket
import sys import sys
@ -40,13 +40,16 @@ def do_process_check(func, always=False):
try: try:
return func(*args, **kwargs) return func(*args, **kwargs)
except (MarionetteException, socket.error, IOError) as e: except (MarionetteException, IOError) as e:
exc, val, tb = sys.exc_info() exc, val, tb = sys.exc_info()
# In case of socket failures force a shutdown of the application
if type(e) in (socket.error, socket.timeout):
m.force_shutdown()
if not isinstance(e, MarionetteException) or type(e) is MarionetteException: if not isinstance(e, MarionetteException) or type(e) is MarionetteException:
if not always: if not always:
check_for_crash() check_for_crash()
if not isinstance(e, MarionetteException) or type(e) is TimeoutException:
m.force_shutdown()
raise exc, val, tb raise exc, val, tb
finally: finally:
if always: if always:

Просмотреть файл

@ -49,7 +49,10 @@ class MarionetteException(Exception):
st = "".join(["\t%s\n" % x for x in self.stacktrace.splitlines()]) st = "".join(["\t%s\n" % x for x in self.stacktrace.splitlines()])
msg += "\nstacktrace:\n%s" % st msg += "\nstacktrace:\n%s" % st
return "".join(traceback.format_exception(self.__class__, msg, tb)).strip() if tb:
msg += ': ' + "".join(traceback.format_tb(tb))
return msg
class ElementNotSelectableException(MarionetteException): class ElementNotSelectableException(MarionetteException):

Просмотреть файл

@ -173,7 +173,7 @@ class GeckoInstance(object):
def restart(self, prefs=None, clean=True): def restart(self, prefs=None, clean=True):
self.close(restart=True) self.close(restart=True)
if clean: if clean and self.profile:
self.profile.cleanup() self.profile.cleanup()
self.profile = None self.profile = None
@ -221,11 +221,9 @@ class FennecInstance(GeckoInstance):
self.runner.device.connect() self.runner.device.connect()
self.runner.start() self.runner.start()
except Exception as e: except Exception as e:
message = 'Error possibly due to runner or device args.' exc, val, tb = sys.exc_info()
e.args += (message,) message = 'Error possibly due to runner or device args: {}'
if hasattr(e, 'strerror') and e.strerror: raise exc, message.format(e.message), tb
e.strerror = ', '.join([e.strerror, message])
raise e
# gecko_log comes from logcat when running with device/emulator # gecko_log comes from logcat when running with device/emulator
logcat_args = { logcat_args = {
'filterspec': 'Gecko', 'filterspec': 'Gecko',

Просмотреть файл

@ -543,6 +543,7 @@ class Marionette(object):
TIMEOUT_PAGE = 'page load' TIMEOUT_PAGE = 'page load'
DEFAULT_SOCKET_TIMEOUT = 360 DEFAULT_SOCKET_TIMEOUT = 360
DEFAULT_STARTUP_TIMEOUT = 120 DEFAULT_STARTUP_TIMEOUT = 120
DEFAULT_SHUTDOWN_TIMEOUT = 65 # Firefox will kill hanging threads after 60s
def __init__(self, host='localhost', port=2828, app=None, bin=None, def __init__(self, host='localhost', port=2828, app=None, bin=None,
baseurl=None, timeout=None, socket_timeout=DEFAULT_SOCKET_TIMEOUT, baseurl=None, timeout=None, socket_timeout=DEFAULT_SOCKET_TIMEOUT,
@ -616,7 +617,7 @@ class Marionette(object):
if self.session: if self.session:
try: try:
self.delete_session() self.delete_session()
except (errors.MarionetteException, socket.error, IOError): except (errors.MarionetteException, IOError):
# These exceptions get thrown if the Marionette server # These exceptions get thrown if the Marionette server
# hit an exception/died or the connection died. We can # hit an exception/died or the connection died. We can
# do no further server-side cleanup in this case. # do no further server-side cleanup in this case.
@ -648,7 +649,7 @@ class Marionette(object):
@do_process_check @do_process_check
def raise_for_port(self, port_obtained): def raise_for_port(self, port_obtained):
if not port_obtained: if not port_obtained:
raise IOError("Timed out waiting for port!") raise socket.timeout("Timed out waiting for port {}!".format(self.port))
@do_process_check @do_process_check
def _send_message(self, name, params=None, key=None): def _send_message(self, name, params=None, key=None):
@ -684,7 +685,8 @@ class Marionette(object):
self.session = None self.session = None
self.window = None self.window = None
self.client.close() self.client.close()
raise errors.TimeoutException("Connection timed out")
raise
res, err = msg.result, msg.error res, err = msg.result, msg.error
if err: if err:
@ -754,17 +756,19 @@ class Marionette(object):
if self.instance: if self.instance:
exc, val, tb = sys.exc_info() exc, val, tb = sys.exc_info()
returncode = self.instance.runner.returncode # Give the application some time to shutdown
returncode = self.instance.runner.wait(timeout=self.DEFAULT_STARTUP_TIMEOUT)
if returncode is None: if returncode is None:
self.instance.runner.stop() self.cleanup()
message = 'Process killed because the connection was lost' message = ('Process killed because the connection to Marionette server is lost.'
' Check gecko.log for errors')
else: else:
message = 'Process died with returncode "{returncode}"' message = 'Process has been closed (Exit code: {returncode})'
if exc: if exc:
message += ' (Reason: {reason})' message += ' (Reason: {reason})'
raise exc, message.format(returncode=returncode, reason=val), tb raise IOError, message.format(returncode=returncode, reason=val), tb
@staticmethod @staticmethod
def convert_keys(*string): def convert_keys(*string):
@ -993,8 +997,8 @@ class Marionette(object):
: param prefs: A dictionary whose keys are preference names. : param prefs: A dictionary whose keys are preference names.
""" """
if not self.instance: if not self.instance:
raise errors.MarionetteException("enforce_gecko_prefs can only be called " raise errors.MarionetteException("enforce_gecko_prefs() can only be called "
"on gecko instances launched by Marionette") "on Gecko instances launched by Marionette")
pref_exists = True pref_exists = True
self.set_context(self.CONTEXT_CHROME) self.set_context(self.CONTEXT_CHROME)
for pref, value in prefs.iteritems(): for pref, value in prefs.iteritems():
@ -1027,13 +1031,14 @@ class Marionette(object):
self.start_session() self.start_session()
self.reset_timeouts() self.reset_timeouts()
@do_process_check
def quit_in_app(self): def quit_in_app(self):
""" """
This will terminate the currently running instance. This will terminate the currently running instance.
""" """
if not self.instance: if not self.instance:
raise errors.MarionetteException("quit_in_app can only be called " raise errors.MarionetteException("quit_in_app() can only be called "
"on gecko instances launched by Marionette") "on Gecko instances launched by Marionette")
# Values here correspond to constants in nsIAppStartup. # Values here correspond to constants in nsIAppStartup.
# See http://mzl.la/1X0JZsC # See http://mzl.la/1X0JZsC
restart_flags = [ restart_flags = [
@ -1042,7 +1047,14 @@ class Marionette(object):
] ]
self._send_message("quitApplication", {"flags": restart_flags}) self._send_message("quitApplication", {"flags": restart_flags})
self.client.close() self.client.close()
self.raise_for_port(self.wait_for_port())
try:
self.raise_for_port(self.wait_for_port())
except socket.timeout:
if self.instance.runner.returncode is not None:
exc, val, tb = sys.exc_info()
self.cleanup()
raise exc, 'Requested restart of the application was aborted', tb
def restart(self, clean=False, in_app=False): def restart(self, clean=False, in_app=False):
""" """
@ -1057,11 +1069,11 @@ class Marionette(object):
by killing the process. by killing the process.
""" """
if not self.instance: if not self.instance:
raise errors.MarionetteException("restart can only be called " raise errors.MarionetteException("restart() can only be called "
"on gecko instances launched by Marionette") "on Gecko instances launched by Marionette")
if in_app: if in_app:
if clean: if clean:
raise ValueError raise ValueError("An in_app restart cannot be triggered with the clean flag set")
self.quit_in_app() self.quit_in_app()
else: else:
self.delete_session() self.delete_session()
@ -1463,8 +1475,13 @@ class Marionette(object):
:param ms: A number value specifying the timeout length in :param ms: A number value specifying the timeout length in
milliseconds (ms) milliseconds (ms)
""" """
if timeout_type not in [self.TIMEOUT_SEARCH, self.TIMEOUT_SCRIPT, self.TIMEOUT_PAGE]: timeout_types = (self.TIMEOUT_PAGE,
raise ValueError("Unknown timeout type: %s" % timeout_type) self.TIMEOUT_SCRIPT,
self.TIMEOUT_SEARCH,
)
if timeout_type not in timeout_types:
raise ValueError("Unknown timeout type: {0} (should be one "
"of {1})".format(timeout_type, timeout_types))
body = {"type": timeout_type, "ms": ms} body = {"type": timeout_type, "ms": ms}
self._send_message("timeouts", body) self._send_message("timeouts", body)

Просмотреть файл

@ -3,7 +3,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
import datetime import datetime
import errno
import json import json
import socket import socket
import time import time
@ -119,7 +118,6 @@ class TcpTransport(object):
Supported protocol levels are 1 and above. Supported protocol levels are 1 and above.
""" """
max_packet_length = 4096 max_packet_length = 4096
connection_lost_msg = "Connection to Marionette server is lost. Check gecko.log for errors."
def __init__(self, addr, port, socket_timeout=360.0): def __init__(self, addr, port, socket_timeout=360.0):
"""If `socket_timeout` is `0` or `0.0`, non-blocking socket mode """If `socket_timeout` is `0` or `0.0`, non-blocking socket mode
@ -176,7 +174,7 @@ class TcpTransport(object):
pass pass
else: else:
if not chunk: if not chunk:
raise IOError(self.connection_lost_msg) raise socket.error("No data received over socket")
sep = data.find(":") sep = data.find(":")
if sep > -1: if sep > -1:
@ -203,7 +201,7 @@ class TcpTransport(object):
bytes_to_recv = int(length) - len(remaining) bytes_to_recv = int(length) - len(remaining)
raise socket.timeout("connection timed out after %ds" % self.socket_timeout) raise socket.timeout("Connection timed out after %ds" % self.socket_timeout)
def connect(self): def connect(self):
"""Connect to the server and process the hello message we expect """Connect to the server and process the hello message we expect
@ -246,19 +244,12 @@ class TcpTransport(object):
totalsent = 0 totalsent = 0
while totalsent < len(payload): while totalsent < len(payload):
try: sent = self.sock.send(payload[totalsent:])
sent = self.sock.send(payload[totalsent:]) if sent == 0:
if sent == 0: raise IOError("Socket error after sending %d of %d bytes" %
raise IOError("socket error after sending %d of %d bytes" % (totalsent, len(payload)))
(totalsent, len(payload))) else:
else: totalsent += sent
totalsent += sent
except IOError as e:
if e.errno == errno.EPIPE:
raise IOError("%s: %s" % (str(e), self.connection_lost_msg))
else:
raise e
def respond(self, obj): def respond(self, obj):
"""Send a response to a command. This can be an arbitrary JSON """Send a response to a command. This can be an arbitrary JSON

Просмотреть файл

@ -121,9 +121,9 @@ class Wait(object):
while not until(self.clock, self.end): while not until(self.clock, self.end):
try: try:
rv = condition(self.marionette) rv = condition(self.marionette)
except (KeyboardInterrupt, SystemExit) as e: except (KeyboardInterrupt, SystemExit):
raise e raise
except self.exceptions as e: except self.exceptions:
last_exc = sys.exc_info() last_exc = sys.exc_info()
if not rv: if not rv:

Просмотреть файл

@ -128,9 +128,9 @@ this.GeckoDriver = function(appName, stopSignal) {
this.sessionCapabilities = { this.sessionCapabilities = {
// mandated capabilities // mandated capabilities
"browserName": Services.appinfo.name, "browserName": Services.appinfo.name.toLowerCase(),
"browserVersion": Services.appinfo.version, "browserVersion": Services.appinfo.version,
"platformName": Services.sysinfo.getProperty("name"), "platformName": Services.sysinfo.getProperty("name").toLowerCase(),
"platformVersion": Services.sysinfo.getProperty("version"), "platformVersion": Services.sysinfo.getProperty("version"),
"specificationLevel": 0, "specificationLevel": 0,

Просмотреть файл

@ -616,9 +616,9 @@ class BaseMarionetteTestRunner(object):
with open(path) as f: with open(path) as f:
data.append(json.loads(f.read())) data.append(json.loads(f.read()))
except ValueError as e: except ValueError as e:
raise Exception("JSON file (%s) is not properly " exc, val, tb = sys.exc_info()
"formatted: %s" % (os.path.abspath(path), msg = "JSON file ({0}) is not properly formatted: {1}"
e.message)) raise exc, msg.format(os.path.abspath(path), e.message), tb
return data return data
@property @property
@ -669,11 +669,7 @@ class BaseMarionetteTestRunner(object):
""" """
self._bin = path self._bin = path
self.tests = [] self.tests = []
if hasattr(self, 'marionette') and self.marionette: self.cleanup()
self.marionette.cleanup()
if self.marionette.instance:
self.marionette.instance = None
self.marionette = None
def reset_test_stats(self): def reset_test_stats(self):
self.passed = 0 self.passed = 0
@ -737,8 +733,10 @@ class BaseMarionetteTestRunner(object):
connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM) connection = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connection.connect((host,int(port))) connection.connect((host,int(port)))
connection.close() connection.close()
except Exception, e: except Exception as e:
raise Exception("Connection attempt to %s:%s failed with error: %s" %(host,port,e)) exc, val, tb = sys.exc_info()
msg = "Connection attempt to {0}:{1} failed with error: {2}"
raise exc, msg.format(host, port, e), tb
if self.workspace: if self.workspace:
kwargs['workspace'] = self.workspace_path kwargs['workspace'] = self.workspace_path
return kwargs return kwargs
@ -896,16 +894,17 @@ setReq.onerror = function() {
# we want to display current test results. # we want to display current test results.
# so we keep the exception to raise it later. # so we keep the exception to raise it later.
interrupted = sys.exc_info() interrupted = sys.exc_info()
except:
# For any other exception we return immediately and have to
# cleanup running processes
self.cleanup()
raise
try: try:
self._print_summary(tests) self._print_summary(tests)
self.record_crash() self.record_crash()
self.elapsedtime = time.time() - start_time self.elapsedtime = time.time() - start_time
if self.marionette.instance:
self.marionette.instance.close()
self.marionette.instance = None
self.marionette.cleanup()
for run_tests in self.mixin_run_tests: for run_tests in self.mixin_run_tests:
run_tests(tests) run_tests(tests)
if self.shuffle: if self.shuffle:
@ -918,6 +917,8 @@ setReq.onerror = function() {
if not interrupted: if not interrupted:
raise raise
finally: finally:
self.cleanup()
# reraise previous interruption now # reraise previous interruption now
if interrupted: if interrupted:
raise interrupted[0], interrupted[1], interrupted[2] raise interrupted[0], interrupted[1], interrupted[2]
@ -1090,10 +1091,16 @@ setReq.onerror = function() {
self.run_test_set(self.tests) self.run_test_set(self.tests)
def cleanup(self): def cleanup(self):
if self.httpd: if hasattr(self, 'httpd') and self.httpd:
self.httpd.stop() self.httpd.stop()
self.httpd = None
if hasattr(self, 'marionette') and self.marionette:
if self.marionette.instance:
self.marionette.instance.close()
self.marionette.instance = None
if self.marionette:
self.marionette.cleanup() self.marionette.cleanup()
self.marionette = None
__del__ = cleanup __del__ = cleanup

Просмотреть файл

@ -11,7 +11,7 @@ class FixtureServer(object):
def __init__(self, root, host="127.0.0.1", port=0): def __init__(self, root, host="127.0.0.1", port=0):
if not os.path.isdir(root): if not os.path.isdir(root):
raise Exception("Server root is not a valid path: %s" % root) raise IOError("Server root is not a valid path: %s" % root)
self.root = root self.root = root
self.host = host self.host = host
self.port = port self.port = port
@ -44,7 +44,7 @@ class FixtureServer(object):
def get_url(self, path="/"): def get_url(self, path="/"):
if not self.alive: if not self.alive:
raise "Server not started" raise Exception("Server not started")
return self._server.get_url(path) return self._server.get_url(path)
@property @property

Просмотреть файл

@ -31,8 +31,8 @@ class Server(object):
break break
if not os.path.isfile(path) and exec_not_on_path: if not os.path.isfile(path) and exec_not_on_path:
raise Exception("Browsermob-Proxy binary couldn't be found in path" raise IOError("Browsermob-Proxy binary couldn't be found in path"
" provided: %s" % path) " provided: %s" % path)
self.path = path self.path = path
self.port = options.get('port', 8080) self.port = options.get('port', 8080)

Просмотреть файл

@ -12,7 +12,7 @@ class TestAboutPages(MarionetteTestCase):
def setUp(self): def setUp(self):
MarionetteTestCase.setUp(self) MarionetteTestCase.setUp(self)
if self.marionette.session_capabilities['platformName'] == 'Darwin': if self.marionette.session_capabilities['platformName'] == 'darwin':
self.mod_key = Keys.META self.mod_key = Keys.META
else: else:
self.mod_key = Keys.CONTROL self.mod_key = Keys.CONTROL

Просмотреть файл

@ -15,7 +15,7 @@ class TestCapabilities(MarionetteTestCase):
self.appinfo = self.marionette.execute_script( self.appinfo = self.marionette.execute_script(
"return Services.appinfo") "return Services.appinfo")
self.os_name = self.marionette.execute_script( self.os_name = self.marionette.execute_script(
"return Services.sysinfo.getProperty('name')") "return Services.sysinfo.getProperty('name')").lower()
self.os_version = self.marionette.execute_script( self.os_version = self.marionette.execute_script(
"return Services.sysinfo.getProperty('version')") "return Services.sysinfo.getProperty('version')")
@ -30,7 +30,7 @@ class TestCapabilities(MarionetteTestCase):
self.assertIn("platformVersion", self.caps) self.assertIn("platformVersion", self.caps)
self.assertIn("specificationLevel", self.caps) self.assertIn("specificationLevel", self.caps)
self.assertEqual(self.caps["browserName"], self.appinfo["name"]) self.assertEqual(self.caps["browserName"], self.appinfo["name"].lower())
self.assertEqual(self.caps["browserVersion"], self.appinfo["version"]) self.assertEqual(self.caps["browserVersion"], self.appinfo["version"])
self.assertEqual(self.caps["platformName"], self.os_name) self.assertEqual(self.caps["platformName"], self.os_name)
self.assertEqual(self.caps["platformVersion"], self.os_version) self.assertEqual(self.caps["platformVersion"], self.os_version)
@ -78,12 +78,12 @@ class TestCapabilities(MarionetteTestCase):
capabilities = {"desiredCapabilities": {"browserName": "ChocolateCake"}} capabilities = {"desiredCapabilities": {"browserName": "ChocolateCake"}}
self.marionette.start_session(capabilities) self.marionette.start_session(capabilities)
caps = self.marionette.session_capabilities caps = self.marionette.session_capabilities
self.assertEqual(caps["browserName"], self.appinfo["name"], self.assertEqual(caps["browserName"], self.appinfo["name"].lower(),
"This should have appname not ChocolateCake") "This should have appname not ChocolateCake.")
def test_we_can_pass_in_required_capabilities_on_session_start(self): def test_we_can_pass_in_required_capabilities_on_session_start(self):
self.marionette.delete_session() self.marionette.delete_session()
capabilities = {"requiredCapabilities": {"browserName": self.appinfo["name"]}} capabilities = {"requiredCapabilities": {"browserName": self.appinfo["name"].lower()}}
self.marionette.start_session(capabilities) self.marionette.start_session(capabilities)
caps = self.marionette.session_capabilities caps = self.marionette.session_capabilities
self.assertIn("browserName", caps) self.assertIn("browserName", caps)

Просмотреть файл

@ -38,7 +38,6 @@ class TestErrors(marionette_test.MarionetteTestCase):
self.assertIn(message, r) self.assertIn(message, r)
self.assertIn(", caused by %r" % cause[0], r) self.assertIn(", caused by %r" % cause[0], r)
self.assertIn("\nstacktrace:\n\tfirst\n\tsecond", r) self.assertIn("\nstacktrace:\n\tfirst\n\tsecond", r)
self.assertIn("MarionetteException:", r)
def test_cause_string(self): def test_cause_string(self):
exc = errors.MarionetteException(cause="foo") exc = errors.MarionetteException(cause="foo")

Просмотреть файл

@ -11,7 +11,7 @@ from marionette_driver.by import By
class TestKeyActions(MarionetteTestCase): class TestKeyActions(MarionetteTestCase):
def setUp(self): def setUp(self):
MarionetteTestCase.setUp(self) MarionetteTestCase.setUp(self)
if self.marionette.session_capabilities["platformName"] == "Darwin": if self.marionette.session_capabilities["platformName"] == "darwin":
self.mod_key = Keys.META self.mod_key = Keys.META
else: else:
self.mod_key = Keys.CONTROL self.mod_key = Keys.CONTROL

Просмотреть файл

@ -11,7 +11,7 @@ from marionette_driver.by import By
class TestMouseAction(MarionetteTestCase): class TestMouseAction(MarionetteTestCase):
def setUp(self): def setUp(self):
MarionetteTestCase.setUp(self) MarionetteTestCase.setUp(self)
if self.marionette.session_capabilities["platformName"] == "Darwin": if self.marionette.session_capabilities["platformName"] == "darwin":
self.mod_key = Keys.META self.mod_key = Keys.META
else: else:
self.mod_key = Keys.CONTROL self.mod_key = Keys.CONTROL

Просмотреть файл

@ -11,6 +11,12 @@ from marionette_driver.by import By
class TestTimeouts(MarionetteTestCase): class TestTimeouts(MarionetteTestCase):
def tearDown(self):
self.marionette.reset_timeouts()
MarionetteTestCase.tearDown(self)
def test_pagetimeout_notdefinetimeout_pass(self): def test_pagetimeout_notdefinetimeout_pass(self):
test_html = self.marionette.absolute_url("test.html") test_html = self.marionette.absolute_url("test.html")
self.marionette.navigate(test_html) self.marionette.navigate(test_html)
@ -62,3 +68,8 @@ class TestTimeouts(MarionetteTestCase):
var callback = arguments[arguments.length - 1]; var callback = arguments[arguments.length - 1];
setTimeout(function() { callback(true); }, 500); setTimeout(function() { callback(true); }, 500);
""")) """))
def test_invalid_timeout_type(self):
self.assertRaises(ValueError, self.marionette.timeouts, "foobar", 1000)
self.assertRaises(ValueError, self.marionette.timeouts, 42, 1000)
self.assertRaises(MarionetteException, self.marionette.timeouts, "page load", "foobar")

Просмотреть файл

@ -58,7 +58,7 @@ class TestTyping(MarionetteTestCase):
def testCutAndPasteShortcuts(self): def testCutAndPasteShortcuts(self):
# test that modifier keys work via copy/paste shortcuts # test that modifier keys work via copy/paste shortcuts
if self.marionette.session_capabilities["platformName"] == "Darwin": if self.marionette.session_capabilities["platformName"] == "darwin":
mod_key = Keys.META mod_key = Keys.META
else: else:
mod_key = Keys.CONTROL mod_key = Keys.CONTROL

Просмотреть файл

@ -12,7 +12,7 @@ class TestWindowHandles(MarionetteTestCase):
def test_new_tab_window_handles(self): def test_new_tab_window_handles(self):
keys = [] keys = []
if self.marionette.session_capabilities['platformName'] == 'Darwin': if self.marionette.session_capabilities['platformName'] == 'darwin':
keys.append(Keys.META) keys.append(Keys.META)
else: else:
keys.append(Keys.CONTROL) keys.append(Keys.CONTROL)

Просмотреть файл

@ -126,7 +126,7 @@ function registerSelf() {
if (register[0]) { if (register[0]) {
let {id, remotenessChange} = register[0][0]; let {id, remotenessChange} = register[0][0];
capabilities = register[0][2]; capabilities = register[0][2];
isB2G = capabilities.platformName == "B2G"; isB2G = capabilities.platformName == "b2g";
listenerId = id; listenerId = id;
if (typeof id != "undefined") { if (typeof id != "undefined") {
// check if we're the main process // check if we're the main process

Просмотреть файл

@ -66,7 +66,7 @@ class Puppeteer(object):
:returns: Platform name :returns: Platform name
""" """
return self.marionette.session_capabilities['platformName'].lower() return self.marionette.session_capabilities['platformName']
@use_class_as_property('api.prefs.Preferences') @use_class_as_property('api.prefs.Preferences')
def prefs(self): def prefs(self):

Просмотреть файл

@ -13,7 +13,7 @@ class Keys(marionette_driver.keys.Keys):
self.marionette_getter = marionette_getter self.marionette_getter = marionette_getter
caps = self.marionette_getter().session_capabilities caps = self.marionette_getter().session_capabilities
self.isDarwin = caps['platformName'] == 'DARWIN' self.isDarwin = caps['platformName'] == 'darwin'
@property @property
def ACCEL(self): def ACCEL(self):

Просмотреть файл

@ -398,7 +398,7 @@ class BaseWindow(BaseLib):
Defaults to `False`. Defaults to `False`.
""" """
platform = self.marionette.session_capabilities['platformName'].lower() platform = self.marionette.session_capabilities['platformName']
keymap = { keymap = {
'accel': Keys.META if platform == 'darwin' else Keys.CONTROL, 'accel': Keys.META if platform == 'darwin' else Keys.CONTROL,

Просмотреть файл

@ -283,8 +283,14 @@ FinderHighlighter.prototype = {
* Optional, defaults to the finder window. * Optional, defaults to the finder window.
* @param {nsIDOMRange} skipRange A range that should not be removed from the * @param {nsIDOMRange} skipRange A range that should not be removed from the
* find selection. * find selection.
* @param {nsIDOMEvent} event When called from an event handler, this will
* be the triggering event.
*/ */
hide(window = null, skipRange = null) { hide(window = null, skipRange = null, event = null) {
// Do not hide on anything but a left-click.
if (event && event.type == "click" && event.button !== 0)
return;
window = window || this.finder._getWindow(); window = window || this.finder._getWindow();
let doc = window.document; let doc = window.document;
@ -836,12 +842,11 @@ FinderHighlighter.prototype = {
this._highlightListeners = [ this._highlightListeners = [
this._scheduleRepaintOfMask.bind(this, window), this._scheduleRepaintOfMask.bind(this, window),
this.hide.bind(this, window) this.hide.bind(this, window, null)
]; ];
window.addEventListener("DOMContentLoaded", this._highlightListeners[0]); window.addEventListener("DOMContentLoaded", this._highlightListeners[0]);
window.addEventListener("mousedown", this._highlightListeners[1]); window.addEventListener("click", this._highlightListeners[1]);
window.addEventListener("resize", this._highlightListeners[1]); window.addEventListener("resize", this._highlightListeners[1]);
window.addEventListener("touchstart", this._highlightListeners[1]);
}, },
/** /**
@ -854,9 +859,8 @@ FinderHighlighter.prototype = {
return; return;
window.removeEventListener("DOMContentLoaded", this._highlightListeners[0]); window.removeEventListener("DOMContentLoaded", this._highlightListeners[0]);
window.removeEventListener("mousedown", this._highlightListeners[1]); window.removeEventListener("click", this._highlightListeners[1]);
window.removeEventListener("resize", this._highlightListeners[1]); window.removeEventListener("resize", this._highlightListeners[1]);
window.removeEventListener("touchstart", this._highlightListeners[1]);
this._highlightListeners = null; this._highlightListeners = null;
}, },

Просмотреть файл

@ -113,7 +113,7 @@ public:
* mozilla::InternalFormEvent * mozilla::InternalFormEvent
* *
* We hold the originating form control for form submit and reset events. * We hold the originating form control for form submit and reset events.
* originator is a weak pointer (does not hold a strong reference). * mOriginator is a weak pointer (does not hold a strong reference).
******************************************************************************/ ******************************************************************************/
class InternalFormEvent : public WidgetEvent class InternalFormEvent : public WidgetEvent
@ -123,7 +123,7 @@ public:
InternalFormEvent(bool aIsTrusted, EventMessage aMessage) InternalFormEvent(bool aIsTrusted, EventMessage aMessage)
: WidgetEvent(aIsTrusted, aMessage, eFormEventClass) : WidgetEvent(aIsTrusted, aMessage, eFormEventClass)
, originator(nullptr) , mOriginator(nullptr)
{ {
} }
@ -137,13 +137,13 @@ public:
return result; return result;
} }
nsIContent *originator; nsIContent* mOriginator;
void AssignFormEventData(const InternalFormEvent& aEvent, bool aCopyTargets) void AssignFormEventData(const InternalFormEvent& aEvent, bool aCopyTargets)
{ {
AssignEventData(aEvent, aCopyTargets); AssignEventData(aEvent, aCopyTargets);
// Don't copy originator due to a weak pointer. // Don't copy mOriginator due to a weak pointer.
} }
}; };

Просмотреть файл

@ -666,9 +666,9 @@ class WidgetPointerEvent : public WidgetMouseEvent
friend class mozilla::dom::PBrowserChild; friend class mozilla::dom::PBrowserChild;
WidgetPointerEvent() WidgetPointerEvent()
: width(0) : mWidth(0)
, height(0) , mHeight(0)
, isPrimary(true) , mIsPrimary(true)
{ {
} }
@ -677,17 +677,17 @@ public:
WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w) WidgetPointerEvent(bool aIsTrusted, EventMessage aMsg, nsIWidget* w)
: WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal) : WidgetMouseEvent(aIsTrusted, aMsg, w, ePointerEventClass, eReal)
, width(0) , mWidth(0)
, height(0) , mHeight(0)
, isPrimary(true) , mIsPrimary(true)
{ {
} }
explicit WidgetPointerEvent(const WidgetMouseEvent& aEvent) explicit WidgetPointerEvent(const WidgetMouseEvent& aEvent)
: WidgetMouseEvent(aEvent) : WidgetMouseEvent(aEvent)
, width(0) , mWidth(0)
, height(0) , mHeight(0)
, isPrimary(true) , mIsPrimary(true)
{ {
mClass = ePointerEventClass; mClass = ePointerEventClass;
} }
@ -704,9 +704,9 @@ public:
return result; return result;
} }
uint32_t width; uint32_t mWidth;
uint32_t height; uint32_t mHeight;
bool isPrimary; bool mIsPrimary;
// XXX Not tested by test_assign_event_data.html // XXX Not tested by test_assign_event_data.html
void AssignPointerEventData(const WidgetPointerEvent& aEvent, void AssignPointerEventData(const WidgetPointerEvent& aEvent,
@ -714,9 +714,9 @@ public:
{ {
AssignMouseEventData(aEvent, aCopyTargets); AssignMouseEventData(aEvent, aCopyTargets);
width = aEvent.width; mWidth = aEvent.mWidth;
height = aEvent.height; mHeight = aEvent.mHeight;
isPrimary = aEvent.isPrimary; mIsPrimary = aEvent.mIsPrimary;
} }
}; };

Просмотреть файл

@ -287,11 +287,11 @@ struct ParamTraits<mozilla::WidgetPointerEvent>
{ {
WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam)); WriteParam(aMsg, static_cast<mozilla::WidgetMouseEvent>(aParam));
WriteParam(aMsg, aParam.pointerId); WriteParam(aMsg, aParam.pointerId);
WriteParam(aMsg, aParam.width); WriteParam(aMsg, aParam.mWidth);
WriteParam(aMsg, aParam.height); WriteParam(aMsg, aParam.mHeight);
WriteParam(aMsg, aParam.tiltX); WriteParam(aMsg, aParam.tiltX);
WriteParam(aMsg, aParam.tiltY); WriteParam(aMsg, aParam.tiltY);
WriteParam(aMsg, aParam.isPrimary); WriteParam(aMsg, aParam.mIsPrimary);
} }
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
@ -299,11 +299,11 @@ struct ParamTraits<mozilla::WidgetPointerEvent>
bool rv = bool rv =
ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEvent*>(aResult)) && ReadParam(aMsg, aIter, static_cast<mozilla::WidgetMouseEvent*>(aResult)) &&
ReadParam(aMsg, aIter, &aResult->pointerId) && ReadParam(aMsg, aIter, &aResult->pointerId) &&
ReadParam(aMsg, aIter, &aResult->width) && ReadParam(aMsg, aIter, &aResult->mWidth) &&
ReadParam(aMsg, aIter, &aResult->height) && ReadParam(aMsg, aIter, &aResult->mHeight) &&
ReadParam(aMsg, aIter, &aResult->tiltX) && ReadParam(aMsg, aIter, &aResult->tiltX) &&
ReadParam(aMsg, aIter, &aResult->tiltY) && ReadParam(aMsg, aIter, &aResult->tiltY) &&
ReadParam(aMsg, aIter, &aResult->isPrimary); ReadParam(aMsg, aIter, &aResult->mIsPrimary);
return rv; return rv;
} }
}; };