зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central and inbound
This commit is contained in:
Коммит
5a944e0ca0
|
@ -355,6 +355,9 @@ DocManager::RemoveListeners(nsIDocument* aDocument)
|
|||
return;
|
||||
|
||||
EventTarget* target = window->GetChromeEventHandler();
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
nsEventListenerManager* elm = target->GetListenerManager(true);
|
||||
elm->RemoveEventListenerByType(this, NS_LITERAL_STRING("pagehide"),
|
||||
dom::TrustedEventsAtCapture());
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
# 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/.
|
||||
|
||||
const kPrefNotifyMissingFlash = "plugins.notifyMissingFlash";
|
||||
const kPrefSessionPersistMinutes = "plugin.sessionPermissionNow.intervalInMinutes";
|
||||
const kPrefPersistentDays = "plugin.persistentPermissionAlways.intervalInDays";
|
||||
|
||||
var gPluginHandler = {
|
||||
PLUGIN_SCRIPTED_STATE_NONE: 0,
|
||||
PLUGIN_SCRIPTED_STATE_FIRED: 1,
|
||||
PLUGIN_SCRIPTED_STATE_DONE: 2,
|
||||
|
||||
PREF_NOTIFY_MISSING_FLASH: "plugins.notifyMissingFlash",
|
||||
PREF_SESSION_PERSIST_MINUTES: "plugin.sessionPermissionNow.intervalInMinutes",
|
||||
PREF_PERSISTENT_DAYS: "plugin.persistentPermissionAlways.intervalInDays",
|
||||
|
||||
getPluginUI: function (plugin, className) {
|
||||
return plugin.ownerDocument.
|
||||
getAnonymousElementByAttribute(plugin, "class", className);
|
||||
|
@ -468,13 +468,14 @@ var gPluginHandler = {
|
|||
let secondaryActions = null;
|
||||
let options = { dismissed: true };
|
||||
|
||||
let showForFlash = Services.prefs.getBoolPref(kPrefNotifyMissingFlash);
|
||||
let showForFlash = Services.prefs.getBoolPref(this.PREF_NOTIFY_MISSING_FLASH);
|
||||
if (pluginIdentifier == "flash" && showForFlash) {
|
||||
let prefNotifyMissingFlash = this.PREF_NOTIFY_MISSING_FLASH;
|
||||
secondaryActions = [{
|
||||
label: gNavigatorBundle.getString("installPlugin.ignoreButton.label"),
|
||||
accessKey: gNavigatorBundle.getString("installPlugin.ignoreButton.accesskey"),
|
||||
callback: function () {
|
||||
Services.prefs.setBoolPref(kPrefNotifyMissingFlash, false);
|
||||
Services.prefs.setBoolPref(prefNotifyMissingFlash, false);
|
||||
}
|
||||
}];
|
||||
options.dismissed = false;
|
||||
|
@ -690,7 +691,7 @@ var gPluginHandler = {
|
|||
}
|
||||
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
expireType = Ci.nsIPermissionManager.EXPIRE_SESSION;
|
||||
expireTime = Date.now() + Services.prefs.getIntPref(kPrefSessionPersistMinutes) * 60 * 1000;
|
||||
expireTime = Date.now() + Services.prefs.getIntPref(this.PREF_SESSION_PERSIST_MINUTES) * 60 * 1000;
|
||||
break;
|
||||
|
||||
case "allowalways":
|
||||
|
@ -700,7 +701,7 @@ var gPluginHandler = {
|
|||
permission = Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
expireType = Ci.nsIPermissionManager.EXPIRE_TIME;
|
||||
expireTime = Date.now() +
|
||||
Services.prefs.getIntPref(kPrefPersistentDays) * 24 * 60 * 60 * 1000;
|
||||
Services.prefs.getIntPref(this.PREF_PERSISTENT_DAYS) * 24 * 60 * 60 * 1000;
|
||||
break;
|
||||
|
||||
case "block":
|
||||
|
|
|
@ -1522,7 +1522,7 @@
|
|||
class="click-to-play-plugins-notification-button-container"
|
||||
pack="center" align="center">
|
||||
<xul:button anonid="primarybutton"
|
||||
class="click-to-play-popup-button primary-button"
|
||||
class="click-to-play-popup-button"
|
||||
oncommand="document.getBindingParent(this)._onButton(this)"
|
||||
flex="1"/>
|
||||
<xul:button anonid="secondarybutton"
|
||||
|
|
|
@ -1189,7 +1189,7 @@ FilterView.prototype = {
|
|||
_doSearch: function(aOperator = "") {
|
||||
this._searchbox.focus();
|
||||
this._searchbox.value = ""; // Need to clear value beforehand. Bug 779738.
|
||||
this._searchbox.value = aOperator;
|
||||
this._searchbox.value = aOperator + DebuggerView.getEditorSelectionText();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@ var gSearchBox = null;
|
|||
|
||||
function test()
|
||||
{
|
||||
requestLongerTimeout(2);
|
||||
requestLongerTimeout(3);
|
||||
|
||||
debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) {
|
||||
gTab = aTab;
|
||||
|
@ -269,6 +269,12 @@ function testScriptSearching() {
|
|||
isnot(gSources.widget.getAttribute("label"), noMatchingSources,
|
||||
"The scripts container should not display a notice that matches are found.");
|
||||
|
||||
|
||||
gEditor.setSelection(1, 5);
|
||||
EventUtils.synthesizeKey("F", { accelKey:true });
|
||||
is(gSearchBox.value, "#" + gEditor.getSelectedText(),
|
||||
"The search field has the right initial value.");
|
||||
|
||||
closeDebuggerAndFinish();
|
||||
}}, 0);
|
||||
}
|
||||
|
|
|
@ -409,7 +409,9 @@ gTests.push({
|
|||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Context menu options
|
||||
|
||||
/*
|
||||
XXX disabled temporarily due to bug 880739
|
||||
|
||||
// image01 - 1x1x100x100
|
||||
let promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToWindow(win, 10, 10);
|
||||
|
@ -456,7 +458,7 @@ gTests.push({
|
|||
purgeEventQueue();
|
||||
|
||||
ok(saveLocationPath.exists(), "image saved");
|
||||
|
||||
*/
|
||||
////////////////////////////////////////////////////////////
|
||||
// Copy image
|
||||
|
||||
|
@ -465,10 +467,10 @@ gTests.push({
|
|||
yield promise;
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
|
||||
menuItem = document.getElementById("context-copy-image");
|
||||
let menuItem = document.getElementById("context-copy-image");
|
||||
ok(menuItem, "menu item exists");
|
||||
ok(!menuItem.hidden, "menu item visible");
|
||||
popupPromise = waitForEvent(document, "popuphidden");
|
||||
let popupPromise = waitForEvent(document, "popuphidden");
|
||||
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
|
||||
yield popupPromise;
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ endif
|
|||
_MOZBUILD_EXTERNAL_VARIABLES := \
|
||||
DIRS \
|
||||
EXTRA_PP_COMPONENTS \
|
||||
GTEST_CMMSRCS \
|
||||
GTEST_CPPSRCS \
|
||||
GTEST_CSRCS \
|
||||
HOST_CSRCS \
|
||||
HOST_LIBRARY_NAME \
|
||||
MODULE \
|
||||
|
|
|
@ -45,6 +45,7 @@ MOCHITEST_FILES = \
|
|||
test_hasFeature.xhtml \
|
||||
$(filter disabled-for-intermittent-failures--bug-701060, test_lang.xhtml) \
|
||||
test_nonAnimStrings.xhtml \
|
||||
test_non-scaling-stroke.html \
|
||||
test_pathAnimInterpolation.xhtml \
|
||||
test_pathSeg.xhtml \
|
||||
test_pointAtLength.xhtml \
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=829085
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 829085 - non-scaling-stroke hit testing</title>
|
||||
<meta charset="utf-8"></meta>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=829085">Mozilla Bug 829085 - non-scaling-stroke hit testing</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="300" height="250">
|
||||
<rect width="100%" height="100%" fill="none" stroke-width="4" stroke="blue"/>
|
||||
<style>
|
||||
line:hover { stroke: lime; }
|
||||
</style>
|
||||
<g transform="scale(1.3) translate(100, -80) rotate(45)">
|
||||
<line id="line" stroke="teal" stroke-width="120px"
|
||||
x1="50" y1="130" x2="200" y2="130"
|
||||
vector-effect="non-scaling-stroke"></line>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
function startTest() {
|
||||
SimpleTest.waitForFocus(function() {
|
||||
disableNonTestMouseEvents(true);
|
||||
var line = document.getElementById('line');
|
||||
// Send a click
|
||||
synthesizeMouseExpectEvent($("svg"), 170, 100, { },
|
||||
$("line"), "click",
|
||||
"Testing mouse event on non-scaling-stroke");
|
||||
disableNonTestMouseEvents(false);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(startTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -61,8 +61,6 @@ function run_test()
|
|||
// Needed to properly setup and shutdown the profile.
|
||||
do_get_profile();
|
||||
|
||||
Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
|
||||
for (var i = 0; i < tests.length; i++)
|
||||
tests[i]();
|
||||
|
||||
|
|
|
@ -108,6 +108,17 @@ Future::PrefEnabled()
|
|||
return Preferences::GetBool("dom.future.enabled", false);
|
||||
}
|
||||
|
||||
static void
|
||||
EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
|
||||
const Optional<JS::Handle<JS::Value> >& aValue)
|
||||
{
|
||||
// FIXME Bug 878849
|
||||
if (aValue.WasPassed() && aValue.Value().isObject()) {
|
||||
JS::Rooted<JSObject*> rooted(aCx, &aValue.Value().toObject());
|
||||
aAc.construct(aCx, rooted);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Future>
|
||||
Future::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
FutureInit& aInit, ErrorResult& aRv)
|
||||
|
@ -129,6 +140,9 @@ Future::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
|
|||
if (aRv.IsJSException()) {
|
||||
Optional<JS::Handle<JS::Value> > value(aCx);
|
||||
aRv.StealJSException(aCx, &value.Value());
|
||||
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
EnterCompartment(ac, aCx, value);
|
||||
future->mResolver->Reject(aCx, value);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,17 @@ FutureCallback::~FutureCallback()
|
|||
MOZ_COUNT_DTOR(FutureCallback);
|
||||
}
|
||||
|
||||
static void
|
||||
EnterCompartment(Maybe<JSAutoCompartment>& aAc, JSContext* aCx,
|
||||
const Optional<JS::Handle<JS::Value> >& aValue)
|
||||
{
|
||||
// FIXME Bug 878849
|
||||
if (aValue.WasPassed() && aValue.Value().isObject()) {
|
||||
JS::Rooted<JSObject*> rooted(aCx, &aValue.Value().toObject());
|
||||
aAc.construct(aCx, rooted);
|
||||
}
|
||||
}
|
||||
|
||||
// ResolveFutureCallback
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED_1(ResolveFutureCallback,
|
||||
|
@ -63,12 +74,8 @@ ResolveFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
|
|||
{
|
||||
// Run resolver's algorithm with value and the synchronous flag set.
|
||||
AutoJSContext cx;
|
||||
// FIXME Bug 878849
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
if (aValue.WasPassed() && aValue.Value().isObject()) {
|
||||
JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
|
||||
ac.construct(cx, rooted);
|
||||
}
|
||||
EnterCompartment(ac, cx, aValue);
|
||||
|
||||
mResolver->ResolveInternal(cx, aValue, FutureResolver::SyncTask);
|
||||
}
|
||||
|
@ -102,12 +109,8 @@ RejectFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
|
|||
{
|
||||
// Run resolver's algorithm with value and the synchronous flag set.
|
||||
AutoJSContext cx;
|
||||
// FIXME Bug 878849
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
if (aValue.WasPassed() && aValue.Value().isObject()) {
|
||||
JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
|
||||
ac.construct(cx, rooted);
|
||||
}
|
||||
EnterCompartment(ac, cx, aValue);
|
||||
|
||||
mResolver->RejectInternal(cx, aValue, FutureResolver::SyncTask);
|
||||
}
|
||||
|
@ -142,12 +145,8 @@ void
|
|||
WrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
|
||||
{
|
||||
AutoJSContext cx;
|
||||
// FIXME Bug 878849
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
if (aValue.WasPassed() && aValue.Value().isObject()) {
|
||||
JS::Rooted<JSObject*> rooted(cx, &aValue.Value().toObject());
|
||||
ac.construct(cx, rooted);
|
||||
}
|
||||
EnterCompartment(ac, cx, aValue);
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
|
@ -162,12 +161,17 @@ WrapperFutureCallback::Call(const Optional<JS::Handle<JS::Value> >& aValue)
|
|||
if (rv.Failed() && rv.IsJSException()) {
|
||||
Optional<JS::Handle<JS::Value> > value(cx);
|
||||
rv.StealJSException(cx, &value.Value());
|
||||
|
||||
Maybe<JSAutoCompartment> ac2;
|
||||
EnterCompartment(ac2, cx, value);
|
||||
mNextResolver->RejectInternal(cx, value, FutureResolver::SyncTask);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, run resolver's resolve with value and the synchronous flag
|
||||
// set.
|
||||
Maybe<JSAutoCompartment> ac2;
|
||||
EnterCompartment(ac2, cx, value);
|
||||
mNextResolver->ResolveInternal(cx, value, FutureResolver::SyncTask);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ include $(DEPTH)/config/autoconf.mk
|
|||
MOCHITEST_FILES = \
|
||||
test_future.html \
|
||||
test_resolve.html \
|
||||
test_bug883683.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Future - bug 883683</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript"><!--
|
||||
|
||||
function runTest() {
|
||||
[{}, {}, {}, {}, {}].reduce(Future.reject);
|
||||
ok(true, "No leaks with reject?");
|
||||
|
||||
[{}, {}, {}, {}, {}].reduce(Future.resolve);
|
||||
ok(true, "No leaks with resolve?");
|
||||
|
||||
[{}, {}, {}, {}, {}].reduce(function(a, b, c, d) { return new Future(function(r) { throw a; }); });
|
||||
ok(true, "No leaks with exception?");
|
||||
|
||||
[{}, {}, {}, {}, {}].reduce(function(a, b, c, d) { return new Future(function(r) { }); });
|
||||
ok(true, "No leaks with empty future?");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.future.enabled", true]]}, runTest);
|
||||
// -->
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -350,8 +350,7 @@ TabChild::Observe(nsISupports *aSubject,
|
|||
mLastMetrics.mZoom = ScreenToScreenScale(1.0);
|
||||
mLastMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
|
||||
mLastMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
|
||||
CSSToScreenScale resolution =
|
||||
AsyncPanZoomController::CalculateResolution(mLastMetrics);
|
||||
CSSToScreenScale resolution = mLastMetrics.CalculateResolution();
|
||||
// We use ScreenToLayerScale(1) below in order to ask gecko to render
|
||||
// what's currently visible on the screen. This is effectively turning
|
||||
// the async zoom amount into the gecko zoom amount.
|
||||
|
@ -602,8 +601,7 @@ TabChild::HandlePossibleViewportChange()
|
|||
nsresult rv = utils->GetIsFirstPaint(&isFirstPaint);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (NS_FAILED(rv) || isFirstPaint) {
|
||||
CSSToScreenScale intrinsicScale =
|
||||
AsyncPanZoomController::CalculateIntrinsicScale(metrics);
|
||||
CSSToScreenScale intrinsicScale = metrics.CalculateIntrinsicScale();
|
||||
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
|
@ -624,7 +622,7 @@ TabChild::HandlePossibleViewportChange()
|
|||
// new CSS viewport, so we know that there's no velocity, acceleration, and
|
||||
// we have no idea how long painting will take.
|
||||
metrics, gfx::Point(0.0f, 0.0f), gfx::Point(0.0f, 0.0f), 0.0);
|
||||
CSSToScreenScale resolution = AsyncPanZoomController::CalculateResolution(metrics);
|
||||
CSSToScreenScale resolution = metrics.CalculateResolution();
|
||||
metrics.mResolution = resolution / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
utils->SetResolution(metrics.mResolution.scale, metrics.mResolution.scale);
|
||||
|
||||
|
@ -1491,8 +1489,7 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
return true;
|
||||
}
|
||||
|
||||
CSSRect cssCompositedRect =
|
||||
AsyncPanZoomController::CalculateCompositedRectInCssPixels(aFrameMetrics);
|
||||
CSSRect cssCompositedRect = aFrameMetrics.CalculateCompositedRectInCssPixels();
|
||||
// The BrowserElementScrolling helper must know about these updated metrics
|
||||
// for other functions it performs, such as double tap handling.
|
||||
nsCString data;
|
||||
|
@ -1534,8 +1531,7 @@ TabChild::ProcessUpdateFrame(const FrameMetrics& aFrameMetrics)
|
|||
utils->SetScrollPositionClampingScrollPortSize(
|
||||
cssCompositedRect.width, cssCompositedRect.height);
|
||||
ScrollWindowTo(window, aFrameMetrics.mScrollOffset);
|
||||
CSSToScreenScale resolution = AsyncPanZoomController::CalculateResolution(
|
||||
aFrameMetrics);
|
||||
CSSToScreenScale resolution = aFrameMetrics.CalculateResolution();
|
||||
utils->SetResolution(resolution.scale, resolution.scale);
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
|
|
|
@ -1387,7 +1387,7 @@ DONE_CREATING_PIXMAP:
|
|||
display,
|
||||
glxpixmap,
|
||||
cfgs[chosenIndex],
|
||||
false,
|
||||
true,
|
||||
libToUse,
|
||||
xsurface);
|
||||
}
|
||||
|
|
|
@ -94,6 +94,31 @@ public:
|
|||
return mScrollOffset * LayersPixelsPerCSSPixel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the scale factor needed to fit the viewport
|
||||
* into its composition bounds.
|
||||
*/
|
||||
CSSToScreenScale CalculateIntrinsicScale() const
|
||||
{
|
||||
return CSSToScreenScale(float(mCompositionBounds.width) / float(mViewport.width));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolution that content should be rendered at given
|
||||
* the configuration in this metrics object: viewport dimensions,
|
||||
* zoom factor, etc. (The mResolution member of this metrics is
|
||||
* ignored.)
|
||||
*/
|
||||
CSSToScreenScale CalculateResolution() const
|
||||
{
|
||||
return CalculateIntrinsicScale() * mZoom;
|
||||
}
|
||||
|
||||
CSSRect CalculateCompositedRectInCssPixels() const
|
||||
{
|
||||
return CSSRect(gfx::RoundedIn(mCompositionBounds / CalculateResolution()));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// The following metrics are all in widget space/device pixels.
|
||||
//
|
||||
|
|
|
@ -245,7 +245,7 @@ AsyncPanZoomController::ReceiveInputEvent(const nsInputEvent& aEvent,
|
|||
CSSToScreenScale currentResolution;
|
||||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
currentResolution = CalculateResolution(mFrameMetrics);
|
||||
currentResolution = mFrameMetrics.CalculateResolution();
|
||||
}
|
||||
|
||||
nsEventStatus status;
|
||||
|
@ -559,7 +559,7 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
|||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
CSSToScreenScale resolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
gfxFloat userZoom = mFrameMetrics.mZoom.scale;
|
||||
ScreenPoint focusPoint = aEvent.mFocusPoint;
|
||||
|
||||
|
@ -579,8 +579,8 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
|
|||
// either axis such that we don't overscroll the boundaries when zooming.
|
||||
gfx::Point neededDisplacement;
|
||||
|
||||
float maxZoom = mMaxZoom / CalculateIntrinsicScale(mFrameMetrics).scale;
|
||||
float minZoom = mMinZoom / CalculateIntrinsicScale(mFrameMetrics).scale;
|
||||
float maxZoom = mMaxZoom / mFrameMetrics.CalculateIntrinsicScale().scale;
|
||||
float minZoom = mMinZoom / mFrameMetrics.CalculateIntrinsicScale().scale;
|
||||
|
||||
bool doScale = (spanRatio > 1.0 && userZoom < maxZoom) ||
|
||||
(spanRatio < 1.0 && userZoom > minZoom);
|
||||
|
@ -660,7 +660,7 @@ nsEventStatus AsyncPanZoomController::OnLongPress(const TapGestureInput& aEvent)
|
|||
if (mGeckoContentController) {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
CSSToScreenScale resolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(
|
||||
ScreenPoint::FromUnknownPoint(gfx::Point(
|
||||
aEvent.mPoint.x, aEvent.mPoint.y)),
|
||||
|
@ -679,7 +679,7 @@ nsEventStatus AsyncPanZoomController::OnSingleTapConfirmed(const TapGestureInput
|
|||
if (mGeckoContentController) {
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
CSSToScreenScale resolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(
|
||||
ScreenPoint::FromUnknownPoint(gfx::Point(
|
||||
aEvent.mPoint.x, aEvent.mPoint.y)),
|
||||
|
@ -695,7 +695,7 @@ nsEventStatus AsyncPanZoomController::OnDoubleTap(const TapGestureInput& aEvent)
|
|||
MonitorAutoLock monitor(mMonitor);
|
||||
|
||||
if (mAllowZoom) {
|
||||
CSSToScreenScale resolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
CSSPoint point = WidgetSpaceToCompensatedViewportSpace(
|
||||
ScreenPoint::FromUnknownPoint(gfx::Point(
|
||||
aEvent.mPoint.x, aEvent.mPoint.y)),
|
||||
|
@ -765,7 +765,7 @@ void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
|||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
ScreenToCSSScale inverseResolution = CalculateResolution(mFrameMetrics).Inverse();
|
||||
ScreenToCSSScale inverseResolution = mFrameMetrics.CalculateResolution().Inverse();
|
||||
|
||||
gfx::Point displacement(mX.GetDisplacementForDuration(inverseResolution.scale,
|
||||
timeDelta),
|
||||
|
@ -809,7 +809,7 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
|||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
ScreenToCSSScale inverseResolution = CalculateResolution(mFrameMetrics).Inverse();
|
||||
ScreenToCSSScale inverseResolution = mFrameMetrics.CalculateResolution().Inverse();
|
||||
|
||||
ScrollBy(CSSPoint::FromUnknownPoint(gfx::Point(
|
||||
mX.GetDisplacementForDuration(inverseResolution.scale, aDelta),
|
||||
|
@ -838,7 +838,7 @@ void AsyncPanZoomController::ScrollBy(const CSSPoint& aOffset) {
|
|||
void AsyncPanZoomController::ScaleWithFocus(float aZoom,
|
||||
const ScreenPoint& aFocus) {
|
||||
float zoomFactor = aZoom / mFrameMetrics.mZoom.scale;
|
||||
CSSToScreenScale resolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
|
||||
SetZoomAndResolution(ScreenToScreenScale(aZoom));
|
||||
|
||||
|
@ -900,7 +900,7 @@ const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
|
|||
double estimatedPaintDuration =
|
||||
aEstimatedPaintDuration > EPSILON ? aEstimatedPaintDuration : 1.0;
|
||||
|
||||
CSSToScreenScale resolution = CalculateResolution(aFrameMetrics);
|
||||
CSSToScreenScale resolution = aFrameMetrics.CalculateResolution();
|
||||
CSSIntRect compositionBounds = gfx::RoundedIn(aFrameMetrics.mCompositionBounds / resolution);
|
||||
CSSRect scrollableRect = aFrameMetrics.mScrollableRect;
|
||||
|
||||
|
@ -970,27 +970,6 @@ const CSSRect AsyncPanZoomController::CalculatePendingDisplayPort(
|
|||
return scrollableRect.ClampRect(shiftedDisplayPort) - scrollOffset;
|
||||
}
|
||||
|
||||
/*static*/ CSSToScreenScale
|
||||
AsyncPanZoomController::CalculateIntrinsicScale(const FrameMetrics& aMetrics)
|
||||
{
|
||||
return CSSToScreenScale(gfxFloat(aMetrics.mCompositionBounds.width) /
|
||||
gfxFloat(aMetrics.mViewport.width));
|
||||
}
|
||||
|
||||
/*static*/ CSSToScreenScale
|
||||
AsyncPanZoomController::CalculateResolution(const FrameMetrics& aMetrics)
|
||||
{
|
||||
return CalculateIntrinsicScale(aMetrics) * aMetrics.mZoom;
|
||||
}
|
||||
|
||||
/*static*/ CSSRect
|
||||
AsyncPanZoomController::CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics)
|
||||
{
|
||||
CSSToScreenScale resolution = CalculateResolution(aMetrics);
|
||||
CSSIntRect rect = gfx::RoundedIn(aMetrics.mCompositionBounds / resolution);
|
||||
return CSSRect(rect);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::SetDPI(int aDPI) {
|
||||
mDPI = aDPI;
|
||||
}
|
||||
|
@ -1146,7 +1125,7 @@ bool AsyncPanZoomController::SampleContentTransformForFrame(const TimeStamp& aSa
|
|||
// what PZC has transformed due to touches like panning or
|
||||
// pinching. Eventually, the root layer transform will become this
|
||||
// during runtime, but we must wait for Gecko to repaint.
|
||||
localScale = CalculateResolution(mFrameMetrics);
|
||||
localScale = mFrameMetrics.CalculateResolution();
|
||||
|
||||
if (frame.IsScrollable()) {
|
||||
metricsScrollOffset = frame.GetScrollOffsetInLayerPixels();
|
||||
|
@ -1238,9 +1217,9 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
|||
aViewportFrame.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
|
||||
// Remote content has sync'd up to the composition geometry
|
||||
// change, so we can accept the viewport it's calculated.
|
||||
CSSToScreenScale previousResolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale previousResolution = mFrameMetrics.CalculateResolution();
|
||||
mFrameMetrics.mViewport = aViewportFrame.mViewport;
|
||||
CSSToScreenScale newResolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale newResolution = mFrameMetrics.CalculateResolution();
|
||||
needContentRepaint |= (previousResolution != newResolution);
|
||||
}
|
||||
|
||||
|
@ -1310,7 +1289,7 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
|||
CSSPoint scrollOffset = mFrameMetrics.mScrollOffset;
|
||||
float currentZoom = mFrameMetrics.mZoom.scale;
|
||||
float targetZoom;
|
||||
float intrinsicScale = CalculateIntrinsicScale(mFrameMetrics).scale;
|
||||
float intrinsicScale = mFrameMetrics.CalculateIntrinsicScale().scale;
|
||||
|
||||
// The minimum zoom to prevent over-zoom-out.
|
||||
// If the zoom factor is lower than this (i.e. we are zoomed more into the page),
|
||||
|
@ -1338,7 +1317,7 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
|||
if (zoomToRect.IsEmpty() ||
|
||||
(currentZoom == localMaxZoom && targetZoom >= localMaxZoom) ||
|
||||
(currentZoom == localMinZoom && targetZoom <= localMinZoom)) {
|
||||
CSSRect compositedRect = CalculateCompositedRectInCssPixels(mFrameMetrics);
|
||||
CSSRect compositedRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
|
||||
float y = scrollOffset.y;
|
||||
float newHeight =
|
||||
cssPageRect.width * (compositedRect.height / compositedRect.width);
|
||||
|
@ -1361,8 +1340,7 @@ void AsyncPanZoomController::ZoomToRect(const gfxRect& aRect) {
|
|||
// Adjust the zoomToRect to a sensible position to prevent overscrolling.
|
||||
FrameMetrics metricsAfterZoom = mFrameMetrics;
|
||||
metricsAfterZoom.mZoom = mEndZoomToMetrics.mZoom;
|
||||
CSSRect rectAfterZoom
|
||||
= CalculateCompositedRectInCssPixels(metricsAfterZoom);
|
||||
CSSRect rectAfterZoom = metricsAfterZoom.CalculateCompositedRectInCssPixels();
|
||||
|
||||
// If either of these conditions are met, the page will be
|
||||
// overscrolled after zoomed
|
||||
|
@ -1442,7 +1420,7 @@ void AsyncPanZoomController::TimeoutTouchListeners() {
|
|||
void AsyncPanZoomController::SetZoomAndResolution(const ScreenToScreenScale& aZoom) {
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
mFrameMetrics.mZoom = aZoom;
|
||||
CSSToScreenScale resolution = CalculateResolution(mFrameMetrics);
|
||||
CSSToScreenScale resolution = mFrameMetrics.CalculateResolution();
|
||||
// We use ScreenToLayerScale(1) below in order to ask gecko to render
|
||||
// what's currently visible on the screen. This is effectively turning
|
||||
// the async zoom amount into the gecko zoom amount.
|
||||
|
@ -1474,7 +1452,7 @@ void AsyncPanZoomController::SendAsyncScrollEvent() {
|
|||
CSSSize scrollableSize;
|
||||
{
|
||||
scrollableSize = mFrameMetrics.mScrollableRect.Size();
|
||||
contentRect = AsyncPanZoomController::CalculateCompositedRectInCssPixels(mFrameMetrics);
|
||||
contentRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
|
||||
contentRect.MoveTo(mCurrentAsyncScrollOffset);
|
||||
}
|
||||
|
||||
|
|
|
@ -223,22 +223,6 @@ public:
|
|||
const gfx::Point& aAcceleration,
|
||||
double aEstimatedPaintDuration);
|
||||
|
||||
/**
|
||||
* Return the scale factor needed to fit the viewport in |aMetrics|
|
||||
* into its composition bounds.
|
||||
*/
|
||||
static CSSToScreenScale CalculateIntrinsicScale(const FrameMetrics& aMetrics);
|
||||
|
||||
/**
|
||||
* Return the resolution that content should be rendered at given
|
||||
* the configuration in aFrameMetrics: viewport dimensions, zoom
|
||||
* factor, etc. (The mResolution member of aFrameMetrics is
|
||||
* ignored.)
|
||||
*/
|
||||
static CSSToScreenScale CalculateResolution(const FrameMetrics& aMetrics);
|
||||
|
||||
static CSSRect CalculateCompositedRectInCssPixels(const FrameMetrics& aMetrics);
|
||||
|
||||
/**
|
||||
* Send an mozbrowserasyncscroll event.
|
||||
* *** The monitor must be held while calling this.
|
||||
|
|
|
@ -298,8 +298,7 @@ float Axis::GetOrigin() {
|
|||
|
||||
float Axis::GetCompositionLength() {
|
||||
const FrameMetrics& metrics = mAsyncPanZoomController->GetFrameMetrics();
|
||||
CSSRect cssCompositedRect =
|
||||
AsyncPanZoomController::CalculateCompositedRectInCssPixels(metrics);
|
||||
CSSRect cssCompositedRect = metrics.CalculateCompositedRectInCssPixels();
|
||||
return GetRectLength(cssCompositedRect);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,23 +23,6 @@ LOCAL_INCLUDES = \
|
|||
-I$(topsrcdir)/gfx/2d/unittest \
|
||||
$(NULL)
|
||||
|
||||
GTEST_CPPSRCS = \
|
||||
TestLayers.cpp \
|
||||
TestTiledLayerBuffer.cpp \
|
||||
TestAsyncPanZoomController.cpp \
|
||||
$(NULL)
|
||||
|
||||
# Because of gkmedia on windows we wont find these
|
||||
# symbols in xul.dll.
|
||||
ifneq ($(MOZ_WIDGET_TOOLKIT),windows)
|
||||
GTEST_CPPSRCS += \
|
||||
TestMoz2D.cpp \
|
||||
TestBase.cpp \
|
||||
TestPoint.cpp \
|
||||
TestScaling.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
||||
|
|
|
@ -8,3 +8,18 @@ MODULE = 'gfxtest'
|
|||
|
||||
LIBRARY_NAME = 'gfxtest'
|
||||
|
||||
GTEST_CPP_SOURCES += [
|
||||
'TestAsyncPanZoomController.cpp',
|
||||
'TestLayers.cpp',
|
||||
'TestTiledLayerBuffer.cpp',
|
||||
]
|
||||
|
||||
# Because of gkmedia on windows we wont find these
|
||||
# symbols in xul.dll.
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows':
|
||||
GTEST_CPP_SOURCES += [
|
||||
'TestBase.cpp'
|
||||
'TestMoz2D.cpp'
|
||||
'TestPoint.cpp'
|
||||
'TestScaling.cpp'
|
||||
]
|
||||
|
|
|
@ -17,6 +17,9 @@ endif
|
|||
_MOZBUILD_EXTERNAL_VARIABLES := \
|
||||
DIRS \
|
||||
EXTRA_PP_COMPONENTS \
|
||||
GTEST_CMMSRCS \
|
||||
GTEST_CPPSRCS \
|
||||
GTEST_CSRCS \
|
||||
HOST_CSRCS \
|
||||
HOST_LIBRARY_NAME \
|
||||
MODULE \
|
||||
|
|
|
@ -5476,7 +5476,6 @@ EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
* JSOP_SETELEM/JSOP_SETPROP would do.
|
||||
*/
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
if (pn->isKind(PNK_ARRAYCOMP)) {
|
||||
if (!EmitNewInit(cx, bce, JSProto_Array, pn))
|
||||
return false;
|
||||
|
@ -5496,7 +5495,6 @@ EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
/* Emit the usual op needed for decompilation. */
|
||||
return Emit1(cx, bce, JSOP_ENDINIT) >= 0;
|
||||
}
|
||||
#endif /* JS_HAS_GENERATORS */
|
||||
|
||||
if (!(pn->pn_xflags & PNX_NONCONST) && pn->pn_head && bce->checkSingletonContext())
|
||||
return EmitSingletonInitialiser(cx, bce, pn);
|
||||
|
@ -5782,7 +5780,6 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
ok = EmitReturn(cx, bce, pn);
|
||||
break;
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
case PNK_YIELD:
|
||||
JS_ASSERT(bce->sc->isFunctionBox());
|
||||
if (pn->pn_kid) {
|
||||
|
@ -5797,7 +5794,6 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
if (Emit1(cx, bce, JSOP_YIELD) < 0)
|
||||
return false;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case PNK_STATEMENTLIST:
|
||||
ok = EmitStatementList(cx, bce, pn, top);
|
||||
|
@ -5943,7 +5939,6 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
: EmitVariables(cx, bce, pn, InitializeVars);
|
||||
break;
|
||||
#endif /* JS_HAS_BLOCK_SCOPE */
|
||||
#if JS_HAS_GENERATORS
|
||||
case PNK_ARRAYPUSH: {
|
||||
int slot;
|
||||
|
||||
|
@ -5962,12 +5957,9 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
return false;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case PNK_ARRAY:
|
||||
#if JS_HAS_GENERATORS
|
||||
case PNK_ARRAYCOMP:
|
||||
#endif
|
||||
ok = EmitArray(cx, bce, pn);
|
||||
break;
|
||||
|
||||
|
|
|
@ -3692,12 +3692,9 @@ Parser<ParseHandler>::matchInOrOf(bool *isForOfp)
|
|||
*isForOfp = false;
|
||||
return true;
|
||||
}
|
||||
if (tokenStream.matchToken(TOK_NAME)) {
|
||||
if (tokenStream.currentToken().name() == context->names().of) {
|
||||
*isForOfp = true;
|
||||
return true;
|
||||
}
|
||||
tokenStream.ungetToken();
|
||||
if (tokenStream.matchContextualKeyword(context->names().of)) {
|
||||
*isForOfp = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -3764,13 +3761,9 @@ Parser<FullParseHandler>::forStatement()
|
|||
bool isForEach = false;
|
||||
unsigned iflags = 0;
|
||||
|
||||
if (allowsForEachIn() && tokenStream.matchToken(TOK_NAME)) {
|
||||
if (tokenStream.currentToken().name() == context->names().each) {
|
||||
iflags = JSITER_FOREACH;
|
||||
isForEach = true;
|
||||
} else {
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
if (allowsForEachIn() && tokenStream.matchContextualKeyword(context->names().each)) {
|
||||
iflags = JSITER_FOREACH;
|
||||
isForEach = true;
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||
|
@ -4394,7 +4387,6 @@ Parser<ParseHandler>::returnStatementOrYieldExpression()
|
|||
}
|
||||
|
||||
if (isYield) {
|
||||
JS_ASSERT(JS_HAS_GENERATORS);
|
||||
if (!abortIfSyntaxParser())
|
||||
return null();
|
||||
|
||||
|
@ -4883,13 +4875,11 @@ Parser<FullParseHandler>::expr()
|
|||
pn2->initList(pn);
|
||||
pn = pn2;
|
||||
do {
|
||||
#if JS_HAS_GENERATORS
|
||||
pn2 = pn->last();
|
||||
if (pn2->isKind(PNK_YIELD) && !pn2->isInParens()) {
|
||||
report(ParseError, false, pn2, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
|
||||
return null();
|
||||
}
|
||||
#endif
|
||||
pn2 = assignExpr();
|
||||
if (!pn2)
|
||||
return null();
|
||||
|
@ -5158,12 +5148,10 @@ Parser<ParseHandler>::assignExpr()
|
|||
{
|
||||
JS_CHECK_RECURSION(context, return null());
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
if (tokenStream.matchToken(TOK_YIELD, TSF_OPERAND))
|
||||
return returnStatementOrYieldExpression();
|
||||
if (tokenStream.hadError())
|
||||
return null();
|
||||
#endif
|
||||
|
||||
// Save the tokenizer state in case we find an arrow function and have to
|
||||
// rewind.
|
||||
|
@ -5369,8 +5357,6 @@ Parser<ParseHandler>::unaryExpr()
|
|||
return pn;
|
||||
}
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
|
||||
/*
|
||||
* A dedicated helper for transplanting the comprehension expression E in
|
||||
*
|
||||
|
@ -5807,12 +5793,8 @@ Parser<FullParseHandler>::comprehensionTail(ParseNode *kid, unsigned blockid, bo
|
|||
|
||||
pn2->setOp(JSOP_ITER);
|
||||
pn2->pn_iflags = JSITER_ENUMERATE;
|
||||
if (allowsForEachIn() && tokenStream.matchToken(TOK_NAME)) {
|
||||
if (tokenStream.currentToken().name() == context->names().each)
|
||||
pn2->pn_iflags |= JSITER_FOREACH;
|
||||
else
|
||||
tokenStream.ungetToken();
|
||||
}
|
||||
if (allowsForEachIn() && tokenStream.matchContextualKeyword(context->names().each))
|
||||
pn2->pn_iflags |= JSITER_FOREACH;
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);
|
||||
|
||||
GenexpGuard<FullParseHandler> guard(this);
|
||||
|
@ -6104,22 +6086,17 @@ Parser<SyntaxParseHandler>::generatorExpr(Node kid)
|
|||
static const char js_generator_str[] = "generator";
|
||||
|
||||
#endif /* JS_HAS_GENERATOR_EXPRS */
|
||||
#endif /* JS_HAS_GENERATORS */
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::assignExprWithoutYield(unsigned msg)
|
||||
{
|
||||
#ifdef JS_HAS_GENERATORS
|
||||
GenexpGuard<ParseHandler> yieldGuard(this);
|
||||
#endif
|
||||
Node res = assignExpr();
|
||||
yieldGuard.endBody();
|
||||
if (res) {
|
||||
#ifdef JS_HAS_GENERATORS
|
||||
if (!yieldGuard.checkValidBody(res, msg))
|
||||
return null();
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -6141,13 +6118,11 @@ Parser<ParseHandler>::argumentList(Node listNode)
|
|||
if (arg0)
|
||||
guard.endBody();
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
if (handler.isOperationWithoutParens(argNode, PNK_YIELD) &&
|
||||
tokenStream.peekToken() == TOK_COMMA) {
|
||||
report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#if JS_HAS_GENERATOR_EXPRS
|
||||
if (tokenStream.matchToken(TOK_FOR)) {
|
||||
if (!guard.checkValidBody(argNode))
|
||||
|
@ -6375,9 +6350,7 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt)
|
|||
pn = handler.newList(PNK_ARRAY, null(), JSOP_NEWINIT);
|
||||
if (!pn)
|
||||
return null();
|
||||
#if JS_HAS_GENERATORS
|
||||
handler.setBlockId(pn, pc->blockidGen);
|
||||
#endif
|
||||
|
||||
if (tokenStream.matchToken(TOK_RB, TSF_OPERAND)) {
|
||||
/*
|
||||
|
@ -6437,7 +6410,6 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt)
|
|||
}
|
||||
}
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
/*
|
||||
* At this point, (index == 0 && missingTrailingComma) implies one
|
||||
* element initialiser was parsed.
|
||||
|
@ -6483,7 +6455,6 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt)
|
|||
if (!arrayInitializerComprehensionTail(pn))
|
||||
return null();
|
||||
}
|
||||
#endif /* JS_HAS_GENERATORS */
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_LIST);
|
||||
}
|
||||
|
|
|
@ -631,6 +631,13 @@ class MOZ_STACK_CLASS TokenStream
|
|||
JS_ALWAYS_TRUE(matchToken(tt));
|
||||
}
|
||||
|
||||
bool matchContextualKeyword(PropertyName* keyword) {
|
||||
if (getToken() == TOK_NAME && currentToken().name() == keyword)
|
||||
return true;
|
||||
ungetToken();
|
||||
return false;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS Position {
|
||||
public:
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// |jit-test| error: can't convert
|
||||
Error.prototype.toString = Function;
|
||||
evaluate("n f", {
|
||||
noScriptRval: true,
|
||||
saveFrameChain: true
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
gczeal(4,1);
|
||||
var iterable = {persistedProp: 17};
|
||||
iterable.__iterator__ = function() {
|
||||
yield ["foo", 2];
|
||||
yield ["bar", 3];
|
||||
};
|
||||
var it = Iterator(iterable);
|
||||
assertEq(it.next().toString(), "foo,2");
|
||||
assertEq(it.next().toString(), "bar,3");
|
|
@ -1813,9 +1813,7 @@ static const JSStdName standard_class_atoms[] = {
|
|||
{js_InitStringClass, EAGER_ATOM_AND_OCLASP(String)},
|
||||
{js_InitExceptionClasses, EAGER_ATOM_AND_OCLASP(Error)},
|
||||
{js_InitRegExpClass, EAGER_ATOM_AND_OCLASP(RegExp)},
|
||||
#if JS_HAS_GENERATORS
|
||||
{js_InitIteratorClasses, EAGER_ATOM_AND_OCLASP(StopIteration)},
|
||||
#endif
|
||||
{js_InitJSONClass, EAGER_ATOM_AND_CLASP(JSON)},
|
||||
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js::ArrayBufferObject::protoClass},
|
||||
{js_InitWeakMapClass, EAGER_ATOM_AND_OCLASP(WeakMap)},
|
||||
|
|
|
@ -65,6 +65,7 @@ const char js_break_str[] = "break";
|
|||
const char js_case_str[] = "case";
|
||||
const char js_catch_str[] = "catch";
|
||||
const char js_class_str[] = "class";
|
||||
const char js_close_str[] = "close";
|
||||
const char js_const_str[] = "const";
|
||||
const char js_continue_str[] = "continue";
|
||||
const char js_debugger_str[] = "debugger";
|
||||
|
@ -89,6 +90,7 @@ const char js_package_str[] = "package";
|
|||
const char js_private_str[] = "private";
|
||||
const char js_protected_str[] = "protected";
|
||||
const char js_public_str[] = "public";
|
||||
const char js_send_str[] = "send";
|
||||
const char js_setter_str[] = "setter";
|
||||
const char js_static_str[] = "static";
|
||||
const char js_super_str[] = "super";
|
||||
|
@ -100,10 +102,6 @@ const char js_void_str[] = "void";
|
|||
const char js_while_str[] = "while";
|
||||
const char js_with_str[] = "with";
|
||||
const char js_yield_str[] = "yield";
|
||||
#if JS_HAS_GENERATORS
|
||||
const char js_close_str[] = "close";
|
||||
const char js_send_str[] = "send";
|
||||
#endif
|
||||
|
||||
/*
|
||||
* For a browser build from 2007-08-09 after the browser starts up there are
|
||||
|
|
|
@ -135,6 +135,7 @@ extern const char js_break_str[];
|
|||
extern const char js_case_str[];
|
||||
extern const char js_catch_str[];
|
||||
extern const char js_class_str[];
|
||||
extern const char js_close_str[];
|
||||
extern const char js_const_str[];
|
||||
extern const char js_continue_str[];
|
||||
extern const char js_debugger_str[];
|
||||
|
@ -159,6 +160,7 @@ extern const char js_package_str[];
|
|||
extern const char js_private_str[];
|
||||
extern const char js_protected_str[];
|
||||
extern const char js_public_str[];
|
||||
extern const char js_send_str[];
|
||||
extern const char js_setter_str[];
|
||||
extern const char js_static_str[];
|
||||
extern const char js_super_str[];
|
||||
|
@ -170,10 +172,6 @@ extern const char js_void_str[];
|
|||
extern const char js_while_str[];
|
||||
extern const char js_with_str[];
|
||||
extern const char js_yield_str[];
|
||||
#if JS_HAS_GENERATORS
|
||||
extern const char js_close_str[];
|
||||
extern const char js_send_str[];
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -1206,7 +1206,6 @@ js::CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
static JSBool
|
||||
fun_isGenerator(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
|
@ -1226,7 +1225,6 @@ fun_isGenerator(JSContext *cx, unsigned argc, Value *vp)
|
|||
JS_SET_RVAL(cx, vp, BooleanValue(result));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ES5 15.3.4.5. */
|
||||
static JSBool
|
||||
|
@ -1317,9 +1315,7 @@ const JSFunctionSpec js::function_methods[] = {
|
|||
JS_FN(js_apply_str, js_fun_apply, 2,0),
|
||||
JS_FN(js_call_str, js_fun_call, 1,0),
|
||||
JS_FN("bind", fun_bind, 1,0),
|
||||
#if JS_HAS_GENERATORS
|
||||
JS_FN("isGenerator", fun_isGenerator,0,0),
|
||||
#endif
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
|
@ -1351,6 +1347,7 @@ js::Function(JSContext *cx, unsigned argc, Value *vp)
|
|||
options.setPrincipals(principals)
|
||||
.setOriginPrincipals(originPrincipals)
|
||||
.setFileAndLine(filename, lineno)
|
||||
.setNoScriptRval(false)
|
||||
.setCompileAndGo(true);
|
||||
|
||||
unsigned n = args.length() ? args.length() - 1 : 0;
|
||||
|
|
|
@ -959,10 +959,8 @@ const JSFunctionSpec ElementIteratorObject::methods[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
static JSBool
|
||||
CloseGenerator(JSContext *cx, HandleObject genobj);
|
||||
#endif
|
||||
|
||||
bool
|
||||
js::ValueToIterator(JSContext *cx, unsigned flags, MutableHandleValue vp)
|
||||
|
@ -1024,12 +1022,9 @@ js::CloseIterator(JSContext *cx, HandleObject obj)
|
|||
*/
|
||||
ni->props_cursor = ni->props_array;
|
||||
}
|
||||
}
|
||||
#if JS_HAS_GENERATORS
|
||||
else if (obj->is<GeneratorObject>()) {
|
||||
} else if (obj->is<GeneratorObject>()) {
|
||||
return CloseGenerator(cx, obj);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1320,8 +1315,6 @@ Class StopIterationObject::class_ = {
|
|||
|
||||
/*** Generators **********************************************************************************/
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
|
||||
static void
|
||||
generator_finalize(FreeOp *fop, JSObject *obj)
|
||||
{
|
||||
|
@ -1418,11 +1411,6 @@ GeneratorState::pushInterpreterFrame(JSContext *cx, FrameGuard *)
|
|||
* or else some kind of epoch scheme would have to be used.
|
||||
*/
|
||||
GeneratorWriteBarrierPre(cx, gen_);
|
||||
|
||||
/*
|
||||
* Don't change the state until after the frame is successfully pushed
|
||||
* or else we might fail to scan some generator values.
|
||||
*/
|
||||
gen_->state = futureState_;
|
||||
|
||||
gen_->fp->clearSuspended();
|
||||
|
@ -1561,9 +1549,12 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, HandleObject obj,
|
|||
if (gen->state == JSGEN_OPEN) {
|
||||
/*
|
||||
* Store the argument to send as the result of the yield
|
||||
* expression.
|
||||
* expression. The generator stack is not barriered, so we need
|
||||
* write barriers here.
|
||||
*/
|
||||
HeapValue::writeBarrierPre(gen->regs.sp[-1]);
|
||||
gen->regs.sp[-1] = arg;
|
||||
HeapValue::writeBarrierPost(cx->runtime(), gen->regs.sp[-1], &gen->regs.sp[-1]);
|
||||
}
|
||||
futureState = JSGEN_RUNNING;
|
||||
break;
|
||||
|
@ -1777,8 +1768,6 @@ static const JSFunctionSpec generator_methods[] = {
|
|||
JS_FS_END
|
||||
};
|
||||
|
||||
#endif /* JS_HAS_GENERATORS */
|
||||
|
||||
/* static */ bool
|
||||
GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
|
||||
{
|
||||
|
@ -1820,14 +1809,12 @@ GlobalObject::initIteratorClasses(JSContext *cx, Handle<GlobalObject *> global)
|
|||
global->setReservedSlot(ELEMENT_ITERATOR_PROTO, ObjectValue(*proto));
|
||||
}
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
if (global->getSlot(GENERATOR_PROTO).isUndefined()) {
|
||||
proto = global->createBlankPrototype(cx, &GeneratorObject::class_);
|
||||
if (!proto || !DefinePropertiesAndBrand(cx, proto, NULL, generator_methods))
|
||||
return false;
|
||||
global->setReservedSlot(GENERATOR_PROTO, ObjectValue(*proto));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (global->getPrototype(JSProto_StopIteration).isUndefined()) {
|
||||
proto = global->createBlankPrototype(cx, &StopIterationObject::class_);
|
||||
|
|
|
@ -324,8 +324,6 @@ class ForOfIterator
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
|
||||
/*
|
||||
* Generator state codes.
|
||||
*/
|
||||
|
@ -357,7 +355,6 @@ bool
|
|||
GeneratorHasMarkableFrame(JSGenerator *gen);
|
||||
|
||||
} /* namespace js */
|
||||
#endif
|
||||
|
||||
extern JSObject *
|
||||
js_InitIteratorClasses(JSContext *cx, js::HandleObject obj);
|
||||
|
|
|
@ -2786,12 +2786,7 @@ ASTSerializer::function(ParseNode *pn, ASTType type, MutableHandleValue dst)
|
|||
{
|
||||
RootedFunction func(cx, pn->pn_funbox->function());
|
||||
|
||||
bool isGenerator =
|
||||
#if JS_HAS_GENERATORS
|
||||
pn->pn_funbox->isGenerator();
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
bool isGenerator = pn->pn_funbox->isGenerator();
|
||||
|
||||
bool isExpression =
|
||||
#if JS_HAS_EXPR_CLOSURES
|
||||
|
|
|
@ -1195,7 +1195,6 @@ Interpret(JSContext *cx, RunState &state)
|
|||
RootedScript rootScript0(cx);
|
||||
DebugOnly<uint32_t> blockDepth;
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
|
||||
JS_ASSERT(size_t(regs.pc - script->code) <= script->length);
|
||||
JS_ASSERT(regs.stackDepth() <= script->nslots);
|
||||
|
@ -1209,7 +1208,6 @@ Interpret(JSContext *cx, RunState &state)
|
|||
goto error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* State communicated between non-local jumps: */
|
||||
bool interpReturnOK;
|
||||
|
@ -3050,7 +3048,6 @@ BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
|
|||
}
|
||||
END_CASE(JSOP_LEAVEBLOCK)
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
BEGIN_CASE(JSOP_GENERATOR)
|
||||
{
|
||||
JS_ASSERT(!cx->isExceptionPending());
|
||||
|
@ -3094,7 +3091,6 @@ BEGIN_CASE(JSOP_ARRAYPUSH)
|
|||
regs.sp--;
|
||||
}
|
||||
END_CASE(JSOP_ARRAYPUSH)
|
||||
#endif /* JS_HAS_GENERATORS */
|
||||
|
||||
default:
|
||||
{
|
||||
|
@ -3149,11 +3145,9 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
case JSTRY_CATCH:
|
||||
JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK);
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
/* Catch cannot intercept the closing of a generator. */
|
||||
if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
|
||||
break;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Don't clear exceptions to save cx->exception from GC
|
||||
|
@ -3196,14 +3190,12 @@ END_CASE(JSOP_ARRAYPUSH)
|
|||
* is an asynchronous return from a generator.
|
||||
*/
|
||||
interpReturnOK = false;
|
||||
#if JS_HAS_GENERATORS
|
||||
if (JS_UNLIKELY(cx->isExceptionPending() &&
|
||||
cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) {
|
||||
cx->clearPendingException();
|
||||
interpReturnOK = true;
|
||||
regs.fp()->clearReturnValue();
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
UnwindForUncatchableException(cx, regs);
|
||||
interpReturnOK = false;
|
||||
|
|
|
@ -25,13 +25,6 @@
|
|||
# define FOR_LET_KEYWORD(macro) \
|
||||
macro(let, let, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_1_7)
|
||||
#endif
|
||||
#if JS_HAS_GENERATORS
|
||||
# define FOR_YIELD_KEYWORD(macro) \
|
||||
macro(yield, yield, TOK_YIELD, JSOP_NOP, JSVERSION_1_7)
|
||||
#else
|
||||
# define FOR_YIELD_KEYWORD(macro) \
|
||||
macro(yield, yield, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_1_7)
|
||||
#endif
|
||||
|
||||
#define FOR_EACH_JAVASCRIPT_KEYWORD(macro) \
|
||||
macro(false, false_, TOK_FALSE, JSOP_FALSE, JSVERSION_DEFAULT) \
|
||||
|
@ -79,9 +72,10 @@
|
|||
macro(protected, protected_, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) \
|
||||
macro(public, public_, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) \
|
||||
macro(static, static_, TOK_STRICT_RESERVED, JSOP_NOP, JSVERSION_DEFAULT) \
|
||||
/* ES5 future reserved keyword in strict mode, keyword in JS1.7 even when not strict. */ \
|
||||
macro(yield, yield, TOK_YIELD, JSOP_NOP, JSVERSION_1_7) \
|
||||
/* Various conditional keywords. */ \
|
||||
FOR_CONST_KEYWORD(macro) \
|
||||
FOR_LET_KEYWORD(macro) \
|
||||
FOR_YIELD_KEYWORD(macro)
|
||||
FOR_LET_KEYWORD(macro)
|
||||
|
||||
#endif /* vm_Keywords_h */
|
||||
|
|
|
@ -244,6 +244,11 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint)
|
|||
isHit = tmpCtx->PointInFill(userSpacePoint);
|
||||
if (!isHit && (hitTestFlags & SVG_HIT_TEST_STROKE)) {
|
||||
nsSVGUtils::SetupCairoStrokeGeometry(this, tmpCtx);
|
||||
// tmpCtx's matrix may have transformed by SetupCairoStrokeGeometry
|
||||
// if there is a non-scaling stroke. We need to transform userSpacePoint
|
||||
// so that everything is using the same co-ordinate system.
|
||||
userSpacePoint =
|
||||
nsSVGUtils::GetStrokeTransform(this).Invert().Transform(userSpacePoint);
|
||||
isHit = tmpCtx->PointInStroke(userSpacePoint);
|
||||
}
|
||||
|
||||
|
|
|
@ -456,7 +456,7 @@ pref("breakpad.reportURL", "https://crash-stats.mozilla.com/report/index/");
|
|||
pref("app.support.baseURL", "http://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/");
|
||||
// Used to submit data to input from about:feedback
|
||||
pref("app.feedback.postURL", "https://input.mozilla.org/%LOCALE%/feedback");
|
||||
pref("app.privacyURL", "http://www.mozilla.org/%LOCALE%/privacy/");
|
||||
pref("app.privacyURL", "https://www.mozilla.org/legal/privacy/firefox.html");
|
||||
pref("app.creditsURL", "http://www.mozilla.org/credits/");
|
||||
pref("app.channelURL", "http://www.mozilla.org/%LOCALE%/firefox/channel/");
|
||||
#if MOZ_UPDATE_CHANNEL == aurora
|
||||
|
|
|
@ -87,6 +87,9 @@ class TreeMetadataEmitter(object):
|
|||
EXTRA_COMPONENTS='EXTRA_COMPONENTS',
|
||||
EXTRA_JS_MODULES='EXTRA_JS_MODULES',
|
||||
EXTRA_PP_COMPONENTS='EXTRA_PP_COMPONENTS',
|
||||
GTEST_CMMSRCS='GTEST_CMM_SOURCES',
|
||||
GTEST_CPPSRCS='GTEST_CPP_SOURCES',
|
||||
GTEST_CSRCS='GTEST_C_SOURCES',
|
||||
HOST_CSRCS='HOST_CSRCS',
|
||||
HOST_LIBRARY_NAME='HOST_LIBRARY_NAME',
|
||||
JS_MODULES_PATH='JS_MODULES_PATH',
|
||||
|
|
|
@ -118,6 +118,27 @@ VARIABLES = {
|
|||
files will be installed in the /components directory of the distribution.
|
||||
"""),
|
||||
|
||||
'GTEST_C_SOURCES': (StrictOrderingOnAppendList, list, [],
|
||||
"""C code source files for GTest unit tests.
|
||||
|
||||
This variable contains a list of C GTEST unit test source files to
|
||||
compile.
|
||||
"""),
|
||||
|
||||
'GTEST_CMM_SOURCES': (StrictOrderingOnAppendList, list, [],
|
||||
"""Sources for GTest unit tests to compile with the Objective C/C++ compiler.
|
||||
|
||||
This variable contains a list of objective-C++ GTest unit test sources
|
||||
to compile.
|
||||
"""),
|
||||
|
||||
'GTEST_CPP_SOURCES': (list, list, [],
|
||||
"""C++ source files for GTest unit tests.
|
||||
|
||||
This is a list of C++ GTest unit test sources. Entries must be files
|
||||
that exist. These generally have .cpp, .cc, or .cxx extensions.
|
||||
"""),
|
||||
|
||||
'HOST_CSRCS': (StrictOrderingOnAppendList, list, [],
|
||||
"""C source files to compile with the host compiler.
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@ DEFINES = ['-Dbar', '-Dfoo']
|
|||
EXTRA_COMPONENTS = ['bar.js', 'foo.js']
|
||||
EXTRA_PP_COMPONENTS = ['bar.pp.js', 'foo.pp.js']
|
||||
|
||||
GTEST_C_SOURCES = ['test1.c', 'test2.c']
|
||||
GTEST_CMM_SOURCES = ['test1.mm', 'test2.mm']
|
||||
GTEST_CPP_SOURCES = ['test1.cpp', 'test2.cpp']
|
||||
|
||||
HOST_CSRCS = ['bar.c', 'foo.c']
|
||||
|
||||
HOST_LIBRARY_NAME = 'host_bar'
|
||||
|
|
|
@ -162,6 +162,18 @@ class TestRecursiveMakeBackend(BackendTester):
|
|||
'EXTRA_PP_COMPONENTS += bar.pp.js',
|
||||
'EXTRA_PP_COMPONENTS += foo.pp.js',
|
||||
],
|
||||
'GTEST_CMMSRCS': [
|
||||
'GTEST_CMMSRCS += test1.mm',
|
||||
'GTEST_CMMSRCS += test2.mm',
|
||||
],
|
||||
'GTEST_CPPSRCS': [
|
||||
'GTEST_CPPSRCS += test1.cpp',
|
||||
'GTEST_CPPSRCS += test2.cpp',
|
||||
],
|
||||
'GTEST_CSRCS': [
|
||||
'GTEST_CSRCS += test1.c',
|
||||
'GTEST_CSRCS += test2.c',
|
||||
],
|
||||
'HOST_CSRCS': [
|
||||
'HOST_CSRCS += bar.c',
|
||||
'HOST_CSRCS += foo.c',
|
||||
|
|
|
@ -13,6 +13,10 @@ DEFINES=['-Dfans', '-Dtans']
|
|||
EXTRA_COMPONENTS=['fans.js', 'tans.js']
|
||||
EXTRA_PP_COMPONENTS=['fans.pp.js', 'tans.pp.js']
|
||||
|
||||
GTEST_C_SOURCES = ['test1.c', 'test2.c']
|
||||
GTEST_CMM_SOURCES = ['test1.mm', 'test2.mm']
|
||||
GTEST_CPP_SOURCES = ['test1.cpp', 'test2.cpp']
|
||||
|
||||
HOST_CSRCS += ['fans.c', 'tans.c']
|
||||
|
||||
HOST_LIBRARY_NAME = 'host_fans'
|
||||
|
|
|
@ -131,6 +131,9 @@ class TestEmitterBasic(unittest.TestCase):
|
|||
DEFINES=['-Dfans', '-Dtans'],
|
||||
EXTRA_COMPONENTS=['fans.js', 'tans.js'],
|
||||
EXTRA_PP_COMPONENTS=['fans.pp.js', 'tans.pp.js'],
|
||||
GTEST_CSRCS=['test1.c', 'test2.c'],
|
||||
GTEST_CMMSRCS=['test1.mm', 'test2.mm'],
|
||||
GTEST_CPPSRCS=['test1.cpp', 'test2.cpp'],
|
||||
HOST_CSRCS=['fans.c', 'tans.c'],
|
||||
HOST_LIBRARY_NAME='host_fans',
|
||||
LIBRARY_NAME='lib_name',
|
||||
|
|
|
@ -22,10 +22,6 @@ EXPORT_LIBRARY = 1
|
|||
LIBXUL_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
|
||||
GTEST_CPPSRCS = \
|
||||
SanityTest.cpp \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(srcdir)/gtest \
|
||||
-I$(srcdir)/gtest/include \
|
||||
|
|
|
@ -61,3 +61,7 @@ CPP_SOURCES += [
|
|||
|
||||
LIBRARY_NAME = 'gtest'
|
||||
|
||||
GTEST_CPP_SOURCES += [
|
||||
'SanityTest.cpp',
|
||||
]
|
||||
|
||||
|
|
|
@ -45,6 +45,17 @@ try {
|
|||
}
|
||||
catch (e) { }
|
||||
|
||||
// Only if building of places is enabled.
|
||||
if (runningInParent &&
|
||||
"mozIAsyncHistory" in Components.interfaces) {
|
||||
// Ensure places history is enabled for xpcshell-tests as some non-FF
|
||||
// apps disable it.
|
||||
let (prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
.getService(Components.interfaces.nsIPrefBranch)) {
|
||||
prefs.setBoolPref("places.history.enabled", true);
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
if (runningInParent) {
|
||||
let prefs = Components.classes["@mozilla.org/preferences-service;1"]
|
||||
|
|
|
@ -36,9 +36,6 @@ add_task(function test_execute()
|
|||
if (!("@mozilla.org/browser/nav-history-service;1" in Cc))
|
||||
return;
|
||||
|
||||
// Ensure places is enabled.
|
||||
Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
|
||||
let dm = Cc["@mozilla.org/download-manager;1"].
|
||||
getService(Ci.nsIDownloadManager);
|
||||
let db = dm.DBConnection;
|
||||
|
|
|
@ -440,6 +440,23 @@ DownloadSource.prototype = {
|
|||
* should be sent or the download source is not HTTP.
|
||||
*/
|
||||
referrer: null,
|
||||
|
||||
/**
|
||||
* Returns a static representation of the current object state.
|
||||
*
|
||||
* @return A JavaScript object that can be serialized to JSON.
|
||||
*/
|
||||
serialize: function DS_serialize()
|
||||
{
|
||||
let serialized = { uri: this.uri.spec };
|
||||
if (this.isPrivate) {
|
||||
serialized.isPrivate = true;
|
||||
}
|
||||
if (this.referrer) {
|
||||
serialized.referrer = this.referrer.spec;
|
||||
}
|
||||
return serialized;
|
||||
},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -456,6 +473,16 @@ DownloadTarget.prototype = {
|
|||
* The nsIFile for the download target.
|
||||
*/
|
||||
file: null,
|
||||
|
||||
/**
|
||||
* Returns a static representation of the current object state.
|
||||
*
|
||||
* @return A JavaScript object that can be serialized to JSON.
|
||||
*/
|
||||
serialize: function DT_serialize()
|
||||
{
|
||||
return { file: this.file.path };
|
||||
},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -555,6 +582,16 @@ DownloadSaver.prototype = {
|
|||
{
|
||||
throw new Error("Not implemented.");
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a static representation of the current object state.
|
||||
*
|
||||
* @return A JavaScript object that can be serialized to JSON.
|
||||
*/
|
||||
serialize: function DS_serialize()
|
||||
{
|
||||
throw new Error("Not implemented.");
|
||||
},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -686,6 +723,14 @@ DownloadCopySaver.prototype = {
|
|||
this._backgroundFileSaver = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Implements "DownloadSaver.serialize".
|
||||
*/
|
||||
serialize: function DCS_serialize()
|
||||
{
|
||||
return { type: "copy" };
|
||||
},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -25,14 +25,16 @@ const Cr = Components.results;
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
|
||||
"resource://gre/modules/DownloadStore.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm")
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
"resource://gre/modules/FileUtils.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "env",
|
||||
"@mozilla.org/process/environment;1",
|
||||
"nsIEnvironment");
|
||||
|
@ -51,6 +53,44 @@ XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
|
|||
this.DownloadIntegration = {
|
||||
// For testing only
|
||||
testMode: false,
|
||||
dontLoad: false,
|
||||
|
||||
/**
|
||||
* Main DownloadStore object for loading and saving the list of persistent
|
||||
* downloads, or null if the download list was never requested and thus it
|
||||
* doesn't need to be persisted.
|
||||
*/
|
||||
_store: null,
|
||||
|
||||
/**
|
||||
* Performs initialization of the list of persistent downloads, before its
|
||||
* first use by the host application. This function may be called only once
|
||||
* during the entire lifetime of the application.
|
||||
*
|
||||
* @param aList
|
||||
* DownloadList object to be populated with the download objects
|
||||
* serialized from the previous session. This list will be persisted
|
||||
* to disk during the session lifetime or when the session terminates.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the list has been populated.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
loadPersistent: function DI_loadPersistent(aList)
|
||||
{
|
||||
if (this.dontLoad) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (this._store) {
|
||||
throw new Error("loadPersistent may be called only once.");
|
||||
}
|
||||
|
||||
this._store = new DownloadStore(aList, OS.Path.join(
|
||||
OS.Constants.Path.profileDir,
|
||||
"downloads.json"));
|
||||
return this._store.load();
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the system downloads directory asynchronously.
|
||||
|
|
|
@ -25,14 +25,144 @@ const Cr = Components.results;
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
|
||||
"resource://gre/modules/Downloads.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
|
||||
"resource://gre/modules/NetUtil.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm")
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
const LocalFile = Components.Constructor("@mozilla.org/file/local;1",
|
||||
"nsIFile", "initWithPath");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () {
|
||||
return new TextDecoder();
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gTextEncoder", function () {
|
||||
return new TextEncoder();
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// DownloadStore
|
||||
|
||||
/**
|
||||
* Handles serialization of Download objects and persistence into a file, so
|
||||
* that the state of downloads can be restored across sessions.
|
||||
*
|
||||
* @param aList
|
||||
* DownloadList object to be populated or serialized.
|
||||
* @param aPath
|
||||
* String containing the file path where data should be saved.
|
||||
*/
|
||||
function DownloadStore() { }
|
||||
function DownloadStore(aList, aPath)
|
||||
{
|
||||
this.list = aList;
|
||||
this.path = aPath;
|
||||
}
|
||||
|
||||
DownloadStore.prototype = {
|
||||
/**
|
||||
* DownloadList object to be populated or serialized.
|
||||
*/
|
||||
list: null,
|
||||
|
||||
/**
|
||||
* String containing the file path where data should be saved.
|
||||
*/
|
||||
path: "",
|
||||
|
||||
/**
|
||||
* Loads persistent downloads from the file to the list.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the operation finished successfully.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
load: function DS_load()
|
||||
{
|
||||
return Task.spawn(function task_DS_load() {
|
||||
let bytes;
|
||||
try {
|
||||
bytes = yield OS.File.read(this.path);
|
||||
} catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
|
||||
// If the file does not exist, there are no downloads to load.
|
||||
return;
|
||||
}
|
||||
|
||||
let storeData = JSON.parse(gTextDecoder.decode(bytes));
|
||||
|
||||
// Create live downloads based on the static snapshot.
|
||||
for (let downloadData of storeData) {
|
||||
try {
|
||||
let source = { uri: NetUtil.newURI(downloadData.source.uri) };
|
||||
if ("referrer" in downloadData.source) {
|
||||
source.referrer = NetUtil.newURI(downloadData.source.referrer);
|
||||
}
|
||||
let download = yield Downloads.createDownload({
|
||||
source: source,
|
||||
target: { file: new LocalFile(downloadData.target.file) },
|
||||
saver: downloadData.saver,
|
||||
});
|
||||
|
||||
this.list.add(download);
|
||||
} catch (ex) {
|
||||
// If an item is unrecognized, don't prevent others from being loaded.
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
* Saves persistent downloads from the list to the file.
|
||||
*
|
||||
* If an error occurs, the previous file is not deleted.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves When the operation finished successfully.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
save: function DS_save()
|
||||
{
|
||||
return Task.spawn(function task_DS_save() {
|
||||
let downloads = yield this.list.getAll();
|
||||
|
||||
// Take a static snapshot of the current state of all the downloads.
|
||||
let storeData = [];
|
||||
let atLeastOneDownload = false;
|
||||
for (let download of downloads) {
|
||||
try {
|
||||
storeData.push({
|
||||
source: download.source.serialize(),
|
||||
target: download.target.serialize(),
|
||||
saver: download.saver.serialize(),
|
||||
});
|
||||
atLeastOneDownload = true;
|
||||
} catch (ex) {
|
||||
// If an item cannot be serialized, don't prevent others from being
|
||||
// saved.
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (atLeastOneDownload) {
|
||||
// Create or overwrite the file if there are downloads to save.
|
||||
let bytes = gTextEncoder.encode(JSON.stringify(storeData));
|
||||
yield OS.File.writeAtomic(this.path, bytes,
|
||||
{ tmpPath: this.path + ".tmp" });
|
||||
} else {
|
||||
// Remove the file if there are no downloads to save at all.
|
||||
try {
|
||||
yield OS.File.remove(this.path);
|
||||
} catch (ex if ex instanceof OS.File.Error &&
|
||||
(ex.becauseNoSuchFile || ex.becauseAccessDenied)) {
|
||||
// On Windows, we may get an access denied error instead of a no such
|
||||
// file error if the file existed before, and was recently deleted.
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
};
|
||||
|
|
|
@ -29,8 +29,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "DownloadIntegration",
|
|||
"resource://gre/modules/DownloadIntegration.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadList",
|
||||
"resource://gre/modules/DownloadList.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
|
||||
"resource://gre/modules/DownloadStore.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadUIHelper",
|
||||
"resource://gre/modules/DownloadUIHelper.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
|
||||
|
@ -173,12 +171,27 @@ this.Downloads = {
|
|||
*/
|
||||
getPublicDownloadList: function D_getPublicDownloadList()
|
||||
{
|
||||
if (!this._publicDownloadList) {
|
||||
this._publicDownloadList = new DownloadList(true);
|
||||
if (!this._promisePublicDownloadList) {
|
||||
this._promisePublicDownloadList = Task.spawn(
|
||||
function task_D_getPublicDownloadList() {
|
||||
let list = new DownloadList(true);
|
||||
try {
|
||||
yield DownloadIntegration.loadPersistent(list);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
throw new Task.Result(list);
|
||||
});
|
||||
}
|
||||
return Promise.resolve(this._publicDownloadList);
|
||||
return this._promisePublicDownloadList;
|
||||
},
|
||||
_publicDownloadList: null,
|
||||
|
||||
/**
|
||||
* This promise is resolved with a reference to a DownloadList object that
|
||||
* represents persistent downloads. This property is null before the list of
|
||||
* downloads is requested for the first time.
|
||||
*/
|
||||
_promisePublicDownloadList: null,
|
||||
|
||||
/**
|
||||
* Retrieves the DownloadList object for downloads that were started from
|
||||
|
|
|
@ -75,6 +75,8 @@ const TEST_INTERRUPTIBLE_GZIP_URI = NetUtil.newURI(HTTP_BASE +
|
|||
TEST_INTERRUPTIBLE_GZIP_PATH);
|
||||
|
||||
const TEST_TARGET_FILE_NAME = "test-download.txt";
|
||||
const TEST_STORE_FILE_NAME = "test-downloads.json";
|
||||
|
||||
const TEST_DATA_SHORT = "This test string is downloaded.";
|
||||
// Generate using gzipCompressString in TelemetryPing.js.
|
||||
const TEST_DATA_SHORT_GZIP_ENCODED_FIRST = [
|
||||
|
@ -184,6 +186,32 @@ function promiseSimpleDownload(aSourceURI) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new public DownloadList object.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The newly created DownloadList object.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
function promiseNewDownloadList() {
|
||||
// Force the creation of a new public download list.
|
||||
Downloads._promisePublicDownloadList = null;
|
||||
return Downloads.getPublicDownloadList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new private DownloadList object.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The newly created DownloadList object.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
function promiseNewPrivateDownloadList() {
|
||||
// Force the creation of a new public download list.
|
||||
Downloads._privateDownloadList = null;
|
||||
return Downloads.getPrivateDownloadList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the given file contents are equal to the given string.
|
||||
*
|
||||
|
@ -420,4 +448,7 @@ add_task(function test_common_initialize()
|
|||
bos.writeByteArray(TEST_DATA_SHORT_GZIP_ENCODED_SECOND,
|
||||
TEST_DATA_SHORT_GZIP_ENCODED_SECOND.length);
|
||||
});
|
||||
|
||||
// Disable integration with the host application requiring profile access.
|
||||
DownloadIntegration.dontLoad = true;
|
||||
});
|
||||
|
|
|
@ -9,35 +9,6 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
/**
|
||||
* Returns a new DownloadList object.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The newly created DownloadList object.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
function promiseNewDownloadList() {
|
||||
// Force the creation of a new public download list.
|
||||
Downloads._publicDownloadList = null;
|
||||
return Downloads.getPublicDownloadList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new private DownloadList object.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves The newly created DownloadList object.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
function promiseNewPrivateDownloadList() {
|
||||
// Force the creation of a new public download list.
|
||||
Downloads._privateDownloadList = null;
|
||||
return Downloads.getPrivateDownloadList();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Tests
|
||||
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests the DownloadStore object.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Globals
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DownloadStore",
|
||||
"resource://gre/modules/DownloadStore.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm")
|
||||
|
||||
/**
|
||||
* Returns a new DownloadList object with an associated DownloadStore.
|
||||
*
|
||||
* @param aStorePath
|
||||
* String pointing to the file to be associated with the DownloadStore,
|
||||
* or undefined to use a non-existing temporary file. In this case, the
|
||||
* temporary file is deleted when the test file execution finishes.
|
||||
*
|
||||
* @return {Promise}
|
||||
* @resolves Array [ Newly created DownloadList , associated DownloadStore ].
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
function promiseNewListAndStore(aStorePath) {
|
||||
return promiseNewDownloadList().then(function (aList) {
|
||||
let path = aStorePath || getTempFile(TEST_STORE_FILE_NAME).path;
|
||||
let store = new DownloadStore(aList, path);
|
||||
return [aList, store];
|
||||
});
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// Tests
|
||||
|
||||
/**
|
||||
* Saves downloads to a file, then reloads them.
|
||||
*/
|
||||
add_task(function test_save_reload()
|
||||
{
|
||||
let [listForSave, storeForSave] = yield promiseNewListAndStore();
|
||||
let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
|
||||
storeForSave.path);
|
||||
|
||||
listForSave.add(yield promiseSimpleDownload(TEST_SOURCE_URI));
|
||||
listForSave.add(yield Downloads.createDownload({
|
||||
source: { uri: TEST_EMPTY_URI,
|
||||
referrer: TEST_REFERRER_URI },
|
||||
target: { file: getTempFile(TEST_TARGET_FILE_NAME) },
|
||||
saver: { type: "copy" },
|
||||
}));
|
||||
|
||||
yield storeForSave.save();
|
||||
yield storeForLoad.load();
|
||||
|
||||
let itemsForSave = yield listForSave.getAll();
|
||||
let itemsForLoad = yield listForLoad.getAll();
|
||||
|
||||
do_check_eq(itemsForSave.length, itemsForLoad.length);
|
||||
|
||||
// Downloads should be reloaded in the same order.
|
||||
for (let i = 0; i < itemsForSave.length; i++) {
|
||||
// The reloaded downloads are different objects.
|
||||
do_check_neq(itemsForSave[i], itemsForLoad[i]);
|
||||
|
||||
// The reloaded downloads have the same properties.
|
||||
do_check_true(itemsForSave[i].source.uri.equals(
|
||||
itemsForLoad[i].source.uri));
|
||||
if (itemsForSave[i].source.referrer) {
|
||||
do_check_true(itemsForSave[i].source.referrer.equals(
|
||||
itemsForLoad[i].source.referrer));
|
||||
} else {
|
||||
do_check_true(itemsForLoad[i].source.referrer === null);
|
||||
}
|
||||
do_check_true(itemsForSave[i].target.file.equals(
|
||||
itemsForLoad[i].target.file));
|
||||
do_check_eq(itemsForSave[i].saver.type,
|
||||
itemsForLoad[i].saver.type);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that saving an empty list deletes any existing file.
|
||||
*/
|
||||
add_task(function test_save_empty()
|
||||
{
|
||||
let [list, store] = yield promiseNewListAndStore();
|
||||
|
||||
let createdFile = yield OS.File.open(store.path, { create: true });
|
||||
yield createdFile.close();
|
||||
|
||||
yield store.save();
|
||||
|
||||
do_check_false(yield OS.File.exists(store.path));
|
||||
|
||||
// If the file does not exist, saving should not generate exceptions.
|
||||
yield store.save();
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks that loading from a missing file results in an empty list.
|
||||
*/
|
||||
add_task(function test_load_empty()
|
||||
{
|
||||
let [list, store] = yield promiseNewListAndStore();
|
||||
|
||||
do_check_false(yield OS.File.exists(store.path));
|
||||
|
||||
yield store.load();
|
||||
|
||||
let items = yield list.getAll();
|
||||
do_check_eq(items.length, 0);
|
||||
});
|
||||
|
||||
/**
|
||||
* Loads downloads from a string in a predefined format. The purpose of this
|
||||
* test is to verify that the JSON format used in previous versions can be
|
||||
* loaded, assuming the file is reloaded on the same platform.
|
||||
*/
|
||||
add_task(function test_load_string_predefined()
|
||||
{
|
||||
let [list, store] = yield promiseNewListAndStore();
|
||||
|
||||
// The platform-dependent file name should be generated dynamically.
|
||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
let filePathLiteral = JSON.stringify(targetFile.path);
|
||||
let sourceUriLiteral = JSON.stringify(TEST_SOURCE_URI.spec);
|
||||
let emptyUriLiteral = JSON.stringify(TEST_EMPTY_URI.spec);
|
||||
let referrerUriLiteral = JSON.stringify(TEST_REFERRER_URI.spec);
|
||||
|
||||
let string = "[{\"source\":{\"uri\":" + sourceUriLiteral + "}," +
|
||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
||||
"\"saver\":{\"type\":\"copy\"}}," +
|
||||
"{\"source\":{\"uri\":" + emptyUriLiteral + "," +
|
||||
"\"referrer\":" + referrerUriLiteral + "}," +
|
||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
||||
"\"saver\":{\"type\":\"copy\"}}]";
|
||||
|
||||
yield OS.File.writeAtomic(store.path,
|
||||
new TextEncoder().encode(string),
|
||||
{ tmpPath: store.path + ".tmp" });
|
||||
|
||||
yield store.load();
|
||||
|
||||
let items = yield list.getAll();
|
||||
|
||||
do_check_eq(items.length, 2);
|
||||
|
||||
do_check_true(items[0].source.uri.equals(TEST_SOURCE_URI));
|
||||
do_check_true(items[0].target.file.equals(targetFile));
|
||||
|
||||
do_check_true(items[1].source.uri.equals(TEST_EMPTY_URI));
|
||||
do_check_true(items[1].source.referrer.equals(TEST_REFERRER_URI));
|
||||
do_check_true(items[1].target.file.equals(targetFile));
|
||||
});
|
||||
|
||||
/**
|
||||
* Loads downloads from a well-formed JSON string containing unrecognized data.
|
||||
*/
|
||||
add_task(function test_load_string_unrecognized()
|
||||
{
|
||||
let [list, store] = yield promiseNewListAndStore();
|
||||
|
||||
// The platform-dependent file name should be generated dynamically.
|
||||
let targetFile = getTempFile(TEST_TARGET_FILE_NAME);
|
||||
let filePathLiteral = JSON.stringify(targetFile.path);
|
||||
let sourceUriLiteral = JSON.stringify(TEST_SOURCE_URI.spec);
|
||||
|
||||
let string = "[{\"source\":null," +
|
||||
"\"target\":null}," +
|
||||
"{\"source\":{\"uri\":" + sourceUriLiteral + "}," +
|
||||
"\"target\":{\"file\":" + filePathLiteral + "}," +
|
||||
"\"saver\":{\"type\":\"copy\"}}]";
|
||||
|
||||
yield OS.File.writeAtomic(store.path,
|
||||
new TextEncoder().encode(string),
|
||||
{ tmpPath: store.path + ".tmp" });
|
||||
|
||||
yield store.load();
|
||||
|
||||
let items = yield list.getAll();
|
||||
|
||||
do_check_eq(items.length, 1);
|
||||
|
||||
do_check_true(items[0].source.uri.equals(TEST_SOURCE_URI));
|
||||
do_check_true(items[0].target.file.equals(targetFile));
|
||||
});
|
||||
|
||||
/**
|
||||
* Loads downloads from a malformed JSON string.
|
||||
*/
|
||||
add_task(function test_load_string_malformed()
|
||||
{
|
||||
let [list, store] = yield promiseNewListAndStore();
|
||||
|
||||
let string = "[{\"source\":null,\"target\":null}," +
|
||||
"{\"source\":{\"uri\":\"about:blank\"}}";
|
||||
|
||||
yield OS.File.writeAtomic(store.path, new TextEncoder().encode(string),
|
||||
{ tmpPath: store.path + ".tmp" });
|
||||
|
||||
try {
|
||||
yield store.load();
|
||||
do_throw("Exception expected when JSON data is malformed.");
|
||||
} catch (ex if ex.name == "SyntaxError") {
|
||||
do_print("The expected SyntaxError exception was thrown.");
|
||||
}
|
||||
|
||||
let items = yield list.getAll();
|
||||
|
||||
do_check_eq(items.length, 0);
|
||||
});
|
|
@ -3,8 +3,8 @@ head = head.js
|
|||
tail = tail.js
|
||||
|
||||
[test_DownloadCore.js]
|
||||
[test_DownloadIntegration.js]
|
||||
[test_DownloadLegacy.js]
|
||||
[test_DownloadList.js]
|
||||
[test_Downloads.js]
|
||||
[test_DownloadIntegration.js]
|
||||
|
||||
[test_DownloadStore.js]
|
||||
|
|
|
@ -138,6 +138,15 @@ if (typeof Components != "undefined") {
|
|||
return this.unixErrno == OS.Constants.libc.EBADF;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because permission is denied to
|
||||
* access a file or directory, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
|
||||
get: function becauseAccessDenied() {
|
||||
return this.unixErrno == OS.Constants.libc.EACCES;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
|
|
|
@ -151,6 +151,15 @@ if (typeof Components != "undefined") {
|
|||
return this.winLastError == exports.OS.Constants.Win.ERROR_INVALID_HANDLE;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because permission is denied to
|
||||
* access a file or directory, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
|
||||
get: function becauseAccessDenied() {
|
||||
return this.winLastError == exports.OS.Constants.Win.ERROR_ACCESS_DENIED;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
|
|
|
@ -55,9 +55,6 @@ function LOG(aMsg) {
|
|||
|
||||
let gTestDir = do_get_cwd();
|
||||
|
||||
// Ensure history is enabled.
|
||||
Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
|
||||
// Initialize profile.
|
||||
let gProfD = do_get_profile();
|
||||
|
||||
|
|
|
@ -6,9 +6,6 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
// Ensure history is enabled.
|
||||
Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/commonjs/sdk/core/promise.js");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
|
|
|
@ -733,8 +733,6 @@ let tests = [
|
|||
|
||||
function run_test()
|
||||
{
|
||||
Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
|
||||
for (let i = 0; i < tests.length; i++)
|
||||
add_task(tests[i]);
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "mozilla/Util.h"
|
||||
#include "mozilla/layers/CompositorChild.h"
|
||||
#include "mozilla/layers/CompositorParent.h"
|
||||
#include "mozilla/layers/AsyncPanZoomController.h"
|
||||
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
|
@ -2784,8 +2783,7 @@ AndroidBridge::RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrame
|
|||
return;
|
||||
}
|
||||
|
||||
CSSToScreenScale resolution =
|
||||
mozilla::layers::AsyncPanZoomController::CalculateResolution(aFrameMetrics);
|
||||
CSSToScreenScale resolution = aFrameMetrics.CalculateResolution();
|
||||
ScreenRect dp = (aFrameMetrics.mDisplayPort + aFrameMetrics.mScrollOffset) * resolution;
|
||||
|
||||
AutoLocalJNIFrame jniFrame(env, 0);
|
||||
|
|
Загрузка…
Ссылка в новой задаче