зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
88a3947938
|
@ -28,6 +28,7 @@ static const uint32_t ACTIVITY_STREAM_FLAGS =
|
|||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::ENABLE_INDEXED_DB |
|
||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGED_CHILD |
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT;
|
||||
|
||||
struct RedirEntry {
|
||||
|
@ -92,6 +93,7 @@ static const RedirEntry kRedirMap[] = {
|
|||
{ "newtab", "about:blank", ACTIVITY_STREAM_FLAGS },
|
||||
{ "welcome", "about:blank",
|
||||
nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_PRIVILEGED_CHILD |
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT },
|
||||
{ "library", "chrome://browser/content/aboutLibrary.xhtml",
|
||||
|
|
|
@ -9,23 +9,29 @@
|
|||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/E10SUtils.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "AboutNewTab",
|
||||
"resource:///modules/AboutNewTab.jsm");
|
||||
|
||||
const TOPIC_APP_QUIT = "quit-application-granted";
|
||||
const TOPIC_LOCALES_CHANGE = "intl:app-locales-changed";
|
||||
const TOPIC_CONTENT_DOCUMENT_INTERACTIVE = "content-document-interactive";
|
||||
|
||||
// Automated tests ensure packaged locales are in this list. Copied output of:
|
||||
// https://github.com/mozilla/activity-stream/blob/master/bin/render-activity-stream-html.js
|
||||
const ACTIVITY_STREAM_LOCALES = "en-US ach an ar ast az be bg bn-BD bn-IN br bs ca cak crh cs cy da de dsb el en-CA en-GB eo es-AR es-CL es-ES es-MX et eu fa ff fi fr fy-NL ga-IE gd gl gn gu-IN he hi-IN hr hsb hu hy-AM ia id it ja ja-JP-mac ka kab kk km kn ko lij lo lt ltg lv mai mk ml mr ms my nb-NO ne-NP nl nn-NO oc pa-IN pl pt-BR pt-PT rm ro ru si sk sl sq sr sv-SE ta te th tl tr uk ur uz vi zh-CN zh-TW".split(" ");
|
||||
|
||||
const ABOUT_URL = "about:newtab";
|
||||
const BASE_URL = "resource://activity-stream/";
|
||||
const ACTIVITY_STREAM_PAGES = new Set(["home", "newtab", "welcome"]);
|
||||
|
||||
const IS_MAIN_PROCESS = Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
|
||||
const IS_PRIVILEGED_PROCESS = Services.appinfo.remoteType === E10SUtils.PRIVILEGED_REMOTE_TYPE;
|
||||
|
||||
const IS_RELEASE_OR_BETA = AppConstants.RELEASE_OR_BETA;
|
||||
|
||||
const PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS = "browser.tabs.remote.separatePrivilegedContentProcess";
|
||||
const PREF_ACTIVITY_STREAM_PRERENDER_ENABLED = "browser.newtabpage.activity-stream.prerender";
|
||||
const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
|
||||
|
||||
|
@ -33,6 +39,7 @@ const PREF_ACTIVITY_STREAM_DEBUG = "browser.newtabpage.activity-stream.debug";
|
|||
function AboutNewTabService() {
|
||||
Services.obs.addObserver(this, TOPIC_APP_QUIT);
|
||||
Services.obs.addObserver(this, TOPIC_LOCALES_CHANGE);
|
||||
Services.prefs.addObserver(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS, this);
|
||||
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
|
||||
if (!IS_RELEASE_OR_BETA) {
|
||||
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
|
||||
|
@ -44,6 +51,8 @@ function AboutNewTabService() {
|
|||
|
||||
if (IS_MAIN_PROCESS) {
|
||||
AboutNewTab.init();
|
||||
} else if (IS_PRIVILEGED_PROCESS) {
|
||||
Services.obs.addObserver(this, TOPIC_CONTENT_DOCUMENT_INTERACTIVE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,6 +94,7 @@ AboutNewTabService.prototype = {
|
|||
_activityStreamPrerender: false,
|
||||
_activityStreamPath: "",
|
||||
_activityStreamDebug: false,
|
||||
_privilegedContentProcess: false,
|
||||
_overridden: false,
|
||||
willNotifyUser: false,
|
||||
|
||||
|
@ -100,7 +110,9 @@ AboutNewTabService.prototype = {
|
|||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
if (data === PREF_ACTIVITY_STREAM_PRERENDER_ENABLED) {
|
||||
if (data === PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS) {
|
||||
this._privilegedContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS);
|
||||
} else if (data === PREF_ACTIVITY_STREAM_PRERENDER_ENABLED) {
|
||||
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
|
||||
this.notifyChange();
|
||||
} else if (!IS_RELEASE_OR_BETA && data === PREF_ACTIVITY_STREAM_DEBUG) {
|
||||
|
@ -109,10 +121,69 @@ AboutNewTabService.prototype = {
|
|||
this.notifyChange();
|
||||
}
|
||||
break;
|
||||
case TOPIC_CONTENT_DOCUMENT_INTERACTIVE:
|
||||
const win = subject.defaultView;
|
||||
|
||||
// It seems like "content-document-interactive" is triggered multiple
|
||||
// times for a single window. The first event always seems to be an
|
||||
// HTMLDocument object that contains a non-null window reference
|
||||
// whereas the remaining ones seem to be proxied objects.
|
||||
// https://searchfox.org/mozilla-central/rev/d2966246905102b36ef5221b0e3cbccf7ea15a86/devtools/server/actors/object.js#100-102
|
||||
if (win === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// We use win.location.pathname instead of win.location.toString()
|
||||
// because we want to account for URLs that contain the location hash
|
||||
// property or query strings (e.g. about:newtab#foo, about:home?bar).
|
||||
// Asserting here would be ideal, but this code path is also taken
|
||||
// by the view-source:// scheme, so we should probably just bail out
|
||||
// and do nothing.
|
||||
if (!ACTIVITY_STREAM_PAGES.has(win.location.pathname)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const onLoaded = () => {
|
||||
const debugString = this._activityStreamDebug ? "-dev" : "";
|
||||
|
||||
// This list must match any similar ones in render-activity-stream-html.js.
|
||||
const scripts = [
|
||||
"chrome://browser/content/contentSearchUI.js",
|
||||
"chrome://browser/content/contentTheme.js",
|
||||
`${BASE_URL}vendor/react${debugString}.js`,
|
||||
`${BASE_URL}vendor/react-dom${debugString}.js`,
|
||||
`${BASE_URL}vendor/prop-types.js`,
|
||||
`${BASE_URL}vendor/react-intl.js`,
|
||||
`${BASE_URL}vendor/redux.js`,
|
||||
`${BASE_URL}vendor/react-redux.js`,
|
||||
`${BASE_URL}prerendered/${this.activityStreamLocale}/activity-stream-strings.js`,
|
||||
`${BASE_URL}data/content/activity-stream.bundle.js`
|
||||
];
|
||||
|
||||
if (this._activityStreamPrerender) {
|
||||
scripts.unshift(`${BASE_URL}prerendered/static/activity-stream-initial-state.js`);
|
||||
}
|
||||
|
||||
for (let script of scripts) {
|
||||
Services.scriptloader.loadSubScript(script, win); // Synchronous call
|
||||
}
|
||||
};
|
||||
subject.addEventListener("DOMContentLoaded", onLoaded, {once: true});
|
||||
|
||||
// There is a possibility that DOMContentLoaded won't be fired. This
|
||||
// unload event (which cannot be cancelled) will attempt to remove
|
||||
// the listener for the DOMContentLoaded event.
|
||||
const onUnloaded = () => {
|
||||
subject.removeEventListener("DOMContentLoaded", onLoaded);
|
||||
};
|
||||
subject.addEventListener("unload", onUnloaded, {once: true});
|
||||
break;
|
||||
case TOPIC_APP_QUIT:
|
||||
this.uninit();
|
||||
if (IS_MAIN_PROCESS) {
|
||||
AboutNewTab.uninit();
|
||||
} else if (IS_PRIVILEGED_PROCESS) {
|
||||
Services.obs.removeObserver(this, TOPIC_CONTENT_DOCUMENT_INTERACTIVE);
|
||||
}
|
||||
break;
|
||||
case TOPIC_LOCALES_CHANGE:
|
||||
|
@ -137,7 +208,6 @@ AboutNewTabService.prototype = {
|
|||
* @param {Boolean} forceState force state change
|
||||
*/
|
||||
toggleActivityStream(stateEnabled, forceState = false) {
|
||||
|
||||
if (!forceState && (this.overridden || stateEnabled === this.activityStreamEnabled)) {
|
||||
// exit there is no change of state
|
||||
return false;
|
||||
|
@ -147,6 +217,7 @@ AboutNewTabService.prototype = {
|
|||
} else {
|
||||
this._activityStreamEnabled = false;
|
||||
}
|
||||
this._privilegedContentProcess = Services.prefs.getBoolPref(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS);
|
||||
this._activityStreamPrerender = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED);
|
||||
if (!IS_RELEASE_OR_BETA) {
|
||||
this._activityStreamDebug = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_DEBUG, false);
|
||||
|
@ -182,6 +253,7 @@ AboutNewTabService.prototype = {
|
|||
"activity-stream",
|
||||
this._activityStreamPrerender ? "-prerendered" : "",
|
||||
this._activityStreamDebug ? "-debug" : "",
|
||||
this._privilegedContentProcess ? "-noscripts" : "",
|
||||
".html"
|
||||
].join("");
|
||||
},
|
||||
|
@ -245,6 +317,7 @@ AboutNewTabService.prototype = {
|
|||
}
|
||||
Services.obs.removeObserver(this, TOPIC_APP_QUIT);
|
||||
Services.obs.removeObserver(this, TOPIC_LOCALES_CHANGE);
|
||||
Services.prefs.removeObserver(PREF_SEPARATE_PRIVILEGED_CONTENT_PROCESS, this);
|
||||
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_PRERENDER_ENABLED, this);
|
||||
if (!IS_RELEASE_OR_BETA) {
|
||||
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_DEBUG, this);
|
||||
|
|
|
@ -37,6 +37,7 @@ ManifestDPIAware true
|
|||
|
||||
Var TmpVal
|
||||
Var MaintCertKey
|
||||
Var ShouldOpenSurvey
|
||||
|
||||
; Other included files may depend upon these includes!
|
||||
; The following includes are provided by NSIS.
|
||||
|
@ -124,6 +125,8 @@ OutFile "helper.exe"
|
|||
!endif
|
||||
ShowUnInstDetails nevershow
|
||||
|
||||
!define URLUninstallSurvey "https://qsurvey.mozilla.com/s3/FF-Desktop-Post-Uninstall?channel=${UpdateChannel}&version=${AppVersion}&osversion="
|
||||
|
||||
################################################################################
|
||||
# Modern User Interface - MUI
|
||||
|
||||
|
@ -157,7 +160,11 @@ UninstPage custom un.preConfirm
|
|||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
; Finish Page
|
||||
|
||||
!define MUI_FINISHPAGE_SHOWREADME
|
||||
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
|
||||
!define MUI_FINISHPAGE_SHOWREADME_TEXT $(UN_SURVEY_CHECKBOX_LABEL)
|
||||
!define MUI_FINISHPAGE_SHOWREADME_FUNCTION un.Survey
|
||||
!define MUI_PAGE_CUSTOMFUNCTION_PRE un.preFinish
|
||||
!insertmacro MUI_UNPAGE_FINISH
|
||||
|
||||
; Use the default dialog for IDD_VERIFY for a simple Banner
|
||||
|
@ -166,6 +173,15 @@ ChangeUI IDD_VERIFY "${NSISDIR}\Contrib\UIs\default.exe"
|
|||
################################################################################
|
||||
# Helper Functions
|
||||
|
||||
Function un.Survey
|
||||
; We can't actually call ExecInExplorer here because it's going to have to
|
||||
; make some marshalled COM calls and those are not allowed from within a
|
||||
; synchronous message handler (where we currently are); we'll be thrown
|
||||
; RPC_E_CANTCALLOUT_ININPUTSYNCCALL if we try. So all we can do is record
|
||||
; that we need to make the call later, which we'll do from un.onGUIEnd.
|
||||
StrCpy $ShouldOpenSurvey "1"
|
||||
FunctionEnd
|
||||
|
||||
; This function is used to uninstall the maintenance service if the
|
||||
; application currently being uninstalled is the last application to use the
|
||||
; maintenance service.
|
||||
|
@ -587,6 +603,12 @@ Function un.preConfirm
|
|||
!insertmacro MUI_INSTALLOPTIONS_SHOW
|
||||
FunctionEnd
|
||||
|
||||
Function un.preFinish
|
||||
; Need to give the survey (readme) checkbox a few extra DU's of height
|
||||
; to accommodate a potentially multi-line label.
|
||||
WriteINIStr "$PLUGINSDIR\ioSpecial.ini" "Field 4" Bottom "120"
|
||||
FunctionEnd
|
||||
|
||||
################################################################################
|
||||
# Initialization Functions
|
||||
|
||||
|
@ -605,6 +627,7 @@ Function un.onInit
|
|||
System::Call 'kernel32::SetDllDirectoryW(w "")'
|
||||
|
||||
StrCpy $LANGUAGE 0
|
||||
StrCpy $ShouldOpenSurvey "0"
|
||||
|
||||
${un.UninstallUnOnInitCommon}
|
||||
|
||||
|
@ -617,4 +640,31 @@ FunctionEnd
|
|||
|
||||
Function un.onGUIEnd
|
||||
${un.OnEndCommon}
|
||||
|
||||
${If} $ShouldOpenSurvey == "1"
|
||||
; Though these values are sometimes incorrect due to bug 444664 it happens
|
||||
; so rarely it isn't worth working around it by reading the registry values.
|
||||
${WinVerGetMajor} $0
|
||||
${WinVerGetMinor} $1
|
||||
${WinVerGetBuild} $2
|
||||
${WinVerGetServicePackLevel} $3
|
||||
StrCpy $R1 "${URLUninstallSurvey}$0.$1.$2.$3"
|
||||
|
||||
; We can't just open the URL normally because we are most likely running
|
||||
; elevated without an unelevated process to redirect through, and we're
|
||||
; not going to go around starting elevated web browsers. But to start an
|
||||
; unelevated process directly from here we need a pretty nasty hack; see
|
||||
; the ExecInExplorer plugin code itself for the details.
|
||||
${If} ${AtLeastWin10}
|
||||
; If we were the default browser and we've now been uninstalled, we need
|
||||
; to take steps to make sure the user doesn't see an "open with" dialog;
|
||||
; they're helping us out by answering this survey, they don't need more
|
||||
; friction. Windows 7 and 8 automatically switch the default to IE, so
|
||||
; nothing to do for those, but 10 leaves the default empty and does show
|
||||
; the dialog, so we have to force Edge there.
|
||||
ExecInExplorer::Exec "microsoft-edge:$R1"
|
||||
${Else}
|
||||
ExecInExplorer::Exec "$R1"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
|
|
@ -68,6 +68,8 @@ STATUS_INSTALL_LANG=Installing Language Files (${AB_CD})…
|
|||
STATUS_UNINSTALL_MAIN=Uninstalling $BrandShortName…
|
||||
STATUS_CLEANUP=A Little Housekeeping…
|
||||
|
||||
UN_SURVEY_CHECKBOX_LABEL=Tell Mozilla why you uninstalled $BrandShortName
|
||||
|
||||
# _DESC strings support approximately 65 characters per line.
|
||||
# One line
|
||||
OPTIONS_SUMMARY=Choose the type of setup you prefer, then click Next.
|
||||
|
|
|
@ -24,9 +24,12 @@ XPIDL_SOURCES += [
|
|||
XPIDL_MODULE = 'caps'
|
||||
|
||||
EXPORTS += [
|
||||
'ContentPrincipal.h',
|
||||
'nsJSPrincipals.h',
|
||||
'nsScriptSecurityManager.h',
|
||||
'NullPrincipal.h',
|
||||
'NullPrincipalURI.h',
|
||||
'SystemPrincipal.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla = [
|
||||
|
|
|
@ -908,12 +908,20 @@ function doTestScroll(aSettings, aCallback)
|
|||
var currentTest = kTests[currentTestIndex];
|
||||
description = "doTestScroll(aSettings=" + aSettings.description + "), " + currentTest.description + ": ";
|
||||
if (currentTest.prepare) {
|
||||
currentTest.prepare(doTestCurrentScroll);
|
||||
// prepare() can make changes to a page such as
|
||||
// changing the 'overflow' property which requires
|
||||
// a repaint to take effect before sending
|
||||
// scroll-wheel events.
|
||||
currentTest.prepare(doWaitForPaintsAndScroll);
|
||||
} else {
|
||||
doTestCurrentScroll();
|
||||
}
|
||||
}
|
||||
|
||||
function doWaitForPaintsAndScroll() {
|
||||
waitForAllPaintsFlushed(doTestCurrentScroll);
|
||||
}
|
||||
|
||||
function doTestCurrentScroll() {
|
||||
var currentTest = kTests[currentTestIndex];
|
||||
sendWheelAndWait(10, 10, currentTest.event, function () {
|
||||
|
|
|
@ -3933,7 +3933,7 @@ MediaManager::IsActivelyCapturingOrHasAPermission(uint64_t aWindowId)
|
|||
// Or are persistent permissions (audio or video) granted?
|
||||
|
||||
auto* window = nsGlobalWindowInner::GetInnerWindowWithId(aWindowId);
|
||||
if (NS_WARN_IF(!window)) {
|
||||
if (NS_WARN_IF(!window) || NS_WARN_IF(!window->GetPrincipal())) {
|
||||
return false;
|
||||
}
|
||||
// Check if this site has persistent permissions.
|
||||
|
@ -3947,7 +3947,7 @@ MediaManager::IsActivelyCapturingOrHasAPermission(uint64_t aWindowId)
|
|||
uint32_t audio = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
uint32_t video = nsIPermissionManager::UNKNOWN_ACTION;
|
||||
{
|
||||
auto* principal = window->GetExtantDoc()->NodePrincipal();
|
||||
auto* principal = window->GetPrincipal();
|
||||
rv = mgr->TestExactPermissionFromPrincipal(principal, "microphone", &audio);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
|
|
|
@ -62,7 +62,7 @@ ServiceWorker::Create(nsIGlobalObject* aOwner,
|
|||
NS_ENSURE_TRUE(reg, nullptr);
|
||||
|
||||
RefPtr<ServiceWorkerInfo> info = reg->GetByDescriptor(aDescriptor);
|
||||
NS_ENSURE_TRUE(reg, nullptr);
|
||||
NS_ENSURE_TRUE(info, nullptr);
|
||||
|
||||
inner = new ServiceWorkerImpl(info, reg);
|
||||
}
|
||||
|
|
|
@ -529,22 +529,25 @@ ServiceWorkerRegistration::UpdateStateInternal(const Maybe<ServiceWorkerDescript
|
|||
}
|
||||
|
||||
if (aActive.isSome()) {
|
||||
mActiveWorker = global->GetOrCreateServiceWorker(aActive.ref());
|
||||
mActiveWorker->SetState(aActive.ref().State());
|
||||
if ((mActiveWorker = global->GetOrCreateServiceWorker(aActive.ref()))) {
|
||||
mActiveWorker->SetState(aActive.ref().State());
|
||||
}
|
||||
} else {
|
||||
mActiveWorker = nullptr;
|
||||
}
|
||||
|
||||
if (aWaiting.isSome()) {
|
||||
mWaitingWorker = global->GetOrCreateServiceWorker(aWaiting.ref());
|
||||
mWaitingWorker->SetState(aWaiting.ref().State());
|
||||
if ((mWaitingWorker = global->GetOrCreateServiceWorker(aWaiting.ref()))) {
|
||||
mWaitingWorker->SetState(aWaiting.ref().State());
|
||||
}
|
||||
} else {
|
||||
mWaitingWorker = nullptr;
|
||||
}
|
||||
|
||||
if (aInstalling.isSome()) {
|
||||
mInstallingWorker = global->GetOrCreateServiceWorker(aInstalling.ref());
|
||||
mInstallingWorker->SetState(aInstalling.ref().State());
|
||||
if ((mInstallingWorker = global->GetOrCreateServiceWorker(aInstalling.ref()))) {
|
||||
mInstallingWorker->SetState(aInstalling.ref().State());
|
||||
}
|
||||
} else {
|
||||
mInstallingWorker = nullptr;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,39 @@ namespace layers {
|
|||
|
||||
const FrameMetrics::ViewID FrameMetrics::NULL_SCROLL_ID = 0;
|
||||
|
||||
void
|
||||
FrameMetrics::RecalculateViewportOffset()
|
||||
{
|
||||
if (!mIsRootContent) {
|
||||
return;
|
||||
}
|
||||
CSSRect visualViewport = GetVisualViewport();
|
||||
// If the visual viewport is contained within the layout viewport, we don't
|
||||
// need to make any adjustments, so we can exit early.
|
||||
//
|
||||
// Additionally, if the composition bounds changes (due to an orientation
|
||||
// change, window resize, etc.), it may take a few frames for mViewport to
|
||||
// update and during that time, the visual viewport may be larger than the
|
||||
// layout viewport, so don't attempt to make any adjustments.
|
||||
if (mViewport.Contains(visualViewport) ||
|
||||
(mViewport.Width() < visualViewport.Width() &&
|
||||
!FuzzyEqualsMultiplicative(mViewport.Width(), visualViewport.Width())) ||
|
||||
(mViewport.Height() < visualViewport.Height() &&
|
||||
!FuzzyEqualsMultiplicative(mViewport.Height(), visualViewport.Height()))) {
|
||||
return;
|
||||
}
|
||||
if (visualViewport.X() < mViewport.X()) {
|
||||
mViewport.MoveToX(visualViewport.X());
|
||||
} else if (mViewport.XMost() < visualViewport.XMost()) {
|
||||
mViewport.MoveByX(visualViewport.XMost() - mViewport.XMost());
|
||||
}
|
||||
if (visualViewport.Y() < mViewport.Y()) {
|
||||
mViewport.MoveToY(visualViewport.Y());
|
||||
} else if (mViewport.YMost() < visualViewport.YMost()) {
|
||||
mViewport.MoveByY(visualViewport.YMost() - mViewport.YMost());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ScrollMetadata::SetUsesContainerScrolling(bool aValue) {
|
||||
MOZ_ASSERT_IF(aValue, gfxPrefs::LayoutUseContainersForRootFrames());
|
||||
|
|
|
@ -481,6 +481,11 @@ public:
|
|||
return mViewport;
|
||||
}
|
||||
|
||||
CSSRect GetVisualViewport() const
|
||||
{
|
||||
return CSSRect(mScrollOffset, CalculateCompositedSizeInCssPixels());
|
||||
}
|
||||
|
||||
void SetExtraResolution(const ScreenToLayerScale2D& aExtraResolution)
|
||||
{
|
||||
mExtraResolution = aExtraResolution;
|
||||
|
@ -526,6 +531,13 @@ public:
|
|||
return mIsScrollInfoLayer;
|
||||
}
|
||||
|
||||
// Determine if the visual viewport is outside of the layout viewport and
|
||||
// adjust the x,y-offset in mViewport accordingly. This is necessary to
|
||||
// allow APZ to async-scroll the layout viewport.
|
||||
//
|
||||
// This is a no-op if mIsRootContent is false.
|
||||
void RecalculateViewportOffset();
|
||||
|
||||
private:
|
||||
// A unique ID assigned to each scrollable frame.
|
||||
ViewID mScrollId;
|
||||
|
|
|
@ -242,7 +242,7 @@ StackScrollerFlingAnimation::DoSample(FrameMetrics& aFrameMetrics,
|
|||
mPreviousOffset = offset;
|
||||
|
||||
mApzc.SetVelocityVector(velocity);
|
||||
aFrameMetrics.SetScrollOffset(offset / aFrameMetrics.GetZoom());
|
||||
mApzc.SetScrollOffset(offset / aFrameMetrics.GetZoom());
|
||||
|
||||
// If we hit a bounds while flinging, send the velocity so that the bounce
|
||||
// animation can play.
|
||||
|
|
|
@ -581,11 +581,13 @@ private:
|
|||
|
||||
class ZoomAnimation: public AsyncPanZoomAnimation {
|
||||
public:
|
||||
ZoomAnimation(const CSSPoint& aStartOffset,
|
||||
ZoomAnimation(AsyncPanZoomController& aApzc,
|
||||
const CSSPoint& aStartOffset,
|
||||
const CSSToParentLayerScale2D& aStartZoom,
|
||||
const CSSPoint& aEndOffset,
|
||||
const CSSToParentLayerScale2D& aEndZoom)
|
||||
: mTotalDuration(
|
||||
: mApzc(aApzc)
|
||||
, mTotalDuration(
|
||||
TimeDuration::FromMilliseconds(gfxPrefs::APZZoomAnimationDuration()))
|
||||
, mStartOffset(aStartOffset)
|
||||
, mStartZoom(aStartZoom)
|
||||
|
@ -602,7 +604,7 @@ public:
|
|||
|
||||
if (animPosition >= 1.0) {
|
||||
aFrameMetrics.SetZoom(mEndZoom);
|
||||
aFrameMetrics.SetScrollOffset(mEndOffset);
|
||||
mApzc.SetScrollOffset(mEndOffset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -618,7 +620,7 @@ public:
|
|||
1 / (sampledPosition / mEndZoom.xScale + (1 - sampledPosition) / mStartZoom.xScale),
|
||||
1 / (sampledPosition / mEndZoom.yScale + (1 - sampledPosition) / mStartZoom.yScale)));
|
||||
|
||||
aFrameMetrics.SetScrollOffset(CSSPoint::FromUnknownPoint(gfx::Point(
|
||||
mApzc.SetScrollOffset(CSSPoint::FromUnknownPoint(gfx::Point(
|
||||
mEndOffset.x * sampledPosition + mStartOffset.x * (1 - sampledPosition),
|
||||
mEndOffset.y * sampledPosition + mStartOffset.y * (1 - sampledPosition)
|
||||
)));
|
||||
|
@ -632,6 +634,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
AsyncPanZoomController& mApzc;
|
||||
|
||||
TimeDuration mDuration;
|
||||
const TimeDuration mTotalDuration;
|
||||
|
||||
|
@ -680,7 +684,7 @@ public:
|
|||
// offset to end up being a bit off from the destination, we can get
|
||||
// artefacts like "scroll to the next snap point in this direction"
|
||||
// scrolling to the snap point we're already supposed to be at.
|
||||
aFrameMetrics.ClampAndSetScrollOffset(
|
||||
mApzc.ClampAndSetScrollOffset(
|
||||
CSSPoint::FromAppUnits(nsPoint(mXAxisModel.GetDestination(),
|
||||
mYAxisModel.GetDestination())));
|
||||
return false;
|
||||
|
@ -719,7 +723,7 @@ public:
|
|||
mApzc.mX.AdjustDisplacement(displacement.x, adjustedOffset.x, overscroll.x);
|
||||
mApzc.mY.AdjustDisplacement(displacement.y, adjustedOffset.y, overscroll.y);
|
||||
|
||||
aFrameMetrics.ScrollBy(adjustedOffset / zoom);
|
||||
mApzc.ScrollBy(adjustedOffset / zoom);
|
||||
|
||||
// The smooth scroll may have caused us to reach the end of our scroll range.
|
||||
// This can happen if either the layout.css.scroll-behavior.damping-ratio
|
||||
|
@ -1075,7 +1079,7 @@ nsEventStatus AsyncPanZoomController::HandleDragEvent(const MouseInput& aEvent,
|
|||
scrollOffset.y = scrollPosition;
|
||||
}
|
||||
APZC_LOG("%p set scroll offset to %s from scrollbar drag\n", this, Stringify(scrollOffset).c_str());
|
||||
mFrameMetrics.SetScrollOffset(scrollOffset);
|
||||
SetScrollOffset(scrollOffset);
|
||||
ScheduleCompositeAndMaybeRepaint();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
|
||||
|
@ -3310,7 +3314,7 @@ void AsyncPanZoomController::AdjustScrollForSurfaceShift(const ScreenPoint& aShi
|
|||
this, Stringify(adjustment).c_str());
|
||||
CSSRect scrollRange = mFrameMetrics.CalculateScrollRange();
|
||||
// Apply shift to mFrameMetrics.mScrollOffset.
|
||||
mFrameMetrics.SetScrollOffset(scrollRange.ClampPoint(
|
||||
SetScrollOffset(scrollRange.ClampPoint(
|
||||
mFrameMetrics.GetScrollOffset() + adjustment));
|
||||
// Apply shift to mCompositedScrollOffset, since the dynamic toolbar expects
|
||||
// the shift to take effect right away, without the usual frame delay.
|
||||
|
@ -3320,12 +3324,27 @@ void AsyncPanZoomController::AdjustScrollForSurfaceShift(const ScreenPoint& aShi
|
|||
UpdateSharedCompositorFrameMetrics();
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetScrollOffset(const CSSPoint& aOffset) {
|
||||
mFrameMetrics.SetScrollOffset(aOffset);
|
||||
mFrameMetrics.RecalculateViewportOffset();
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ClampAndSetScrollOffset(const CSSPoint& aOffset) {
|
||||
mFrameMetrics.ClampAndSetScrollOffset(aOffset);
|
||||
mFrameMetrics.RecalculateViewportOffset();
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
|
||||
mFrameMetrics.ScrollBy(aOffset);
|
||||
SetScrollOffset(mFrameMetrics.GetScrollOffset() + aOffset);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScrollByAndClamp(const CSSPoint& aOffset) {
|
||||
mFrameMetrics.ClampAndSetScrollOffset(mFrameMetrics.GetScrollOffset() + aOffset);
|
||||
ClampAndSetScrollOffset(mFrameMetrics.GetScrollOffset() + aOffset);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::CopyScrollInfoFrom(const FrameMetrics& aFrameMetrics) {
|
||||
mFrameMetrics.CopyScrollInfoFrom(aFrameMetrics);
|
||||
mFrameMetrics.RecalculateViewportOffset();
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::ScaleWithFocus(float aScale,
|
||||
|
@ -3335,7 +3354,7 @@ void AsyncPanZoomController::ScaleWithFocus(float aScale,
|
|||
// at the same position on the screen before and after the change in zoom. The below code
|
||||
// accomplishes this; see https://bugzilla.mozilla.org/show_bug.cgi?id=923431#c6 for an
|
||||
// in-depth explanation of how.
|
||||
mFrameMetrics.SetScrollOffset((mFrameMetrics.GetScrollOffset() + aFocus) - (aFocus / aScale));
|
||||
SetScrollOffset((mFrameMetrics.GetScrollOffset() + aFocus) - (aFocus / aScale));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3458,9 +3477,8 @@ const ScreenMargin AsyncPanZoomController::CalculatePendingDisplayPort(
|
|||
displayPort.MoveBy(velocity * paintFactor * gfxPrefs::APZVelocityBias());
|
||||
|
||||
APZC_LOG_FM(aFrameMetrics,
|
||||
"Calculated displayport as (%f %f %f %f) from velocity %s paint time %f metrics",
|
||||
displayPort.x, displayPort.y, displayPort.Width(), displayPort.Height(),
|
||||
ToString(aVelocity).c_str(), paintFactor);
|
||||
"Calculated displayport as %s from velocity %s paint time %f metrics",
|
||||
Stringify(displayPort).c_str(), ToString(aVelocity).c_str(), paintFactor);
|
||||
|
||||
CSSMargin cssMargins;
|
||||
cssMargins.left = -displayPort.X();
|
||||
|
@ -3610,6 +3628,10 @@ AsyncPanZoomController::RequestContentRepaint(const FrameMetrics& aFrameMetrics,
|
|||
mLastPaintRequestMetrics.GetViewport().Width()) < EPSILON &&
|
||||
fabsf(aFrameMetrics.GetViewport().Height() -
|
||||
mLastPaintRequestMetrics.GetViewport().Height()) < EPSILON &&
|
||||
fabsf(aFrameMetrics.GetViewport().X() -
|
||||
mLastPaintRequestMetrics.GetViewport().X()) < EPSILON &&
|
||||
fabsf(aFrameMetrics.GetViewport().Y() -
|
||||
mLastPaintRequestMetrics.GetViewport().Y()) < EPSILON &&
|
||||
aFrameMetrics.GetScrollGeneration() ==
|
||||
mLastPaintRequestMetrics.GetScrollGeneration() &&
|
||||
aFrameMetrics.GetScrollUpdateType() ==
|
||||
|
@ -4068,20 +4090,6 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
|||
}
|
||||
}
|
||||
|
||||
bool needContentRepaint = false;
|
||||
bool viewportUpdated = false;
|
||||
if (FuzzyEqualsAdditive(aLayerMetrics.GetCompositionBounds().Width(), mFrameMetrics.GetCompositionBounds().Width()) &&
|
||||
FuzzyEqualsAdditive(aLayerMetrics.GetCompositionBounds().Height(), mFrameMetrics.GetCompositionBounds().Height())) {
|
||||
// Remote content has sync'd up to the composition geometry
|
||||
// change, so we can accept the viewport it's calculated.
|
||||
if (mFrameMetrics.GetViewport().Width() != aLayerMetrics.GetViewport().Width() ||
|
||||
mFrameMetrics.GetViewport().Height() != aLayerMetrics.GetViewport().Height()) {
|
||||
needContentRepaint = true;
|
||||
viewportUpdated = true;
|
||||
}
|
||||
mFrameMetrics.SetViewport(aLayerMetrics.GetViewport());
|
||||
}
|
||||
|
||||
// If the layers update was not triggered by our own repaint request, then
|
||||
// we want to take the new scroll offset. Check the scroll generation as well
|
||||
// to filter duplicate calls to NotifyLayersUpdated with the same scroll offset
|
||||
|
@ -4101,6 +4109,22 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
|||
// TODO if we're in a drag and scrollOffsetUpdated is set then we want to
|
||||
// ignore it
|
||||
|
||||
bool needContentRepaint = false;
|
||||
bool viewportUpdated = false;
|
||||
if (FuzzyEqualsAdditive(aLayerMetrics.GetCompositionBounds().Width(), mFrameMetrics.GetCompositionBounds().Width()) &&
|
||||
FuzzyEqualsAdditive(aLayerMetrics.GetCompositionBounds().Height(), mFrameMetrics.GetCompositionBounds().Height())) {
|
||||
// Remote content has sync'd up to the composition geometry
|
||||
// change, so we can accept the viewport it's calculated.
|
||||
if (mFrameMetrics.GetViewport().Width() != aLayerMetrics.GetViewport().Width() ||
|
||||
mFrameMetrics.GetViewport().Height() != aLayerMetrics.GetViewport().Height()) {
|
||||
needContentRepaint = true;
|
||||
viewportUpdated = true;
|
||||
}
|
||||
if (viewportUpdated || scrollOffsetUpdated) {
|
||||
mFrameMetrics.SetViewport(aLayerMetrics.GetViewport());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
if (aLayerMetrics.IsRootContent()) {
|
||||
if (APZCTreeManager* manager = GetApzcTreeManager()) {
|
||||
|
@ -4204,7 +4228,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
|||
// becomes incorrect for the purposes of calculating the LD transform. To
|
||||
// correct this we need to update mExpectedGeckoMetrics to be the
|
||||
// last thing we know was painted by Gecko.
|
||||
mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
|
||||
CopyScrollInfoFrom(aLayerMetrics);
|
||||
mCompositedLayoutViewport = mFrameMetrics.GetViewport();
|
||||
mCompositedScrollOffset = mFrameMetrics.GetScrollOffset();
|
||||
mExpectedGeckoMetrics = aLayerMetrics;
|
||||
|
@ -4229,7 +4253,7 @@ void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMe
|
|||
// Even if we didn't accept a new scroll offset from content, the
|
||||
// scrollable rect may have changed in a way that makes our local
|
||||
// scroll offset out of bounds, so re-clamp it.
|
||||
mFrameMetrics.ClampAndSetScrollOffset(mFrameMetrics.GetScrollOffset());
|
||||
ClampAndSetScrollOffset(mFrameMetrics.GetScrollOffset());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4407,8 +4431,10 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect, const uint32_t aFlags) {
|
|||
}
|
||||
|
||||
endZoomToMetrics.SetScrollOffset(aRect.TopLeft());
|
||||
endZoomToMetrics.RecalculateViewportOffset();
|
||||
|
||||
StartAnimation(new ZoomAnimation(
|
||||
*this,
|
||||
mFrameMetrics.GetScrollOffset(),
|
||||
mFrameMetrics.GetZoom(),
|
||||
endZoomToMetrics.GetScrollOffset(),
|
||||
|
|
|
@ -665,6 +665,23 @@ protected:
|
|||
*/
|
||||
nsEventStatus OnCancelTap(const TapGestureInput& aEvent);
|
||||
|
||||
/**
|
||||
* The following five methods modify the scroll offset. For the APZC
|
||||
* representing the RCD-RSF, they also recalculate the offset of the layout
|
||||
* viewport.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Scroll the scroll frame to an X,Y offset.
|
||||
*/
|
||||
void SetScrollOffset(const CSSPoint& aOffset);
|
||||
|
||||
/**
|
||||
* Scroll the scroll frame to an X,Y offset, clamping the resulting scroll
|
||||
* offset to the scroll range.
|
||||
*/
|
||||
void ClampAndSetScrollOffset(const CSSPoint& aOffset);
|
||||
|
||||
/**
|
||||
* Scroll the scroll frame by an X,Y offset.
|
||||
* The resulting scroll offset is not clamped to the scrollable rect;
|
||||
|
@ -674,10 +691,15 @@ protected:
|
|||
|
||||
/**
|
||||
* Scroll the scroll frame by an X,Y offset, clamping the resulting
|
||||
* scroll offset to the scrollable rect.
|
||||
* scroll offset to the scroll range.
|
||||
*/
|
||||
void ScrollByAndClamp(const CSSPoint& aOffset);
|
||||
|
||||
/**
|
||||
* Copy the scroll offset and scroll generation from |aFrameMetrics|.
|
||||
*/
|
||||
void CopyScrollInfoFrom(const FrameMetrics& aFrameMetrics);
|
||||
|
||||
/**
|
||||
* Scales the viewport by an amount (note that it multiplies this scale in to
|
||||
* the current scale, it doesn't set it to |aScale|). Also considers a focus
|
||||
|
@ -1185,6 +1207,7 @@ private:
|
|||
friend class GenericScrollAnimation;
|
||||
friend class WheelScrollAnimation;
|
||||
friend class KeyboardScrollAnimation;
|
||||
friend class ZoomAnimation;
|
||||
|
||||
friend class GenericOverscrollEffect;
|
||||
friend class WidgetOverscrollEffect;
|
||||
|
|
|
@ -155,7 +155,7 @@ public:
|
|||
mApzc.mX.AdjustDisplacement(offset.x, adjustedOffset.x, overscroll.x);
|
||||
mApzc.mY.AdjustDisplacement(offset.y, adjustedOffset.y, overscroll.y);
|
||||
|
||||
aFrameMetrics.ScrollBy(adjustedOffset / aFrameMetrics.GetZoom());
|
||||
mApzc.ScrollBy(adjustedOffset / aFrameMetrics.GetZoom());
|
||||
|
||||
// The fling may have caused us to reach the end of our scroll range.
|
||||
if (!IsZero(overscroll)) {
|
||||
|
|
|
@ -105,7 +105,7 @@ GenericScrollAnimation::DoSample(FrameMetrics& aFrameMetrics, const TimeDuration
|
|||
return false;
|
||||
}
|
||||
|
||||
aFrameMetrics.ScrollBy(adjustedOffset / zoom);
|
||||
mApzc.ScrollBy(adjustedOffset / zoom);
|
||||
return !finished;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,10 @@ protected:
|
|||
FrameMetrics GetPinchableFrameMetrics()
|
||||
{
|
||||
FrameMetrics fm;
|
||||
fm.SetCompositionBounds(ParentLayerRect(200, 200, 100, 200));
|
||||
fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 200));
|
||||
fm.SetScrollableRect(CSSRect(0, 0, 980, 1000));
|
||||
fm.SetScrollOffset(CSSPoint(300, 300));
|
||||
fm.SetViewport(CSSRect(300, 300, 100, 200));
|
||||
fm.SetZoom(CSSToParentLayerScale2D(2.0, 2.0));
|
||||
// APZC only allows zooming on the root scrollable frame.
|
||||
fm.SetIsRootContent(true);
|
||||
|
@ -56,10 +57,10 @@ protected:
|
|||
FrameMetrics fm = apzc->GetFrameMetrics();
|
||||
|
||||
if (aShouldTriggerPinch) {
|
||||
// the visible area of the document in CSS pixels is now x=305 y=310 w=40 h=80
|
||||
// the visible area of the document in CSS pixels is now x=325 y=330 w=40 h=80
|
||||
EXPECT_EQ(2.5f, fm.GetZoom().ToScaleFactor().scale);
|
||||
EXPECT_EQ(305, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(310, fm.GetScrollOffset().y);
|
||||
EXPECT_EQ(325, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(330, fm.GetScrollOffset().y);
|
||||
} else {
|
||||
// The frame metrics should stay the same since touch-action:none makes
|
||||
// apzc ignore pinch gestures.
|
||||
|
@ -88,9 +89,9 @@ protected:
|
|||
fm = apzc->GetFrameMetrics();
|
||||
|
||||
if (aShouldTriggerPinch) {
|
||||
// the visible area of the document in CSS pixels is now x=880 y=0 w=100 h=200
|
||||
// the visible area of the document in CSS pixels is now x=805 y=0 w=100 h=200
|
||||
EXPECT_EQ(1.0f, fm.GetZoom().ToScaleFactor().scale);
|
||||
EXPECT_EQ(880, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(805, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(0, fm.GetScrollOffset().y);
|
||||
} else {
|
||||
EXPECT_EQ(2.0f, fm.GetZoom().ToScaleFactor().scale);
|
||||
|
@ -341,6 +342,85 @@ TEST_F(APZCPinchTester, Panning_TwoFinger_ZoomDisabled) {
|
|||
EXPECT_EQ(2.0, fm.GetZoom().ToScaleFactor().scale);
|
||||
}
|
||||
|
||||
TEST_F(APZCPinchTester, Panning_Beyond_LayoutViewport) {
|
||||
apzc->SetFrameMetrics(GetPinchableFrameMetrics());
|
||||
MakeApzcZoomable();
|
||||
|
||||
// Case 1 - visual viewport is still inside layout viewport.
|
||||
Pan(apzc, 350, 300, PanOptions::NoFling);
|
||||
FrameMetrics fm = apzc->GetFrameMetrics();
|
||||
// It starts from (300, 300) pans by (0, 50) screen pixels, but there is a
|
||||
// 2x zoom, which causes the scroll offset to change by half of that (0, 25).
|
||||
// But the visual viewport is still inside the layout viewport.
|
||||
EXPECT_EQ(300, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(325, fm.GetScrollOffset().y);
|
||||
EXPECT_EQ(300, fm.GetViewport().X());
|
||||
EXPECT_EQ(300, fm.GetViewport().Y());
|
||||
|
||||
// Case 2 - visual viewport crosses the bottom boundary of the layout
|
||||
// viewport.
|
||||
Pan(apzc, 525, 325, PanOptions::NoFling);
|
||||
fm = apzc->GetFrameMetrics();
|
||||
// It starts from (300, 325) pans by (0, 200) screen pixels, but there is a
|
||||
// 2x zoom, which causes the scroll offset to change by half of that
|
||||
// (0, 100). The visual viewport crossed the bottom boundary of the layout
|
||||
// viewport by 25px.
|
||||
EXPECT_EQ(300, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(425, fm.GetScrollOffset().y);
|
||||
EXPECT_EQ(300, fm.GetViewport().X());
|
||||
EXPECT_EQ(325, fm.GetViewport().Y());
|
||||
|
||||
// Case 3 - visual viewport crosses the top boundary of the layout viewport.
|
||||
Pan(apzc, 425, 775, PanOptions::NoFling);
|
||||
fm = apzc->GetFrameMetrics();
|
||||
// It starts from (300, 425) pans by (0, -350) screen pixels, but there is a
|
||||
// 2x zoom, which causes the scroll offset to change by half of that
|
||||
// (0, -175). The visual viewport crossed the top of the layout viewport by
|
||||
// 75px.
|
||||
EXPECT_EQ(300, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(250, fm.GetScrollOffset().y);
|
||||
EXPECT_EQ(300, fm.GetViewport().X());
|
||||
EXPECT_EQ(250, fm.GetViewport().Y());
|
||||
|
||||
// Case 4 - visual viewport crosses the left boundary of the layout viewport.
|
||||
Pan(apzc, ScreenIntPoint(150, 10), ScreenIntPoint(350, 10), PanOptions::NoFling);
|
||||
fm = apzc->GetFrameMetrics();
|
||||
// It starts from (300, 250) pans by (-200, 0) screen pixels, but there is a
|
||||
// 2x zoom, which causes the scroll offset to change by half of that
|
||||
// (-100, 0). The visual viewport crossed the left boundary of the layout
|
||||
// viewport by 100px.
|
||||
EXPECT_EQ(200, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(250, fm.GetScrollOffset().y);
|
||||
EXPECT_EQ(200, fm.GetViewport().X());
|
||||
EXPECT_EQ(250, fm.GetViewport().Y());
|
||||
|
||||
// Case 5 - visual viewport crosses the right boundary of the layout viewport.
|
||||
Pan(apzc, ScreenIntPoint(350, 10), ScreenIntPoint(150, 10), PanOptions::NoFling);
|
||||
fm = apzc->GetFrameMetrics();
|
||||
// It starts from (200, 250) pans by (200, 0) screen pixels, but there is a
|
||||
// 2x zoom, which causes the scroll offset to change by half of that
|
||||
// (100, 0). The visual viewport crossed the right boundary of the layout
|
||||
// viewport by 50px.
|
||||
EXPECT_EQ(300, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(250, fm.GetScrollOffset().y);
|
||||
EXPECT_EQ(250, fm.GetViewport().X());
|
||||
EXPECT_EQ(250, fm.GetViewport().Y());
|
||||
|
||||
// Case 6 - visual viewport crosses both the vertical and horizontal
|
||||
// boundaries of the layout viewport by moving diagonally towards the
|
||||
// top-right corner.
|
||||
Pan(apzc, ScreenIntPoint(350, 200), ScreenIntPoint(150, 400), PanOptions::NoFling);
|
||||
fm = apzc->GetFrameMetrics();
|
||||
// It starts from (300, 250) pans by (200, -200) screen pixels, but there is
|
||||
// a 2x zoom, which causes the scroll offset to change by half of that
|
||||
// (100, -100). The visual viewport moved by (100, -100) outside the
|
||||
// boundary of the layout viewport.
|
||||
EXPECT_EQ(400, fm.GetScrollOffset().x);
|
||||
EXPECT_EQ(150, fm.GetScrollOffset().y);
|
||||
EXPECT_EQ(350, fm.GetViewport().X());
|
||||
EXPECT_EQ(150, fm.GetViewport().Y());
|
||||
}
|
||||
|
||||
TEST_F(APZCPinchGestureDetectorTester, Pinch_APZZoom_Disabled) {
|
||||
SCOPED_GFX_PREF(APZAllowZooming, bool, false);
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width; initial-scale=1.0">
|
||||
<title>Ensure layout viewport responds to panning while pinched</title>
|
||||
<script type="application/javascript" src="apz_test_utils.js"></script>
|
||||
<script type="application/javascript" src="apz_test_native_event_utils.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/paint_listener.js"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#content {
|
||||
height: 5000px;
|
||||
width: 5000px;
|
||||
background: repeating-linear-gradient(#EEE, #EEE 100px, #DDD 100px, #DDD 200px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
<script type="application/javascript">
|
||||
const RESOLUTION = 4;
|
||||
const OFFSET_SCREEN_PX = 50;
|
||||
const OFFSET_CSS_PX = OFFSET_SCREEN_PX / RESOLUTION;
|
||||
|
||||
function computeDelta(visual) {
|
||||
// Compute the distance from the right/bottom edge of the visual
|
||||
// viewport to the same edge of the layout viewport and add the desired
|
||||
// offset to that.
|
||||
const layout = visual * RESOLUTION;
|
||||
return layout - visual + OFFSET_SCREEN_PX;
|
||||
}
|
||||
|
||||
function* test(testDriver) {
|
||||
const target = document.getElementById("content");
|
||||
const cases = [
|
||||
{
|
||||
x: 0,
|
||||
y: 0,
|
||||
dx: (width) => -computeDelta(width),
|
||||
dy: (height) => 0,
|
||||
expected: {
|
||||
x: [OFFSET_CSS_PX, "x-offset was adjusted"],
|
||||
y: [0, "y-offset was not affected"],
|
||||
},
|
||||
},
|
||||
{
|
||||
x: OFFSET_SCREEN_PX,
|
||||
y: 0,
|
||||
dx: (width) => 0,
|
||||
dy: (height) => -computeDelta(height),
|
||||
expected: {
|
||||
x: [OFFSET_CSS_PX, "x-offset was not affected"],
|
||||
y: [OFFSET_CSS_PX, "y-offset was adjusted"],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (let c of cases) {
|
||||
yield synthesizeNativeTouchDrag(target,
|
||||
c.x,
|
||||
c.y,
|
||||
c.dx(document.documentElement.clientWidth),
|
||||
c.dy(document.documentElement.clientHeight),
|
||||
testDriver);
|
||||
yield waitForApzFlushedRepaints(testDriver);
|
||||
is(window.scrollX, c.expected.x[0], c.expected.x[1]);
|
||||
is(window.scrollY, c.expected.y[0], c.expected.y[1]);
|
||||
}
|
||||
}
|
||||
|
||||
SpecialPowers.getDOMWindowUtils(window).setResolutionAndScaleTo(RESOLUTION);
|
||||
waitUntilApzStable().then(runContinuation(test)).then(subtestDone);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -17,27 +17,35 @@ var prefs = [
|
|||
["apz.touch_start_tolerance", "0.0"],
|
||||
// The subtests in this test do touch-drags to pan the page, but we don't
|
||||
// want those pans to turn into fling animations, so we increase the
|
||||
// fling-stop threshold velocity to absurdly high.
|
||||
["apz.fling_stopped_threshold", "10000"],
|
||||
// fling-min threshold velocity to an arbitrarily large value.
|
||||
["apz.fling_min_velocity_threshold", "10000"],
|
||||
// The helper_bug1280013's div gets a displayport on scroll, but if the
|
||||
// test takes too long the displayport can expire before we read the value
|
||||
// out of the test. So we disable displayport expiry for these tests.
|
||||
["apz.displayport_expiry_ms", 0],
|
||||
// Prevent the dynamic toolbar from interfering with main-thread scroll
|
||||
// offset values.
|
||||
["browser.chrome.dynamictoolbar", false],
|
||||
];
|
||||
|
||||
// Increase the tap timeouts so the double-tap is still detected in case of
|
||||
// random delays during testing.
|
||||
var doubletap_prefs = prefs.slice(); // make a copy
|
||||
doubletap_prefs.push(["ui.click_hold_context_menus.delay", 10000]);
|
||||
doubletap_prefs.push(["apz.max_tap_time", 10000]);
|
||||
var doubletap_prefs = [
|
||||
...prefs,
|
||||
["ui.click_hold_context_menus.delay", 10000],
|
||||
["apz.max_tap_time", 10000],
|
||||
];
|
||||
|
||||
var subtests = [
|
||||
{'file': 'helper_bug1280013.html', 'prefs': prefs},
|
||||
{'file': 'helper_basic_zoom.html', 'prefs': prefs},
|
||||
{'file': 'helper_zoomed_pan.html', 'prefs': prefs},
|
||||
{'file': 'helper_basic_doubletap_zoom.html', 'prefs': doubletap_prefs},
|
||||
];
|
||||
|
||||
if (isApzEnabled()) {
|
||||
// This has a lot of subtests, and Android emulators are slow.
|
||||
SimpleTest.requestLongerTimeout(2);
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.onload = function() {
|
||||
runSubtestsSeriallyInFreshWindows(subtests)
|
||||
|
|
|
@ -78,7 +78,9 @@ static CSSPoint
|
|||
ScrollFrameTo(nsIScrollableFrame* aFrame, const FrameMetrics& aMetrics, bool& aSuccessOut)
|
||||
{
|
||||
aSuccessOut = false;
|
||||
CSSPoint targetScrollPosition = aMetrics.GetScrollOffset();
|
||||
CSSPoint targetScrollPosition = aMetrics.IsRootContent()
|
||||
? aMetrics.GetViewport().TopLeft()
|
||||
: aMetrics.GetScrollOffset();
|
||||
|
||||
if (!aFrame) {
|
||||
return targetScrollPosition;
|
||||
|
@ -93,18 +95,20 @@ ScrollFrameTo(nsIScrollableFrame* aFrame, const FrameMetrics& aMetrics, bool& aS
|
|||
return geckoScrollPosition;
|
||||
}
|
||||
|
||||
// If the frame is overflow:hidden on a particular axis, we don't want to allow
|
||||
// user-driven scroll on that axis. Simply set the scroll position on that axis
|
||||
// to whatever it already is. Note that this will leave the APZ's async scroll
|
||||
// position out of sync with the gecko scroll position, but APZ can deal with that
|
||||
// (by design). Note also that when we run into this case, even if both axes
|
||||
// have overflow:hidden, we want to set aSuccessOut to true, so that the displayport
|
||||
// follows the async scroll position rather than the gecko scroll position.
|
||||
// If this is the root content with overflow:hidden, then APZ should not
|
||||
// allow scrolling in such a way that moves the layout viewport.
|
||||
//
|
||||
// If this is overflow:hidden, but not the root content, then
|
||||
// nsLayoutUtils::CalculateScrollableRectForFrame should have sized the
|
||||
// scrollable rect in a way that prevents APZ from scrolling it at all.
|
||||
//
|
||||
// In either case, targetScrollPosition should be the same as
|
||||
// geckoScrollPosition here.
|
||||
if (aFrame->GetScrollbarStyles().mVertical == NS_STYLE_OVERFLOW_HIDDEN) {
|
||||
targetScrollPosition.y = geckoScrollPosition.y;
|
||||
MOZ_ASSERT(targetScrollPosition.y == geckoScrollPosition.y);
|
||||
}
|
||||
if (aFrame->GetScrollbarStyles().mHorizontal == NS_STYLE_OVERFLOW_HIDDEN) {
|
||||
targetScrollPosition.x = geckoScrollPosition.x;
|
||||
MOZ_ASSERT(targetScrollPosition.x == geckoScrollPosition.x);
|
||||
}
|
||||
|
||||
// If the scrollable frame is currently in the middle of an async or smooth
|
||||
|
@ -162,6 +166,15 @@ ScrollFrame(nsIContent* aContent,
|
|||
// actual scroll offset.
|
||||
APZCCallbackHelper::AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
|
||||
}
|
||||
} else if (aMetrics.IsRootContent() &&
|
||||
aMetrics.GetScrollOffset() != aMetrics.GetViewport().TopLeft()) {
|
||||
// APZ uses the visual viewport's offset to calculate where to place the
|
||||
// display port, so the display port is misplaced when a pinch zoom occurs.
|
||||
//
|
||||
// We need to force a display port adjustment in the following paint to
|
||||
// account for a difference between mScrollOffset and the actual scroll
|
||||
// offset in repaints requested by AsyncPanZoomController::NotifyLayersUpdated.
|
||||
APZCCallbackHelper::AdjustDisplayPortForScrollDelta(aMetrics, actualScrollOffset);
|
||||
} else {
|
||||
// For whatever reason we couldn't update the scroll offset on the scroll frame,
|
||||
// which means the data APZ used for its displayport calculation is stale. Fall
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
|
||||
/* fluent-dom@0.2.0 */
|
||||
/* fluent-dom@aa95b1f (July 10, 2018) */
|
||||
|
||||
const { Localization } =
|
||||
ChromeUtils.import("resource://gre/modules/Localization.jsm", {});
|
||||
|
@ -403,13 +403,12 @@ const L10N_ELEMENT_QUERY = `[${L10NID_ATTR_NAME}]`;
|
|||
*/
|
||||
class DOMLocalization extends Localization {
|
||||
/**
|
||||
* @param {Window} windowElement
|
||||
* @param {Array<String>} resourceIds - List of resource IDs
|
||||
* @param {Function} generateMessages - Function that returns a
|
||||
* generator over MessageContexts
|
||||
* @returns {DOMLocalization}
|
||||
*/
|
||||
constructor(windowElement, resourceIds, generateMessages) {
|
||||
constructor(resourceIds, generateMessages) {
|
||||
super(resourceIds, generateMessages);
|
||||
|
||||
// A Set of DOM trees observed by the `MutationObserver`.
|
||||
|
@ -418,10 +417,8 @@ class DOMLocalization extends Localization {
|
|||
this.pendingrAF = null;
|
||||
// list of elements pending for translation.
|
||||
this.pendingElements = new Set();
|
||||
this.windowElement = windowElement;
|
||||
this.mutationObserver = new windowElement.MutationObserver(
|
||||
mutations => this.translateMutations(mutations)
|
||||
);
|
||||
this.windowElement = null;
|
||||
this.mutationObserver = null;
|
||||
|
||||
this.observerConfig = {
|
||||
attribute: true,
|
||||
|
@ -519,6 +516,18 @@ class DOMLocalization extends Localization {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.windowElement) {
|
||||
if (this.windowElement !== newRoot.ownerGlobal) {
|
||||
throw new Error(`Cannot connect a root:
|
||||
DOMLocalization already has a root from a different window`);
|
||||
}
|
||||
} else {
|
||||
this.windowElement = newRoot.ownerGlobal;
|
||||
this.mutationObserver = new this.windowElement.MutationObserver(
|
||||
mutations => this.translateMutations(mutations)
|
||||
);
|
||||
}
|
||||
|
||||
this.roots.add(newRoot);
|
||||
this.mutationObserver.observe(newRoot, this.observerConfig);
|
||||
}
|
||||
|
@ -537,11 +546,20 @@ class DOMLocalization extends Localization {
|
|||
*/
|
||||
disconnectRoot(root) {
|
||||
this.roots.delete(root);
|
||||
// Pause and resume the mutation observer to stop observing `root`.
|
||||
// Pause the mutation observer to stop observing `root`.
|
||||
this.pauseObserving();
|
||||
this.resumeObserving();
|
||||
|
||||
return this.roots.size === 0;
|
||||
if (this.roots.size === 0) {
|
||||
this.mutationObserver = null;
|
||||
this.windowElement = null;
|
||||
this.pendingrAF = null;
|
||||
this.pendingElements.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Resume observing all other roots.
|
||||
this.resumeObserving();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -562,6 +580,10 @@ class DOMLocalization extends Localization {
|
|||
* @private
|
||||
*/
|
||||
pauseObserving() {
|
||||
if (!this.mutationObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.translateMutations(this.mutationObserver.takeRecords());
|
||||
this.mutationObserver.disconnect();
|
||||
}
|
||||
|
@ -572,6 +594,10 @@ class DOMLocalization extends Localization {
|
|||
* @private
|
||||
*/
|
||||
resumeObserving() {
|
||||
if (!this.mutationObserver) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const root of this.roots) {
|
||||
this.mutationObserver.observe(root, this.observerConfig);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
|
||||
/* fluent-dom@0.2.0 */
|
||||
/* fluent-dom@aa95b1f (July 10, 2018) */
|
||||
|
||||
/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
|
||||
/* global console */
|
||||
|
@ -109,7 +109,7 @@ class Localization {
|
|||
*
|
||||
* @returns {Localization}
|
||||
*/
|
||||
constructor(resourceIds, generateMessages = defaultGenerateMessages) {
|
||||
constructor(resourceIds = [], generateMessages = defaultGenerateMessages) {
|
||||
this.resourceIds = resourceIds;
|
||||
this.generateMessages = generateMessages;
|
||||
this.ctxs =
|
||||
|
@ -119,11 +119,13 @@ class Localization {
|
|||
addResourceIds(resourceIds) {
|
||||
this.resourceIds.push(...resourceIds);
|
||||
this.onChange();
|
||||
return this.resourceIds.length;
|
||||
}
|
||||
|
||||
removeResourceIds(resourceIds) {
|
||||
this.resourceIds = this.resourceIds.filter(r => !resourceIds.includes(r));
|
||||
this.onChange();
|
||||
return this.resourceIds.length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -277,6 +279,7 @@ class Localization {
|
|||
onChange() {
|
||||
this.ctxs =
|
||||
new CachedAsyncIterable(this.generateMessages(this.resourceIds));
|
||||
this.ctxs.touchNext(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*/
|
||||
|
||||
|
||||
/* fluent@0.6.3 */
|
||||
/* fluent@aa95b1f (July 10, 2018) */
|
||||
|
||||
/* eslint no-magic-numbers: [0] */
|
||||
|
||||
|
@ -1670,6 +1670,22 @@ function resolve(ctx, args, message, errors = []) {
|
|||
return Type(env, message).toString(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fluent Resource is a structure storing a map
|
||||
* of localization entries.
|
||||
*/
|
||||
class FluentResource extends Map {
|
||||
constructor(entries, errors = []) {
|
||||
super(entries);
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
static fromString(source) {
|
||||
const [entries, errors] = parse(source);
|
||||
return new FluentResource(Object.entries(entries), errors);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Message contexts are single-language stores of translations. They are
|
||||
* responsible for parsing translation resources in the Fluent syntax and can
|
||||
|
@ -1712,11 +1728,17 @@ class MessageContext {
|
|||
* - `useIsolating` - boolean specifying whether to use Unicode isolation
|
||||
* marks (FSI, PDI) for bidi interpolations.
|
||||
*
|
||||
* - `transform` - a function used to transform string parts of patterns.
|
||||
*
|
||||
* @param {string|Array<string>} locales - Locale or locales of the context
|
||||
* @param {Object} [options]
|
||||
* @returns {MessageContext}
|
||||
*/
|
||||
constructor(locales, { functions = {}, useIsolating = true, transform = v => v } = {}) {
|
||||
constructor(locales, {
|
||||
functions = {},
|
||||
useIsolating = true,
|
||||
transform = v => v
|
||||
} = {}) {
|
||||
this.locales = Array.isArray(locales) ? locales : [locales];
|
||||
|
||||
this._terms = new Map();
|
||||
|
@ -1778,8 +1800,31 @@ class MessageContext {
|
|||
* @returns {Array<Error>}
|
||||
*/
|
||||
addMessages(source) {
|
||||
const [entries, errors] = parse(source);
|
||||
for (const id in entries) {
|
||||
const res = FluentResource.fromString(source);
|
||||
return this.addResource(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a translation resource to the context.
|
||||
*
|
||||
* The translation resource must be a proper FluentResource
|
||||
* parsed by `MessageContext.parseResource`.
|
||||
*
|
||||
* let res = MessageContext.parseResource("foo = Foo");
|
||||
* ctx.addResource(res);
|
||||
* ctx.getMessage('foo');
|
||||
*
|
||||
* // Returns a raw representation of the 'foo' message.
|
||||
*
|
||||
* Parsed entities should be formatted with the `format` method in case they
|
||||
* contain logic (references, select expressions etc.).
|
||||
*
|
||||
* @param {FluentResource} res - FluentResource object.
|
||||
* @returns {Array<Error>}
|
||||
*/
|
||||
addResource(res) {
|
||||
const errors = res.errors.slice();
|
||||
for (const [id, value] of res) {
|
||||
if (id.startsWith("-")) {
|
||||
// Identifiers starting with a dash (-) define terms. Terms are private
|
||||
// and cannot be retrieved from MessageContext.
|
||||
|
@ -1787,13 +1832,13 @@ class MessageContext {
|
|||
errors.push(`Attempt to override an existing term: "${id}"`);
|
||||
continue;
|
||||
}
|
||||
this._terms.set(id, entries[id]);
|
||||
this._terms.set(id, value);
|
||||
} else {
|
||||
if (this._messages.has(id)) {
|
||||
errors.push(`Attempt to override an existing message: "${id}"`);
|
||||
continue;
|
||||
}
|
||||
this._messages.set(id, entries[id]);
|
||||
this._messages.set(id, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
const resourceIds = getResourceLinks(document.head || document);
|
||||
|
||||
document.l10n = new DOMLocalization(window, resourceIds);
|
||||
document.l10n = new DOMLocalization(resourceIds);
|
||||
|
||||
// Trigger the first two contexts to be loaded eagerly.
|
||||
document.l10n.ctxs.touchNext(2);
|
||||
|
|
|
@ -33,7 +33,6 @@ new-tab
|
|||
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
generateMessages
|
||||
);
|
||||
|
|
|
@ -25,7 +25,6 @@ key2 = Value for <a>Key 2<a/>.
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(async () => {
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
addLoadEvent(async () => {
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -26,7 +26,6 @@ key2 =
|
|||
|
||||
async function test() {
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -25,7 +25,6 @@ key2 = Visit <a data-l10n-name="link">this link<a/>.
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(async () => {
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const domLoc = new DOMLocalization(
|
||||
window,
|
||||
[],
|
||||
mockGenerateMessages
|
||||
);
|
||||
|
|
|
@ -2315,6 +2315,10 @@ BytecodeEmitter::emitSwitch(ParseNode* pn)
|
|||
MOZ_ASSERT(cases->isKind(ParseNodeKind::LexicalScope) ||
|
||||
cases->isKind(ParseNodeKind::StatementList));
|
||||
|
||||
// Ensure that the column of the switch statement is set properly.
|
||||
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
// Emit code for the discriminant.
|
||||
if (!emitTree(pn->pn_left))
|
||||
return false;
|
||||
|
@ -4574,6 +4578,11 @@ BytecodeEmitter::emitIf(ParseNode* pn)
|
|||
IfEmitter ifThenElse(this);
|
||||
|
||||
if_again:
|
||||
// Make sure this code is attributed to the "if" so that it gets a useful
|
||||
// column number, instead of the default 0 value.
|
||||
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
/* Emit code for the condition before pushing stmtInfo. */
|
||||
if (!emitTree(pn->pn_kid1))
|
||||
return false;
|
||||
|
@ -4704,6 +4713,10 @@ BytecodeEmitter::emitLexicalScope(ParseNode* pn)
|
|||
bool
|
||||
BytecodeEmitter::emitWith(ParseNode* pn)
|
||||
{
|
||||
// Ensure that the column of the 'with' is set properly.
|
||||
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
if (!emitTree(pn->pn_left))
|
||||
return false;
|
||||
|
||||
|
@ -5842,6 +5855,10 @@ BytecodeEmitter::emitAsyncWrapper(unsigned index, bool needsHomeObject, bool isA
|
|||
bool
|
||||
BytecodeEmitter::emitDo(ParseNode* pn)
|
||||
{
|
||||
// Ensure that the column of the 'do' is set properly.
|
||||
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
/* Emit an annotated nop so IonBuilder can recognize the 'do' loop. */
|
||||
unsigned noteIndex;
|
||||
if (!newSrcNote(SRC_WHILE, ¬eIndex))
|
||||
|
@ -8495,11 +8512,19 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
|||
break;
|
||||
|
||||
case ParseNodeKind::Break:
|
||||
// Ensure that the column of the 'break' is set properly.
|
||||
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
if (!emitBreak(pn->as<BreakStatement>().label()))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case ParseNodeKind::Continue:
|
||||
// Ensure that the column of the 'continue' is set properly.
|
||||
if (!updateSourceCoordNotes(pn->pn_pos.begin))
|
||||
return false;
|
||||
|
||||
if (!emitContinue(pn->as<ContinueStatement>().label()))
|
||||
return false;
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// Set breakpoints "everywhere" in a function, then call the function and check that
|
||||
// the breakpoints were added are at the expected columns, and the breakpoints
|
||||
// were executed in th expected order.
|
||||
//
|
||||
// `code` is a JS Script. The final line should define a function `f` to validate.
|
||||
// `expectedBpts` is a string of spaces and carets ('^'). Throws if we don't hit
|
||||
// breakpoints on exactly the columns indicated by the carets.
|
||||
// `expectedOrdering` is a string of integer indices for the offsets that are
|
||||
// executed, in the order that then are executed. Test code can also push
|
||||
// additional items into this string using items.push("!").
|
||||
function assertOffsetColumns(code, expectedBpts, expectedOrdering = null) {
|
||||
if (expectedOrdering === null) {
|
||||
// The default ordering simply runs the breakpoints in order.
|
||||
expectedOrdering = Array.from(expectedBpts.match(/\^/g), (_, i) => i).join(" ");
|
||||
}
|
||||
|
||||
// Define the function `f` in a new global.
|
||||
const global = newGlobal();
|
||||
|
||||
const lines = code.split(/\r?\n|\r]/g);
|
||||
const initCode = lines.slice(0, -1).join("\n");
|
||||
const execCode = lines[lines.length - 1];
|
||||
|
||||
// Treat everything but the last line as initialization code.
|
||||
global.eval(initCode);
|
||||
|
||||
// Run the test code itself.
|
||||
global.eval(execCode);
|
||||
|
||||
// Allow some tests to append to a log that will show up in expected ordering.
|
||||
const hits = global.hits = [];
|
||||
const bpts = new Set();
|
||||
|
||||
// Set breakpoints everywhere and call the function.
|
||||
const dbg = new Debugger;
|
||||
const script = dbg.addDebuggee(global).makeDebuggeeValue(global.f).script;
|
||||
for (const offset of script.getAllColumnOffsets()) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
assertEq(offset.columnNumber < execCode.length, true);
|
||||
bpts.add(offset.columnNumber);
|
||||
|
||||
script.setBreakpoint(offset.offset, {
|
||||
hit(frame) {
|
||||
hits.push(offset.columnNumber);
|
||||
},
|
||||
});
|
||||
}
|
||||
global.f(3);
|
||||
|
||||
const actualBpts = Array.from(execCode, (_, i) => {
|
||||
return bpts.has(i) ? "^" : " ";
|
||||
}).join("");
|
||||
|
||||
if (actualBpts.trimEnd() !== expectedBpts.trimEnd()) {
|
||||
throw new Error(`Assertion failed:
|
||||
code: ${execCode}
|
||||
expected bpts: ${expectedBpts}
|
||||
actual bpts: ${actualBpts}\n`);
|
||||
}
|
||||
|
||||
const indexLookup = new Map(
|
||||
Array.from(bpts).sort().map((col, i) => [col, i]));
|
||||
const actualOrdering = hits
|
||||
.map(item => typeof item === "number" ? indexLookup.get(item) : item)
|
||||
.join(" ");
|
||||
|
||||
if (actualOrdering.trimEnd() !== expectedOrdering.trimEnd()) {
|
||||
throw new Error(`Assertion failed:
|
||||
code: ${execCode}
|
||||
bpts: ${expectedBpts}
|
||||
expected order: ${expectedOrdering}
|
||||
actual order: ${actualOrdering}\n`);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// getColumnOffsets correctly places the various parts of a ForStatement.
|
||||
|
||||
var global = newGlobal();
|
||||
Debugger(global).onDebuggerStatement = function (frame) {
|
||||
var script = frame.eval("f").return.script;
|
||||
script.getAllColumnOffsets().forEach(function (offset) {
|
||||
script.setBreakpoint(offset.offset, {
|
||||
hit: function (frame) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
global.log += offset.columnNumber + " ";
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
global.log = '';
|
||||
global.eval("function f(n) { for (var i = 0; i < n; ++i) log += '. '; log += '! '; } debugger;");
|
||||
global.f(3);
|
||||
assertEq(global.log, "25 32 44 . 39 32 44 . 39 32 44 . 39 32 57 ! 70 ");
|
|
@ -1,21 +0,0 @@
|
|||
// getColumnOffsets correctly places multiple variable declarations.
|
||||
|
||||
var global = newGlobal();
|
||||
Debugger(global).onDebuggerStatement = function (frame) {
|
||||
var script = frame.eval("f").return.script;
|
||||
script.getAllColumnOffsets().forEach(function (offset) {
|
||||
script.setBreakpoint(offset.offset, {
|
||||
hit: function (frame) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
global.log += offset.columnNumber + " ";
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
global.log = '';
|
||||
global.eval("function f(n){var w0,x1=3,y2=4,z3=9} debugger;");
|
||||
global.f(3);
|
||||
|
||||
// Should have hit each variable declared.
|
||||
assertEq(global.log, "21 26 31 35 ");
|
|
@ -1,20 +0,0 @@
|
|||
// getColumnOffsets correctly places comma separated expressions.
|
||||
|
||||
var global = newGlobal();
|
||||
Debugger(global).onDebuggerStatement = function (frame) {
|
||||
var script = frame.eval("f").return.script;
|
||||
script.getAllColumnOffsets().forEach(function (offset) {
|
||||
script.setBreakpoint(offset.offset, {
|
||||
hit: function (frame) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
global.log += offset.columnNumber + " ";
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
global.log = '';
|
||||
global.eval("function f(n){print(n),print(n),print(n)} debugger;");
|
||||
global.f(3);
|
||||
// Should hit each call that was separated by commas.
|
||||
assertEq(global.log, "14 23 32 40 ");
|
|
@ -1,20 +0,0 @@
|
|||
// getColumnOffsets correctly places object properties.
|
||||
|
||||
var global = newGlobal();
|
||||
Debugger(global).onDebuggerStatement = function (frame) {
|
||||
var script = frame.eval("f").return.script;
|
||||
script.getAllColumnOffsets().forEach(function (offset) {
|
||||
script.setBreakpoint(offset.offset, {
|
||||
hit: function (frame) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
global.log += offset.columnNumber + " ";
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
global.log = '';
|
||||
global.eval("function f(n){var o={a:1,b:2,c:3}} debugger;");
|
||||
global.f(3);
|
||||
// Should hit each property in the object.
|
||||
assertEq(global.log, "18 21 25 29 33 ");
|
|
@ -1,20 +0,0 @@
|
|||
// getColumnOffsets correctly places array properties.
|
||||
|
||||
var global = newGlobal();
|
||||
Debugger(global).onDebuggerStatement = function (frame) {
|
||||
var script = frame.eval("f").return.script;
|
||||
script.getAllColumnOffsets().forEach(function (offset) {
|
||||
script.setBreakpoint(offset.offset, {
|
||||
hit: function (frame) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
global.log += offset.columnNumber + " ";
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
global.log = '';
|
||||
global.eval("function f(n){var a=[1,2,n]} debugger;");
|
||||
global.f(3);
|
||||
// Should hit each item in the array.
|
||||
assertEq(global.log, "18 21 23 25 27 ");
|
|
@ -1,28 +0,0 @@
|
|||
// getColumnOffsets correctly places function calls.
|
||||
|
||||
var global = newGlobal();
|
||||
Debugger(global).onDebuggerStatement = function (frame) {
|
||||
var script = frame.eval("f").return.script;
|
||||
script.getAllColumnOffsets().forEach(function (offset) {
|
||||
script.setBreakpoint(offset.offset, {
|
||||
hit: function (frame) {
|
||||
assertEq(offset.lineNumber, 1);
|
||||
global.log += offset.columnNumber + " ";
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
global.log = "";
|
||||
global.eval("function ppppp() { return 1; }");
|
||||
// 1 2 3 4
|
||||
// 01234567890123456789012345678901234567890123456789
|
||||
global.eval("function f(){ 1 && ppppp(ppppp()) && new Error() } debugger;");
|
||||
global.f();
|
||||
|
||||
// 14 - Enter the function body
|
||||
// 25 - Inner print()
|
||||
// 19 - Outer print()
|
||||
// 37 - new Error()
|
||||
// 49 - Exit the function body
|
||||
assertEq(global.log, "14 25 19 37 49 ");
|
|
@ -0,0 +1,85 @@
|
|||
load(libdir + "assert-offset-columns.js");
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a ForStatement.
|
||||
assertOffsetColumns(
|
||||
"function f(n) { for (var i = 0; i < n; ++i) hits.push('.'); hits.push('!'); }",
|
||||
" ^ ^ ^ ^ ^ ^",
|
||||
"0 1 3 . 2 1 3 . 2 1 3 . 2 1 4 ! 5",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places multiple variable declarations.
|
||||
assertOffsetColumns(
|
||||
"function f(n){var w0,x1=3,y2=4,z3=9}",
|
||||
" ^ ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places comma separated expressions.
|
||||
assertOffsetColumns(
|
||||
"function f(n){print(n),print(n),print(n)}",
|
||||
" ^ ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places object properties.
|
||||
assertOffsetColumns(
|
||||
// Should hit each property in the object.
|
||||
"function f(n){var o={a:1,b:2,c:3}}",
|
||||
" ^ ^ ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places array properties.
|
||||
assertOffsetColumns(
|
||||
// Should hit each item in the array.
|
||||
"function f(n){var a=[1,2,n]}",
|
||||
" ^ ^ ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places function calls.
|
||||
assertOffsetColumns(
|
||||
"function ppppp() { return 1; }\n" +
|
||||
"function f(){ 1 && ppppp(ppppp()) && new Error() }",
|
||||
" ^ ^ ^ ^ ^",
|
||||
"0 2 1 3 4",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a SwitchStatement.
|
||||
assertOffsetColumns(
|
||||
"function f(n) { switch(n) { default: print(n); } }",
|
||||
" ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a BreakStatement.
|
||||
assertOffsetColumns(
|
||||
"function f(n) { do { print(n); break; } while(false); }",
|
||||
" ^ ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a ContinueStatement.
|
||||
assertOffsetColumns(
|
||||
"function f(n) { do { print(n); continue; } while(false); }",
|
||||
" ^ ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a WithStatement.
|
||||
assertOffsetColumns(
|
||||
"function f(n) { with({}) { print(n); } }",
|
||||
" ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a IfStatement.
|
||||
assertOffsetColumns(
|
||||
"function f(n) { if (n == 3) print(n); }",
|
||||
" ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a IfStatement
|
||||
// with an if/else
|
||||
assertOffsetColumns(
|
||||
"function f(n) { if (n == 2); else if (n === 3) print(n); }",
|
||||
" ^ ^ ^ ^",
|
||||
);
|
||||
|
||||
// getColumnOffsets correctly places the various parts of a DoWhileStatement.
|
||||
assertOffsetColumns(
|
||||
"function f(n) { do { print(n); } while(false); }",
|
||||
" ^ ^ ^",
|
||||
);
|
|
@ -1455,7 +1455,7 @@
|
|||
* Pushes a JS_UNINITIALIZED_LEXICAL value onto the stack, representing an
|
||||
* uninitialized lexical binding.
|
||||
*
|
||||
* This opcode is used with the JSOP_INITLET opcode.
|
||||
* This opcode is used with the JSOP_INITLEXICAL opcode.
|
||||
* Category: Literals
|
||||
* Type: Constants
|
||||
* Operands:
|
||||
|
@ -2025,7 +2025,7 @@
|
|||
/* Lexical environment support. */ \
|
||||
/*
|
||||
* Replaces the current block on the env chain with a fresh block
|
||||
* that copies all the bindings in the bock. This operation implements the
|
||||
* that copies all the bindings in the block. This operation implements the
|
||||
* behavior of inducing a fresh lexical environment for every iteration of a
|
||||
* for(let ...; ...; ...) loop, if any declarations induced by such a loop
|
||||
* are captured within the loop.
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#define STARTUP_COMPLETE_TOPIC "browser-delayed-startup-finished"
|
||||
#define DOC_ELEM_INSERTED_TOPIC "document-element-inserted"
|
||||
#define CONTENT_DOCUMENT_LOADED_TOPIC "content-document-loaded"
|
||||
#define CACHE_WRITE_TOPIC "browser-idle-startup-tasks-finished"
|
||||
#define CLEANUP_TOPIC "xpcom-shutdown"
|
||||
#define SHUTDOWN_TOPIC "quit-application-granted"
|
||||
|
@ -240,10 +241,10 @@ ScriptPreloader::ScriptPreloader()
|
|||
: mMonitor("[ScriptPreloader.mMonitor]")
|
||||
, mSaveMonitor("[ScriptPreloader.mSaveMonitor]")
|
||||
{
|
||||
// We do not set the process type for child processes here because the
|
||||
// remoteType in ContentChild is not ready yet.
|
||||
if (XRE_IsParentProcess()) {
|
||||
sProcessType = ProcessType::Parent;
|
||||
} else {
|
||||
sProcessType = GetChildProcessType(dom::ContentChild::GetSingleton()->GetRemoteType());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
|
@ -254,13 +255,8 @@ ScriptPreloader::ScriptPreloader()
|
|||
// as idle tasks for the first browser window have completed.
|
||||
obs->AddObserver(this, STARTUP_COMPLETE_TOPIC, false);
|
||||
obs->AddObserver(this, CACHE_WRITE_TOPIC, false);
|
||||
} else {
|
||||
// In the child process, we need to freeze the script cache before any
|
||||
// untrusted code has been executed. The insertion of the first DOM
|
||||
// document element may sometimes be earlier than is ideal, but at
|
||||
// least it should always be safe.
|
||||
obs->AddObserver(this, DOC_ELEM_INSERTED_TOPIC, false);
|
||||
}
|
||||
|
||||
obs->AddObserver(this, SHUTDOWN_TOPIC, false);
|
||||
obs->AddObserver(this, CLEANUP_TOPIC, false);
|
||||
obs->AddObserver(this, CACHE_INVALIDATE_TOPIC, false);
|
||||
|
@ -367,6 +363,7 @@ ScriptPreloader::Observe(nsISupports* subject, const char* topic, const char16_t
|
|||
mStartupFinished = true;
|
||||
} else if (!strcmp(topic, CACHE_WRITE_TOPIC)) {
|
||||
obs->RemoveObserver(this, CACHE_WRITE_TOPIC);
|
||||
|
||||
MOZ_ASSERT(mStartupFinished);
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
|
@ -374,7 +371,7 @@ ScriptPreloader::Observe(nsISupports* subject, const char* topic, const char16_t
|
|||
Unused << NS_NewNamedThread("SaveScripts",
|
||||
getter_AddRefs(mSaveThread), this);
|
||||
}
|
||||
} else if (!strcmp(topic, DOC_ELEM_INSERTED_TOPIC)) {
|
||||
} else if (mContentStartupFinishedTopic.Equals(topic)) {
|
||||
// If this is an uninitialized about:blank viewer or a chrome: document
|
||||
// (which should always be an XBL binding document), ignore it. We don't
|
||||
// have to worry about it loading malicious content.
|
||||
|
@ -407,8 +404,16 @@ ScriptPreloader::FinishContentStartup()
|
|||
{
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
|
||||
#ifdef DEBUG
|
||||
if (mContentStartupFinishedTopic.Equals(CONTENT_DOCUMENT_LOADED_TOPIC)) {
|
||||
MOZ_ASSERT(sProcessType == ProcessType::Privileged);
|
||||
} else {
|
||||
MOZ_ASSERT(sProcessType != ProcessType::Privileged);
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->RemoveObserver(this, DOC_ELEM_INSERTED_TOPIC);
|
||||
obs->RemoveObserver(this, mContentStartupFinishedTopic.get());
|
||||
|
||||
mSaveTimer = nullptr;
|
||||
|
||||
|
@ -441,7 +446,7 @@ ScriptPreloader::GetCacheFile(const nsAString& suffix)
|
|||
return std::move(cacheFile);
|
||||
}
|
||||
|
||||
static const uint8_t MAGIC[] = "mozXDRcachev001";
|
||||
static const uint8_t MAGIC[] = "mozXDRcachev002";
|
||||
|
||||
Result<Ok, nsresult>
|
||||
ScriptPreloader::OpenCache()
|
||||
|
@ -503,6 +508,25 @@ ScriptPreloader::InitCache(const Maybe<ipc::FileDescriptor>& cacheFile, ScriptCa
|
|||
|
||||
mCacheInitialized = true;
|
||||
mChildActor = cacheChild;
|
||||
sProcessType = GetChildProcessType(dom::ContentChild::GetSingleton()->GetRemoteType());
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
MOZ_RELEASE_ASSERT(obs);
|
||||
|
||||
if (sProcessType == ProcessType::Privileged) {
|
||||
// Since we control all of the documents loaded in the privileged
|
||||
// content process, we can increase the window of active time for the
|
||||
// ScriptPreloader to include the scripts that are loaded until the
|
||||
// first document finishes loading.
|
||||
mContentStartupFinishedTopic.AssignLiteral(CONTENT_DOCUMENT_LOADED_TOPIC);
|
||||
} else {
|
||||
// In the child process, we need to freeze the script cache before any
|
||||
// untrusted code has been executed. The insertion of the first DOM
|
||||
// document element may sometimes be earlier than is ideal, but at
|
||||
// least it should always be safe.
|
||||
mContentStartupFinishedTopic.AssignLiteral(DOC_ELEM_INSERTED_TOPIC);
|
||||
}
|
||||
obs->AddObserver(this, mContentStartupFinishedTopic.get(), false);
|
||||
|
||||
RegisterWeakMemoryReporter(this);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ namespace loader {
|
|||
class ScriptCacheChild;
|
||||
|
||||
enum class ProcessType : uint8_t {
|
||||
Uninitialized,
|
||||
Parent,
|
||||
Web,
|
||||
Extension,
|
||||
|
@ -111,6 +112,7 @@ public:
|
|||
|
||||
static ProcessType CurrentProcessType()
|
||||
{
|
||||
MOZ_ASSERT(sProcessType != ProcessType::Uninitialized);
|
||||
return sProcessType;
|
||||
}
|
||||
|
||||
|
@ -490,6 +492,7 @@ private:
|
|||
ScriptCacheChild* mChildActor = nullptr;
|
||||
|
||||
nsString mBaseName;
|
||||
nsCString mContentStartupFinishedTopic;
|
||||
|
||||
nsCOMPtr<nsIFile> mProfD;
|
||||
nsCOMPtr<nsIThread> mSaveThread;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIFileURL.h"
|
||||
#include "ContentPrincipal.h"
|
||||
#include "SystemPrincipal.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
@ -135,7 +137,7 @@ ReportError(JSContext* cx, const char* origMsg, nsIURI* uri)
|
|||
static bool
|
||||
PrepareScript(nsIURI* uri,
|
||||
JSContext* cx,
|
||||
HandleObject targetObj,
|
||||
bool wantGlobalScript,
|
||||
const char* uriStr,
|
||||
const nsAString& charset,
|
||||
const char* buf,
|
||||
|
@ -162,7 +164,7 @@ PrepareScript(nsIURI* uri,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (JS_IsGlobalObject(targetObj)) {
|
||||
if (wantGlobalScript) {
|
||||
return JS::Compile(cx, options, srcBuf, script);
|
||||
}
|
||||
return JS::CompileForNonSyntacticScope(cx, options, srcBuf, script);
|
||||
|
@ -170,7 +172,7 @@ PrepareScript(nsIURI* uri,
|
|||
// We only use lazy source when no special encoding is specified because
|
||||
// the lazy source loader doesn't know the encoding.
|
||||
options.setSourceIsLazy(true);
|
||||
if (JS_IsGlobalObject(targetObj)) {
|
||||
if (wantGlobalScript) {
|
||||
return JS::Compile(cx, options, buf, len, script);
|
||||
}
|
||||
return JS::CompileForNonSyntacticScope(cx, options, buf, len, script);
|
||||
|
@ -252,7 +254,9 @@ EvalScript(JSContext* cx,
|
|||
// needed during the last startup in that scope. But for startups
|
||||
// when a non-cached script is used (e.g., after add-on
|
||||
// installation), this may be a Sandbox global, which may be
|
||||
// nuked but held alive by the JSScript.
|
||||
// nuked but held alive by the JSScript. We can avoid this problem
|
||||
// by using a different scope when compiling the script. See
|
||||
// useCompilationScope in ReadScript().
|
||||
//
|
||||
// In general, this isn't a problem, since add-on Sandboxes which
|
||||
// use the script preloader are not destroyed until add-on shutdown,
|
||||
|
@ -417,8 +421,8 @@ AsyncScriptLoader::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
|
|||
RootedObject targetObj(cx, mTargetObj);
|
||||
RootedObject loadScope(cx, mLoadScope);
|
||||
|
||||
if (!PrepareScript(uri, cx, targetObj, spec.get(), mCharset,
|
||||
reinterpret_cast<const char*>(aBuf), aLength,
|
||||
if (!PrepareScript(uri, cx, JS_IsGlobalObject(targetObj), spec.get(),
|
||||
mCharset, reinterpret_cast<const char*>(aBuf), aLength,
|
||||
mWantReturnValue, &script))
|
||||
{
|
||||
return NS_OK;
|
||||
|
@ -506,6 +510,7 @@ mozJSSubScriptLoader::ReadScript(nsIURI* uri,
|
|||
const char* uriStr,
|
||||
nsIIOService* serv,
|
||||
bool wantReturnValue,
|
||||
bool useCompilationScope,
|
||||
MutableHandleScript script)
|
||||
{
|
||||
script.set(nullptr);
|
||||
|
@ -553,8 +558,22 @@ mozJSSubScriptLoader::ReadScript(nsIURI* uri,
|
|||
rv = NS_ReadInputStreamToString(instream, buf, len);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return PrepareScript(uri, cx, targetObj, uriStr, charset,
|
||||
buf.get(), len, wantReturnValue,
|
||||
Maybe<JSAutoRealm> ar;
|
||||
|
||||
// Note that when using the ScriptPreloader cache with loadSubScript, there
|
||||
// will be a side-effect of keeping the global that the script was compiled
|
||||
// for alive. See note above in EvalScript().
|
||||
//
|
||||
// This will compile the script in XPConnect compilation scope. When the
|
||||
// script is evaluated, it will be cloned into the target scope to be
|
||||
// executed, avoiding leaks on the first session when we don't have a
|
||||
// startup cache.
|
||||
if (useCompilationScope) {
|
||||
ar.emplace(cx, xpc::CompilationScope());
|
||||
}
|
||||
|
||||
return PrepareScript(uri, cx, JS_IsGlobalObject(targetObj),
|
||||
uriStr, charset, buf.get(), len, wantReturnValue,
|
||||
script);
|
||||
}
|
||||
|
||||
|
@ -690,9 +709,29 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
|
|||
|
||||
// Suppress caching if we're compiling as content or if we're loading a
|
||||
// blob: URI.
|
||||
bool ignoreCache = options.ignoreCache
|
||||
|| !GetObjectPrincipal(targetObj)->GetIsSystemPrincipal()
|
||||
|| scheme.EqualsLiteral("blob");
|
||||
bool useCompilationScope = false;
|
||||
auto* principal = BasePrincipal::Cast(GetObjectPrincipal(targetObj));
|
||||
bool isSystem = principal->Is<SystemPrincipal>();
|
||||
if (!isSystem && principal->Is<ContentPrincipal>()) {
|
||||
auto* content = principal->As<ContentPrincipal>();
|
||||
|
||||
nsAutoCString scheme;
|
||||
content->mCodebase->GetScheme(scheme);
|
||||
|
||||
// We want to enable caching for scripts with Activity Stream's
|
||||
// codebase URLs.
|
||||
if (scheme.EqualsLiteral("about")) {
|
||||
nsAutoCString filePath;
|
||||
content->mCodebase->GetFilePath(filePath);
|
||||
|
||||
useCompilationScope = filePath.EqualsLiteral("home") ||
|
||||
filePath.EqualsLiteral("newtab") ||
|
||||
filePath.EqualsLiteral("welcome");
|
||||
isSystem = true;
|
||||
}
|
||||
}
|
||||
bool ignoreCache = options.ignoreCache || !isSystem || scheme.EqualsLiteral("blob");
|
||||
|
||||
StartupCache* cache = ignoreCache ? nullptr : StartupCache::GetSingleton();
|
||||
|
||||
nsAutoCString cachePath;
|
||||
|
@ -722,7 +761,7 @@ mozJSSubScriptLoader::DoLoadSubScriptWithOptions(const nsAString& url,
|
|||
cache = nullptr;
|
||||
} else if (!ReadScript(uri, cx, targetObj, options.charset,
|
||||
static_cast<const char*>(uriStr.get()), serv,
|
||||
options.wantReturnValue, &script)) {
|
||||
options.wantReturnValue, useCompilationScope, &script)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ private:
|
|||
bool ReadScript(nsIURI* uri, JSContext* cx, JS::HandleObject targetObj,
|
||||
const nsAString& charset, const char* uriStr,
|
||||
nsIIOService* serv,
|
||||
bool wantReturnValue,
|
||||
bool wantReturnValue, bool useCompilationScope,
|
||||
JS::MutableHandleScript script);
|
||||
|
||||
nsresult ReadScriptAsync(nsIURI* uri,
|
||||
|
|
|
@ -4,7 +4,7 @@ import os
|
|||
import struct
|
||||
import sys
|
||||
|
||||
MAGIC = b'mozXDRcachev001\0'
|
||||
MAGIC = b'mozXDRcachev002\0'
|
||||
|
||||
|
||||
def usage():
|
||||
|
@ -17,17 +17,20 @@ def usage():
|
|||
|
||||
|
||||
class ProcessTypes:
|
||||
Default = 0
|
||||
Web = 1
|
||||
Extension = 2
|
||||
Privileged = 3
|
||||
Uninitialized = 0
|
||||
Parent = 1
|
||||
Web = 2
|
||||
Extension = 3
|
||||
Privileged = 4
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
|
||||
def __str__(self):
|
||||
res = []
|
||||
if self.val & (1 << self.Default):
|
||||
if self.val & (1 << self.Uninitialized):
|
||||
raise Exception('Uninitialized process type')
|
||||
if self.val & (1 << self.Parent):
|
||||
res.append('Parent')
|
||||
if self.val & (1 << self.Web):
|
||||
res.append('Web')
|
||||
|
|
|
@ -4106,11 +4106,11 @@ nsLayoutUtils::GetFirstNonAnonymousFrame(nsIFrame* aFrame)
|
|||
}
|
||||
|
||||
struct BoxToRect : public nsLayoutUtils::BoxCallback {
|
||||
nsIFrame* mRelativeTo;
|
||||
const nsIFrame* mRelativeTo;
|
||||
nsLayoutUtils::RectCallback* mCallback;
|
||||
uint32_t mFlags;
|
||||
|
||||
BoxToRect(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
|
||||
BoxToRect(const nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
|
||||
uint32_t aFlags)
|
||||
: mRelativeTo(aRelativeTo), mCallback(aCallback), mFlags(aFlags) {}
|
||||
|
||||
|
@ -4145,7 +4145,7 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
|
|||
struct MOZ_RAII BoxToRectAndText : public BoxToRect {
|
||||
Sequence<nsString>* mTextList;
|
||||
|
||||
BoxToRectAndText(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
|
||||
BoxToRectAndText(const nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
|
||||
Sequence<nsString>* aTextList, uint32_t aFlags)
|
||||
: BoxToRect(aRelativeTo, aCallback, aFlags), mTextList(aTextList) {}
|
||||
|
||||
|
@ -4185,7 +4185,7 @@ struct MOZ_RAII BoxToRectAndText : public BoxToRect {
|
|||
};
|
||||
|
||||
void
|
||||
nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, const nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback, uint32_t aFlags)
|
||||
{
|
||||
BoxToRect converter(aRelativeTo, aCallback, aFlags);
|
||||
|
@ -4193,7 +4193,8 @@ nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
|||
}
|
||||
|
||||
void
|
||||
nsLayoutUtils::GetAllInFlowRectsAndTexts(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
nsLayoutUtils::GetAllInFlowRectsAndTexts(nsIFrame* aFrame,
|
||||
const nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback,
|
||||
Sequence<nsString>* aTextList,
|
||||
uint32_t aFlags)
|
||||
|
@ -4230,7 +4231,7 @@ nsIFrame* nsLayoutUtils::GetContainingBlockForClientRect(nsIFrame* aFrame)
|
|||
}
|
||||
|
||||
nsRect
|
||||
nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame, const nsIFrame* aRelativeTo,
|
||||
uint32_t aFlags) {
|
||||
RectAccumulator accumulator;
|
||||
GetAllInFlowRects(aFrame, aRelativeTo, &accumulator, aFlags);
|
||||
|
@ -9121,8 +9122,12 @@ nsLayoutUtils::ComputeScrollMetadata(nsIFrame* aForFrame,
|
|||
nsLayoutUtils::CalculateScrollableRectForFrame(scrollableFrame, aForFrame)));
|
||||
|
||||
if (scrollableFrame) {
|
||||
nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
|
||||
metrics.SetScrollOffset(CSSPoint::FromAppUnits(scrollPosition));
|
||||
CSSPoint scrollPosition = CSSPoint::FromAppUnits(scrollableFrame->GetScrollPosition());
|
||||
metrics.SetScrollOffset(scrollPosition);
|
||||
|
||||
CSSRect viewport = metrics.GetViewport();
|
||||
viewport.MoveTo(scrollPosition);
|
||||
metrics.SetViewport(viewport);
|
||||
|
||||
nsPoint smoothScrollPosition = scrollableFrame->LastScrollDestination();
|
||||
metrics.SetSmoothScrollOffset(CSSPoint::FromAppUnits(smoothScrollPosition));
|
||||
|
|
|
@ -1221,10 +1221,11 @@ public:
|
|||
* or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.
|
||||
* Otherwise (by default), the border box is used.
|
||||
*/
|
||||
static void GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
static void GetAllInFlowRects(nsIFrame* aFrame, const nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback, uint32_t aFlags = 0);
|
||||
|
||||
static void GetAllInFlowRectsAndTexts(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
static void GetAllInFlowRectsAndTexts(nsIFrame* aFrame,
|
||||
const nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback,
|
||||
mozilla::dom::Sequence<nsString>* aTextList,
|
||||
uint32_t aFlags = 0);
|
||||
|
@ -1239,7 +1240,7 @@ public:
|
|||
* or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.
|
||||
* Otherwise (by default), the border box is used.
|
||||
*/
|
||||
static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame, const nsIFrame* aRelativeTo,
|
||||
uint32_t aFlags = 0);
|
||||
|
||||
enum {
|
||||
|
|
|
@ -144,7 +144,6 @@ namespace mozilla {
|
|||
class RefreshDriverTimer {
|
||||
public:
|
||||
RefreshDriverTimer()
|
||||
: mLastFireEpoch(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -202,7 +201,6 @@ public:
|
|||
}
|
||||
|
||||
TimeStamp MostRecentRefresh() const { return mLastFireTime; }
|
||||
int64_t MostRecentRefreshEpochTime() const { return mLastFireEpoch; }
|
||||
|
||||
void SwapRefreshDrivers(RefreshDriverTimer* aNewTimer)
|
||||
{
|
||||
|
@ -220,7 +218,6 @@ public:
|
|||
}
|
||||
mRootRefreshDrivers.Clear();
|
||||
|
||||
aNewTimer->mLastFireEpoch = mLastFireEpoch;
|
||||
aNewTimer->mLastFireTime = mLastFireTime;
|
||||
|
||||
StopTimer();
|
||||
|
@ -278,16 +275,15 @@ protected:
|
|||
|
||||
/*
|
||||
* Actually runs a tick, poking all the attached RefreshDrivers.
|
||||
* Grabs the "now" time via JS_Now and TimeStamp::Now().
|
||||
* Grabs the "now" time via TimeStamp::Now().
|
||||
*/
|
||||
void Tick()
|
||||
{
|
||||
int64_t jsnow = JS_Now();
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
Tick(jsnow, now);
|
||||
Tick(now);
|
||||
}
|
||||
|
||||
void TickRefreshDrivers(int64_t aJsNow, TimeStamp aNow, nsTArray<RefPtr<nsRefreshDriver>>& aDrivers)
|
||||
void TickRefreshDrivers(TimeStamp aNow, nsTArray<RefPtr<nsRefreshDriver>>& aDrivers)
|
||||
{
|
||||
if (aDrivers.IsEmpty()) {
|
||||
return;
|
||||
|
@ -300,37 +296,34 @@ protected:
|
|||
continue;
|
||||
}
|
||||
|
||||
TickDriver(driver, aJsNow, aNow);
|
||||
TickDriver(driver, aNow);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Tick the refresh drivers based on the given timestamp.
|
||||
*/
|
||||
void Tick(int64_t jsnow, TimeStamp now)
|
||||
void Tick(TimeStamp now)
|
||||
{
|
||||
ScheduleNextTick(now);
|
||||
|
||||
mLastFireEpoch = jsnow;
|
||||
mLastFireTime = now;
|
||||
|
||||
LOG("[%p] ticking drivers...", this);
|
||||
// RD is short for RefreshDriver
|
||||
AUTO_PROFILER_TRACING("Paint", "RefreshDriverTick");
|
||||
|
||||
TickRefreshDrivers(jsnow, now, mContentRefreshDrivers);
|
||||
TickRefreshDrivers(jsnow, now, mRootRefreshDrivers);
|
||||
TickRefreshDrivers(now, mContentRefreshDrivers);
|
||||
TickRefreshDrivers(now, mRootRefreshDrivers);
|
||||
|
||||
LOG("[%p] done.", this);
|
||||
}
|
||||
|
||||
static void TickDriver(nsRefreshDriver* driver, int64_t jsnow, TimeStamp now)
|
||||
static void TickDriver(nsRefreshDriver* driver, TimeStamp now)
|
||||
{
|
||||
LOG(">> TickDriver: %p (jsnow: %" PRId64 ")", driver, jsnow);
|
||||
driver->Tick(jsnow, now);
|
||||
driver->Tick(now);
|
||||
}
|
||||
|
||||
int64_t mLastFireEpoch;
|
||||
TimeStamp mLastFireTime;
|
||||
TimeStamp mTargetTime;
|
||||
|
||||
|
@ -394,7 +387,6 @@ protected:
|
|||
void StartTimer() override
|
||||
{
|
||||
// pretend we just fired, and we schedule the next tick normally
|
||||
mLastFireEpoch = JS_Now();
|
||||
mLastFireTime = TimeStamp::Now();
|
||||
|
||||
mTargetTime = mLastFireTime + mRateDuration;
|
||||
|
@ -725,7 +717,6 @@ private:
|
|||
// Protect updates to `sActiveVsyncTimers`.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mLastFireEpoch = JS_Now();
|
||||
mLastFireTime = TimeStamp::Now();
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
|
@ -761,10 +752,7 @@ private:
|
|||
|
||||
void RunRefreshDrivers(TimeStamp aTimeStamp)
|
||||
{
|
||||
int64_t jsnow = JS_Now();
|
||||
TimeDuration diff = TimeStamp::Now() - aTimeStamp;
|
||||
int64_t vsyncJsNow = jsnow - diff.ToMicroseconds();
|
||||
Tick(vsyncJsNow, aTimeStamp);
|
||||
Tick(aTimeStamp);
|
||||
}
|
||||
|
||||
RefPtr<RefreshDriverVsyncObserver> mVsyncObserver;
|
||||
|
@ -885,7 +873,6 @@ protected:
|
|||
|
||||
void StartTimer() override
|
||||
{
|
||||
mLastFireEpoch = JS_Now();
|
||||
mLastFireTime = TimeStamp::Now();
|
||||
|
||||
mTargetTime = mLastFireTime + mRateDuration;
|
||||
|
@ -936,12 +923,10 @@ protected:
|
|||
/* Runs just one driver's tick. */
|
||||
void TickOne()
|
||||
{
|
||||
int64_t jsnow = JS_Now();
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
||||
ScheduleNextTick(now);
|
||||
|
||||
mLastFireEpoch = jsnow;
|
||||
mLastFireTime = now;
|
||||
|
||||
nsTArray<RefPtr<nsRefreshDriver>> drivers(mContentRefreshDrivers);
|
||||
|
@ -951,7 +936,7 @@ protected:
|
|||
if (index < drivers.Length() &&
|
||||
!drivers[index]->IsTestControllingRefreshesEnabled())
|
||||
{
|
||||
TickDriver(drivers[index], jsnow, now);
|
||||
TickDriver(drivers[index], now);
|
||||
}
|
||||
|
||||
mNextDriverIndex++;
|
||||
|
@ -1147,7 +1132,6 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
|
|||
MOZ_ASSERT(mPresContext,
|
||||
"Need a pres context to tell us to call Disconnect() later "
|
||||
"and decrement sRefreshDriverCount.");
|
||||
mMostRecentRefreshEpochTime = JS_Now();
|
||||
mMostRecentRefresh = TimeStamp::Now();
|
||||
mMostRecentTick = mMostRecentRefresh;
|
||||
mNextThrottledFrameRequestTick = mMostRecentTick;
|
||||
|
@ -1182,7 +1166,6 @@ nsRefreshDriver::AdvanceTimeAndRefresh(int64_t aMilliseconds)
|
|||
StopTimer();
|
||||
|
||||
if (!mTestControllingRefreshes) {
|
||||
mMostRecentRefreshEpochTime = JS_Now();
|
||||
mMostRecentRefresh = TimeStamp::Now();
|
||||
|
||||
mTestControllingRefreshes = true;
|
||||
|
@ -1194,7 +1177,6 @@ nsRefreshDriver::AdvanceTimeAndRefresh(int64_t aMilliseconds)
|
|||
}
|
||||
}
|
||||
|
||||
mMostRecentRefreshEpochTime += aMilliseconds * 1000;
|
||||
mMostRecentRefresh += TimeDuration::FromMilliseconds((double) aMilliseconds);
|
||||
|
||||
mozilla::dom::AutoNoJSAPI nojsapi;
|
||||
|
@ -1221,14 +1203,6 @@ nsRefreshDriver::MostRecentRefresh() const
|
|||
return mMostRecentRefresh;
|
||||
}
|
||||
|
||||
int64_t
|
||||
nsRefreshDriver::MostRecentRefreshEpochTime() const
|
||||
{
|
||||
const_cast<nsRefreshDriver*>(this)->EnsureTimerStarted();
|
||||
|
||||
return mMostRecentRefreshEpochTime;
|
||||
}
|
||||
|
||||
bool
|
||||
nsRefreshDriver::AddRefreshObserver(nsARefreshObserver* aObserver,
|
||||
FlushType aFlushType)
|
||||
|
@ -1408,11 +1382,6 @@ nsRefreshDriver::EnsureTimerStarted(EnsureTimerStartedFlags aFlags)
|
|||
aFlags & eAllowTimeToGoBackwards
|
||||
? mActiveTimer->MostRecentRefresh()
|
||||
: std::max(mActiveTimer->MostRecentRefresh(), mMostRecentRefresh);
|
||||
mMostRecentRefreshEpochTime =
|
||||
aFlags & eAllowTimeToGoBackwards
|
||||
? mActiveTimer->MostRecentRefreshEpochTime()
|
||||
: std::max(mActiveTimer->MostRecentRefreshEpochTime(),
|
||||
mMostRecentRefreshEpochTime);
|
||||
|
||||
if (mMostRecentRefresh != newMostRecentRefresh) {
|
||||
mMostRecentRefresh = newMostRecentRefresh;
|
||||
|
@ -1526,9 +1495,9 @@ nsRefreshDriver::DoTick()
|
|||
"Shouldn't have a JSContext on the stack");
|
||||
|
||||
if (mTestControllingRefreshes) {
|
||||
Tick(mMostRecentRefreshEpochTime, mMostRecentRefresh);
|
||||
Tick(mMostRecentRefresh);
|
||||
} else {
|
||||
Tick(JS_Now(), TimeStamp::Now());
|
||||
Tick(TimeStamp::Now());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1789,7 +1758,7 @@ nsRefreshDriver::CancelIdleRunnable(nsIRunnable* aRunnable)
|
|||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
nsRefreshDriver::Tick(TimeStamp aNowTime)
|
||||
{
|
||||
MOZ_ASSERT(!nsContentUtils::GetCurrentJSContext(),
|
||||
"Shouldn't have a JSContext on the stack");
|
||||
|
@ -1822,7 +1791,6 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
TimeStamp previousRefresh = mMostRecentRefresh;
|
||||
|
||||
mMostRecentRefresh = aNowTime;
|
||||
mMostRecentRefreshEpochTime = aNowEpoch;
|
||||
|
||||
if (IsWaitingForPaint(aNowTime)) {
|
||||
// We're currently suspended waiting for earlier Tick's to
|
||||
|
|
|
@ -116,10 +116,6 @@ public:
|
|||
* the main event loop have the same start time.)
|
||||
*/
|
||||
mozilla::TimeStamp MostRecentRefresh() const;
|
||||
/**
|
||||
* Same thing, but in microseconds since the epoch.
|
||||
*/
|
||||
int64_t MostRecentRefreshEpochTime() const;
|
||||
|
||||
/**
|
||||
* Add / remove refresh observers. Returns whether the operation
|
||||
|
@ -430,7 +426,7 @@ private:
|
|||
void DispatchAnimationEvents();
|
||||
void RunFrameRequestCallbacks(mozilla::TimeStamp aNowTime);
|
||||
void UpdateIntersectionObservations();
|
||||
void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
|
||||
void Tick(mozilla::TimeStamp aNowTime);
|
||||
|
||||
enum EnsureTimerStartedFlags {
|
||||
eNone = 0,
|
||||
|
@ -512,7 +508,6 @@ private:
|
|||
// True if the next tick should notify DOMContentFlushed.
|
||||
bool mNotifyDOMContentFlushed;
|
||||
|
||||
int64_t mMostRecentRefreshEpochTime;
|
||||
// Number of seconds that the refresh driver is blocked waiting for a compositor
|
||||
// transaction to be completed before we append a note to the gfx critical log.
|
||||
// The number is doubled every time the threshold is hit.
|
||||
|
|
|
@ -10,11 +10,11 @@ interface nsIChannel;
|
|||
interface nsILoadInfo;
|
||||
|
||||
[scriptable, uuid(c0c19db9-1b5a-4ac5-b656-ed6f8149fa48)]
|
||||
interface nsIAboutModule : nsISupports
|
||||
interface nsIAboutModule : nsISupports
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs a new channel for the about protocol module.
|
||||
* Constructs a new channel for the about protocol module.
|
||||
*
|
||||
* @param aURI the uri of the new channel
|
||||
* @param aLoadInfo the loadinfo of the new channel
|
||||
|
@ -71,6 +71,13 @@ interface nsIAboutModule : nsISupports
|
|||
*/
|
||||
const unsigned long MAKE_LINKABLE = (1 << 7);
|
||||
|
||||
/**
|
||||
* A flag that indicates that this URI can be loaded in the privileged
|
||||
* content process if privileged content process is enabled. Ignored unless
|
||||
* URI_MUST_LOAD_IN_CHILD is also specified.
|
||||
*/
|
||||
const unsigned long URI_CAN_LOAD_IN_PRIVILEGED_CHILD = (1 << 8);
|
||||
|
||||
/**
|
||||
* A method to get the flags that apply to a given about: URI. The URI
|
||||
* passed in is guaranteed to be one of the URIs that this module
|
||||
|
@ -81,8 +88,8 @@ interface nsIAboutModule : nsISupports
|
|||
|
||||
%{C++
|
||||
|
||||
#define NS_ABOUT_MODULE_CONTRACTID "@mozilla.org/network/protocol/about;1"
|
||||
#define NS_ABOUT_MODULE_CONTRACTID_PREFIX NS_ABOUT_MODULE_CONTRACTID "?what="
|
||||
#define NS_ABOUT_MODULE_CONTRACTID "@mozilla.org/network/protocol/about;1"
|
||||
#define NS_ABOUT_MODULE_CONTRACTID_PREFIX NS_ABOUT_MODULE_CONTRACTID "?what="
|
||||
#define NS_ABOUT_MODULE_CONTRACTID_LENGTH 49 // strlen(NS_ABOUT_MODULE_CONTRACTID_PREFIX)
|
||||
|
||||
%}
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
/* 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/. */
|
||||
|
||||
// This file is an NSIS plugin which exports a function that starts a process
|
||||
// from a provided path by using the shell automation API to have explorer.exe
|
||||
// invoke ShellExecute. This roundabout method of starting a process is useful
|
||||
// because it means the new process will use the integrity level and security
|
||||
// token of the shell, so it allows starting an unelevated process from inside
|
||||
// an elevated one. The method is based on
|
||||
// https://blogs.msdn.microsoft.com/oldnewthing/20131118-00/?p=2643
|
||||
// but the code has been rewritten to remove the need for ATL or the C runtime.
|
||||
|
||||
// Normally an NSIS installer would use the UAC plugin, which itself uses both
|
||||
// an unelevated and an elevated process, and the elevated process can invoke
|
||||
// functions in the unelevated one, so this plugin wouldn't be needed.
|
||||
// But uninstallers are often directly run elevated because that's just how
|
||||
// the Windows UI launches them, so there is no unelevated process. This
|
||||
// plugin allows starting a needed unelevated process in that situation.
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#pragma comment(lib, "shlwapi.lib")
|
||||
|
||||
static IShellView*
|
||||
GetDesktopWindowShellView()
|
||||
{
|
||||
IShellView* view = nullptr;
|
||||
IShellWindows* shell = nullptr;
|
||||
CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
|
||||
IID_PPV_ARGS(&shell));
|
||||
if (shell) {
|
||||
VARIANT empty;
|
||||
VariantInit(&empty);
|
||||
|
||||
VARIANT loc;
|
||||
loc.vt = VT_VARIANT | VT_BYREF;
|
||||
PIDLIST_ABSOLUTE locList;
|
||||
SHGetFolderLocation(nullptr, CSIDL_DESKTOP, nullptr, 0, &locList);
|
||||
loc.byref = locList;
|
||||
|
||||
HWND windowHandle = 0;
|
||||
IDispatch* dispatch = nullptr;
|
||||
|
||||
shell->FindWindowSW(&loc, &empty, SWC_DESKTOP, (long*)&windowHandle,
|
||||
SWFO_NEEDDISPATCH, &dispatch);
|
||||
if (dispatch) {
|
||||
IServiceProvider* provider = nullptr;
|
||||
dispatch->QueryInterface(IID_PPV_ARGS(&provider));
|
||||
if (provider) {
|
||||
IShellBrowser* browser = nullptr;
|
||||
provider->QueryService(SID_STopLevelBrowser, IID_PPV_ARGS(&browser));
|
||||
if (browser) {
|
||||
browser->QueryActiveShellView(&view);
|
||||
browser->Release();
|
||||
}
|
||||
provider->Release();
|
||||
}
|
||||
dispatch->Release();
|
||||
}
|
||||
shell->Release();
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
static IShellDispatch2*
|
||||
GetApplicationFromShellView(IShellView* view)
|
||||
{
|
||||
IShellDispatch2* shellDispatch = nullptr;
|
||||
IDispatch* viewDisp = nullptr;
|
||||
HRESULT hr = view->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&viewDisp));
|
||||
if (SUCCEEDED(hr)) {
|
||||
IShellFolderViewDual* shellViewFolder = nullptr;
|
||||
viewDisp->QueryInterface(IID_PPV_ARGS(&shellViewFolder));
|
||||
if (shellViewFolder) {
|
||||
IDispatch* dispatch = nullptr;
|
||||
shellViewFolder->get_Application(&dispatch);
|
||||
if (dispatch) {
|
||||
dispatch->QueryInterface(IID_PPV_ARGS(&shellDispatch));
|
||||
dispatch->Release();
|
||||
}
|
||||
shellViewFolder->Release();
|
||||
}
|
||||
viewDisp->Release();
|
||||
}
|
||||
return shellDispatch;
|
||||
}
|
||||
|
||||
static bool
|
||||
ShellExecInExplorerProcess(wchar_t* path)
|
||||
{
|
||||
bool rv = false;
|
||||
if (SUCCEEDED(CoInitialize(nullptr))) {
|
||||
IShellView *desktopView = GetDesktopWindowShellView();
|
||||
if (desktopView) {
|
||||
IShellDispatch2 *shellDispatch = GetApplicationFromShellView(desktopView);
|
||||
if (shellDispatch) {
|
||||
BSTR bstrPath = SysAllocString(path);
|
||||
rv = SUCCEEDED(shellDispatch->ShellExecuteW(bstrPath,
|
||||
VARIANT{}, VARIANT{},
|
||||
VARIANT{}, VARIANT{}));
|
||||
SysFreeString(bstrPath);
|
||||
shellDispatch->Release();
|
||||
}
|
||||
desktopView->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
struct stack_t {
|
||||
stack_t* next;
|
||||
TCHAR text[MAX_PATH];
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes an element from the top of the NSIS stack
|
||||
*
|
||||
* @param stacktop A pointer to the top of the stack
|
||||
* @param str The string to pop to
|
||||
* @param len The max length
|
||||
* @return 0 on success
|
||||
*/
|
||||
int
|
||||
popstring(stack_t **stacktop, TCHAR *str, int len)
|
||||
{
|
||||
// Removes the element from the top of the stack and puts it in the buffer
|
||||
stack_t *th;
|
||||
if (!stacktop || !*stacktop) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
th = (*stacktop);
|
||||
lstrcpyn(str, th->text, len);
|
||||
*stacktop = th->next;
|
||||
HeapFree(GetProcessHeap(), 0, th);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an element to the top of the NSIS stack
|
||||
*
|
||||
* @param stacktop A pointer to the top of the stack
|
||||
* @param str The string to push on the stack
|
||||
* @param len The length of the string to push on the stack
|
||||
* @return 0 on success
|
||||
*/
|
||||
void
|
||||
pushstring(stack_t **stacktop, const TCHAR *str, int len)
|
||||
{
|
||||
stack_t *th;
|
||||
if (!stacktop) {
|
||||
return;
|
||||
}
|
||||
th = (stack_t*)HeapAlloc(GetProcessHeap(), 0, sizeof(stack_t) + len);
|
||||
lstrcpyn(th->text, str, len);
|
||||
th->next = *stacktop;
|
||||
*stacktop = th;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an executable or URL from the shell process.
|
||||
*
|
||||
* @param stacktop Pointer to the top of the stack, AKA the first parameter to
|
||||
the plugin call. Should contain the file or URL to execute.
|
||||
* @return 1 if the file/URL was executed successfully, 0 if it was not
|
||||
*/
|
||||
extern "C" void __declspec(dllexport)
|
||||
Exec(HWND, int, TCHAR *, stack_t **stacktop, void *)
|
||||
{
|
||||
wchar_t path[MAX_PATH + 1];
|
||||
// We're skipping building the C runtime to keep the file size low, so we
|
||||
// can't use a normal string initialization because that would call memset.
|
||||
path[0] = L'\0';
|
||||
popstring(stacktop, path, MAX_PATH);
|
||||
bool rv = ShellExecInExplorerProcess(path);
|
||||
pushstring(stacktop, rv ? L"1" : L"0", 2);
|
||||
}
|
||||
|
||||
BOOL APIENTRY
|
||||
DllMain(HMODULE, DWORD, LPVOID)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27428.2015
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ExecInExplorer", "ExecInExplorer.vcxproj", "{B5DBA89B-37EE-425C-A375-4E04E69731FA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Debug|x64.Build.0 = Debug|x64
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Debug|x86.Build.0 = Debug|Win32
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Release|x64.ActiveCfg = Release|x64
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Release|x64.Build.0 = Release|x64
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Release|x86.ActiveCfg = Release|Win32
|
||||
{B5DBA89B-37EE-425C-A375-4E04E69731FA}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {69740CF4-5E42-4A56-AFF5-2D17D42CFB75}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,175 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{B5DBA89B-37EE-425C-A375-4E04E69731FA}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>ExecInExplorer</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;EXECINEXPLORER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<OmitDefaultLibName>true</OmitDefaultLibName>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EntryPointSymbol>DllMain</EntryPointSymbol>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;EXECINEXPLORER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<OmitDefaultLibName>true</OmitDefaultLibName>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EntryPointSymbol>DllMain</EntryPointSymbol>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;EXECINEXPLORER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<OmitDefaultLibName>true</OmitDefaultLibName>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EntryPointSymbol>DllMain</EntryPointSymbol>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>false</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;EXECINEXPLORER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<OmitDefaultLibName>true</OmitDefaultLibName>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<EntryPointSymbol>DllMain</EntryPointSymbol>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ExecInExplorer.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
Двоичный файл не отображается.
|
@ -128,6 +128,7 @@ skip-if = os == 'android'
|
|||
skip-if = os == 'android' && debug || (os == 'linux' && !asan) # bug 1397615, bug 1455405
|
||||
[test_ext_webrequest_errors.html]
|
||||
[test_ext_webrequest_filter.html]
|
||||
skip-if = os == 'android' && debug # bug 1452348
|
||||
[test_ext_webrequest_frameId.html]
|
||||
[test_ext_webrequest_hsts.html]
|
||||
skip-if = os == 'android' || os == 'linux' # linux, bug 1398120
|
||||
|
|
|
@ -38,7 +38,11 @@ function getExtension() {
|
|||
browser.test.assertTrue(securityInfo.certificates.length == 1, "no certificate chain");
|
||||
}
|
||||
let cert = securityInfo.certificates[0];
|
||||
browser.test.assertTrue(cert.validity.start < Date.now() < cert.validity.end, "cert validity is correct");
|
||||
let now = Date.now();
|
||||
browser.test.assertTrue(Number.isInteger(cert.validity.start), "cert start is integer");
|
||||
browser.test.assertTrue(Number.isInteger(cert.validity.end), "cert end is integer");
|
||||
browser.test.assertTrue(cert.validity.start < now, "cert start validity is correct");
|
||||
browser.test.assertTrue(now < cert.validity.end, "cert end validity is correct");
|
||||
if (options.rawDER) {
|
||||
for (let cert of securityInfo.certificates) {
|
||||
browser.test.assertTrue(cert.rawDER.length > 0, "have rawDER");
|
||||
|
|
|
@ -43,8 +43,6 @@ const PRIVILEGED_REMOTE_TYPE = "privileged";
|
|||
const LARGE_ALLOCATION_REMOTE_TYPE = "webLargeAllocation";
|
||||
const DEFAULT_REMOTE_TYPE = WEB_REMOTE_TYPE;
|
||||
|
||||
const ACTIVITY_STREAM_PAGES = new Set(["home", "newtab", "welcome"]);
|
||||
|
||||
function validatedWebRemoteType(aPreferredRemoteType, aTargetUri, aCurrentUri) {
|
||||
// If the domain is whitelisted to allow it to use file:// URIs, then we have
|
||||
// to run it in a file content process, in case it uses file:// sub-resources.
|
||||
|
@ -159,9 +157,8 @@ var E10SUtils = {
|
|||
|
||||
let flags = module.getURIFlags(aURI);
|
||||
if (flags & Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD) {
|
||||
// Load Activity Stream in a separate process.
|
||||
if (useSeparatePrivilegedContentProcess &&
|
||||
ACTIVITY_STREAM_PAGES.has(aURI.filePath)) {
|
||||
if ((flags & Ci.nsIAboutModule.URI_CAN_LOAD_IN_PRIVILEGED_CHILD) &&
|
||||
useSeparatePrivilegedContentProcess) {
|
||||
return PRIVILEGED_REMOTE_TYPE;
|
||||
}
|
||||
return DEFAULT_REMOTE_TYPE;
|
||||
|
|
|
@ -214,8 +214,8 @@ const SecurityInfo = {
|
|||
subject: cert.subjectName,
|
||||
issuer: cert.issuerName,
|
||||
validity: {
|
||||
start: cert.validity.notBefore,
|
||||
end: cert.validity.notAfter,
|
||||
start: cert.validity.notBefore ? Math.trunc(cert.validity.notBefore / 1000) : 0,
|
||||
end: cert.validity.notAfter ? Math.trunc(cert.validity.notAfter / 1000) : 0,
|
||||
},
|
||||
fingerprint: {
|
||||
sha1: cert.sha1Fingerprint,
|
||||
|
|
|
@ -28,6 +28,7 @@ CUSTOM_NSIS_PLUGINS = \
|
|||
ApplicationID.dll \
|
||||
CertCheck.dll \
|
||||
CityHash.dll \
|
||||
ExecInExplorer.dll \
|
||||
InetBgDL.dll \
|
||||
InvokeShellVerb.dll \
|
||||
liteFirewallW.dll \
|
||||
|
|
Загрузка…
Ссылка в новой задаче