This commit is contained in:
Ehsan Akhgari 2015-01-19 14:35:38 -05:00
Родитель 3eab8b4db8 a6aca89eaa
Коммит ad89cf8ff2
116 изменённых файлов: 2853 добавлений и 1776 удалений

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

@ -219,7 +219,7 @@ skip-if = e10s
[browser_bug565667.js]
run-if = toolkit == "cocoa"
[browser_bug567306.js]
skip-if = e10s
skip-if = e10s # Bug XXX - Needs some massaging to run in e10s
[browser_bug575561.js]
[browser_bug575830.js]
skip-if = e10s # Bug 1056146 - zoom tests use FullZoomHelper and break in e10s

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

@ -13,8 +13,8 @@ function test() {
whenNewWindowLoaded(undefined, function (win) {
whenDelayedStartupFinished(win, function () {
let selectedBrowser = win.gBrowser.selectedBrowser;
selectedBrowser.addEventListener("pageshow", function() {
selectedBrowser.removeEventListener("pageshow", arguments.callee, true);
selectedBrowser.addEventListener("pageshow", function pageshowListener() {
selectedBrowser.removeEventListener("pageshow", pageshowListener, true);
ok(true, "pageshow listener called: " + win.content.location);
waitForFocus(function () {
onFocus(win);
@ -39,7 +39,11 @@ function onFocus(win) {
ok(!win.gFindBarInitialized, "find bar is not yet initialized");
let findBar = win.gFindBar;
selectText(win.content);
findBar.onFindCommand();
findBar.onFindCommand().then(onInitialized.bind(null, findBar, win));
}
function onInitialized(findBar, win) {
// When the OS supports the Find Clipboard (OSX), the find field value is
// persisted across Fx sessions, thus not useful to test.
if (!HasFindClipboard)

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

@ -2,13 +2,6 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
///////////////////
//
// Whitelisting this test.
// As part of bug 1077403, the leaking uncaught rejection should be fixed.
//
thisTestLeaksUncaughtRejectionsAndShouldBeFixed("");
var gTab = null;
function load(url, cb) {

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

@ -29,7 +29,7 @@ support-files =
[test_bug364677.html]
[test_bug395533.html]
[test_contextmenu.html]
skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
skip-if = toolkit == "gtk2" || toolkit == "gtk3" || (os == 'mac' && os_version != '10.6') # disabled on Linux due to bug 513558, on Mac after 10.6 due to bug 792304
[test_contextmenu_input.html]
skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558
[test_feed_discovery.html]

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

@ -852,20 +852,14 @@ function waitForEvents(event)
}
}
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
SpecialPowers.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
if (isOSXMtnLion) {
todo(false, "Mountain Lion doesn't like this test (bug 792304)");
} else {
SpecialPowers.setBoolPref("plugins.click_to_play", true);
setTestPluginEnabledState(Ci.nsIPluginTag.STATE_CLICKTOPLAY);
var subwindow = window.open("./subtst_contextmenu.html", "contextmenu-subtext", "width=600,height=800");
subwindow.addEventListener("MozAfterPaint", waitForEvents, false);
subwindow.onload = waitForEvents;
var subwindow = window.open("./subtst_contextmenu.html", "contextmenu-subtext", "width=600,height=800");
subwindow.addEventListener("MozAfterPaint", waitForEvents, false);
subwindow.onload = waitForEvents;
SimpleTest.waitForExplicitFinish();
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>

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

@ -28,7 +28,7 @@ browser.jar:
content/browser/preferences/languages.js
* content/browser/preferences/main.xul
* content/browser/preferences/main.js
* content/browser/preferences/permissions.xul
content/browser/preferences/permissions.xul
* content/browser/preferences/permissions.js
* content/browser/preferences/preferences.xul
content/browser/preferences/preferences.js
@ -48,5 +48,5 @@ browser.jar:
content/browser/preferences/search.js
* content/browser/preferences/tabs.xul
* content/browser/preferences/tabs.js
* content/browser/preferences/translation.xul
content/browser/preferences/translation.xul
content/browser/preferences/translation.js

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

@ -1,9 +1,8 @@
<?xml version="1.0"?>
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>
@ -29,7 +28,7 @@
<keyset>
<key key="&windowClose.key;" modifiers="accel" oncommand="window.close();"/>
</keyset>
<vbox class="contentPane" flex="1">
<description id="permissionsText" control="url"/>
<separator class="thin"/>

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

@ -1,9 +1,8 @@
<?xml version="1.0"?>
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<!-- 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/. -->
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/preferences/preferences.css" type="text/css"?>

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

@ -2104,8 +2104,7 @@ NetworkDetailsView.prototype = {
// 2) come from a target that provides security information.
let hasSecurityInfo = aData.securityState &&
aData.securityState !== "insecure";
$("#security-tab").hidden = !hasSecurityInfo;
this.sidebar.toggleTab(hasSecurityInfo, "security-tab", "security-tabpanel");
// Switch to the "Headers" tabpanel if the "Preview" previously selected
// and this is not an HTML response or "Security" was selected but this

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

@ -39,7 +39,8 @@ support-files =
[browser_perf_recordings-io-01.js]
[browser_perf_recordings-io-02.js]
[browser_perf_recordings-io-03.js]
[browser_perf_recordings-io-04.js]
[browser_perf-recording-selected-01.js]
[browser_perf-recording-selected-02.js]
[browser_perf-recording-selected-03.js]
[browser_perf_recordings-io-04.js]
[browser_perf-recording-selected-04.js]

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

@ -0,0 +1,29 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that all components get rerendered for a profile when switching.
*/
let test = Task.async(function*() {
let { target, panel, toolbox } = yield initPerformance(SIMPLE_URL);
let { $, EVENTS, PerformanceController, RecordingsView } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel);
yield startRecording(panel);
yield stopRecording(panel);
let rerender = waitForWidgetsRendered(panel);
RecordingsView.selectedIndex = 0;
yield rerender;
rerender = waitForWidgetsRendered(panel);
RecordingsView.selectedIndex = 1;
yield rerender;
yield teardown(panel);
finish();
});

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

@ -12,13 +12,12 @@ let CallTreeView = {
*/
initialize: function () {
this._callTree = $(".call-tree-cells-container");
this._onRecordingStopped = this._onRecordingStopped.bind(this);
this._onRecordingSelected = this._onRecordingSelected.bind(this);
this._onRecordingStoppedOrSelected = this._onRecordingStoppedOrSelected.bind(this);
this._onRangeChange = this._onRangeChange.bind(this);
this._onLink = this._onLink.bind(this);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
OverviewView.on(EVENTS.OVERVIEW_RANGE_SELECTED, this._onRangeChange);
OverviewView.on(EVENTS.OVERVIEW_RANGE_CLEARED, this._onRangeChange);
},
@ -27,8 +26,8 @@ let CallTreeView = {
* Unbinds events.
*/
destroy: function () {
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
OverviewView.off(EVENTS.OVERVIEW_RANGE_SELECTED, this._onRangeChange);
OverviewView.off(EVENTS.OVERVIEW_RANGE_CLEARED, this._onRangeChange);
},
@ -47,20 +46,10 @@ let CallTreeView = {
},
/**
* Called when recording is stopped.
* Called when recording is stopped or has been selected.
*/
_onRecordingStopped: function () {
let profilerData = PerformanceController.getProfilerData();
this.render(profilerData);
},
/**
* Called when a recording has been selected.
*/
_onRecordingSelected: function (_, recording) {
_onRecordingStoppedOrSelected: function (_, recording) {
// If not recording, then this recording is done and we can render all of it
// Otherwise, TODO in bug 1120699 will hide the details view altogether if
// this is still recording.
if (!recording.isRecording()) {
let profilerData = recording.getProfilerData();
this.render(profilerData);

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

@ -12,14 +12,15 @@ let FlameGraphView = {
* Sets up the view with event binding.
*/
initialize: Task.async(function* () {
this._onRecordingStopped = this._onRecordingStopped.bind(this);
this._onRecordingStoppedOrSelected = this._onRecordingStoppedOrSelected.bind(this);
this._onRangeChange = this._onRangeChange.bind(this);
this.graph = new FlameGraph($("#flamegraph-view"));
this.graph.timelineTickUnits = L10N.getStr("graphs.ms");
yield this.graph.ready();
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
OverviewView.on(EVENTS.OVERVIEW_RANGE_SELECTED, this._onRangeChange);
OverviewView.on(EVENTS.OVERVIEW_RANGE_CLEARED, this._onRangeChange);
}),
@ -28,7 +29,8 @@ let FlameGraphView = {
* Unbinds events.
*/
destroy: function () {
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
OverviewView.off(EVENTS.OVERVIEW_RANGE_SELECTED, this._onRangeChange);
OverviewView.off(EVENTS.OVERVIEW_RANGE_CLEARED, this._onRangeChange);
},
@ -52,11 +54,14 @@ let FlameGraphView = {
},
/**
* Called when recording is stopped.
* Called when recording is stopped or selected.
*/
_onRecordingStopped: function () {
let profilerData = PerformanceController.getProfilerData();
this.render(profilerData);
_onRecordingStoppedOrSelected: function (_, recording) {
// If not recording, then this recording is done and we can render all of it
if (!recording.isRecording()) {
let profilerData = recording.getProfilerData();
this.render(profilerData);
}
},
/**

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

@ -12,8 +12,7 @@ let WaterfallView = {
*/
initialize: Task.async(function *() {
this._onRecordingStarted = this._onRecordingStarted.bind(this);
this._onRecordingStopped = this._onRecordingStopped.bind(this);
this._onRecordingSelected = this._onRecordingSelected.bind(this);
this._onRecordingStoppedOrSelected = this._onRecordingStoppedOrSelected.bind(this);
this._onMarkerSelected = this._onMarkerSelected.bind(this);
this._onResize = this._onResize.bind(this);
@ -25,8 +24,8 @@ let WaterfallView = {
this.details.on("resize", this._onResize);
PerformanceController.on(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
PerformanceController.on(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
PerformanceController.on(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
this.waterfall.recalculateBounds();
}),
@ -40,8 +39,8 @@ let WaterfallView = {
this.details.off("resize", this._onResize);
PerformanceController.off(EVENTS.RECORDING_STARTED, this._onRecordingStarted);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStopped);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingSelected);
PerformanceController.off(EVENTS.RECORDING_STOPPED, this._onRecordingStoppedOrSelected);
PerformanceController.off(EVENTS.RECORDING_SELECTED, this._onRecordingStoppedOrSelected);
},
/**
@ -65,16 +64,9 @@ let WaterfallView = {
},
/**
* Called when recording stops.
* Called when recording stops or is selected.
*/
_onRecordingStopped: function () {
this.render();
},
/**
* Called when a recording is selected.
*/
_onRecordingSelected: function (_, recording) {
_onRecordingStoppedOrSelected: function (_, recording) {
if (!recording.isRecording()) {
this.render();
}

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

@ -203,7 +203,9 @@ PreviewController.prototype = {
// Resizes the canvasPreview to 0x0, essentially freeing its memory.
// updateCanvasPreview() will detect the size mismatch as a resize event
// the next time it is called.
resetCanvasPreview: function () this.resizeCanvasPreview(0, 0),
resetCanvasPreview: function () {
this.resizeCanvasPreview(0, 0);
},
resizeCanvasPreview: function (width, height) {
this.canvasPreview.width = width;

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

@ -199,7 +199,7 @@ browser.jar:
skin/classic/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay.css)
skin/classic/browser/downloads/buttons.png (downloads/buttons.png)
skin/classic/browser/downloads/buttons@2x.png (downloads/buttons@2x.png)
* skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
skin/classic/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
skin/classic/browser/downloads/download-glow-menuPanel.png (downloads/download-glow-menuPanel.png)
skin/classic/browser/downloads/download-glow-menuPanel@2x.png (downloads/download-glow-menuPanel@2x.png)
skin/classic/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png)

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

@ -26,8 +26,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=995943
/** Test for CAPS file:// URI prefs. **/
SimpleTest.waitForExplicitFinish();
SimpleTest.requestCompleteLog();
if (Services.appinfo.OS == "Darwin") // See bug 1067022
SimpleTest.expectAssertions(0, 1);
if (navigator.userAgent.indexOf("Mac OS X 10.10") != -1)
SimpleTest.expectAssertions(5); // See bug 1067022
else if (Services.appinfo.OS == "Darwin")
SimpleTest.expectAssertions(0, 1); // See bug 1067022
var rootdir = Services.appinfo.OS == "WINNT" ? "file:///C:" : "file:///";

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

@ -319,8 +319,8 @@ private:
/*
* A class that represents a new script entry point.
*/
class AutoEntryScript : public AutoJSAPI,
protected ScriptSettingsStackEntry {
class MOZ_STACK_CLASS AutoEntryScript : public AutoJSAPI,
protected ScriptSettingsStackEntry {
public:
explicit AutoEntryScript(nsIGlobalObject* aGlobalObject,
bool aIsMainThread = NS_IsMainThread(),
@ -341,10 +341,10 @@ private:
// is the principal of the callee function that is part of the CallArgs just a
// bit up the stack, and which will outlive us. So we know the principal
// can't go away until then either.
nsIPrincipal* mWebIDLCallerPrincipal;
nsIPrincipal* MOZ_NON_OWNING_REF mWebIDLCallerPrincipal;
friend nsIPrincipal* GetWebIDLCallerPrincipal();
nsIDocShell* mDocShellForJSRunToCompletion;
nsCOMPtr<nsIDocShell> mDocShellForJSRunToCompletion;
bool mIsMainThread;
};

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

@ -155,7 +155,9 @@ enum EventNameType {
struct EventNameMapping
{
nsIAtom* mAtom;
// This holds pointers to nsGkAtoms members, and is therefore safe as a
// non-owning reference.
nsIAtom* MOZ_OWNING_REF mAtom;
uint32_t mId;
int32_t mType;
mozilla::EventClassID mEventClassID;

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

@ -680,7 +680,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 904183 # b2g(bug 904183
[test_fileapi.html]
skip-if = e10s
[test_fileapi_slice.html]
disabled = Busted on B2G, Android, E10S and now Mulet. Bug 775227.
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android' || e10s #bug 775227
[test_getElementById.html]
[test_html_colors_quirks.html]
[test_html_colors_standards.html]

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

@ -22,11 +22,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=575946
<pre id="test">
<script class="testbody" type="text/javascript">
const isOSXMtnLion = navigator.userAgent.indexOf("Mac OS X 10.8") != -1;
if (isOSXMtnLion) {
todo(false, "Mountain Lion doesn't like this test (bug 788999)");
} else {
var fileNum = 1;
SimpleTest.waitForExplicitFinish();
@ -136,7 +131,6 @@ var img = new Image;
img.src = URL.createObjectURL(imgfile.slice(testBinaryData.length, testBinaryData.length + size + 1000));
img.onload = imageLoadHandler;
expectedTestCount++;
}
</script>
</pre>
</body> </html>

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

@ -175,7 +175,9 @@ private:
// For callees that know we exist, we can be a stringbuffer/length/null-flag
// triple.
nsStringBuffer* mStringBuffer;
nsStringBuffer* MOZ_UNSAFE_REF("The ways in which this can be safe are "
"documented above and enforced through "
"assertions") mStringBuffer;
uint32_t mLength;
bool mIsNull;
};

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

@ -558,7 +558,7 @@ protected:
uint32_t mNoListenerForEvent : 23;
nsAutoTObserverArray<Listener, 2> mListeners;
dom::EventTarget* mTarget; // WEAK
dom::EventTarget* MOZ_NON_OWNING_REF mTarget;
nsCOMPtr<nsIAtom> mNoListenerForEventAtom;
friend class ELMCreationDetector;

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

@ -18,6 +18,7 @@
#include "nsTArray.h"
#include "MediaDecoder.h"
#include "MediaDecoderReader.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/mozalloc.h"
#include "VideoUtils.h"
#include "mozilla/dom/TimeRanges.h"
@ -165,7 +166,7 @@ static_assert(QUICK_BUFFERING_LOW_DATA_USECS <= AMPLE_AUDIO_USECS,
// MediaDecoderStateMachine::UpdateEstimatedDuration(); changes of duration
// less than this are ignored, as they're assumed to be the result of
// instability in the duration estimation.
static const int64_t ESTIMATED_DURATION_FUZZ_FACTOR_USECS = USECS_PER_S / 2;
static const uint64_t ESTIMATED_DURATION_FUZZ_FACTOR_USECS = USECS_PER_S / 2;
static TimeDuration UsecsToDuration(int64_t aUsecs) {
return TimeDuration::FromMicroseconds(aUsecs);
@ -1449,7 +1450,7 @@ void MediaDecoderStateMachine::UpdateEstimatedDuration(int64_t aDuration)
AssertCurrentThreadInMonitor();
int64_t duration = GetDuration();
if (aDuration != duration &&
std::abs(aDuration - duration) > ESTIMATED_DURATION_FUZZ_FACTOR_USECS) {
mozilla::Abs(aDuration - duration) > ESTIMATED_DURATION_FUZZ_FACTOR_USECS) {
SetDuration(aDuration);
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(mDecoder, &MediaDecoder::DurationChanged);

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

@ -59,6 +59,10 @@ static bool gDebug_isLoggingEnabled = false;
static bool gDebug_isGPSLocationIgnored = false;
static const char* kNetworkConnStateChangedTopic = "network-connection-state-changed";
static const char* kMozSettingsChangedTopic = "mozsettings-changed";
#ifdef MOZ_B2G_RIL
static const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
static const char* kSettingRilDefaultServiceId = "ril.data.defaultServiceId";
#endif
// Both of these settings can be toggled in the Gaia Developer settings screen.
static const char* kSettingDebugEnabled = "geolocation.debugging.enabled";
static const char* kSettingDebugGpsIgnored = "geolocation.debugging.gps-locations-ignored";
@ -289,6 +293,10 @@ GonkGPSGeolocationProvider::GonkGPSGeolocationProvider()
#ifdef MOZ_B2G_RIL
, mSupportsMSB(false)
, mSupportsMSA(false)
, mRilDataServiceId(0)
, mNumberOfRilServices(1)
, mObservingNetworkConnStateChange(false)
, mObservingSettingsChange(false)
#endif
, mSupportsSingleShot(false)
, mSupportsTimeInjection(false)
@ -714,17 +722,24 @@ GonkGPSGeolocationProvider::SetupAGPS()
return;
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(this, kNetworkConnStateChangedTopic, false);
}
// Request RIL date service ID for correct RadioInterface object first due to
// multi-SIM case needs it to handle AGPS related stuffs. For single SIM, 0
// will be returned as default RIL data service ID.
RequestSettingValue(kSettingRilDefaultServiceId);
}
void
GonkGPSGeolocationProvider::UpdateRadioInterface()
{
nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetService("@mozilla.org/ril;1");
if (ril) {
// TODO: Bug 878748 - B2G GPS: acquire correct RadioInterface instance in
// MultiSIM configuration
ril->GetRadioInterface(0 /* clientId */, getter_AddRefs(mRadioInterface));
}
NS_ENSURE_TRUE_VOID(ril);
ril->GetRadioInterface(mRilDataServiceId, getter_AddRefs(mRadioInterface));
}
bool
GonkGPSGeolocationProvider::IsValidRilServiceId(uint32_t aServiceId)
{
return aServiceId < mNumberOfRilServices;
}
#endif // MOZ_B2G_RIL
@ -848,9 +863,12 @@ GonkGPSGeolocationProvider::Startup()
// Setup an observer to watch changes to the setting.
nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
if (observerService) {
MOZ_ASSERT(!mObservingSettingsChange);
nsresult rv = observerService->AddObserver(this, kMozSettingsChangedTopic, false);
if (NS_FAILED(rv)) {
NS_WARNING("geo: Gonk GPS AddObserver failed");
} else {
mObservingSettingsChange = true;
}
}
@ -872,6 +890,9 @@ GonkGPSGeolocationProvider::Startup()
}
mStarted = true;
#ifdef MOZ_B2G_RIL
mNumberOfRilServices = Preferences::GetUint(kPrefRilNumRadioInterfaces, 1);
#endif
return NS_OK;
}
@ -906,11 +927,15 @@ GonkGPSGeolocationProvider::Shutdown()
rv = obs->RemoveObserver(this, kNetworkConnStateChangedTopic);
if (NS_FAILED(rv)) {
NS_WARNING("geo: Gonk GPS network state RemoveObserver failed");
} else {
mObservingNetworkConnStateChange = false;
}
#endif
rv = obs->RemoveObserver(this, kMozSettingsChangedTopic);
if (NS_FAILED(rv)) {
NS_WARNING("geo: Gonk GPS mozsettings RemoveObserver failed");
} else {
mObservingSettingsChange = false;
}
}
@ -1043,6 +1068,15 @@ GonkGPSGeolocationProvider::Observe(nsISupports* aSubject,
gDebug_isLoggingEnabled =
setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false;
return NS_OK;
} else if (setting.mKey.EqualsASCII(kSettingRilDefaultServiceId)) {
if (!setting.mValue.isNumber() ||
!IsValidRilServiceId(setting.mValue.toNumber())) {
return NS_ERROR_UNEXPECTED;
}
mRilDataServiceId = setting.mValue.toNumber();
UpdateRadioInterface();
return NS_OK;
}
}
@ -1071,6 +1105,32 @@ GonkGPSGeolocationProvider::Handle(const nsAString& aName,
SetAGpsDataConn(apn);
}
}
} else if (aName.EqualsASCII(kSettingRilDefaultServiceId)) {
uint32_t id = 0;
JSContext *cx = nsContentUtils::GetCurrentJSContext();
NS_ENSURE_TRUE(cx, NS_OK);
if (!JS::ToUint32(cx, aResult, &id)) {
return NS_ERROR_FAILURE;
}
if (!IsValidRilServiceId(id)) {
return NS_ERROR_UNEXPECTED;
}
mRilDataServiceId = id;
UpdateRadioInterface();
MOZ_ASSERT(!mObservingNetworkConnStateChange);
// Now we know which service ID to deal with, observe necessary topic then
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, NS_OK);
if (NS_FAILED(obs->AddObserver(this, kNetworkConnStateChangedTopic, false))) {
NS_WARNING("Failed to add network state changed observer!");
} else {
mObservingNetworkConnStateChange = true;
}
}
#endif // MOZ_B2G_RIL
return NS_OK;

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

@ -82,6 +82,8 @@ private:
void InjectLocation(double latitude, double longitude, float accuracy);
void RequestSettingValue(const char* aKey);
#ifdef MOZ_B2G_RIL
void UpdateRadioInterface();
bool IsValidRilServiceId(uint32_t aServiceId);
void SetupAGPS();
int32_t GetDataConnectionState();
void SetAGpsDataConn(nsAString& aApn);
@ -101,6 +103,13 @@ private:
#ifdef MOZ_B2G_RIL
bool mSupportsMSB;
bool mSupportsMSA;
uint32_t mRilDataServiceId;
// mNumberOfRilServices indicates how many SIM slots supported on device, and
// RadioInterfaceLayer.js takes responsibility to set up the corresponding
// preference value.
uint32_t mNumberOfRilServices;
bool mObservingNetworkConnStateChange;
bool mObservingSettingsChange;
#endif
bool mSupportsSingleShot;
bool mSupportsTimeInjection;

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

@ -2037,6 +2037,12 @@ public:
{
MutexAutoLock lock(mMutex);
if (!mWorkerPrivate ||
!mWorkerPrivate->BlockAndCollectRuntimeStats(&rtStats, aAnonymize)) {
// Returning NS_OK here will effectively report 0 memory.
return NS_OK;
}
path.AppendLiteral("explicit/workers/workers(");
if (aAnonymize && !mWorkerPrivate->Domain().IsEmpty()) {
path.AppendLiteral("<anonymized-domain>)/worker(<anonymized-url>");
@ -2056,12 +2062,6 @@ public:
path.AppendPrintf(", 0x%p)/", static_cast<void*>(mWorkerPrivate));
TryToMapAddon(path);
if (!mWorkerPrivate ||
!mWorkerPrivate->BlockAndCollectRuntimeStats(&rtStats, aAnonymize)) {
// Returning NS_OK here will effectively report 0 memory.
return NS_OK;
}
}
return xpc::ReportJSRuntimeExplicitTreeStats(rtStats, path,

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

@ -39,32 +39,6 @@
q: cite
*/
/* Here is how to open a channel for testing
(from embed/qa/testembed/Tests.cpp):
nsCOMPtr<nsIChannel> theChannel;
nsCString uri;
nsCOMPtr<nsIURI> theURI;
rv = NS_NewURI(getter_AddRefs(theURI), theSpec);
if (!theURI)
error;
rv = NS_OpenURI(getter_AddRefs(theChannel), theURI, nullptr, theLoadGroup);
if (!theChannel)
error;
nsCOMPtr<nsILoadGroup> theLoadGroup(do_CreateInstance(NS_LOADGROUP_CONTRACTID));
if (!theLoadGroup)
error;
nsCOMPtr<nsIStreamListener> listener(static_cast<nsIStreamListener*>(qaBrowserImpl));
//nsCOMPtr<nsIWeakReference> thisListener(do_GetWeakReference(listener));
//qaWebBrowser->AddWebBrowserListener(thisListener, NS_GET_IID(nsIStreamListener));
// this calls nsIStreamListener::OnDataAvailable()
rv = theChannel->AsyncOpen(listener, nullptr);
nsCOMPtr<nsIRequest> theRequest = do_QueryInterface(theChannel);
// Now we can do things on nsIRequest (like what?)
*/
#include "nsHTMLURIRefObject.h"
#include "mozilla/mozalloc.h"

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

@ -234,6 +234,7 @@ private:
DECL_GFX_PREF(Once, "image.cache.timeweight", ImageCacheTimeWeight, int32_t, 500);
DECL_GFX_PREF(Once, "image.cache.size", ImageCacheSize, int32_t, 5*1024*1024);
DECL_GFX_PREF(Live, "image.downscale-during-decode.enabled", ImageDownscaleDuringDecodeEnabled, bool, false);
DECL_GFX_PREF(Live, "image.high_quality_downscaling.enabled", ImageHQDownscalingEnabled, bool, false);
DECL_GFX_PREF(Live, "image.high_quality_downscaling.min_factor", ImageHQDownscalingMinFactor, uint32_t, 1000);
DECL_GFX_PREF(Live, "image.high_quality_upscaling.max_size", ImageHQUpscalingMaxSize, uint32_t, 20971520);

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

@ -638,12 +638,12 @@ nsICODecoder::NeedsNewFrame() const
}
nsresult
nsICODecoder::AllocateFrame()
nsICODecoder::AllocateFrame(const nsIntSize& aTargetSize /* = nsIntSize() */)
{
nsresult rv;
if (mContainedDecoder) {
rv = mContainedDecoder->AllocateFrame();
rv = mContainedDecoder->AllocateFrame(aTargetSize);
mCurrentFrame = mContainedDecoder->GetCurrentFrameRef();
mProgress |= mContainedDecoder->TakeProgress();
mInvalidRect.Union(mContainedDecoder->TakeInvalidRect());
@ -652,7 +652,7 @@ nsICODecoder::AllocateFrame()
// Grab a strong ref that we'll later hand over to the contained decoder. This
// lets us avoid creating a RawAccessFrameRef off-main-thread.
rv = Decoder::AllocateFrame();
rv = Decoder::AllocateFrame(aTargetSize);
mRefForContainedDecoder = GetCurrentFrameRef();
return rv;
}

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

@ -40,7 +40,8 @@ public:
virtual void WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_OVERRIDE;
virtual void FinishInternal() MOZ_OVERRIDE;
virtual nsresult AllocateFrame() MOZ_OVERRIDE;
virtual nsresult AllocateFrame(const nsIntSize& aTargetSize
/* = nsIntSize() */) MOZ_OVERRIDE;
protected:
virtual bool NeedsNewFrame() const MOZ_OVERRIDE;

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

@ -69,7 +69,7 @@ native nsIntSizeByVal(nsIntSize);
*
* Internally, imgIContainer also manages animation of images.
*/
[scriptable, builtinclass, uuid(14ea6fa5-183e-4409-ac88-110bd2e05292)]
[scriptable, builtinclass, uuid(4adb4c92-284d-4f5a-85e7-e924ec57510f)]
interface imgIContainer : nsISupports
{
/**
@ -345,11 +345,27 @@ interface imgIContainer : nsISupports
void requestDecode();
/*
* This is equivalent to requestDecode() but it also decodes some of the
* image.
* This is equivalent to requestDecode() but it also synchronously decodes
* images that can be decoded "quickly" according to some heuristic.
*/
[noscript] void startDecoding();
/*
* This method is equivalent to requestDecode(), but enables the caller to
* provide more detailed information about the decode request.
*
* @param aSize The size to which the image should be scaled while decoding,
* if possible. If the image cannot be scaled to this size while
* being decoded, it will be decoded at its intrinsic size.
* @param aFlags Flags of the FLAG_* variety. Only the decode flags
* (FLAG_DECODE_*) and FLAG_SYNC_DECODE (which will
* synchronously decode images that can be decoded "quickly",
* just like startDecoding() does) are accepted; others will be
* ignored.
*/
[noscript] void requestDecodeForSize([const] in nsIntSize aSize,
in uint32_t aFlags);
/*
* Returns true if no more decoding can be performed on this image. Images
* with errors return true since they cannot be decoded any further. Note that

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

@ -328,11 +328,18 @@ Decoder::FinishSharedDecoder()
}
nsresult
Decoder::AllocateFrame()
Decoder::AllocateFrame(const nsIntSize& aTargetSize /* = nsIntSize() */)
{
MOZ_ASSERT(mNeedsNewFrame);
nsIntSize targetSize = aTargetSize;
if (targetSize == nsIntSize()) {
MOZ_ASSERT(HasSize());
targetSize = mImageMetadata.GetSize();
}
mCurrentFrame = EnsureFrame(mNewFrameData.mFrameNum,
targetSize,
mNewFrameData.mFrameRect,
mDecodeFlags,
mNewFrameData.mFormat,
@ -366,6 +373,7 @@ Decoder::AllocateFrame()
RawAccessFrameRef
Decoder::EnsureFrame(uint32_t aFrameNum,
const nsIntSize& aTargetSize,
const nsIntRect& aFrameRect,
uint32_t aDecodeFlags,
SurfaceFormat aFormat,
@ -383,8 +391,8 @@ Decoder::EnsureFrame(uint32_t aFrameNum,
// Adding a frame that doesn't already exist. This is the normal case.
if (aFrameNum == mFrameCount) {
return InternalAddFrame(aFrameNum, aFrameRect, aDecodeFlags, aFormat,
aPaletteDepth, aPreviousFrame);
return InternalAddFrame(aFrameNum, aTargetSize, aFrameRect, aDecodeFlags,
aFormat, aPaletteDepth, aPreviousFrame);
}
// We're replacing a frame. It must be the first frame; there's no reason to
@ -415,7 +423,7 @@ Decoder::EnsureFrame(uint32_t aFrameNum,
bool nonPremult =
aDecodeFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
if (NS_FAILED(aPreviousFrame->ReinitForDecoder(oldSize, aFrameRect, aFormat,
aPaletteDepth, nonPremult))) {
aPaletteDepth, nonPremult))) {
NS_WARNING("imgFrame::ReinitForDecoder should succeed");
mFrameCount = 0;
aPreviousFrame->Abort();
@ -427,6 +435,7 @@ Decoder::EnsureFrame(uint32_t aFrameNum,
RawAccessFrameRef
Decoder::InternalAddFrame(uint32_t aFrameNum,
const nsIntSize& aTargetSize,
const nsIntRect& aFrameRect,
uint32_t aDecodeFlags,
SurfaceFormat aFormat,
@ -438,15 +447,13 @@ Decoder::InternalAddFrame(uint32_t aFrameNum,
return RawAccessFrameRef();
}
MOZ_ASSERT(mImageMetadata.HasSize());
nsIntSize imageSize(mImageMetadata.GetWidth(), mImageMetadata.GetHeight());
if (imageSize.width <= 0 || imageSize.height <= 0 ||
if (aTargetSize.width <= 0 || aTargetSize.height <= 0 ||
aFrameRect.width <= 0 || aFrameRect.height <= 0) {
NS_WARNING("Trying to add frame with zero or negative size");
return RawAccessFrameRef();
}
if (!SurfaceCache::CanHold(imageSize.ToIntSize())) {
if (!SurfaceCache::CanHold(aTargetSize.ToIntSize())) {
NS_WARNING("Trying to add frame that's too large for the SurfaceCache");
return RawAccessFrameRef();
}
@ -454,7 +461,7 @@ Decoder::InternalAddFrame(uint32_t aFrameNum,
nsRefPtr<imgFrame> frame = new imgFrame();
bool nonPremult =
aDecodeFlags & imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
if (NS_FAILED(frame->InitForDecoder(imageSize, aFrameRect, aFormat,
if (NS_FAILED(frame->InitForDecoder(aTargetSize, aFrameRect, aFormat,
aPaletteDepth, nonPremult))) {
NS_WARNING("imgFrame::Init should succeed");
return RawAccessFrameRef();
@ -468,7 +475,7 @@ Decoder::InternalAddFrame(uint32_t aFrameNum,
InsertOutcome outcome =
SurfaceCache::Insert(frame, ImageKey(mImage.get()),
RasterSurfaceKey(imageSize.ToIntSize(),
RasterSurfaceKey(aTargetSize.ToIntSize(),
aDecodeFlags,
aFrameNum),
Lifetime::Persistent);
@ -599,12 +606,15 @@ Decoder::PostFrameStop(Opacity aFrameOpacity /* = Opacity::TRANSPARENT */,
// If we're not sending partial invalidations, then we send an invalidation
// here when the first frame is complete.
if (!mSendPartialInvalidations && !mIsAnimated) {
mInvalidRect.UnionRect(mInvalidRect, mCurrentFrame->GetRect());
mInvalidRect.UnionRect(mInvalidRect,
nsIntRect(nsIntPoint(0, 0), GetSize()));
}
}
void
Decoder::PostInvalidation(nsIntRect& aRect)
Decoder::PostInvalidation(const nsIntRect& aRect,
const Maybe<nsIntRect>& aRectAtTargetSize
/* = Nothing() */)
{
// We should be mid-frame
NS_ABORT_IF_FALSE(mInFrame, "Can't invalidate when not mid-frame!");
@ -614,7 +624,7 @@ Decoder::PostInvalidation(nsIntRect& aRect)
// or we're past the first frame.
if (mSendPartialInvalidations && !mIsAnimated) {
mInvalidRect.UnionRect(mInvalidRect, aRect);
mCurrentFrame->ImageUpdated(aRect);
mCurrentFrame->ImageUpdated(aRectAtTargetSize.valueOr(aRect));
}
}

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

@ -127,6 +127,24 @@ public:
mSizeDecode = aSizeDecode;
}
/**
* If this decoder supports downscale-during-decode, sets the target size that
* this image should be decoded to.
*
* If this decoder *doesn't* support downscale-during-decode, returns
* NS_ERROR_NOT_AVAILABLE. If the provided size is unacceptable, returns
* another error.
*
* Returning NS_OK from this method is a promise that the decoder will decode
* the image to the requested target size unless it encounters an error.
*
* This must be called before Init() is called.
*/
virtual nsresult SetTargetSize(const nsIntSize& aSize)
{
return NS_ERROR_NOT_AVAILABLE;
}
/**
* Set whether should send partial invalidations.
*
@ -233,6 +251,12 @@ public:
PostSize(aSize.width, aSize.height, aOrientation);
}
nsIntSize GetSize() const
{
MOZ_ASSERT(HasSize());
return mImageMetadata.GetSize();
}
// Use HistogramCount as an invalid Histogram ID
virtual Telemetry::ID SpeedHistogram() { return Telemetry::HistogramCount; }
@ -259,7 +283,7 @@ public:
// Try to allocate a frame as described in mNewFrameData and return the
// status code from that attempt. Clears mNewFrameData.
virtual nsresult AllocateFrame();
virtual nsresult AllocateFrame(const nsIntSize& aTargetSize = nsIntSize());
already_AddRefed<imgFrame> GetCurrentFrame()
{
@ -332,9 +356,19 @@ protected:
int32_t aTimeout = 0,
BlendMethod aBlendMethod = BlendMethod::OVER);
// Called by the decoders when they have a region to invalidate. We may not
// actually pass these invalidations on right away.
void PostInvalidation(nsIntRect& aRect);
/**
* Called by the decoders when they have a region to invalidate. We may not
* actually pass these invalidations on right away.
*
* @param aRect The invalidation rect in the coordinate system of the unscaled
* image (that is, the image at its intrinsic size).
* @param aRectAtTargetSize If not Nothing(), the invalidation rect in the
* coordinate system of the scaled image (that is,
* the image at our target decoding size). This must
* be supplied if we're downscaling during decode.
*/
void PostInvalidation(const nsIntRect& aRect,
const Maybe<nsIntRect>& aRectAtTargetSize = Nothing());
// Called by the decoders when they have successfully decoded the image. This
// may occur as the result of the decoder getting to the appropriate point in
@ -361,9 +395,14 @@ protected:
* It is not possible to create sparse frame arrays; you can only append
* frames to the current frame array, or if there is only one frame in the
* array, replace that frame.
* @aTargetSize specifies the target size we're decoding to. If we're not
* downscaling during decode, this will always be the same as the image's
* intrinsic size.
*
* If a non-paletted frame is desired, pass 0 for aPaletteDepth.
*/
RawAccessFrameRef EnsureFrame(uint32_t aFrameNum,
const nsIntSize& aTargetSize,
const nsIntRect& aFrameRect,
uint32_t aDecodeFlags,
gfx::SurfaceFormat aFormat,
@ -371,6 +410,7 @@ protected:
imgFrame* aPreviousFrame);
RawAccessFrameRef InternalAddFrame(uint32_t aFrameNum,
const nsIntSize& aTargetSize,
const nsIntRect& aFrameRect,
uint32_t aDecodeFlags,
gfx::SurfaceFormat aFormat,

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

@ -255,6 +255,12 @@ DynamicImage::StartDecoding()
return NS_OK;
}
NS_IMETHODIMP
DynamicImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
{
return NS_OK;
}
bool
DynamicImage::IsDecoded()
{

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

@ -52,11 +52,16 @@ public:
* multipart/x-mixed-replace image parts fall into this category.) If this
* flag is set, INIT_FLAG_DISCARDABLE and INIT_FLAG_DECODE_ON_DRAW must not be
* set.
*
* INIT_FLAG_DOWNSCALE_DURING_DECODE: The container should attempt to
* downscale images during decoding instead of decoding them to their
* intrinsic size.
*/
static const uint32_t INIT_FLAG_NONE = 0x0;
static const uint32_t INIT_FLAG_DISCARDABLE = 0x1;
static const uint32_t INIT_FLAG_DECODE_ON_DRAW = 0x2;
static const uint32_t INIT_FLAG_TRANSIENT = 0x4;
static const uint32_t INIT_FLAG_NONE = 0x0;
static const uint32_t INIT_FLAG_DISCARDABLE = 0x1;
static const uint32_t INIT_FLAG_DECODE_ON_DRAW = 0x2;
static const uint32_t INIT_FLAG_TRANSIENT = 0x4;
static const uint32_t INIT_FLAG_DOWNSCALE_DURING_DECODE = 0x8;
/**
* Creates a new image container.

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

@ -31,14 +31,22 @@ namespace image {
ImageFactory::Initialize()
{ }
static bool
ShouldDownscaleDuringDecode(const nsCString& aMimeType)
{
// Not enabled for anything yet.
return false;
}
static uint32_t
ComputeImageFlags(ImageURL* uri, bool isMultiPart)
ComputeImageFlags(ImageURL* uri, const nsCString& aMimeType, bool isMultiPart)
{
nsresult rv;
// We default to the static globals.
bool isDiscardable = gfxPrefs::ImageMemDiscardable();
bool doDecodeOnDraw = gfxPrefs::ImageMemDecodeOnDraw();
bool doDownscaleDuringDecode = gfxPrefs::ImageDownscaleDuringDecodeEnabled();
// We want UI to be as snappy as possible and not to flicker. Disable
// discarding and decode-on-draw for chrome URLS.
@ -56,10 +64,15 @@ ComputeImageFlags(ImageURL* uri, bool isMultiPart)
isDiscardable = doDecodeOnDraw = false;
}
// Downscale-during-decode is only enabled for certain content types.
if (doDownscaleDuringDecode && !ShouldDownscaleDuringDecode(aMimeType)) {
doDownscaleDuringDecode = false;
}
// For multipart/x-mixed-replace, we basically want a direct channel to the
// decoder. Disable both for this case as well.
// decoder. Disable everything for this case.
if (isMultiPart) {
isDiscardable = doDecodeOnDraw = false;
isDiscardable = doDecodeOnDraw = doDownscaleDuringDecode = false;
}
// We have all the information we need.
@ -73,6 +86,9 @@ ComputeImageFlags(ImageURL* uri, bool isMultiPart)
if (isMultiPart) {
imageFlags |= Image::INIT_FLAG_TRANSIENT;
}
if (doDownscaleDuringDecode) {
imageFlags |= Image::INIT_FLAG_DOWNSCALE_DURING_DECODE;
}
return imageFlags;
}
@ -89,7 +105,7 @@ ImageFactory::CreateImage(nsIRequest* aRequest,
"Pref observers should have been initialized already");
// Compute the image's initialization flags.
uint32_t imageFlags = ComputeImageFlags(aURI, aIsMultiPart);
uint32_t imageFlags = ComputeImageFlags(aURI, aMimeType, aIsMultiPart);
// Select the type of image to create based on MIME type.
if (aMimeType.EqualsLiteral(IMAGE_SVG_XML)) {

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

@ -53,6 +53,7 @@ public:
int32_t GetWidth() const { return mSize->width; }
int32_t GetHeight() const { return mSize->height; }
nsIntSize GetSize() const { return *mSize; }
Orientation GetOrientation() const { return *mOrientation; }
private:

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

@ -224,6 +224,12 @@ ImageWrapper::StartDecoding()
return mInnerImage->StartDecoding();
}
NS_IMETHODIMP
ImageWrapper::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
{
return mInnerImage->RequestDecodeForSize(aSize, aFlags);
}
bool
ImageWrapper::IsDecoded()
{

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

@ -34,6 +34,7 @@
#include "gfxContext.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Move.h"
#include "mozilla/MemoryReporting.h"
@ -315,14 +316,21 @@ RasterImage::Init(const char* aMimeType,
// transient images.
MOZ_ASSERT(!(aFlags & INIT_FLAG_TRANSIENT) ||
(!(aFlags & INIT_FLAG_DISCARDABLE) &&
!(aFlags & INIT_FLAG_DECODE_ON_DRAW)),
"Transient images can't be discardable or decode-on-draw");
!(aFlags & INIT_FLAG_DECODE_ON_DRAW) &&
!(aFlags & INIT_FLAG_DOWNSCALE_DURING_DECODE)),
"Illegal init flags for transient image");
// Store initialization data
mSourceDataMimeType.Assign(aMimeType);
mDiscardable = !!(aFlags & INIT_FLAG_DISCARDABLE);
mDecodeOnDraw = !!(aFlags & INIT_FLAG_DECODE_ON_DRAW);
mTransient = !!(aFlags & INIT_FLAG_TRANSIENT);
mDownscaleDuringDecode = !!(aFlags & INIT_FLAG_DOWNSCALE_DURING_DECODE);
#ifndef MOZ_ENABLE_SKIA
// Downscale-during-decode requires Skia.
mDownscaleDuringDecode = false;
#endif
// Lock this image's surfaces in the SurfaceCache if we're not discardable.
if (!mDiscardable) {
@ -330,8 +338,7 @@ RasterImage::Init(const char* aMimeType,
}
// Create the initial size decoder.
nsresult rv = Decode(DecodeStrategy::ASYNC, DECODE_FLAGS_DEFAULT,
/* aDoSizeDecode = */ true);
nsresult rv = Decode(DecodeStrategy::ASYNC, Nothing(), DECODE_FLAGS_DEFAULT);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
@ -463,7 +470,7 @@ RasterImage::GetType()
DrawableFrameRef
RasterImage::LookupFrameInternal(uint32_t aFrameNum,
const nsIntSize& aSize,
const IntSize& aSize,
uint32_t aFlags)
{
if (!mAnim) {
@ -478,10 +485,30 @@ RasterImage::LookupFrameInternal(uint32_t aFrameNum,
return mAnim->GetCompositedFrame(aFrameNum);
}
return SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize.ToIntSize(),
DecodeFlags(aFlags),
aFrameNum));
Maybe<uint32_t> alternateFlags;
if (IsOpaque()) {
// If we're opaque, we can always substitute a frame that was decoded with a
// different decode flag for premultiplied alpha, because that can only
// matter for frames with transparency.
alternateFlags = Some(aFlags ^ FLAG_DECODE_NO_PREMULTIPLY_ALPHA);
}
// We don't want any substitution for sync decodes (except the premultiplied
// alpha optimization above), so we use SurfaceCache::Lookup in this case.
if (aFlags & FLAG_SYNC_DECODE) {
return SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize,
DecodeFlags(aFlags),
aFrameNum),
alternateFlags);
}
// We'll return the best match we can find to the requested frame.
return SurfaceCache::LookupBestMatch(ImageKey(this),
RasterSurfaceKey(aSize,
DecodeFlags(aFlags),
aFrameNum),
alternateFlags);
}
DrawableFrameRef
@ -492,32 +519,34 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
{
MOZ_ASSERT(NS_IsMainThread());
DrawableFrameRef ref = LookupFrameInternal(aFrameNum, aSize, aFlags);
IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
? aSize.ToIntSize()
: mSize.ToIntSize();
if (!ref && IsOpaque() && aFrameNum == 0) {
// We can use non-premultiplied alpha frames when premultipled alpha is
// requested, or vice versa, if this image is opaque. Try again with the bit
// toggled.
ref = LookupFrameInternal(aFrameNum, aSize,
aFlags ^ FLAG_DECODE_NO_PREMULTIPLY_ALPHA);
DrawableFrameRef ref = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
if (!ref && !mHasSize) {
// We can't request a decode without knowing our intrinsic size. Give up.
return DrawableFrameRef();
}
if (!ref) {
if (!ref || ref->GetImageSize() != requestedSize) {
// The OS threw this frame away. We need to redecode if we can.
MOZ_ASSERT(!mAnim, "Animated frames should be locked");
WantDecodedFrames(aFlags, aShouldSyncNotify);
WantDecodedFrames(ThebesIntSize(requestedSize), aFlags, aShouldSyncNotify);
// If we were able to sync decode, we should already have the frame. If we
// had to decode asynchronously, maybe we've gotten lucky.
ref = LookupFrameInternal(aFrameNum, aSize, aFlags);
if (!ref) {
// We didn't successfully redecode, so just fail.
return DrawableFrameRef();
// If we can sync decode, we should already have the frame.
if ((aFlags & FLAG_SYNC_DECODE) && aShouldSyncNotify) {
ref = LookupFrameInternal(aFrameNum, requestedSize, aFlags);
}
}
if (!ref) {
// We still weren't able to get a frame. Give up.
return DrawableFrameRef();
}
if (ref->GetCompositingFailed()) {
return DrawableFrameRef();
}
@ -1122,8 +1151,7 @@ RasterImage::OnImageDataComplete(nsIRequest*, nsISupports*, nsresult aStatus,
// We need to guarantee that we've gotten the image's size, or at least
// determined that we won't be able to get it, before we deliver the load
// event. That means we have to do a synchronous size decode here.
Decode(DecodeStrategy::SYNC_IF_POSSIBLE, DECODE_FLAGS_DEFAULT,
/* aDoSizeDecode = */ true);
Decode(DecodeStrategy::SYNC_IF_POSSIBLE, Nothing(), DECODE_FLAGS_DEFAULT);
}
// Determine our final status, giving precedence to Necko failure codes. We
@ -1249,13 +1277,16 @@ RasterImage::CanDiscard() {
// Sets up a decoder for this image.
already_AddRefed<Decoder>
RasterImage::CreateDecoder(bool aDoSizeDecode, uint32_t aFlags)
RasterImage::CreateDecoder(const Maybe<nsIntSize>& aSize, uint32_t aFlags)
{
// Make sure we actually get size before doing a full decode.
if (aDoSizeDecode) {
MOZ_ASSERT(!mHasSize, "Should not do unnecessary size decodes");
} else {
if (aSize) {
MOZ_ASSERT(mHasSize, "Must do a size decode before a full decode!");
MOZ_ASSERT(mDownscaleDuringDecode || *aSize == mSize,
"Can only decode to our intrinsic size if we're not allowed to "
"downscale-during-decode");
} else {
MOZ_ASSERT(!mHasSize, "Should not do unnecessary size decodes");
}
// Figure out which decoder we want.
@ -1296,27 +1327,38 @@ RasterImage::CreateDecoder(bool aDoSizeDecode, uint32_t aFlags)
MOZ_ASSERT(decoder, "Should have a decoder now");
// Initialize the decoder.
decoder->SetSizeDecode(aDoSizeDecode);
decoder->SetSizeDecode(!aSize);
decoder->SetSendPartialInvalidations(!mHasBeenDecoded);
decoder->SetImageIsTransient(mTransient);
decoder->SetDecodeFlags(DecodeFlags(aFlags));
if (!aDoSizeDecode) {
if (aSize) {
// We already have the size; tell the decoder so it can preallocate a
// frame. By default, we create an ARGB frame with no offset. If decoders
// need a different type, they need to ask for it themselves.
// XXX(seth): Note that we call SetSize() and NeedNewFrame() with the
// image's intrinsic size, but AllocateFrame with our target size.
decoder->SetSize(mSize, mOrientation);
decoder->NeedNewFrame(0, 0, 0, mSize.width, mSize.height,
decoder->NeedNewFrame(0, 0, 0, aSize->width, aSize->height,
SurfaceFormat::B8G8R8A8);
decoder->AllocateFrame();
decoder->AllocateFrame(*aSize);
}
decoder->SetIterator(mSourceBuffer->Iterator());
// Set a target size for downscale-during-decode if applicable.
if (mDownscaleDuringDecode && aSize && *aSize != mSize) {
DebugOnly<nsresult> rv = decoder->SetTargetSize(*aSize);
MOZ_ASSERT(nsresult(rv) != NS_ERROR_NOT_AVAILABLE,
"We're downscale-during-decode but decoder doesn't support it?");
MOZ_ASSERT(NS_SUCCEEDED(rv), "Bad downscale-during-decode target size?");
}
decoder->Init();
if (NS_FAILED(decoder->GetDecoderError())) {
return nullptr;
}
if (!aDoSizeDecode) {
if (!aSize) {
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Subtract(mDecodeCount);
mDecodeCount++;
Telemetry::GetHistogramById(Telemetry::IMAGE_DECODE_COUNT)->Add(mDecodeCount);
@ -1336,12 +1378,13 @@ RasterImage::CreateDecoder(bool aDoSizeDecode, uint32_t aFlags)
}
void
RasterImage::WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify)
RasterImage::WantDecodedFrames(const nsIntSize& aSize, uint32_t aFlags,
bool aShouldSyncNotify)
{
if (aShouldSyncNotify) {
// We can sync notify, which means we can also sync decode.
if (aFlags & FLAG_SYNC_DECODE) {
Decode(DecodeStrategy::SYNC_IF_POSSIBLE, aFlags);
Decode(DecodeStrategy::SYNC_IF_POSSIBLE, Some(aSize), aFlags);
return;
}
@ -1349,12 +1392,12 @@ RasterImage::WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify)
// case that we're redecoding an image (see bug 845147).
Decode(mHasBeenDecoded ? DecodeStrategy::ASYNC
: DecodeStrategy::SYNC_FOR_SMALL_IMAGES,
aFlags);
Some(aSize), aFlags);
return;
}
// We can't sync notify, so do an async decode.
Decode(DecodeStrategy::ASYNC, aFlags);
Decode(DecodeStrategy::ASYNC, Some(aSize), aFlags);
}
//******************************************************************************
@ -1362,24 +1405,7 @@ RasterImage::WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify)
NS_IMETHODIMP
RasterImage::RequestDecode()
{
MOZ_ASSERT(NS_IsMainThread());
if (mError) {
return NS_ERROR_FAILURE;
}
if (!mHasSize) {
mWantFullDecode = true;
return NS_OK;
}
// Look up the first frame of the image, which will implicitly start decoding
// if it's not available right now.
// XXX(seth): Passing false for aShouldSyncNotify here has the effect of
// decoding asynchronously, but that's not obvious from the argument name.
// This API needs to be reworked.
LookupFrame(0, mSize, DECODE_FLAGS_DEFAULT, /* aShouldSyncNotify = */ false);
return NS_OK;
return RequestDecodeForSize(mSize, DECODE_FLAGS_DEFAULT);
}
/* void startDecode() */
@ -1391,20 +1417,38 @@ RasterImage::StartDecoding()
NS_NewRunnableMethod(this, &RasterImage::StartDecoding));
}
return RequestDecodeForSize(mSize, FLAG_SYNC_DECODE);
}
NS_IMETHODIMP
RasterImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
{
MOZ_ASSERT(NS_IsMainThread());
if (mError) {
return NS_ERROR_FAILURE;
}
if (!mHasSize) {
mWantFullDecode = true;
return NS_OK;
}
// Fall back to our intrinsic size if we don't support
// downscale-during-decode.
nsIntSize targetSize = mDownscaleDuringDecode ? aSize : mSize;
// Sync decode small images if requested.
bool shouldSyncDecodeSmallImages = aFlags & FLAG_SYNC_DECODE;
// Look up the first frame of the image, which will implicitly start decoding
// if it's not available right now.
// XXX(seth): Passing true for aShouldSyncNotify here has the effect of
// synchronously decoding small images, but that's not obvious from the
// argument name. This API needs to be reworked.
LookupFrame(0, mSize, DECODE_FLAGS_DEFAULT, /* aShouldSyncNotify = */ true);
// synchronously decoding small images, while passing false has the effect of
// decoding asynchronously, but that's not obvious from the argument name.
// This API needs to be reworked.
LookupFrame(0, targetSize, DecodeFlags(aFlags),
/* aShouldSyncNotify = */ shouldSyncDecodeSmallImages);
return NS_OK;
}
@ -1418,29 +1462,30 @@ RasterImage::IsDecoded()
NS_IMETHODIMP
RasterImage::Decode(DecodeStrategy aStrategy,
uint32_t aFlags,
bool aDoSizeDecode /* = false */)
const Maybe<nsIntSize>& aSize,
uint32_t aFlags)
{
MOZ_ASSERT(aDoSizeDecode || NS_IsMainThread());
MOZ_ASSERT(!aSize || NS_IsMainThread());
if (mError) {
return NS_ERROR_FAILURE;
}
// If we don't have a size yet, we can't do any other decoding.
if (!mHasSize && !aDoSizeDecode) {
if (!mHasSize && aSize) {
mWantFullDecode = true;
return NS_OK;
}
// Create a decoder.
nsRefPtr<Decoder> decoder = CreateDecoder(aDoSizeDecode, aFlags);
nsRefPtr<Decoder> decoder = CreateDecoder(aSize, aFlags);
if (!decoder) {
return NS_ERROR_FAILURE;
}
if (!aDoSizeDecode) {
// Send out early notifications right away.
if (aSize) {
// This isn't a size decode (which doesn't send any early notifications), so
// send out notifications right away.
NotifyProgress(decoder->TakeProgress(),
decoder->TakeInvalidRect(),
decoder->GetDecodeFlags());
@ -1495,6 +1540,11 @@ RasterImage::CanScale(GraphicsFilter aFilter,
return false;
}
// We don't HQ scale images that we can downscale during decode.
if (mDownscaleDuringDecode) {
return false;
}
// We don't use the scaler for animated or transient images to avoid doing a
// bunch of work on an image that just gets thrown away.
if (mAnim || mTransient) {
@ -1530,6 +1580,40 @@ RasterImage::CanScale(GraphicsFilter aFilter,
#endif
}
bool
RasterImage::CanDownscaleDuringDecode(const nsIntSize& aSize, uint32_t aFlags)
{
// Check basic requirements: downscale-during-decode is enabled for this
// image, we have all the source data and know our size, the flags allow us to
// do it, and a 'good' filter is being used.
if (!mDownscaleDuringDecode || !mHasSize ||
!(aFlags & imgIContainer::FLAG_HIGH_QUALITY_SCALING)) {
return false;
}
// We don't downscale animated images during decode.
if (mAnim) {
return false;
}
// Never upscale.
if (aSize.width >= mSize.width || aSize.height >= mSize.height) {
return false;
}
// Zero or negative width or height is unacceptable.
if (aSize.width < 1 || aSize.height < 1) {
return false;
}
// There's no point in scaling if we can't store the result.
if (!SurfaceCache::CanHold(aSize.ToIntSize())) {
return false;
}
return true;
}
void
RasterImage::NotifyNewScaledFrame()
{
@ -1654,13 +1738,14 @@ RasterImage::Draw(gfxContext* aContext,
mProgressTracker->OnUnlockedDraw();
}
// XXX(seth): For now, we deliberately don't look up a frame of size aSize
// (though DrawWithPreDownscaleIfNeeded will do so later). It doesn't make
// sense to do so until we support downscale-during-decode. Right now we need
// to make sure that we always touch an mSize-sized frame so that we have
// something to HQ scale.
// If we're not using GraphicsFilter::FILTER_GOOD, we shouldn't high-quality
// scale or downscale during decode.
uint32_t flags = aFilter == GraphicsFilter::FILTER_GOOD
? aFlags
: aFlags & ~FLAG_HIGH_QUALITY_SCALING;
DrawableFrameRef ref =
LookupFrame(GetRequestedFrameIndex(aWhichFrame), mSize, aFlags);
LookupFrame(GetRequestedFrameIndex(aWhichFrame), aSize, flags);
if (!ref) {
// Getting the frame (above) touches the image and kicks off decoding.
if (mDrawStartTime.IsNull()) {
@ -1673,7 +1758,7 @@ RasterImage::Draw(gfxContext* aContext,
ref->IsImageComplete();
DrawWithPreDownscaleIfNeeded(Move(ref), aContext, aSize,
aRegion, aFilter, aFlags);
aRegion, aFilter, flags);
if (shouldRecordTelemetry) {
TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime;
@ -1938,7 +2023,10 @@ RasterImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame,
nsIntSize destSize(ceil(aDest.width), ceil(aDest.height));
if (CanScale(aFilter, destSize, aFlags)) {
if (aFilter == GraphicsFilter::FILTER_GOOD &&
CanDownscaleDuringDecode(destSize, aFlags)) {
return destSize;
} else if (CanScale(aFilter, destSize, aFlags)) {
DrawableFrameRef frameRef =
SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(destSize.ToIntSize(),

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

@ -296,7 +296,7 @@ private:
bool aShouldSyncNotify = true);
DrawableFrameRef LookupFrameInternal(uint32_t aFrameNum,
const nsIntSize& aSize,
const gfx::IntSize& aSize,
uint32_t aFlags);
DrawableFrameRef LookupFrame(uint32_t aFrameNum,
const nsIntSize& aSize,
@ -325,12 +325,26 @@ private:
// Decoding.
//////////////////////////////////////////////////////////////////////////////
already_AddRefed<Decoder> CreateDecoder(bool aDoSizeDecode, uint32_t aFlags);
/**
* Creates and runs a decoder, either synchronously or asynchronously
* according to @aStrategy. Passes the provided target size @aSize and decode
* flags @aFlags to CreateDecoder. If a size decode is desired, pass Nothing
* for @aSize.
*/
NS_IMETHOD Decode(DecodeStrategy aStrategy,
const Maybe<nsIntSize>& aSize,
uint32_t aFlags);
void WantDecodedFrames(uint32_t aFlags, bool aShouldSyncNotify);
/**
* Creates a new decoder with a target size of @aSize and decode flags
* specified by @aFlags. If a size decode is desired, pass Nothing() for
* @aSize.
*/
already_AddRefed<Decoder> CreateDecoder(const Maybe<nsIntSize>& aSize,
uint32_t aFlags);
NS_IMETHOD Decode(DecodeStrategy aStrategy, uint32_t aFlags,
bool aDoSizeDecode = false);
void WantDecodedFrames(const nsIntSize& aSize, uint32_t aFlags,
bool aShouldSyncNotify);
private: // data
nsIntSize mSize;
@ -378,6 +392,7 @@ private: // data
bool mDiscardable:1; // Is container discardable?
bool mHasSourceData:1; // Do we have source data?
bool mHasBeenDecoded:1; // Decoded at least once?
bool mDownscaleDuringDecode:1;
// Whether we're waiting to start animation. If we get a StartAnimation() call
// but we don't yet have more than one frame, mPendingAnimation is set so that
@ -408,6 +423,9 @@ private: // data
// Determines whether we can perform an HQ scale with the given parameters.
bool CanScale(GraphicsFilter aFilter, const nsIntSize& aSize, uint32_t aFlags);
// Determines whether we can downscale during decode with the given parameters.
bool CanDownscaleDuringDecode(const nsIntSize& aSize, uint32_t aFlags);
// Called by the HQ scaler when a new scaled frame is ready.
void NotifyNewScaledFrame();

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

@ -248,6 +248,23 @@ public:
return surface.forget();
}
already_AddRefed<CachedSurface>
LookupBestMatch(const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags)
{
// Try for a perfect match first.
nsRefPtr<CachedSurface> surface;
mSurfaces.Get(aSurfaceKey, getter_AddRefs(surface));
if (surface) {
return surface.forget();
}
// There's no perfect match, so find the best match we can.
MatchContext matchContext(aSurfaceKey, aAlternateFlags);
ForEach(TryToImproveMatch, &matchContext);
return matchContext.mBestMatch.forget();
}
void ForEach(SurfaceTable::EnumReadFunction aFunction, void* aData)
{
mSurfaces.EnumerateRead(aFunction, aData);
@ -257,6 +274,75 @@ public:
bool IsLocked() const { return mLocked; }
private:
struct MatchContext
{
MatchContext(const SurfaceKey& aIdealKey,
const Maybe<uint32_t>& aAlternateFlags)
: mIdealKey(aIdealKey)
, mAlternateFlags(aAlternateFlags)
{ }
const SurfaceKey& mIdealKey;
const Maybe<uint32_t> mAlternateFlags;
nsRefPtr<CachedSurface> mBestMatch;
};
static PLDHashOperator TryToImproveMatch(const SurfaceKey& aSurfaceKey,
CachedSurface* aSurface,
void* aContext)
{
auto context = static_cast<MatchContext*>(aContext);
const SurfaceKey& idealKey = context->mIdealKey;
// Matching the animation time and SVG context is required.
if (aSurfaceKey.AnimationTime() != idealKey.AnimationTime() ||
aSurfaceKey.SVGContext() != idealKey.SVGContext()) {
return PL_DHASH_NEXT;
}
// Matching the flags is required, but we can match the alternate flags as
// well if some were provided.
if (aSurfaceKey.Flags() != idealKey.Flags() &&
Some(aSurfaceKey.Flags()) != context->mAlternateFlags) {
return PL_DHASH_NEXT;
}
// Anything is better than nothing! (Within the constraints we just
// checked, of course.)
if (!context->mBestMatch) {
context->mBestMatch = aSurface;
return PL_DHASH_NEXT;
}
MOZ_ASSERT(context->mBestMatch, "Should have a current best match");
SurfaceKey bestMatchKey = context->mBestMatch->GetSurfaceKey();
// Compare sizes. We use an area-based heuristic here instead of computing a
// truly optimal answer, since it seems very unlikely to make a difference
// for realistic sizes.
int64_t idealArea = idealKey.Size().width * idealKey.Size().height;
int64_t surfaceArea = aSurfaceKey.Size().width * aSurfaceKey.Size().height;
int64_t bestMatchArea =
bestMatchKey.Size().width * bestMatchKey.Size().height;
// If the best match is smaller than the ideal size, prefer bigger sizes.
if (bestMatchArea < idealArea) {
if (surfaceArea > bestMatchArea) {
context->mBestMatch = aSurface;
}
return PL_DHASH_NEXT;
}
// Other, prefer sizes closer to the ideal size, but still not smaller.
if (idealArea <= surfaceArea && surfaceArea < bestMatchArea) {
context->mBestMatch = aSurface;
return PL_DHASH_NEXT;
}
// This surface isn't an improvement over the current best match.
return PL_DHASH_NEXT;
}
SurfaceTable mSurfaces;
bool mLocked;
};
@ -453,6 +539,45 @@ public:
return ref;
}
DrawableFrameRef LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags)
{
nsRefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache)
return DrawableFrameRef(); // No cached surfaces for this image.
// Repeatedly look up the best match, trying again if the resulting surface
// has been freed by the operating system, until we can either lock a
// surface for drawing or there are no matching surfaces left.
// XXX(seth): This is O(N^2), but N is expected to be very small. If we
// encounter a performance problem here we can revisit this.
nsRefPtr<CachedSurface> surface;
DrawableFrameRef ref;
while (true) {
surface = cache->LookupBestMatch(aSurfaceKey, aAlternateFlags);
if (!surface) {
return DrawableFrameRef(); // Lookup in the per-image cache missed.
}
ref = surface->DrawableRef();
if (ref) {
break;
}
// The surface was released by the operating system. Remove the cache
// entry as well.
Remove(surface);
}
if (!surface->IsLocked()) {
mExpirationTracker.MarkUsed(surface);
}
return ref;
}
void RemoveSurface(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey)
{
@ -787,15 +912,37 @@ SurfaceCache::Shutdown()
}
/* static */ DrawableFrameRef
SurfaceCache::Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey)
SurfaceCache::Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags /* = Nothing() */)
{
if (!sInstance) {
return DrawableFrameRef();
}
MutexAutoLock lock(sInstance->GetMutex());
return sInstance->Lookup(aImageKey, aSurfaceKey);
DrawableFrameRef ref = sInstance->Lookup(aImageKey, aSurfaceKey);
if (!ref && aAlternateFlags) {
ref = sInstance->Lookup(aImageKey,
aSurfaceKey.WithNewFlags(*aAlternateFlags));
}
return ref;
}
/* static */ DrawableFrameRef
SurfaceCache::LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
/* = Nothing() */)
{
if (!sInstance) {
return DrawableFrameRef();
}
MutexAutoLock lock(sInstance->GetMutex());
return sInstance->LookupBestMatch(aImageKey, aSurfaceKey, aAlternateFlags);
}
/* static */ InsertOutcome

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

@ -63,6 +63,14 @@ public:
}
IntSize Size() const { return mSize; }
Maybe<SVGImageContext> SVGContext() const { return mSVGContext; }
float AnimationTime() const { return mAnimationTime; }
uint32_t Flags() const { return mFlags; }
SurfaceKey WithNewFlags(uint32_t aFlags) const
{
return SurfaceKey(mSize, mSVGContext, mAnimationTime, aFlags);
}
private:
SurfaceKey(const IntSize& aSize,
@ -171,12 +179,41 @@ struct SurfaceCache
*
* @param aImageKey Key data identifying which image the surface belongs to.
* @param aSurfaceKey Key data which uniquely identifies the requested surface.
* @param aAlternateFlags If not Nothing(), a different set of flags than the
* ones specified in @aSurfaceKey which are also
* acceptable to the caller. This is more efficient
* than calling Lookup() twice, which requires taking a
* lock each time.
*
* @return a DrawableFrameRef to the imgFrame wrapping the requested surface,
* or an empty DrawableFrameRef if not found.
*/
static DrawableFrameRef Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey);
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
= Nothing());
/**
* Looks up the best matching surface in the cache and returns a drawable
* reference to the imgFrame containing it.
*
* Returned surfaces may vary from the requested surface only in terms of
* size, unless @aAlternateFlags is specified.
*
* @param aImageKey Key data identifying which image the surface belongs to.
* @param aSurfaceKey Key data which identifies the ideal surface to return.
* @param aAlternateFlags If not Nothing(), a different set of flags than the
* ones specified in @aSurfaceKey which are also
* acceptable to the caller. This is much more
* efficient than calling LookupBestMatch() twice.
*
* @return a DrawableFrameRef to the imgFrame wrapping a surface similar to
* the requested surface, or an empty DrawableFrameRef if not found.
*/
static DrawableFrameRef LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<uint32_t>& aAlternateFlags
= Nothing());
/**
* Insert a surface into the cache. If a surface with the same ImageKey and

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

@ -899,6 +899,15 @@ VectorImage::StartDecoding()
return NS_OK;
}
NS_IMETHODIMP
VectorImage::RequestDecodeForSize(const nsIntSize& aSize, uint32_t aFlags)
{
// Nothing to do for SVG images, though in theory we could rasterize to the
// provided size ahead of time if we supported off-main-thread SVG
// rasterization...
return NS_OK;
}
bool
VectorImage::IsDecoded()
{

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

@ -31,7 +31,7 @@ load 256-height.ico
HTTP load delayedframe.sjs
asserts(0-1) load 681190.html # asserts can't create such a big surface
skip-if(Android&&smallScreen) skip-if(B2G) load 694165-1.xhtml # nexus-s Android 2.3.6, bug 876275 for B2G on a VM
skip-if(Android&&smallScreen) skip-if(B2G) skip-if(OSX==1010&&isDebugBuild) load 694165-1.xhtml # nexus-s Android 2.3.6, bug 876275 for B2G on a VM; bug 1123195 for OS X 10.10 debug
load 732319-1.html
load 844403-1.html

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

@ -462,7 +462,7 @@ struct JSClass {
// the beginning of every global object's slots for use by the
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 4
#define JSCLASS_GLOBAL_SLOT_COUNT (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 30)
#define JSCLASS_GLOBAL_SLOT_COUNT (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 31)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

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

@ -31,6 +31,7 @@ using mozilla::FloorLog2;
namespace js {
extern const JSFunctionSpec Float32x4Methods[];
extern const JSFunctionSpec Float64x2Methods[];
extern const JSFunctionSpec Int32x4Methods[];
}
@ -65,6 +66,7 @@ js::IsVectorObject(HandleValue v)
template bool js::IsVectorObject<Int32x4>(HandleValue v);
template bool js::IsVectorObject<Float32x4>(HandleValue v);
template bool js::IsVectorObject<Float64x2>(HandleValue v);
template<typename V>
bool
@ -124,6 +126,9 @@ static bool type##Lane##lane(JSContext *cx, unsigned argc, Value *vp) { \
FOUR_LANES_ACCESSOR(Int32x4);
FOUR_LANES_ACCESSOR(Float32x4);
#undef FOUR_LANES_ACCESSOR
LANE_ACCESSOR(Float64x2, 0);
LANE_ACCESSOR(Float64x2, 1);
#undef LANE_ACCESSOR
template<typename SimdType>
@ -168,6 +173,7 @@ static bool type##SignMask(JSContext *cx, unsigned argc, Value *vp) { \
return SignMask<type>(cx, argc, vp); \
}
SIGN_MASK(Float32x4);
SIGN_MASK(Float64x2);
SIGN_MASK(Int32x4);
#undef SIGN_MASK
@ -201,6 +207,13 @@ class Float32x4Defn {
static const JSPropertySpec TypedObjectProperties[];
static const JSFunctionSpec TypedObjectMethods[];
};
class Float64x2Defn {
public:
static const SimdTypeDescr::Type type = SimdTypeDescr::TYPE_FLOAT64;
static const JSFunctionSpec TypeDescriptorMethods[];
static const JSPropertySpec TypedObjectProperties[];
static const JSFunctionSpec TypedObjectMethods[];
};
} // namespace js
const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = {
@ -224,6 +237,25 @@ const JSFunctionSpec js::Float32x4Defn::TypedObjectMethods[] = {
JS_FS_END
};
const JSFunctionSpec js::Float64x2Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END
};
const JSPropertySpec js::Float64x2Defn::TypedObjectProperties[] = {
JS_PSG("x", Float64x2Lane0, JSPROP_PERMANENT),
JS_PSG("y", Float64x2Lane1, JSPROP_PERMANENT),
JS_PSG("signMask", Float64x2SignMask, JSPROP_PERMANENT),
JS_PS_END
};
const JSFunctionSpec js::Float64x2Defn::TypedObjectMethods[] = {
JS_SELF_HOSTED_FN("toSource", "SimdToSource", 0, 0),
JS_FS_END
};
const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
@ -268,6 +300,7 @@ CreateSimdClass(JSContext *cx, Handle<GlobalObject*> global, HandlePropertyName
typeDescr->initReservedSlot(JS_DESCR_SLOT_SIZE, Int32Value(SimdTypeDescr::size(type)));
typeDescr->initReservedSlot(JS_DESCR_SLOT_OPAQUE, BooleanValue(false));
typeDescr->initReservedSlot(JS_DESCR_SLOT_TYPE, Int32Value(T::type));
typeDescr->initReservedSlot(JS_DESCR_SLOT_LANES, Int32Value(SimdTypeDescr::lanes(type)));
if (!CreateUserSizeAndAlignmentProperties(cx, typeDescr))
return nullptr;
@ -298,6 +331,18 @@ CreateSimdClass(JSContext *cx, Handle<GlobalObject*> global, HandlePropertyName
return typeDescr;
}
const char*
SimdTypeToMinimumLanesNumber(SimdTypeDescr &descr) {
switch (descr.type()) {
case SimdTypeDescr::TYPE_INT32:
case SimdTypeDescr::TYPE_FLOAT32:
return "3";
case SimdTypeDescr::TYPE_FLOAT64:
return "1";
}
MOZ_CRASH("Unexpected SIMD type description.");
}
bool
SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
{
@ -336,6 +381,13 @@ SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
}
break;
}
case SimdTypeDescr::TYPE_FLOAT64: {
double *mem = reinterpret_cast<double*>(result->typedMem());
for (unsigned i = 0; i < 2; i++) {
if (!ToNumber(cx, args[i], &mem[i]))
return false;
}
}
}
args.rval().setObject(*result);
return true;
@ -386,6 +438,23 @@ SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global)
return nullptr;
}
// float64x2
RootedObject float64x2Object(cx);
float64x2Object = CreateSimdClass<Float64x2Defn>(cx, global,
cx->names().float64x2);
if (!float64x2Object)
return nullptr;
// Define float64x2 functions and install as a property of the SIMD object.
RootedValue float64x2Value(cx, ObjectValue(*float64x2Object));
if (!JS_DefineFunctions(cx, float64x2Object, Float64x2Methods) ||
!DefineProperty(cx, SIMD, cx->names().float64x2,
float64x2Value, nullptr, nullptr,
JSPROP_READONLY | JSPROP_PERMANENT))
{
return nullptr;
}
// int32x4
RootedObject int32x4Object(cx);
int32x4Object = CreateSimdClass<Int32x4Defn>(cx, global,
@ -411,6 +480,7 @@ SIMDObject::initClass(JSContext *cx, Handle<GlobalObject *> global)
global->setConstructor(JSProto_SIMD, SIMDValue);
global->setFloat32x4TypeDescr(*float32x4Object);
global->setFloat64x2TypeDescr(*float64x2Object);
global->setInt32x4TypeDescr(*int32x4Object);
return SIMD;
}
@ -441,6 +511,7 @@ js::CreateSimd(JSContext *cx, typename V::Elem *data)
}
template JSObject *js::CreateSimd<Float32x4>(JSContext *cx, Float32x4::Elem *data);
template JSObject *js::CreateSimd<Float64x2>(JSContext *cx, Float64x2::Elem *data);
template JSObject *js::CreateSimd<Int32x4>(JSContext *cx, Int32x4::Elem *data);
namespace js {
@ -767,8 +838,10 @@ CompareFunc(JSContext *cx, unsigned argc, Value *vp)
int32_t result[Int32x4::lanes];
InElem *left = TypedObjectMemory<InElem *>(args[0]);
InElem *right = TypedObjectMemory<InElem *>(args[1]);
for (unsigned i = 0; i < Int32x4::lanes; i++)
result[i] = Op<InElem>::apply(left[i], right[i]);
for (unsigned i = 0; i < Int32x4::lanes; i++) {
unsigned j = (i * In::lanes) / Int32x4::lanes;
result[i] = Op<InElem>::apply(left[j], right[j]);
}
return StoreResult<Int32x4>(cx, args, result);
}
@ -787,7 +860,8 @@ FuncConvert(JSContext *cx, unsigned argc, Value *vp)
Elem *val = TypedObjectMemory<Elem *>(args[0]);
RetElem result[Vret::lanes];
for (unsigned i = 0; i < Vret::lanes; i++)
result[i] = ConvertScalar<RetElem>(val[i]);
result[i] = i < V::lanes ? ConvertScalar<RetElem>(val[i]) : 0;
return StoreResult<Vret>(cx, args, result);
}
@ -858,27 +932,29 @@ Int32x4Bool(JSContext *cx, unsigned argc, Value *vp)
return StoreResult<Int32x4>(cx, args, result);
}
template<typename In>
static bool
Float32x4Clamp(JSContext *cx, unsigned argc, Value *vp)
Clamp(JSContext *cx, unsigned argc, Value *vp)
{
typedef typename In::Elem InElem;
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 3 || !IsVectorObject<Float32x4>(args[0]) ||
!IsVectorObject<Float32x4>(args[1]) || !IsVectorObject<Float32x4>(args[2]))
if (args.length() != 3 || !IsVectorObject<In>(args[0]) ||
!IsVectorObject<In>(args[1]) || !IsVectorObject<In>(args[2]))
{
return ErrorBadArgs(cx);
}
float *val = TypedObjectMemory<float *>(args[0]);
float *lowerLimit = TypedObjectMemory<float *>(args[1]);
float *upperLimit = TypedObjectMemory<float *>(args[2]);
InElem *val = TypedObjectMemory<InElem *>(args[0]);
InElem *lowerLimit = TypedObjectMemory<InElem *>(args[1]);
InElem *upperLimit = TypedObjectMemory<InElem *>(args[2]);
float result[Float32x4::lanes];
for (unsigned i = 0; i < Float32x4::lanes; i++) {
InElem result[In::lanes];
for (unsigned i = 0; i < In::lanes; i++) {
result[i] = val[i] < lowerLimit[i] ? lowerLimit[i] : val[i];
result[i] = result[i] > upperLimit[i] ? upperLimit[i] : result[i];
}
return StoreResult<Float32x4>(cx, args, result);
return StoreResult<In>(cx, args, result);
}
template<typename V>
@ -987,8 +1063,7 @@ Load(JSContext *cx, unsigned argc, Value *vp)
return false;
Elem *dest = reinterpret_cast<Elem*>(result->typedMem());
for (unsigned i = 0; i < NumElem; i++)
dest[i] = typedArrayData[i];
memcpy(dest, typedArrayData, sizeof(Elem) * NumElem);
args.rval().setObject(*result);
return true;
@ -1012,8 +1087,7 @@ Store(JSContext *cx, unsigned argc, Value *vp)
return ErrorBadArgs(cx);
Elem *src = TypedObjectMemory<Elem*>(args[2]);
for (unsigned i = 0; i < NumElem; i++)
typedArrayData[i] = src[i];
memcpy(typedArrayData, src, sizeof(Elem) * NumElem);
args.rval().setObject(args[2].toObject());
return true;
@ -1026,7 +1100,16 @@ js::simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp) \
return Func(cx, argc, vp); \
}
FLOAT32X4_FUNCTION_LIST(DEFINE_SIMD_FLOAT32X4_FUNCTION)
#undef DEFINE_SIMD_FLOAT32x4_FUNCTION
#undef DEFINE_SIMD_FLOAT32X4_FUNCTION
#define DEFINE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands, Flags) \
bool \
js::simd_float64x2_##Name(JSContext *cx, unsigned argc, Value *vp) \
{ \
return Func(cx, argc, vp); \
}
FLOAT64X2_FUNCTION_LIST(DEFINE_SIMD_FLOAT64X2_FUNCTION)
#undef DEFINE_SIMD_FLOAT64X2_FUNCTION
#define DEFINE_SIMD_INT32X4_FUNCTION(Name, Func, Operands, Flags) \
bool \
@ -1045,6 +1128,14 @@ const JSFunctionSpec js::Float32x4Methods[] = {
JS_FS_END
};
const JSFunctionSpec js::Float64x2Methods[] = {
#define SIMD_FLOAT64X2_FUNCTION_ITEM(Name, Func, Operands, Flags) \
JS_FN(#Name, js::simd_float64x2_##Name, Operands, Flags),
FLOAT64X2_FUNCTION_LIST(SIMD_FLOAT64X2_FUNCTION_ITEM)
#undef SIMD_FLOAT64X2_FUNCTION_ITEM
JS_FS_END
};
const JSFunctionSpec js::Int32x4Methods[] = {
#define SIMD_INT32X4_FUNCTION_ITEM(Name, Func, Operands, Flags) \
JS_FN(#Name, js::simd_int32x4_##Name, Operands, Flags),

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

@ -22,6 +22,8 @@
#define FLOAT32X4_UNARY_FUNCTION_LIST(V) \
V(abs, (UnaryFunc<Float32x4, Abs, Float32x4>), 1, 0) \
V(fromFloat64x2, (FuncConvert<Float64x2, Float32x4> ), 1, 0) \
V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Float32x4>), 1, 0) \
V(fromInt32x4, (FuncConvert<Int32x4, Float32x4> ), 1, 0) \
V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float32x4>), 1, 0) \
V(neg, (UnaryFunc<Float32x4, Neg, Float32x4>), 1, 0) \
@ -64,7 +66,7 @@
#define FLOAT32X4_TERNARY_FUNCTION_LIST(V) \
V(bitselect, BitSelect<Float32x4>, 3, 0) \
V(clamp, Float32x4Clamp, 3, 0) \
V(clamp, Clamp<Float32x4>, 3, 0) \
V(select, Select<Float32x4>, 3, 0)
#define FLOAT32X4_SHUFFLE_FUNCTION_LIST(V) \
@ -77,9 +79,60 @@
FLOAT32X4_TERNARY_FUNCTION_LIST(V) \
FLOAT32X4_SHUFFLE_FUNCTION_LIST(V)
#define FLOAT64X2_UNARY_FUNCTION_LIST(V) \
V(abs, (UnaryFunc<Float64x2, Abs, Float64x2>), 1, 0) \
V(fromFloat32x4, (FuncConvert<Float32x4, Float64x2> ), 1, 0) \
V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Float64x2>), 1, 0) \
V(fromInt32x4, (FuncConvert<Int32x4, Float64x2> ), 1, 0) \
V(fromInt32x4Bits, (FuncConvertBits<Int32x4, Float64x2>), 1, 0) \
V(neg, (UnaryFunc<Float64x2, Neg, Float64x2>), 1, 0) \
V(reciprocal, (UnaryFunc<Float64x2, Rec, Float64x2>), 1, 0) \
V(reciprocalSqrt, (UnaryFunc<Float64x2, RecSqrt, Float64x2>), 1, 0) \
V(splat, (FuncSplat<Float64x2>), 1, 0) \
V(sqrt, (UnaryFunc<Float64x2, Sqrt, Float64x2>), 1, 0)
#define FLOAT64X2_BINARY_FUNCTION_LIST(V) \
V(add, (BinaryFunc<Float64x2, Add, Float64x2>), 2, 0) \
V(div, (BinaryFunc<Float64x2, Div, Float64x2>), 2, 0) \
V(equal, (CompareFunc<Float64x2, Equal>), 2, 0) \
V(greaterThan, (CompareFunc<Float64x2, GreaterThan>), 2, 0) \
V(greaterThanOrEqual, (CompareFunc<Float64x2, GreaterThanOrEqual>), 2, 0) \
V(lessThan, (CompareFunc<Float64x2, LessThan>), 2, 0) \
V(lessThanOrEqual, (CompareFunc<Float64x2, LessThanOrEqual>), 2, 0) \
V(load, (Load<Float64x2, 2>), 2, 0) \
V(loadX, (Load<Float64x2, 1>), 2, 0) \
V(max, (BinaryFunc<Float64x2, Maximum, Float64x2>), 2, 0) \
V(maxNum, (BinaryFunc<Float64x2, MaxNum, Float64x2>), 2, 0) \
V(min, (BinaryFunc<Float64x2, Minimum, Float64x2>), 2, 0) \
V(minNum, (BinaryFunc<Float64x2, MinNum, Float64x2>), 2, 0) \
V(mul, (BinaryFunc<Float64x2, Mul, Float64x2>), 2, 0) \
V(notEqual, (CompareFunc<Float64x2, NotEqual>), 2, 0) \
V(store, (Store<Float64x2, 2>), 3, 0) \
V(storeX, (Store<Float64x2, 1>), 3, 0) \
V(sub, (BinaryFunc<Float64x2, Sub, Float64x2>), 2, 0) \
V(withX, (FuncWith<Float64x2, WithX>), 2, 0) \
V(withY, (FuncWith<Float64x2, WithY>), 2, 0)
#define FLOAT64X2_TERNARY_FUNCTION_LIST(V) \
V(bitselect, BitSelect<Float64x2>, 3, 0) \
V(clamp, Clamp<Float64x2>, 3, 0) \
V(select, Select<Float64x2>, 3, 0)
#define FLOAT64X2_SHUFFLE_FUNCTION_LIST(V) \
V(swizzle, Swizzle<Float64x2>, 2, 0) \
V(shuffle, Shuffle<Float64x2>, 3, 0)
#define FLOAT64X2_FUNCTION_LIST(V) \
FLOAT64X2_UNARY_FUNCTION_LIST(V) \
FLOAT64X2_BINARY_FUNCTION_LIST(V) \
FLOAT64X2_TERNARY_FUNCTION_LIST(V) \
FLOAT64X2_SHUFFLE_FUNCTION_LIST(V)
#define INT32X4_UNARY_FUNCTION_LIST(V) \
V(fromFloat32x4, (FuncConvert<Float32x4, Int32x4>), 1, 0) \
V(fromFloat32x4Bits, (FuncConvertBits<Float32x4, Int32x4>), 1, 0) \
V(fromFloat64x2, (FuncConvert<Float64x2, Int32x4>), 1, 0) \
V(fromFloat64x2Bits, (FuncConvertBits<Float64x2, Int32x4>), 1, 0) \
V(neg, (UnaryFunc<Int32x4, Neg, Int32x4>), 1, 0) \
V(not, (UnaryFunc<Int32x4, Not, Int32x4>), 1, 0) \
V(splat, (FuncSplat<Int32x4>), 0, 0)
@ -212,6 +265,26 @@ struct Float32x4 {
}
};
struct Float64x2 {
typedef double Elem;
static const unsigned lanes = 2;
static const SimdTypeDescr::Type type = SimdTypeDescr::TYPE_FLOAT64;
static TypeDescr &GetTypeDescr(GlobalObject &global) {
return global.float64x2TypeDescr().as<TypeDescr>();
}
static Elem toType(Elem a) {
return a;
}
static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
*out = v.toNumber();
return true;
}
static void setReturn(CallArgs &args, Elem value) {
args.rval().setDouble(JS::CanonicalizeNaN(value));
}
};
struct Int32x4 {
typedef int32_t Elem;
static const unsigned lanes = 4;
@ -246,6 +319,12 @@ simd_float32x4_##Name(JSContext *cx, unsigned argc, Value *vp);
FLOAT32X4_FUNCTION_LIST(DECLARE_SIMD_FLOAT32X4_FUNCTION)
#undef DECLARE_SIMD_FLOAT32X4_FUNCTION
#define DECLARE_SIMD_FLOAT64X2_FUNCTION(Name, Func, Operands, Flags) \
extern bool \
simd_float64x2_##Name(JSContext *cx, unsigned argc, Value *vp);
FLOAT64X2_FUNCTION_LIST(DECLARE_SIMD_FLOAT64X2_FUNCTION)
#undef DECLARE_SIMD_FLOAT64X2_FUNCTION
#define DECLARE_SIMD_INT32x4_FUNCTION(Name, Func, Operands, Flags) \
extern bool \
simd_int32x4_##Name(JSContext *cx, unsigned argc, Value *vp);

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

@ -406,18 +406,25 @@ js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
}
/***************************************************************************
* X4 type objects
* SIMD type objects
*
* Note: these are partially defined in SIMD.cpp
*/
static const int32_t SimdSizes[] = {
#define SIMD_SIZE(_kind, _type, _name) \
sizeof(_type) * 4,
#define SIMD_SIZE(_kind, _type, _name, _lanes) \
sizeof(_type) * _lanes,
JS_FOR_EACH_SIMD_TYPE_REPR(SIMD_SIZE) 0
#undef SIMD_SIZE
};
static int32_t SimdLanes[] = {
#define SIMD_LANE(_kind, _type, _name, _lanes) \
_lanes,
JS_FOR_EACH_SIMD_TYPE_REPR(SIMD_LANE) 0
#undef SIMD_LANE
};
int32_t
SimdTypeDescr::size(Type t)
{
@ -430,6 +437,12 @@ SimdTypeDescr::alignment(Type t)
return SimdSizes[t];
}
int32_t
SimdTypeDescr::lanes(Type t)
{
return SimdLanes[t];
}
/***************************************************************************
* ArrayMetaTypeDescr class
*/
@ -2694,6 +2707,16 @@ js::GetFloat32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp)
return true;
}
bool
js::GetFloat64x2TypeDescr(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
Rooted<GlobalObject*> global(cx, cx->global());
MOZ_ASSERT(global);
args.rval().setObject(global->float64x2TypeDescr());
return true;
}
bool
js::GetInt32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp)
{

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

@ -325,7 +325,7 @@ class ComplexTypeDescr : public TypeDescr
};
/*
* Type descriptors `float32x4` and `int32x4`
* Type descriptors `float32x4`, `int32x4` and `float64x2`
*/
class SimdTypeDescr : public ComplexTypeDescr
{
@ -333,6 +333,7 @@ class SimdTypeDescr : public ComplexTypeDescr
enum Type {
TYPE_INT32 = JS_SIMDTYPEREPR_INT32,
TYPE_FLOAT32 = JS_SIMDTYPEREPR_FLOAT32,
TYPE_FLOAT64 = JS_SIMDTYPEREPR_FLOAT64
};
static const type::Kind Kind = type::Simd;
@ -340,6 +341,7 @@ class SimdTypeDescr : public ComplexTypeDescr
static const Class class_;
static int32_t size(Type t);
static int32_t alignment(Type t);
static int32_t lanes(Type t);
SimdTypeDescr::Type type() const {
return (SimdTypeDescr::Type) getReservedSlot(JS_DESCR_SLOT_TYPE).toInt32();
@ -350,8 +352,9 @@ class SimdTypeDescr : public ComplexTypeDescr
};
#define JS_FOR_EACH_SIMD_TYPE_REPR(macro_) \
macro_(SimdTypeDescr::TYPE_INT32, int32_t, int32) \
macro_(SimdTypeDescr::TYPE_FLOAT32, float, float32)
macro_(SimdTypeDescr::TYPE_INT32, int32_t, int32, 4) \
macro_(SimdTypeDescr::TYPE_FLOAT32, float, float32, 4) \
macro_(SimdTypeDescr::TYPE_FLOAT64, double, float64, 2)
bool IsTypedObjectClass(const Class *clasp); // Defined below
bool IsTypedObjectArray(JSObject& obj);
@ -880,6 +883,14 @@ bool GetTypedObjectModule(JSContext *cx, unsigned argc, Value *vp);
*/
bool GetFloat32x4TypeDescr(JSContext *cx, unsigned argc, Value *vp);
/*
* Usage: GetFloat64x2TypeDescr()
*
* Returns the float64x2 type object. SIMD pseudo-module must have
* been initialized for this to be safe.
*/
bool GetFloat64x2TypeDescr(JSContext *cx, unsigned argc, Value *vp);
/*
* Usage: GetInt32x4TypeDescr()
*

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

@ -152,6 +152,11 @@ function TypedObjectGetSimd(descr, typedObj, offset) {
var w = Load_float32(typedObj, offset + 12);
return GetFloat32x4TypeDescr()(x, y, z, w);
case JS_SIMDTYPEREPR_FLOAT64:
var x = Load_float64(typedObj, offset + 0);
var y = Load_float64(typedObj, offset + 8);
return GetFloat64x2TypeDescr()(x, y);
case JS_SIMDTYPEREPR_INT32:
var x = Load_int32(typedObj, offset + 0);
var y = Load_int32(typedObj, offset + 4);
@ -322,6 +327,10 @@ function TypedObjectSetSimd(descr, typedObj, offset, fromValue) {
Store_float32(typedObj, offset + 8, Load_float32(fromValue, 8));
Store_float32(typedObj, offset + 12, Load_float32(fromValue, 12));
break;
case JS_SIMDTYPEREPR_FLOAT64:
Store_float64(typedObj, offset + 0, Load_float64(fromValue, 0));
Store_float64(typedObj, offset + 8, Load_float64(fromValue, 8));
break;
case JS_SIMDTYPEREPR_INT32:
Store_int32(typedObj, offset + 0, Load_int32(fromValue, 0));
Store_int32(typedObj, offset + 4, Load_int32(fromValue, 4));
@ -457,6 +466,21 @@ function SimdProtoString(type) {
return "int32x4";
case JS_SIMDTYPEREPR_FLOAT32:
return "float32x4";
case JS_SIMDTYPEREPR_FLOAT64:
return "float64x2";
}
assert(false, "Unhandled type constant");
return undefined;
}
function SimdTypeToLength(type) {
switch (type) {
case JS_SIMDTYPEREPR_INT32:
case JS_SIMDTYPEREPR_FLOAT32:
return 4;
case JS_SIMDTYPEREPR_FLOAT64:
return 2;
}
assert(false, "Unhandled type constant");
@ -473,7 +497,12 @@ function SimdToSource() {
ThrowError(JSMSG_INCOMPATIBLE_PROTO, "SIMD", "toSource", typeof this);
var type = DESCR_TYPE(descr);
return SimdProtoString(type)+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
var protoString = SimdProtoString(type);
var length = SimdTypeToLength(type);
if (length == 4)
return protoString+"("+this.x+", "+this.y+", "+this.z+", "+this.w+")";
else if (length == 2)
return protoString+"("+this.x+", "+this.y+")";
}
///////////////////////////////////////////////////////////////////////////

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

@ -32,8 +32,9 @@
#define JS_DESCR_SLOT_ARRAYPROTO 6 // Lazily created prototype for arrays
#define JS_DESCR_SLOT_TRACE_LIST 7 // List of references for use in tracing
// Slots on scalars, references, and x4s
// Slots on scalars, references, and SIMD objects
#define JS_DESCR_SLOT_TYPE 8 // Type code
#define JS_DESCR_SLOT_LANES 9
// Slots on array descriptors
#define JS_DESCR_SLOT_ARRAY_ELEM_TYPE 8
@ -85,5 +86,6 @@
// case.
#define JS_SIMDTYPEREPR_INT32 0
#define JS_SIMDTYPEREPR_FLOAT32 1
#define JS_SIMDTYPEREPR_FLOAT64 2
#endif

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

@ -1,14 +1,11 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 946042;
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
var float64x2 = SIMD.float64x2;
var summary = 'float32x4 clamp';
var summary = 'float32x4/float64x2 clamp';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
// FIXME -- Bug 1068028: Amend to check for correctness of NaN/-0 border cases once the semantics are defined.
var a = float32x4(-20, 10, 30, 0.5);
var lower = float32x4(2, 1, 50, 0);
@ -37,6 +34,24 @@ function test() {
assertEq(i.z, 10);
assertEq(i.w, -10);
var j = float64x2(-20, 10);
var k = float64x2(2.125, 3);
var lower3 = float64x2(2, 1);
var upper3 = float64x2(2.5, 5);
var l = float64x2.clamp(j, lower3, upper3);
assertEq(l.x, 2);
assertEq(l.y, 5);
var m = float64x2.clamp(k, lower3, upper3);
assertEq(m.x, 2.125);
assertEq(m.y, 3);
var n = float64x2(-5, 5);
var lower4 = float64x2(-Infinity, 0);
var upper4 = float64x2(+Infinity, +Infinity);
var p = float64x2.clamp(n, lower4, upper4);
assertEq(p.x, -5);
assertEq(p.y, 5);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -6,6 +6,7 @@
*/
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var fround = Math.fround;
@ -15,41 +16,60 @@ function boolToSimdLogical(b) {
}
function testEqualFloat32x4(v, w) {
testBinaryFunc(v, w, float32x4.equal, (x, y) => boolToSimdLogical(fround(x) == fround(y)));
testBinaryCompare(v, w, float32x4.equal, (x, y) => boolToSimdLogical(fround(x) == fround(y)));
}
function testNotEqualFloat32x4(v, w) {
testBinaryFunc(v, w, float32x4.notEqual, (x, y) => boolToSimdLogical(fround(x) != fround(y)));
testBinaryCompare(v, w, float32x4.notEqual, (x, y) => boolToSimdLogical(fround(x) != fround(y)));
}
function testLessThanFloat32x4(v, w) {
testBinaryFunc(v, w, float32x4.lessThan, (x, y) => boolToSimdLogical(fround(x) < fround(y)));
testBinaryCompare(v, w, float32x4.lessThan, (x, y) => boolToSimdLogical(fround(x) < fround(y)));
}
function testLessThanOrEqualFloat32x4(v, w) {
testBinaryFunc(v, w, float32x4.lessThanOrEqual, (x, y) => boolToSimdLogical(fround(x) <= fround(y)));
testBinaryCompare(v, w, float32x4.lessThanOrEqual, (x, y) => boolToSimdLogical(fround(x) <= fround(y)));
}
function testGreaterThanFloat32x4(v, w) {
testBinaryFunc(v, w, float32x4.greaterThan, (x, y) => boolToSimdLogical(fround(x) > fround(y)));
testBinaryCompare(v, w, float32x4.greaterThan, (x, y) => boolToSimdLogical(fround(x) > fround(y)));
}
function testGreaterThanOrEqualFloat32x4(v, w) {
testBinaryFunc(v, w, float32x4.greaterThanOrEqual, (x, y) => boolToSimdLogical(fround(x) >= fround(y)));
testBinaryCompare(v, w, float32x4.greaterThanOrEqual, (x, y) => boolToSimdLogical(fround(x) >= fround(y)));
}
function testEqualFloat64x2(v, w) {
testBinaryCompare(v, w, float64x2.equal, (x, y) => boolToSimdLogical(x == y));
}
function testNotEqualFloat64x2(v, w) {
testBinaryCompare(v, w, float64x2.notEqual, (x, y) => boolToSimdLogical(x != y));
}
function testLessThanFloat64x2(v, w) {
testBinaryCompare(v, w, float64x2.lessThan, (x, y) => boolToSimdLogical(x < y));
}
function testLessThanOrEqualFloat64x2(v, w) {
testBinaryCompare(v, w, float64x2.lessThanOrEqual, (x, y) => boolToSimdLogical(x <= y));
}
function testGreaterThanFloat64x2(v, w) {
testBinaryCompare(v, w, float64x2.greaterThan, (x, y) => boolToSimdLogical(x > y));
}
function testGreaterThanOrEqualFloat64x2(v, w) {
testBinaryCompare(v, w, float64x2.greaterThanOrEqual, (x, y) => boolToSimdLogical(x >= y));
}
function testEqualInt32x4(v, w) {
testBinaryFunc(v, w, int32x4.equal, (x, y) => boolToSimdLogical(x == y));
testBinaryCompare(v, w, int32x4.equal, (x, y) => boolToSimdLogical(x == y));
}
function testNotEqualInt32x4(v, w) {
testBinaryFunc(v, w, int32x4.notEqual, (x, y) => boolToSimdLogical(x != y));
testBinaryCompare(v, w, int32x4.notEqual, (x, y) => boolToSimdLogical(x != y));
}
function testLessThanInt32x4(v, w) {
testBinaryFunc(v, w, int32x4.lessThan, (x, y) => boolToSimdLogical(x < y));
testBinaryCompare(v, w, int32x4.lessThan, (x, y) => boolToSimdLogical(x < y));
}
function testLessThanOrEqualInt32x4(v, w) {
testBinaryFunc(v, w, int32x4.lessThanOrEqual, (x, y) => boolToSimdLogical(x <= y));
testBinaryCompare(v, w, int32x4.lessThanOrEqual, (x, y) => boolToSimdLogical(x <= y));
}
function testGreaterThanInt32x4(v, w) {
testBinaryFunc(v, w, int32x4.greaterThan, (x, y) => boolToSimdLogical(x > y));
testBinaryCompare(v, w, int32x4.greaterThan, (x, y) => boolToSimdLogical(x > y));
}
function testGreaterThanOrEqualInt32x4(v, w) {
testBinaryFunc(v, w, int32x4.greaterThanOrEqual, (x, y) => boolToSimdLogical(x >= y));
testBinaryCompare(v, w, int32x4.greaterThanOrEqual, (x, y) => boolToSimdLogical(x >= y));
}
function test() {
@ -75,6 +95,32 @@ function test() {
}
}
var float64x2val = [
float64x2(1, 20),
float64x2(10, 2),
float64x2(9.999, 2.1234),
float64x2(10, 2.1233),
float64x2(30.4443, 4),
float64x2(30.4444, 4.0001),
float64x2(NaN, -Infinity),
float64x2(+Infinity, NaN),
float64x2(+Infinity, -0),
float64x2(-0, -Infinity),
float64x2(13.37, 42.42),
float64x2(NaN, 0)
];
for (v of float64x2val) {
for (w of float64x2val) {
testEqualFloat64x2(v, w);
testNotEqualFloat64x2(v, w);
testLessThanFloat64x2(v, w);
testLessThanOrEqualFloat64x2(v, w);
testGreaterThanFloat64x2(v, w);
testGreaterThanOrEqualFloat64x2(v, w);
}
}
var int32x4val = [
int32x4(1, 2, 3, 4),
int32x4(-1, -2, -3, -4),

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

@ -1,54 +0,0 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 946042;
var float32x4 = SIMD.float32x4;
function testMaxFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.max, (x, y) => Math.fround(Math.max(x, y)));
}
function testMinFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.min, (x, y) => Math.fround(Math.min(x, y)));
}
function maxNum(x, y) {
if (x != x)
return y;
if (y != y)
return x;
return Math.max(x, y);
}
function minNum(x, y) {
if (x != x)
return y;
if (y != y)
return x;
return Math.min(x, y);
}
function testMaxNumFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.maxNum, maxNum);
}
function testMinNumFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.minNum, minNum);
}
function test() {
print(BUGNUMBER + ": " + summary);
for ([v, w] of [[float32x4(1, 20, 30, 4), float32x4(10, 2, 3, 40)],
[float32x4(9.999, 2.1234, 30.4443, 4), float32x4(10, 2.1233, 30.4444, 4.0001)],
[float32x4(NaN, -Infinity, +Infinity, -0), float32x4(13.37, 42.42, NaN, 0)]])
{
testMinFloat32(v, w);
testMaxFloat32(v, w);
testMinNumFloat32(v, w);
testMaxNumFloat32(v, w);
}
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,60 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
var summary = 'float32x4 fromFloat64x2';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = float64x2(1, 2);
var c = float32x4.fromFloat64x2(a);
assertEq(c.x, 1);
assertEq(c.y, 2);
assertEq(c.z, 0);
assertEq(c.w, 0);
var d = float64x2(-0, NaN);
var f = float32x4.fromFloat64x2(d);
assertEq(f.x, -0);
assertEq(f.y, NaN);
assertEq(f.z, 0);
assertEq(f.w, 0);
var g = float64x2(Infinity, -Infinity);
var i = float32x4.fromFloat64x2(g);
assertEq(i.x, Infinity);
assertEq(i.y, -Infinity);
assertEq(i.z, 0);
assertEq(i.w, 0);
var j = Math.pow(2, 25) - 1;
var k = -Math.pow(2, 25);
var l = float64x2(j, k);
var m = float32x4.fromFloat64x2(l);
assertEq(m.x, Math.fround(j));
assertEq(m.y, Math.fround(k));
assertEq(m.z, 0);
assertEq(m.w, 0);
var o = Math.pow(2, 1000);
var p = Math.pow(2, -1000);
var q = float64x2(o, p);
var r = float32x4.fromFloat64x2(q);
assertEq(r.x, Math.fround(o));
assertEq(r.y, Math.fround(p));
assertEq(r.z, 0);
assertEq(r.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,43 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'float32x4 fromFloat64x2Bits';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = float64x2(2.000000473111868, 512.0001225471497);
var b = float32x4.fromFloat64x2Bits(a);
assertEq(b.x, 1.0);
assertEq(b.y, 2.0);
assertEq(b.z, 3.0);
assertEq(b.w, 4.0);
var c = float64x2(-0, NaN);
var d = float32x4.fromFloat64x2Bits(c);
assertEq(d.x, 0);
assertEq(d.y, -0);
assertEq(d.z, 0);
assertEq(d.w, NaN);
var e = float64x2(Infinity, -Infinity);
var f = float32x4.fromFloat64x2Bits(e);
assertEq(f.x, 0);
assertEq(f.y, NaN);
assertEq(f.z, 0);
assertEq(f.w, NaN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,77 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var summary = 'float64x2 arithmetic';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function add(a, b) { return a + b; }
function sub(a, b) { return a - b; }
function mul(a, b) { return a * b; }
function div(a, b) { return a / b; }
function neg(a) { return -a; }
function reciprocal(a) { return 1 / a; }
function reciprocalSqrt(a) { return 1 / Math.sqrt(a); }
function testAdd(v, w) {
return testBinaryFunc(v, w, float64x2.add, add);
}
function testSub(v, w) {
return testBinaryFunc(v, w, float64x2.sub, sub);
}
function testMul(v, w) {
return testBinaryFunc(v, w, float64x2.mul, mul);
}
function testDiv(v, w) {
return testBinaryFunc(v, w, float64x2.div, div);
}
function testAbs(v) {
return testUnaryFunc(v, float64x2.abs, Math.abs);
}
function testNeg(v) {
return testUnaryFunc(v, float64x2.neg, neg);
}
function testReciprocal(v) {
return testUnaryFunc(v, float64x2.reciprocal, reciprocal);
}
function testReciprocalSqrt(v) {
return testUnaryFunc(v, float64x2.reciprocalSqrt, reciprocalSqrt);
}
function testSqrt(v) {
return testUnaryFunc(v, float64x2.sqrt, Math.sqrt);
}
function test() {
print(BUGNUMBER + ": " + summary);
var v, w;
for ([v, w] of [[float64x2(1, 2), float64x2(3, 4)],
[float64x2(1.894, 2.8909), float64x2(100.764, 200.987)],
[float64x2(-1, -2), float64x2(-14.54, 57)],
[float64x2(+Infinity, -Infinity), float64x2(NaN, -0)]])
{
testAdd(v, w);
testSub(v, w);
testMul(v, w);
testDiv(v, w);
testAbs(v);
testNeg(v);
testReciprocal(v);
testSqrt(v);
}
for (v of [float64x2(1, 0.25), float64x2(3, 0.5),
float64x2(-0, NaN), float64x2(+Infinity, -Infinity)])
{
testReciprocalSqrt(v);
}
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,30 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var summary = 'float64x2 alignment';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
var StructType = TypedObject.StructType;
var uint8 = TypedObject.uint8;
function test() {
print(BUGNUMBER + ": " + summary);
assertEq(float64x2.byteLength, 16);
assertEq(float64x2.byteAlignment, 16);
var Compound = new StructType({c: uint8, d: uint8, f: float64x2});
assertEq(Compound.fieldOffsets["c"], 0);
assertEq(Compound.fieldOffsets["d"], 1);
assertEq(Compound.fieldOffsets["f"], 16);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,41 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
var summary = 'float64x2 fromFloat32x4';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = float32x4(100, 200, 300, 400);
var c = float64x2.fromFloat32x4(a);
assertEq(c.x, 100);
assertEq(c.y, 200);
var d = float32x4(NaN, -0, NaN, -0);
var f = float64x2.fromFloat32x4(d);
assertEq(f.x, NaN);
assertEq(f.y, -0);
var g = float32x4(Infinity, -Infinity, Infinity, -Infinity);
var i = float64x2.fromFloat32x4(g);
assertEq(i.x, Infinity);
assertEq(i.y, -Infinity);
var j = float32x4(13.37, 12.853, 49.97, 53.124);
var l = float64x2.fromFloat32x4(j);
assertEq(l.x, Math.fround(13.37));
assertEq(l.y, Math.fround(12.853));
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,32 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'float64x2 fromFloat32x4Bits';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = float32x4(0, 1.875, 0, 2);
var c = float64x2.fromFloat32x4Bits(a);
assertEq(c.x, 1.0);
assertEq(c.y, 2.0);
var d = float32x4(NaN, -0, Infinity, -Infinity);
var f = float64x2.fromFloat32x4Bits(d);
assertEq(f.x, -1.058925634e-314);
assertEq(f.y, -1.404448428688076e+306);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,31 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'float64x2 fromInt32x4';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = int32x4(1, 2, 3, 4);
var c = float64x2.fromInt32x4(a);
assertEq(c.x, 1);
assertEq(c.y, 2);
var d = int32x4(INT32_MAX, INT32_MIN, 0, 0);
var f = float64x2.fromInt32x4(d);
assertEq(f.x, INT32_MAX);
assertEq(f.y, INT32_MIN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,31 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'float64x2 fromInt32x4Bits';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = int32x4(0x00000000, 0x3ff00000, 0x0000000, 0x40000000);
var c = float64x2.fromInt32x4Bits(a);
assertEq(c.x, 1.0);
assertEq(c.y, 2.0);
var d = int32x4(0xabcdef12, 0x3ff00000, 0x21fedcba, 0x40000000);
var f = float64x2.fromInt32x4Bits(d);
assertEq(f.x, 1.0000006400213732);
assertEq(f.y, 2.0000002532866263);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,47 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'float64x2 getters';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
// Create a float64x2 and check that the getters work:
var f = float64x2(11, 22);
assertEq(f.x, 11);
assertEq(f.y, 22);
// Test that the getters work when called reflectively:
var g = f.__lookupGetter__("x");
assertEq(g.call(f), 11);
// Test that getters cannot be applied to various incorrect things:
assertThrowsInstanceOf(function() {
g.call({})
}, TypeError, "Getter applicable to random objects");
assertThrowsInstanceOf(function() {
g.call(0xDEADBEEF)
}, TypeError, "Getter applicable to integers");
assertThrowsInstanceOf(function() {
var T = new TypedObject.StructType({x: TypedObject.float64,
y: TypedObject.float64});
var v = new T({x: 11, y: 22});
g.call(v)
}, TypeError, "Getter applicable to structs");
assertThrowsInstanceOf(function() {
var t = new int32x4(1, 2, 3, 4);
g.call(t)
}, TypeError, "Getter applicable to int32x4");
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,51 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'float64x2 handles';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
var ArrayType = TypedObject.ArrayType;
var float64 = TypedObject.float64;
var Handle = TypedObject.Handle;
function test() {
print(BUGNUMBER + ": " + summary);
var Array = float64x2.array(3);
var array = new Array([float64x2(1, 2),
float64x2(3, 4),
float64x2(5, 6)]);
// Test that trying to create handle into the interior of a
// float64x2 fails.
assertThrowsInstanceOf(function() {
var h = float64.handle(array, 1, "w");
}, TypeError, "Creating a float64 handle to prop via ctor");
assertThrowsInstanceOf(function() {
var h = float64.handle();
Handle.move(h, array, 1, "w");
}, TypeError, "Creating a float64 handle to prop via move");
assertThrowsInstanceOf(function() {
var h = float64.handle(array, 1, 0);
}, TypeError, "Creating a float64 handle to elem via ctor");
assertThrowsInstanceOf(function() {
var h = float64.handle();
Handle.move(h, array, 1, 0);
}, TypeError, "Creating a float64 handle to elem via move");
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,36 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var summary = 'float64x2 reify';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
var ArrayType = TypedObject.ArrayType;
function test() {
print(BUGNUMBER + ": " + summary);
var Array = float64x2.array(3);
var array = new Array([float64x2(1, 2),
float64x2(3, 4),
float64x2(5, 6)]);
// Test that reading array[1] produces a *copy* of float64x2, not an
// alias into the array.
var f = array[1];
assertEq(f.y, 4);
assertEq(array[1].y, 4);
array[1] = float64x2(7, 8);
assertEq(f.y, 4);
assertEq(array[1].y, 8);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,45 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var summary = 'float64x2 setter';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
var ArrayType = TypedObject.ArrayType;
function test() {
print(BUGNUMBER + ": " + summary);
var Array = float64x2.array(3);
var array = new Array([float64x2(1, 2),
float64x2(3, 4),
float64x2(5, 6)]);
assertEq(array[1].y, 4);
// Test that we are allowed to write float64x2 values into array,
// but not other things.
array[1] = float64x2(7, 8);
assertEq(array[1].y, 8);
assertThrowsInstanceOf(function() {
array[1] = {x: 7, y: 8 };
}, TypeError, "Setting float64x2 from an object");
assertThrowsInstanceOf(function() {
array[1] = [ 7, 8 ];
}, TypeError, "Setting float64x2 from an array");
assertThrowsInstanceOf(function() {
array[1] = 9;
}, TypeError, "Setting float64x2 from a number");
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,36 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var summary = 'float64x2 with';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = float64x2(1, 2);
var x = float64x2.withX(a, 5);
var y = float64x2.withY(a, 5);
assertEq(x.x, 5);
assertEq(x.y, 2);
assertEq(y.x, 1);
assertEq(y.y, 5);
var b = float64x2(NaN, -0);
var x1 = float64x2.withX(b, Infinity);
var y1 = float64x2.withY(b, -Infinity);
assertEq(x1.x, Infinity);
assertEq(x1.y, -0);
assertEq(y1.x, NaN);
assertEq(y1.y, -Infinity);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,51 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'int32x4 fromFloat64x2';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = float64x2(1, 2.2);
var c = int32x4.fromFloat64x2(a);
assertEq(c.x, 1);
assertEq(c.y, 2);
assertEq(c.z, 0);
assertEq(c.w, 0);
var d = float64x2(NaN, -0);
var f = int32x4.fromFloat64x2(d);
assertEq(f.x, 0);
assertEq(f.y, 0);
assertEq(f.z, 0);
assertEq(f.w, 0);
var g = float64x2(Infinity, -Infinity);
var i = int32x4.fromFloat64x2(g);
assertEq(i.x, 0);
assertEq(i.y, 0);
assertEq(i.z, 0);
assertEq(i.w, 0);
var j = Math.pow(2, 31);
var k = -Math.pow(2, 31) - 1;
var m = float64x2(j, k);
var l = int32x4.fromFloat64x2(m);
assertEq(l.x, INT32_MIN);
assertEq(l.y, INT32_MAX);
assertEq(l.z, 0);
assertEq(l.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -0,0 +1,49 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
var BUGNUMBER = 1031203;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
var summary = 'int32x4 fromFloat64x2Bits';
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
print(BUGNUMBER + ": " + summary);
var a = float64x2(1.0, 2.0);
var c = int32x4.fromFloat64x2Bits(a);
assertEq(c.x, 0x00000000);
assertEq(c.y, 0x3FF00000);
assertEq(c.z, 0x00000000);
assertEq(c.w, 0x40000000);
var d = float64x2(+Infinity, -Infinity);
var f = int32x4.fromFloat64x2Bits(d);
assertEq(f.x, 0x00000000);
assertEq(f.y, 0x7ff00000);
assertEq(f.z, 0x00000000);
assertEq(f.w, -0x100000);
var g = float64x2(-0, NaN);
var i = int32x4.fromFloat64x2Bits(g);
assertEq(i.x, 0x00000000);
assertEq(i.y, -0x80000000);
assertEq(i.z, 0x00000000);
assertEq(i.w, 0x7ff80000);
var j = float64x2(1.0000006400213732, 2.0000002532866263);
var l = int32x4.fromFloat64x2Bits(j);
assertEq(l.x, -0x543210ee);
assertEq(l.y, 0x3ff00000);
assertEq(l.z, 0x21fedcba);
assertEq(l.w, 0x40000000);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -5,11 +5,11 @@
* https://creativecommons.org/publicdomain/zero/1.0/
*/
// Our float32array will have 16 elements
const SIZE_ARRAY = 16;
// Our array for int32x4 and float32x4 will have 16 elements
const SIZE_32_ARRAY = 16;
const SIZE_64_ARRAY = 8;
// 1 float32 == 4 bytes
const SIZE_BYTES = SIZE_ARRAY * 4;
const SIZE_BYTES = SIZE_32_ARRAY * 4;
function MakeComparator(kind, arr) {
var bpe = arr.BYTES_PER_ELEMENT;
@ -28,10 +28,14 @@ function MakeComparator(kind, arr) {
sizeOfLaneElem = 4;
typedArrayCtor = Float32Array;
break;
case 'float64x2':
sizeOfLaneElem = 8;
typedArrayCtor = Float64Array;
break;
default:
assertEq(true, false, "unknown SIMD kind");
}
var lanes = 16 / sizeOfLaneElem;
// Reads (numElemToRead * sizeOfLaneElem) bytes in arr, and reinterprets
// these bytes as a typed array equivalent to the typed SIMD vector.
var slice = function(start, numElemToRead) {
@ -49,31 +53,38 @@ function MakeComparator(kind, arr) {
return new typedArrayCtor(new Uint8Array(asArray).buffer);
}
var assertFunc = (lanes == 2) ? assertEqX2 : assertEqX4;
var type = SIMD[kind];
return {
loadX: function(index) {
var v = SIMD[kind].loadX(arr, index);
assertEqX4(v, slice(index, 1));
var v = type.loadX(arr, index);
assertFunc(v, slice(index, 1));
},
loadXY: function(index) {
var v = SIMD[kind].loadXY(arr, index);
assertEqX4(v, slice(index, 2));
if (lanes < 4)
return;
var v = type.loadXY(arr, index);
assertFunc(v, slice(index, 2));
},
loadXYZ: function(index) {
var v = SIMD[kind].loadXYZ(arr, index);
assertEqX4(v, slice(index, 3));
loadXYZ: function(index) {
if (lanes < 4)
return;
var v = type.loadXYZ(arr, index);
assertFunc(v, slice(index, 3));
},
load: function(index) {
var v = SIMD[kind].load(arr, index);
assertEqX4(v, slice(index, 4));
var v = type.load(arr, index);
assertFunc(v, slice(index, 4));
}
}
}
function testLoad(kind, TA) {
for (var i = SIZE_ARRAY; i--;)
var lanes = TA.length / 4;
for (var i = TA.length; i--;)
TA[i] = i;
for (var ta of [
@ -97,7 +108,7 @@ function testLoad(kind, TA) {
var C = MakeComparator(kind, ta);
var bpe = ta.BYTES_PER_ELEMENT;
var lastValidArgLoadX = (SIZE_BYTES - 4) / bpe | 0;
var lastValidArgLoadX = (SIZE_BYTES - (lanes == 4 ? 4 : 8)) / bpe | 0;
var lastValidArgLoadXY = (SIZE_BYTES - 8) / bpe | 0;
var lastValidArgLoadXYZ = (SIZE_BYTES - 12) / bpe | 0;
var lastValidArgLoad = (SIZE_BYTES - 16) / bpe | 0;
@ -121,25 +132,30 @@ function testLoad(kind, TA) {
C.loadXY(2);
C.loadXY(3);
C.loadXY(lastValidArgLoadXY);
assertThrowsInstanceOf(() => SIMD[kind].loadXY(ta, lastValidArgLoadXY + 1), RangeError);
C.loadXYZ(0);
C.loadXYZ(1);
C.loadXYZ(2);
C.loadXYZ(3);
C.loadXYZ(lastValidArgLoadXYZ);
assertThrowsInstanceOf(() => SIMD[kind].loadXYZ(ta, lastValidArgLoadXYZ + 1), RangeError);
if (lanes >= 4) {
assertThrowsInstanceOf(() => SIMD[kind].loadXY(ta, lastValidArgLoadXY + 1), RangeError);
assertThrowsInstanceOf(() => SIMD[kind].loadXYZ(ta, lastValidArgLoadXYZ + 1), RangeError);
}
}
// Test ToInt32 behavior
var v = SIMD[kind].load(TA, 12.5);
assertEqX4(v, [12, 13, 14, 15]);
if (lanes == 4) {
// Test ToInt32 behavior
var v = SIMD[kind].load(TA, 12.5);
assertEqX4(v, [12, 13, 14, 15]);
var obj = {
valueOf: function() { return 12 }
var obj = {
valueOf: function() { return 12 }
}
var v = SIMD[kind].load(TA, obj);
assertEqX4(v, [12, 13, 14, 15]);
}
var v = SIMD[kind].load(TA, obj);
assertEqX4(v, [12, 13, 14, 15]);
var obj = {
valueOf: function() { throw new TypeError("i ain't a number"); }
@ -147,8 +163,9 @@ function testLoad(kind, TA) {
assertThrowsInstanceOf(() => SIMD[kind].load(TA, obj), TypeError);
}
testLoad('float32x4', new Float32Array(SIZE_ARRAY));
testLoad('int32x4', new Int32Array(SIZE_ARRAY));
testLoad('float32x4', new Float32Array(SIZE_32_ARRAY));
testLoad('float64x2', new Float64Array(SIZE_64_ARRAY));
testLoad('int32x4', new Int32Array(SIZE_32_ARRAY));
if (typeof reportCompare === "function")
reportCompare(true, true);

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

@ -0,0 +1,85 @@
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
/*
* Any copyright is dedicated to the Public Domain.
* https://creativecommons.org/publicdomain/zero/1.0/
*/
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
function testMaxFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.max, (x, y) => Math.fround(Math.max(x, y)), 4);
}
function testMinFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.min, (x, y) => Math.fround(Math.min(x, y)), 4);
}
function testMaxFloat64(v, w) {
return testBinaryFunc(v, w, float64x2.max, (x, y) => Math.max(x, y), 2);
}
function testMinFloat64(v, w) {
return testBinaryFunc(v, w, float64x2.min, (x, y) => Math.min(x, y), 2);
}
function maxNum(x, y) {
if (x != x)
return y;
if (y != y)
return x;
return Math.max(x, y);
}
function minNum(x, y) {
if (x != x)
return y;
if (y != y)
return x;
return Math.min(x, y);
}
function testMaxNumFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.maxNum, maxNum, 4);
}
function testMinNumFloat32(v, w) {
return testBinaryFunc(v, w, float32x4.minNum, minNum, 4);
}
function testMaxNumFloat64(v, w) {
return testBinaryFunc(v, w, float64x2.maxNum, maxNum, 2);
}
function testMinNumFloat64(v, w) {
return testBinaryFunc(v, w, float64x2.minNum, minNum, 2);
}
function test() {
var v, w;
for ([v, w] of [[float32x4(1, 20, 30, 4), float32x4(10, 2, 3, 40)],
[float32x4(9.999, 2.1234, 30.4443, 4), float32x4(10, 2.1233, 30.4444, 4.0001)],
[float32x4(NaN, -Infinity, +Infinity, -0), float32x4(13.37, 42.42, NaN, 0)]])
{
testMinFloat32(v, w);
testMaxFloat32(v, w);
testMinNumFloat32(v, w);
testMaxNumFloat32(v, w);
}
for ([v, w] of [[float64x2(1, 20), float64x2(10, 2)],
[float64x2(30, 4), float64x2(3, 40)],
[float64x2(9.999, 2.1234), float64x2(10, 2.1233)],
[float64x2(30.4443, 4), float64x2(30.4444, 4.0001)],
[float64x2(NaN, -Infinity), float64x2(13.37, 42.42)],
[float64x2(+Infinity, -0), float64x2(NaN, 0)]])
{
testMinFloat64(v, w);
testMaxFloat64(v, w);
testMinNumFloat64(v, w);
testMaxNumFloat64(v, w);
}
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -6,6 +6,7 @@
*/
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
function select(mask, ifTrue, ifFalse) {
@ -27,38 +28,38 @@ function testSelect(type, inputs) {
for (var i = 0; i < 16; i++) {
var mask = int32x4.bool(!!(i & 1), !!((i >> 1) & 1), !!((i >> 2) & 1), !!((i >> 3) & 1));
for ([x, y] of inputs)
assertEqX4(type.select(mask, x, y), select(mask, x, y));
assertEqVec(type.select(mask, x, y), select(mask, x, y));
}
}
function bitselect(ScalarTypedArray, mask, ifTrue, ifFalse) {
var m = simdToArray(mask);
var tv = new ScalarTypedArray(simdToArray(ifTrue));
var fv = new ScalarTypedArray(simdToArray(ifFalse));
tv = new Int32Array(tv.buffer);
fv = new Int32Array(fv.buffer);
var res = new Int32Array(4);
for (var i = 0; i < 4; i++) {
var t = 0;
for (var bit = 0; bit < 32; bit++) {
var readVal = (m[i] >> bit) & 1 ? tv[i] : fv[i];
var readBit = (readVal >> bit) & 1;
t |= readBit << bit;
}
res[i] = t;
function int32x4FromTypeBits(type, vec) {
switch (type) {
case float32x4:
return int32x4.fromFloat32x4Bits(vec);
case float64x2:
return int32x4.fromFloat64x2Bits(vec);
case int32x4:
return vec;
default:
throw new TypeError("Unknown SIMD type.");
}
}
res = new ScalarTypedArray(res.buffer);
return Array.prototype.map.call(res, x => x);
function bitselect(type, mask, ifTrue, ifFalse) {
var tv = int32x4FromTypeBits(type, ifTrue);
var fv = int32x4FromTypeBits(type, ifFalse);
var tr = int32x4.and(mask, tv);
var fr = int32x4.and(int32x4.not(mask), fv);
var orApplied = int32x4.or(tr, fr);
var converted = type == int32x4 ? orApplied : type.fromInt32x4Bits(orApplied);
return simdToArray(converted);
}
function findCorrespondingScalarTypedArray(type) {
switch (type) {
case int32x4: return Int32Array;
case float32x4: return Float32Array;
case float64x2: return Float64Array;
default: throw new Error("undefined scalar typed array");
}
}
@ -73,7 +74,7 @@ function testBitSelectSimple(type, inputs) {
for (var i = 0; i < 16; i++) {
var mask = int32x4.bool(!!(i & 1), !!((i >> 1) & 1), !!((i >> 2) & 1), !!((i >> 3) & 1));
for ([x, y] of inputs)
assertEqX4(type.bitselect(mask, x, y), bitselect(ScalarTypedArray, mask, x, y));
assertEqVec(type.bitselect(mask, x, y), bitselect(type, mask, x, y));
}
}
@ -91,7 +92,7 @@ function testBitSelectComplex(type, inputs) {
var ScalarTypedArray = findCorrespondingScalarTypedArray(type);
for (var mask of masks) {
for ([x, y] of inputs)
assertEqX4(type.bitselect(mask, x, y), bitselect(ScalarTypedArray, mask, x, y));
assertEqVec(type.bitselect(mask, x, y), bitselect(type, mask, x, y));
}
}
@ -115,6 +116,19 @@ function test() {
testBitSelectSimple(float32x4, inputs);
testBitSelectComplex(float32x4, inputs);
inputs = [
[float64x2(0.125,4.25), float64x2(9.75,16.125)],
[float64x2(1.5,2.75), float64x2(3.25,4.5)],
[float64x2(-1.5,-0), float64x2(NaN,-Infinity)],
[float64x2(1,-2), float64x2(13.37,3.13)],
[float64x2(1.5,2.75), float64x2(NaN,Infinity)],
[float64x2(-NaN,-Infinity), float64x2(9.75,16.125)]
];
testSelect(float64x2, inputs);
testBitSelectSimple(float64x2, inputs);
testBitSelectComplex(float64x2, inputs);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -1,3 +1,13 @@
function assertEqX2(v, arr) {
try {
assertEq(v.x, arr[0]);
assertEq(v.y, arr[1]);
} catch (e) {
print("stack trace:", e.stack);
throw e;
}
}
function assertEqX4(v, arr) {
try {
assertEq(v.x, arr[0]);
@ -10,14 +20,51 @@ function assertEqX4(v, arr) {
}
}
function simdLength(v) {
var pt = Object.getPrototypeOf(v);
if (pt === SIMD.int32x4.prototype || pt === SIMD.float32x4.prototype) {
return 4;
} else if (pt === SIMD.float64x2.prototype) {
return 2;
} else {
throw new TypeError("Unknown SIMD kind.");
}
}
function assertEqVec(v, arr) {
var lanes = simdLength(v);
if (lanes == 4)
assertEqX4(v, arr);
else if (lanes == 2)
assertEqX2(v, arr);
else
throw new TypeError("Unknown SIMD kind.");
}
function simdToArray(v) {
return [v.x, v.y, v.z, v.w];
var lanes = simdLength(v);
if (lanes == 4)
return [v.x, v.y, v.z, v.w];
else if (lanes == 2)
return [v.x, v.y];
else
throw new TypeError("Unknown SIMD kind.");
}
const INT32_MAX = Math.pow(2, 31) - 1;
const INT32_MIN = -Math.pow(2, 31);
assertEq(INT32_MAX + 1 | 0, INT32_MIN);
function testUnaryFunc(v, simdFunc, func) {
var varr = simdToArray(v);
var observed = simdToArray(simdFunc(v));
var expected = varr.map(function(v, i) { return func(varr[i]); });
for (var i = 0; i < observed.length; i++)
assertEq(observed[i], expected[i]);
}
function testBinaryFunc(v, w, simdFunc, func) {
var varr = simdToArray(v);
var warr = simdToArray(w);
@ -29,6 +76,19 @@ function testBinaryFunc(v, w, simdFunc, func) {
assertEq(observed[i], expected[i]);
}
function testBinaryCompare(v, w, simdFunc, func) {
var varr = simdToArray(v);
var warr = simdToArray(w);
var inLanes = simdLength(v);
var observed = simdToArray(simdFunc(v, w));
assertEq(observed.length, 4);
for (var i = 0; i < 4; i++) {
var j = ((i * inLanes) / 4) | 0;
assertEq(observed[i], func(varr[j], warr[j]));
}
}
function testBinaryScalarFunc(v, scalar, simdFunc, func) {
var varr = simdToArray(v);

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

@ -31,17 +31,19 @@ function testStore(ta, kind, i, v) {
SIMD[kind].storeX(ta, i, v);
assertChanged(ta, i, [v.x]);
reset(ta);
SIMD[kind].storeXY(ta, i, v);
assertChanged(ta, i, [v.x, v.y]);
reset(ta);
SIMD[kind].storeXYZ(ta, i, v);
assertChanged(ta, i, [v.x, v.y, v.z]);
reset(ta);
SIMD[kind].store(ta, i, v);
assertChanged(ta, i, [v.x, v.y, v.z, v.w]);
assertChanged(ta, i, simdToArray(v));
if (simdLength(v) > 2) {
reset(ta);
SIMD[kind].storeXY(ta, i, v);
assertChanged(ta, i, [v.x, v.y]);
reset(ta);
SIMD[kind].storeXYZ(ta, i, v);
assertChanged(ta, i, [v.x, v.y, v.z]);
}
}
function testStoreInt32x4() {
@ -78,8 +80,32 @@ function testStoreFloat32x4() {
assertThrowsInstanceOf(() => SIMD.int32x4.store(F32, 0, v), TypeError);
}
function testStoreFloat64x2() {
var F64 = new Float64Array(16);
var v = SIMD.float64x2(1, 2);
testStore(F64, 'float64x2', 0, v);
testStore(F64, 'float64x2', 1, v);
testStore(F64, 'float64x2', 14, v);
var v = SIMD.float64x2(NaN, -0);
testStore(F64, 'float64x2', 0, v);
testStore(F64, 'float64x2', 1, v);
testStore(F64, 'float64x2', 14, v);
var v = SIMD.float64x2(-Infinity, +Infinity);
testStore(F64, 'float64x2', 0, v);
testStore(F64, 'float64x2', 1, v);
testStore(F64, 'float64x2', 14, v);
assertThrowsInstanceOf(() => SIMD.float64x2.store(F64), TypeError);
assertThrowsInstanceOf(() => SIMD.float64x2.store(F64, 0), TypeError);
assertThrowsInstanceOf(() => SIMD.float32x4.store(F64, 0, v), TypeError);
}
testStoreInt32x4();
testStoreFloat32x4();
testStoreFloat64x2();
if (typeof reportCompare === "function")
reportCompare(true, true);

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

@ -6,28 +6,61 @@
*/
var float32x4 = SIMD.float32x4;
var float64x2 = SIMD.float64x2;
var int32x4 = SIMD.int32x4;
function swizzle(arr, x, y, z, w) {
function swizzle2(arr, x, y) {
return [arr[x], arr[y]];
}
function swizzle4(arr, x, y, z, w) {
return [arr[x], arr[y], arr[z], arr[w]];
}
function getNumberOfLanesFromType(type) {
switch (type) {
case float32x4:
case int32x4:
return 4;
case float64x2:
return 2;
}
throw new TypeError("Unknown SIMD type.");
}
function testSwizzleForType(type) {
var v = type(1,2,3,4);
var lanes = getNumberOfLanesFromType(type);
var v = lanes == 4 ? type(1, 2, 3, 4) : type(1, 2);
assertThrowsInstanceOf(() => type.swizzle() , TypeError);
assertThrowsInstanceOf(() => type.swizzle(v, 0) , TypeError);
assertThrowsInstanceOf(() => type.swizzle(v, 0, 1) , TypeError);
assertThrowsInstanceOf(() => type.swizzle(v, 0, 1, 2) , TypeError);
assertThrowsInstanceOf(() => type.swizzle(v, 0, 1, 2, 4) , TypeError);
assertThrowsInstanceOf(() => type.swizzle(v, 0, 1, 2, -1) , TypeError);
assertThrowsInstanceOf(() => type.swizzle(0, 1, 2, 3, v) , TypeError);
if (lanes == 2) {
assertThrowsInstanceOf(() => type.swizzle(v, 0, -1) , TypeError);
assertThrowsInstanceOf(() => type.swizzle(v, 0, 2) , TypeError);
} else {
assertEq(lanes, 4);
assertThrowsInstanceOf(() => type.swizzle(v, 0, 1), TypeError);
}
// Test all possible swizzles.
var x, y, z, w;
for (var i = 0; i < Math.pow(4, 4); i++) {
[x, y, z, w] = [i & 3, (i >> 2) & 3, (i >> 4) & 3, (i >> 6) & 3];
assertEqX4(type.swizzle(v, x, y, z, w), swizzle(simdToArray(v), x, y, z, w));
if (lanes == 4) {
var x, y, z, w;
for (var i = 0; i < Math.pow(4, 4); i++) {
[x, y, z, w] = [i & 3, (i >> 2) & 3, (i >> 4) & 3, (i >> 6) & 3];
assertEqVec(type.swizzle(v, x, y, z, w), swizzle4(simdToArray(v), x, y, z, w));
}
} else {
assertEq(lanes, 2);
var x, y;
for (var i = 0; i < Math.pow(2, 2); i++) {
[x, y] = [x & 1, (y >> 1) & 1];
assertEqVec(type.swizzle(v, x, y), swizzle2(simdToArray(v), x, y));
}
}
// Test that the lane inputs are converted into an int32.
@ -36,7 +69,12 @@ function testSwizzleForType(type) {
x: 0,
valueOf: function() { return this.x++ }
};
assertEqX4(type.swizzle(v, obj, obj, obj, obj), swizzle(simdToArray(v), 0, 1, 2, 3));
if (lanes == 4) {
assertEqVec(type.swizzle(v, obj, obj, obj, obj), swizzle4(simdToArray(v), 0, 1, 2, 3));
} else {
assertEq(lanes, 2);
assertEqVec(type.swizzle(v, obj, obj), swizzle2(simdToArray(v), 0, 1));
}
// Object for which ToInt32 will fail.
obj = {
@ -65,7 +103,21 @@ function testSwizzleFloat32x4() {
testSwizzleForType(float32x4);
}
function shuffle(lhsa, rhsa, x, y, z, w) {
function testSwizzleFloat64x2() {
var v = float64x2(1, 2);
assertThrowsInstanceOf(function() {
float32x4.swizzle(v, 0, 0, 0, 0);
}, TypeError);
testSwizzleForType(float64x2);
}
function shuffle2(lhsa, rhsa, x, y) {
return [(x < 2 ? lhsa : rhsa)[x % 2],
(y < 2 ? lhsa : rhsa)[y % 2]];
}
function shuffle4(lhsa, rhsa, x, y, z, w) {
return [(x < 4 ? lhsa : rhsa)[x % 4],
(y < 4 ? lhsa : rhsa)[y % 4],
(z < 4 ? lhsa : rhsa)[z % 4],
@ -73,24 +125,50 @@ function shuffle(lhsa, rhsa, x, y, z, w) {
}
function testShuffleForType(type) {
var lhs = type(1,2,3,4);
var rhs = type(5,6,7,8);
var lanes = getNumberOfLanesFromType(type);
var lhs, rhs;
if (lanes == 4) {
lhs = type(1, 2, 3, 4);
rhs = type(5, 6, 7, 8);
} else {
assertEq(lanes, 2);
lhs = type(1, 2);
rhs = type(3, 4);
}
assertThrowsInstanceOf(() => type.shuffle(lhs) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0, 1) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0, 1, 2) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0, 1, 2, -1) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0, 1, 2, 8) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, 0, 1, 2, 7, rhs) , TypeError);
if (lanes == 2) {
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0, 4) , TypeError);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0, -1) , TypeError);
} else {
assertEq(lanes, 4);
assertThrowsInstanceOf(() => type.shuffle(lhs, rhs, 0, 1) , TypeError);
}
// Test all possible shuffles.
var x, y, z, w;
for (var i = 0; i < Math.pow(8, 4); i++) {
[x, y, z, w] = [i & 7, (i >> 3) & 7, (i >> 6) & 7, (i >> 9) & 7];
assertEqX4(type.shuffle(lhs, rhs, x, y, z, w),
shuffle(simdToArray(lhs), simdToArray(rhs), x, y, z, w));
if (lanes == 4) {
var x, y, z, w;
for (var i = 0; i < Math.pow(8, 4); i++) {
[x, y, z, w] = [i & 7, (i >> 3) & 7, (i >> 6) & 7, (i >> 9) & 7];
assertEqVec(type.shuffle(lhs, rhs, x, y, z, w),
shuffle4(simdToArray(lhs), simdToArray(rhs), x, y, z, w));
}
} else {
assertEq(lanes, 2);
var x, y;
for (var i = 0; i < Math.pow(4, 2); i++) {
[x, y] = [i & 3, (i >> 3) & 3];
assertEqVec(type.shuffle(lhs, rhs, x, y),
shuffle2(simdToArray(lhs), simdToArray(rhs), x, y));
}
}
// Test that the lane inputs are converted into an int32.
@ -99,8 +177,14 @@ function testShuffleForType(type) {
x: 0,
valueOf: function() { return this.x++ }
};
assertEqX4(type.shuffle(lhs, rhs, obj, obj, obj, obj),
shuffle(simdToArray(lhs),simdToArray(rhs), 0, 1, 2, 3));
if (lanes == 4) {
assertEqVec(type.shuffle(lhs, rhs, obj, obj, obj, obj),
shuffle4(simdToArray(lhs), simdToArray(rhs), 0, 1, 2, 3));
} else {
assertEq(lanes, 2);
assertEqVec(type.shuffle(lhs, rhs, obj, obj),
shuffle2(simdToArray(lhs), simdToArray(rhs), 0, 1));
}
// Object for which ToInt32 will fail.
obj = {
@ -129,10 +213,22 @@ function testShuffleFloat32x4() {
testShuffleForType(float32x4);
}
function testShuffleFloat64x2() {
var v = float64x2(1, 2);
assertThrowsInstanceOf(function() {
float32x4.shuffle(v, v, 0, 0, 0, 0);
}, TypeError);
testShuffleForType(float64x2);
}
testSwizzleInt32x4();
testSwizzleFloat32x4();
testSwizzleFloat64x2();
testShuffleInt32x4();
testShuffleFloat32x4();
testShuffleFloat64x2();
if (typeof reportCompare === "function")
reportCompare(true, true);

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

@ -79,6 +79,7 @@
macro(float32, float32, "float32") \
macro(float32x4, float32x4, "float32x4") \
macro(float64, float64, "float64") \
macro(float64x2, float64x2, "float64x2") \
macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
macro(format, format, "format") \
macro(frame, frame, "frame") \

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

@ -104,8 +104,9 @@ class GlobalObject : public NativeObject
static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_PROTO_SETTING_SLOW + 1;
static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1;
static const unsigned INTRINSICS = DEBUGGERS + 1;
static const unsigned FLOAT32X4_TYPE_DESCR = INTRINSICS + 1;
static const unsigned INT32X4_TYPE_DESCR = FLOAT32X4_TYPE_DESCR + 1;
static const unsigned FLOAT32X4_TYPE_DESCR = INTRINSICS + 1;
static const unsigned FLOAT64X2_TYPE_DESCR = FLOAT32X4_TYPE_DESCR + 1;
static const unsigned INT32X4_TYPE_DESCR = FLOAT64X2_TYPE_DESCR + 1;
static const unsigned FOR_OF_PIC_CHAIN = INT32X4_TYPE_DESCR + 1;
/* Total reserved-slot count for global objects. */
@ -408,6 +409,16 @@ class GlobalObject : public NativeObject
return getSlotRef(FLOAT32X4_TYPE_DESCR).toObject();
}
void setFloat64x2TypeDescr(JSObject &obj) {
MOZ_ASSERT(getSlotRef(FLOAT64X2_TYPE_DESCR).isUndefined());
setSlot(FLOAT64X2_TYPE_DESCR, ObjectValue(obj));
}
JSObject &float64x2TypeDescr() {
MOZ_ASSERT(getSlotRef(FLOAT64X2_TYPE_DESCR).isObject());
return getSlotRef(FLOAT64X2_TYPE_DESCR).toObject();
}
void setInt32x4TypeDescr(JSObject &obj) {
MOZ_ASSERT(getSlotRef(INT32X4_TYPE_DESCR).isUndefined());
setSlot(INT32X4_TYPE_DESCR, ObjectValue(obj));

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

@ -969,6 +969,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("ClampToUint8", js::ClampToUint8, 1, 0),
JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0),
JS_FN("GetFloat32x4TypeDescr", js::GetFloat32x4TypeDescr, 0, 0),
JS_FN("GetFloat64x2TypeDescr", js::GetFloat64x2TypeDescr, 0, 0),
JS_FN("GetInt32x4TypeDescr", js::GetInt32x4TypeDescr, 0, 0),
#define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name) \

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

@ -584,18 +584,30 @@ SelectionCarets::SelectWord()
nsPoint ptInFrame = mDownPoint;
nsLayoutUtils::TransformPoint(rootFrame, ptFrame, ptInFrame);
// If target frame is editable, we should move focus to targe frame. If
// target frame isn't editable and our focus content is editable, we should
nsIFrame* currFrame = ptFrame;
nsIContent* newFocusContent = nullptr;
while (currFrame) {
int32_t tabIndexUnused = 0;
if (currFrame->IsFocusable(&tabIndexUnused, true)) {
newFocusContent = currFrame->GetContent();
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocusContent));
if (domElement)
break;
}
currFrame = currFrame->GetParent();
}
// If target frame is focusable, we should move focus to it. If target frame
// isn't focusable, and our previous focused content is editable, we should
// clear focus.
nsFocusManager* fm = nsFocusManager::GetFocusManager();
nsIContent* editingHost = ptFrame->GetContent()->GetEditingHost();
if (editingHost) {
nsCOMPtr<nsIDOMElement> elt = do_QueryInterface(editingHost->GetParent());
if (elt) {
fm->SetFocus(elt, 0);
}
if (newFocusContent && currFrame) {
nsCOMPtr<nsIDOMElement> domElement(do_QueryInterface(newFocusContent));
fm->SetFocus(domElement,0);
if (!nsContentUtils::HasNonEmptyTextContent(
if (editingHost && !nsContentUtils::HasNonEmptyTextContent(
editingHost, nsContentUtils::eRecurseIntoChildren)) {
SELECTIONCARETS_LOG("Select a editable content %p with empty text",
editingHost);

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

@ -39,17 +39,32 @@ class SelectionCaretsTest(MarionetteTestCase):
self._contenteditable = self.marionette.find_element(*self._contenteditable_selector)
self._content = self.marionette.find_element(*self._content_selector)
def _long_press_to_select_first_word(self, el, sel):
# Move caret inside the first word.
def _first_word_location(self, el):
'''Get the location (x, y) of the first word in el.
Note: this function has a side effect which changes focus to the
target element el.
'''
sel = SelectionManager(el)
# Move caret behind the first character to get the location of the first
# word.
el.tap()
sel.move_caret_to_front()
sel.move_caret_by_offset(1)
x, y = sel.caret_location()
# Long press the caret position. Selection carets should appear, and the
# first word will be selected. On Windows, those spaces after the word
# will also be selected.
long_press_without_contextmenu(self.marionette, el, self._long_press_time, x, y)
return sel.caret_location()
def _long_press_to_select(self, el, x, y):
'''Long press the location (x, y) to select a word.
SelectionCarets should appear. On Windows, those spaces after the
word will also be selected.
'''
long_press_without_contextmenu(self.marionette, el, self._long_press_time,
x, y)
def _test_long_press_to_select_a_word(self, el, assertFunc):
sel = SelectionManager(el)
@ -59,7 +74,8 @@ class SelectionCaretsTest(MarionetteTestCase):
target_content = words[0]
# Goal: Select the first word.
self._long_press_to_select_first_word(el, sel)
x, y = self._first_word_location(el)
self._long_press_to_select(el, x, y)
# Ignore extra spaces selected after the word.
assertFunc(target_content, sel.selected_content.rstrip())
@ -79,7 +95,8 @@ class SelectionCaretsTest(MarionetteTestCase):
sel.select_all()
(_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()
self._long_press_to_select_first_word(el, sel)
x, y = self._first_word_location(el)
self._long_press_to_select(el, x, y)
# Move the right caret to the end of the content.
(caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
@ -91,7 +108,8 @@ class SelectionCaretsTest(MarionetteTestCase):
# Ignore extra spaces at the beginning of the content in comparison.
assertFunc(target_content.lstrip(), sel.selected_content.lstrip())
def _test_minimum_select_one_character(self, el, assertFunc):
def _test_minimum_select_one_character(self, el, assertFunc,
x=None, y=None):
sel = SelectionManager(el)
original_content = sel.content
words = original_content.split()
@ -100,7 +118,13 @@ class SelectionCaretsTest(MarionetteTestCase):
# Goal: Select the first character.
target_content = original_content[0]
self._long_press_to_select_first_word(el, sel)
if x and y:
# If we got x and y from the arguments, use it as a hint of the
# location of the first word
pass
else:
x, y = self._first_word_location(el)
self._long_press_to_select(el, x, y)
# Move the right caret to the position of the left caret.
(caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
@ -108,6 +132,24 @@ class SelectionCaretsTest(MarionetteTestCase):
assertFunc(target_content, sel.selected_content)
def _test_focus_obtained_by_long_press(self, el1, el2):
'''Test the focus could be changed from el1 to el2 by long press.
If the focus is changed to e2 successfully, SelectionCarets should
appear and could be dragged.
'''
# Goal: Tap to focus el1, and then select the first character on
# el2.
# We want to collect the location of the first word in el2 here
# since self._first_word_location() has the side effect which would
# change the focus.
x, y = self._first_word_location(el2)
el1.tap()
self._test_minimum_select_one_character(el2, self.assertEqual,
x=x, y=y)
########################################################################
# <input> test cases with selection carets enabled
########################################################################
@ -123,6 +165,18 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_minimum_select_one_character(self._input, self.assertEqual)
def test_input_focus_obtained_by_long_press_from_textarea(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._textarea, self._input)
def test_input_focus_obtained_by_long_press_from_contenteditable(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._contenteditable, self._input)
def test_input_focus_obtained_by_long_press_from_content_non_editable(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._content, self._input)
########################################################################
# <input> test cases with selection carets disabled
########################################################################
@ -149,6 +203,18 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_minimum_select_one_character(self._textarea, self.assertEqual)
def test_textarea_focus_obtained_by_long_press_from_input(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._input, self._textarea)
def test_textarea_focus_obtained_by_long_press_from_contenteditable(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._contenteditable, self._textarea)
def test_textarea_focus_obtained_by_long_press_from_content_non_editable(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._content, self._textarea)
########################################################################
# <textarea> test cases with selection carets disabled
########################################################################
@ -201,6 +267,18 @@ class SelectionCaretsTest(MarionetteTestCase):
self.openTestHtml(enabled=True)
self._test_minimum_select_one_character(self._contenteditable, self.assertEqual)
def test_contenteditable_focus_obtained_by_long_press_from_input(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._input, self._contenteditable)
def test_contenteditable_focus_obtained_by_long_press_from_textarea(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._textarea, self._contenteditable)
def test_contenteditable_focus_obtained_by_long_press_from_content_non_editable(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._content, self._contenteditable)
########################################################################
# <div> contenteditable test cases with selection carets disabled
########################################################################
@ -218,3 +296,16 @@ class SelectionCaretsTest(MarionetteTestCase):
def test_content_non_editable_minimum_select_one_character_by_selection(self):
self.openTestHtml(enabled=True)
self._test_minimum_select_one_character(self._content, self.assertEqual)
def test_content_non_editable_focus_obtained_by_long_press_from_input(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._input, self._content)
def test_content_non_editable_focus_obtained_by_long_press_from_textarea(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._textarea, self._content)
def test_content_non_editable_focus_obtained_by_long_press_from_contenteditable(self):
self.openTestHtml(enabled=True)
self._test_focus_obtained_by_long_press(self._contenteditable, self._content)

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

@ -2925,8 +2925,24 @@ nsCSSRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext)
UniquePtr<nsMediaQueryResultCacheKey>
nsCSSRuleProcessor::CloneMQCacheKey()
{
MOZ_ASSERT(!(mRuleCascades && mPreviousCacheKey));
RuleCascadeData* c = mRuleCascades;
if (!c || !c->mCacheKey.HasFeatureConditions()) {
if (!c) {
// We might have an mPreviousCacheKey. It already comes from a call
// to CloneMQCacheKey, so don't bother checking
// HasFeatureConditions().
if (mPreviousCacheKey) {
NS_ASSERTION(mPreviousCacheKey->HasFeatureConditions(),
"we shouldn't have a previous cache key unless it has "
"feature conditions");
return MakeUnique<nsMediaQueryResultCacheKey>(*mPreviousCacheKey);
}
return UniquePtr<nsMediaQueryResultCacheKey>();
}
if (!c->mCacheKey.HasFeatureConditions()) {
return UniquePtr<nsMediaQueryResultCacheKey>();
}

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

@ -24,6 +24,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1089417
is(fwin.getComputedStyle(fdoc.documentElement).backgroundColor,
"rgb(0, 128, 0)",
"media query change should have restyled");
f.height = "200";
fdoc.getElementById("s").disabled = true;
fdoc.getElementById("s").disabled = false;
is(fwin.getComputedStyle(fdoc.documentElement).backgroundColor,
"rgb(255, 0, 0)",
"media query change should have restyled");
SimpleTest.finish();
}

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

@ -3752,13 +3752,20 @@ pref("browser.zoom.reflowZoom.reflowTimeout", 500);
*/
pref("browser.zoom.reflowZoom.reflowTextOnPageLoad", true);
//
// Image-related prefs
//
// The maximum size, in bytes, of the decoded images we cache
pref("image.cache.size", 5242880);
// A weight, from 0-1000, to place on time when comparing to size.
// Size is given a weight of 1000 - timeweight.
pref("image.cache.timeweight", 500);
// Whether we attempt to downscale images during decoding.
pref("image.downscale-during-decode.enabled", false);
// The default Accept header sent for images loaded over HTTP(S)
pref("image.http.accept", "image/png,image/*;q=0.8,*/*;q=0.5");

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

@ -1365,6 +1365,15 @@ HttpBaseChannel::IsNoCacheResponse(bool *value)
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::IsPrivateResponse(bool *value)
{
if (!mResponseHead)
return NS_ERROR_NOT_AVAILABLE;
*value = mResponseHead->Private();
return NS_OK;
}
NS_IMETHODIMP
HttpBaseChannel::GetResponseStatus(uint32_t *aValue)
{

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

@ -153,6 +153,7 @@ public:
NS_IMETHOD SetRedirectionLimit(uint32_t value) MOZ_OVERRIDE;
NS_IMETHOD IsNoStoreResponse(bool *value) MOZ_OVERRIDE;
NS_IMETHOD IsNoCacheResponse(bool *value) MOZ_OVERRIDE;
NS_IMETHOD IsPrivateResponse(bool *value) MOZ_OVERRIDE;
NS_IMETHOD GetResponseStatus(uint32_t *aValue) MOZ_OVERRIDE;
NS_IMETHOD GetResponseStatusText(nsACString& aValue) MOZ_OVERRIDE;
NS_IMETHOD GetRequestSucceeded(bool *aValue) MOZ_OVERRIDE;

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

@ -193,6 +193,12 @@ NullHttpChannel::IsNoCacheResponse(bool *_retval)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::IsPrivateResponse(bool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
NullHttpChannel::RedirectTo(nsIURI *aNewURI)
{

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

@ -145,6 +145,7 @@ struct ParamTraits<mozilla::net::nsHttpResponseHead>
WriteParam(aMsg, aParam.mContentLength);
WriteParam(aMsg, aParam.mContentType);
WriteParam(aMsg, aParam.mContentCharset);
WriteParam(aMsg, aParam.mCacheControlPrivate);
WriteParam(aMsg, aParam.mCacheControlNoStore);
WriteParam(aMsg, aParam.mCacheControlNoCache);
WriteParam(aMsg, aParam.mPragmaNoCache);
@ -159,6 +160,7 @@ struct ParamTraits<mozilla::net::nsHttpResponseHead>
!ReadParam(aMsg, aIter, &aResult->mContentLength) ||
!ReadParam(aMsg, aIter, &aResult->mContentType) ||
!ReadParam(aMsg, aIter, &aResult->mContentCharset) ||
!ReadParam(aMsg, aIter, &aResult->mCacheControlPrivate) ||
!ReadParam(aMsg, aIter, &aResult->mCacheControlNoStore) ||
!ReadParam(aMsg, aIter, &aResult->mCacheControlNoCache) ||
!ReadParam(aMsg, aIter, &aResult->mPragmaNoCache))

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

@ -624,6 +624,7 @@ nsHttpResponseHead::Reset()
mVersion = NS_HTTP_VERSION_1_1;
mStatus = 200;
mContentLength = UINT64_MAX;
mCacheControlPrivate = false;
mCacheControlNoStore = false;
mCacheControlNoCache = false;
mPragmaNoCache = false;
@ -792,11 +793,16 @@ nsHttpResponseHead::ParseCacheControl(const char *val)
{
if (!(val && *val)) {
// clear flags
mCacheControlPrivate = false;
mCacheControlNoCache = false;
mCacheControlNoStore = false;
return;
}
// search header value for occurrence of "private"
if (nsHttp::FindToken(val, "private", HTTP_HEADER_VALUE_SEPS))
mCacheControlPrivate = true;
// search header value for occurrence(s) of "no-cache" but ignore
// occurrence(s) of "no-cache=blah"
if (nsHttp::FindToken(val, "no-cache", HTTP_HEADER_VALUE_SEPS))

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

@ -23,6 +23,7 @@ public:
nsHttpResponseHead() : mVersion(NS_HTTP_VERSION_1_1)
, mStatus(200)
, mContentLength(UINT64_MAX)
, mCacheControlPrivate(false)
, mCacheControlNoStore(false)
, mCacheControlNoCache(false)
, mPragmaNoCache(false) {}
@ -37,6 +38,7 @@ public:
int64_t ContentLength() const { return mContentLength; }
const nsAFlatCString &ContentType() const { return mContentType; }
const nsAFlatCString &ContentCharset() const { return mContentCharset; }
bool Private() const { return mCacheControlPrivate; }
bool NoStore() const { return mCacheControlNoStore; }
bool NoCache() const { return (mCacheControlNoCache || mPragmaNoCache); }
/**
@ -128,6 +130,7 @@ private:
int64_t mContentLength;
nsCString mContentType;
nsCString mContentCharset;
bool mCacheControlPrivate;
bool mCacheControlNoStore;
bool mCacheControlNoCache;
bool mPragmaNoCache;

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

@ -14,7 +14,7 @@ interface nsIHttpHeaderVisitor;
* the inspection of the resulting HTTP response status and headers when they
* become available.
*/
[scriptable, uuid(82083578-fb78-4f9a-953c-cecbae500697)]
[scriptable, uuid(a8bed710-653c-4ea4-9747-a629cc482cf8)]
interface nsIHttpChannel : nsIChannel
{
/**************************************************************************
@ -299,6 +299,15 @@ interface nsIHttpChannel : nsIChannel
*/
boolean isNoCacheResponse();
/**
* Returns true if the server sent a "Cache-Control: private" response
* header.
*
* @throws NS_ERROR_NOT_AVAILABLE if called before the response
* has been received (before onStartRequest).
*/
boolean isPrivateResponse();
/**
* Instructs the channel to immediately redirect to a new destination.
* Can only be called on channels not yet opened.

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

@ -768,6 +768,13 @@ nsViewSourceChannel::IsNoCacheResponse(bool *_retval)
mHttpChannel->IsNoCacheResponse(_retval);
}
NS_IMETHODIMP
nsViewSourceChannel::IsPrivateResponse(bool *_retval)
{
return !mHttpChannel ? NS_ERROR_NULL_POINTER :
mHttpChannel->IsPrivateResponse(_retval);
}
NS_IMETHODIMP
nsViewSourceChannel::RedirectTo(nsIURI *uri)
{

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

@ -171,7 +171,7 @@ int main(int argc, char **argv)
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER);
RETURN_IF_FAILED(rv, "NS_OpenURI");
RETURN_IF_FAILED(rv, "NS_NewChannel");
rv = chan->AsyncOpen(listener, nullptr);
RETURN_IF_FAILED(rv, "AsyncOpen");

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

@ -1,398 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TestCommon.h"
#include "nsNetUtil.h"
#include "nsIServiceManager.h"
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIProgressEventSink.h"
#include "nsIComponentManager.h"
#include "prprf.h"
#include "nsXPCOM.h"
#include "nsISupportsPrimitives.h"
#include "plstr.h"
#include "nsCOMArray.h"
#include "nsIComponentRegistrar.h"
#include <algorithm>
#include "nsIScriptSecurityManager.h"
namespace TestPageLoad {
int getStrLine(const char *src, char *str, int ind, int max);
nsresult auxLoad(char *uriBuf);
//----------------------------------------------------------------------
#define RETURN_IF_FAILED(rv, ret, step) \
PR_BEGIN_MACRO \
if (NS_FAILED(rv)) { \
printf(">>> %s failed: rv=%x\n", step, static_cast<uint32_t>(rv)); \
return ret;\
} \
PR_END_MACRO
static nsCString globalStream;
//static char urlBuf[256];
static nsCOMPtr<nsIURI> baseURI;
static nsCOMArray<nsIURI> uriList;
//Temp, should remove:
static int numStart=0;
static int numFound=0;
static int32_t gKeepRunning = 0;
//--------writer fun----------------------
static NS_METHOD streamParse (nsIInputStream* in,
void* closure,
const char* fromRawSegment,
uint32_t toOffset,
uint32_t count,
uint32_t *writeCount) {
char parseBuf[2048], loc[2048], lineBuf[2048];
char *loc_t, *loc_t2;
int i = 0;
const char *tmp;
if(!globalStream.IsEmpty()) {
globalStream.Append(fromRawSegment);
tmp = globalStream.get();
//printf("\n>>NOW:\n^^^^^\n%s\n^^^^^^^^^^^^^^", tmp);
} else {
tmp = fromRawSegment;
}
while(i < (int)count) {
i = getStrLine(tmp, lineBuf, i, count);
if(i < 0) {
*writeCount = count;
return NS_OK;
}
parseBuf[0]='\0';
if((loc_t=PL_strcasestr(lineBuf, "img"))!= nullptr
|| (loc_t=PL_strcasestr(lineBuf, "script"))!=nullptr) {
loc_t2=PL_strcasestr(loc_t, "src");
if(loc_t2!=nullptr) {
loc_t2+=3;
strcpy(loc, loc_t2);
sscanf(loc, "=\"%[^\"]", parseBuf);
if(parseBuf[0]=='\0')
sscanf(loc, "=%s", parseBuf);
if(parseBuf[0]!='\0'){
numFound++;
auxLoad(parseBuf);
}
}
}
/***NEED BETTER CHECK FOR STYLESHEETS
if((loc_t=PL_strcasestr(lineBuf, "link"))!= nullptr) {
loc_t2=PL_strcasestr(loc_t, "href");
if(loc_t2!=nullptr) {
loc_t2+=4;
strcpy(loc, loc_t2);
//printf("%s\n", loc);
sscanf(loc, "=\"%[^\"]", parseBuf);
if(parseBuf[0]!='\0'){
//printf("%s\n", parseBuf);
numFound++;
auxLoad(parseBuf);
}
}
}
*/
if((loc_t=PL_strcasestr(lineBuf, "background"))!=nullptr) {
loc_t+=10;
strcpy(loc, loc_t);
sscanf(loc, "=\"%[^\"]", parseBuf);
if(parseBuf[0]!='\0') {
numFound++;
auxLoad(parseBuf);
}
}
i++;
}
*writeCount = count;
return NS_OK;
}
//-----------------------------------------------------------------------------
// nsIStreamListener implementation
//-----------------------------------------------------------------------------
class MyListener : public nsIStreamListener
{
virtual ~MyListener() {}
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
MyListener() { }
};
NS_IMPL_ISUPPORTS(MyListener,
nsIRequestObserver,
nsIStreamListener)
NS_IMETHODIMP
MyListener::OnStartRequest(nsIRequest *req, nsISupports *ctxt)
{
//printf(">>> OnStartRequest\n");
numStart++;
return NS_OK;
}
NS_IMETHODIMP
MyListener::OnStopRequest(nsIRequest *req, nsISupports *ctxt, nsresult status)
{
//printf(">>> OnStopRequest status=%x\n", status);
if (--gKeepRunning == 0)
QuitPumpingEvents();
return NS_OK;
}
NS_IMETHODIMP
MyListener::OnDataAvailable(nsIRequest *req, nsISupports *ctxt,
nsIInputStream *stream,
uint64_t offset, uint32_t count)
{
//printf(">>> OnDataAvailable [count=%u]\n", count);
nsresult rv = NS_ERROR_FAILURE;
uint32_t bytesRead=0;
char buf[1024];
if(ctxt == nullptr) {
bytesRead=0;
rv = stream->ReadSegments(streamParse, nullptr, count, &bytesRead);
} else {
while (count) {
uint32_t amount = std::min<uint32_t>(count, sizeof(buf));
rv = stream->Read(buf, amount, &bytesRead);
count -= bytesRead;
}
}
if (NS_FAILED(rv)) {
printf(">>> stream->Read failed with rv=%x\n",
static_cast<uint32_t>(rv));
return rv;
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// NotificationCallbacks implementation
//-----------------------------------------------------------------------------
class MyNotifications : public nsIInterfaceRequestor
, public nsIProgressEventSink
{
virtual ~MyNotifications() {}
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSIPROGRESSEVENTSINK
MyNotifications() { }
};
NS_IMPL_ISUPPORTS(MyNotifications,
nsIInterfaceRequestor,
nsIProgressEventSink)
NS_IMETHODIMP
MyNotifications::GetInterface(const nsIID &iid, void **result)
{
return QueryInterface(iid, result);
}
NS_IMETHODIMP
MyNotifications::OnStatus(nsIRequest *req, nsISupports *ctx,
nsresult status, const char16_t *statusText)
{
//printf("status: %x\n", status);
return NS_OK;
}
NS_IMETHODIMP
MyNotifications::OnProgress(nsIRequest *req, nsISupports *ctx,
uint64_t progress, uint64_t progressMax)
{
// char buf[100];
// PR_snprintf(buf, sizeof(buf), "%llu/%llu\n", progress, progressMax);
// printf("%s", buf);
return NS_OK;
}
//-----------------------------------------------------------------------------
// main, etc..
//-----------------------------------------------------------------------------
//---------getStrLine Helper function---------------
//Finds a newline in src starting at ind. Puts the
//line in str (must be big enough). Returns the index
//of the newline, or -1 if at end of string. If reaches
//end of string ('\0'), then will copy contents to
//globalStream.
int getStrLine(const char *src, char *str, int ind, int max) {
char c = src[ind];
int i=0;
globalStream.Assign('\0');
while(c!='\n' && c!='\0' && i<max) {
str[i] = src[ind];
i++; ind++;
c = src[ind];
}
str[i]='\0';
if(i==max || c=='\0') {
globalStream.Assign(str);
//printf("\nCarryover (%d|%d):\n------------\n%s\n-------\n",i,max,str);
return -1;
}
return ind;
}
//----------AUX LOAD-----------
nsresult auxLoad(char *uriBuf)
{
nsresult rv;
nsCOMPtr<nsISupportsPRBool> myBool = do_CreateInstance(NS_SUPPORTS_PRBOOL_CONTRACTID);
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIChannel> chan;
nsCOMPtr<nsIStreamListener> listener = new MyListener();
nsCOMPtr<nsIInterfaceRequestor> callbacks = new MyNotifications();
printf("Getting: %s", uriBuf);
//If relative link
if(strncmp(uriBuf, "http:", 5)) {
//Relative link
rv = NS_NewURI(getter_AddRefs(uri), uriBuf, baseURI);
if (NS_FAILED(rv)) return(rv);
} else {
//Absolute link, no base needed
rv = NS_NewURI(getter_AddRefs(uri), uriBuf);
if (NS_FAILED(rv)) return(rv);
}
//Compare to see if exists
bool equal;
for(int32_t i = 0; i < uriList.Count(); i++) {
uri->Equals(uriList[i], &equal);
if(equal) {
printf("(duplicate, canceling) %s\n",uriBuf);
return NS_OK;
}
}
printf("\n");
uriList.AppendObject(uri);
nsCOMPtr<nsIScriptSecurityManager> secman =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
RETURN_IF_FAILED(rv, rv, "Couldn't get script security manager!");
nsCOMPtr<nsIPrincipal> systemPrincipal;
rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
RETURN_IF_FAILED(rv, rv, "Couldn't get system principal!");
rv = NS_NewChannel(getter_AddRefs(chan),
uri,
systemPrincipal,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // loadGroup
callbacks);
RETURN_IF_FAILED(rv, rv, "NS_NewChannel");
gKeepRunning++;
rv = chan->AsyncOpen(listener, myBool);
RETURN_IF_FAILED(rv, rv, "AsyncOpen");
return NS_OK;
}
//---------Buffer writer fun---------
} // namespace
using namespace TestPageLoad;
//---------MAIN-----------
int main(int argc, char **argv)
{
if (test_common_init(&argc, &argv) != 0)
return -1;
nsresult rv;
if (argc == 1) {
printf("usage: TestPageLoad <url>\n");
return -1;
}
{
nsCOMPtr<nsIServiceManager> servMan;
NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr);
PRTime start, finish;
printf("Loading necko ... \n");
nsCOMPtr<nsIChannel> chan;
nsCOMPtr<nsIStreamListener> listener = new MyListener();
nsCOMPtr<nsIInterfaceRequestor> callbacks = new MyNotifications();
rv = NS_NewURI(getter_AddRefs(baseURI), argv[1]);
RETURN_IF_FAILED(rv, -1, "NS_NewURI");
nsCOMPtr<nsIScriptSecurityManager> secman =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
RETURN_IF_FAILED(rv, -1, "Couldn't get script security manager!");
nsCOMPtr<nsIPrincipal> systemPrincipal;
rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
RETURN_IF_FAILED(rv, -1, "Couldn't get system principal!");
rv = NS_NewChannel(getter_AddRefs(chan),
baseURI,
systemPrincipal,
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // loadGroup
callbacks);
RETURN_IF_FAILED(rv, -1, "NS_OpenURI");
gKeepRunning++;
//TIMER STARTED-----------------------
printf("Starting clock ... \n");
start = PR_Now();
rv = chan->AsyncOpen(listener, nullptr);
RETURN_IF_FAILED(rv, -1, "AsyncOpen");
PumpEvents();
finish = PR_Now();
uint32_t totalTime32 = uint32_t(finish - start);
printf("\n\n--------------------\nAll done:\nnum found:%d\nnum start:%d\n", numFound, numStart);
printf("\n\n>>PageLoadTime>>%u>>\n\n", totalTime32);
} // this scopes the nsCOMPtrs
// no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
rv = NS_ShutdownXPCOM(nullptr);
NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
return 0;
}

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

@ -1,273 +0,0 @@
#include "TestCommon.h"
#include <stdio.h>
#include "nsCRT.h" /* should be "plstr.h"? */
#include "nsNetUtil.h"
#include "nsIServiceManager.h"
#include "nsIComponentRegistrar.h"
#include "nsISupportsArray.h"
#include "nsContentUtils.h"
#include <algorithm>
namespace TestPerf {
static nsIIOService *gIOService = nullptr;
//-----------------------------------------------------------------------------
static bool
load_sync_1(nsISupports *element, void *data)
{
nsCOMPtr<nsIInputStream> stream;
nsCOMPtr<nsIURI> uri( do_QueryInterface(element) );
nsAutoCString spec;
nsresult rv;
rv = NS_OpenURI(getter_AddRefs(stream),
uri,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // aLoadGroup
nullptr, // aCallbacks
LOAD_NORMAL,
gIOService);
if (NS_FAILED(rv)) {
uri->GetAsciiSpec(spec);
fprintf(stderr, "*** failed opening %s [rv=%x]\n", spec.get(), rv);
return true;
}
char buf[4096];
uint32_t bytesRead;
while (1) {
rv = stream->Read(buf, sizeof(buf), &bytesRead);
if (NS_FAILED(rv) || bytesRead == 0) {
if (NS_FAILED(rv)) {
uri->GetAsciiSpec(spec);
fprintf(stderr, "*** failed reading %s [rv=%x]\n", spec.get(), rv);
}
break;
}
}
return true;
}
static nsresult
load_sync(nsISupportsArray *urls)
{
urls->EnumerateForwards(load_sync_1, nullptr);
return NS_OK;
}
//-----------------------------------------------------------------------------
static int gRequestCount = 0;
class MyListener : public nsIStreamListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
MyListener() { }
virtual ~MyListener() {}
};
NS_IMPL_ISUPPORTS(MyListener, nsIStreamListener, nsIRequestObserver)
NS_IMETHODIMP
MyListener::OnStartRequest(nsIRequest *req, nsISupports *ctx)
{
return NS_OK;
}
NS_IMETHODIMP
MyListener::OnDataAvailable(nsIRequest *req, nsISupports *ctx,
nsIInputStream *stream,
uint64_t offset, uint32_t count)
{
nsresult rv;
char buf[4096];
uint32_t n, bytesRead;
while (count) {
n = std::min<uint32_t>(count, sizeof(buf));
rv = stream->Read(buf, n, &bytesRead);
if (NS_FAILED(rv))
break;
count -= bytesRead;
if (bytesRead == 0)
break;
}
return NS_OK;
}
NS_IMETHODIMP
MyListener::OnStopRequest(nsIRequest *req, nsISupports *ctx, nsresult status)
{
if (NS_FAILED(status)) {
nsAutoCString spec;
req->GetName(spec);
fprintf(stderr, "*** failed loading %s [reason=%x]\n", spec.get(), status);
}
if (--gRequestCount == 0) {
// post shutdown event
QuitPumpingEvents();
}
return NS_OK;
}
static bool
load_async_1(nsISupports *element, void *data)
{
nsCOMPtr<nsIURI> uri( do_QueryInterface(element) );
if (!uri)
return true;
MyListener *listener = new MyListener();
if (!listener)
return true;
NS_ADDREF(listener);
nsresult rv = NS_OpenURI(listener,
nullptr, // aContext
uri,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER,
nullptr, // aLoadGroup
nullptr, // aCallbacks
gIOService);
NS_RELEASE(listener);
if (NS_SUCCEEDED(rv))
gRequestCount++;
else
printf(">> NS_OpenURI failed [rv=%x]\n", rv);
return true;
}
static nsresult
load_async(nsISupportsArray *urls)
{
urls->EnumerateForwards(load_async_1, nullptr);
PumpEvents();
return NS_OK;
}
//-----------------------------------------------------------------------------
static nsresult
read_file(const char *fname, nsISupportsArray *urls)
{
FILE *fp = fopen(fname, "r");
if (!fp) {
printf("failed opening file: %s\n", fname);
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> uri;
nsresult rv;
char buf[512];
while (fgets(buf, sizeof(buf), fp)) {
// remove trailing newline
buf[strlen(buf) - 1] = 0;
rv = NS_NewURI(getter_AddRefs(uri), buf, nullptr, gIOService);
if (NS_FAILED(rv))
printf("*** ignoring malformed uri: %s\n", buf);
else {
//nsXPIDLCString spec;
//uri->GetSpec(getter_Copies(spec));
//printf("read url: %s\n", spec.get());
urls->AppendElement(uri);
}
}
fclose(fp);
return NS_OK;
}
//-----------------------------------------------------------------------------
static void
print_usage()
{
printf("usage: TestPerf [-sync|-async] <file-of-urls>\n");
}
} // namespace
using namespace TestPerf;
int
main(int argc, char **argv)
{
if (test_common_init(&argc, &argv) != 0)
return -1;
nsresult rv;
bool sync;
if (argc < 3) {
print_usage();
return -1;
}
if (PL_strcasecmp(argv[1], "-sync") == 0)
sync = true;
else if (PL_strcasecmp(argv[1], "-async") == 0)
sync = false;
else {
print_usage();
return -1;
}
nsCOMPtr<nsIServiceManager> servMan;
NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr);
nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
registrar->AutoRegister(nullptr);
// cache the io service
{
nsCOMPtr<nsIIOService> ioserv( do_GetIOService() );
NS_ADDREF(gIOService = ioserv);
}
nsCOMPtr<nsISupportsArray> urls;
rv = NS_NewISupportsArray(getter_AddRefs(urls));
if (NS_FAILED(rv)) return -1;
rv = read_file(argv[2], urls);
if (NS_FAILED(rv)) {
printf("failed reading file-of-urls\n");
return -1;
}
uint32_t urlCount;
urls->Count(&urlCount);
PRIntervalTime start = PR_IntervalNow();
if (sync)
rv = load_sync(urls);
else
rv = load_async(urls);
if (NS_FAILED(rv)) {
printf("load failed\n");
return -1;
}
PRIntervalTime end = PR_IntervalNow();
fprintf(stderr, "read: %u urls; total time: %u milliseconds\n",
urlCount,
PR_IntervalToMilliseconds(end - start));
NS_RELEASE(gIOService);
return 0;
}

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

@ -649,7 +649,7 @@ nsresult StartLoadingURL(const char* aUrlString)
NS_RELEASE(callbacks);
if (NS_FAILED(rv)) {
LOG(("ERROR: NS_OpenURI failed for %s [rv=%x]\n", aUrlString, rv));
LOG(("ERROR: NS_NewChannel failed for %s [rv=%x]\n", aUrlString, rv));
return rv;
}

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

@ -1,111 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <nsCOMPtr.h>
#include <nsString.h>
#include <nsIURI.h>
#include <nsIChannel.h>
#include <nsIHTTPChannel.h>
#include <nsIInputStream.h>
#include "nsContentUtils.h"
#include <nsNetUtil.h>
/*
* Test synchronous HTTP.
*/
#define RETURN_IF_FAILED(rv, what) \
PR_BEGIN_MACRO \
if (NS_FAILED(rv)) { \
printf(what ": failed - %08x\n", rv); \
return -1; \
} \
PR_END_MACRO
struct TestContext {
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIChannel> channel;
nsCOMPtr<nsIInputStream> inputStream;
PRTime t1, t2;
uint32_t bytesRead, totalRead;
TestContext()
: t1(0), t2(0), bytesRead(0), totalRead(0)
{ printf("TestContext [this=%p]\n", (void*)this); }
~TestContext()
{ printf("~TestContext [this=%p]\n", (void*)this); }
};
int
main(int argc, char **argv)
{
nsresult rv;
TestContext *c;
int i, nc=0, npending=0;
char buf[256];
if (argc < 2) {
printf("Usage: TestSyncHTTP <url-list>\n");
return -1;
}
c = new TestContext[argc-1];
for (i=0; i<(argc-1); ++i, ++nc) {
rv = NS_NewURI(getter_AddRefs(c[i].uri), argv[i+1]);
RETURN_IF_FAILED(rv, "NS_NewURI");
rv = NS_OpenURI(getter_AddRefs(c[i].channel,
c[i].uri,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER);
RETURN_IF_FAILED(rv, "NS_OpenURI");
nsCOMPtr<nsIHTTPChannel> httpChannel = do_QueryInterface(c[i].channel);
if (httpChannel)
httpChannel->SetOpenHasEventQueue(false);
// initialize these fields for reading
c[i].bytesRead = 1;
c[i].totalRead = 0;
}
for (i=0; i<nc; ++i) {
c[i].t1 = PR_Now();
rv = c[i].channel->Open(getter_AddRefs(c[i].inputStream));
RETURN_IF_FAILED(rv, "nsIChannel::OpenInputStream");
}
npending = nc;
while (npending) {
for (i=0; i<nc; ++i) {
//
// read the response content...
//
if (c[i].bytesRead > 0) {
rv = c[i].inputStream->Read(buf, sizeof buf, &c[i].bytesRead);
RETURN_IF_FAILED(rv, "nsIInputStream::Read");
c[i].totalRead += c[i].bytesRead;
if (c[i].bytesRead == 0) {
c[i].t2 = PR_Now();
printf("finished GET of: %s\n", argv[i+1]);
printf("total read: %u bytes\n", c[i].totalRead);
printf("total read time: %0.3f\n",
((double) (c[i].t2 - c[i].t1))/1000000.0);
npending--;
}
}
}
}
delete[] c;
NS_ShutdownXPCOM(nullptr);
return 0;
}

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

@ -1,290 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdio.h>
#include "nsCOMPtr.h"
#include "nsIEventQueueService.h"
#include "nsIServiceManager.h"
#include "nsIStreamListener.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsContentUtils.h"
#include <algorithm>
//#include "prthread.h"
// This test attempts to load a URL on a separate thread. It is currently
// designed simply to expose the problems inherent in such an ambitous task
// (i.e., it don't work).
// Utility functions...
// Create event queue for current thread.
static nsCOMPtr<nsIEventQueue>
createEventQueue() {
nsCOMPtr<nsIEventQueue> result;
// Get event queue service.
nsresult rv = NS_OK;
nsCOMPtr<nsIEventQueueService> eqs =
do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
if ( NS_SUCCEEDED( rv ) ) {
eqs->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(result));
} else {
printf( "%s %d: NS_WITH_SERVICE(nsIEventQueueService) failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
return result;
}
// Create channel for requested URL.
static nsCOMPtr<nsIChannel>
createChannel( const char *url ) {
nsCOMPtr<nsIInputStream> result;
nsCOMPtr<nsIURI> uri;
printf( "Calling NS_NewURI for %s...\n", url );
nsresult rv = NS_NewURI( getter_AddRefs( uri ), url );
if ( NS_SUCCEEDED( rv ) ) {
printf( "...NS_NewURI completed OK\n" );
// Allocate a new input channel on this thread.
printf( "Calling NS_OpenURI...\n" );
nsresult rv = NS_OpenURI(getter_AddRefs(result),
uri,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_NORMAL,
nsIContentPolicy::TYPE_OTHER);
if ( NS_SUCCEEDED( rv ) ) {
printf( "...NS_OpenURI completed OK\n" );
} else {
printf( "%s %d: NS_OpenURI failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
} else {
printf( "%s %d: NS_NewURI failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
}
return result;
}
// Test listener. It basically dumps incoming data to console.
class TestListener : public nsIStreamListener {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSISTREAMOBSERVER
TestListener();
~TestListener();
static void IOThread( void *p );
private:
bool mDone;
int mThreadNo;
FILE *mFile;
static int threadCount;
}; // class TestListener
int TestListener::threadCount = 0;
TestListener::TestListener()
: mDone( false ), mThreadNo( ++threadCount ) {
printf( "TestListener ctor called on thread %d\n", mThreadNo );
}
TestListener::~TestListener() {
printf( "TestListener dtor called on thread %d\n", mThreadNo );
}
NS_IMPL_ISUPPORTS( TestListener, nsIStreamListener, nsIRequestObserver )
NS_IMETHODIMP
TestListener::OnStartRequest( nsIChannel *aChannel, nsISupports *aContext ) {
nsresult rv = NS_OK;
printf( "TestListener::OnStartRequest called on thread %d\n", mThreadNo );
// Open output file.
char fileName[32];
sprintf( fileName, "%s%d", "thread", mThreadNo );
mFile = fopen( fileName, "wb" );
setbuf( mFile, 0 );
return rv;
}
NS_IMETHODIMP
TestListener::OnStopRequest( nsIChannel *aChannel,
nsISupports *aContext,
nsresult aStatus,
const char16_t *aMsg ) {
nsresult rv = NS_OK;
printf( "TestListener::OnStopRequest called on thread %d\n", mThreadNo );
fclose( mFile );
mDone = true;
return rv;
}
NS_IMETHODIMP
TestListener::OnDataAvailable( nsIChannel *aChannel,
nsISupports *aContext,
nsIInputStream *aStream,
uint64_t offset,
uint32_t aLength ) {
nsresult rv = NS_OK;
printf( "TestListener::OnDataAvailable called on thread %d\n", mThreadNo );
// Write the data to the console.
// Read a buffer full till aLength bytes have been processed.
char buffer[ 8192 ];
unsigned long bytesRemaining = aLength;
while ( bytesRemaining ) {
unsigned int bytesRead;
// Read a buffer full or the number remaining (whichever is smaller).
rv = aStream->Read( buffer,
std::min( sizeof( buffer ), bytesRemaining ),
&bytesRead );
if ( NS_SUCCEEDED( rv ) ) {
// Write the bytes just read to the output file.
fwrite( buffer, 1, bytesRead, mFile );
bytesRemaining -= bytesRead;
} else {
printf( "%s %d: Read error, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
break;
}
}
printf( "\n" );
return rv;
}
// IOThread: this function creates a new TestListener object (on the new
// thread), opens a channel, and does AsyncRead to it.
void
TestListener::IOThread( void *p ) {
printf( "I/O thread (0x%08X) started...\n", (int)(void*)PR_GetCurrentThread() );
// Argument is pointer to the nsIEventQueue for the main thread.
nsIEventQueue *mainThreadQ = static_cast<nsIEventQueue*>(p);
// Create channel for random web page.
nsCOMPtr<nsIChannel> channel = createChannel( (const char*)p );
if ( channel ) {
// Create event queue.
nsCOMPtr<nsIEventQueue> ioEventQ = createEventQueue();
if ( ioEventQ ) {
// Create test listener.
TestListener *testListener = new TestListener();
testListener->AddRef();
// Read the channel.
printf( "Doing AsyncRead...\n" );
nsresult rv = channel->AsyncRead( testListener, 0 );
if ( NS_SUCCEEDED( rv ) ) {
printf( "...AsyncRead completed OK\n" );
// Process events till testListener says stop.
printf( "Start event loop on io thread %d...\n", testListener->mThreadNo );
while ( !testListener->mDone ) {
PLEvent *event;
ioEventQ->GetEvent( &event );
ioEventQ->HandleEvent( event );
}
printf( "...io thread %d event loop exiting\n", testListener->mThreadNo );
} else {
printf( "%s %d: AsyncRead failed on thread %d, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, testListener->mThreadNo, (int)rv );
}
// Release the test listener.
testListener->Release();
}
}
printf( "...I/O thread terminating\n" );
}
static const int maxThreads = 5;
int
main( int argc, char* argv[] ) {
setbuf( stdout, 0 );
if ( argc < 2 || argc > maxThreads + 1 ) {
printf( "usage: testThreadedIO url1 <url2>...\n"
"where <url#> is a location to be loaded on a separate thread\n"
"limit is %d urls/threads", maxThreads );
return -1;
}
nsresult rv= (nsresult)-1;
printf( "Test starting...\n" );
// Initialize XPCOM.
printf( "Initializing XPCOM...\n" );
rv = NS_InitXPCOM2(nullptr, nullptr, nullptr);
if ( NS_FAILED( rv ) ) {
printf( "%s %d: NS_InitXPCOM failed, rv=0x%08X\n",
(char*)__FILE__, (int)__LINE__, (int)rv );
return rv;
}
printf( "...XPCOM initialized OK\n" );
// Create the Event Queue for this thread...
printf( "Creating event queue for main thread (0x%08X)...\n",
(int)(void*)PR_GetCurrentThread() );
{
nsCOMPtr<nsIEventQueue> mainThreadQ = createEventQueue();
if ( mainThreadQ ) {
printf( "...main thread's event queue created OK\n" );
// Spawn threads to do I/O.
int goodThreads = 0;
PRThread *thread[ maxThreads ];
for ( int threadNo = 1; threadNo < argc; threadNo++ ) {
printf( "Creating I/O thread %d to load %s...\n", threadNo, argv[threadNo] );
PRThread *ioThread = PR_CreateThread( PR_USER_THREAD,
TestListener::IOThread,
argv[threadNo],
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0 );
if ( ioThread ) {
thread[ goodThreads++ ] = ioThread;
printf( "...I/O thread %d (0x%08X) created OK\n",
threadNo, (int)(void*)ioThread );
} else {
printf( "%s %d: PR_CreateThread for thread %d failed\n",
(char*)__FILE__, (int)__LINE__, threadNo );
}
}
// Wait for all the threads to terminate.
for ( int joinThread = 0; joinThread < goodThreads; joinThread++ ) {
printf( "Waiting for thread %d to terminate...\n", joinThread+1 );
PR_JoinThread( thread[ joinThread ] );
}
}
} // this scopes the nsCOMPtrs
// no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
// Shut down XPCOM.
printf( "Shutting down XPCOM...\n" );
NS_ShutdownXPCOM( 0 );
printf( "...XPCOM shutdown complete\n" );
// Exit.
printf( "...test complete, rv=0x%08X\n", (int)rv );
return rv;
}

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

@ -59,6 +59,7 @@ function commonCheck(ch)
do_check_true(ch.contentLength > -1);
do_check_eq(ch.getResponseHeader("connection"), "close");
do_check_false(ch.isNoStoreResponse());
do_check_false(ch.isPrivateResponse());
}
function start_objHandler(ch, cx)

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

@ -24,7 +24,6 @@ GeckoSimplePrograms([
'TestDNS',
'TestIncrementalDownload',
'TestOpen',
'TestPageLoad',
'TestProtocols',
'TestServ',
'TestStandardURL',
@ -38,7 +37,6 @@ GeckoSimplePrograms([
#SIMPLE_PROGRAMS += [
# TestIDN',
# TestIOThreads',
# TestPerf',
# TestSocketTransport',
# TestStreamChannel',
# TestStreamPump',

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше