Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2017-02-03 13:32:38 +01:00
Родитель b51488fd48 e95ecef88f
Коммит 3860f49d11
83 изменённых файлов: 1100 добавлений и 1981 удалений

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

@ -38,6 +38,7 @@ parser/**
probes/**
python/**
rdf/**
servo/**
startupcache/**
testing/**
tools/update-packaging/**

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

@ -192,14 +192,6 @@ const TELEMETRY_DDSTAT_SOLVED = 4;
let gDecoderDoctorHandler = {
getLabelForNotificationBox(type) {
if (type == "adobe-cdm-not-found" &&
AppConstants.platform == "win") {
return gNavigatorBundle.getString("decoder.noCodecs.message");
}
if (type == "adobe-cdm-not-activated" &&
AppConstants.platform == "win") {
return gNavigatorBundle.getString("decoder.noCodecs.message");
}
if (type == "platform-decoder-not-found") {
if (AppConstants.platform == "win") {
return gNavigatorBundle.getString("decoder.noHWAcceleration.message");

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

@ -46,26 +46,6 @@ function* test_decoder_doctor_notification(type, notificationMessage, options) {
});
}
add_task(function* test_adobe_cdm_not_found() {
// This is only sent on Windows.
if (AppConstants.platform != "win") {
return;
}
let message = gNavigatorBundle.getString("decoder.noCodecs.message");
yield test_decoder_doctor_notification("adobe-cdm-not-found", message);
});
add_task(function* test_adobe_cdm_not_activated() {
// This is only sent on Windows.
if (AppConstants.platform != "win") {
return;
}
let message = gNavigatorBundle.getString("decoder.noCodecs.message");
yield test_decoder_doctor_notification("adobe-cdm-not-activated", message);
});
add_task(function* test_platform_decoder_not_found() {
let message;
let isLinux = AppConstants.platform == "linux";

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

@ -3,6 +3,21 @@ const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm
const URL_BASE = "https://example.com/browser/browser/base/content/test/general";
const ID = "update@tests.mozilla.org";
function promiseInstallAddon(url) {
return AddonManager.getInstallForURL(url, null, "application/x-xpinstall")
.then(install => {
ok(install, "Created install");
return new Promise(resolve => {
install.addListener({
onInstallEnded(_install, addon) {
resolve(addon);
},
});
install.install();
});
});
}
function promiseViewLoaded(tab, viewid) {
let win = tab.linkedBrowser.contentWindow;
if (win.gViewController && !win.gViewController.isLoading &&
@ -44,42 +59,22 @@ function getBadgeStatus() {
return menuButton.getAttribute("badge-status");
}
function promiseUpdateDownloaded(addon) {
function promiseInstallEvent(addon, event) {
return new Promise(resolve => {
let listener = {
onDownloadEnded(install) {
if (install.addon.id == addon.id) {
AddonManager.removeInstallListener(listener);
resolve();
}
},
let listener = {};
listener[event] = (install, ...args) => {
if (install.addon.id == addon.id) {
AddonManager.removeInstallListener(listener);
resolve(...args);
}
};
AddonManager.addInstallListener(listener);
});
}
function promiseUpgrade(addon) {
return new Promise(resolve => {
let listener = {
onInstallEnded(install, newAddon) {
if (newAddon.id == addon.id) {
AddonManager.removeInstallListener(listener);
resolve(newAddon);
}
},
};
AddonManager.addInstallListener(listener);
});
}
add_task(function* () {
yield SpecialPowers.pushPrefEnv({set: [
// Turn on background updates
["extensions.update.enabled", true],
// Point updates to the local mochitest server
["extensions.update.background.url", `${URL_BASE}/browser_webext_update.json`],
// Set some prefs that apply to all the tests in this file
add_task(function setup() {
return SpecialPowers.pushPrefEnv({set: [
// We don't have pre-pinned certificates for the local mochitest server
["extensions.install.requireBuiltInCerts", false],
["extensions.update.requireBuiltInCerts", false],
@ -87,27 +82,27 @@ add_task(function* () {
// XXX remove this when prompts are enabled by default
["extensions.webextPermissionPrompts", true],
]});
});
add_task(function* test_background_update() {
yield SpecialPowers.pushPrefEnv({set: [
// Turn on background updates
["extensions.update.enabled", true],
// Point updates to the local mochitest server
["extensions.update.background.url", `${URL_BASE}/browser_webext_update.json`],
]});
// Install version 1.0 of the test extension
let url1 = `${URL_BASE}/browser_webext_update1.xpi`;
let install = yield AddonManager.getInstallForURL(url1, null, "application/x-xpinstall");
ok(install, "Created install");
let addon = yield new Promise(resolve => {
install.addListener({
onInstallEnded(_install, _addon) {
resolve(_addon);
},
});
install.install();
});
let addon = yield promiseInstallAddon(`${URL_BASE}/browser_webext_update1.xpi`);
ok(addon, "Addon was installed");
is(getBadgeStatus(), "", "Should not start out with an addon alert badge");
// Trigger an update check and wait for the update for this addon
// to be downloaded.
let updatePromise = promiseUpdateDownloaded(addon);
let updatePromise = promiseInstallEvent(addon, "onDownloadEnded");
AddonManagerPrivate.backgroundUpdateCheck();
yield updatePromise;
@ -152,7 +147,7 @@ add_task(function* () {
yield PanelUI.hide();
// Re-check for an update
updatePromise = promiseUpdateDownloaded(addon);
updatePromise = promiseInstallEvent(addon, "onDownloadEnded");
yield AddonManagerPrivate.backgroundUpdateCheck();
yield updatePromise;
@ -179,7 +174,7 @@ add_task(function* () {
is(win.gViewController.currentViewId, VIEW, "about:addons is at extensions list");
// Wait for the permission prompt and accept it this time
updatePromise = promiseUpgrade(addon);
updatePromise = promiseInstallEvent(addon, "onInstallEnded");
panel = yield popupPromise;
panel.button.click();
@ -189,4 +184,119 @@ add_task(function* () {
yield BrowserTestUtils.removeTab(tab);
is(getBadgeStatus(), "", "Addon alert badge should be gone");
addon.uninstall();
yield SpecialPowers.popPrefEnv();
});
// Helper function to test a specific scenario for interactive updates.
// `checkFn` is a callable that triggers a check for updates.
// `autoUpdate` specifies whether the test should be run with
// updates applied automatically or not.
function* interactiveUpdateTest(autoUpdate, checkFn) {
yield SpecialPowers.pushPrefEnv({set: [
["extensions.update.autoUpdateDefault", autoUpdate],
// Point updates to the local mochitest server
["extensions.update.url", `${URL_BASE}/browser_webext_update.json`],
]});
// Trigger an update check, manually applying the update if we're testing
// without auto-update.
function* triggerUpdate(win, addon) {
let manualUpdatePromise;
if (!autoUpdate) {
manualUpdatePromise = new Promise(resolve => {
let listener = {
onNewInstall() {
AddonManager.removeInstallListener(listener);
resolve();
},
};
AddonManager.addInstallListener(listener);
});
}
checkFn(win, addon);
if (manualUpdatePromise) {
yield manualUpdatePromise;
let item = win.document.getElementById("addon-list")
.children.find(_item => _item.value == ID);
EventUtils.synthesizeMouseAtCenter(item._updateBtn, {}, win);
}
}
// Install version 1.0 of the test extension
let addon = yield promiseInstallAddon(`${URL_BASE}/browser_webext_update1.xpi`);
ok(addon, "Addon was installed");
is(addon.version, "1.0", "Version 1 of the addon is installed");
// Open add-ons manager and navigate to extensions list
let loadPromise = new Promise(resolve => {
let listener = (subject, topic) => {
if (subject.location.href == "about:addons") {
Services.obs.removeObserver(listener, topic);
resolve(subject);
}
};
Services.obs.addObserver(listener, "EM-loaded", false);
});
let tab = gBrowser.addTab("about:addons");
gBrowser.selectedTab = tab;
let win = yield loadPromise;
const VIEW = "addons://list/extension";
let viewPromise = promiseViewLoaded(tab, VIEW);
win.loadView(VIEW);
yield viewPromise;
// Trigger an update check
let popupPromise = promisePopupNotificationShown("addon-webext-permissions");
yield triggerUpdate(win, addon);
let panel = yield popupPromise;
// Click the cancel button, wait to see the cancel event
let cancelPromise = promiseInstallEvent(addon, "onInstallCancelled");
panel.secondaryButton.click();
yield cancelPromise;
addon = yield AddonManager.getAddonByID(ID);
is(addon.version, "1.0", "Should still be running the old version");
// Trigger a new update check
popupPromise = promisePopupNotificationShown("addon-webext-permissions");
yield triggerUpdate(win, addon);
// This time, accept the upgrade
let updatePromise = promiseInstallEvent(addon, "onInstallEnded");
panel = yield popupPromise;
panel.button.click();
addon = yield updatePromise;
is(addon.version, "2.0", "Should have upgraded");
yield BrowserTestUtils.removeTab(tab);
addon.uninstall();
yield SpecialPowers.popPrefEnv();
}
// Invoke the "Check for Updates" menu item
function checkAll(win) {
win.gViewController.doCommand("cmd_findAllUpdates");
}
// Test "Check for Updates" with both auto-update settings
add_task(() => interactiveUpdateTest(true, checkAll));
add_task(() => interactiveUpdateTest(false, checkAll));
// Invoke an invidual extension's "Find Updates" menu item
function checkOne(win, addon) {
win.gViewController.doCommand("cmd_findItemUpdates", addon);
}
// Test "Find Updates" with both auto-update settings
add_task(() => interactiveUpdateTest(true, checkOne));
add_task(() => interactiveUpdateTest(false, checkOne));

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

@ -128,8 +128,11 @@ this.ExtensionsUI = {
}
let reply = answer => {
Services.obs.notifyObservers(subject, "webextension-permission-response",
JSON.stringify(answer));
if (answer) {
info.resolve();
} else {
info.reject();
}
};
let perms = info.addon.userPermissions;

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

@ -675,6 +675,7 @@ toolbarpaletteitem[place="palette"] > toolbaritem > toolbarbutton {
#PanelUI-update-status > .toolbarbutton-text,
#PanelUI-fxa-label > .toolbarbutton-text,
#PanelUI-footer-addons > toolbarbutton > .toolbarbutton-text,
#PanelUI-customize > .toolbarbutton-text {
margin: 0;
padding: 0 6px;

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

@ -43,7 +43,7 @@ def compiler_class(compiler):
def checking_fn(fn):
return fn
@depends_when(self, dependable(flags), extra_toolchain_flags, when=when)
@depends(self, dependable(flags), extra_toolchain_flags, when=when)
@checking_fn
def func(compiler, flags, extra_flags):
flags = flags or []

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

@ -74,11 +74,11 @@ js_option('--with-linux-headers',
passed_linux_header_flags = depends_if('--with-linux-headers')(lambda v: ['-I%s' % v[0]])
@depends_when(try_compile(includes=['asm/unistd.h'],
body='return sizeof(__NR_perf_event_open);',
flags=passed_linux_header_flags,
check_msg='for perf_event_open system call'),
when=have_perf_event_h)
@depends(try_compile(includes=['asm/unistd.h'],
body='return sizeof(__NR_perf_event_open);',
flags=passed_linux_header_flags,
check_msg='for perf_event_open system call'),
when=have_perf_event_h)
def have_perf_event_open(have_perf_event_open):
if have_perf_event_open:
return True

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

@ -40,8 +40,8 @@ def pkg_check_modules(var, package_desc, when=always,
def when_and_compile_environment(when, compile_environment):
return when and compile_environment
@depends_when(pkg_config, pkg_config_version,
when=when_and_compile_environment)
@depends(pkg_config, pkg_config_version,
when=when_and_compile_environment)
def check_pkg_config(pkg_config, version):
min_version = '0.9.0'
if pkg_config is None:
@ -52,7 +52,7 @@ def pkg_check_modules(var, package_desc, when=always,
die("*** Your version of pkg-config is too old. You need version %s or newer.",
min_version)
@depends_when(pkg_config, package_desc, when=when_and_compile_environment)
@depends(pkg_config, package_desc, when=when_and_compile_environment)
@imports('subprocess')
@imports('sys')
@imports(_from='mozbuild.configure.util', _import='LineIO')
@ -74,20 +74,20 @@ def pkg_check_modules(var, package_desc, when=always,
if not allow_missing:
sys.exit(1)
@depends_when(pkg_config, package_desc, when=package)
@depends(pkg_config, package_desc, when=package)
@checking('%s_CFLAGS' % var, callback=lambda t: ' '.join(t))
def pkg_cflags(pkg_config, package_desc):
flags = check_cmd_output(pkg_config, '--cflags', package_desc)
return tuple(flags.split())
@depends_when(pkg_config, package_desc, when=package)
@depends(pkg_config, package_desc, when=package)
@checking('%s_LIBS' % var, callback=lambda t: ' '.join(t))
def pkg_libs(pkg_config, package_desc):
libs = check_cmd_output(pkg_config, '--libs', package_desc)
# Remove evil flags like -Wl,--export-dynamic
return tuple(libs.replace('-Wl,--export-dynamic', '').split())
@depends_when(pkg_cflags, pkg_libs, when=package)
@depends(pkg_cflags, pkg_libs, when=package)
def pkg_info(cflags, libs):
return namespace(cflags=cflags, libs=libs)

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

@ -399,26 +399,6 @@ def depends_if(*args):
return wrapper
return decorator
# Like @depends_if, but a distinguished value passed as a keyword argument
# "when" is truth tested instead of every argument. This value is not passed
# to the function if it is called.
@template
def depends_when(*args, **kwargs):
if not len(kwargs) == 1 and kwargs.get('when'):
die('depends_when requires a single keyword argument, "when"')
when = kwargs['when']
if not when:
return depends(*args)
def decorator(fn):
@depends(when, *args)
def wrapper(val, *args):
if val:
return fn(*args)
return wrapper
return decorator
# Hacks related to old-configure
# ==============================

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

@ -26,6 +26,7 @@
#include "mozilla/LookAndFeel.h"
#include "mozilla/Unused.h"
#include "mozilla/intl/LocaleService.h"
#include "nsICommandLine.h"
#include "nsILocaleService.h"
@ -386,6 +387,7 @@ nsresult nsChromeRegistryChrome::UpdateSelectedLocale()
NS_ASSERTION(obsSvc, "Couldn't get observer service.");
obsSvc->NotifyObservers((nsIChromeRegistry*) this,
"selected-locale-has-changed", nullptr);
mozilla::intl::LocaleService::GetInstance()->Refresh();
}
}

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

@ -29,6 +29,7 @@ function configureStore() {
error: Services.prefs.getBoolPref(PREFS.FILTER.ERROR),
warn: Services.prefs.getBoolPref(PREFS.FILTER.WARN),
info: Services.prefs.getBoolPref(PREFS.FILTER.INFO),
debug: Services.prefs.getBoolPref(PREFS.FILTER.DEBUG),
log: Services.prefs.getBoolPref(PREFS.FILTER.LOG),
css: Services.prefs.getBoolPref(PREFS.FILTER.CSS),
net: Services.prefs.getBoolPref(PREFS.FILTER.NET),

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

@ -30,6 +30,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_webconsole_context_menu_open_url.js]
[browser_webconsole_context_menu_store_as_global.js]
[browser_webconsole_filters.js]
[browser_webconsole_filters_persist.js]
[browser_webconsole_init.js]
[browser_webconsole_input_focus.js]
[browser_webconsole_keyboard_accessibility.js]

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

@ -0,0 +1,72 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests all filters persist.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/mochitest/test-console-filters.html";
add_task(function* () {
let hud = yield openNewTabAndConsole(TEST_URI);
let filterButtons = yield getFilterButtons(hud);
info("Disable all filters");
filterButtons.forEach(filterButton => {
if (filterIsEnabled(filterButton)) {
filterButton.click();
}
});
info("Close and re-open the console");
yield closeTabAndToolbox();
hud = yield openNewTabAndConsole(TEST_URI);
info("Check that all filters are disabled, and enable them");
filterButtons = yield getFilterButtons(hud);
filterButtons.forEach(filterButton => {
ok(!filterIsEnabled(filterButton), "filter is disabled");
filterButton.click();
});
info("Close and re-open the console");
yield closeTabAndToolbox();
hud = yield openNewTabAndConsole(TEST_URI);
info("Check that all filters are enabled");
filterButtons = yield getFilterButtons(hud);
filterButtons.forEach(filterButton => {
ok(filterIsEnabled(filterButton), "filter is enabled");
});
// Check that the ui settings were persisted.
yield closeTabAndToolbox();
});
function* getFilterButtons(hud) {
const outputNode = hud.ui.experimentalOutputNode;
info("Wait for console toolbar to appear");
const toolbar = yield waitFor(() => {
return outputNode.querySelector(".webconsole-filterbar-primary");
});
// Show the filter bar if it is hidden
if (!outputNode.querySelector(".webconsole-filterbar-secondary")) {
toolbar.querySelector(".devtools-filter-icon").click();
}
info("Wait for console filterbar to appear");
const filterBar = yield waitFor(() => {
return outputNode.querySelector(".webconsole-filterbar-secondary");
});
ok(filterBar, "Filter bar is shown when filter icon is clicked.");
return filterBar.querySelectorAll(".menu-filter-button");
}
function filterIsEnabled(button) {
return button.classList.contains("checked");
}

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

@ -41,6 +41,9 @@ AudioChannelAgent::AudioChannelAgent()
, mInnerWindowID(0)
, mIsRegToService(false)
{
// Init service in the begining, it can help us to know whether there is any
// created media component via AudioChannelService::IsServiceStarted().
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
}
AudioChannelAgent::~AudioChannelAgent()
@ -181,6 +184,9 @@ AudioChannelAgent::InitInternal(nsPIDOMWindowInner* aWindow,
mCallback = aCallback;
}
RefPtr<AudioChannelService> service = AudioChannelService::GetOrCreate();
service->NotifyCreatedNewAgent(this);
MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug,
("AudioChannelAgent, InitInternal, this = %p, type = %d, "
"owner = %p, hasCallback = %d\n", this, mAudioChannelType,

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

@ -201,6 +201,13 @@ AudioChannelService::CreateServiceIfNeeded()
}
}
/* static */ bool
AudioChannelService::IsServiceStarted()
{
// The service would start when the first AudioChannelAgent is created.
return !!gAudioChannelService;
}
/* static */ already_AddRefed<AudioChannelService>
AudioChannelService::GetOrCreate()
{
@ -286,6 +293,19 @@ AudioChannelService::~AudioChannelService()
{
}
void
AudioChannelService::NotifyCreatedNewAgent(AudioChannelAgent* aAgent)
{
MOZ_ASSERT(aAgent);
nsCOMPtr<nsPIDOMWindowOuter> window = aAgent->Window();
if (!window) {
return;
}
window->NotifyCreatedNewMediaComponent();
}
void
AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudibleState aAudible)
@ -1392,7 +1412,18 @@ AudioChannelService::AudioChannelWindow::MaybeNotifyMediaBlocked(AudioChannelAge
}
MOZ_ASSERT(window->IsOuterWindow());
if (window->GetMediaSuspend() != nsISuspendedTypes::SUSPENDED_BLOCK) {
nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow();
if (!inner) {
return;
}
nsCOMPtr<nsIDocument> doc = inner->GetExtantDoc();
if (!doc) {
return;
}
if (window->GetMediaSuspend() != nsISuspendedTypes::SUSPENDED_BLOCK ||
!doc->Hidden()) {
return;
}

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

@ -100,6 +100,8 @@ public:
static bool IsEnableAudioCompeting();
static bool IsServiceStarted();
/**
* Any audio channel agent that starts playing should register itself to
* this service, sharing the AudioChannel.
@ -197,6 +199,8 @@ public:
void ChildStatusReceived(uint64_t aChildID, bool aTelephonyChannel,
bool aContentOrNormalChannel, bool aAnyChannel);
void NotifyCreatedNewAgent(AudioChannelAgent* aAgent);
private:
AudioChannelService();
~AudioChannelService();

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

@ -8,6 +8,7 @@
* Base class for all our document implementations.
*/
#include "AudioChannelService.h"
#include "nsDocument.h"
#include "nsIDocumentInlines.h"
#include "mozilla/AnimationComparator.h"
@ -12084,9 +12085,7 @@ nsDocument::MaybeActiveMediaComponents()
}
mEverInForeground = true;
if (GetWindow()->GetMediaSuspend() == nsISuspendedTypes::SUSPENDED_BLOCK) {
GetWindow()->SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
}
GetWindow()->MaybeActiveMediaComponents();
}
NS_IMETHODIMP

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

@ -4168,6 +4168,45 @@ nsPIDOMWindowInner::IsRunningTimeout()
return TimeoutManager().IsRunningTimeout();
}
void
nsPIDOMWindowOuter::NotifyCreatedNewMediaComponent()
{
if (mMediaSuspend != nsISuspendedTypes::SUSPENDED_BLOCK) {
return;
}
// If the document is already on the foreground but the suspend state is still
// suspend-block, that means the media component was created after calling
// MaybeActiveMediaComponents, so the window's suspend state doesn't be
// changed yet. Therefore, we need to call it again, because the state is only
// changed after there exists alive media within the window.
MaybeActiveMediaComponents();
}
void
nsPIDOMWindowOuter::MaybeActiveMediaComponents()
{
if (IsInnerWindow()) {
return mOuterWindow->MaybeActiveMediaComponents();
}
nsCOMPtr<nsPIDOMWindowInner> inner = GetCurrentInnerWindow();
if (!inner) {
return;
}
nsCOMPtr<nsIDocument> doc = inner->GetExtantDoc();
if (!doc) {
return;
}
if (!doc->Hidden() &&
mMediaSuspend == nsISuspendedTypes::SUSPENDED_BLOCK &&
AudioChannelService::IsServiceStarted()) {
SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
}
}
SuspendTypes
nsPIDOMWindowOuter::GetMediaSuspend() const
{

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

@ -963,6 +963,9 @@ public:
float GetAudioVolume() const;
nsresult SetAudioVolume(float aVolume);
void NotifyCreatedNewMediaComponent();
void MaybeActiveMediaComponents();
void SetServiceWorkersTestingEnabled(bool aEnabled);
bool GetServiceWorkersTestingEnabled();

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

@ -82,7 +82,6 @@ support-files =
support-files = pointerevent_setpointercapture_disconnected-manual.html
[test_pointerevent_setpointercapture_inactive_button_mouse-manual.html]
support-files = pointerevent_setpointercapture_inactive_button_mouse-manual.html
disabled = should be investigated
[test_pointerevent_setpointercapture_invalid_pointerid-manual.html]
support-files = pointerevent_setpointercapture_invalid_pointerid-manual.html
[test_pointerevent_setpointercapture_override_pending_capture_element-manual.html]

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

@ -81,56 +81,60 @@ var MouseEventHelper = (function() {
};
}) ();
function createMouseEvent(aEventType, aParams) {
var eventObj = {type: aEventType};
// Default to mouse.
eventObj.inputSource =
(aParams && "inputSource" in aParams) ? aParams.inputSource :
MouseEvent.MOZ_SOURCE_MOUSE;
// Compute pointerId
eventObj.id =
(eventObj.inputSource === MouseEvent.MOZ_SOURCE_MOUSE) ? MouseEventHelper.MOUSE_ID :
MouseEventHelper.PEN_ID;
// Check or generate a |button| value.
var isButtonEvent = aEventType === "mouseup" || aEventType === "mousedown";
// Set |button| to the default value first.
eventObj.button = isButtonEvent ? MouseEventHelper.BUTTON_LEFT
: MouseEventHelper.BUTTON_NONE;
// |button| is passed, use and check it.
if (aParams && "button" in aParams) {
var hasButtonValue = (aParams.button !== MouseEventHelper.BUTTON_NONE);
ok(!isButtonEvent || hasButtonValue,
"Inappropriate |button| value caught.");
eventObj.button = aParams.button;
}
// Generate a |buttons| value and update buttons state
var buttonsMask = MouseEventHelper.computeButtonsMaskFromButton(eventObj.button);
switch(aEventType) {
case "mousedown":
MouseEventHelper.BUTTONS_STATE |= buttonsMask; // Set button flag.
break;
case "mouseup":
MouseEventHelper.BUTTONS_STATE &= ~buttonsMask; // Clear button flag.
break;
}
eventObj.buttons = MouseEventHelper.BUTTONS_STATE;
// Replace the button value for mousemove events.
// Since in widget level design, even when no button is pressed at all, the
// value of WidgetMouseEvent.button is still 0, which is the same value as
// the one for mouse left button.
if (aEventType === "mousemove") {
eventObj.button = MouseEventHelper.BUTTON_LEFT;
}
return eventObj;
}
// Helper function to send MouseEvent with different parameters
function sendMouseEvent(int_win, elemId, mouseEventType, params) {
var elem = int_win.document.getElementById(elemId);
if(!!elem) {
if (elem) {
var rect = elem.getBoundingClientRect();
var eventObj = {type: mouseEventType};
// Default to mouse.
eventObj.inputSource =
(params && "inputSource" in params) ? params.inputSource :
MouseEvent.MOZ_SOURCE_MOUSE;
// Compute pointerId
eventObj.id =
(eventObj.inputSource === MouseEvent.MOZ_SOURCE_MOUSE) ? MouseEventHelper.MOUSE_ID :
MouseEventHelper.PEN_ID;
// Check or generate a |button| value.
var isButtonEvent = mouseEventType === "mouseup" ||
mouseEventType === "mousedown";
// Set |button| to the default value first.
eventObj.button = isButtonEvent ? MouseEventHelper.BUTTON_LEFT
: MouseEventHelper.BUTTON_NONE;
// |button| is passed, use and check it.
if (params && "button" in params) {
var hasButtonValue = (params.button !== MouseEventHelper.BUTTON_NONE);
ok(!isButtonEvent || hasButtonValue,
"Inappropriate |button| value caught.");
eventObj.button = params.button;
}
// Generate a |buttons| value and update buttons state
var buttonsMask = MouseEventHelper.computeButtonsMaskFromButton(eventObj.button);
switch(mouseEventType) {
case "mousedown":
MouseEventHelper.BUTTONS_STATE |= buttonsMask; // Set button flag.
break;
case "mouseup":
MouseEventHelper.BUTTONS_STATE &= ~buttonsMask; // Clear button flag.
break;
}
eventObj.buttons = MouseEventHelper.BUTTONS_STATE;
// Replace the button value for mousemove events.
// Since in widget level design, even when no button is pressed at all, the
// value of WidgetMouseEvent.button is still 0, which is the same value as
// the one for mouse left button.
if (mouseEventType === "mousemove") {
eventObj.button = MouseEventHelper.BUTTON_LEFT;
}
var eventObj = createMouseEvent(mouseEventType, params);
// Default to the center of the target element but we can still send to a
// position outside of the target element.
@ -145,6 +149,13 @@ function sendMouseEvent(int_win, elemId, mouseEventType, params) {
}
}
// Helper function to send MouseEvent with position
function sendMouseEventAtPoint(aWindow, aLeft, aTop, aMouseEventType, aParams) {
var eventObj = createMouseEvent(aMouseEventType, aParams);
console.log(eventObj);
synthesizeMouseAtPoint(aLeft, aTop, eventObj, aWindow);
}
// Touch Event Helper Object
var TouchEventHelper = {
// State

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

@ -17,9 +17,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1000870
runTestInNewWindow("pointerevent_setpointercapture_inactive_button_mouse-manual.html");
}
function executeTest(int_win) {
sendMouseEvent(int_win, "target1", "mousemove");
sendMouseEvent(int_win, "target0", "mousemove");
sendMouseEvent(int_win, "target1", "mousemove");
let target0 = int_win.document.getElementById("target0");
let rect = target0.getBoundingClientRect();
sendMouseEventAtPoint(int_win, rect.left + 1, rect.top + 1, "mousemove");
sendMouseEventAtPoint(int_win, rect.left - 1, rect.top - 1, "mousemove");
}
</script>
</head>

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

@ -429,18 +429,14 @@ GetFilesHelperBase::AddExploredDirectory(nsIFile* aDir)
return rv;
}
nsAutoCString path;
nsAutoString path;
if (!isLink) {
nsAutoString path16;
rv = aDir->GetPath(path16);
rv = aDir->GetPath(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
path = NS_ConvertUTF16toUTF8(path16);
} else {
rv = aDir->GetNativeTarget(path);
rv = aDir->GetTarget(path);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -463,8 +459,8 @@ GetFilesHelperBase::ShouldFollowSymLink(nsIFile* aDir)
MOZ_ASSERT(isLink && isDir, "Why are we here?");
#endif
nsAutoCString targetPath;
if (NS_WARN_IF(NS_FAILED(aDir->GetNativeTarget(targetPath)))) {
nsAutoString targetPath;
if (NS_WARN_IF(NS_FAILED(aDir->GetTarget(targetPath)))) {
return false;
}

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

@ -65,7 +65,7 @@ protected:
// We populate this array in the I/O thread with the BlobImpl.
FallibleTArray<RefPtr<BlobImpl>> mTargetBlobImplArray;
nsTHashtable<nsCStringHashKey> mExploredDirectories;
nsTHashtable<nsStringHashKey> mExploredDirectories;
};
// Retrieving the list of files can be very time/IO consuming. We use this

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

@ -1471,6 +1471,33 @@ HTMLMediaElement::GetMozDebugReaderData(nsAString& aString)
}
}
already_AddRefed<Promise>
HTMLMediaElement::MozRequestDebugInfo(ErrorResult& aRv)
{
RefPtr<Promise> promise = CreateDOMPromise(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsAutoString result;
GetMozDebugReaderData(result);
if (mDecoder) {
mDecoder->RequestDebugInfo()->Then(
AbstractThread::MainThread(), __func__,
[promise, result] (const nsACString& aString) {
promise->MaybeResolve(result + NS_ConvertUTF8toUTF16(aString));
},
[promise, result] () {
promise->MaybeResolve(result);
});
} else {
promise->MaybeResolve(result);
}
return promise.forget();
}
void
HTMLMediaElement::MozDumpDebugInfo()
{

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

@ -604,6 +604,10 @@ public:
// data. Used for debugging purposes.
void GetMozDebugReaderData(nsAString& aString);
// Returns a promise which will be resolved after collecting debugging
// data from decoder/reader/MDSM. Used for debugging purposes.
already_AddRefed<Promise> MozRequestDebugInfo(ErrorResult& aRv);
void MozDumpDebugInfo();
void SetVisible(bool aVisible);

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

@ -791,7 +791,9 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
Preferences::GetUint("media.audio-max-decode-error", 3))
, mVideo(this, MediaData::VIDEO_DATA,
Preferences::GetUint("media.video-max-decode-error", 2))
, mDemuxer(nullptr)
, mDemuxer(new DemuxerProxy(aDemuxer, aDecoder
? aDecoder->AbstractMainThread()
: AbstractThread::MainThread()))
, mDemuxerInitDone(false)
, mLastReportedNumDecodedFrames(0)
, mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
@ -804,15 +806,10 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
MOZ_ASSERT(aDemuxer);
MOZ_COUNT_CTOR(MediaFormatReader);
if (aDecoder) {
mDemuxer = MakeUnique<DemuxerProxy>(aDemuxer,
aDecoder->AbstractMainThread());
if (aDecoder->CompositorUpdatedEvent()) {
mCompositorUpdatedListener =
aDecoder->CompositorUpdatedEvent()->Connect(
mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
}
if (aDecoder && aDecoder->CompositorUpdatedEvent()) {
mCompositorUpdatedListener =
aDecoder->CompositorUpdatedEvent()->Connect(
mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
}
}
@ -917,10 +914,11 @@ MediaFormatReader::InitInternal()
mVideo.mTaskQueue =
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER));
// Note: GMPCrashHelper must be created on main thread, as it may use
// weak references, which aren't threadsafe.
mCrashHelper = mDecoder->GetCrashHelper();
if (mDecoder) {
// Note: GMPCrashHelper must be created on main thread, as it may use
// weak references, which aren't threadsafe.
mCrashHelper = mDecoder->GetCrashHelper();
}
return NS_OK;
}

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

@ -134,6 +134,8 @@ private:
DECL_MEDIA_PREF("media.gmp.decoder.enabled", PDMGMPEnabled, bool, true);
DECL_MEDIA_PREF("media.gmp.decoder.aac", GMPAACPreferred, uint32_t, 0);
DECL_MEDIA_PREF("media.gmp.decoder.h264", GMPH264Preferred, uint32_t, 0);
DECL_MEDIA_PREF("media.eme.audio.blank", EMEBlankAudio, bool, false);
DECL_MEDIA_PREF("media.eme.video.blank", EMEBlankVideo, bool, false);
// MediaDecoderStateMachine
DECL_MEDIA_PREF("media.suspend-bkgnd-video.enabled", MDSMSuspendBackgroundVideoEnabled, bool, false);

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

@ -150,6 +150,7 @@ protected:
friend class H264Converter;
friend class PDMFactory;
friend class dom::RemoteDecoderModule;
friend class EMEDecoderModule;
// Creates a Video decoder. The layers backend is passed in so that
// decoders can determine whether hardware accelerated decoding can be used.

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

@ -16,10 +16,13 @@
#include "nsClassHashtable.h"
#include "GMPDecoderModule.h"
#include "MP4Decoder.h"
#include "MediaPrefs.h"
#include "mozilla/EMEUtils.h"
namespace mozilla {
typedef MozPromiseRequestHolder<CDMProxy::DecryptPromise> DecryptPromiseRequestHolder;
extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
class EMEDecryptor : public MediaDataDecoder {
@ -232,6 +235,12 @@ EMEDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
{
MOZ_ASSERT(aParams.mConfig.mCrypto.mValid);
if (MediaPrefs::EMEBlankVideo()) {
EME_LOG("EMEDecoderModule::CreateVideoDecoder() creating a blank decoder.");
RefPtr<PlatformDecoderModule> m(CreateBlankDecoderModule());
return m->CreateVideoDecoder(aParams);
}
if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) {
// GMP decodes. Assume that means it can decrypt too.
RefPtr<MediaDataDecoderProxy> wrapper =
@ -263,6 +272,12 @@ EMEDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
MOZ_ASSERT(!SupportsMimeType(aParams.mConfig.mMimeType, nullptr));
MOZ_ASSERT(mPDM);
if (MediaPrefs::EMEBlankAudio()) {
EME_LOG("EMEDecoderModule::CreateAudioDecoder() creating a blank decoder.");
RefPtr<PlatformDecoderModule> m(CreateBlankDecoderModule());
return m->CreateAudioDecoder(aParams);
}
RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams));
if (!decoder) {
return nullptr;

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

@ -598,13 +598,16 @@ void
RemoteDataDecoder::Shutdown()
{
LOG("");
MOZ_ASSERT(mJavaDecoder && mJavaCallbacks);
mJavaDecoder->Release();
mJavaDecoder = nullptr;
if (mJavaDecoder) {
mJavaDecoder->Release();
mJavaDecoder = nullptr;
}
JavaCallbacksSupport::GetNative(mJavaCallbacks)->Cancel();
mJavaCallbacks = nullptr;
if (mJavaCallbacks) {
JavaCallbacksSupport::GetNative(mJavaCallbacks)->Cancel();
mJavaCallbacks = nullptr;
}
mFormat = nullptr;
}

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

@ -5,9 +5,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSMILCompositor.h"
#include "nsSMILCSSProperty.h"
#include "nsCSSProps.h"
#include "nsHashKeys.h"
#include "nsSMILCSSProperty.h"
// PLDHashEntryHdr methods
bool
@ -143,14 +144,17 @@ nsSMILCompositor::CreateSMILAttr()
uint32_t
nsSMILCompositor::GetFirstFuncToAffectSandwich()
{
// canThrottle is true when attributeName is not 'display' and
// the element or subtree is display:none
RefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElementNoFlush(mKey.mElement,
nullptr, nullptr);
// For performance reasons, we throttle most animations on elements in
// display:none subtrees. (We can't throttle animations that target the
// "display" property itself, though -- if we did, display:none elements
// could never be dynamically displayed via animations.)
// To determine whether we're in a display:none subtree, we will check the
// element's primary frame since element in display:none subtree doesn't have
// a primary frame. Before this process, we will construct frame when we
// append an element to subtree. So we will not need to worry about pending
// frame construction in this step.
bool canThrottle = mKey.mAttributeName != nsGkAtoms::display &&
styleContext &&
styleContext->IsInDisplayNoneSubtree();
!mKey.mElement->GetPrimaryFrame();
uint32_t i;
for (i = mAnimationFunctions.Length(); i > 0; --i) {

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

@ -15,13 +15,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=515116
<div id="content">
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="100" height="100"
onload="this.pauseAnimations();">
<desc>
<defs>
<filter>
<feComponentTransfer>
<feFuncR id="feFuncR" type="table"/>
</feComponentTransfer>
</filter>
</desc>
</defs>
<text id="text">text</text>
<path id="path"/>
<polyline id="polyline"/>

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

@ -104,6 +104,8 @@ partial interface HTMLMediaElement {
readonly attribute MediaSource? mozMediaSourceObject;
[ChromeOnly]
readonly attribute DOMString mozDebugReaderData;
[ChromeOnly, NewObject]
Promise<DOMString> mozRequestDebugInfo();
[Pref="media.test.dumpDebugInfo"]
void mozDumpDebugInfo();

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

@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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/. */
#include "LocaleService.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
#include "nsIToolkitChromeRegistry.h"
using namespace mozilla::intl;
/**
* This function performs the actual language negotiation for the API.
*
* Currently it collects the locale ID used by nsChromeRegistry and
* adds hardcoded "en-US" locale as a fallback.
*/
static void
ReadAppLocales(nsTArray<nsCString>& aRetVal)
{
nsAutoCString uaLangTag;
nsCOMPtr<nsIToolkitChromeRegistry> cr =
mozilla::services::GetToolkitChromeRegistryService();
if (cr) {
cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), true, uaLangTag);
}
if (!uaLangTag.IsEmpty()) {
aRetVal.AppendElement(uaLangTag);
}
if (!uaLangTag.EqualsLiteral("en-US")) {
aRetVal.AppendElement(NS_LITERAL_CSTRING("en-US"));
}
}
mozilla::StaticAutoPtr<LocaleService> LocaleService::sInstance;
LocaleService* LocaleService::GetInstance()
{
if (!sInstance) {
sInstance = new LocaleService();
ClearOnShutdown(&sInstance);
}
return sInstance;
}
void
LocaleService::GetAppLocales(nsTArray<nsCString>& aRetVal)
{
if (mAppLocales.IsEmpty()) {
ReadAppLocales(mAppLocales);
}
aRetVal = mAppLocales;
}
void
LocaleService::GetAppLocale(nsACString& aRetVal)
{
if (mAppLocales.IsEmpty()) {
ReadAppLocales(mAppLocales);
}
aRetVal = mAppLocales[0];
}
void
LocaleService::Refresh()
{
nsTArray<nsCString> newLocales;
ReadAppLocales(newLocales);
if (mAppLocales != newLocales) {
mAppLocales = Move(newLocales);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr, "intl:app-locales-changed", nullptr);
}
}
}

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

@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode:nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef mozilla_intl_LocaleService_h__
#define mozilla_intl_LocaleService_h__
#include "mozilla/StaticPtr.h"
#include "nsString.h"
#include "nsTArray.h"
namespace mozilla {
namespace intl {
/**
* LocaleService is a manager of language negotiation in Gecko.
*
* It's intended to be the core place for collecting available and
* requested languages and negotiating them to produce a fallback
* chain of locales for the application.
*/
class LocaleService
{
public:
static LocaleService* GetInstance();
/**
* Returns a list of locales that the application should be localized to.
*
* The result is a sorted list of valid locale IDs and it should be
* used for all APIs that accept list of locales, like ECMA402 and L10n APIs.
*
* This API always returns at least one locale.
*
* Example: ["en-US", "de", "pl", "sr-Cyrl", "zh-Hans-HK"]
*
* Usage:
* nsTArray<nsCString> appLocales;
* LocaleService::GetInstance()->GetAppLocales(appLocales);
*/
void GetAppLocales(nsTArray<nsCString>& aRetVal);
/**
* Returns the best locale that the application should be localized to.
*
* The result is a valid locale IDs and it should be
* used for all APIs that do not handle language negotiation.
*
* Where possible, GetAppLocales should be preferred over this API and
* all callsites should handle some form of "best effort" language
* negotiation to respect user preferences in case the use case does
* not have data for the first locale in the list.
*
* Example: "zh-Hans-HK"
*
* Usage:
* nsAutoCString appLocale;
* LocaleService::GetInstance()->GetAppLocale(appLocale);
*/
void GetAppLocale(nsACString& aRetVal);
/**
* Triggers a refresh of the language negotiation process.
*
* If the result differs from the previous list, it will additionally
* trigger a global event "intl:app-locales-changed".
*/
void Refresh();
protected:
nsTArray<nsCString> mAppLocales;
private:
static StaticAutoPtr<LocaleService> sInstance;
};
} // intl
} // namespace mozilla
#endif /* mozilla_intl_LocaleService_h__ */

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

@ -35,7 +35,12 @@ EXPORTS += [
'nsWin32Locale.h',
]
EXPORTS.mozilla.intl += [
'LocaleService.h'
]
UNIFIED_SOURCES += [
'LocaleService.cpp',
'nsCollation.cpp',
'nsLanguageAtomService.cpp',
'nsLocale.cpp',
@ -74,3 +79,6 @@ GENERATED_FILES += [
langgroups = GENERATED_FILES['langGroups.properties.h']
langgroups.script = 'props2arrays.py'
langgroups.inputs = ['langGroups.properties']
if CONFIG['ENABLE_TESTS']:
DIRS += ['tests/gtest']

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

@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "gtest/gtest.h"
#include "LocaleService.h"
#include "mozilla/Services.h"
#include "nsIToolkitChromeRegistry.h"
using namespace mozilla::intl;
TEST(Intl_Locale_LocaleService, GetAppLocales) {
nsTArray<nsCString> appLocales;
LocaleService::GetInstance()->GetAppLocales(appLocales);
ASSERT_FALSE(appLocales.IsEmpty());
}
TEST(Intl_Locale_LocaleService, GetAppLocales_firstMatchesChromeReg) {
nsTArray<nsCString> appLocales;
LocaleService::GetInstance()->GetAppLocales(appLocales);
nsAutoCString uaLangTag;
nsCOMPtr<nsIToolkitChromeRegistry> cr =
mozilla::services::GetToolkitChromeRegistryService();
if (cr) {
cr->GetSelectedLocale(NS_LITERAL_CSTRING("global"), true, uaLangTag);
}
ASSERT_TRUE(appLocales[0].Equals(uaLangTag));
}
TEST(Intl_Locale_LocaleService, GetAppLocales_lastIsEnUS) {
nsTArray<nsCString> appLocales;
LocaleService::GetInstance()->GetAppLocales(appLocales);
int32_t len = appLocales.Length();
ASSERT_TRUE(appLocales[len - 1].EqualsLiteral("en-US"));
}
TEST(Intl_Locale_LocaleService, GetAppLocale) {
nsTArray<nsCString> appLocales;
LocaleService::GetInstance()->GetAppLocales(appLocales);
nsAutoCString locale;
LocaleService::GetInstance()->GetAppLocale(locale);
ASSERT_TRUE(appLocales[0] == locale);
}

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

@ -0,0 +1,15 @@
# -*- Mode: python; 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/.
UNIFIED_SOURCES += [
'TestLocaleService.cpp',
]
LOCAL_INCLUDES += [
'/intl/locale',
]
FINAL_LIBRARY = 'xul-gtest'

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

@ -56,12 +56,6 @@ class Visitor:
def visitProtocol(self, p):
for namespace in p.namespaces:
namespace.accept(self)
for spawns in p.spawnsStmts:
spawns.accept(self)
for bridges in p.bridgesStmts:
bridges.accept(self)
for opens in p.opensStmts:
opens.accept(self)
for mgr in p.managers:
mgr.accept(self)
for managed in p.managesStmts:
@ -72,15 +66,6 @@ class Visitor:
def visitNamespace(self, ns):
pass
def visitSpawnsStmt(self, spawns):
pass
def visitBridgesStmt(self, bridges):
pass
def visitOpensStmt(self, opens):
pass
def visitManager(self, mgr):
pass
@ -226,9 +211,6 @@ class Protocol(NamespacedNode):
NamespacedNode.__init__(self, loc)
self.sendSemantics = ASYNC
self.nested = NOT_NESTED
self.spawnsStmts = [ ]
self.bridgesStmts = [ ]
self.opensStmts = [ ]
self.managers = [ ]
self.managesStmts = [ ]
self.messageDecls = [ ]
@ -249,25 +231,6 @@ class UnionDecl(NamespacedNode):
NamespacedNode.__init__(self, loc, name)
self.components = components
class SpawnsStmt(Node):
def __init__(self, loc, side, proto, spawnedAs):
Node.__init__(self, loc)
self.side = side
self.proto = proto
self.spawnedAs = spawnedAs
class BridgesStmt(Node):
def __init__(self, loc, parentSide, childSide):
Node.__init__(self, loc)
self.parentSide = parentSide
self.childSide = childSide
class OpensStmt(Node):
def __init__(self, loc, side, proto):
Node.__init__(self, loc)
self.side = side
self.proto = proto
class Manager(Node):
def __init__(self, loc, managerName):
Node.__init__(self, loc)

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

@ -9,7 +9,7 @@ from collections import OrderedDict
import ipdl.ast
import ipdl.builtin
from ipdl.cxx.ast import *
from ipdl.type import ActorType, ProcessGraph, TypeVisitor, builtinHeaderIncludes
from ipdl.type import ActorType, TypeVisitor, builtinHeaderIncludes
##-----------------------------------------------------------------------------
## "Public" interface to lowering
@ -363,11 +363,6 @@ def _otherSide(side):
if side == 'parent': return 'child'
assert 0
def _sideToTransportMode(side):
if side == 'parent': mode = 'SERVER'
elif side == 'child': mode = 'CLIENT'
return ExprVar('mozilla::ipc::Transport::MODE_'+ mode)
def _ifLogging(topLevelProtocol, stmts):
iflogging = StmtIf(ExprCall(ExprVar('mozilla::ipc::LoggingEnabledFor'),
args=[ topLevelProtocol ]))
@ -1476,27 +1471,6 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
_makeForwardDeclForActor(p.decl.type, 'Child')
])
bridges = ProcessGraph.bridgesOf(p.decl.type)
for bridge in bridges:
ppt, pside = bridge.parent.ptype, _otherSide(bridge.parent.side)
cpt, cside = bridge.child.ptype, _otherSide(bridge.child.side)
self.hdrfile.addthings([
Whitespace.NL,
_makeForwardDeclForActor(ppt, pside),
_makeForwardDeclForActor(cpt, cside)
])
self.cppIncludeHeaders.append(_protocolHeaderName(ppt._ast, pside))
self.cppIncludeHeaders.append(_protocolHeaderName(cpt._ast, cside))
opens = ProcessGraph.opensOf(p.decl.type)
for o in opens:
optype, oside = o.opener.ptype, o.opener.side
self.hdrfile.addthings([
Whitespace.NL,
_makeForwardDeclForActor(optype, oside)
])
self.cppIncludeHeaders.append(_protocolHeaderName(optype._ast, oside))
self.hdrfile.addthing(Whitespace("""
//-----------------------------------------------------------------------------
// Code common to %sChild and %sParent
@ -1508,19 +1482,6 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
self.hdrfile.addthing(_putInNamespaces(ns, p.namespaces))
ns.addstmt(Whitespace.NL)
# user-facing methods for connecting two process with a new channel
for bridge in bridges:
bdecl, bdefn = _splitFuncDeclDefn(self.genBridgeFunc(bridge))
ns.addstmts([ bdecl, Whitespace.NL ])
self.funcDefns.append(bdefn)
# user-facing methods for opening a new channel across two
# existing endpoints
for o in opens:
odecl, odefn = _splitFuncDeclDefn(self.genOpenFunc(o))
ns.addstmts([ odecl, Whitespace.NL ])
self.funcDefns.append(odefn)
edecl, edefn = _splitFuncDeclDefn(self.genEndpointFunc())
ns.addstmts([ edecl, Whitespace.NL ])
self.funcDefns.append(edefn)
@ -1574,55 +1535,6 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
ns.addstmts([ Whitespace.NL, Whitespace.NL ])
def genBridgeFunc(self, bridge):
p = self.protocol
parentHandleType = _cxxBareType(ActorType(bridge.parent.ptype),
_otherSide(bridge.parent.side),
fq=1)
parentvar = ExprVar('parentHandle')
childHandleType = _cxxBareType(ActorType(bridge.child.ptype),
_otherSide(bridge.child.side),
fq=1)
childvar = ExprVar('childHandle')
bridgefunc = MethodDefn(MethodDecl(
'Bridge',
params=[ Decl(parentHandleType, parentvar.name),
Decl(childHandleType, childvar.name) ],
ret=Type.NSRESULT))
bridgefunc.addstmt(StmtReturn(ExprCall(
ExprVar('mozilla::ipc::Bridge'),
args=[ _backstagePass(),
p.callGetChannel(parentvar), p.callOtherPid(parentvar),
p.callGetChannel(childvar), p.callOtherPid(childvar),
_protocolId(p.decl.type),
ExprVar(_messageStartName(p.decl.type) + 'Child')
])))
return bridgefunc
def genOpenFunc(self, o):
p = self.protocol
localside = o.opener.side
openertype = _cxxBareType(ActorType(o.opener.ptype), o.opener.side,
fq=1)
openervar = ExprVar('opener')
openfunc = MethodDefn(MethodDecl(
'Open',
params=[ Decl(openertype, openervar.name) ],
ret=Type.BOOL))
openfunc.addstmt(StmtReturn(ExprCall(
ExprVar('mozilla::ipc::Open'),
args=[ _backstagePass(),
p.callGetChannel(openervar), p.callOtherPid(openervar),
_sideToTransportMode(localside),
_protocolId(p.decl.type),
ExprVar(_messageStartName(p.decl.type) + 'Child')
])))
return openfunc
# Generate code for PFoo::CreateEndpoints.
def genEndpointFunc(self):
p = self.protocol.decl.type
@ -2610,10 +2522,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
inherits=inherits,
abstract=True)
bridgeActorsCreated = ProcessGraph.bridgeEndpointsOf(ptype, self.side)
opensActorsCreated = ProcessGraph.opensEndpointsOf(ptype, self.side)
channelOpenedActors = OrderedDict.fromkeys(bridgeActorsCreated + opensActorsCreated, None)
friends = _FindFriends().findFriends(ptype)
if ptype.isManaged():
friends.update(ptype.managers)
@ -2634,13 +2542,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
self.prettyside)),
Whitespace.NL ])
for actor in channelOpenedActors:
self.hdrfile.addthings([
Whitespace.NL,
_makeForwardDeclForActor(actor.ptype, actor.side),
Whitespace.NL
])
self.cls.addstmt(Label.PROTECTED)
for typedef in p.cxxTypedefs():
self.cls.addstmt(typedef)
@ -2692,17 +2593,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
ret=Type.BOOL,
virtual=1, pure=1)))
for actor in channelOpenedActors:
# add the Alloc interface for actors created when a
# new channel is opened
actortype = _cxxBareType(actor.asType(), actor.side)
self.cls.addstmt(StmtDecl(MethodDecl(
_allocMethod(actor.ptype, actor.side).name,
params=[ Decl(Type('Transport', ptr=1), 'aTransport'),
Decl(Type('ProcessId'), 'aOtherPid') ],
ret=actortype,
virtual=1, pure=1)))
# ActorDestroy() method; default is no-op
self.cls.addstmts([
Whitespace.NL,
@ -2865,11 +2755,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
for md in p.messageDecls:
self.visitMessageDecl(md)
# Handlers for the creation of actors when a new channel is
# opened
if len(channelOpenedActors):
self.makeChannelOpenedHandlers(channelOpenedActors)
# add default cases
default = StmtBlock()
default.addstmt(StmtReturn(_Result.NotKnown))
@ -3299,84 +3184,6 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
return case
def makeChannelOpenedHandlers(self, actors):
handlers = StmtBlock()
# unpack the transport descriptor et al.
msgvar = self.msgvar
tdvar = ExprVar('td')
pidvar = ExprVar('pid')
pvar = ExprVar('protocolid')
iffail = StmtIf(ExprNot(ExprCall(
ExprVar('mozilla::ipc::UnpackChannelOpened'),
args=[ _backstagePass(),
msgvar,
ExprAddrOf(tdvar), ExprAddrOf(pidvar), ExprAddrOf(pvar) ])))
iffail.addifstmt(StmtReturn(_Result.PayloadError))
handlers.addstmts([
StmtDecl(Decl(Type('TransportDescriptor'), tdvar.name)),
StmtDecl(Decl(Type('ProcessId'), pidvar.name)),
StmtDecl(Decl(Type('ProtocolId'), pvar.name)),
iffail,
Whitespace.NL
])
def makeHandlerCase(actor):
self.protocolCxxIncludes.append(_protocolHeaderName(actor.ptype._ast,
actor.side))
case = StmtBlock()
modevar = _sideToTransportMode(actor.side)
tvar = ExprVar('t')
iffailopen = StmtIf(ExprNot(ExprAssn(
tvar,
ExprCall(ExprVar('mozilla::ipc::OpenDescriptor'),
args=[ tdvar, modevar ]))))
iffailopen.addifstmt(StmtReturn(_Result.ValuError))
pvar = ExprVar('p')
iffailalloc = StmtIf(ExprNot(ExprAssn(
pvar,
ExprCall(
_allocMethod(actor.ptype, actor.side),
args=[ _uniqueptrGet(tvar), pidvar ]))))
iffailalloc.addifstmt(StmtReturn(_Result.ProcessingError))
settrans = StmtExpr(ExprCall(
ExprSelect(pvar, '->', 'IToplevelProtocol::SetTransport'),
args=[ExprMove(tvar)]))
case.addstmts([
StmtDecl(Decl(_uniqueptr(Type('Transport')), tvar.name)),
StmtDecl(Decl(Type(_actorName(actor.ptype.name(), actor.side),
ptr=1), pvar.name)),
iffailopen,
iffailalloc,
settrans,
StmtBreak()
])
label = _messageStartName(actor.ptype)
if actor.side == 'child':
label += 'Child'
return CaseLabel(label), case
pswitch = StmtSwitch(pvar)
for actor in actors:
label, case = makeHandlerCase(actor)
pswitch.addcase(label, case)
die = Block()
die.addstmts([ _fatalError('Invalid protocol'),
StmtReturn(_Result.ValuError) ])
pswitch.addcase(DefaultLabel(), die)
handlers.addstmts([
pswitch,
StmtReturn(_Result.Processed)
])
self.asyncSwitch.addcase(CaseLabel('CHANNEL_OPENED_MESSAGE_TYPE'),
handlers)
##-------------------------------------------------------------------------
## The next few functions are the crux of the IPDL code generator.
## They generate code for all the nasty work of message

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

@ -105,10 +105,8 @@ def locFromTok(p, num):
##-----------------------------------------------------------------------------
reserved = set((
'as',
'async',
'both',
'bridges',
'child',
'class',
'compress',
@ -123,13 +121,11 @@ reserved = set((
'namespace',
'nested',
'nullable',
'opens',
'or',
'parent',
'prio',
'protocol',
'returns',
'spawns',
'struct',
'sync',
'union',
@ -350,61 +346,9 @@ def p_ProtocolDefn(p):
def p_ProtocolBody(p):
"""ProtocolBody : SpawnsStmtsOpt"""
"""ProtocolBody : ManagersStmtOpt"""
p[0] = p[1]
##--------------------
## spawns/bridges/opens stmts
def p_SpawnsStmtsOpt(p):
"""SpawnsStmtsOpt : SpawnsStmt SpawnsStmtsOpt
| BridgesStmtsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].spawnsStmts.insert(0, p[1])
p[0] = p[2]
def p_SpawnsStmt(p):
"""SpawnsStmt : PARENT SPAWNS ID AsOpt ';'
| CHILD SPAWNS ID AsOpt ';'"""
p[0] = SpawnsStmt(locFromTok(p, 1), p[1], p[3], p[4])
def p_AsOpt(p):
"""AsOpt : AS PARENT
| AS CHILD
| """
if 3 == len(p):
p[0] = p[2]
else:
p[0] = 'child'
def p_BridgesStmtsOpt(p):
"""BridgesStmtsOpt : BridgesStmt BridgesStmtsOpt
| OpensStmtsOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].bridgesStmts.insert(0, p[1])
p[0] = p[2]
def p_BridgesStmt(p):
"""BridgesStmt : BRIDGES ID ',' ID ';'"""
p[0] = BridgesStmt(locFromTok(p, 1), p[2], p[4])
def p_OpensStmtsOpt(p):
"""OpensStmtsOpt : OpensStmt OpensStmtsOpt
| ManagersStmtOpt"""
if 2 == len(p):
p[0] = p[1]
else:
p[2].opensStmts.insert(0, p[1])
p[0] = p[2]
def p_OpensStmt(p):
"""OpensStmt : PARENT OPENS ID ';'
| CHILD OPENS ID ';'"""
p[0] = OpensStmt(locFromTok(p, 1), p[1], p[3])
##--------------------
## manager/manages stmts

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

@ -15,17 +15,6 @@ import ipdl.builtin as builtin
_DELETE_MSG = '__delete__'
def _otherside(side):
if side == 'parent': return 'child'
elif side == 'child': return 'parent'
else: assert 0 and 'unknown side "%s"'% (side)
def cartesian_product(s1, s2):
for e1 in s1:
for e2 in s2:
yield (e1, e2)
class TypeVisitor:
def __init__(self):
self.visited = set()
@ -223,26 +212,11 @@ class MessageType(IPDLType):
def hasImplicitActorParam(self):
return self.isCtor() or self.isDtor()
class Bridge:
def __init__(self, parentPtype, childPtype):
assert parentPtype.isToplevel() and childPtype.isToplevel()
self.parent = parentPtype
self.child = childPtype
def __cmp__(self, o):
return cmp(self.parent, o.parent) or cmp(self.child, o.child)
def __eq__(self, o):
return self.parent == o.parent and self.child == o.child
def __hash__(self):
return hash(self.parent) + hash(self.child)
class ProtocolType(IPDLType):
def __init__(self, qname, nestedRange, sendSemantics):
self.qname = qname
self.nestedRange = nestedRange
self.sendSemantics = sendSemantics
self.spawns = set() # ProtocolType
self.opens = set() # ProtocolType
self.managers = [] # ProtocolType
self.manages = [ ]
self.hasDelete = False
@ -258,14 +232,6 @@ class ProtocolType(IPDLType):
assert mgrtype.isIPDL() and mgrtype.isProtocol()
self.managers.append(mgrtype)
def addSpawn(self, ptype):
assert self.isToplevel() and ptype.isToplevel()
self.spawns.add(ptype)
def addOpen(self, ptype):
assert self.isToplevel() and ptype.isToplevel()
self.opens.add(ptype)
def managedBy(self, mgr):
self.managers = list(mgr)
@ -556,10 +522,6 @@ With this information, it finally type checks the AST.'''
if not runpass(CheckTypes(self.errors)):
return False
if not (runpass(BuildProcessGraph(self.errors))
and runpass(CheckProcessGraph(self.errors))):
return False
return True
def reportErrors(self, errout):
@ -789,15 +751,6 @@ class GatherDecls(TcheckVisitor):
# protocol scope
self.symtab.enterScope(p)
for spawns in p.spawnsStmts:
spawns.accept(self)
for bridges in p.bridgesStmts:
bridges.accept(self)
for opens in p.opensStmts:
opens.accept(self)
seenmgrs = set()
for mgr in p.managers:
if mgr.name in seenmgrs:
@ -851,33 +804,6 @@ class GatherDecls(TcheckVisitor):
self.symtab.exitScope(p)
def visitSpawnsStmt(self, spawns):
pname = spawns.proto
spawns.proto = self.symtab.lookup(pname)
if spawns.proto is None:
self.error(spawns.loc,
"spawned protocol `%s' has not been declared",
pname)
def visitBridgesStmt(self, bridges):
def lookup(p):
decl = self.symtab.lookup(p)
if decl is None:
self.error(bridges.loc,
"bridged protocol `%s' has not been declared", p)
return decl
bridges.parentSide = lookup(bridges.parentSide)
bridges.childSide = lookup(bridges.childSide)
def visitOpensStmt(self, opens):
pname = opens.proto
opens.proto = self.symtab.lookup(pname)
if opens.proto is None:
self.error(opens.loc,
"opened protocol `%s' has not been declared",
pname)
def visitManager(self, mgr):
mgrdecl = self.symtab.lookup(mgr.name)
pdecl = mgr.of.decl
@ -1107,21 +1033,6 @@ class CheckTypes(TcheckVisitor):
# check that we require no more "power" than our manager protocols
ptype, pname = p.decl.type, p.decl.shortname
if len(p.spawnsStmts) and not ptype.isToplevel():
self.error(p.decl.loc,
"protocol `%s' is not top-level and so cannot declare |spawns|",
pname)
if len(p.bridgesStmts) and not ptype.isToplevel():
self.error(p.decl.loc,
"protocol `%s' is not top-level and so cannot declare |bridges|",
pname)
if len(p.opensStmts) and not ptype.isToplevel():
self.error(p.decl.loc,
"protocol `%s' is not top-level and so cannot declare |opens|",
pname)
for mgrtype in ptype.managers:
if mgrtype is not None and ptype.needsMoreJuiceThan(mgrtype):
self.error(
@ -1156,57 +1067,6 @@ class CheckTypes(TcheckVisitor):
return Visitor.visitProtocol(self, p)
def visitSpawnsStmt(self, spawns):
if not self.ptype.isToplevel():
self.error(spawns.loc,
"only top-level protocols can have |spawns| statements; `%s' cannot",
self.ptype.name())
return
spawnedType = spawns.proto.type
if not (spawnedType.isIPDL() and spawnedType.isProtocol()
and spawnedType.isToplevel()):
self.error(spawns.loc,
"cannot spawn non-top-level-protocol `%s'",
spawnedType.name())
else:
self.ptype.addSpawn(spawnedType)
def visitBridgesStmt(self, bridges):
if not self.ptype.isToplevel():
self.error(bridges.loc,
"only top-level protocols can have |bridges| statements; `%s' cannot",
self.ptype.name())
return
parentType = bridges.parentSide.type
childType = bridges.childSide.type
if not (parentType.isIPDL() and parentType.isProtocol()
and childType.isIPDL() and childType.isProtocol()
and parentType.isToplevel() and childType.isToplevel()):
self.error(bridges.loc,
"cannot bridge non-top-level-protocol(s) `%s' and `%s'",
parentType.name(), childType.name())
def visitOpensStmt(self, opens):
if not self.ptype.isToplevel():
self.error(opens.loc,
"only top-level protocols can have |opens| statements; `%s' cannot",
self.ptype.name())
return
openedType = opens.proto.type
if not (openedType.isIPDL() and openedType.isProtocol()
and openedType.isToplevel()):
self.error(opens.loc,
"cannot open non-top-level-protocol `%s'",
openedType.name())
else:
self.ptype.addOpen(openedType)
def visitManagesStmt(self, mgs):
pdecl = mgs.manager.decl
ptype, pname = pdecl.type, pdecl.shortname
@ -1298,330 +1158,3 @@ class CheckTypes(TcheckVisitor):
loc,
"ctor for protocol `%s', which is not managed by protocol `%s'",
mname[:-len('constructor')], pname)
##-----------------------------------------------------------------------------
class Process:
def __init__(self):
self.actors = set() # set(Actor)
self.edges = { } # Actor -> [ SpawnsEdge ]
self.spawn = set() # set(Actor)
def edge(self, spawner, spawn):
if spawner not in self.edges: self.edges[spawner] = [ ]
self.edges[spawner].append(SpawnsEdge(spawner, spawn))
self.spawn.add(spawn)
def iteredges(self):
for edgelist in self.edges.itervalues():
for edge in edgelist:
yield edge
def merge(self, o):
'Merge the Process |o| into this Process'
if self == o:
return
for actor in o.actors:
ProcessGraph.actorToProcess[actor] = self
self.actors.update(o.actors)
self.edges.update(o.edges)
self.spawn.update(o.spawn)
ProcessGraph.processes.remove(o)
def spawns(self, actor):
return actor in self.spawn
def __cmp__(self, o): return cmp(self.actors, o.actors)
def __eq__(self, o): return self.actors == o.actors
def __hash__(self): return hash(id(self))
def __repr__(self):
return reduce(lambda a, x: str(a) + str(x) +'|', self.actors, '|')
def __str__(self): return repr(self)
class Actor:
def __init__(self, ptype, side):
self.ptype = ptype
self.side = side
def asType(self):
return ActorType(self.ptype)
def other(self):
return Actor(self.ptype, _otherside(self.side))
def __cmp__(self, o):
return cmp(self.ptype, o.ptype) or cmp(self.side, o.side)
def __eq__(self, o):
return self.ptype == o.ptype and self.side == o.side
def __hash__(self): return hash(repr(self))
def __repr__(self): return '%s%s'% (self.ptype.name(), self.side.title())
def __str__(self): return repr(self)
class SpawnsEdge:
def __init__(self, spawner, spawn):
self.spawner = spawner # Actor
self.spawn = spawn # Actor
def __repr__(self):
return '(%r)--spawns-->(%r)'% (self.spawner, self.spawn)
def __str__(self): return repr(self)
class BridgeEdge:
def __init__(self, bridgeProto, parent, child):
self.bridgeProto = bridgeProto # ProtocolType
self.parent = parent # Actor
self.child = child # Actor
def __repr__(self):
return '(%r)--%s bridge-->(%r)'% (
self.parent, self.bridgeProto.name(), self.child)
def __str__(self): return repr(self)
class OpensEdge:
def __init__(self, opener, openedProto):
self.opener = opener # Actor
self.openedProto = openedProto # ProtocolType
def __repr__(self):
return '(%r)--opens-->(%s)'% (self.opener, self.openedProto.name())
def __str__(self): return repr(self)
# "singleton" class with state that persists across type checking of
# all protocols
class ProcessGraph:
processes = set() # set(Process)
bridges = { } # ProtocolType -> [ BridgeEdge ]
opens = { } # ProtocolType -> [ OpensEdge ]
actorToProcess = { } # Actor -> Process
visitedSpawns = set() # set(ActorType)
visitedBridges = set() # set(ActorType)
@classmethod
def findProcess(cls, actor):
return cls.actorToProcess.get(actor, None)
@classmethod
def getProcess(cls, actor):
if actor not in cls.actorToProcess:
p = Process()
p.actors.add(actor)
cls.processes.add(p)
cls.actorToProcess[actor] = p
return cls.actorToProcess[actor]
@classmethod
def bridgesOf(cls, bridgeP):
return cls.bridges.get(bridgeP, [])
@classmethod
def bridgeEndpointsOf(cls, ptype, side):
actor = Actor(ptype, side)
endpoints = []
for b in cls.iterbridges():
if b.parent == actor:
endpoints.append(Actor(b.bridgeProto, 'parent'))
if b.child == actor:
endpoints.append(Actor(b.bridgeProto, 'child'))
return endpoints
@classmethod
def iterbridges(cls):
for edges in cls.bridges.itervalues():
for bridge in edges:
yield bridge
@classmethod
def opensOf(cls, openedP):
return cls.opens.get(openedP, [])
@classmethod
def opensEndpointsOf(cls, ptype, side):
actor = Actor(ptype, side)
endpoints = []
for o in cls.iteropens():
if actor == o.opener:
endpoints.append(Actor(o.openedProto, o.opener.side))
elif actor == o.opener.other():
endpoints.append(Actor(o.openedProto, o.opener.other().side))
return endpoints
@classmethod
def iteropens(cls):
for edges in cls.opens.itervalues():
for opens in edges:
yield opens
@classmethod
def spawn(cls, spawner, remoteSpawn):
localSpawn = remoteSpawn.other()
spawnerProcess = ProcessGraph.getProcess(spawner)
spawnerProcess.merge(ProcessGraph.getProcess(localSpawn))
spawnerProcess.edge(spawner, remoteSpawn)
@classmethod
def bridge(cls, parent, child, bridgeP):
bridgeParent = Actor(bridgeP, 'parent')
parentProcess = ProcessGraph.getProcess(parent)
parentProcess.merge(ProcessGraph.getProcess(bridgeParent))
bridgeChild = Actor(bridgeP, 'child')
childProcess = ProcessGraph.getProcess(child)
childProcess.merge(ProcessGraph.getProcess(bridgeChild))
if bridgeP not in cls.bridges:
cls.bridges[bridgeP] = [ ]
cls.bridges[bridgeP].append(BridgeEdge(bridgeP, parent, child))
@classmethod
def open(cls, opener, opened, openedP):
remoteOpener, remoteOpened, = opener.other(), opened.other()
openerProcess = ProcessGraph.getProcess(opener)
openerProcess.merge(ProcessGraph.getProcess(opened))
remoteOpenerProcess = ProcessGraph.getProcess(remoteOpener)
remoteOpenerProcess.merge(ProcessGraph.getProcess(remoteOpened))
if openedP not in cls.opens:
cls.opens[openedP] = [ ]
cls.opens[openedP].append(OpensEdge(opener, openedP))
class BuildProcessGraph(TcheckVisitor):
class findSpawns(TcheckVisitor):
def __init__(self, errors):
TcheckVisitor.__init__(self, None, errors)
def visitTranslationUnit(self, tu):
TcheckVisitor.visitTranslationUnit(self, tu)
def visitInclude(self, inc):
if inc.tu.protocol:
inc.tu.protocol.accept(self)
def visitProtocol(self, p):
ptype = p.decl.type
# non-top-level protocols don't add any information
if not ptype.isToplevel() or ptype in ProcessGraph.visitedSpawns:
return
ProcessGraph.visitedSpawns.add(ptype)
self.visiting = ptype
ProcessGraph.getProcess(Actor(ptype, 'parent'))
ProcessGraph.getProcess(Actor(ptype, 'child'))
return TcheckVisitor.visitProtocol(self, p)
def visitSpawnsStmt(self, spawns):
# The picture here is:
# [ spawner | localSpawn | ??? ] (process 1)
# |
# |
# [ remoteSpawn | ???] (process 2)
#
# A spawns stmt tells us that |spawner| and |localSpawn|
# are in the same process.
spawner = Actor(self.visiting, spawns.side)
remoteSpawn = Actor(spawns.proto.type, spawns.spawnedAs)
ProcessGraph.spawn(spawner, remoteSpawn)
def __init__(self, errors):
TcheckVisitor.__init__(self, None, errors)
self.visiting = None # ActorType
self.visited = set() # set(ActorType)
def visitTranslationUnit(self, tu):
tu.accept(self.findSpawns(self.errors))
TcheckVisitor.visitTranslationUnit(self, tu)
def visitInclude(self, inc):
if inc.tu.protocol:
inc.tu.protocol.accept(self)
def visitProtocol(self, p):
ptype = p.decl.type
# non-top-level protocols don't add any information
if not ptype.isToplevel() or ptype in ProcessGraph.visitedBridges:
return
ProcessGraph.visitedBridges.add(ptype)
self.visiting = ptype
return TcheckVisitor.visitProtocol(self, p)
def visitBridgesStmt(self, bridges):
bridgeProto = self.visiting
parentSideProto = bridges.parentSide.type
childSideProto = bridges.childSide.type
# the picture here is:
# (process 1|
# [ parentSide(Parent|Child) | childSide(Parent|Child) | ... ]
# | |
# | (process 2| |
# [ parentSide(Child|Parent) | bridgeParent ] |
# | |
# | | (process 3|
# [ bridgeChild | childSide(Child|Parent) ]
#
# First we have to figure out which parentSide/childSide
# actors live in the same process. The possibilities are {
# parent, child } x { parent, child }. (Multiple matches
# aren't allowed yet.) Then we make ProcessGraph aware of the
# new bridge.
parentSideActor, childSideActor = None, None
pc = ( 'parent', 'child' )
for parentSide, childSide in cartesian_product(pc, pc):
pactor = Actor(parentSideProto, parentSide)
pproc = ProcessGraph.findProcess(pactor)
cactor = Actor(childSideProto, childSide)
cproc = ProcessGraph.findProcess(cactor)
assert pproc and cproc
if pproc == cproc:
if parentSideActor is not None:
if parentSideProto != childSideProto:
self.error(bridges.loc,
"ambiguous bridge `%s' between `%s' and `%s'",
bridgeProto.name(),
parentSideProto.name(),
childSideProto.name())
else:
parentSideActor, childSideActor = pactor.other(), cactor.other()
if parentSideActor is None:
self.error(bridges.loc,
"`%s' and `%s' cannot be bridged by `%s' ",
parentSideProto.name(), childSideProto.name(),
bridgeProto.name())
ProcessGraph.bridge(parentSideActor, childSideActor, bridgeProto)
def visitOpensStmt(self, opens):
openedP = opens.proto.type
opener = Actor(self.visiting, opens.side)
opened = Actor(openedP, opens.side)
# The picture here is:
# [ opener | opened ] (process 1)
# | |
# | |
# [ remoteOpener | remoteOpened ] (process 2)
#
# An opens stmt tells us that the pairs |opener|/|opened|
# and |remoteOpener|/|remoteOpened| are each in the same
# process.
ProcessGraph.open(opener, opened, openedP)
class CheckProcessGraph(TcheckVisitor):
def __init__(self, errors):
TcheckVisitor.__init__(self, None, errors)
# TODO: verify spawns-per-process assumption and check that graph
# is a dag
def visitTranslationUnit(self, tu):
if 0:
print 'Processes'
for process in ProcessGraph.processes:
print ' ', process
for edge in process.iteredges():
print ' ', edge
print 'Bridges'
for bridgeList in ProcessGraph.bridges.itervalues():
for bridge in bridgeList:
print ' ', bridge
print 'Opens'
for opensList in ProcessGraph.opens.itervalues():
for opens in opensList:
print ' ', opens

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

@ -6,7 +6,6 @@ IPDLTESTSRCS = $(filter Test%,$(CPPSRCS))
IPDLTESTS = $(IPDLTESTSRCS:.cpp=)
EXTRA_PROTOCOLS = \
TestBridgeSub \
TestEndpointBridgeSub \
$(NULL)

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

@ -1,28 +0,0 @@
include protocol PTestBridgeMainSub;
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeMain {
child spawns PTestBridgeSub;
child opens PTestBridgeMainSub;
child:
async Start();
parent:
async __delete__();
/*
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
*/
};
} // namespace mozilla
} // namespace _ipdltest

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

@ -1,35 +0,0 @@
include protocol PTestBridgeMain;
include protocol PTestBridgeSub;
namespace mozilla {
namespace _ipdltest {
// (Bridge protocols can have different semantics than the endpoints
// they bridge)
intr protocol PTestBridgeMainSub {
bridges PTestBridgeMain, PTestBridgeSub;
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
/*
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
*/
};
} // namespace mozilla
} // namespace _ipdltest

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

@ -1,27 +0,0 @@
include protocol PTestBridgeMainSub;
namespace mozilla {
namespace _ipdltest {
protocol PTestBridgeSub {
child:
async Ping();
parent:
async BridgeEm();
async __delete__();
/*
state START:
send Ping goto BRIDGEEM;
state BRIDGEEM:
recv BridgeEm goto DEAD;
state DEAD:
recv __delete__;
*/
};
} // namespace mozilla
} // namespace _ipdltest

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

@ -9,7 +9,6 @@ namespace _ipdltest {
protocol PTestEndpointBridgeMain {
child spawns PTestEndpointBridgeSub;
child:
async Start();

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

@ -1,27 +0,0 @@
include protocol PTestOpensOpened;
namespace mozilla {
namespace _ipdltest {
protocol PTestOpens {
// This channel is opened and parked on a non-main thread
child opens PTestOpensOpened;
child:
async Start();
parent:
async __delete__();
/*
state START:
send Start goto DEAD;
state DEAD:
recv __delete__;
*/
};
} // namespace mozilla
} // namespace _ipdltest

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

@ -1,30 +0,0 @@
namespace mozilla {
namespace _ipdltest2 {
// (Opens protocols can have different semantics than the endpoints
// that opened them)
intr protocol PTestOpensOpened {
child:
async Hi();
intr HiRpc();
parent:
async Hello();
sync HelloSync();
intr HelloRpc();
async __delete__();
/*
state START: recv Hello goto HI;
state HI: send Hi goto HELLO_SYNC;
state HELLO_SYNC: recv HelloSync goto HELLO_RPC;
state HELLO_RPC: answer HelloRpc goto HI_RPC;
state HI_RPC: call HiRpc goto DEAD;
state DEAD:
recv __delete__;
*/
};
} // namespace mozilla
} // namespace _ipdltest2

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

@ -1,233 +0,0 @@
#include "TestBridgeMain.h"
#include "base/task.h"
#include "IPDLUnitTests.h" // fail etc.
#include "IPDLUnitTestSubprocess.h"
#include "nsAutoPtr.h"
using namespace std;
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// main process
void
TestBridgeMainParent::Main()
{
if (!SendStart())
fail("sending Start");
}
PTestBridgeMainSubParent*
TestBridgeMainParent::AllocPTestBridgeMainSubParent(Transport* transport,
ProcessId otherPid)
{
nsAutoPtr<TestBridgeMainSubParent> a(new TestBridgeMainSubParent(transport));
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ParentSide)) {
return nullptr;
}
return a.forget();
}
void
TestBridgeMainParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
mozilla::ipc::IPCResult
TestBridgeMainSubParent::RecvHello()
{
if (!SendHi()) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
TestBridgeMainSubParent::RecvHelloSync()
{
return IPC_OK();
}
mozilla::ipc::IPCResult
TestBridgeMainSubParent::AnswerHelloRpc()
{
if (!CallHiRpc()) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
void
TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeMainSubParent>(this)));
}
//-----------------------------------------------------------------------------
// sub process --- child of main
TestBridgeMainChild* gBridgeMainChild;
TestBridgeMainChild::TestBridgeMainChild()
: mSubprocess(nullptr)
{
gBridgeMainChild = this;
}
mozilla::ipc::IPCResult
TestBridgeMainChild::RecvStart()
{
vector<string> subsubArgs;
subsubArgs.push_back("TestBridgeSub");
mSubprocess = new IPDLUnitTestSubprocess();
if (!mSubprocess->SyncLaunch(subsubArgs))
fail("problem launching subprocess");
IPC::Channel* transport = mSubprocess->GetChannel();
if (!transport)
fail("no transport");
TestBridgeSubParent* bsp = new TestBridgeSubParent();
bsp->Open(transport, base::GetProcId(mSubprocess->GetChildProcessHandle()));
bsp->Main();
return IPC_OK();
}
void
TestBridgeMainChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
// NB: this is kosher because QuitChild() joins with the IO thread
XRE_GetIOMessageLoop()->PostTask(
do_AddRef(new DeleteTask<IPDLUnitTestSubprocess>(mSubprocess)));
QuitChild();
}
void
TestBridgeSubParent::Main()
{
if (!SendPing())
fail("sending Ping");
}
mozilla::ipc::IPCResult
TestBridgeSubParent::RecvBridgeEm()
{
if (NS_FAILED(PTestBridgeMainSub::Bridge(gBridgeMainChild, this)))
fail("bridging Main and Sub");
return IPC_OK();
}
void
TestBridgeSubParent::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeMainChild->Close();
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeSubParent>(this)));
}
//-----------------------------------------------------------------------------
// subsub process --- child of sub
static TestBridgeSubChild* gBridgeSubChild;
TestBridgeSubChild::TestBridgeSubChild()
{
gBridgeSubChild = this;
}
mozilla::ipc::IPCResult
TestBridgeSubChild::RecvPing()
{
if (!SendBridgeEm())
fail("sending BridgeEm");
return IPC_OK();
}
PTestBridgeMainSubChild*
TestBridgeSubChild::AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherPid)
{
nsAutoPtr<TestBridgeMainSubChild> a(new TestBridgeMainSubChild(transport));
if (!a->Open(transport, otherPid, XRE_GetIOMessageLoop(), ipc::ChildSide)) {
return nullptr;
}
if (!a->SendHello())
fail("sending Hello");
return a.forget();
}
void
TestBridgeSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
mozilla::ipc::IPCResult
TestBridgeMainSubChild::RecvHi()
{
if (!SendHelloSync())
fail("sending HelloSync");
if (!CallHelloRpc())
fail("calling HelloRpc");
if (!mGotHi)
fail("didn't answer HiRpc");
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestBridgeMainSubChild::Close));
return IPC_OK();
}
mozilla::ipc::IPCResult
TestBridgeMainSubChild::AnswerHiRpc()
{
mGotHi = true; // d00d
return IPC_OK();
}
void
TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why)
{
if (NormalShutdown != why)
fail("unexpected destruction!");
gBridgeSubChild->Close();
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
MessageLoop::current()->PostTask(
do_AddRef(new DeleteTask<TestBridgeMainSubChild>(this)));
}
} // namespace mozilla
} // namespace _ipdltest

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

@ -1,149 +0,0 @@
#ifndef mozilla__ipdltest_TestBridgeMain_h
#define mozilla__ipdltest_TestBridgeMain_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestBridgeMainParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainChild.h"
#include "mozilla/_ipdltest/PTestBridgeSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeSubChild.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubParent.h"
#include "mozilla/_ipdltest/PTestBridgeMainSubChild.h"
namespace mozilla {
namespace _ipdltest {
//-----------------------------------------------------------------------------
// "Main" process
//
class TestBridgeMainParent :
public PTestBridgeMainParent
{
public:
TestBridgeMainParent() {}
virtual ~TestBridgeMainParent() {}
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual PTestBridgeMainSubParent*
AllocPTestBridgeMainSubParent(Transport* transport,
ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestBridgeMainSubParent :
public PTestBridgeMainSubParent
{
public:
explicit TestBridgeMainSubParent(Transport* aTransport)
: mTransport(aTransport)
{}
virtual ~TestBridgeMainSubParent() {}
protected:
virtual mozilla::ipc::IPCResult RecvHello() override;
virtual mozilla::ipc::IPCResult RecvHelloSync() override;
virtual mozilla::ipc::IPCResult AnswerHelloRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
Transport* mTransport;
};
//-----------------------------------------------------------------------------
// "Sub" process --- child of "main"
//
class TestBridgeSubParent;
class TestBridgeMainChild :
public PTestBridgeMainChild
{
public:
TestBridgeMainChild();
virtual ~TestBridgeMainChild() {}
protected:
virtual mozilla::ipc::IPCResult RecvStart() override;
virtual PTestBridgeMainSubChild*
AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherProcess) override
{
// This shouldn't be called. It's just a byproduct of testing that
// the right code is generated for a bridged protocol that's also
// opened, but we only test bridging here.
MOZ_CRASH();
}
virtual void ActorDestroy(ActorDestroyReason why) override;
IPDLUnitTestSubprocess* mSubprocess;
};
class TestBridgeSubParent :
public PTestBridgeSubParent
{
public:
TestBridgeSubParent() {}
virtual ~TestBridgeSubParent() {}
void Main();
protected:
virtual mozilla::ipc::IPCResult RecvBridgeEm() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
//-----------------------------------------------------------------------------
// "Subsub" process --- child of "sub"
//
class TestBridgeSubChild :
public PTestBridgeSubChild
{
public:
TestBridgeSubChild();
virtual ~TestBridgeSubChild() {}
protected:
virtual mozilla::ipc::IPCResult RecvPing() override;
virtual PTestBridgeMainSubChild*
AllocPTestBridgeMainSubChild(Transport* transport,
ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
class TestBridgeMainSubChild :
public PTestBridgeMainSubChild
{
public:
explicit TestBridgeMainSubChild(Transport* aTransport)
: mGotHi(false)
, mTransport(aTransport)
{}
virtual ~TestBridgeMainSubChild() {}
protected:
virtual mozilla::ipc::IPCResult RecvHi() override;
virtual mozilla::ipc::IPCResult AnswerHiRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
bool mGotHi;
Transport* mTransport;
};
} // namespace _ipdltest
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestBridgeMain_h

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

@ -1,257 +0,0 @@
#include "base/task.h"
#include "base/thread.h"
#include "TestOpens.h"
#include "IPDLUnitTests.h" // fail etc.
using namespace mozilla::ipc;
using base::ProcessHandle;
using base::Thread;
namespace mozilla {
// NB: this is generally bad style, but I am lazy.
using namespace _ipdltest;
using namespace _ipdltest2;
static MessageLoop* gMainThread;
static void
AssertNotMainThread()
{
if (!gMainThread)
fail("gMainThread is not initialized");
if (MessageLoop::current() == gMainThread)
fail("unexpectedly called on the main thread");
}
//-----------------------------------------------------------------------------
// parent
// Thread on which TestOpensOpenedParent runs
static Thread* gParentThread;
void
TestOpensParent::Main()
{
if (!SendStart())
fail("sending Start");
}
static void
OpenParent(TestOpensOpenedParent* aParent,
Transport* aTransport, base::ProcessId aOtherPid)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aParent->Open(aTransport, aOtherPid,
XRE_GetIOMessageLoop(), ipc::ParentSide))
fail("opening Parent");
}
PTestOpensOpenedParent*
TestOpensParent::AllocPTestOpensOpenedParent(Transport* transport,
ProcessId otherPid)
{
gMainThread = MessageLoop::current();
gParentThread = new Thread("ParentThread");
if (!gParentThread->Start())
fail("starting parent thread");
TestOpensOpenedParent* a = new TestOpensOpenedParent(transport);
gParentThread->message_loop()->PostTask(
NewRunnableFunction(OpenParent, a, transport, otherPid));
return a;
}
void
TestOpensParent::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gParentThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
passed("ok");
QuitParent();
}
mozilla::ipc::IPCResult
TestOpensOpenedParent::RecvHello()
{
AssertNotMainThread();
if (!SendHi()) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
TestOpensOpenedParent::RecvHelloSync()
{
AssertNotMainThread();
return IPC_OK();
}
mozilla::ipc::IPCResult
TestOpensOpenedParent::AnswerHelloRpc()
{
AssertNotMainThread();
if (!CallHiRpc()) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
static void
ShutdownTestOpensOpenedParent(TestOpensOpenedParent* parent,
Transport* transport)
{
delete parent;
}
void
TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why)
fail("unexpected destruction!");
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up.
gParentThread->message_loop()->PostTask(
NewRunnableFunction(ShutdownTestOpensOpenedParent,
this, mTransport));
}
//-----------------------------------------------------------------------------
// child
static TestOpensChild* gOpensChild;
// Thread on which TestOpensOpenedChild runs
static Thread* gChildThread;
TestOpensChild::TestOpensChild()
{
gOpensChild = this;
}
mozilla::ipc::IPCResult
TestOpensChild::RecvStart()
{
if (!PTestOpensOpened::Open(this))
fail("opening PTestOpensOpened");
return IPC_OK();
}
static void
OpenChild(TestOpensOpenedChild* aChild,
Transport* aTransport, base::ProcessId aOtherPid)
{
AssertNotMainThread();
// Open the actor on the off-main thread to park it there.
// Messages will be delivered to this thread's message loop
// instead of the main thread's.
if (!aChild->Open(aTransport, aOtherPid,
XRE_GetIOMessageLoop(), ipc::ChildSide))
fail("opening Child");
// Kick off the unit tests
if (!aChild->SendHello())
fail("sending Hello");
}
PTestOpensOpenedChild*
TestOpensChild::AllocPTestOpensOpenedChild(Transport* transport,
ProcessId otherPid)
{
gMainThread = MessageLoop::current();
gChildThread = new Thread("ChildThread");
if (!gChildThread->Start())
fail("starting child thread");
TestOpensOpenedChild* a = new TestOpensOpenedChild(transport);
gChildThread->message_loop()->PostTask(
NewRunnableFunction(OpenChild, a, transport, otherPid));
return a;
}
void
TestOpensChild::ActorDestroy(ActorDestroyReason why)
{
// Stops the thread and joins it
delete gChildThread;
if (NormalShutdown != why)
fail("unexpected destruction!");
QuitChild();
}
mozilla::ipc::IPCResult
TestOpensOpenedChild::RecvHi()
{
AssertNotMainThread();
if (!SendHelloSync())
fail("sending HelloSync");
if (!CallHelloRpc())
fail("calling HelloRpc");
if (!mGotHi)
fail("didn't answer HiRpc");
// Need to close the channel without message-processing frames on
// the C++ stack
MessageLoop::current()->PostTask(
NewNonOwningRunnableMethod(this, &TestOpensOpenedChild::Close));
return IPC_OK();
}
mozilla::ipc::IPCResult
TestOpensOpenedChild::AnswerHiRpc()
{
AssertNotMainThread();
mGotHi = true; // d00d
return IPC_OK();
}
static void
ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child,
Transport* transport)
{
delete child;
// Kick off main-thread shutdown.
gMainThread->PostTask(
NewNonOwningRunnableMethod(gOpensChild, &TestOpensChild::Close));
}
void
TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
{
AssertNotMainThread();
if (NormalShutdown != why)
fail("unexpected destruction!");
// ActorDestroy() is just a callback from IPDL-generated code,
// which needs the top-level actor (this) to stay alive a little
// longer so other things can be cleaned up. Defer shutdown to
// let cleanup finish.
gChildThread->message_loop()->PostTask(
NewRunnableFunction(ShutdownTestOpensOpenedChild,
this, mTransport));
}
} // namespace mozilla

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

@ -1,107 +0,0 @@
#ifndef mozilla__ipdltest_TestOpens_h
#define mozilla__ipdltest_TestOpens_h 1
#include "mozilla/_ipdltest/IPDLUnitTests.h"
#include "mozilla/_ipdltest/PTestOpensParent.h"
#include "mozilla/_ipdltest/PTestOpensChild.h"
#include "mozilla/_ipdltest2/PTestOpensOpenedParent.h"
#include "mozilla/_ipdltest2/PTestOpensOpenedChild.h"
namespace mozilla {
// parent process
namespace _ipdltest {
class TestOpensParent : public PTestOpensParent
{
public:
TestOpensParent() {}
virtual ~TestOpensParent() {}
static bool RunTestInProcesses() { return true; }
static bool RunTestInThreads() { return false; }
void Main();
protected:
virtual PTestOpensOpenedParent*
AllocPTestOpensOpenedParent(Transport* transport, ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
} // namespace _ipdltest
namespace _ipdltest2 {
class TestOpensOpenedParent : public PTestOpensOpenedParent
{
public:
explicit TestOpensOpenedParent(Transport* aTransport)
: mTransport(aTransport)
{}
virtual ~TestOpensOpenedParent() {}
protected:
virtual mozilla::ipc::IPCResult RecvHello() override;
virtual mozilla::ipc::IPCResult RecvHelloSync() override;
virtual mozilla::ipc::IPCResult AnswerHelloRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
Transport* mTransport;
};
} // namespace _ipdltest2
// child process
namespace _ipdltest {
class TestOpensChild : public PTestOpensChild
{
public:
TestOpensChild();
virtual ~TestOpensChild() {}
protected:
virtual mozilla::ipc::IPCResult RecvStart() override;
virtual PTestOpensOpenedChild*
AllocPTestOpensOpenedChild(Transport* transport, ProcessId otherProcess) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
};
} // namespace _ipdltest
namespace _ipdltest2 {
class TestOpensOpenedChild : public PTestOpensOpenedChild
{
public:
explicit TestOpensOpenedChild(Transport* aTransport)
: mGotHi(false)
, mTransport(aTransport)
{}
virtual ~TestOpensOpenedChild() {}
protected:
virtual mozilla::ipc::IPCResult RecvHi() override;
virtual mozilla::ipc::IPCResult AnswerHiRpc() override;
virtual void ActorDestroy(ActorDestroyReason why) override;
bool mGotHi;
Transport* mTransport;
};
} // namespace _ipdltest2
} // namespace mozilla
#endif // ifndef mozilla__ipdltest_TestOpens_h

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

@ -16,7 +16,6 @@ EXPORTS.mozilla._ipdltest += [
SOURCES += [
'TestActorPunning.cpp',
'TestBadActor.cpp',
'TestBridgeMain.cpp',
'TestCancel.cpp',
'TestCrashCleanup.cpp',
'TestDataStructures.cpp',
@ -35,7 +34,6 @@ SOURCES += [
'TestManyChildAllocs.cpp',
'TestMultiMgrs.cpp',
'TestNestedLoops.cpp',
'TestOpens.cpp',
'TestRaceDeadlock.cpp',
'TestRaceDeferral.cpp',
'TestRacyInterruptReplies.cpp',
@ -66,9 +64,6 @@ IPDL_SOURCES += [
'PTestActorPunningSub.ipdl',
'PTestBadActor.ipdl',
'PTestBadActorSub.ipdl',
'PTestBridgeMain.ipdl',
'PTestBridgeMainSub.ipdl',
'PTestBridgeSub.ipdl',
'PTestCancel.ipdl',
'PTestCrashCleanup.ipdl',
'PTestDataStructures.ipdl',
@ -105,8 +100,6 @@ IPDL_SOURCES += [
'PTestMultiMgrsLeft.ipdl',
'PTestMultiMgrsRight.ipdl',
'PTestNestedLoops.ipdl',
'PTestOpens.ipdl',
'PTestOpensOpened.ipdl',
'PTestPriority.ipdl',
'PTestRaceDeadlock.ipdl',
'PTestRaceDeferral.ipdl',

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

@ -1,9 +0,0 @@
include protocol content;
sync protocol compositor {
bridges compositor, content;
child:
async __delete__();
};

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

@ -1,15 +0,0 @@
include protocol compositor;
include protocol jetpack;
include protocol media;
include protocol plugin;
sync protocol content {
parent spawns compositor as parent;
parent spawns jetpack;
child spawns plugin;
child opens media;
child:
async __delete__();
};

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

@ -1,10 +0,0 @@
include protocol content;
include protocol jetpack;
intr protocol jetpackContent {
bridges jetpack, content;
child:
async __delete__();
};

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

@ -26,7 +26,7 @@ set_config('MOZ_SYSTEM_FFI', depends_if(system_ffi)(lambda _: True))
add_old_configure_assignment('MOZ_SYSTEM_FFI', depends_if(system_ffi)(lambda _: True))
# Target selection, based on ffi/configure.ac.
@depends_when(target, when=building_ffi)
@depends(target, when=building_ffi)
def ffi_target(target):
if target.cpu not in ('x86', 'x86_64', 'arm', 'aarch64'):
die('Building libffi from the tree is not supported on this platform. '

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

@ -31,11 +31,11 @@
#ifndef JIT_SPEW_DIR
# if defined(_WIN32)
# define JIT_SPEW_DIR ""
# define JIT_SPEW_DIR "."
# elif defined(__ANDROID__)
# define JIT_SPEW_DIR "/data/local/tmp/"
# define JIT_SPEW_DIR "/data/local/tmp"
# else
# define JIT_SPEW_DIR "/tmp/"
# define JIT_SPEW_DIR "/tmp"
# endif
#endif

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

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<title>Test dynamically-appended animation in a subtree that dynamically became 'display:none'</title>
</head>
<body style="background-color: lime;">
<div id="target" style="display: none;">
<svg>
<rect width="100" height="100" fill="brown" id="rect">
</rect>
</svg>
</div>
<script>
document.addEventListener('MozReftestInvalidate', function() {
var svg = document.getElementsByTagName("svg")[0];
svg.pauseAnimations(); // pause svg animation.
var target = document.getElementById("target");
var rect = document.getElementById("rect");
var animate = document.createElementNS('http://www.w3.org/2000/svg',
'animate');
animate.setAttribute('attributeName', 'fill');
animate.setAttribute('from', 'blue');
animate.setAttribute('to', 'red');
animate.setAttribute('dur', '100s');
rect.appendChild(animate);
requestAnimationFrame(function(time) {
target.style.display = 'block';
requestAnimationFrame(function(time) {
document.documentElement.removeAttribute("class");
});
});
});
</script>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<title>Test animation in a subtree that dynamically becames 'display:none'</title>
</head>
<body style="background-color: lime;">
<div id="target">
<svg>
<rect width="100%" height="100%" fill="blue">
<animate attributeName="fill" from="brown" to="red" dur="100s"/>
</rect>
</svg>
</div>
<script>
document.addEventListener('MozReftestInvalidate', function() {
var target = document.getElementById("target");
target.style.display = "none";
requestAnimationFrame(function(time) {
document.documentElement.removeAttribute("class");
});
});
</script>
</body>
</html>

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

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<title>Test dynamically-appended animation on an element that dynamically becomes 'display:none'</title>
</head>
<body style="background-color: lime;">
<div>
<svg>
<rect width="100" height="100" fill="brown" id="rect">
</rect>
</svg>
</div>
<script>
document.addEventListener('MozReftestInvalidate', function() {
var rect = document.getElementById("rect");
var animate = document.createElementNS('http://www.w3.org/2000/svg',
'animate');
animate.setAttribute('attributeName', 'fill');
animate.setAttribute('from', 'blue');
animate.setAttribute('to', 'red');
animate.setAttribute('dur', '100s');
rect.appendChild(animate);
requestAnimationFrame(function(time) {
rect.style.display = 'none';
requestAnimationFrame(function(time) {
document.documentElement.removeAttribute("class");
});
});
});
</script>
</body>
</html>

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

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
<title>Test animation on an element that dynamically becomes 'display:none'</title>
</head>
<body style="background-color: lime;">
<div>
<svg>
<rect width="100%" height="100%" fill="blue" id="rect">
<animate attributeName="fill" from="brown" to="red" dur="100s"/>
</rect>
</svg>
</div>
<script>
document.addEventListener('MozReftestInvalidate', function() {
var rect = document.getElementById("rect");
rect.style.display = "none";
requestAnimationFrame(function(time) {
document.documentElement.removeAttribute("class");
});
});
</script>
</body>
</html>

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

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Testcase reference file for animated pass condition(HTML)</title>
</head>
<body style="background-color: lime;">
<svg xmlns="http://www.w3.org/2000/svg">
<rect width="100" height="100" fill="blue"/>
</svg>

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

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head>
<title>Testcase reference file for generic pass condition(HTML)</title>
</head>
<body style="background-color: lime;">
</body>
</html>

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

@ -280,4 +280,10 @@ fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,2) == anim-gradient-attr-presence-0
== anim-display.svg lime.svg
== anim-display-in-g-element.svg lime.svg
# Test animation that change 'display' style value to 'none'
== anim-change-display-none-for-ancestor-elem.html lime.html
== anim-change-display-none-for-target-elem.html lime.html
== anim-change-display-none-for-dynamically-appended-elem.html lime.html
== anim-change-display-block-for-dynamically-appended-elem.html anim-standard-ref.html
pref(layout.css.clip-path-shapes.enabled,true) fuzzy(63,146) == anim-clipPath-viewBox.svg anim-clipPath-viewBox-ref.svg

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

@ -8,6 +8,9 @@
#include "PreloadedStyleSheet.h"
#include "mozilla/css/Loader.h"
#include "nsLayoutUtils.h"
namespace mozilla {
PreloadedStyleSheet::PreloadedStyleSheet(nsIURI* aURI,

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

@ -11,8 +11,14 @@
#include "mozilla/css/SheetParsingMode.h"
#include "mozilla/Result.h"
#include "mozilla/StyleBackendType.h"
#include "mozilla/StyleSheet.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIPreloadedStyleSheet.h"
class nsIURI;
namespace mozilla {
class PreloadedStyleSheet : public nsIPreloadedStyleSheet

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

@ -38,6 +38,7 @@
#include "nsCSSPseudoElements.h"
#include "mozilla/StyleSetHandle.h"
#include "mozilla/StyleSetHandleInlines.h"
#include "mozilla/RestyleManager.h"
#include "imgIRequest.h"
#include "nsLayoutUtils.h"
#include "nsCSSKeywords.h"

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

@ -14,6 +14,11 @@
#include "mozilla/dom/MediaListBinding.h"
#include "mozilla/StyleSheet.h"
#include "nsCSSParser.h"
#include "nsCSSRules.h"
#include "nsMediaFeatures.h"
#include "nsRuleNode.h"
using namespace mozilla;
template <class Numeric>
int32_t DoCompare(Numeric a, Numeric b)
@ -512,7 +517,7 @@ nsMediaList::~nsMediaList()
/* virtual */ JSObject*
nsMediaList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return MediaListBinding::Wrap(aCx, this, aGivenProto);
return dom::MediaListBinding::Wrap(aCx, this, aGivenProto);
}
void

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

@ -389,6 +389,20 @@ this.ExtensionData = class {
return result;
}
// Compute the difference between two sets of permissions, suitable
// for presenting to the user.
static comparePermissions(oldPermissions, newPermissions) {
// See bug 1331769: should we do something more complicated to
// compare host permissions?
// e.g., if we go from <all_urls> to a specific host or from
// a *.domain.com to specific-host.domain.com that's actually a
// drop in permissions but the simple test below will cause a prompt.
return {
hosts: newPermissions.hosts.filter(perm => !oldPermissions.hosts.includes(perm)),
permissions: newPermissions.permissions.filter(perm => !oldPermissions.permissions.includes(perm)),
};
}
// Reads the extension's |manifest.json| file, and stores its
// parsed contents in |this.manifest|.
readManifest() {

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

@ -7,6 +7,7 @@ description = "Testing code for libgkrust"
[features]
bindgen = ["gkrust-shared/bindgen"]
servo = ["gkrust-shared/servo"]
[dependencies]
mp4parse-gtest = { path = "../../../../dom/media/gtest" }

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

@ -5,7 +5,10 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
features = []
if CONFIG['MOZ_STYLO'] and CONFIG['MOZ_STYLO_BINDGEN']:
features += ['bindgen']
if CONFIG['MOZ_STYLO']:
features += ['servo']
if CONFIG['MOZ_STYLO_BINDGEN']:
features += ['bindgen']
RustLibrary('gkrust-gtest', features)

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

@ -7,6 +7,7 @@ description = "Rust code for libxul"
[features]
bindgen = ["gkrust-shared/bindgen"]
servo = ["gkrust-shared/servo"]
[dependencies]
gkrust-shared = { path = "shared" }

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

@ -5,7 +5,10 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
features = []
if CONFIG['MOZ_STYLO'] and CONFIG['MOZ_STYLO_BINDGEN']:
features += ['bindgen']
if CONFIG['MOZ_STYLO']:
features += ['servo']
if CONFIG['MOZ_STYLO_BINDGEN']:
features += ['bindgen']
RustLibrary('gkrust', features)

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

@ -6,7 +6,7 @@ license = "MPL-2.0"
description = "Shared Rust code for libxul"
[dependencies]
geckoservo = { path = "../../../../servo/ports/geckolib" }
geckoservo = { path = "../../../../servo/ports/geckolib", optional = true }
mp4parse_capi = { path = "../../../../media/libstagefright/binding/mp4parse_capi" }
nsstring = { path = "../../../../xpcom/rust/nsstring" }
rust_url_capi = { path = "../../../../netwerk/base/rust-url-capi" }
@ -14,6 +14,7 @@ rust_url_capi = { path = "../../../../netwerk/base/rust-url-capi" }
[features]
default = []
bindgen = ["geckoservo/bindgen"]
servo = ["geckoservo"]
[lib]
path = "lib.rs"

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

@ -2,6 +2,9 @@
// 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/.
#[cfg(feature="servo")]
extern crate geckoservo;
extern crate mp4parse_capi;
extern crate nsstring;
extern crate rust_url_capi;

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

@ -1380,15 +1380,7 @@ var AddonManagerInternal = {
let oldPerms = info.existingAddon.userPermissions || {hosts: [], permissions: []};
let newPerms = info.addon.userPermissions;
// See bug 1331769: should we do something more complicated to
// compare host permissions?
// e.g., if we go from <all_urls> to a specific host or from
// a *.domain.com to specific-host.domain.com that's actually a
// drop in permissions but the simple test below will cause a prompt.
let difference = {
hosts: newPerms.hosts.filter(perm => !oldPerms.hosts.includes(perm)),
permissions: newPerms.permissions.filter(perm => !oldPerms.permissions.includes(perm)),
};
let difference = Extension.comparePermissions(oldPerms, newPerms);
// If there are no new permissions, just go ahead with the update
if (difference.hosts.length == 0 && difference.permissions.length == 0) {
@ -2110,7 +2102,9 @@ var AddonManagerInternal = {
install.addon.userDisabled = false;
}
if (WEBEXT_PERMISSION_PROMPTS) {
let needsRestart = (install.addon.pendingOperations != AddonManager.PENDING_NONE);
if (WEBEXT_PERMISSION_PROMPTS && !needsRestart) {
let subject = {wrappedJSObject: {target: browser, addon: install.addon}};
Services.obs.notifyObservers(subject, "webextension-install-notify", null);
} else {
@ -2847,24 +2841,12 @@ var AddonManagerInternal = {
// "addon-install-confirmation" notification. If the application
// does not implement its own prompt, use the built-in xul dialog.
if (info.addon.userPermissions && WEBEXT_PERMISSION_PROMPTS) {
const observer = {
observe(subject, topic, data) {
if (topic == "webextension-permission-response"
&& subject.wrappedJSObject.info.addon == info.addon) {
let answer = JSON.parse(data);
Services.obs.removeObserver(observer, "webextension-permission-response");
if (answer) {
resolve();
} else {
reject();
}
}
let subject = {
wrappedJSObject: {
target: browser,
info: Object.assign({resolve, reject}, info),
}
};
Services.obs.addObserver(observer, "webextension-permission-response", false);
let subject = {wrappedJSObject: {target: browser, info}};
Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
} else if (requireConfirm) {
// The methods below all want to call the install() or cancel()

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

@ -21,6 +21,8 @@ Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/addons/AddonRepository.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils", "resource:///modules/E10SUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Extension",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ExtensionParent",
"resource://gre/modules/ExtensionParent.jsm");
@ -38,6 +40,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
XPCOMUtils.defineLazyModuleGetter(this, "Experiments",
"resource:///modules/experiments/Experiments.jsm");
XPCOMUtils.defineLazyPreferenceGetter(this, "WEBEXT_PERMISSION_PROMPTS",
"extensions.webextPermissionPrompts", false);
const PREF_DISCOVERURL = "extensions.webservice.discoverURL";
const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane";
const PREF_XPI_ENABLED = "xpinstall.enabled";
@ -694,6 +699,40 @@ var gEventManager = {
}
};
function attachUpdateHandler(install) {
if (!WEBEXT_PERMISSION_PROMPTS) {
return;
}
install.promptHandler = (info) => {
let oldPerms = info.existingAddon.userPermissions || {hosts: [], permissions: []};
let newPerms = info.addon.userPermissions;
let difference = Extension.comparePermissions(oldPerms, newPerms);
// If there are no new permissions, just proceed
if (difference.hosts.length == 0 && difference.permissions.length == 0) {
return Promise.resolve();
}
return new Promise((resolve, reject) => {
let subject = {
wrappedJSObject: {
target: getBrowserElement(),
info: {
type: "update",
addon: info.addon,
icon: info.addon.icon,
permissions: difference,
resolve,
reject,
},
},
};
Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
});
};
}
var gViewController = {
viewPort: null,
@ -1081,6 +1120,10 @@ var gViewController = {
pendingChecks--;
updateStatus();
},
onInstallCancelled() {
pendingChecks--;
updateStatus();
},
onInstallFailed() {
pendingChecks--;
updateStatus();
@ -1098,6 +1141,7 @@ var gViewController = {
onUpdateAvailable(aAddon, aInstall) {
gEventManager.delegateAddonEvent("onUpdateAvailable",
[aAddon, aInstall]);
attachUpdateHandler(aInstall);
if (AddonManager.shouldAutoUpdate(aAddon)) {
aInstall.addListener(updateInstallListener);
aInstall.install();
@ -1143,6 +1187,7 @@ var gViewController = {
onUpdateAvailable(aAddon, aInstall) {
gEventManager.delegateAddonEvent("onUpdateAvailable",
[aAddon, aInstall]);
attachUpdateHandler(aInstall);
if (AddonManager.shouldAutoUpdate(aAddon))
aInstall.install();
},

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

@ -2787,6 +2787,22 @@ NativeKey::MayBeSameCharMessage(const MSG& aCharMsg1,
(aCharMsg1.lParam & ~kScanCodeMask) == (aCharMsg2.lParam & ~kScanCodeMask);
}
bool
NativeKey::IsSamePhysicalKeyMessage(const MSG& aKeyOrCharMsg1,
const MSG& aKeyOrCharMsg2) const
{
if (NS_WARN_IF(aKeyOrCharMsg1.message < WM_KEYFIRST) ||
NS_WARN_IF(aKeyOrCharMsg1.message > WM_KEYLAST) ||
NS_WARN_IF(aKeyOrCharMsg2.message < WM_KEYFIRST) ||
NS_WARN_IF(aKeyOrCharMsg2.message > WM_KEYLAST)) {
return false;
}
return WinUtils::GetScanCode(aKeyOrCharMsg1.lParam) ==
WinUtils::GetScanCode(aKeyOrCharMsg2.lParam) &&
WinUtils::IsExtendedScanCode(aKeyOrCharMsg1.lParam) ==
WinUtils::IsExtendedScanCode(aKeyOrCharMsg2.lParam);
}
bool
NativeKey::GetFollowingCharMessage(MSG& aCharMsg)
{
@ -2836,7 +2852,7 @@ NativeKey::GetFollowingCharMessage(MSG& aCharMsg)
// On Metrofox, PeekMessage() sometimes returns WM_NULL even if we specify
// the message range. So, if it returns WM_NULL, we should retry to get
// the following char message it was found above.
for (uint32_t i = 0; i < 5; i++) {
for (uint32_t i = 0; i < 50; i++) {
MSG removedMsg, nextKeyMsgInAllWindows;
bool doCrash = false;
if (!WinUtils::PeekMessage(&removedMsg, mMsg.hwnd,
@ -2977,13 +2993,52 @@ NativeKey::GetFollowingCharMessage(MSG& aCharMsg)
MOZ_CRASH("We lost the following char message");
}
// Retry for the strange case.
// We're still not sure why ::PeekMessage() may return WM_NULL even with
// its first message and its last message are same message. However,
// at developing Metrofox, we met this case even with usual keyboard
// layouts. So, it might be possible in desktop application or it really
// occurs with some odd keyboard layouts which perhaps hook API.
if (removedMsg.message == WM_NULL) {
MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
("%p NativeKey::GetFollowingCharMessage(), WARNING, failed to "
"remove a char message, instead, removed WM_NULL message, ",
"removedMsg=%s",
this, ToString(removedMsg).get()));
// Check if there is the message which we're trying to remove.
MSG newNextKeyMsg;
if (!WinUtils::PeekMessage(&newNextKeyMsg, mMsg.hwnd,
WM_KEYFIRST, WM_KEYLAST,
PM_NOREMOVE | PM_NOYIELD)) {
// If there is no key message, we should mark this keydown as consumed
// because the key operation may have already been handled or canceled.
MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
("%p NativeKey::GetFollowingCharMessage(), WARNING, failed to "
"remove a char message because it's gone during removing it from "
"the queue, nextKeyMsg=%s",
this, ToString(nextKeyMsg).get()));
MOZ_ASSERT(!mCharMessageHasGone);
mFollowingCharMsgs.Clear();
mCharMessageHasGone = true;
return false;
}
if (!IsCharMessage(newNextKeyMsg)) {
// If next key message becomes a non-char message, we should mark this
// keydown as consumed because the key operation may have already been
// handled or canceled.
MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
("%p NativeKey::GetFollowingCharMessage(), WARNING, failed to "
"remove a char message because it's gone during removing it from "
"the queue, nextKeyMsg=%s, newNextKeyMsg=%s",
this, ToString(nextKeyMsg).get(), ToString(newNextKeyMsg).get()));
MOZ_ASSERT(!mCharMessageHasGone);
mFollowingCharMsgs.Clear();
mCharMessageHasGone = true;
return false;
}
MOZ_LOG(sNativeKeyLogger, LogLevel::Debug,
("%p NativeKey::GetFollowingCharMessage(), there is the message "
"which is being tried to be removed from the queue, trying again...",
this));
continue;
}
@ -2999,64 +3054,80 @@ NativeKey::GetFollowingCharMessage(MSG& aCharMsg)
return false;
}
// This is normal case.
if (MayBeSameCharMessage(removedMsg, nextKeyMsg)) {
aCharMsg = removedMsg;
MOZ_LOG(sNativeKeyLogger, LogLevel::Verbose,
("%p NativeKey::GetFollowingCharMessage(), succeeded to retrieve "
"next char message, aCharMsg=%s",
this, ToString(aCharMsg).get()));
return true;
}
// Even if removed message is different char message from the found char
// message, when the scan code is same, we can assume that the message
// is overwritten by somebody who hooks API. See bug 1336028 comment 0 for
// the possible scenarios.
if (IsCharMessage(removedMsg) &&
IsSamePhysicalKeyMessage(removedMsg, nextKeyMsg)) {
aCharMsg = removedMsg;
MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
("%p NativeKey::GetFollowingCharMessage(), WARNING, succeeded to "
"remove a char message, but the removed message was changed from "
"the found message except their scancode, aCharMsg=%s, "
"nextKeyMsg(the found message)=%s",
this, ToString(aCharMsg).get(), ToString(nextKeyMsg).get()));
return true;
}
// NOTE: Although, we don't know when this case occurs, the scan code value
// in lParam may be changed from 0 to something. The changed value
// is different from the scan code of handling keydown message.
if (!MayBeSameCharMessage(removedMsg, nextKeyMsg)) {
MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
("%p NativeKey::GetFollowingCharMessage(), FAILED, removed message "
"is really different from what we have already found, removedMsg=%s, "
"nextKeyMsg=%s",
this, ToString(removedMsg).get(), ToString(nextKeyMsg).get()));
MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
("%p NativeKey::GetFollowingCharMessage(), FAILED, removed message "
"is really different from what we have already found, removedMsg=%s, "
"nextKeyMsg=%s",
this, ToString(removedMsg).get(), ToString(nextKeyMsg).get()));
#ifdef MOZ_CRASHREPORTER
nsPrintfCString info("\nPeekMessage() removed unexpcted char message! "
"\nActive keyboard layout=0x%08X (%s), "
"\nHandling message: %s, InSendMessageEx()=%s, "
"\nFound message: %s, "
"\nRemoved message: %s, ",
KeyboardLayout::GetActiveLayout(),
KeyboardLayout::GetActiveLayoutName().get(),
ToString(mMsg).get(),
GetResultOfInSendMessageEx().get(),
ToString(nextKeyMsg).get(),
ToString(removedMsg).get());
nsPrintfCString info("\nPeekMessage() removed unexpcted char message! "
"\nActive keyboard layout=0x%08X (%s), "
"\nHandling message: %s, InSendMessageEx()=%s, "
"\nFound message: %s, "
"\nRemoved message: %s, ",
KeyboardLayout::GetActiveLayout(),
KeyboardLayout::GetActiveLayoutName().get(),
ToString(mMsg).get(),
GetResultOfInSendMessageEx().get(),
ToString(nextKeyMsg).get(),
ToString(removedMsg).get());
CrashReporter::AppendAppNotesToCrashReport(info);
// What's the next key message?
MSG nextKeyMsgAfter;
if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd,
WM_KEYFIRST, WM_KEYLAST,
PM_NOREMOVE | PM_NOYIELD)) {
nsPrintfCString info("\nNext key message after unexpected char message "
"removed: %s, ",
ToString(nextKeyMsgAfter).get());
CrashReporter::AppendAppNotesToCrashReport(info);
// What's the next key message?
MSG nextKeyMsgAfter;
if (WinUtils::PeekMessage(&nextKeyMsgAfter, mMsg.hwnd,
WM_KEYFIRST, WM_KEYLAST,
PM_NOREMOVE | PM_NOYIELD)) {
nsPrintfCString info("\nNext key message after unexpected char message "
"removed: %s, ",
ToString(nextKeyMsgAfter).get());
CrashReporter::AppendAppNotesToCrashReport(info);
} else {
CrashReporter::AppendAppNotesToCrashReport(
NS_LITERAL_CSTRING("\nThere is no key message after unexpected char "
"message removed, "));
}
// Another window has a key message?
MSG nextKeyMsgInAllWindows;
if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
WM_KEYFIRST, WM_KEYLAST,
PM_NOREMOVE | PM_NOYIELD)) {
nsPrintfCString info("\nNext key message in all windows: %s.",
ToString(nextKeyMsgInAllWindows).get());
CrashReporter::AppendAppNotesToCrashReport(info);
} else {
CrashReporter::AppendAppNotesToCrashReport(
NS_LITERAL_CSTRING("\nThere is no key message in any windows."));
}
#endif // #ifdef MOZ_CRASHREPORTER
MOZ_CRASH("PeekMessage() removed unexpected message");
} else {
CrashReporter::AppendAppNotesToCrashReport(
NS_LITERAL_CSTRING("\nThere is no key message after unexpected char "
"message removed, "));
}
aCharMsg = removedMsg;
MOZ_LOG(sNativeKeyLogger, LogLevel::Verbose,
("%p NativeKey::GetFollowingCharMessage(), succeeded to retrieve next "
"char message, aCharMsg=%s",
this, ToString(aCharMsg).get()));
return true;
// Another window has a key message?
if (WinUtils::PeekMessage(&nextKeyMsgInAllWindows, 0,
WM_KEYFIRST, WM_KEYLAST,
PM_NOREMOVE | PM_NOYIELD)) {
nsPrintfCString info("\nNext key message in all windows: %s.",
ToString(nextKeyMsgInAllWindows).get());
CrashReporter::AppendAppNotesToCrashReport(info);
} else {
CrashReporter::AppendAppNotesToCrashReport(
NS_LITERAL_CSTRING("\nThere is no key message in any windows."));
}
#endif // #ifdef MOZ_CRASHREPORTER
MOZ_CRASH("PeekMessage() removed unexpected message");
}
MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
("%p NativeKey::GetFollowingCharMessage(), FAILED, removed messages "

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

@ -513,6 +513,8 @@ private:
return (aMessage == WM_SYSCHAR || aMessage == WM_SYSDEADCHAR);
}
bool MayBeSameCharMessage(const MSG& aCharMsg1, const MSG& aCharMsg2) const;
bool IsSamePhysicalKeyMessage(const MSG& aKeyOrCharMsg1,
const MSG& aKeyOrCharMsg2) const;
bool IsFollowedByPrintableCharMessage() const;
bool IsFollowedByPrintableCharOrSysCharMessage() const;
bool IsFollowedByDeadCharMessage() const;