2018-01-19 03:59:58 +08:00
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- /
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
/ * T h i s S o u r c e C o d e F o r m i s s u b j e c t t o t h e t e r m s o f t h e M o z i l l a P u b l i c
* 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 . EXPORTED _SYMBOLS = [ "OnRefTestLoad" , "OnRefTestUnload" ] ;
var CC = Components . classes ;
const CI = Components . interfaces ;
const CR = Components . results ;
const CU = Components . utils ;
const XHTML _NS = "http://www.w3.org/1999/xhtml" ;
const XUL _NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" ;
const NS _LOCAL _FILE _CONTRACTID = "@mozilla.org/file/local;1" ;
const NS _GFXINFO _CONTRACTID = "@mozilla.org/gfx/info;1" ;
const IO _SERVICE _CONTRACTID = "@mozilla.org/network/io-service;1" ;
const DEBUG _CONTRACTID = "@mozilla.org/xpcom/debug;1" ;
const NS _LOCALFILEINPUTSTREAM _CONTRACTID =
"@mozilla.org/network/file-input-stream;1" ;
const NS _SCRIPTSECURITYMANAGER _CONTRACTID =
"@mozilla.org/scriptsecuritymanager;1" ;
const NS _REFTESTHELPER _CONTRACTID =
"@mozilla.org/reftest-helper;1" ;
const NS _NETWORK _PROTOCOL _CONTRACTID _PREFIX =
"@mozilla.org/network/protocol;1?name=" ;
const NS _XREAPPINFO _CONTRACTID =
"@mozilla.org/xre/app-info;1" ;
const NS _DIRECTORY _SERVICE _CONTRACTID =
"@mozilla.org/file/directory_service;1" ;
const NS _OBSERVER _SERVICE _CONTRACTID =
"@mozilla.org/observer-service;1" ;
CU . import ( "resource://gre/modules/FileUtils.jsm" ) ;
CU . import ( "chrome://reftest/content/httpd.jsm" , this ) ;
CU . import ( "chrome://reftest/content/StructuredLog.jsm" , this ) ;
CU . import ( "resource://gre/modules/Services.jsm" ) ;
CU . import ( "resource://gre/modules/NetUtil.jsm" ) ;
var gLoadTimeout = 0 ;
var gTimeoutHook = null ;
var gRemote = false ;
var gIgnoreWindowSize = false ;
var gShuffle = false ;
var gRepeat = null ;
var gRunUntilFailure = false ;
var gTotalChunks = 0 ;
var gThisChunk = 0 ;
var gContainingWindow = null ;
var gURLFilterRegex = { } ;
var gContentGfxInfo = null ;
const FOCUS _FILTER _ALL _TESTS = "all" ;
const FOCUS _FILTER _NEEDS _FOCUS _TESTS = "needs-focus" ;
const FOCUS _FILTER _NON _NEEDS _FOCUS _TESTS = "non-needs-focus" ;
var gFocusFilterMode = FOCUS _FILTER _ALL _TESTS ;
// "<!--CLEAR-->"
const BLANK _URL _FOR _CLEARING = "data:text/html;charset=UTF-8,%3C%21%2D%2DCLEAR%2D%2D%3E" ;
var gBrowser ;
// Are we testing web content loaded in a separate process?
var gBrowserIsRemote ; // bool
var gB2GisMulet ; // bool
// Are we using <iframe mozbrowser>?
var gBrowserIsIframe ; // bool
var gBrowserMessageManager ;
var gCanvas1 , gCanvas2 ;
// gCurrentCanvas is non-null between InitCurrentCanvasWithSnapshot and the next
// RecordResult.
var gCurrentCanvas = null ;
var gURLs ;
var gManifestsLoaded = { } ;
// Map from URI spec to the number of times it remains to be used
var gURIUseCounts ;
// Map from URI spec to the canvas rendered for that URI
var gURICanvases ;
var gTestResults = {
// Successful...
Pass : 0 ,
LoadOnly : 0 ,
// Unexpected...
Exception : 0 ,
FailedLoad : 0 ,
UnexpectedFail : 0 ,
UnexpectedPass : 0 ,
AssertionUnexpected : 0 ,
AssertionUnexpectedFixed : 0 ,
// Known problems...
KnownFail : 0 ,
AssertionKnown : 0 ,
Random : 0 ,
Skip : 0 ,
Slow : 0 ,
} ;
var gTotalTests = 0 ;
var gState ;
var gCurrentURL ;
var gTestLog = [ ] ;
var gLogLevel ;
var gServer ;
var gCount = 0 ;
var gAssertionCount = 0 ;
var gIOService ;
var gDebug ;
var gWindowUtils ;
var gSlowestTestTime = 0 ;
var gSlowestTestURL ;
var gFailedUseWidgetLayers = false ;
var gDrawWindowFlags ;
var gExpectingProcessCrash = false ;
var gExpectedCrashDumpFiles = [ ] ;
var gUnexpectedCrashDumpFiles = { } ;
var gCrashDumpDir ;
var gFailedNoPaint = false ;
var gFailedOpaqueLayer = false ;
var gFailedOpaqueLayerMessages = [ ] ;
var gFailedAssignedLayer = false ;
var gFailedAssignedLayerMessages = [ ] ;
// The enabled-state of the test-plugins, stored so they can be reset later
var gTestPluginEnabledStates = null ;
const TYPE _REFTEST _EQUAL = '==' ;
const TYPE _REFTEST _NOTEQUAL = '!=' ;
const TYPE _LOAD = 'load' ; // test without a reference (just test that it does
// not assert, crash, hang, or leak)
const TYPE _SCRIPT = 'script' ; // test contains individual test results
// The order of these constants matters, since when we have a status
// listed for a *manifest*, we combine the status with the status for
// the test by using the *larger*.
// FIXME: In the future, we may also want to use this rule for combining
// statuses that are on the same line (rather than making the last one
// win).
const EXPECTED _PASS = 0 ;
const EXPECTED _FAIL = 1 ;
const EXPECTED _RANDOM = 2 ;
const EXPECTED _DEATH = 3 ; // test must be skipped to avoid e.g. crash/hang
const EXPECTED _FUZZY = 4 ;
// types of preference value we might want to set for a specific test
const PREF _BOOLEAN = 0 ;
const PREF _STRING = 1 ;
const PREF _INTEGER = 2 ;
var gPrefsToRestore = [ ] ;
const gProtocolRE = /^\w+:/ ;
const gPrefItemRE = /^(|test-|ref-)pref\((.+?),(.*)\)$/ ;
var gHttpServerPort = - 1 ;
// whether to run slow tests or not
var gRunSlowTests = true ;
// whether we should skip caching canvases
var gNoCanvasCache = false ;
var gRecycledCanvases = new Array ( ) ;
// Only dump the sandbox once, because it doesn't depend on the
// manifest URL (yet!).
var gDumpedConditionSandbox = false ;
function HasUnexpectedResult ( )
{
return gTestResults . Exception > 0 ||
gTestResults . FailedLoad > 0 ||
gTestResults . UnexpectedFail > 0 ||
gTestResults . UnexpectedPass > 0 ||
gTestResults . AssertionUnexpected > 0 ||
gTestResults . AssertionUnexpectedFixed > 0 ;
}
// By default we just log to stdout
var gLogFile = null ;
var gDumpFn = function ( line ) {
dump ( line ) ;
if ( gLogFile ) {
gLogFile . write ( line , line . length ) ;
}
}
var gDumpRawLog = function ( record ) {
// Dump JSON representation of data on a single line
var line = "\n" + JSON . stringify ( record ) + "\n" ;
dump ( line ) ;
if ( gLogFile ) {
gLogFile . write ( line , line . length ) ;
}
}
var logger = new StructuredLogger ( 'reftest' , gDumpRawLog ) ;
function TestBuffer ( str )
{
logger . debug ( str ) ;
gTestLog . push ( str ) ;
}
function FlushTestBuffer ( )
{
// In debug mode, we've dumped all these messages already.
if ( gLogLevel !== 'debug' ) {
for ( var i = 0 ; i < gTestLog . length ; ++ i ) {
logger . info ( "Saved log: " + gTestLog [ i ] ) ;
}
}
gTestLog = [ ] ;
}
function LogWidgetLayersFailure ( )
{
logger . error ( "USE_WIDGET_LAYERS disabled because the screen resolution is too low. This falls back to an alternate rendering path (that may not be representative) and is not implemented with e10s enabled." ) ;
logger . error ( "Consider increasing your screen resolution, or adding '--disable-e10s' to your './mach reftest' command" ) ;
}
function AllocateCanvas ( )
{
if ( gRecycledCanvases . length > 0 ) {
return gRecycledCanvases . shift ( ) ;
}
var canvas = gContainingWindow . document . createElementNS ( XHTML _NS , "canvas" ) ;
var r = gBrowser . getBoundingClientRect ( ) ;
canvas . setAttribute ( "width" , Math . ceil ( r . width ) ) ;
canvas . setAttribute ( "height" , Math . ceil ( r . height ) ) ;
return canvas ;
}
function ReleaseCanvas ( canvas )
{
// store a maximum of 2 canvases, if we're not caching
if ( ! gNoCanvasCache || gRecycledCanvases . length < 2 ) {
gRecycledCanvases . push ( canvas ) ;
}
}
function IDForEventTarget ( event )
{
try {
return "'" + event . target . getAttribute ( 'id' ) + "'" ;
} catch ( ex ) {
return "<unknown>" ;
}
}
function getTestPlugin ( aName ) {
var ph = CC [ "@mozilla.org/plugin/host;1" ] . getService ( CI . nsIPluginHost ) ;
var tags = ph . getPluginTags ( ) ;
// Find the test plugin
for ( var i = 0 ; i < tags . length ; i ++ ) {
if ( tags [ i ] . name == aName )
return tags [ i ] ;
}
logger . warning ( "Failed to find the test-plugin." ) ;
return null ;
}
this . OnRefTestLoad = function OnRefTestLoad ( win )
{
gCrashDumpDir = CC [ NS _DIRECTORY _SERVICE _CONTRACTID ]
. getService ( CI . nsIProperties )
. get ( "ProfD" , CI . nsIFile ) ;
gCrashDumpDir . append ( "minidumps" ) ;
var env = CC [ "@mozilla.org/process/environment;1" ] .
getService ( CI . nsIEnvironment ) ;
var prefs = Components . classes [ "@mozilla.org/preferences-service;1" ] .
getService ( Components . interfaces . nsIPrefBranch ) ;
try {
gBrowserIsRemote = prefs . getBoolPref ( "browser.tabs.remote.autostart" ) ;
} catch ( e ) {
gBrowserIsRemote = false ;
}
try {
gB2GisMulet = prefs . getBoolPref ( "b2g.is_mulet" ) ;
} catch ( e ) {
gB2GisMulet = false ;
}
try {
gBrowserIsIframe = prefs . getBoolPref ( "reftest.browser.iframe.enabled" ) ;
} catch ( e ) {
gBrowserIsIframe = false ;
}
try {
gLogLevel = prefs . getCharPref ( "reftest.logLevel" ) ;
} catch ( e ) {
gLogLevel = 'info' ;
}
if ( win === undefined || win == null ) {
win = window ;
}
if ( gContainingWindow == null && win != null ) {
gContainingWindow = win ;
}
if ( gBrowserIsIframe ) {
gBrowser = gContainingWindow . document . createElementNS ( XHTML _NS , "iframe" ) ;
gBrowser . setAttribute ( "mozbrowser" , "" ) ;
gBrowser . setAttribute ( "mozapp" , prefs . getCharPref ( "b2g.system_manifest_url" ) ) ;
} else {
gBrowser = gContainingWindow . document . createElementNS ( XUL _NS , "xul:browser" ) ;
}
gBrowser . setAttribute ( "id" , "browser" ) ;
gBrowser . setAttribute ( "type" , "content-primary" ) ;
gBrowser . setAttribute ( "remote" , gBrowserIsRemote ? "true" : "false" ) ;
// Make sure the browser element is exactly 800x1000, no matter
// what size our window is
gBrowser . setAttribute ( "style" , "padding: 0px; margin: 0px; border:none; min-width: 800px; min-height: 1000px; max-width: 800px; max-height: 1000px" ) ;
if ( Services . appinfo . OS == "Android" ) {
let doc ;
2018-05-13 22:46:04 +02:00
doc = gContainingWindow . document . getElementById ( 'main-window' ) ;
2018-01-19 03:59:58 +08:00
while ( doc . hasChildNodes ( ) ) {
doc . removeChild ( doc . firstChild ) ;
}
doc . appendChild ( gBrowser ) ;
} else {
document . getElementById ( "reftest-window" ) . appendChild ( gBrowser ) ;
}
// reftests should have the test plugins enabled, not click-to-play
let plugin1 = getTestPlugin ( "Test Plug-in" ) ;
let plugin2 = getTestPlugin ( "Second Test Plug-in" ) ;
if ( plugin1 && plugin2 ) {
gTestPluginEnabledStates = [ plugin1 . enabledState , plugin2 . enabledState ] ;
plugin1 . enabledState = CI . nsIPluginTag . STATE _ENABLED ;
plugin2 . enabledState = CI . nsIPluginTag . STATE _ENABLED ;
} else {
logger . warning ( "Could not get test plugin tags." ) ;
}
gBrowserMessageManager = gBrowser . QueryInterface ( CI . nsIFrameLoaderOwner )
. frameLoader . messageManager ;
// The content script waits for the initial onload, then notifies
// us.
RegisterMessageListenersAndLoadContentScript ( ) ;
}
function InitAndStartRefTests ( )
{
/* These prefs are optional, so we don't need to spit an error to the log */
try {
var prefs = Components . classes [ "@mozilla.org/preferences-service;1" ] .
getService ( Components . interfaces . nsIPrefBranch ) ;
} catch ( e ) {
logger . error ( "EXCEPTION: " + e ) ;
}
try {
prefs . setBoolPref ( "android.widget_paints_background" , false ) ;
} catch ( e ) { }
/* set the gLoadTimeout */
try {
gLoadTimeout = prefs . getIntPref ( "reftest.timeout" ) ;
} catch ( e ) {
gLoadTimeout = 5 * 60 * 1000 ; //5 minutes as per bug 479518
}
/* Get the logfile for android tests */
try {
var logFile = prefs . getCharPref ( "reftest.logFile" ) ;
if ( logFile ) {
var f = FileUtils . File ( logFile ) ;
gLogFile = FileUtils . openFileOutputStream ( f , FileUtils . MODE _WRONLY | FileUtils . MODE _CREATE ) ;
}
} catch ( e ) { }
try {
gRemote = prefs . getBoolPref ( "reftest.remote" ) ;
} catch ( e ) {
gRemote = false ;
}
try {
gIgnoreWindowSize = prefs . getBoolPref ( "reftest.ignoreWindowSize" ) ;
} catch ( e ) {
gIgnoreWindowSize = false ;
}
/* Support for running a chunk (subset) of tests. In separate try as this is optional */
try {
gTotalChunks = prefs . getIntPref ( "reftest.totalChunks" ) ;
gThisChunk = prefs . getIntPref ( "reftest.thisChunk" ) ;
}
catch ( e ) {
gTotalChunks = 0 ;
gThisChunk = 0 ;
}
try {
gFocusFilterMode = prefs . getCharPref ( "reftest.focusFilterMode" ) ;
} catch ( e ) { }
gWindowUtils = gContainingWindow . QueryInterface ( CI . nsIInterfaceRequestor ) . getInterface ( CI . nsIDOMWindowUtils ) ;
if ( ! gWindowUtils || ! gWindowUtils . compareCanvases )
throw "nsIDOMWindowUtils inteface missing" ;
gIOService = CC [ IO _SERVICE _CONTRACTID ] . getService ( CI . nsIIOService ) ;
gDebug = CC [ DEBUG _CONTRACTID ] . getService ( CI . nsIDebug2 ) ;
RegisterProcessCrashObservers ( ) ;
if ( gRemote ) {
gServer = null ;
} else {
gServer = new HttpServer ( ) ;
}
try {
if ( gServer )
StartHTTPServer ( ) ;
} catch ( ex ) {
//gBrowser.loadURI('data:text/plain,' + ex);
++ gTestResults . Exception ;
logger . error ( "EXCEPTION: " + ex ) ;
DoneTests ( ) ;
}
// Focus the content browser.
if ( gFocusFilterMode != FOCUS _FILTER _NON _NEEDS _FOCUS _TESTS ) {
gBrowser . focus ( ) ;
}
StartTests ( ) ;
}
function StartHTTPServer ( )
{
gServer . registerContentType ( "sjs" , "sjs" ) ;
gServer . start ( - 1 ) ;
gHttpServerPort = gServer . identity . primaryPort ;
}
// Perform a Fisher-Yates shuffle of the array.
function Shuffle ( array )
{
for ( var i = array . length - 1 ; i > 0 ; i -- ) {
var j = Math . floor ( Math . random ( ) * ( i + 1 ) ) ;
var temp = array [ i ] ;
array [ i ] = array [ j ] ;
array [ j ] = temp ;
}
}
function StartTests ( )
{
var manifests ;
/* These prefs are optional, so we don't need to spit an error to the log */
try {
var prefs = Components . classes [ "@mozilla.org/preferences-service;1" ] .
getService ( Components . interfaces . nsIPrefBranch ) ;
} catch ( e ) {
logger . error ( "EXCEPTION: " + e ) ;
}
try {
gNoCanvasCache = prefs . getIntPref ( "reftest.nocache" ) ;
} catch ( e ) {
gNoCanvasCache = false ;
}
try {
gShuffle = prefs . getBoolPref ( "reftest.shuffle" ) ;
} catch ( e ) {
gShuffle = false ;
}
try {
gRunUntilFailure = prefs . getBoolPref ( "reftest.runUntilFailure" ) ;
} catch ( e ) {
gRunUntilFailure = false ;
}
// When we repeat this function is called again, so really only want to set
// gRepeat once.
if ( gRepeat == null ) {
try {
gRepeat = prefs . getIntPref ( "reftest.repeat" ) ;
} catch ( e ) {
gRepeat = 0 ;
}
}
try {
gRunSlowTests = prefs . getIntPref ( "reftest.skipslowtests" ) ;
} catch ( e ) {
gRunSlowTests = false ;
}
if ( gShuffle ) {
gNoCanvasCache = true ;
}
gURLs = [ ] ;
gManifestsLoaded = { } ;
try {
var manifests = JSON . parse ( prefs . getCharPref ( "reftest.manifests" ) ) ;
gURLFilterRegex = manifests [ null ] ;
} catch ( e ) {
logger . error ( "Unable to find reftest.manifests pref. Please ensure your profile is setup properly" ) ;
DoneTests ( ) ;
}
try {
var globalFilter = manifests . hasOwnProperty ( "" ) ? new RegExp ( manifests [ "" ] ) : null ;
var manifestURLs = Object . keys ( manifests ) ;
// Ensure we read manifests from higher up the directory tree first so that we
// process includes before reading the included manifest again
manifestURLs . sort ( function ( a , b ) { return a . length - b . length } )
manifestURLs . forEach ( function ( manifestURL ) {
logger . info ( "Reading manifest " + manifestURL ) ;
var filter = manifests [ manifestURL ] ? new RegExp ( manifests [ manifestURL ] ) : null ;
ReadTopManifest ( manifestURL , [ globalFilter , filter , false ] ) ;
} ) ;
BuildUseCounts ( ) ;
// Filter tests which will be skipped to get a more even distribution when chunking
// tURLs is a temporary array containing all active tests
var tURLs = new Array ( ) ;
var tIDs = new Array ( ) ;
for ( var i = 0 ; i < gURLs . length ; ++ i ) {
if ( gURLs [ i ] . expected == EXPECTED _DEATH )
continue ;
if ( gURLs [ i ] . needsFocus && ! Focus ( ) )
continue ;
if ( gURLs [ i ] . slow && ! gRunSlowTests )
continue ;
tURLs . push ( gURLs [ i ] ) ;
tIDs . push ( gURLs [ i ] . identifier ) ;
}
logger . suiteStart ( tIDs , { "skipped" : gURLs . length - tURLs . length } ) ;
if ( gTotalChunks > 0 && gThisChunk > 0 ) {
// Calculate start and end indices of this chunk if tURLs array were
// divided evenly
var testsPerChunk = tURLs . length / gTotalChunks ;
var start = Math . round ( ( gThisChunk - 1 ) * testsPerChunk ) ;
var end = Math . round ( gThisChunk * testsPerChunk ) ;
// Map these indices onto the gURLs array. This avoids modifying the
// gURLs array which prevents skipped tests from showing up in the log
start = gThisChunk == 1 ? 0 : gURLs . indexOf ( tURLs [ start ] ) ;
end = gThisChunk == gTotalChunks ? gURLs . length : gURLs . indexOf ( tURLs [ end + 1 ] ) - 1 ;
gURLs = gURLs . slice ( start , end ) ;
logger . info ( "Running chunk " + gThisChunk + " out of " + gTotalChunks + " chunks. " +
"tests " + ( start + 1 ) + "-" + end + "/" + gURLs . length ) ;
}
if ( gShuffle ) {
Shuffle ( gURLs ) ;
}
gTotalTests = gURLs . length ;
if ( ! gTotalTests )
throw "No tests to run" ;
gURICanvases = { } ;
StartCurrentTest ( ) ;
} catch ( ex ) {
//gBrowser.loadURI('data:text/plain,' + ex);
++ gTestResults . Exception ;
logger . error ( "EXCEPTION: " + ex ) ;
DoneTests ( ) ;
}
}
function OnRefTestUnload ( )
{
let plugin1 = getTestPlugin ( "Test Plug-in" ) ;
let plugin2 = getTestPlugin ( "Second Test Plug-in" ) ;
if ( plugin1 && plugin2 ) {
plugin1 . enabledState = gTestPluginEnabledStates [ 0 ] ;
plugin2 . enabledState = gTestPluginEnabledStates [ 1 ] ;
} else {
logger . warning ( "Failed to get test plugin tags." ) ;
}
}
// Read all available data from an input stream and return it
// as a string.
function getStreamContent ( inputStream )
{
var streamBuf = "" ;
var sis = CC [ "@mozilla.org/scriptableinputstream;1" ] .
createInstance ( CI . nsIScriptableInputStream ) ;
sis . init ( inputStream ) ;
var available ;
while ( ( available = sis . available ( ) ) != 0 ) {
streamBuf += sis . read ( available ) ;
}
return streamBuf ;
}
// Build the sandbox for fails-if(), etc., condition evaluation.
function BuildConditionSandbox ( aURL ) {
var sandbox = new Components . utils . Sandbox ( aURL . spec ) ;
var xr = CC [ NS _XREAPPINFO _CONTRACTID ] . getService ( CI . nsIXULRuntime ) ;
var appInfo = CC [ NS _XREAPPINFO _CONTRACTID ] . getService ( CI . nsIXULAppInfo ) ;
sandbox . isDebugBuild = gDebug . isDebugBuild ;
// xr.XPCOMABI throws exception for configurations without full ABI
// support (mobile builds on ARM)
var XPCOMABI = "" ;
try {
XPCOMABI = xr . XPCOMABI ;
} catch ( e ) { }
sandbox . xulRuntime = CU . cloneInto ( { widgetToolkit : xr . widgetToolkit , OS : xr . OS , XPCOMABI : XPCOMABI } , sandbox ) ;
var testRect = gBrowser . getBoundingClientRect ( ) ;
sandbox . smallScreen = false ;
if ( gContainingWindow . innerWidth < 800 || gContainingWindow . innerHeight < 1000 ) {
sandbox . smallScreen = true ;
}
var gfxInfo = ( NS _GFXINFO _CONTRACTID in CC ) && CC [ NS _GFXINFO _CONTRACTID ] . getService ( CI . nsIGfxInfo ) ;
let readGfxInfo = function ( obj , key ) {
if ( gContentGfxInfo && ( key in gContentGfxInfo ) ) {
return gContentGfxInfo [ key ] ;
}
return obj [ key ] ;
}
try {
sandbox . d2d = readGfxInfo ( gfxInfo , "D2DEnabled" ) ;
sandbox . dwrite = readGfxInfo ( gfxInfo , "DWriteEnabled" ) ;
} catch ( e ) {
sandbox . d2d = false ;
sandbox . dwrite = false ;
}
var info = gfxInfo . getInfo ( ) ;
var canvasBackend = readGfxInfo ( info , "AzureCanvasBackend" ) ;
var contentBackend = readGfxInfo ( info , "AzureContentBackend" ) ;
var canvasAccelerated = readGfxInfo ( info , "AzureCanvasAccelerated" ) ;
sandbox . azureCairo = canvasBackend == "cairo" ;
sandbox . azureQuartz = canvasBackend == "quartz" ;
sandbox . azureSkia = canvasBackend == "skia" ;
sandbox . skiaContent = contentBackend == "skia" ;
sandbox . azureSkiaGL = canvasAccelerated ; // FIXME: assumes GL right now
// true if we are using the same Azure backend for rendering canvas and content
sandbox . contentSameGfxBackendAsCanvas = contentBackend == canvasBackend
|| ( contentBackend == "none" && canvasBackend == "cairo" ) ;
sandbox . layersGPUAccelerated =
gWindowUtils . layerManagerType != "Basic" ;
sandbox . d3d11 =
gWindowUtils . layerManagerType == "Direct3D 11" ;
sandbox . d3d9 =
gWindowUtils . layerManagerType == "Direct3D 9" ;
sandbox . layersOpenGL =
gWindowUtils . layerManagerType == "OpenGL" ;
sandbox . layersOMTC =
gWindowUtils . layerManagerRemote == true ;
// Shortcuts for widget toolkits.
2018-05-13 22:46:04 +02:00
sandbox . B2G = false ;
2018-01-19 03:59:58 +08:00
sandbox . Android = xr . OS == "Android" && ! sandbox . B2G ;
sandbox . cocoaWidget = xr . widgetToolkit == "cocoa" ;
sandbox . gtkWidget = xr . widgetToolkit == "gtk2"
|| xr . widgetToolkit == "gtk3" ;
sandbox . qtWidget = xr . widgetToolkit == "qt" ;
sandbox . winWidget = xr . widgetToolkit == "windows" ;
// Scrollbars that are semi-transparent. See bug 1169666.
sandbox . transparentScrollbars = xr . widgetToolkit == "gtk3" ;
if ( sandbox . Android ) {
var sysInfo = CC [ "@mozilla.org/system-info;1" ] . getService ( CI . nsIPropertyBag2 ) ;
// This is currently used to distinguish Android 4.0.3 (SDK version 15)
// and later from Android 2.x
sandbox . AndroidVersion = sysInfo . getPropertyAsInt32 ( "version" ) ;
}
# if MOZ _ASAN
sandbox . AddressSanitizer = true ;
# else
sandbox . AddressSanitizer = false ;
# endif
# if MOZ _WEBRTC
sandbox . webrtc = true ;
# else
sandbox . webrtc = false ;
# endif
var hh = CC [ NS _NETWORK _PROTOCOL _CONTRACTID _PREFIX + "http" ] .
getService ( CI . nsIHttpProtocolHandler ) ;
var httpProps = [ "userAgent" , "appName" , "appVersion" , "vendor" ,
"vendorSub" , "product" , "productSub" , "platform" ,
"oscpu" , "language" , "misc" ] ;
sandbox . http = new sandbox . Object ( ) ;
httpProps . forEach ( ( x ) => sandbox . http [ x ] = hh [ x ] ) ;
// Set OSX to be the Mac OS X version, as an integer, or undefined
// for other platforms. The integer is formed by 100 times the
// major version plus the minor version, so 1006 for 10.6, 1010 for
// 10.10, etc.
var osxmatch = /Mac OS X (\d+).(\d+)$/ . exec ( hh . oscpu ) ;
sandbox . OSX = osxmatch ? parseInt ( osxmatch [ 1 ] ) * 100 + parseInt ( osxmatch [ 2 ] ) : undefined ;
// see if we have the test plugin available,
// and set a sandox prop accordingly
var navigator = gContainingWindow . navigator ;
var testPlugin = navigator . plugins [ "Test Plug-in" ] ;
sandbox . haveTestPlugin = ! ! testPlugin ;
// Set a flag on sandbox if the windows default theme is active
sandbox . windowsDefaultTheme = gContainingWindow . matchMedia ( "(-moz-windows-default-theme)" ) . matches ;
var prefs = CC [ "@mozilla.org/preferences-service;1" ] .
getService ( CI . nsIPrefBranch ) ;
try {
sandbox . nativeThemePref = ! prefs . getBoolPref ( "mozilla.widget.disable-native-theme" ) ;
} catch ( e ) {
sandbox . nativeThemePref = true ;
}
sandbox . prefs = CU . cloneInto ( {
getBoolPref : function ( p ) { return prefs . getBoolPref ( p ) ; } ,
getIntPref : function ( p ) { return prefs . getIntPref ( p ) ; }
} , sandbox , { cloneFunctions : true } ) ;
// Tests shouldn't care about this except for when they need to
// crash the content process
sandbox . browserIsRemote = gBrowserIsRemote ;
sandbox . Mulet = gB2GisMulet ;
try {
sandbox . asyncPan = gContainingWindow . document . docShell . asyncPanZoomEnabled ;
} catch ( e ) {
sandbox . asyncPan = false ;
}
if ( ! gDumpedConditionSandbox ) {
logger . info ( "Dumping JSON representation of sandbox" ) ;
logger . info ( JSON . stringify ( CU . waiveXrays ( sandbox ) ) ) ;
gDumpedConditionSandbox = true ;
}
// Graphics features
sandbox . usesRepeatResampling = sandbox . d2d ;
return sandbox ;
}
function AddPrefSettings ( aWhere , aPrefName , aPrefValExpression , aSandbox , aTestPrefSettings , aRefPrefSettings )
{
var prefVal = Components . utils . evalInSandbox ( "(" + aPrefValExpression + ")" , aSandbox ) ;
var prefType ;
var valType = typeof ( prefVal ) ;
if ( valType == "boolean" ) {
prefType = PREF _BOOLEAN ;
} else if ( valType == "string" ) {
prefType = PREF _STRING ;
} else if ( valType == "number" && ( parseInt ( prefVal ) == prefVal ) ) {
prefType = PREF _INTEGER ;
} else {
return false ;
}
var setting = { name : aPrefName ,
type : prefType ,
value : prefVal } ;
if ( aWhere != "ref-" ) {
aTestPrefSettings . push ( setting ) ;
}
if ( aWhere != "test-" ) {
aRefPrefSettings . push ( setting ) ;
}
return true ;
}
function ReadTopManifest ( aFileURL , aFilter )
{
var url = gIOService . newURI ( aFileURL , null , null ) ;
if ( ! url )
throw "Expected a file or http URL for the manifest." ;
ReadManifest ( url , EXPECTED _PASS , aFilter ) ;
}
function AddTestItem ( aTest , aFilter )
{
if ( ! aFilter )
aFilter = [ null , [ ] , false ] ;
globalFilter = aFilter [ 0 ] ;
manifestFilter = aFilter [ 1 ] ;
invertManifest = aFilter [ 2 ] ;
if ( ( globalFilter && ! globalFilter . test ( aTest . url1 . spec ) ) ||
( manifestFilter &&
! ( invertManifest ^ manifestFilter . test ( aTest . url1 . spec ) ) ) )
return ;
if ( gFocusFilterMode == FOCUS _FILTER _NEEDS _FOCUS _TESTS &&
! aTest . needsFocus )
return ;
if ( gFocusFilterMode == FOCUS _FILTER _NON _NEEDS _FOCUS _TESTS &&
aTest . needsFocus )
return ;
if ( aTest . url2 !== null )
aTest . identifier = [ aTest . prettyPath , aTest . type , aTest . url2 . spec ] ;
else
aTest . identifier = aTest . prettyPath ;
gURLs . push ( aTest ) ;
}
// Note: If you materially change the reftest manifest parsing,
// please keep the parser in print-manifest-dirs.py in sync.
function ReadManifest ( aURL , inherited _status , aFilter )
{
// Ensure each manifest is only read once. This assumes that manifests that are
// included with an unusual inherited_status or filters will be read via their
// include before they are read directly in the case of a duplicate
if ( gManifestsLoaded . hasOwnProperty ( aURL . spec ) ) {
if ( gManifestsLoaded [ aURL . spec ] === null )
return ;
else
aFilter = [ aFilter [ 0 ] , aFilter [ 1 ] , true ] ;
}
gManifestsLoaded [ aURL . spec ] = aFilter [ 1 ] ;
var secMan = CC [ NS _SCRIPTSECURITYMANAGER _CONTRACTID ]
. getService ( CI . nsIScriptSecurityManager ) ;
var listURL = aURL ;
var channel = NetUtil . newChannel ( { uri : aURL , loadUsingSystemPrincipal : true } ) ;
var inputStream = channel . open2 ( ) ;
if ( channel instanceof Components . interfaces . nsIHttpChannel
&& channel . responseStatus != 200 ) {
logger . error ( "HTTP ERROR : " + channel . responseStatus ) ;
}
var streamBuf = getStreamContent ( inputStream ) ;
inputStream . close ( ) ;
var lines = streamBuf . split ( /\n|\r|\r\n/ ) ;
// Build the sandbox for fails-if(), etc., condition evaluation.
var sandbox = BuildConditionSandbox ( aURL ) ;
var lineNo = 0 ;
var urlprefix = "" ;
var defaultTestPrefSettings = [ ] , defaultRefPrefSettings = [ ] ;
for ( var str of lines ) {
++ lineNo ;
if ( str . charAt ( 0 ) == "#" )
continue ; // entire line was a comment
var i = str . search ( /\s+#/ ) ;
if ( i >= 0 )
str = str . substring ( 0 , i ) ;
// strip leading and trailing whitespace
str = str . replace ( /^\s*/ , '' ) . replace ( /\s*$/ , '' ) ;
if ( ! str || str == "" )
continue ;
var items = str . split ( /\s+/ ) ; // split on whitespace
if ( items [ 0 ] == "url-prefix" ) {
if ( items . length != 2 )
throw "url-prefix requires one url in manifest file " + aURL . spec + " line " + lineNo ;
urlprefix = items [ 1 ] ;
continue ;
}
if ( items [ 0 ] == "default-preferences" ) {
var m ;
var item ;
defaultTestPrefSettings = [ ] ;
defaultRefPrefSettings = [ ] ;
items . shift ( ) ;
while ( ( item = items . shift ( ) ) ) {
if ( ! ( m = item . match ( gPrefItemRE ) ) ) {
throw "Unexpected item in default-preferences list in manifest file " + aURL . spec + " line " + lineNo ;
}
if ( ! AddPrefSettings ( m [ 1 ] , m [ 2 ] , m [ 3 ] , sandbox , defaultTestPrefSettings , defaultRefPrefSettings ) ) {
throw "Error in pref value in manifest file " + aURL . spec + " line " + lineNo ;
}
}
continue ;
}
var expected _status = EXPECTED _PASS ;
var allow _silent _fail = false ;
var minAsserts = 0 ;
var maxAsserts = 0 ;
var needs _focus = false ;
var slow = false ;
var testPrefSettings = defaultTestPrefSettings . concat ( ) ;
var refPrefSettings = defaultRefPrefSettings . concat ( ) ;
var fuzzy _max _delta = 2 ;
var fuzzy _max _pixels = 1 ;
var chaosMode = false ;
while ( items [ 0 ] . match ( /^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy|chaos-mode)/ ) ) {
var item = items . shift ( ) ;
var stat ;
var cond ;
var m = item . match ( /^(fails|random|skip|silentfail)-if(\(.*\))$/ ) ;
if ( m ) {
stat = m [ 1 ] ;
// Note: m[2] contains the parentheses, and we want them.
cond = Components . utils . evalInSandbox ( m [ 2 ] , sandbox ) ;
} else if ( item . match ( /^(fails|random|skip)$/ ) ) {
stat = item ;
cond = true ;
} else if ( item == "needs-focus" ) {
needs _focus = true ;
cond = false ;
} else if ( ( m = item . match ( /^asserts\((\d+)(-\d+)?\)$/ ) ) ) {
cond = false ;
minAsserts = Number ( m [ 1 ] ) ;
maxAsserts = ( m [ 2 ] == undefined ) ? minAsserts
: Number ( m [ 2 ] . substring ( 1 ) ) ;
} else if ( ( m = item . match ( /^asserts-if\((.*?),(\d+)(-\d+)?\)$/ ) ) ) {
cond = false ;
if ( Components . utils . evalInSandbox ( "(" + m [ 1 ] + ")" , sandbox ) ) {
minAsserts = Number ( m [ 2 ] ) ;
maxAsserts =
( m [ 3 ] == undefined ) ? minAsserts
: Number ( m [ 3 ] . substring ( 1 ) ) ;
}
} else if ( item == "slow" ) {
cond = false ;
slow = true ;
} else if ( ( m = item . match ( /^require-or\((.*?)\)$/ ) ) ) {
var args = m [ 1 ] . split ( /,/ ) ;
if ( args . length != 2 ) {
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": wrong number of args to require-or" ;
}
var [ precondition _str , fallback _action ] = args ;
var preconditions = precondition _str . split ( /&&/ ) ;
cond = false ;
for ( var precondition of preconditions ) {
if ( precondition === "debugMode" ) {
// Currently unimplemented. Requires asynchronous
// JSD call + getting an event while no JS is running
stat = fallback _action ;
cond = true ;
break ;
} else if ( precondition === "true" ) {
// For testing
} else {
// Unknown precondition. Assume it is unimplemented.
stat = fallback _action ;
cond = true ;
break ;
}
}
} else if ( ( m = item . match ( /^slow-if\((.*?)\)$/ ) ) ) {
cond = false ;
if ( Components . utils . evalInSandbox ( "(" + m [ 1 ] + ")" , sandbox ) )
slow = true ;
} else if ( item == "silentfail" ) {
cond = false ;
allow _silent _fail = true ;
} else if ( ( m = item . match ( gPrefItemRE ) ) ) {
cond = false ;
if ( ! AddPrefSettings ( m [ 1 ] , m [ 2 ] , m [ 3 ] , sandbox , testPrefSettings , refPrefSettings ) ) {
throw "Error in pref value in manifest file " + aURL . spec + " line " + lineNo ;
}
} else if ( ( m = item . match ( /^fuzzy\((\d+),(\d+)\)$/ ) ) ) {
cond = false ;
expected _status = EXPECTED _FUZZY ;
fuzzy _max _delta = Number ( m [ 1 ] ) ;
fuzzy _max _pixels = Number ( m [ 2 ] ) ;
} else if ( ( m = item . match ( /^fuzzy-if\((.*?),(\d+),(\d+)\)$/ ) ) ) {
cond = false ;
if ( Components . utils . evalInSandbox ( "(" + m [ 1 ] + ")" , sandbox ) ) {
expected _status = EXPECTED _FUZZY ;
fuzzy _max _delta = Number ( m [ 2 ] ) ;
fuzzy _max _pixels = Number ( m [ 3 ] ) ;
}
} else if ( item == "chaos-mode" ) {
cond = false ;
chaosMode = true ;
} else {
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": unexpected item " + item ;
}
if ( cond ) {
if ( stat == "fails" ) {
expected _status = EXPECTED _FAIL ;
} else if ( stat == "random" ) {
expected _status = EXPECTED _RANDOM ;
} else if ( stat == "skip" ) {
expected _status = EXPECTED _DEATH ;
} else if ( stat == "silentfail" ) {
allow _silent _fail = true ;
}
}
}
expected _status = Math . max ( expected _status , inherited _status ) ;
if ( minAsserts > maxAsserts ) {
throw "Bad range in manifest file " + aURL . spec + " line " + lineNo ;
}
var runHttp = false ;
var httpDepth ;
if ( items [ 0 ] == "HTTP" ) {
runHttp = ( aURL . scheme == "file" ) ; // We can't yet run the local HTTP server
// for non-local reftests.
httpDepth = 0 ;
items . shift ( ) ;
} else if ( items [ 0 ] . match ( /HTTP\(\.\.(\/\.\.)*\)/ ) ) {
// Accept HTTP(..), HTTP(../..), HTTP(../../..), etc.
runHttp = ( aURL . scheme == "file" ) ; // We can't yet run the local HTTP server
// for non-local reftests.
httpDepth = ( items [ 0 ] . length - 5 ) / 3 ;
items . shift ( ) ;
}
// do not prefix the url for include commands or urls specifying
// a protocol
if ( urlprefix && items [ 0 ] != "include" ) {
if ( items . length > 1 && ! items [ 1 ] . match ( gProtocolRE ) ) {
items [ 1 ] = urlprefix + items [ 1 ] ;
}
if ( items . length > 2 && ! items [ 2 ] . match ( gProtocolRE ) ) {
items [ 2 ] = urlprefix + items [ 2 ] ;
}
}
var principal = secMan . createCodebasePrincipal ( aURL , { } ) ;
if ( items [ 0 ] == "include" ) {
if ( items . length != 2 )
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": incorrect number of arguments to include" ;
if ( runHttp )
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": use of include with http" ;
var incURI = gIOService . newURI ( items [ 1 ] , null , listURL ) ;
secMan . checkLoadURIWithPrincipal ( principal , incURI ,
CI . nsIScriptSecurityManager . DISALLOW _SCRIPT ) ;
ReadManifest ( incURI , expected _status , aFilter ) ;
} else if ( items [ 0 ] == TYPE _LOAD ) {
if ( items . length != 2 )
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": incorrect number of arguments to load" ;
if ( expected _status != EXPECTED _PASS &&
expected _status != EXPECTED _DEATH )
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": incorrect known failure type for load test" ;
var [ testURI ] = runHttp
? ServeFiles ( principal , httpDepth ,
listURL , [ items [ 1 ] ] )
: [ gIOService . newURI ( items [ 1 ] , null , listURL ) ] ;
var prettyPath = runHttp
? gIOService . newURI ( items [ 1 ] , null , listURL ) . spec
: testURI . spec ;
secMan . checkLoadURIWithPrincipal ( principal , testURI ,
CI . nsIScriptSecurityManager . DISALLOW _SCRIPT ) ;
AddTestItem ( { type : TYPE _LOAD ,
expected : expected _status ,
allowSilentFail : allow _silent _fail ,
prettyPath : prettyPath ,
minAsserts : minAsserts ,
maxAsserts : maxAsserts ,
needsFocus : needs _focus ,
slow : slow ,
prefSettings1 : testPrefSettings ,
prefSettings2 : refPrefSettings ,
fuzzyMaxDelta : fuzzy _max _delta ,
fuzzyMaxPixels : fuzzy _max _pixels ,
url1 : testURI ,
url2 : null ,
chaosMode : chaosMode } , aFilter ) ;
} else if ( items [ 0 ] == TYPE _SCRIPT ) {
if ( items . length != 2 )
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": incorrect number of arguments to script" ;
var [ testURI ] = runHttp
? ServeFiles ( principal , httpDepth ,
listURL , [ items [ 1 ] ] )
: [ gIOService . newURI ( items [ 1 ] , null , listURL ) ] ;
var prettyPath = runHttp
? gIOService . newURI ( items [ 1 ] , null , listURL ) . spec
: testURI . spec ;
secMan . checkLoadURIWithPrincipal ( principal , testURI ,
CI . nsIScriptSecurityManager . DISALLOW _SCRIPT ) ;
AddTestItem ( { type : TYPE _SCRIPT ,
expected : expected _status ,
allowSilentFail : allow _silent _fail ,
prettyPath : prettyPath ,
minAsserts : minAsserts ,
maxAsserts : maxAsserts ,
needsFocus : needs _focus ,
slow : slow ,
prefSettings1 : testPrefSettings ,
prefSettings2 : refPrefSettings ,
fuzzyMaxDelta : fuzzy _max _delta ,
fuzzyMaxPixels : fuzzy _max _pixels ,
url1 : testURI ,
url2 : null ,
chaosMode : chaosMode } , aFilter ) ;
} else if ( items [ 0 ] == TYPE _REFTEST _EQUAL || items [ 0 ] == TYPE _REFTEST _NOTEQUAL ) {
if ( items . length != 3 )
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": incorrect number of arguments to " + items [ 0 ] ;
var [ testURI , refURI ] = runHttp
? ServeFiles ( principal , httpDepth ,
listURL , [ items [ 1 ] , items [ 2 ] ] )
: [ gIOService . newURI ( items [ 1 ] , null , listURL ) ,
gIOService . newURI ( items [ 2 ] , null , listURL ) ] ;
var prettyPath = runHttp
? gIOService . newURI ( items [ 1 ] , null , listURL ) . spec
: testURI . spec ;
secMan . checkLoadURIWithPrincipal ( principal , testURI ,
CI . nsIScriptSecurityManager . DISALLOW _SCRIPT ) ;
secMan . checkLoadURIWithPrincipal ( principal , refURI ,
CI . nsIScriptSecurityManager . DISALLOW _SCRIPT ) ;
AddTestItem ( { type : items [ 0 ] ,
expected : expected _status ,
allowSilentFail : allow _silent _fail ,
prettyPath : prettyPath ,
minAsserts : minAsserts ,
maxAsserts : maxAsserts ,
needsFocus : needs _focus ,
slow : slow ,
prefSettings1 : testPrefSettings ,
prefSettings2 : refPrefSettings ,
fuzzyMaxDelta : fuzzy _max _delta ,
fuzzyMaxPixels : fuzzy _max _pixels ,
url1 : testURI ,
url2 : refURI ,
chaosMode : chaosMode } , aFilter ) ;
} else {
throw "Error in manifest file " + aURL . spec + " line " + lineNo + ": unknown test type " + items [ 0 ] ;
}
}
}
function AddURIUseCount ( uri )
{
if ( uri == null )
return ;
var spec = uri . spec ;
if ( spec in gURIUseCounts ) {
gURIUseCounts [ spec ] ++ ;
} else {
gURIUseCounts [ spec ] = 1 ;
}
}
function BuildUseCounts ( )
{
if ( gNoCanvasCache ) {
return ;
}
gURIUseCounts = { } ;
for ( var i = 0 ; i < gURLs . length ; ++ i ) {
var url = gURLs [ i ] ;
if ( url . expected != EXPECTED _DEATH &&
( url . type == TYPE _REFTEST _EQUAL ||
url . type == TYPE _REFTEST _NOTEQUAL ) ) {
if ( url . prefSettings1 . length == 0 ) {
AddURIUseCount ( gURLs [ i ] . url1 ) ;
}
if ( url . prefSettings2 . length == 0 ) {
AddURIUseCount ( gURLs [ i ] . url2 ) ;
}
}
}
}
function ServeFiles ( manifestPrincipal , depth , aURL , files )
{
var listURL = aURL . QueryInterface ( CI . nsIFileURL ) ;
var directory = listURL . file . parent ;
// Allow serving a tree that's an ancestor of the directory containing
// the files so that they can use resources in ../ (etc.).
var dirPath = "/" ;
while ( depth > 0 ) {
dirPath = "/" + directory . leafName + dirPath ;
directory = directory . parent ;
-- depth ;
}
gCount ++ ;
var path = "/" + Date . now ( ) + "/" + gCount ;
gServer . registerDirectory ( path + "/" , directory ) ;
var secMan = CC [ NS _SCRIPTSECURITYMANAGER _CONTRACTID ]
. getService ( CI . nsIScriptSecurityManager ) ;
var testbase = gIOService . newURI ( "http://localhost:" + gHttpServerPort +
path + dirPath , null , null ) ;
// Give the testbase URI access to XUL and XBL
Services . perms . add ( testbase , "allowXULXBL" , Services . perms . ALLOW _ACTION ) ;
function FileToURI ( file )
{
// Only serve relative URIs via the HTTP server, not absolute
// ones like about:blank.
var testURI = gIOService . newURI ( file , null , testbase ) ;
// XXX necessary? manifestURL guaranteed to be file, others always HTTP
secMan . checkLoadURIWithPrincipal ( manifestPrincipal , testURI ,
CI . nsIScriptSecurityManager . DISALLOW _SCRIPT ) ;
return testURI ;
}
return files . map ( FileToURI ) ;
}
// Return true iff this window is focused when this function returns.
function Focus ( )
{
var fm = CC [ "@mozilla.org/focus-manager;1" ] . getService ( CI . nsIFocusManager ) ;
fm . focusedWindow = gContainingWindow ;
# ifdef XP _MACOSX
try {
var dock = CC [ "@mozilla.org/widget/macdocksupport;1" ] . getService ( CI . nsIMacDockSupport ) ;
dock . activateApplication ( true ) ;
} catch ( ex ) {
}
# endif // XP_MACOSX
return true ;
}
function Blur ( )
{
// On non-remote reftests, this will transfer focus to the dummy window
// we created to hold focus for non-needs-focus tests. Buggy tests
// (ones which require focus but don't request needs-focus) will then
// fail.
gContainingWindow . blur ( ) ;
}
function StartCurrentTest ( )
{
gTestLog = [ ] ;
// make sure we don't run tests that are expected to kill the browser
while ( gURLs . length > 0 ) {
var test = gURLs [ 0 ] ;
logger . testStart ( test . identifier ) ;
if ( test . expected == EXPECTED _DEATH ) {
++ gTestResults . Skip ;
logger . testEnd ( test . identifier , "SKIP" ) ;
gURLs . shift ( ) ;
} else if ( test . needsFocus && ! Focus ( ) ) {
// FIXME: Marking this as a known fail is dangerous! What
// if it starts failing all the time?
++ gTestResults . Skip ;
logger . testEnd ( test . identifier , "SKIP" , null , "(COULDN'T GET FOCUS)" ) ;
gURLs . shift ( ) ;
} else if ( test . slow && ! gRunSlowTests ) {
++ gTestResults . Slow ;
logger . testEnd ( test . identifier , "SKIP" , null , "(SLOW)" ) ;
gURLs . shift ( ) ;
} else {
break ;
}
}
if ( ( gURLs . length == 0 && gRepeat == 0 ) ||
( gRunUntilFailure && HasUnexpectedResult ( ) ) ) {
RestoreChangedPreferences ( ) ;
DoneTests ( ) ;
} else if ( gURLs . length == 0 && gRepeat > 0 ) {
// Repeat
gRepeat -- ;
StartTests ( ) ;
} else {
if ( gURLs [ 0 ] . chaosMode ) {
gWindowUtils . enterChaosMode ( ) ;
}
if ( ! gURLs [ 0 ] . needsFocus ) {
Blur ( ) ;
}
var currentTest = gTotalTests - gURLs . length ;
gContainingWindow . document . title = "reftest: " + currentTest + " / " + gTotalTests +
" (" + Math . floor ( 100 * ( currentTest / gTotalTests ) ) + "%)" ;
StartCurrentURI ( 1 ) ;
}
}
function StartCurrentURI ( aState )
{
gState = aState ;
gCurrentURL = gURLs [ 0 ] [ "url" + aState ] . spec ;
RestoreChangedPreferences ( ) ;
var prefSettings = gURLs [ 0 ] [ "prefSettings" + aState ] ;
if ( prefSettings . length > 0 ) {
var prefs = Components . classes [ "@mozilla.org/preferences-service;1" ] .
getService ( Components . interfaces . nsIPrefBranch ) ;
var badPref = undefined ;
try {
prefSettings . forEach ( function ( ps ) {
var oldVal ;
if ( ps . type == PREF _BOOLEAN ) {
try {
oldVal = prefs . getBoolPref ( ps . name ) ;
} catch ( e ) {
badPref = "boolean preference '" + ps . name + "'" ;
throw "bad pref" ;
}
} else if ( ps . type == PREF _STRING ) {
try {
oldVal = prefs . getCharPref ( ps . name ) ;
} catch ( e ) {
badPref = "string preference '" + ps . name + "'" ;
throw "bad pref" ;
}
} else if ( ps . type == PREF _INTEGER ) {
try {
oldVal = prefs . getIntPref ( ps . name ) ;
} catch ( e ) {
badPref = "integer preference '" + ps . name + "'" ;
throw "bad pref" ;
}
} else {
throw "internal error - unknown preference type" ;
}
if ( oldVal != ps . value ) {
gPrefsToRestore . push ( { name : ps . name ,
type : ps . type ,
value : oldVal } ) ;
var value = ps . value ;
if ( ps . type == PREF _BOOLEAN ) {
prefs . setBoolPref ( ps . name , value ) ;
} else if ( ps . type == PREF _STRING ) {
prefs . setCharPref ( ps . name , value ) ;
value = '"' + value + '"' ;
} else if ( ps . type == PREF _INTEGER ) {
prefs . setIntPref ( ps . name , value ) ;
}
logger . info ( "SET PREFERENCE pref(" + ps . name + "," + value + ")" ) ;
}
} ) ;
} catch ( e ) {
if ( e == "bad pref" ) {
var test = gURLs [ 0 ] ;
if ( test . expected == EXPECTED _FAIL ) {
logger . testEnd ( test . identifier , "FAIL" , "FAIL" ,
"(SKIPPED; " + badPref + " not known or wrong type)" ) ;
++ gTestResults . Skip ;
} else {
logger . testEnd ( test . identifier , "FAIL" , "PASS" ,
badPref + " not known or wrong type" ) ;
++ gTestResults . UnexpectedFail ;
}
// skip the test that had a bad preference
gURLs . shift ( ) ;
StartCurrentTest ( ) ;
return ;
} else {
throw e ;
}
}
}
if ( prefSettings . length == 0 &&
gURICanvases [ gCurrentURL ] &&
( gURLs [ 0 ] . type == TYPE _REFTEST _EQUAL ||
gURLs [ 0 ] . type == TYPE _REFTEST _NOTEQUAL ) &&
gURLs [ 0 ] . maxAsserts == 0 ) {
// Pretend the document loaded --- RecordResult will notice
// there's already a canvas for this URL
gContainingWindow . setTimeout ( RecordResult , 0 ) ;
} else {
var currentTest = gTotalTests - gURLs . length ;
// Log this to preserve the same overall log format,
// should be removed if the format is updated
gDumpFn ( "REFTEST TEST-LOAD | " + gCurrentURL + " | " + currentTest + " / " + gTotalTests +
" (" + Math . floor ( 100 * ( currentTest / gTotalTests ) ) + "%)\n" ) ;
TestBuffer ( "START " + gCurrentURL ) ;
var type = gURLs [ 0 ] . type
if ( TYPE _SCRIPT == type ) {
SendLoadScriptTest ( gCurrentURL , gLoadTimeout ) ;
} else {
SendLoadTest ( type , gCurrentURL , gLoadTimeout ) ;
}
}
}
function DoneTests ( )
{
logger . suiteEnd ( extra = { 'results' : gTestResults } ) ;
logger . info ( "Slowest test took " + gSlowestTestTime + "ms (" + gSlowestTestURL + ")" ) ;
logger . info ( "Total canvas count = " + gRecycledCanvases . length ) ;
if ( gFailedUseWidgetLayers ) {
LogWidgetLayersFailure ( ) ;
}
function onStopped ( ) {
let appStartup = CC [ "@mozilla.org/toolkit/app-startup;1" ] . getService ( CI . nsIAppStartup ) ;
appStartup . quit ( CI . nsIAppStartup . eForceQuit ) ;
}
if ( gServer ) {
gServer . stop ( onStopped ) ;
}
else {
onStopped ( ) ;
}
}
function UpdateCanvasCache ( url , canvas )
{
var spec = url . spec ;
-- gURIUseCounts [ spec ] ;
if ( gURIUseCounts [ spec ] == 0 ) {
ReleaseCanvas ( canvas ) ;
delete gURICanvases [ spec ] ;
} else if ( gURIUseCounts [ spec ] > 0 ) {
gURICanvases [ spec ] = canvas ;
} else {
throw "Use counts were computed incorrectly" ;
}
}
// Recompute drawWindow flags for every drawWindow operation.
// We have to do this every time since our window can be
// asynchronously resized (e.g. by the window manager, to make
// it fit on screen) at unpredictable times.
// Fortunately this is pretty cheap.
function DoDrawWindow ( ctx , x , y , w , h )
{
var flags = ctx . DRAWWINDOW _DRAW _CARET | ctx . DRAWWINDOW _DRAW _VIEW ;
var testRect = gBrowser . getBoundingClientRect ( ) ;
if ( gIgnoreWindowSize ||
( 0 <= testRect . left &&
0 <= testRect . top &&
gContainingWindow . innerWidth >= testRect . right &&
gContainingWindow . innerHeight >= testRect . bottom ) ) {
// We can use the window's retained layer manager
// because the window is big enough to display the entire
// browser element
flags |= ctx . DRAWWINDOW _USE _WIDGET _LAYERS ;
} else if ( gBrowserIsRemote ) {
logger . error ( gCurrentURL + " | can't drawWindow remote content" ) ;
++ gTestResults . Exception ;
}
if ( gDrawWindowFlags != flags ) {
// Every time the flags change, dump the new state.
gDrawWindowFlags = flags ;
var flagsStr = "DRAWWINDOW_DRAW_CARET | DRAWWINDOW_DRAW_VIEW" ;
if ( flags & ctx . DRAWWINDOW _USE _WIDGET _LAYERS ) {
flagsStr += " | DRAWWINDOW_USE_WIDGET_LAYERS" ;
} else {
// Output a special warning because we need to be able to detect
// this whenever it happens.
LogWidgetLayersFailure ( ) ;
gFailedUseWidgetLayers = true ;
}
logger . info ( "drawWindow flags = " + flagsStr +
"; window size = " + gContainingWindow . innerWidth + "," + gContainingWindow . innerHeight +
"; test browser size = " + testRect . width + "," + testRect . height ) ;
}
TestBuffer ( "DoDrawWindow " + x + "," + y + "," + w + "," + h ) ;
ctx . drawWindow ( gContainingWindow , x , y , w , h , "rgb(255,255,255)" ,
gDrawWindowFlags ) ;
}
function InitCurrentCanvasWithSnapshot ( )
{
TestBuffer ( "Initializing canvas snapshot" ) ;
if ( gURLs [ 0 ] . type == TYPE _LOAD || gURLs [ 0 ] . type == TYPE _SCRIPT ) {
// We don't want to snapshot this kind of test
return false ;
}
if ( ! gCurrentCanvas ) {
gCurrentCanvas = AllocateCanvas ( ) ;
}
var ctx = gCurrentCanvas . getContext ( "2d" ) ;
DoDrawWindow ( ctx , 0 , 0 , gCurrentCanvas . width , gCurrentCanvas . height ) ;
return true ;
}
function UpdateCurrentCanvasForInvalidation ( rects )
{
TestBuffer ( "Updating canvas for invalidation" ) ;
if ( ! gCurrentCanvas ) {
return ;
}
var ctx = gCurrentCanvas . getContext ( "2d" ) ;
for ( var i = 0 ; i < rects . length ; ++ i ) {
var r = rects [ i ] ;
// Set left/top/right/bottom to pixel boundaries
var left = Math . floor ( r . left ) ;
var top = Math . floor ( r . top ) ;
var right = Math . ceil ( r . right ) ;
var bottom = Math . ceil ( r . bottom ) ;
// Clamp the values to the canvas size
left = Math . max ( 0 , Math . min ( left , gCurrentCanvas . width ) ) ;
top = Math . max ( 0 , Math . min ( top , gCurrentCanvas . height ) ) ;
right = Math . max ( 0 , Math . min ( right , gCurrentCanvas . width ) ) ;
bottom = Math . max ( 0 , Math . min ( bottom , gCurrentCanvas . height ) ) ;
ctx . save ( ) ;
ctx . translate ( left , top ) ;
DoDrawWindow ( ctx , left , top , right - left , bottom - top ) ;
ctx . restore ( ) ;
}
}
function UpdateWholeCurrentCanvasForInvalidation ( )
{
TestBuffer ( "Updating entire canvas for invalidation" ) ;
if ( ! gCurrentCanvas ) {
return ;
}
var ctx = gCurrentCanvas . getContext ( "2d" ) ;
DoDrawWindow ( ctx , 0 , 0 , gCurrentCanvas . width , gCurrentCanvas . height ) ;
}
function RecordResult ( testRunTime , errorMsg , scriptResults )
{
TestBuffer ( "RecordResult fired" ) ;
// Keep track of which test was slowest, and how long it took.
if ( testRunTime > gSlowestTestTime ) {
gSlowestTestTime = testRunTime ;
gSlowestTestURL = gCurrentURL ;
}
// Not 'const ...' because of 'EXPECTED_*' value dependency.
var outputs = { } ;
outputs [ EXPECTED _PASS ] = {
true : { s : [ "PASS" , "PASS" ] , n : "Pass" } ,
false : { s : [ "FAIL" , "PASS" ] , n : "UnexpectedFail" }
} ;
outputs [ EXPECTED _FAIL ] = {
true : { s : [ "PASS" , "FAIL" ] , n : "UnexpectedPass" } ,
false : { s : [ "FAIL" , "FAIL" ] , n : "KnownFail" }
} ;
outputs [ EXPECTED _RANDOM ] = {
true : { s : [ "PASS" , "PASS" ] , n : "Random" } ,
false : { s : [ "FAIL" , "FAIL" ] , n : "Random" }
} ;
outputs [ EXPECTED _FUZZY ] = outputs [ EXPECTED _PASS ] ;
var output ;
var extra ;
if ( gURLs [ 0 ] . type == TYPE _LOAD ) {
++ gTestResults . LoadOnly ;
logger . testEnd ( gURLs [ 0 ] . identifier , "PASS" , "PASS" , "(LOAD ONLY)" ) ;
gCurrentCanvas = null ;
FinishTestItem ( ) ;
return ;
}
if ( gURLs [ 0 ] . type == TYPE _SCRIPT ) {
var expected = gURLs [ 0 ] . expected ;
if ( errorMsg ) {
// Force an unexpected failure to alert the test author to fix the test.
expected = EXPECTED _PASS ;
} else if ( scriptResults . length == 0 ) {
// This failure may be due to a JavaScript Engine bug causing
// early termination of the test. If we do not allow silent
// failure, report an error.
if ( ! gURLs [ 0 ] . allowSilentFail )
errorMsg = "No test results reported. (SCRIPT)\n" ;
else
logger . info ( "An expected silent failure occurred" ) ;
}
if ( errorMsg ) {
output = outputs [ expected ] [ false ] ;
extra = { status _msg : output . n } ;
++ gTestResults [ output . n ] ;
logger . testEnd ( gURLs [ 0 ] . identifier , output . s [ 0 ] , output . s [ 1 ] , errorMsg , null , extra ) ;
FinishTestItem ( ) ;
return ;
}
var anyFailed = scriptResults . some ( function ( result ) { return ! result . passed ; } ) ;
var outputPair ;
if ( anyFailed && expected == EXPECTED _FAIL ) {
// If we're marked as expected to fail, and some (but not all) tests
// passed, treat those tests as though they were marked random
// (since we can't tell whether they were really intended to be
// marked failing or not).
outputPair = { true : outputs [ EXPECTED _RANDOM ] [ true ] ,
false : outputs [ expected ] [ false ] } ;
} else {
outputPair = outputs [ expected ] ;
}
var index = 0 ;
scriptResults . forEach ( function ( result ) {
var output = outputPair [ result . passed ] ;
var extra = { status _msg : output . n } ;
++ gTestResults [ output . n ] ;
logger . testEnd ( gURLs [ 0 ] . identifier , output . s [ 0 ] , output . s [ 1 ] ,
result . description + " item " + ( ++ index ) , null , extra ) ;
} ) ;
if ( anyFailed && expected == EXPECTED _PASS ) {
FlushTestBuffer ( ) ;
}
FinishTestItem ( ) ;
return ;
}
if ( gURLs [ 0 ] [ "prefSettings" + gState ] . length == 0 &&
gURICanvases [ gCurrentURL ] ) {
gCurrentCanvas = gURICanvases [ gCurrentURL ] ;
}
if ( gCurrentCanvas == null ) {
logger . error ( gCurrentURL , "program error managing snapshots" ) ;
++ gTestResults . Exception ;
}
if ( gState == 1 ) {
gCanvas1 = gCurrentCanvas ;
} else {
gCanvas2 = gCurrentCanvas ;
}
gCurrentCanvas = null ;
ResetRenderingState ( ) ;
switch ( gState ) {
case 1 :
// First document has been loaded.
// Proceed to load the second document.
CleanUpCrashDumpFiles ( ) ;
StartCurrentURI ( 2 ) ;
break ;
case 2 :
// Both documents have been loaded. Compare the renderings and see
// if the comparison result matches the expected result specified
// in the manifest.
// number of different pixels
var differences ;
// whether the two renderings match:
var equal ;
var maxDifference = { } ;
differences = gWindowUtils . compareCanvases ( gCanvas1 , gCanvas2 , maxDifference ) ;
equal = ( differences == 0 ) ;
// what is expected on this platform (PASS, FAIL, or RANDOM)
var expected = gURLs [ 0 ] . expected ;
if ( maxDifference . value > 0 && maxDifference . value <= gURLs [ 0 ] . fuzzyMaxDelta &&
differences <= gURLs [ 0 ] . fuzzyMaxPixels ) {
if ( equal ) {
throw "Inconsistent result from compareCanvases." ;
}
equal = expected == EXPECTED _FUZZY ;
logger . info ( "REFTEST fuzzy match" ) ;
}
var failedExtraCheck = gFailedNoPaint || gFailedOpaqueLayer || gFailedAssignedLayer ;
// whether the comparison result matches what is in the manifest
var test _passed = ( equal == ( gURLs [ 0 ] . type == TYPE _REFTEST _EQUAL ) ) && ! failedExtraCheck ;
output = outputs [ expected ] [ test _passed ] ;
extra = { status _msg : output . n } ;
++ gTestResults [ output . n ] ;
// It's possible that we failed both an "extra check" and the normal comparison, but we don't
// have a way to annotate these separately, so just print an error for the extra check failures.
if ( failedExtraCheck ) {
var failures = [ ] ;
if ( gFailedNoPaint ) {
failures . push ( "failed reftest-no-paint" ) ;
}
// The gFailed*Messages arrays will contain messages from both the test and the reference.
if ( gFailedOpaqueLayer ) {
failures . push ( "failed reftest-opaque-layer: " + gFailedOpaqueLayerMessages . join ( ", " ) ) ;
}
if ( gFailedAssignedLayer ) {
failures . push ( "failed reftest-assigned-layer: " + gFailedAssignedLayerMessages . join ( ", " ) ) ;
}
var failureString = failures . join ( ", " ) ;
logger . testEnd ( gURLs [ 0 ] . identifier , output . s [ 0 ] , output . s [ 1 ] , failureString , null , extra ) ;
} else {
var message = "image comparison" ;
if ( ! test _passed && expected == EXPECTED _PASS ||
! test _passed && expected == EXPECTED _FUZZY ||
test _passed && expected == EXPECTED _FAIL ) {
if ( ! equal ) {
extra . max _difference = maxDifference . value ;
extra . differences = differences ;
var image1 = gCanvas1 . toDataURL ( ) ;
var image2 = gCanvas2 . toDataURL ( ) ;
extra . reftest _screenshots = [
{ url : gURLs [ 0 ] . identifier [ 0 ] ,
screenshot : image1 . slice ( image1 . indexOf ( "," ) + 1 ) } ,
gURLs [ 0 ] . identifier [ 1 ] ,
{ url : gURLs [ 0 ] . identifier [ 2 ] ,
screenshot : image2 . slice ( image2 . indexOf ( "," ) + 1 ) }
] ;
extra . image1 = image1 ;
extra . image2 = image2 ;
message += ( ", max difference: " + extra . max _difference +
", number of differing pixels: " + differences ) ;
} else {
extra . image1 = gCanvas1 . toDataURL ( ) ;
}
}
logger . testEnd ( gURLs [ 0 ] . identifier , output . s [ 0 ] , output . s [ 1 ] , message , null , extra ) ;
if ( gNoCanvasCache ) {
ReleaseCanvas ( gCanvas1 ) ;
ReleaseCanvas ( gCanvas2 ) ;
} else {
if ( gURLs [ 0 ] . prefSettings1 . length == 0 ) {
UpdateCanvasCache ( gURLs [ 0 ] . url1 , gCanvas1 ) ;
}
if ( gURLs [ 0 ] . prefSettings2 . length == 0 ) {
UpdateCanvasCache ( gURLs [ 0 ] . url2 , gCanvas2 ) ;
}
}
}
if ( ( ! test _passed && expected == EXPECTED _PASS ) || ( test _passed && expected == EXPECTED _FAIL ) ) {
FlushTestBuffer ( ) ;
}
CleanUpCrashDumpFiles ( ) ;
FinishTestItem ( ) ;
break ;
default :
throw "Unexpected state." ;
}
}
function LoadFailed ( why )
{
++ gTestResults . FailedLoad ;
// Once bug 896840 is fixed, this can go away, but for now it will give log
// output that is TBPL starable for bug 789751 and bug 720452.
if ( ! why ) {
logger . error ( "load failed with unknown reason" ) ;
}
logger . testEnd ( gURLs [ 0 ] [ "url" + gState ] . spec , "FAIL" , "PASS" , "load failed: " + why ) ;
FlushTestBuffer ( ) ;
FinishTestItem ( ) ;
}
function RemoveExpectedCrashDumpFiles ( )
{
if ( gExpectingProcessCrash ) {
for ( let crashFilename of gExpectedCrashDumpFiles ) {
let file = gCrashDumpDir . clone ( ) ;
file . append ( crashFilename ) ;
if ( file . exists ( ) ) {
file . remove ( false ) ;
}
}
}
gExpectedCrashDumpFiles . length = 0 ;
}
function FindUnexpectedCrashDumpFiles ( )
{
if ( ! gCrashDumpDir . exists ( ) ) {
return ;
}
let entries = gCrashDumpDir . directoryEntries ;
if ( ! entries ) {
return ;
}
let foundCrashDumpFile = false ;
while ( entries . hasMoreElements ( ) ) {
let file = entries . getNext ( ) . QueryInterface ( CI . nsIFile ) ;
let path = String ( file . path ) ;
if ( path . match ( /\.(dmp|extra)$/ ) && ! gUnexpectedCrashDumpFiles [ path ] ) {
if ( ! foundCrashDumpFile ) {
++ gTestResults . UnexpectedFail ;
foundCrashDumpFile = true ;
logger . testEnd ( gCurrentURL , "FAIL" , "PASS" , "This test left crash dumps behind, but we weren't expecting it to!" ) ;
}
logger . info ( "Found unexpected crash dump file " + path ) ;
gUnexpectedCrashDumpFiles [ path ] = true ;
}
}
}
function CleanUpCrashDumpFiles ( )
{
RemoveExpectedCrashDumpFiles ( ) ;
FindUnexpectedCrashDumpFiles ( ) ;
gExpectingProcessCrash = false ;
}
function FinishTestItem ( )
{
// Replace document with BLANK_URL_FOR_CLEARING in case there are
// assertions when unloading.
logger . debug ( "Loading a blank page" ) ;
// After clearing, content will notify us of the assertion count
// and tests will continue.
SendClear ( ) ;
gFailedNoPaint = false ;
gFailedOpaqueLayer = false ;
gFailedOpaqueLayerMessages = [ ] ;
gFailedAssignedLayer = false ;
gFailedAssignedLayerMessages = [ ] ;
}
function DoAssertionCheck ( numAsserts )
{
if ( gDebug . isDebugBuild ) {
if ( gBrowserIsRemote ) {
// Count chrome-process asserts too when content is out of
// process.
var newAssertionCount = gDebug . assertionCount ;
var numLocalAsserts = newAssertionCount - gAssertionCount ;
gAssertionCount = newAssertionCount ;
numAsserts += numLocalAsserts ;
}
var minAsserts = gURLs [ 0 ] . minAsserts ;
var maxAsserts = gURLs [ 0 ] . maxAsserts ;
var expectedAssertions = "expected " + minAsserts ;
if ( minAsserts != maxAsserts ) {
expectedAssertions += " to " + maxAsserts ;
}
expectedAssertions += " assertions" ;
if ( numAsserts < minAsserts ) {
++ gTestResults . AssertionUnexpectedFixed ;
gDumpFn ( "REFTEST TEST-UNEXPECTED-PASS | " + gURLs [ 0 ] . prettyPath +
" | assertion count " + numAsserts + " is less than " +
expectedAssertions + "\n" ) ;
} else if ( numAsserts > maxAsserts ) {
++ gTestResults . AssertionUnexpected ;
gDumpFn ( "REFTEST TEST-UNEXPECTED-FAIL | " + gURLs [ 0 ] . prettyPath +
" | assertion count " + numAsserts + " is more than " +
expectedAssertions + "\n" ) ;
} else if ( numAsserts != 0 ) {
++ gTestResults . AssertionKnown ;
gDumpFn ( "REFTEST TEST-KNOWN-FAIL | " + gURLs [ 0 ] . prettyPath +
"assertion count " + numAsserts + " matches " +
expectedAssertions + "\n" ) ;
}
}
if ( gURLs [ 0 ] . chaosMode ) {
gWindowUtils . leaveChaosMode ( ) ;
}
// And start the next test.
gURLs . shift ( ) ;
StartCurrentTest ( ) ;
}
function ResetRenderingState ( )
{
SendResetRenderingState ( ) ;
// We would want to clear any viewconfig here, if we add support for it
}
function RestoreChangedPreferences ( )
{
if ( gPrefsToRestore . length > 0 ) {
var prefs = Components . classes [ "@mozilla.org/preferences-service;1" ] .
getService ( Components . interfaces . nsIPrefBranch ) ;
gPrefsToRestore . reverse ( ) ;
gPrefsToRestore . forEach ( function ( ps ) {
var value = ps . value ;
if ( ps . type == PREF _BOOLEAN ) {
prefs . setBoolPref ( ps . name , value ) ;
} else if ( ps . type == PREF _STRING ) {
prefs . setCharPref ( ps . name , value ) ;
value = '"' + value + '"' ;
} else if ( ps . type == PREF _INTEGER ) {
prefs . setIntPref ( ps . name , value ) ;
}
logger . info ( "RESTORE PREFERENCE pref(" + ps . name + "," + value + ")" ) ;
} ) ;
gPrefsToRestore = [ ] ;
}
}
function RegisterMessageListenersAndLoadContentScript ( )
{
gBrowserMessageManager . addMessageListener (
"reftest:AssertionCount" ,
function ( m ) { RecvAssertionCount ( m . json . count ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:ContentReady" ,
function ( m ) { return RecvContentReady ( m . data ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:Exception" ,
function ( m ) { RecvException ( m . json . what ) }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:FailedLoad" ,
function ( m ) { RecvFailedLoad ( m . json . why ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:FailedNoPaint" ,
function ( m ) { RecvFailedNoPaint ( ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:FailedOpaqueLayer" ,
function ( m ) { RecvFailedOpaqueLayer ( m . json . why ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:FailedAssignedLayer" ,
function ( m ) { RecvFailedAssignedLayer ( m . json . why ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:InitCanvasWithSnapshot" ,
function ( m ) { return RecvInitCanvasWithSnapshot ( ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:Log" ,
function ( m ) { RecvLog ( m . json . type , m . json . msg ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:ScriptResults" ,
function ( m ) { RecvScriptResults ( m . json . runtimeMs , m . json . error , m . json . results ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:TestDone" ,
function ( m ) { RecvTestDone ( m . json . runtimeMs ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:UpdateCanvasForInvalidation" ,
function ( m ) { RecvUpdateCanvasForInvalidation ( m . json . rects ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:UpdateWholeCanvasForInvalidation" ,
function ( m ) { RecvUpdateWholeCanvasForInvalidation ( ) ; }
) ;
gBrowserMessageManager . addMessageListener (
"reftest:ExpectProcessCrash" ,
function ( m ) { RecvExpectProcessCrash ( ) ; }
) ;
gBrowserMessageManager . loadFrameScript ( "chrome://reftest/content/reftest-content.js" , true , true ) ;
}
function RecvAssertionCount ( count )
{
DoAssertionCheck ( count ) ;
}
function RecvContentReady ( info )
{
gContentGfxInfo = info . gfx ;
InitAndStartRefTests ( ) ;
return { remote : gBrowserIsRemote } ;
}
function RecvException ( what )
{
logger . error ( gCurrentURL + " | " + what ) ;
++ gTestResults . Exception ;
}
function RecvFailedLoad ( why )
{
LoadFailed ( why ) ;
}
function RecvFailedNoPaint ( )
{
gFailedNoPaint = true ;
}
function RecvFailedOpaqueLayer ( why ) {
gFailedOpaqueLayer = true ;
gFailedOpaqueLayerMessages . push ( why ) ;
}
function RecvFailedAssignedLayer ( why ) {
gFailedAssignedLayer = true ;
gFailedAssignedLayerMessages . push ( why ) ;
}
function RecvInitCanvasWithSnapshot ( )
{
var painted = InitCurrentCanvasWithSnapshot ( ) ;
return { painted : painted } ;
}
function RecvLog ( type , msg )
{
msg = "[CONTENT] " + msg ;
if ( type == "info" ) {
TestBuffer ( msg ) ;
} else if ( type == "warning" ) {
logger . warning ( msg ) ;
} else {
logger . error ( "REFTEST TEST-UNEXPECTED-FAIL | " + gCurrentURL + " | unknown log type " + type + "\n" ) ;
++ gTestResults . Exception ;
}
}
function RecvScriptResults ( runtimeMs , error , results )
{
RecordResult ( runtimeMs , error , results ) ;
}
function RecvTestDone ( runtimeMs )
{
RecordResult ( runtimeMs , '' , [ ] ) ;
}
function RecvUpdateCanvasForInvalidation ( rects )
{
UpdateCurrentCanvasForInvalidation ( rects ) ;
}
function RecvUpdateWholeCanvasForInvalidation ( )
{
UpdateWholeCurrentCanvasForInvalidation ( ) ;
}
function OnProcessCrashed ( subject , topic , data )
{
var id ;
subject = subject . QueryInterface ( CI . nsIPropertyBag2 ) ;
if ( topic == "plugin-crashed" ) {
id = subject . getPropertyAsAString ( "pluginDumpID" ) ;
} else if ( topic == "ipc:content-shutdown" ) {
id = subject . getPropertyAsAString ( "dumpID" ) ;
}
if ( id ) {
gExpectedCrashDumpFiles . push ( id + ".dmp" ) ;
gExpectedCrashDumpFiles . push ( id + ".extra" ) ;
}
}
function RegisterProcessCrashObservers ( )
{
var os = CC [ NS _OBSERVER _SERVICE _CONTRACTID ]
. getService ( CI . nsIObserverService ) ;
os . addObserver ( OnProcessCrashed , "plugin-crashed" , false ) ;
os . addObserver ( OnProcessCrashed , "ipc:content-shutdown" , false ) ;
}
function RecvExpectProcessCrash ( )
{
gExpectingProcessCrash = true ;
}
function SendClear ( )
{
gBrowserMessageManager . sendAsyncMessage ( "reftest:Clear" ) ;
}
function SendLoadScriptTest ( uri , timeout )
{
gBrowserMessageManager . sendAsyncMessage ( "reftest:LoadScriptTest" ,
{ uri : uri , timeout : timeout } ) ;
}
function SendLoadTest ( type , uri , timeout )
{
gBrowserMessageManager . sendAsyncMessage ( "reftest:LoadTest" ,
{ type : type , uri : uri , timeout : timeout }
) ;
}
function SendResetRenderingState ( )
{
gBrowserMessageManager . sendAsyncMessage ( "reftest:ResetRenderingState" ) ;
}