mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Merge inbound to m-c.
This commit is contained in:
commit
f16ab57207
@ -341,6 +341,15 @@ function setupSearchEngine()
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the test harness that we're done loading the page.
|
||||
*/
|
||||
function loadSucceeded()
|
||||
{
|
||||
var event = new CustomEvent("AboutHomeLoadSnippetsSucceeded", {bubbles:true});
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the local snippets from the remote storage, then show them through
|
||||
* showSnippets.
|
||||
@ -350,6 +359,10 @@ function loadSnippets()
|
||||
if (!gSnippetsMap)
|
||||
throw new Error("Snippets map has not properly been initialized");
|
||||
|
||||
// Allow tests to modify the snippets map before using it.
|
||||
var event = new CustomEvent("AboutHomeLoadSnippets", {bubbles:true});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
// Check cached snippets version.
|
||||
let cachedVersion = gSnippetsMap.get("snippets-cached-version") || 0;
|
||||
let currentVersion = document.documentElement.getAttribute("snippetsVersion");
|
||||
@ -370,6 +383,7 @@ function loadSnippets()
|
||||
xhr.open("GET", updateURL, true);
|
||||
} catch (ex) {
|
||||
showSnippets();
|
||||
loadSucceeded();
|
||||
return;
|
||||
}
|
||||
// Even if fetching should fail we don't want to spam the server, thus
|
||||
@ -385,10 +399,12 @@ function loadSnippets()
|
||||
gSnippetsMap.set("snippets-cached-version", currentVersion);
|
||||
}
|
||||
showSnippets();
|
||||
loadSucceeded();
|
||||
};
|
||||
xhr.send(null);
|
||||
} else {
|
||||
showSnippets();
|
||||
loadSucceeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2753,6 +2753,10 @@
|
||||
onget="return this.mCurrentBrowser.currentURI;"
|
||||
readonly="true"/>
|
||||
|
||||
<property name="finder"
|
||||
onget="return this.mCurrentBrowser.finder"
|
||||
readonly="true"/>
|
||||
|
||||
<property name="docShell"
|
||||
onget="return this.mCurrentBrowser.docShell"
|
||||
readonly="true"/>
|
||||
|
@ -17,6 +17,7 @@ registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
|
||||
Services.prefs.clearUserPref("browser.rights.override");
|
||||
Services.prefs.clearUserPref("browser.rights." + gRightsVersion + ".shown");
|
||||
Services.prefs.clearUserPref("browser.aboutHomeSnippets.updateUrl");
|
||||
});
|
||||
|
||||
let gTests = [
|
||||
@ -338,20 +339,25 @@ function test()
|
||||
for (let test of gTests) {
|
||||
info(test.desc);
|
||||
|
||||
// Make sure we don't try to load snippets from the network.
|
||||
Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl", "nonexistent://test");
|
||||
|
||||
if (test.beforeRun)
|
||||
yield test.beforeRun();
|
||||
|
||||
let tab = yield promiseNewTabLoadEvent("about:home", "DOMContentLoaded");
|
||||
// Create a tab to run the test.
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank");
|
||||
|
||||
// Add an event handler to modify the snippets map once it's ready.
|
||||
let snippetsPromise = promiseSetupSnippetsMap(tab, test.setup);
|
||||
|
||||
// Start loading about:home and wait for it to complete.
|
||||
yield promiseTabLoadEvent(tab, "about:home", "AboutHomeLoadSnippetsSucceeded");
|
||||
|
||||
// This promise should already be resolved since the page is done,
|
||||
// but we still want to get the snippets map out of it.
|
||||
let snippetsMap = yield snippetsPromise;
|
||||
|
||||
// Must wait for both the snippets map and the browser attributes, since
|
||||
// can't guess the order they will happen.
|
||||
// So, start listening now, but verify the promise is fulfilled only
|
||||
// after the snippets map setup.
|
||||
let promise = promiseBrowserAttributes(tab);
|
||||
// Prepare the snippets map with default values, then run the test setup.
|
||||
let snippetsMap = yield promiseSetupSnippetsMap(tab, test.setup);
|
||||
// Ensure browser has set attributes already, or wait for them.
|
||||
yield promise;
|
||||
info("Running test");
|
||||
yield test.run(snippetsMap);
|
||||
info("Cleanup");
|
||||
@ -364,29 +370,31 @@ function test()
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new tab and waits for a load event.
|
||||
* Starts a load in an existing tab and waits for it to finish (via some event).
|
||||
*
|
||||
* @param aTab
|
||||
* The tab to load into.
|
||||
* @param aUrl
|
||||
* The url to load in a new tab.
|
||||
* The url to load.
|
||||
* @param aEvent
|
||||
* The load event type to wait for. Defaults to "load".
|
||||
* @return {Promise} resolved when the event is handled. Gets the new tab.
|
||||
* @return {Promise} resolved when the event is handled.
|
||||
*/
|
||||
function promiseNewTabLoadEvent(aUrl, aEventType="load")
|
||||
function promiseTabLoadEvent(aTab, aURL, aEventType="load")
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(aUrl);
|
||||
info("Wait tab event: " + aEventType);
|
||||
tab.linkedBrowser.addEventListener(aEventType, function load(event) {
|
||||
if (event.originalTarget != tab.linkedBrowser.contentDocument ||
|
||||
aTab.linkedBrowser.addEventListener(aEventType, function load(event) {
|
||||
if (event.originalTarget != aTab.linkedBrowser.contentDocument ||
|
||||
event.target.location.href == "about:blank") {
|
||||
info("skipping spurious load event");
|
||||
return;
|
||||
}
|
||||
tab.linkedBrowser.removeEventListener(aEventType, load, true);
|
||||
aTab.linkedBrowser.removeEventListener(aEventType, load, true);
|
||||
info("Tab event received: " + aEventType);
|
||||
deferred.resolve(tab);
|
||||
}, true);
|
||||
deferred.resolve();
|
||||
}, true, true);
|
||||
aTab.linkedBrowser.loadURI(aURL);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
@ -403,28 +411,32 @@ function promiseNewTabLoadEvent(aUrl, aEventType="load")
|
||||
function promiseSetupSnippetsMap(aTab, aSetupFn)
|
||||
{
|
||||
let deferred = Promise.defer();
|
||||
let cw = aTab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
info("Waiting for snippets map");
|
||||
cw.ensureSnippetsMapThen(function (aSnippetsMap) {
|
||||
info("Got snippets map: " +
|
||||
"{ last-update: " + aSnippetsMap.get("snippets-last-update") +
|
||||
", cached-version: " + aSnippetsMap.get("snippets-cached-version") +
|
||||
" }");
|
||||
// Don't try to update.
|
||||
aSnippetsMap.set("snippets-last-update", Date.now());
|
||||
aSnippetsMap.set("snippets-cached-version", AboutHomeUtils.snippetsVersion);
|
||||
// Clear snippets.
|
||||
aSnippetsMap.delete("snippets");
|
||||
aSetupFn(aSnippetsMap);
|
||||
// Must be sure to continue after the page snippets map setup.
|
||||
executeSoon(function() deferred.resolve(aSnippetsMap));
|
||||
});
|
||||
aTab.linkedBrowser.addEventListener("AboutHomeLoadSnippets", function load(event) {
|
||||
aTab.linkedBrowser.removeEventListener("AboutHomeLoadSnippets", load, true);
|
||||
|
||||
let cw = aTab.linkedBrowser.contentWindow.wrappedJSObject;
|
||||
// The snippets should already be ready by this point. Here we're
|
||||
// just obtaining a reference to the snippets map.
|
||||
cw.ensureSnippetsMapThen(function (aSnippetsMap) {
|
||||
info("Got snippets map: " +
|
||||
"{ last-update: " + aSnippetsMap.get("snippets-last-update") +
|
||||
", cached-version: " + aSnippetsMap.get("snippets-cached-version") +
|
||||
" }");
|
||||
// Don't try to update.
|
||||
aSnippetsMap.set("snippets-last-update", Date.now());
|
||||
aSnippetsMap.set("snippets-cached-version", AboutHomeUtils.snippetsVersion);
|
||||
// Clear snippets.
|
||||
aSnippetsMap.delete("snippets");
|
||||
aSetupFn(aSnippetsMap);
|
||||
deferred.resolve(aSnippetsMap);
|
||||
});
|
||||
}, true, true);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the attributes being set by browser.js and overwrites snippetsURL
|
||||
* to ensure we won't try to hit the network and we can force xhr to throw.
|
||||
* Waits for the attributes being set by browser.js.
|
||||
*
|
||||
* @param aTab
|
||||
* The tab containing about:home.
|
||||
@ -435,16 +447,10 @@ function promiseBrowserAttributes(aTab)
|
||||
let deferred = Promise.defer();
|
||||
|
||||
let docElt = aTab.linkedBrowser.contentDocument.documentElement;
|
||||
//docElt.setAttribute("snippetsURL", "nonexistent://test");
|
||||
let observer = new MutationObserver(function (mutations) {
|
||||
for (let mutation of mutations) {
|
||||
info("Got attribute mutation: " + mutation.attributeName +
|
||||
" from " + mutation.oldValue);
|
||||
if (mutation.attributeName == "snippetsURL" &&
|
||||
docElt.getAttribute("snippetsURL") != "nonexistent://test") {
|
||||
docElt.setAttribute("snippetsURL", "nonexistent://test");
|
||||
}
|
||||
|
||||
// Now we just have to wait for the last attribute.
|
||||
if (mutation.attributeName == "searchEngineName") {
|
||||
info("Remove attributes observer");
|
||||
|
@ -41,7 +41,11 @@ function nextTest() {
|
||||
testFindDisabled(url, nextTest);
|
||||
} else {
|
||||
// Make sure the find bar is re-enabled after disabled page is closed.
|
||||
testFindEnabled("about:blank", finish);
|
||||
testFindEnabled("about:blank", function () {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", { });
|
||||
ok(gFindBar.hidden, "Find bar should now be hidden");
|
||||
finish();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,26 +178,32 @@ let AboutHome = {
|
||||
// Send all the chrome-privileged data needed by about:home. This
|
||||
// gets re-sent when the search engine changes.
|
||||
sendAboutHomeData: function(target) {
|
||||
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
|
||||
getService(Ci.nsISessionStore);
|
||||
let data = {
|
||||
showRestoreLastSession: ss.canRestoreLastSession,
|
||||
snippetsURL: AboutHomeUtils.snippetsURL,
|
||||
showKnowYourRights: AboutHomeUtils.showKnowYourRights,
|
||||
snippetsVersion: AboutHomeUtils.snippetsVersion
|
||||
};
|
||||
let wrapper = {};
|
||||
Components.utils.import("resource:///modules/sessionstore/SessionStore.jsm",
|
||||
wrapper);
|
||||
let ss = wrapper.SessionStore;
|
||||
ss.promiseInitialized.then(function() {
|
||||
let data = {
|
||||
showRestoreLastSession: ss.canRestoreLastSession,
|
||||
snippetsURL: AboutHomeUtils.snippetsURL,
|
||||
showKnowYourRights: AboutHomeUtils.showKnowYourRights,
|
||||
snippetsVersion: AboutHomeUtils.snippetsVersion
|
||||
};
|
||||
|
||||
if (AboutHomeUtils.showKnowYourRights) {
|
||||
// Set pref to indicate we've shown the notification.
|
||||
let currentVersion = Services.prefs.getIntPref("browser.rights.version");
|
||||
Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
|
||||
}
|
||||
if (AboutHomeUtils.showKnowYourRights) {
|
||||
// Set pref to indicate we've shown the notification.
|
||||
let currentVersion = Services.prefs.getIntPref("browser.rights.version");
|
||||
Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
|
||||
}
|
||||
|
||||
if (target) {
|
||||
target.messageManager.sendAsyncMessage("AboutHome:Update", data);
|
||||
} else {
|
||||
let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
|
||||
mm.broadcastAsyncMessage("AboutHome:Update", data);
|
||||
}
|
||||
if (target) {
|
||||
target.messageManager.sendAsyncMessage("AboutHome:Update", data);
|
||||
} else {
|
||||
let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
|
||||
mm.broadcastAsyncMessage("AboutHome:Update", data);
|
||||
}
|
||||
}).then(null, function onError(x) {
|
||||
Cu.reportError("Error in AboutHome.sendAboutHomeData " + x);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
@ -48,6 +48,29 @@ public interface Actions {
|
||||
*/
|
||||
void sendGeckoEvent(String geckoEvent, String data);
|
||||
|
||||
/**
|
||||
* Sends a preferences get event to Gecko.
|
||||
*
|
||||
* @param requestId The id of this request.
|
||||
* @param prefNames The preferences being requested.
|
||||
*/
|
||||
void sendPreferencesGetEvent(int requestId, String[] prefNames);
|
||||
|
||||
/**
|
||||
* Sends a preferences observe event to Gecko.
|
||||
*
|
||||
* @param requestId The id of this request.
|
||||
* @param prefNames The preferences being requested.
|
||||
*/
|
||||
void sendPreferencesObserveEvent(int requestId, String[] prefNames);
|
||||
|
||||
/**
|
||||
* Sends a preferences remove observers event to Gecko.
|
||||
*
|
||||
* @param requestId The id of this request.
|
||||
*/
|
||||
void sendPreferencesRemoveObserversEvent(int requestid);
|
||||
|
||||
/**
|
||||
* Listens for a gecko event to be sent from the Gecko instance.
|
||||
* The returned object can be used to test if the event has been
|
||||
|
@ -44,6 +44,9 @@ public class FennecNativeActions implements Actions {
|
||||
private Method mRegisterEventListener;
|
||||
private Method mUnregisterEventListener;
|
||||
private Method mBroadcastEvent;
|
||||
private Method mPreferencesGetEvent;
|
||||
private Method mPreferencesObserveEvent;
|
||||
private Method mPreferencesRemoveObserversEvent;
|
||||
private Method mSetDrawListener;
|
||||
private Method mQuerySql;
|
||||
private Object mRobocopApi;
|
||||
@ -66,6 +69,9 @@ public class FennecNativeActions implements Actions {
|
||||
mRegisterEventListener = mApiClass.getMethod("registerEventListener", String.class, mEventListenerClass);
|
||||
mUnregisterEventListener = mApiClass.getMethod("unregisterEventListener", String.class, mEventListenerClass);
|
||||
mBroadcastEvent = mApiClass.getMethod("broadcastEvent", String.class, String.class);
|
||||
mPreferencesGetEvent = mApiClass.getMethod("preferencesGetEvent", Integer.TYPE, String[].class);
|
||||
mPreferencesObserveEvent = mApiClass.getMethod("preferencesObserveEvent", Integer.TYPE, String[].class);
|
||||
mPreferencesRemoveObserversEvent = mApiClass.getMethod("preferencesRemoveObserversEvent", Integer.TYPE);
|
||||
mSetDrawListener = mApiClass.getMethod("setDrawListener", mDrawListenerClass);
|
||||
mQuerySql = mApiClass.getMethod("querySql", String.class, String.class);
|
||||
|
||||
@ -265,6 +271,34 @@ public class FennecNativeActions implements Actions {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPreferencesEvent(Method method, int requestId, String[] prefNames) {
|
||||
try {
|
||||
method.invoke(mRobocopApi, requestId, prefNames);
|
||||
} catch (IllegalAccessException e) {
|
||||
FennecNativeDriver.log(LogLevel.ERROR, e);
|
||||
} catch (InvocationTargetException e) {
|
||||
FennecNativeDriver.log(LogLevel.ERROR, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendPreferencesGetEvent(int requestId, String[] prefNames) {
|
||||
sendPreferencesEvent(mPreferencesGetEvent, requestId, prefNames);
|
||||
}
|
||||
|
||||
public void sendPreferencesObserveEvent(int requestId, String[] prefNames) {
|
||||
sendPreferencesEvent(mPreferencesObserveEvent, requestId, prefNames);
|
||||
}
|
||||
|
||||
public void sendPreferencesRemoveObserversEvent(int requestId) {
|
||||
try {
|
||||
mPreferencesRemoveObserversEvent.invoke(mRobocopApi, requestId);
|
||||
} catch (IllegalAccessException e) {
|
||||
FennecNativeDriver.log(LogLevel.ERROR, e);
|
||||
} catch (InvocationTargetException e) {
|
||||
FennecNativeDriver.log(LogLevel.ERROR, e);
|
||||
}
|
||||
}
|
||||
|
||||
class DrawListenerProxy implements InvocationHandler {
|
||||
private final PaintExpecter mPaintExpecter;
|
||||
|
||||
|
@ -217,7 +217,7 @@ class FileKind(object):
|
||||
|
||||
def get_all_filenames():
|
||||
'''Get a list of all the files in the (Mercurial or Git) repository.'''
|
||||
cmds = [['hg', 'manifest', '-q'], ['git', 'ls-files']]
|
||||
cmds = [['hg', 'manifest', '-q'], ['git', 'ls-files', '--full-name', '../..']]
|
||||
for cmd in cmds:
|
||||
try:
|
||||
all_filenames = subprocess.check_output(cmd, universal_newlines=True,
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
||||
#define NS_ICANVASRENDERINGCONTEXTINTERNAL_IID \
|
||||
{ 0x9a6a5bdf, 0x1261, 0x4057, \
|
||||
{ 0x85, 0xcc, 0xaf, 0x97, 0x6c, 0x36, 0x99, 0xa9 } }
|
||||
{ 0x8b8da863, 0xd151, 0x4014, \
|
||||
{ 0x8b, 0xdc, 0x62, 0xb5, 0x0d, 0xc0, 0x2b, 0x62 } }
|
||||
|
||||
class gfxContext;
|
||||
class gfxASurface;
|
||||
@ -65,9 +65,6 @@ public:
|
||||
gfxPattern::GraphicsFilter aFilter,
|
||||
uint32_t aFlags = RenderFlagPremultAlpha) = 0;
|
||||
|
||||
// Creates an image buffer. Returns null on failure.
|
||||
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat) = 0;
|
||||
|
||||
// Gives you a stream containing the image represented by this context.
|
||||
// The format is given in aMimeTime, for example "image/png".
|
||||
//
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "ImageEncoder.h"
|
||||
#include "imgIEncoder.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxASurface.h"
|
||||
@ -1036,71 +1036,71 @@ CanvasRenderingContext2D::Render(gfxContext *ctx, gfxPattern::GraphicsFilter aFi
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::GetImageBuffer(uint8_t** aImageBuffer,
|
||||
int32_t* aFormat)
|
||||
NS_IMETHODIMP
|
||||
CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
|
||||
const PRUnichar *aEncoderOptions,
|
||||
nsIInputStream **aStream)
|
||||
{
|
||||
*aImageBuffer = nullptr;
|
||||
*aFormat = 0;
|
||||
|
||||
nsRefPtr<gfxASurface> surface;
|
||||
nsresult rv = GetThebesSurface(getter_AddRefs(surface));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
EnsureTarget();
|
||||
if (!IsTargetValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxASurface> surface;
|
||||
|
||||
if (NS_FAILED(GetThebesSurface(getter_AddRefs(surface)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
|
||||
static const fallible_t fallible = fallible_t();
|
||||
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
|
||||
nsAutoArrayPtr<char> conid(new (fallible) char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
|
||||
|
||||
if (!conid) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
strcpy(conid, encoderPrefix);
|
||||
strcat(conid, aMimeType);
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
|
||||
if (!encoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsAutoArrayPtr<uint8_t> imageBuffer(new (fallible) uint8_t[mWidth * mHeight * 4]);
|
||||
if (!imageBuffer) {
|
||||
return;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgsurf =
|
||||
new gfxImageSurface(imageBuffer,
|
||||
new gfxImageSurface(imageBuffer.get(),
|
||||
gfxIntSize(mWidth, mHeight),
|
||||
mWidth * 4,
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
|
||||
if (!imgsurf || imgsurf->CairoStatus()) {
|
||||
delete[] imageBuffer;
|
||||
return;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
|
||||
|
||||
if (!ctx || ctx->HasError()) {
|
||||
delete[] imageBuffer;
|
||||
return;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx->SetSource(surface, gfxPoint(0, 0));
|
||||
ctx->Paint();
|
||||
|
||||
*aImageBuffer = imageBuffer;
|
||||
*aFormat = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
}
|
||||
rv = encoder->InitFromData(imageBuffer.get(),
|
||||
mWidth * mHeight * 4, mWidth, mHeight, mWidth * 4,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB,
|
||||
nsDependentString(aEncoderOptions));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_IMETHODIMP
|
||||
CanvasRenderingContext2D::GetInputStream(const char *aMimeType,
|
||||
const PRUnichar *aEncoderOptions,
|
||||
nsIInputStream **aStream)
|
||||
{
|
||||
uint8_t* imageBuffer = nullptr;
|
||||
int32_t format = 0;
|
||||
GetImageBuffer(&imageBuffer, &format);
|
||||
if (!imageBuffer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCString enccid("@mozilla.org/image/encoder;2?type=");
|
||||
enccid += aMimeType;
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
|
||||
if (!encoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
|
||||
encoder, aEncoderOptions, aStream);
|
||||
return CallQueryInterface(encoder, aStream);
|
||||
}
|
||||
|
||||
SurfaceFormat
|
||||
@ -3739,9 +3739,6 @@ NS_IMETHODIMP
|
||||
CanvasRenderingContext2D::GetThebesSurface(gfxASurface **surface)
|
||||
{
|
||||
EnsureTarget();
|
||||
if (!IsTargetValid()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxASurface> thebesSurface =
|
||||
gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mTarget);
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
|
||||
#include "mozilla/dom/CanvasPattern.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "imgIEncoder.h"
|
||||
|
||||
class nsXULElement;
|
||||
|
||||
@ -449,8 +448,6 @@ public:
|
||||
|
||||
friend class CanvasRenderingContext2DUserData;
|
||||
|
||||
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
|
||||
|
||||
protected:
|
||||
nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
|
||||
uint32_t aWidth, uint32_t aHeight,
|
||||
|
@ -1,299 +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 "ImageEncoder.h"
|
||||
|
||||
#include "mozilla/dom/CanvasRenderingContext2D.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class EncodingCompleteEvent : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
EncodingCompleteEvent(nsIScriptContext* aScriptContext,
|
||||
nsIThread* aEncoderThread,
|
||||
FileCallback& aCallback)
|
||||
: mImgSize(0)
|
||||
, mType()
|
||||
, mImgData(nullptr)
|
||||
, mScriptContext(aScriptContext)
|
||||
, mEncoderThread(aEncoderThread)
|
||||
, mCallback(&aCallback)
|
||||
{}
|
||||
virtual ~EncodingCompleteEvent() {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsRefPtr<nsDOMMemoryFile> blob =
|
||||
new nsDOMMemoryFile(mImgData, mImgSize, mType);
|
||||
|
||||
if (mScriptContext) {
|
||||
JSContext* jsContext = mScriptContext->GetNativeContext();
|
||||
if (jsContext) {
|
||||
JS_updateMallocCounter(jsContext, mImgSize);
|
||||
}
|
||||
}
|
||||
|
||||
mozilla::ErrorResult rv;
|
||||
mCallback->Call(blob, rv);
|
||||
NS_ENSURE_SUCCESS(rv.ErrorCode(), rv.ErrorCode());
|
||||
|
||||
mEncoderThread->Shutdown();
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
|
||||
void SetMembers(void* aImgData, uint64_t aImgSize, const nsAutoString& aType)
|
||||
{
|
||||
mImgData = aImgData;
|
||||
mImgSize = aImgSize;
|
||||
mType = aType;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t mImgSize;
|
||||
nsAutoString mType;
|
||||
void* mImgData;
|
||||
nsCOMPtr<nsIScriptContext> mScriptContext;
|
||||
nsCOMPtr<nsIThread> mEncoderThread;
|
||||
nsRefPtr<FileCallback> mCallback;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(EncodingCompleteEvent, nsIRunnable);
|
||||
|
||||
class EncodingRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
EncodingRunnable(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
uint8_t* aImageBuffer,
|
||||
imgIEncoder* aEncoder,
|
||||
EncodingCompleteEvent* aEncodingCompleteEvent,
|
||||
int32_t aFormat,
|
||||
const nsIntSize aSize,
|
||||
bool aUsingCustomOptions)
|
||||
: mType(aType)
|
||||
, mOptions(aOptions)
|
||||
, mImageBuffer(aImageBuffer)
|
||||
, mEncoder(aEncoder)
|
||||
, mEncodingCompleteEvent(aEncodingCompleteEvent)
|
||||
, mFormat(aFormat)
|
||||
, mSize(aSize)
|
||||
, mUsingCustomOptions(aUsingCustomOptions)
|
||||
{}
|
||||
virtual ~EncodingRunnable() {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsresult rv = ImageEncoder::ExtractDataInternal(mType,
|
||||
mOptions,
|
||||
mImageBuffer,
|
||||
mFormat,
|
||||
mSize,
|
||||
nullptr,
|
||||
getter_AddRefs(stream),
|
||||
mEncoder);
|
||||
|
||||
// If there are unrecognized custom parse options, we should fall back to
|
||||
// the default values for the encoder without any options at all.
|
||||
if (rv == NS_ERROR_INVALID_ARG && mUsingCustomOptions) {
|
||||
rv = ImageEncoder::ExtractDataInternal(mType,
|
||||
EmptyString(),
|
||||
mImageBuffer,
|
||||
mFormat,
|
||||
mSize,
|
||||
nullptr,
|
||||
getter_AddRefs(stream),
|
||||
mEncoder);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint64_t imgSize;
|
||||
rv = stream->Available(&imgSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(imgSize <= UINT32_MAX, NS_ERROR_FILE_TOO_BIG);
|
||||
|
||||
void* imgData = nullptr;
|
||||
rv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mEncodingCompleteEvent->SetMembers(imgData, imgSize, mType);
|
||||
rv = NS_DispatchToMainThread(mEncodingCompleteEvent, NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
nsAutoString mType;
|
||||
nsAutoString mOptions;
|
||||
nsAutoArrayPtr<uint8_t> mImageBuffer;
|
||||
nsCOMPtr<imgIEncoder> mEncoder;
|
||||
nsRefPtr<EncodingCompleteEvent> mEncodingCompleteEvent;
|
||||
int32_t mFormat;
|
||||
const nsIntSize mSize;
|
||||
bool mUsingCustomOptions;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(EncodingRunnable, nsIRunnable)
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
ImageEncoder::ExtractData(nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
nsIInputStream** aStream)
|
||||
{
|
||||
nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
|
||||
if (!encoder) {
|
||||
return NS_IMAGELIB_ERROR_NO_ENCODER;
|
||||
}
|
||||
|
||||
return ExtractDataInternal(aType, aOptions, nullptr, 0, aSize, aContext,
|
||||
aStream, encoder);
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
ImageEncoder::ExtractDataAsync(nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
bool aUsingCustomOptions,
|
||||
uint8_t* aImageBuffer,
|
||||
int32_t aFormat,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
nsIScriptContext* aScriptContext,
|
||||
FileCallback& aCallback)
|
||||
{
|
||||
nsCOMPtr<imgIEncoder> encoder = ImageEncoder::GetImageEncoder(aType);
|
||||
if (!encoder) {
|
||||
return NS_IMAGELIB_ERROR_NO_ENCODER;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> encoderThread;
|
||||
nsresult rv = NS_NewThread(getter_AddRefs(encoderThread), nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRefPtr<EncodingCompleteEvent> completeEvent =
|
||||
new EncodingCompleteEvent(aScriptContext, encoderThread, aCallback);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event = new EncodingRunnable(aType,
|
||||
aOptions,
|
||||
aImageBuffer,
|
||||
encoder,
|
||||
completeEvent,
|
||||
aFormat,
|
||||
aSize,
|
||||
aUsingCustomOptions);
|
||||
return encoderThread->Dispatch(event, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
/*static*/ nsresult
|
||||
ImageEncoder::GetInputStream(int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
uint8_t* aImageBuffer,
|
||||
int32_t aFormat,
|
||||
imgIEncoder* aEncoder,
|
||||
const PRUnichar* aEncoderOptions,
|
||||
nsIInputStream** aStream)
|
||||
{
|
||||
nsresult rv =
|
||||
aEncoder->InitFromData(aImageBuffer,
|
||||
aWidth * aHeight * 4, aWidth, aHeight, aWidth * 4,
|
||||
aFormat,
|
||||
nsDependentString(aEncoderOptions));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return CallQueryInterface(aEncoder, aStream);
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
ImageEncoder::ExtractDataInternal(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
uint8_t* aImageBuffer,
|
||||
int32_t aFormat,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
nsIInputStream** aStream,
|
||||
imgIEncoder* aEncoder)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> imgStream;
|
||||
|
||||
// get image bytes
|
||||
nsresult rv;
|
||||
if (aImageBuffer) {
|
||||
rv = ImageEncoder::GetInputStream(
|
||||
aSize.width,
|
||||
aSize.height,
|
||||
aImageBuffer,
|
||||
aFormat,
|
||||
aEncoder,
|
||||
nsPromiseFlatString(aOptions).get(),
|
||||
getter_AddRefs(imgStream));
|
||||
} else if (aContext) {
|
||||
NS_ConvertUTF16toUTF8 encoderType(aType);
|
||||
rv = aContext->GetInputStream(encoderType.get(),
|
||||
nsPromiseFlatString(aOptions).get(),
|
||||
getter_AddRefs(imgStream));
|
||||
} else {
|
||||
// no context, so we have to encode an empty image
|
||||
// note that if we didn't have a current context, the spec says we're
|
||||
// supposed to just return transparent black pixels of the canvas
|
||||
// dimensions.
|
||||
nsRefPtr<gfxImageSurface> emptyCanvas =
|
||||
new gfxImageSurface(gfxIntSize(aSize.width, aSize.height),
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (emptyCanvas->CairoStatus()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
rv = aEncoder->InitFromData(emptyCanvas->Data(),
|
||||
aSize.width * aSize.height * 4,
|
||||
aSize.width,
|
||||
aSize.height,
|
||||
aSize.width * 4,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB,
|
||||
aOptions);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
imgStream = do_QueryInterface(aEncoder);
|
||||
}
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
imgStream.forget(aStream);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<imgIEncoder>
|
||||
ImageEncoder::GetImageEncoder(nsAString& aType)
|
||||
{
|
||||
// Get an image encoder for the media type.
|
||||
nsCString encoderCID("@mozilla.org/image/encoder;2?type=");
|
||||
NS_ConvertUTF16toUTF8 encoderType(aType);
|
||||
encoderCID += encoderType;
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get());
|
||||
|
||||
if (!encoder && aType != NS_LITERAL_STRING("image/png")) {
|
||||
// Unable to create an encoder instance of the specified type. Falling back
|
||||
// to PNG.
|
||||
aType.AssignLiteral("image/png");
|
||||
nsCString PNGEncoderCID("@mozilla.org/image/encoder;2?type=image/png");
|
||||
encoder = do_CreateInstance(PNGEncoderCID.get());
|
||||
}
|
||||
|
||||
return encoder.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
@ -1,92 +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/. */
|
||||
|
||||
#ifndef ImageEncoder_h
|
||||
#define ImageEncoder_h
|
||||
|
||||
#include "imgIEncoder.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsError.h"
|
||||
#include "mozilla/dom/HTMLCanvasElementBinding.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsSize.h"
|
||||
|
||||
class nsICanvasRenderingContextInternal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class EncodingRunnable;
|
||||
|
||||
class ImageEncoder
|
||||
{
|
||||
public:
|
||||
// Extracts data synchronously and gives you a stream containing the image
|
||||
// represented by aContext. aType may change to "image/png" if we had to fall
|
||||
// back to a PNG encoder. A return value of NS_OK implies successful data
|
||||
// extraction. If there are any unrecognized custom parse options in
|
||||
// aOptions, NS_ERROR_INVALID_ARG will be returned. When encountering this
|
||||
// error it is usual to call this function again without any options at all.
|
||||
static nsresult ExtractData(nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
nsIInputStream** aStream);
|
||||
|
||||
// Extracts data asynchronously. aType may change to "image/png" if we had to
|
||||
// fall back to a PNG encoder. aOptions are the options to be passed to the
|
||||
// encoder and aUsingCustomOptions specifies whether custom parse options were
|
||||
// used (i.e. by using -moz-parse-options). If there are any unrecognized
|
||||
// custom parse options, we fall back to the default values for the encoder
|
||||
// without any options at all. A return value of NS_OK only implies
|
||||
// successful dispatching of the extraction step to the encoding thread.
|
||||
static nsresult ExtractDataAsync(nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
bool aUsingCustomOptions,
|
||||
uint8_t* aImageBuffer,
|
||||
int32_t aFormat,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
nsIScriptContext* aScriptContext,
|
||||
FileCallback& aCallback);
|
||||
|
||||
// Gives you a stream containing the image represented by aImageBuffer.
|
||||
// The format is given in aFormat, for example
|
||||
// imgIEncoder::INPUT_FORMAT_HOSTARGB.
|
||||
static nsresult GetInputStream(int32_t aWidth,
|
||||
int32_t aHeight,
|
||||
uint8_t* aImageBuffer,
|
||||
int32_t aFormat,
|
||||
imgIEncoder* aEncoder,
|
||||
const PRUnichar* aEncoderOptions,
|
||||
nsIInputStream** aStream);
|
||||
|
||||
private:
|
||||
// When called asynchronously, aContext is null.
|
||||
static nsresult
|
||||
ExtractDataInternal(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
uint8_t* aImageBuffer,
|
||||
int32_t aFormat,
|
||||
const nsIntSize aSize,
|
||||
nsICanvasRenderingContextInternal* aContext,
|
||||
nsIInputStream** aStream,
|
||||
imgIEncoder* aEncoder);
|
||||
|
||||
// Creates and returns an encoder instance of the type specified in aType.
|
||||
// aType may change to "image/png" if no instance of the original type could
|
||||
// be created and we had to fall back to a PNG encoder. A return value of
|
||||
// NULL should be interpreted as NS_IMAGELIB_ERROR_NO_ENCODER and aType is
|
||||
// undefined in this case.
|
||||
static already_AddRefed<imgIEncoder> GetImageEncoder(nsAString& aType);
|
||||
|
||||
friend class EncodingRunnable;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // ImageEncoder_h
|
@ -22,6 +22,5 @@ INCLUDES += \
|
||||
-I$(srcdir)/../../html/content/src \
|
||||
-I$(srcdir)/../../../js/xpconnect/src \
|
||||
-I$(srcdir)/../../../dom/base \
|
||||
-I$(srcdir)/../../../image/src \
|
||||
-I$(topsrcdir)/content/xul/content/src \
|
||||
$(NULL)
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
#include "nsIVariant.h"
|
||||
|
||||
#include "ImageEncoder.h"
|
||||
#include "imgIEncoder.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPattern.h"
|
||||
@ -721,54 +721,6 @@ void WebGLContext::LoseOldestWebGLContextIfLimitExceeded()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat)
|
||||
{
|
||||
*aImageBuffer = nullptr;
|
||||
*aFormat = 0;
|
||||
|
||||
nsRefPtr<gfxImageSurface> imgsurf =
|
||||
new gfxImageSurface(gfxIntSize(mWidth, mHeight),
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
|
||||
if (!imgsurf || imgsurf->CairoStatus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(imgsurf);
|
||||
if (!ctx || ctx->HasError()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use Render() to make sure that appropriate y-flip gets applied
|
||||
uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0;
|
||||
nsresult rv = Render(ctx, gfxPattern::FILTER_NEAREST, flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
if (!mOptions.premultipliedAlpha) {
|
||||
// We need to convert to INPUT_FORMAT_RGBA, otherwise
|
||||
// we are automatically considered premult, and unpremult'd.
|
||||
// Yes, it is THAT silly.
|
||||
// Except for different lossy conversions by color,
|
||||
// we could probably just change the label, and not change the data.
|
||||
gfxUtils::ConvertBGRAtoRGBA(imgsurf);
|
||||
format = imgIEncoder::INPUT_FORMAT_RGBA;
|
||||
}
|
||||
|
||||
static const fallible_t fallible = fallible_t();
|
||||
uint8_t* imageBuffer = new (fallible) uint8_t[mWidth * mHeight * 4];
|
||||
if (!imageBuffer) {
|
||||
return;
|
||||
}
|
||||
memcpy(imageBuffer, imgsurf->Data(), mWidth * mHeight * 4);
|
||||
|
||||
*aImageBuffer = imageBuffer;
|
||||
*aFormat = format;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLContext::GetInputStream(const char* aMimeType,
|
||||
const PRUnichar* aEncoderOptions,
|
||||
@ -778,22 +730,48 @@ WebGLContext::GetInputStream(const char* aMimeType,
|
||||
if (!gl)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
uint8_t* imageBuffer = nullptr;
|
||||
int32_t format = 0;
|
||||
GetImageBuffer(&imageBuffer, &format);
|
||||
if (!imageBuffer) {
|
||||
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(gfxIntSize(mWidth, mHeight),
|
||||
gfxASurface::ImageFormatARGB32);
|
||||
if (surf->CairoStatus() != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsRefPtr<gfxContext> tmpcx = new gfxContext(surf);
|
||||
// Use Render() to make sure that appropriate y-flip gets applied
|
||||
uint32_t flags = mOptions.premultipliedAlpha ? RenderFlagPremultAlpha : 0;
|
||||
nsresult rv = Render(tmpcx, gfxPattern::FILTER_NEAREST, flags);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
const char encoderPrefix[] = "@mozilla.org/image/encoder;2?type=";
|
||||
nsAutoArrayPtr<char> conid(new char[strlen(encoderPrefix) + strlen(aMimeType) + 1]);
|
||||
|
||||
strcpy(conid, encoderPrefix);
|
||||
strcat(conid, aMimeType);
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(conid);
|
||||
if (!encoder)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
int format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
if (!mOptions.premultipliedAlpha) {
|
||||
// We need to convert to INPUT_FORMAT_RGBA, otherwise
|
||||
// we are automatically considered premult, and unpremult'd.
|
||||
// Yes, it is THAT silly.
|
||||
// Except for different lossy conversions by color,
|
||||
// we could probably just change the label, and not change the data.
|
||||
gfxUtils::ConvertBGRAtoRGBA(surf);
|
||||
format = imgIEncoder::INPUT_FORMAT_RGBA;
|
||||
}
|
||||
|
||||
nsCString enccid("@mozilla.org/image/encoder;2?type=");
|
||||
enccid += aMimeType;
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get());
|
||||
if (!encoder) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = encoder->InitFromData(surf->Data(),
|
||||
mWidth * mHeight * 4,
|
||||
mWidth, mHeight,
|
||||
surf->Stride(),
|
||||
format,
|
||||
nsDependentString(aEncoderOptions));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return ImageEncoder::GetInputStream(mWidth, mHeight, imageBuffer, format,
|
||||
encoder, aEncoderOptions, aStream);
|
||||
return CallQueryInterface(encoder, aStream);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -160,7 +160,6 @@ public:
|
||||
NS_IMETHOD Render(gfxContext *ctx,
|
||||
gfxPattern::GraphicsFilter f,
|
||||
uint32_t aFlags = RenderFlagPremultAlpha) MOZ_OVERRIDE;
|
||||
virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
|
||||
NS_IMETHOD GetInputStream(const char* aMimeType,
|
||||
const PRUnichar* aEncoderOptions,
|
||||
nsIInputStream **aStream) MOZ_OVERRIDE;
|
||||
|
@ -22,7 +22,6 @@ CPP_SOURCES += [
|
||||
'DocumentRendererChild.cpp',
|
||||
'DocumentRendererParent.cpp',
|
||||
'ImageData.cpp',
|
||||
'ImageEncoder.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBGL']:
|
||||
|
@ -7,43 +7,42 @@
|
||||
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
|
||||
<script>
|
||||
|
||||
function compareAsync(file, canvas, type, callback)
|
||||
var gCompares = 0;
|
||||
|
||||
function compareAsync(file, canvas, type)
|
||||
{
|
||||
++gCompares;
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload =
|
||||
function(e) {
|
||||
is(e.target.result, canvas.toDataURL(type),
|
||||
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
|
||||
callback(canvas);
|
||||
if (--gCompares == 0) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function test1(canvas)
|
||||
{
|
||||
var pngfile = canvas.mozGetAsFile("foo.png");
|
||||
is(pngfile.type, "image/png", "Default type for mozGetAsFile should be PNG");
|
||||
compareAsync(pngfile, canvas, "image/png", test2);
|
||||
is(pngfile.name, "foo.png", "File name should be what we passed in");
|
||||
}
|
||||
|
||||
function test2(canvas)
|
||||
{
|
||||
var jpegfile = canvas.mozGetAsFile("bar.jpg", "image/jpeg");
|
||||
is(jpegfile.type, "image/jpeg",
|
||||
"When a valid type is specified that should be returned");
|
||||
compareAsync(jpegfile, canvas, "image/jpeg", SimpleTest.finish);
|
||||
is(jpegfile.name, "bar.jpg", "File name should be what we passed in");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function () {
|
||||
|
||||
var canvas = document.getElementById('c');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
|
||||
|
||||
test1(canvas);
|
||||
var pngfile = canvas.mozGetAsFile("foo.png");
|
||||
is(pngfile.type, "image/png", "Default type for mozGetAsFile should be PNG");
|
||||
compareAsync(pngfile, canvas, "image/png");
|
||||
is(pngfile.name, "foo.png", "File name should be what we passed in");
|
||||
|
||||
var jpegfile = canvas.mozGetAsFile("bar.jpg", "image/jpeg");
|
||||
is(jpegfile.type, "image/jpeg",
|
||||
"When a valid type is specified that should be returned");
|
||||
compareAsync(jpegfile, canvas, "image/jpeg");
|
||||
is(jpegfile.name, "bar.jpg", "File name should be what we passed in");
|
||||
|
||||
});
|
||||
</script>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE HTML>
|
||||
<title>Canvas test: toBlob</title>
|
||||
<title>Canvas test: mozGetAsFile</title>
|
||||
<script src="/MochiKit/MochiKit.js"></script>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
@ -7,40 +7,34 @@
|
||||
<canvas id="c" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas>
|
||||
<script>
|
||||
|
||||
function BlobListener(type, canvas, callback, file)
|
||||
var gCompares = 2;
|
||||
|
||||
function BlobListener(type, canvas, file)
|
||||
{
|
||||
is(file.type, type,
|
||||
"When a valid type is specified that should be returned");
|
||||
var reader = new FileReader();
|
||||
reader.onload =
|
||||
reader.onload =
|
||||
function(e) {
|
||||
is(e.target.result, canvas.toDataURL(type),
|
||||
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
|
||||
callback(canvas);
|
||||
"<canvas>.mozGetAsFile().getAsDataURL() should equal <canvas>.toDataURL()");
|
||||
if (--gCompares == 0) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
function test1(canvas)
|
||||
{
|
||||
canvas.toBlob(BlobListener.bind(undefined, "image/png", canvas, test2));
|
||||
}
|
||||
|
||||
function test2(canvas)
|
||||
{
|
||||
canvas.toBlob(
|
||||
BlobListener.bind(undefined, "image/jpeg", canvas, SimpleTest.finish),
|
||||
"image/jpeg");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function () {
|
||||
|
||||
var canvas = document.getElementById('c');
|
||||
var ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.drawImage(document.getElementById('yellow75.png'), 0, 0);
|
||||
|
||||
test1(canvas);
|
||||
canvas.toBlob(BlobListener.bind(undefined, "image/png", canvas));
|
||||
canvas.toBlob(BlobListener.bind(undefined, "image/jpeg", canvas), "image/jpeg");
|
||||
|
||||
});
|
||||
</script>
|
||||
|
@ -223,9 +223,10 @@ protected:
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& aParams,
|
||||
bool* usingCustomParseOptions);
|
||||
nsresult ExtractData(nsAString& aType,
|
||||
nsresult ExtractData(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream);
|
||||
nsIInputStream** aStream,
|
||||
bool& aFellBackToPNG);
|
||||
nsresult ToDataURLImpl(JSContext* aCx,
|
||||
const nsAString& aMimeType,
|
||||
const JS::Value& aEncoderOptions,
|
||||
|
@ -5,10 +5,10 @@
|
||||
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
|
||||
#include "ImageEncoder.h"
|
||||
#include "Layers.h"
|
||||
#include "imgIEncoder.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "Layers.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/dom/CanvasRenderingContext2D.h"
|
||||
@ -22,7 +22,6 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsDOMFile.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsFrameManager.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsITimer.h"
|
||||
@ -46,6 +45,29 @@ namespace {
|
||||
typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
|
||||
HTMLImageOrCanvasOrVideoElement;
|
||||
|
||||
class ToBlobRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ToBlobRunnable(mozilla::dom::FileCallback& aCallback,
|
||||
nsIDOMBlob* aBlob)
|
||||
: mCallback(&aCallback),
|
||||
mBlob(aBlob)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
mozilla::ErrorResult rv;
|
||||
mCallback->Call(mBlob, rv);
|
||||
return rv.ErrorCode();
|
||||
}
|
||||
private:
|
||||
nsRefPtr<mozilla::dom::FileCallback> mCallback;
|
||||
nsCOMPtr<nsIDOMBlob> mBlob;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace mozilla {
|
||||
@ -330,10 +352,10 @@ HTMLCanvasElement::MozFetchAsStream(nsIInputStreamCallback *aCallback,
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv;
|
||||
bool fellBackToPNG = false;
|
||||
nsCOMPtr<nsIInputStream> inputData;
|
||||
|
||||
nsAutoString type(aType);
|
||||
rv = ExtractData(type, EmptyString(), getter_AddRefs(inputData));
|
||||
rv = ExtractData(aType, EmptyString(), getter_AddRefs(inputData), fellBackToPNG);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncData = do_QueryInterface(inputData, &rv);
|
||||
@ -365,15 +387,68 @@ HTMLCanvasElement::GetMozPrintCallback() const
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLCanvasElement::ExtractData(nsAString& aType,
|
||||
HTMLCanvasElement::ExtractData(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
nsIInputStream** aStream)
|
||||
nsIInputStream** aStream,
|
||||
bool& aFellBackToPNG)
|
||||
{
|
||||
return ImageEncoder::ExtractData(aType,
|
||||
aOptions,
|
||||
GetSize(),
|
||||
mCurrentContext,
|
||||
aStream);
|
||||
// note that if we don't have a current context, the spec says we're
|
||||
// supposed to just return transparent black pixels of the canvas
|
||||
// dimensions.
|
||||
nsRefPtr<gfxImageSurface> emptyCanvas;
|
||||
nsIntSize size = GetWidthHeight();
|
||||
if (!mCurrentContext) {
|
||||
emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32);
|
||||
if (emptyCanvas->CairoStatus()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// get image bytes
|
||||
nsCOMPtr<nsIInputStream> imgStream;
|
||||
NS_ConvertUTF16toUTF8 encoderType(aType);
|
||||
|
||||
try_again:
|
||||
if (mCurrentContext) {
|
||||
rv = mCurrentContext->GetInputStream(encoderType.get(),
|
||||
nsPromiseFlatString(aOptions).get(),
|
||||
getter_AddRefs(imgStream));
|
||||
} else {
|
||||
// no context, so we have to encode the empty image we created above
|
||||
nsCString enccid("@mozilla.org/image/encoder;2?type=");
|
||||
enccid += encoderType;
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(enccid.get(), &rv);
|
||||
if (NS_SUCCEEDED(rv) && encoder) {
|
||||
rv = encoder->InitFromData(emptyCanvas->Data(),
|
||||
size.width * size.height * 4,
|
||||
size.width,
|
||||
size.height,
|
||||
size.width * 4,
|
||||
imgIEncoder::INPUT_FORMAT_HOSTARGB,
|
||||
aOptions);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
imgStream = do_QueryInterface(encoder);
|
||||
}
|
||||
} else {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) && !aFellBackToPNG) {
|
||||
// Try image/png instead.
|
||||
// XXX ERRMSG we need to report an error to developers here! (bug 329026)
|
||||
aFellBackToPNG = true;
|
||||
encoderType.AssignLiteral("image/png");
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
imgStream.forget(aStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -424,6 +499,8 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
|
||||
const JS::Value& aEncoderOptions,
|
||||
nsAString& aDataURL)
|
||||
{
|
||||
bool fallbackToPNG = false;
|
||||
|
||||
nsIntSize size = GetWidthHeight();
|
||||
if (size.height == 0 || size.width == 0) {
|
||||
aDataURL = NS_LITERAL_STRING("data:,");
|
||||
@ -444,18 +521,23 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = ExtractData(type, params, getter_AddRefs(stream));
|
||||
rv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
|
||||
|
||||
// If there are unrecognized custom parse options, we should fall back to
|
||||
// the default values for the encoder without any options at all.
|
||||
if (rv == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
|
||||
rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
|
||||
fallbackToPNG = false;
|
||||
rv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
|
||||
}
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// build data URL string
|
||||
aDataURL = NS_LITERAL_STRING("data:") + type + NS_LITERAL_STRING(";base64,");
|
||||
if (fallbackToPNG)
|
||||
aDataURL = NS_LITERAL_STRING("data:image/png;base64,");
|
||||
else
|
||||
aDataURL = NS_LITERAL_STRING("data:") + type +
|
||||
NS_LITERAL_STRING(";base64,");
|
||||
|
||||
uint64_t count;
|
||||
rv = stream->Available(&count);
|
||||
@ -465,6 +547,7 @@ HTMLCanvasElement::ToDataURLImpl(JSContext* aCx,
|
||||
return Base64EncodeInputStream(stream, aDataURL, (uint32_t)count, aDataURL.Length());
|
||||
}
|
||||
|
||||
// XXXkhuey the encoding should be off the main thread, but we're lazy.
|
||||
void
|
||||
HTMLCanvasElement::ToBlob(JSContext* aCx,
|
||||
FileCallback& aCallback,
|
||||
@ -495,24 +578,52 @@ HTMLCanvasElement::ToBlob(JSContext* aCx,
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptContext> scriptContext =
|
||||
GetScriptContextFromJSContext(nsContentUtils::GetCurrentJSContext());
|
||||
bool fallbackToPNG = false;
|
||||
|
||||
uint8_t* imageBuffer = nullptr;
|
||||
int32_t format = 0;
|
||||
if (mCurrentContext) {
|
||||
mCurrentContext->GetImageBuffer(&imageBuffer, &format);
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
aRv = ExtractData(type, params, getter_AddRefs(stream), fallbackToPNG);
|
||||
// If there are unrecognized custom parse options, we should fall back to
|
||||
// the default values for the encoder without any options at all.
|
||||
if (aRv.ErrorCode() == NS_ERROR_INVALID_ARG && usingCustomParseOptions) {
|
||||
fallbackToPNG = false;
|
||||
aRv = ExtractData(type, EmptyString(), getter_AddRefs(stream), fallbackToPNG);
|
||||
}
|
||||
|
||||
aRv = ImageEncoder::ExtractDataAsync(type,
|
||||
params,
|
||||
usingCustomParseOptions,
|
||||
imageBuffer,
|
||||
format,
|
||||
GetSize(),
|
||||
mCurrentContext,
|
||||
scriptContext,
|
||||
aCallback);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fallbackToPNG) {
|
||||
type.AssignLiteral("image/png");
|
||||
}
|
||||
|
||||
uint64_t imgSize;
|
||||
aRv = stream->Available(&imgSize);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
if (imgSize > UINT32_MAX) {
|
||||
aRv.Throw(NS_ERROR_FILE_TOO_BIG);
|
||||
return;
|
||||
}
|
||||
|
||||
void* imgData = nullptr;
|
||||
aRv = NS_ReadInputStreamToBuffer(stream, &imgData, imgSize);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The DOMFile takes ownership of the buffer
|
||||
nsRefPtr<nsDOMMemoryFile> blob =
|
||||
new nsDOMMemoryFile(imgData, imgSize, type);
|
||||
|
||||
JSContext* cx = nsContentUtils::GetCurrentJSContext();
|
||||
if (cx) {
|
||||
JS_updateMallocCounter(cx, imgSize);
|
||||
}
|
||||
|
||||
nsRefPtr<ToBlobRunnable> runnable = new ToBlobRunnable(aCallback, blob);
|
||||
aRv = NS_DispatchToCurrentThread(runnable);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIDOMFile>
|
||||
@ -546,11 +657,18 @@ HTMLCanvasElement::MozGetAsFileImpl(const nsAString& aName,
|
||||
const nsAString& aType,
|
||||
nsIDOMFile** aResult)
|
||||
{
|
||||
bool fallbackToPNG = false;
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsAutoString type(aType);
|
||||
nsresult rv = ExtractData(type, EmptyString(), getter_AddRefs(stream));
|
||||
nsresult rv = ExtractData(aType, EmptyString(), getter_AddRefs(stream),
|
||||
fallbackToPNG);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString type(aType);
|
||||
if (fallbackToPNG) {
|
||||
type.AssignLiteral("image/png");
|
||||
}
|
||||
|
||||
uint64_t imgSize;
|
||||
rv = stream->Available(&imgSize);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -22,7 +22,6 @@ INCLUDES += \
|
||||
-I$(srcdir)/../../../../editor/libeditor/text \
|
||||
-I$(srcdir)/../../../../editor/txmgr/src \
|
||||
-I$(srcdir)/../../../../netwerk/base/src \
|
||||
-I$(srcdir)/../../../../content/canvas/src \
|
||||
-I$(srcdir) \
|
||||
-I$(topsrcdir)/xpcom/ds \
|
||||
-I$(topsrcdir)/content/media/ \
|
||||
|
@ -302,6 +302,10 @@ private:
|
||||
NS_IMETHODIMP DispatchAsyncScrollEventRunnable::Run()
|
||||
{
|
||||
nsCOMPtr<Element> frameElement = mTabParent->GetOwnerElement();
|
||||
nsIDocument *doc = frameElement->OwnerDoc();
|
||||
nsCOMPtr<nsIGlobalObject> globalObject = doc->GetScopeObject();
|
||||
NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// Create the event's detail object.
|
||||
AsyncScrollEventDetailInitializer detail;
|
||||
detail.mLeft = mContentRect.x;
|
||||
@ -310,7 +314,12 @@ NS_IMETHODIMP DispatchAsyncScrollEventRunnable::Run()
|
||||
detail.mHeight = mContentRect.height;
|
||||
detail.mScrollWidth = mContentRect.width;
|
||||
detail.mScrollHeight = mContentRect.height;
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
JS::Rooted<JSObject*> globalJSObject(cx, globalObject->GetGlobalJSObject());
|
||||
NS_ENSURE_TRUE(globalJSObject, NS_ERROR_UNEXPECTED);
|
||||
|
||||
JSAutoCompartment ac(cx, globalJSObject);
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
|
||||
// We can get away with a null global here because
|
||||
|
@ -19,13 +19,11 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#include "IndexedDatabaseManager.h"
|
||||
|
||||
#define PERMISSION_INDEXEDDB "indexedDB"
|
||||
#define PREF_INDEXEDDB_ENABLED "dom.indexedDB.enabled"
|
||||
#define TOPIC_PERMISSIONS_PROMPT "indexedDB-permissions-prompt"
|
||||
#define TOPIC_PERMISSIONS_RESPONSE "indexedDB-permissions-response"
|
||||
|
||||
@ -40,7 +38,6 @@
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
using namespace mozilla::services;
|
||||
using mozilla::dom::quota::CheckQuotaHelper;
|
||||
using mozilla::Preferences;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -50,21 +47,13 @@ GetIndexedDBPermissions(nsIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!Preferences::GetBool(PREF_INDEXEDDB_ENABLED)) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
// No window here means chrome access.
|
||||
if (!aWindow) {
|
||||
return PERMISSION_ALLOWED;
|
||||
}
|
||||
NS_ASSERTION(aWindow, "Chrome shouldn't check the permission!");
|
||||
|
||||
nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(aWindow));
|
||||
NS_ENSURE_TRUE(sop, nsIPermissionManager::DENY_ACTION);
|
||||
|
||||
if (nsContentUtils::IsSystemPrincipal(sop->GetPrincipal())) {
|
||||
return PERMISSION_ALLOWED;
|
||||
}
|
||||
NS_ASSERTION(!nsContentUtils::IsSystemPrincipal(sop->GetPrincipal()),
|
||||
"Chrome windows shouldn't check the permission!");
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(aWindow);
|
||||
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(webNav);
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "mozilla/dom/quota/OriginOrPatternString.h"
|
||||
#include "mozilla/dom/quota/QuotaManager.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/storage.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
@ -46,6 +47,8 @@
|
||||
|
||||
#include "ipc/IndexedDBChild.h"
|
||||
|
||||
#define PREF_INDEXEDDB_ENABLED "dom.indexedDB.enabled"
|
||||
|
||||
USING_INDEXEDDB_NAMESPACE
|
||||
USING_QUOTA_NAMESPACE
|
||||
|
||||
@ -56,6 +59,7 @@ using mozilla::dom::NonNull;
|
||||
using mozilla::dom::Optional;
|
||||
using mozilla::dom::TabChild;
|
||||
using mozilla::ErrorResult;
|
||||
using mozilla::Preferences;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -602,22 +606,33 @@ IDBFactory::OpenInternal(const nsAString& aName,
|
||||
rv = openHelper->Init();
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
|
||||
nsRefPtr<CheckPermissionsHelper> permissionHelper =
|
||||
new CheckPermissionsHelper(openHelper, window);
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
rv = quotaManager->
|
||||
WaitForOpenAllowed(OriginOrPatternString::FromOrigin(aASCIIOrigin),
|
||||
Nullable<PersistenceType>(aPersistenceType),
|
||||
openHelper->Id(), permissionHelper);
|
||||
if (!Preferences::GetBool(PREF_INDEXEDDB_ENABLED)) {
|
||||
openHelper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
|
||||
rv = openHelper->WaitForOpenAllowed();
|
||||
}
|
||||
else {
|
||||
NS_ASSERTION(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY, "Huh?");
|
||||
StoragePrivilege openerPrivilege;
|
||||
rv = QuotaManager::GetInfoFromWindow(window, nullptr, nullptr,
|
||||
&openerPrivilege, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = openHelper->WaitForOpenAllowed();
|
||||
if (openerPrivilege != Chrome &&
|
||||
aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
|
||||
nsRefPtr<CheckPermissionsHelper> permissionHelper =
|
||||
new CheckPermissionsHelper(openHelper, window);
|
||||
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
NS_ASSERTION(quotaManager, "This should never be null!");
|
||||
|
||||
rv = quotaManager->
|
||||
WaitForOpenAllowed(OriginOrPatternString::FromOrigin(aASCIIOrigin),
|
||||
Nullable<PersistenceType>(aPersistenceType),
|
||||
openHelper->Id(), permissionHelper);
|
||||
}
|
||||
else {
|
||||
// Chrome and temporary storage doesn't need to check the permission.
|
||||
rv = openHelper->WaitForOpenAllowed();
|
||||
}
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
|
@ -1737,7 +1737,8 @@ OpenDatabaseHelper::DispatchToIOThread()
|
||||
nsresult
|
||||
OpenDatabaseHelper::RunImmediately()
|
||||
{
|
||||
NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
|
||||
NS_ASSERTION(mState == eCreated || mState == eOpenPending,
|
||||
"We've already been dispatched?");
|
||||
NS_ASSERTION(NS_FAILED(mResultCode),
|
||||
"Should only be short-circuiting if we failed!");
|
||||
NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
|
||||
@ -2168,6 +2169,10 @@ OpenDatabaseHelper::Run()
|
||||
PROFILER_MAIN_THREAD_LABEL("IndexedDB", "OpenDatabaseHelper::Run");
|
||||
|
||||
if (mState == eOpenPending) {
|
||||
if (NS_FAILED(mResultCode)) {
|
||||
return RunImmediately();
|
||||
}
|
||||
|
||||
return DispatchToIOThread();
|
||||
}
|
||||
|
||||
|
@ -124,6 +124,12 @@ struct RectTyped :
|
||||
RectTyped<UnknownUnits> ToUnknownRect() const {
|
||||
return RectTyped<UnknownUnits>(this->x, this->y, this->width, this->height);
|
||||
}
|
||||
|
||||
// This is here only to keep IPDL-generated code happy. DO NOT USE.
|
||||
bool operator==(const RectTyped<units>& aRect) const
|
||||
{
|
||||
return RectTyped<units>::IsEqualEdges(aRect);
|
||||
}
|
||||
};
|
||||
typedef RectTyped<UnknownUnits> Rect;
|
||||
|
||||
|
@ -186,6 +186,7 @@ Layer::Layer(LayerManager* aManager, void* aImplData) :
|
||||
mUseTileSourceRect(false),
|
||||
mIsFixedPosition(false),
|
||||
mMargins(0, 0, 0, 0),
|
||||
mStickyPositionData(nullptr),
|
||||
mDebugColorIndex(0),
|
||||
mAnimationGeneration(0)
|
||||
{}
|
||||
@ -1280,6 +1281,14 @@ Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
|
||||
if (GetIsFixedPosition()) {
|
||||
aTo.AppendPrintf(" [isFixedPosition anchor=%f,%f]", mAnchor.x, mAnchor.y);
|
||||
}
|
||||
if (GetIsStickyPosition()) {
|
||||
aTo.AppendPrintf(" [isStickyPosition scrollId=%d outer=%f,%f %fx%f "
|
||||
"inner=%f,%f %fx%f]", mStickyPositionData->mScrollId,
|
||||
mStickyPositionData->mOuter.x, mStickyPositionData->mOuter.y,
|
||||
mStickyPositionData->mOuter.width, mStickyPositionData->mOuter.height,
|
||||
mStickyPositionData->mInner.x, mStickyPositionData->mInner.y,
|
||||
mStickyPositionData->mInner.width, mStickyPositionData->mInner.height);
|
||||
}
|
||||
|
||||
return aTo;
|
||||
}
|
||||
|
@ -909,6 +909,32 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* If a layer is "sticky position", |aScrollId| holds the scroll identifier
|
||||
* of the scrollable content that contains it. The difference between the two
|
||||
* rectangles |aOuter| and |aInner| is treated as two intervals in each
|
||||
* dimension, with the current scroll position at the origin. For each
|
||||
* dimension, while that component of the scroll position lies within either
|
||||
* interval, the layer should not move relative to its scrolling container.
|
||||
*/
|
||||
void SetStickyPositionData(FrameMetrics::ViewID aScrollId, LayerRect aOuter,
|
||||
LayerRect aInner)
|
||||
{
|
||||
if (!mStickyPositionData ||
|
||||
!mStickyPositionData->mOuter.IsEqualEdges(aOuter) ||
|
||||
!mStickyPositionData->mInner.IsEqualEdges(aInner)) {
|
||||
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) StickyPositionData", this));
|
||||
if (!mStickyPositionData) {
|
||||
mStickyPositionData = new StickyPositionData;
|
||||
}
|
||||
mStickyPositionData->mScrollId = aScrollId;
|
||||
mStickyPositionData->mOuter = aOuter;
|
||||
mStickyPositionData->mInner = aInner;
|
||||
Mutated();
|
||||
}
|
||||
}
|
||||
|
||||
// These getters can be used anytime.
|
||||
float GetOpacity() { return mOpacity; }
|
||||
const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nullptr; }
|
||||
@ -926,8 +952,12 @@ public:
|
||||
float GetPostXScale() const { return mPostXScale; }
|
||||
float GetPostYScale() const { return mPostYScale; }
|
||||
bool GetIsFixedPosition() { return mIsFixedPosition; }
|
||||
bool GetIsStickyPosition() { return mStickyPositionData; }
|
||||
LayerPoint GetFixedPositionAnchor() { return mAnchor; }
|
||||
const LayerMargin& GetFixedPositionMargins() { return mMargins; }
|
||||
FrameMetrics::ViewID GetStickyScrollContainerId() { return mStickyPositionData->mScrollId; }
|
||||
const LayerRect& GetStickyScrollRangeOuter() { return mStickyPositionData->mOuter; }
|
||||
const LayerRect& GetStickyScrollRangeInner() { return mStickyPositionData->mInner; }
|
||||
Layer* GetMaskLayer() const { return mMaskLayer; }
|
||||
|
||||
// Note that all lengths in animation data are either in CSS pixels or app
|
||||
@ -1283,6 +1313,12 @@ protected:
|
||||
bool mIsFixedPosition;
|
||||
LayerPoint mAnchor;
|
||||
LayerMargin mMargins;
|
||||
struct StickyPositionData {
|
||||
FrameMetrics::ViewID mScrollId;
|
||||
LayerRect mOuter;
|
||||
LayerRect mInner;
|
||||
};
|
||||
nsAutoPtr<StickyPositionData> mStickyPositionData;
|
||||
DebugOnly<uint32_t> mDebugColorIndex;
|
||||
// If this layer is used for OMTA, then this counter is used to ensure we
|
||||
// stay in sync with the animation manager
|
||||
|
@ -214,14 +214,31 @@ GetLayerFixedMarginsOffset(Layer* aLayer,
|
||||
return translation;
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer,
|
||||
Layer* aTransformedSubtreeRoot,
|
||||
const gfx3DMatrix& aPreviousTransformForRoot,
|
||||
const LayerMargin& aFixedLayerMargins)
|
||||
static gfxFloat
|
||||
IntervalOverlap(gfxFloat aTranslation, gfxFloat aMin, gfxFloat aMax)
|
||||
{
|
||||
if (aLayer != aTransformedSubtreeRoot && aLayer->GetIsFixedPosition() &&
|
||||
!aLayer->GetParent()->GetIsFixedPosition()) {
|
||||
// Determine the amount of overlap between the 1D vector |aTranslation|
|
||||
// and the interval [aMin, aMax].
|
||||
if (aTranslation > 0) {
|
||||
return std::max(0.0, std::min(aMax, aTranslation) - std::max(aMin, 0.0));
|
||||
} else {
|
||||
return std::min(0.0, std::max(aMin, aTranslation) - std::min(aMax, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
|
||||
Layer* aTransformedSubtreeRoot,
|
||||
const gfx3DMatrix& aPreviousTransformForRoot,
|
||||
const LayerMargin& aFixedLayerMargins)
|
||||
{
|
||||
bool isRootFixed = aLayer->GetIsFixedPosition() &&
|
||||
!aLayer->GetParent()->GetIsFixedPosition();
|
||||
bool isStickyForSubtree = aLayer->GetIsStickyPosition() &&
|
||||
aTransformedSubtreeRoot->AsContainerLayer() &&
|
||||
aLayer->GetStickyScrollContainerId() ==
|
||||
aTransformedSubtreeRoot->AsContainerLayer()->GetFrameMetrics().mScrollId;
|
||||
if (aLayer != aTransformedSubtreeRoot && (isRootFixed || isStickyForSubtree)) {
|
||||
// Insert a translation so that the position of the anchor point is the same
|
||||
// before and after the change to the transform of aTransformedSubtreeRoot.
|
||||
// This currently only works for fixed layers with 2D transforms.
|
||||
@ -286,6 +303,21 @@ AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer,
|
||||
oldCumulativeTransform.Transform(locallyTransformedOffsetAnchor));
|
||||
gfxPoint translation = oldAnchorPositionInNewSpace - locallyTransformedAnchor;
|
||||
|
||||
if (aLayer->GetIsStickyPosition()) {
|
||||
// For sticky positioned layers, the difference between the two rectangles
|
||||
// defines a pair of translation intervals in each dimension through which
|
||||
// the layer should not move relative to the scroll container. To
|
||||
// accomplish this, we limit each dimension of the |translation| to that
|
||||
// part of it which overlaps those intervals.
|
||||
const LayerRect& stickyOuter = aLayer->GetStickyScrollRangeOuter();
|
||||
const LayerRect& stickyInner = aLayer->GetStickyScrollRangeInner();
|
||||
|
||||
translation.y = IntervalOverlap(translation.y, stickyOuter.y, stickyOuter.YMost()) -
|
||||
IntervalOverlap(translation.y, stickyInner.y, stickyInner.YMost());
|
||||
translation.x = IntervalOverlap(translation.x, stickyOuter.x, stickyOuter.XMost()) -
|
||||
IntervalOverlap(translation.x, stickyInner.x, stickyInner.XMost());
|
||||
}
|
||||
|
||||
// Finally, apply the 2D translation to the layer transform.
|
||||
TranslateShadowLayer2D(aLayer, translation);
|
||||
|
||||
@ -296,8 +328,8 @@ AsyncCompositionManager::AlignFixedLayersForAnchorPoint(Layer* aLayer,
|
||||
|
||||
for (Layer* child = aLayer->GetFirstChild();
|
||||
child; child = child->GetNextSibling()) {
|
||||
AlignFixedLayersForAnchorPoint(child, aTransformedSubtreeRoot,
|
||||
aPreviousTransformForRoot, aFixedLayerMargins);
|
||||
AlignFixedAndStickyLayers(child, aTransformedSubtreeRoot,
|
||||
aPreviousTransformForRoot, aFixedLayerMargins);
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,7 +533,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(TimeStamp aCurrentFram
|
||||
#endif
|
||||
oldTransform.Scale(resolution.scale, resolution.scale, 1);
|
||||
|
||||
AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform, fixedLayerMargins);
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
|
||||
|
||||
appliedTransform = true;
|
||||
}
|
||||
@ -607,7 +639,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev
|
||||
// transform so that fixed position content moves and scales accordingly.
|
||||
// These calculations will effectively scale and offset fixed position layers
|
||||
// in screen space when the compensatory transform is performed in
|
||||
// AlignFixedLayersForAnchorPoint.
|
||||
// AlignFixedAndStickyLayers.
|
||||
ScreenRect contentScreenRect = mContentRect * userZoom;
|
||||
gfxPoint3D overscrollTranslation;
|
||||
if (userScroll.x < contentScreenRect.x) {
|
||||
@ -637,7 +669,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer, const LayoutDev
|
||||
|
||||
// Make sure fixed position layers don't move away from their anchor points
|
||||
// when we're asynchronously panning or zooming
|
||||
AlignFixedLayersForAnchorPoint(aLayer, aLayer, oldTransform, fixedLayerMargins);
|
||||
AlignFixedAndStickyLayers(aLayer, aLayer, oldTransform, fixedLayerMargins);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -146,19 +146,20 @@ private:
|
||||
ScreenPoint& aOffset);
|
||||
|
||||
/**
|
||||
* Adds a translation to the transform of any fixed-pos layer descendant of
|
||||
* aTransformedSubtreeRoot whose parent layer is not fixed. The translation is
|
||||
* chosen so that the layer's anchor point relative to aTransformedSubtreeRoot's
|
||||
* parent layer is the same as it was when aTransformedSubtreeRoot's
|
||||
* GetLocalTransform() was aPreviousTransformForRoot.
|
||||
* Adds a translation to the transform of any fixed position (whose parent
|
||||
* layer is not fixed) or sticky position layer descendant of
|
||||
* aTransformedSubtreeRoot. The translation is chosen so that the layer's
|
||||
* anchor point relative to aTransformedSubtreeRoot's parent layer is the same
|
||||
* as it was when aTransformedSubtreeRoot's GetLocalTransform() was
|
||||
* aPreviousTransformForRoot. For sticky position layers, the translation is
|
||||
* further intersected with the layer's sticky scroll ranges.
|
||||
* This function will also adjust layers so that the given content document
|
||||
* fixed position margins will be respected during asynchronous panning and
|
||||
* zooming.
|
||||
*/
|
||||
void AlignFixedLayersForAnchorPoint(Layer* aLayer,
|
||||
Layer* aTransformedSubtreeRoot,
|
||||
const gfx3DMatrix& aPreviousTransformForRoot,
|
||||
const LayerMargin& aFixedLayerMargins);
|
||||
void AlignFixedAndStickyLayers(Layer* aLayer, Layer* aTransformedSubtreeRoot,
|
||||
const gfx3DMatrix& aPreviousTransformForRoot,
|
||||
const LayerMargin& aFixedLayerMargins);
|
||||
|
||||
/**
|
||||
* DRAWING PHASE ONLY
|
||||
|
@ -131,7 +131,7 @@ ThebesLayerComposite::RenderLayer(const nsIntPoint& aOffset,
|
||||
tiledLayerProps.mDisplayPort = GetDisplayPort();
|
||||
tiledLayerProps.mEffectiveResolution = GetEffectiveResolution();
|
||||
tiledLayerProps.mCompositionBounds = GetCompositionBounds();
|
||||
tiledLayerProps.mRetainTiles = !mIsFixedPosition;
|
||||
tiledLayerProps.mRetainTiles = !(mIsFixedPosition || mStickyPositionData);
|
||||
tiledLayerProps.mValidRegion = mValidRegion;
|
||||
}
|
||||
|
||||
|
@ -272,6 +272,11 @@ LayerTransactionParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
|
||||
layer->SetIsFixedPosition(common.isFixedPosition());
|
||||
layer->SetFixedPositionAnchor(common.fixedPositionAnchor());
|
||||
layer->SetFixedPositionMargins(common.fixedPositionMargin());
|
||||
if (common.isStickyPosition()) {
|
||||
layer->SetStickyPositionData(common.stickyScrollContainerId(),
|
||||
common.stickyScrollRangeOuter(),
|
||||
common.stickyScrollRangeInner());
|
||||
}
|
||||
if (PLayerParent* maskLayer = common.maskLayerParent()) {
|
||||
layer->SetMaskLayer(cast(maskLayer)->AsLayer());
|
||||
} else {
|
||||
|
@ -33,6 +33,7 @@ using mozilla::dom::ScreenOrientation;
|
||||
using mozilla::layers::TextureInfo;
|
||||
using mozilla::LayerMargin;
|
||||
using mozilla::LayerPoint;
|
||||
using mozilla::LayerRect;
|
||||
using mozilla::layers::ScaleMode;
|
||||
using mozilla::layers::DiagnosticTypes;
|
||||
|
||||
@ -192,6 +193,10 @@ struct CommonLayerAttributes {
|
||||
bool isFixedPosition;
|
||||
LayerPoint fixedPositionAnchor;
|
||||
LayerMargin fixedPositionMargin;
|
||||
bool isStickyPosition;
|
||||
uint64_t stickyScrollContainerId;
|
||||
LayerRect stickyScrollRangeOuter;
|
||||
LayerRect stickyScrollRangeInner;
|
||||
nullable PLayer maskLayer;
|
||||
// Animated colors will only honored for ColorLayers.
|
||||
Animation[] animations;
|
||||
|
@ -496,6 +496,12 @@ ShadowLayerForwarder::EndTransaction(InfallibleTArray<EditReply>* aReplies)
|
||||
common.isFixedPosition() = mutant->GetIsFixedPosition();
|
||||
common.fixedPositionAnchor() = mutant->GetFixedPositionAnchor();
|
||||
common.fixedPositionMargin() = mutant->GetFixedPositionMargins();
|
||||
common.isStickyPosition() = mutant->GetIsStickyPosition();
|
||||
if (mutant->GetIsStickyPosition()) {
|
||||
common.stickyScrollContainerId() = mutant->GetStickyScrollContainerId();
|
||||
common.stickyScrollRangeOuter() = mutant->GetStickyScrollRangeOuter();
|
||||
common.stickyScrollRangeInner() = mutant->GetStickyScrollRangeInner();
|
||||
}
|
||||
if (Layer* maskLayer = mutant->GetMaskLayer()) {
|
||||
common.maskLayerChild() = Shadow(maskLayer->AsShadowableLayer());
|
||||
} else {
|
||||
|
@ -89,6 +89,61 @@ gfxCharacterMap::NotifyReleased()
|
||||
delete this;
|
||||
}
|
||||
|
||||
gfxFontEntry::gfxFontEntry() :
|
||||
mItalic(false), mFixedPitch(false),
|
||||
mIsProxy(false), mIsValid(true),
|
||||
mIsBadUnderlineFont(false),
|
||||
mIsUserFont(false),
|
||||
mIsLocalUserFont(false),
|
||||
mStandardFace(false),
|
||||
mSymbolFont(false),
|
||||
mIgnoreGDEF(false),
|
||||
mIgnoreGSUB(false),
|
||||
mSVGInitialized(false),
|
||||
mHasSpaceFeaturesInitialized(false),
|
||||
mHasSpaceFeatures(false),
|
||||
mHasSpaceFeaturesKerning(false),
|
||||
mHasSpaceFeaturesNonKerning(false),
|
||||
mHasSpaceFeaturesSubDefault(false),
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
{
|
||||
}
|
||||
|
||||
gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
|
||||
mName(aName), mItalic(false), mFixedPitch(false),
|
||||
mIsProxy(false), mIsValid(true),
|
||||
mIsBadUnderlineFont(false), mIsUserFont(false),
|
||||
mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
|
||||
mSymbolFont(false),
|
||||
mIgnoreGDEF(false),
|
||||
mIgnoreGSUB(false),
|
||||
mSVGInitialized(false),
|
||||
mHasSpaceFeaturesInitialized(false),
|
||||
mHasSpaceFeatures(false),
|
||||
mHasSpaceFeaturesKerning(false),
|
||||
mHasSpaceFeaturesNonKerning(false),
|
||||
mHasSpaceFeaturesSubDefault(false),
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
{
|
||||
memset(&mHasSpaceFeaturesSub, 0, sizeof(mHasSpaceFeaturesSub));
|
||||
}
|
||||
|
||||
gfxFontEntry::~gfxFontEntry()
|
||||
{
|
||||
// For downloaded fonts, we need to tell the user font cache that this
|
||||
@ -102,11 +157,6 @@ gfxFontEntry::~gfxFontEntry()
|
||||
// face objects should have been released.
|
||||
MOZ_ASSERT(!mHBFace);
|
||||
MOZ_ASSERT(!mGrFaceInitialized);
|
||||
|
||||
if (mSVGGlyphs) {
|
||||
delete mSVGGlyphs;
|
||||
}
|
||||
delete mUserFontData;
|
||||
}
|
||||
|
||||
bool gfxFontEntry::IsSymbolFont()
|
||||
@ -248,7 +298,7 @@ gfxFontEntry::RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId,
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFontEntry::TryGetSVGData()
|
||||
gfxFontEntry::TryGetSVGData(gfxFont* aFont)
|
||||
{
|
||||
if (!gfxPlatform::GetPlatform()->OpenTypeSVGEnabled()) {
|
||||
return false;
|
||||
@ -266,12 +316,31 @@ gfxFontEntry::TryGetSVGData()
|
||||
|
||||
// gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
|
||||
// with it.
|
||||
mSVGGlyphs = new gfxSVGGlyphs(svgTable);
|
||||
mSVGGlyphs = new gfxSVGGlyphs(svgTable, this);
|
||||
}
|
||||
|
||||
if (!mFontsUsingSVGGlyphs.Contains(aFont)) {
|
||||
mFontsUsingSVGGlyphs.AppendElement(aFont);
|
||||
}
|
||||
|
||||
return !!mSVGGlyphs;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontEntry::NotifyFontDestroyed(gfxFont* aFont)
|
||||
{
|
||||
mFontsUsingSVGGlyphs.RemoveElement(aFont);
|
||||
}
|
||||
|
||||
void
|
||||
gfxFontEntry::NotifyGlyphsChanged()
|
||||
{
|
||||
for (uint32_t i = 0, count = mFontsUsingSVGGlyphs.Length(); i < count; ++i) {
|
||||
gfxFont* font = mFontsUsingSVGGlyphs[i];
|
||||
font->NotifyGlyphsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FontTableBlobData
|
||||
*
|
||||
@ -1704,6 +1773,14 @@ gfxFont::gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
|
||||
mKerningSet = HasFeatureSet(HB_TAG('k','e','r','n'), mKerningEnabled);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
NotifyFontDestroyed(nsPtrHashKey<gfxFont::GlyphChangeObserver>* aKey,
|
||||
void* aClosure)
|
||||
{
|
||||
aKey->GetKey()->ForgetFont();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
gfxFont::~gfxFont()
|
||||
{
|
||||
uint32_t i, count = mGlyphExtentsArray.Length();
|
||||
@ -1713,6 +1790,12 @@ gfxFont::~gfxFont()
|
||||
for (i = 0; i < count; ++i) {
|
||||
delete mGlyphExtentsArray[i];
|
||||
}
|
||||
|
||||
mFontEntry->NotifyFontDestroyed(this);
|
||||
|
||||
if (mGlyphChangeObservers) {
|
||||
mGlyphChangeObservers->EnumerateEntries(NotifyFontDestroyed, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/
|
||||
@ -2295,14 +2378,14 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
double direction = aTextRun->GetDirection();
|
||||
gfxMatrix globalMatrix = aContext->CurrentMatrix();
|
||||
|
||||
bool haveSVGGlyphs = GetFontEntry()->TryGetSVGData();
|
||||
bool haveSVGGlyphs = GetFontEntry()->TryGetSVGData(this);
|
||||
nsAutoPtr<gfxTextContextPaint> contextPaint;
|
||||
if (haveSVGGlyphs && !aContextPaint) {
|
||||
// If no pattern is specified for fill, use the current pattern
|
||||
NS_ASSERTION((aDrawMode & GLYPH_STROKE) == 0, "no pattern supplied for stroking text");
|
||||
nsRefPtr<gfxPattern> fillPattern = aContext->GetPattern();
|
||||
contextPaint = new SimpleTextContextPaint(fillPattern, nullptr,
|
||||
aContext->CurrentMatrix());
|
||||
aContext->CurrentMatrix());
|
||||
aContextPaint = contextPaint;
|
||||
}
|
||||
|
||||
@ -2935,6 +3018,28 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
||||
return metrics;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
NotifyGlyphChangeObservers(nsPtrHashKey<gfxFont::GlyphChangeObserver>* aKey,
|
||||
void* aClosure)
|
||||
{
|
||||
aKey->GetKey()->NotifyGlyphsChanged();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFont::NotifyGlyphsChanged()
|
||||
{
|
||||
uint32_t i, count = mGlyphExtentsArray.Length();
|
||||
for (i = 0; i < count; ++i) {
|
||||
// Flush cached extents array
|
||||
mGlyphExtentsArray[i]->NotifyGlyphsChanged();
|
||||
}
|
||||
|
||||
if (mGlyphChangeObservers) {
|
||||
mGlyphChangeObservers->EnumerateEntries(NotifyGlyphChangeObservers, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
IsBoundarySpace(PRUnichar aChar, PRUnichar aNextChar)
|
||||
{
|
||||
@ -3389,7 +3494,7 @@ gfxFont::SetupGlyphExtents(gfxContext *aContext, uint32_t aGlyphID, bool aNeedTi
|
||||
aContext->IdentityMatrix();
|
||||
|
||||
gfxRect svgBounds;
|
||||
if (mFontEntry->TryGetSVGData() && mFontEntry->HasSVGGlyph(aGlyphID) &&
|
||||
if (mFontEntry->TryGetSVGData(this) && mFontEntry->HasSVGGlyph(aGlyphID) &&
|
||||
mFontEntry->GetSVGGlyphExtents(aContext, aGlyphID, &svgBounds)) {
|
||||
gfxFloat d2a = aExtents->GetAppUnitsPerDevUnit();
|
||||
aExtents->SetTightGlyphExtents(aGlyphID,
|
||||
@ -3725,6 +3830,23 @@ gfxFont::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
|
||||
SizeOfExcludingThis(aMallocSizeOf, aSizes);
|
||||
}
|
||||
|
||||
void
|
||||
gfxFont::AddGlyphChangeObserver(GlyphChangeObserver *aObserver)
|
||||
{
|
||||
if (!mGlyphChangeObservers) {
|
||||
mGlyphChangeObservers = new nsTHashtable<nsPtrHashKey<GlyphChangeObserver> >;
|
||||
}
|
||||
mGlyphChangeObservers->PutEntry(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
gfxFont::RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver)
|
||||
{
|
||||
NS_ASSERTION(mGlyphChangeObservers, "No observers registered");
|
||||
NS_ASSERTION(mGlyphChangeObservers->Contains(aObserver), "Observer not registered");
|
||||
mGlyphChangeObservers->RemoveEntry(aObserver);
|
||||
}
|
||||
|
||||
gfxGlyphExtents::~gfxGlyphExtents()
|
||||
{
|
||||
#ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
|
||||
|
@ -228,35 +228,7 @@ class gfxFontEntry {
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(gfxFontEntry)
|
||||
|
||||
gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false) :
|
||||
mName(aName), mItalic(false), mFixedPitch(false),
|
||||
mIsProxy(false), mIsValid(true),
|
||||
mIsBadUnderlineFont(false), mIsUserFont(false),
|
||||
mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
|
||||
mSymbolFont(false),
|
||||
mIgnoreGDEF(false),
|
||||
mIgnoreGSUB(false),
|
||||
mSVGInitialized(false),
|
||||
mHasSpaceFeaturesInitialized(false),
|
||||
mHasSpaceFeatures(false),
|
||||
mHasSpaceFeaturesKerning(false),
|
||||
mHasSpaceFeaturesNonKerning(false),
|
||||
mHasSpaceFeaturesSubDefault(false),
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mUserFontData(nullptr),
|
||||
mSVGGlyphs(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
{
|
||||
memset(&mHasSpaceFeaturesSub, 0, sizeof(mHasSpaceFeaturesSub));
|
||||
}
|
||||
|
||||
gfxFontEntry(const nsAString& aName, bool aIsStandardFace = false);
|
||||
virtual ~gfxFontEntry();
|
||||
|
||||
// unique name for the face, *not* the family; not necessarily the
|
||||
@ -324,12 +296,15 @@ public:
|
||||
// can be safely dereferenced.
|
||||
virtual nsresult ReadCMAP();
|
||||
|
||||
bool TryGetSVGData();
|
||||
bool TryGetSVGData(gfxFont* aFont);
|
||||
bool HasSVGGlyph(uint32_t aGlyphId);
|
||||
bool GetSVGGlyphExtents(gfxContext *aContext, uint32_t aGlyphId,
|
||||
gfxRect *aResult);
|
||||
bool RenderSVGGlyph(gfxContext *aContext, uint32_t aGlyphId, int aDrawMode,
|
||||
gfxTextContextPaint *aContextPaint);
|
||||
// Call this when glyph geometry or rendering has changed
|
||||
// (e.g. animated SVG glyphs)
|
||||
void NotifyGlyphsChanged();
|
||||
|
||||
virtual bool MatchesGenericFamily(const nsACString& aGeneric) const {
|
||||
return true;
|
||||
@ -414,6 +389,10 @@ public:
|
||||
// Caller must call gfxFontEntry::ReleaseGrFace when finished with it.
|
||||
gr_face* GetGrFace();
|
||||
virtual void ReleaseGrFace(gr_face* aFace);
|
||||
|
||||
// Called to notify that aFont is being destroyed. Needed when we're tracking
|
||||
// the fonts belonging to this font entry.
|
||||
void NotifyFontDestroyed(gfxFont* aFont);
|
||||
|
||||
// For memory reporting
|
||||
virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
@ -455,9 +434,10 @@ public:
|
||||
nsRefPtr<gfxCharacterMap> mCharacterMap;
|
||||
uint32_t mUVSOffset;
|
||||
nsAutoArrayPtr<uint8_t> mUVSData;
|
||||
gfxUserFontData* mUserFontData;
|
||||
gfxSVGGlyphs *mSVGGlyphs;
|
||||
|
||||
nsAutoPtr<gfxUserFontData> mUserFontData;
|
||||
nsAutoPtr<gfxSVGGlyphs> mSVGGlyphs;
|
||||
// list of gfxFonts that are using SVG glyphs
|
||||
nsTArray<gfxFont*> mFontsUsingSVGGlyphs;
|
||||
nsTArray<gfxFontFeature> mFeatureSettings;
|
||||
uint32_t mLanguageOverride;
|
||||
|
||||
@ -468,34 +448,7 @@ protected:
|
||||
friend class gfxFontFamily;
|
||||
friend class gfxSingleFaceMacFontFamily;
|
||||
|
||||
gfxFontEntry() :
|
||||
mItalic(false), mFixedPitch(false),
|
||||
mIsProxy(false), mIsValid(true),
|
||||
mIsBadUnderlineFont(false),
|
||||
mIsUserFont(false),
|
||||
mIsLocalUserFont(false),
|
||||
mStandardFace(false),
|
||||
mSymbolFont(false),
|
||||
mIgnoreGDEF(false),
|
||||
mIgnoreGSUB(false),
|
||||
mSVGInitialized(false),
|
||||
mHasSpaceFeaturesInitialized(false),
|
||||
mHasSpaceFeatures(false),
|
||||
mHasSpaceFeaturesKerning(false),
|
||||
mHasSpaceFeaturesNonKerning(false),
|
||||
mHasSpaceFeaturesSubDefault(false),
|
||||
mCheckedForGraphiteTables(false),
|
||||
mHasCmapTable(false),
|
||||
mGrFaceInitialized(false),
|
||||
mWeight(500), mStretch(NS_FONT_STRETCH_NORMAL),
|
||||
mUVSOffset(0), mUVSData(nullptr),
|
||||
mUserFontData(nullptr),
|
||||
mSVGGlyphs(nullptr),
|
||||
mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
|
||||
mHBFace(nullptr),
|
||||
mGrFace(nullptr),
|
||||
mGrFaceRefCnt(0)
|
||||
{ }
|
||||
gfxFontEntry();
|
||||
|
||||
virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle, bool aNeedsBold) {
|
||||
NS_NOTREACHED("oops, somebody didn't override CreateFontInstance");
|
||||
@ -1160,6 +1113,10 @@ public:
|
||||
|
||||
enum { INVALID_WIDTH = 0xFFFF };
|
||||
|
||||
void NotifyGlyphsChanged() {
|
||||
mTightGlyphExtents.Clear();
|
||||
}
|
||||
|
||||
// returns INVALID_WIDTH => not a contained glyph
|
||||
// Otherwise the glyph has no before-bearing or vertical bearings,
|
||||
// and the result is its width measured from the baseline origin, in
|
||||
@ -1695,6 +1652,9 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Glyph rendering/geometry has changed, so invalidate data as necessary.
|
||||
void NotifyGlyphsChanged();
|
||||
|
||||
virtual void SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
FontCacheSizes* aSizes) const;
|
||||
virtual void SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
@ -1718,7 +1678,39 @@ public:
|
||||
return mKerningSet && !mKerningEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass this object to be notified of glyph changes. Delete the object
|
||||
* when no longer needed.
|
||||
*/
|
||||
class GlyphChangeObserver {
|
||||
public:
|
||||
virtual ~GlyphChangeObserver()
|
||||
{
|
||||
if (mFont) {
|
||||
mFont->RemoveGlyphChangeObserver(this);
|
||||
}
|
||||
}
|
||||
// This gets called when the gfxFont dies.
|
||||
void ForgetFont() { mFont = nullptr; }
|
||||
virtual void NotifyGlyphsChanged() = 0;
|
||||
protected:
|
||||
GlyphChangeObserver(gfxFont *aFont) : mFont(aFont)
|
||||
{
|
||||
mFont->AddGlyphChangeObserver(this);
|
||||
}
|
||||
gfxFont* mFont;
|
||||
};
|
||||
friend class GlyphChangeObserver;
|
||||
|
||||
bool GlyphsMayChange()
|
||||
{
|
||||
// Currently only fonts with SVG glyphs can have animated glyphs
|
||||
return mFontEntry->TryGetSVGData(this);
|
||||
}
|
||||
|
||||
protected:
|
||||
void AddGlyphChangeObserver(GlyphChangeObserver *aObserver);
|
||||
void RemoveGlyphChangeObserver(GlyphChangeObserver *aObserver);
|
||||
|
||||
bool HasSubstitutionRulesWithSpaceLookups(int32_t aRunScript) {
|
||||
NS_ASSERTION(GetFontEntry()->mHasSpaceFeaturesInitialized,
|
||||
@ -1925,6 +1917,7 @@ protected:
|
||||
nsExpirationState mExpirationState;
|
||||
gfxFontStyle mStyle;
|
||||
nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray;
|
||||
nsAutoPtr<nsTHashtable<nsPtrHashKey<GlyphChangeObserver> > > mGlyphChangeObservers;
|
||||
|
||||
gfxFloat mAdjustedSize;
|
||||
|
||||
|
@ -31,11 +31,15 @@
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsHostObjectProtocolHandler.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "gfxFont.h"
|
||||
#include "nsSMILAnimationController.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
#define SVG_CONTENT_TYPE NS_LITERAL_CSTRING("image/svg+xml")
|
||||
#define UTF8_CHARSET NS_LITERAL_CSTRING("utf-8")
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
typedef mozilla::dom::Element Element;
|
||||
|
||||
mozilla::gfx::UserDataKey gfxTextContextPaint::sUserDataKey;
|
||||
@ -44,10 +48,10 @@ const float gfxSVGGlyphs::SVG_UNITS_PER_EM = 1000.0f;
|
||||
|
||||
const gfxRGBA SimpleTextContextPaint::sZero = gfxRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable)
|
||||
gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable, gfxFontEntry *aFontEntry)
|
||||
: mSVGData(aSVGTable)
|
||||
, mFontEntry(aFontEntry)
|
||||
{
|
||||
mSVGData = aSVGTable;
|
||||
|
||||
unsigned int length;
|
||||
const char* svgData = hb_blob_get_data(mSVGData, &length);
|
||||
mHeader = reinterpret_cast<const Header*>(svgData);
|
||||
@ -70,6 +74,12 @@ gfxSVGGlyphs::~gfxSVGGlyphs()
|
||||
hb_blob_destroy(mSVGData);
|
||||
}
|
||||
|
||||
void
|
||||
gfxSVGGlyphs::DidRefresh()
|
||||
{
|
||||
mFontEntry->NotifyGlyphsChanged();
|
||||
}
|
||||
|
||||
/*
|
||||
* Comparison operator for finding a range containing a given glyph ID. Simply
|
||||
* checks whether |key| is less (greater) than every element of |range|, in
|
||||
@ -120,7 +130,7 @@ gfxSVGGlyphs::FindOrCreateGlyphsDocument(uint32_t aGlyphId)
|
||||
if (entry->mDocOffset > 0 &&
|
||||
uint64_t(mHeader->mDocIndexOffset) + entry->mDocOffset + entry->mDocLength <= length) {
|
||||
result = new gfxSVGGlyphsDocument(data + mHeader->mDocIndexOffset + entry->mDocOffset,
|
||||
entry->mDocLength);
|
||||
entry->mDocLength, this);
|
||||
mGlyphDocs.Put(entry->mDocOffset, result);
|
||||
}
|
||||
}
|
||||
@ -131,8 +141,6 @@ gfxSVGGlyphs::FindOrCreateGlyphsDocument(uint32_t aGlyphId)
|
||||
nsresult
|
||||
gfxSVGGlyphsDocument::SetupPresentation()
|
||||
{
|
||||
mDocument->SetIsBeingUsedAsImage();
|
||||
|
||||
nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
||||
nsXPIDLCString contractId;
|
||||
nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", "image/svg+xml", getter_Copies(contractId));
|
||||
@ -154,22 +162,36 @@ gfxSVGGlyphsDocument::SetupPresentation()
|
||||
nsCOMPtr<nsIPresShell> presShell;
|
||||
rv = viewer->GetPresShell(getter_AddRefs(presShell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
presShell->GetPresContext()->SetIsGlyph(true);
|
||||
nsPresContext* presContext = presShell->GetPresContext();
|
||||
presContext->SetIsGlyph(true);
|
||||
|
||||
if (!presShell->DidInitialize()) {
|
||||
nsRect rect = presShell->GetPresContext()->GetVisibleArea();
|
||||
nsRect rect = presContext->GetVisibleArea();
|
||||
rv = presShell->Initialize(rect.width, rect.height);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
mDocument->FlushPendingNotifications(Flush_Layout);
|
||||
|
||||
nsSMILAnimationController* controller = mDocument->GetAnimationController();
|
||||
if (controller) {
|
||||
controller->Resume(nsSMILTimeContainer::PAUSE_IMAGE);
|
||||
}
|
||||
mDocument->SetImagesNeedAnimating(true);
|
||||
|
||||
mViewer = viewer;
|
||||
mPresShell = presShell;
|
||||
mPresShell->AddPostRefreshObserver(this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
gfxSVGGlyphsDocument::DidRefresh()
|
||||
{
|
||||
mOwner->DidRefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Walk the DOM tree to find all glyph elements and insert them into the lookup
|
||||
* table
|
||||
@ -251,7 +273,10 @@ gfxSVGGlyphsDocument::GetGlyphElement(uint32_t aGlyphId)
|
||||
return mGlyphIdMap.Get(aGlyphId);
|
||||
}
|
||||
|
||||
gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen)
|
||||
gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer,
|
||||
uint32_t aBufLen,
|
||||
gfxSVGGlyphs *aSVGGlyphs)
|
||||
: mOwner(aSVGGlyphs)
|
||||
{
|
||||
ParseDocument(aBuffer, aBufLen);
|
||||
if (!mDocument) {
|
||||
@ -274,6 +299,22 @@ gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBuf
|
||||
FindGlyphElements(root);
|
||||
}
|
||||
|
||||
gfxSVGGlyphsDocument::~gfxSVGGlyphsDocument()
|
||||
{
|
||||
if (mDocument) {
|
||||
nsSMILAnimationController* controller = mDocument->GetAnimationController();
|
||||
if (controller) {
|
||||
controller->Pause(nsSMILTimeContainer::PAUSE_PAGEHIDE);
|
||||
}
|
||||
}
|
||||
if (mPresShell) {
|
||||
mPresShell->RemovePostRefreshObserver(this);
|
||||
}
|
||||
if (mViewer) {
|
||||
mViewer->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
static nsresult
|
||||
CreateBufferedStream(const uint8_t *aBuffer, uint32_t aBufLen,
|
||||
nsCOMPtr<nsIInputStream> &aResult)
|
||||
@ -339,6 +380,8 @@ gfxSVGGlyphsDocument::ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen)
|
||||
|
||||
channel->SetOwner(principal);
|
||||
|
||||
// Set this early because various decisions during page-load depend on it.
|
||||
document->SetIsBeingUsedAsImage();
|
||||
document->SetReadyStateInternal(nsIDocument::READYSTATE_UNINITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener;
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include "gfxPattern.h"
|
||||
#include "gfxFont.h"
|
||||
#include "mozilla/gfx/UserData.h"
|
||||
#include "nsRefreshDriver.h"
|
||||
|
||||
class gfxSVGGlyphs;
|
||||
|
||||
|
||||
/**
|
||||
@ -27,21 +30,20 @@
|
||||
* Finds and looks up elements contained in the SVG document which have glyph
|
||||
* mappings to be drawn by gfxSVGGlyphs
|
||||
*/
|
||||
class gfxSVGGlyphsDocument
|
||||
class gfxSVGGlyphsDocument MOZ_FINAL : public nsAPostRefreshObserver
|
||||
{
|
||||
typedef mozilla::dom::Element Element;
|
||||
typedef gfxFont::DrawMode DrawMode;
|
||||
|
||||
public:
|
||||
gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen);
|
||||
gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen,
|
||||
gfxSVGGlyphs *aSVGGlyphs);
|
||||
|
||||
Element *GetGlyphElement(uint32_t aGlyphId);
|
||||
|
||||
~gfxSVGGlyphsDocument() {
|
||||
if (mViewer) {
|
||||
mViewer->Destroy();
|
||||
}
|
||||
}
|
||||
~gfxSVGGlyphsDocument();
|
||||
|
||||
virtual void DidRefresh() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsresult ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen);
|
||||
@ -52,6 +54,8 @@ private:
|
||||
|
||||
void InsertGlyphId(Element *aGlyphElement);
|
||||
|
||||
// Weak so as not to create a cycle. mOwner owns us so this can't dangle.
|
||||
gfxSVGGlyphs* mOwner;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsIContentViewer> mViewer;
|
||||
nsCOMPtr<nsIPresShell> mPresShell;
|
||||
@ -83,13 +87,18 @@ public:
|
||||
* that are passed in, and will hb_blob_destroy() them when finished;
|
||||
* the caller should -not- destroy these references.
|
||||
*/
|
||||
gfxSVGGlyphs(hb_blob_t *aSVGTable);
|
||||
gfxSVGGlyphs(hb_blob_t *aSVGTable, gfxFontEntry *aFontEntry);
|
||||
|
||||
/**
|
||||
* Releases our references to the SVG table.
|
||||
* Releases our references to the SVG table and cleans up everything else.
|
||||
*/
|
||||
~gfxSVGGlyphs();
|
||||
|
||||
/**
|
||||
* This is called when the refresh driver has ticked.
|
||||
*/
|
||||
void DidRefresh();
|
||||
|
||||
/**
|
||||
* Find the |gfxSVGGlyphsDocument| containing an SVG glyph for |aGlyphId|.
|
||||
* If |aGlyphId| does not map to an SVG document, return null.
|
||||
@ -126,6 +135,7 @@ private:
|
||||
nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
|
||||
|
||||
hb_blob_t *mSVGData;
|
||||
gfxFontEntry *mFontEntry;
|
||||
|
||||
const struct Header {
|
||||
mozilla::AutoSwap_PRUint16 mVersion;
|
||||
|
@ -246,7 +246,8 @@ public:
|
||||
kWindowsServer2003 = 0x50002,
|
||||
kWindowsVista = 0x60000,
|
||||
kWindows7 = 0x60001,
|
||||
kWindows8 = 0x60002
|
||||
kWindows8 = 0x60002,
|
||||
kWindows8_1 = 0x60003
|
||||
};
|
||||
|
||||
static int32_t WindowsOSVersion(int32_t *aBuildNum = nullptr);
|
||||
|
@ -54,7 +54,7 @@ function takeReferenceSnapshot() {
|
||||
"reference div should disappear when it becomes display:none");
|
||||
}
|
||||
|
||||
function myOnStopFrame() {
|
||||
function myOnStopFrame(aRequest) {
|
||||
gOnStopFrameCounter++;
|
||||
ok(true, "myOnStopFrame called");
|
||||
let currentSnapshot = snapshotWindow(window, false);
|
||||
@ -64,8 +64,7 @@ function myOnStopFrame() {
|
||||
"at call #" + gOnStopFrameCounter + " to onStopFrame");
|
||||
cleanUpAndFinish();
|
||||
}
|
||||
else
|
||||
setTimeout(myOnStopFrame, 1);
|
||||
setTimeout(function() { myOnStopFrame(0, 0); }, 1000);
|
||||
}
|
||||
|
||||
function failTest() {
|
||||
@ -81,6 +80,8 @@ function cleanUpAndFinish() {
|
||||
if (gIsTestFinished) {
|
||||
return;
|
||||
}
|
||||
let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent);
|
||||
imgLoadingContent.removeObserver(gMyDecoderObserver);
|
||||
SimpleTest.finish();
|
||||
gIsTestFinished = true;
|
||||
}
|
||||
@ -88,12 +89,19 @@ function cleanUpAndFinish() {
|
||||
function main() {
|
||||
takeReferenceSnapshot();
|
||||
|
||||
// Create, customize & attach decoder observer
|
||||
observer = new ImageDecoderObserverStub();
|
||||
observer.frameComplete = myOnStopFrame;
|
||||
gMyDecoderObserver =
|
||||
Cc["@mozilla.org/image/tools;1"].getService(Ci.imgITools)
|
||||
.createScriptedObserver(observer);
|
||||
let imgLoadingContent = gImg.QueryInterface(Ci.nsIImageLoadingContent);
|
||||
imgLoadingContent.addObserver(gMyDecoderObserver);
|
||||
|
||||
// We want to test the cold loading behavior, so clear cache in case an
|
||||
// earlier test got our image in there already.
|
||||
clearImageCache();
|
||||
|
||||
setTimeout(myOnStopFrame, 1);
|
||||
|
||||
// kick off image-loading! myOnStopFrame handles the rest.
|
||||
gImg.setAttribute("src", "lime-anim-100x100.svg");
|
||||
|
||||
|
@ -287,7 +287,6 @@ class Message : public Pickle {
|
||||
COMPRESS_BIT = 0x0200
|
||||
};
|
||||
|
||||
#pragma pack(push, 2)
|
||||
struct Header : Pickle::Header {
|
||||
int32_t routing; // ID of the view that this message is destined for
|
||||
msgid_t type; // specifies the user-defined message type
|
||||
@ -305,7 +304,6 @@ class Message : public Pickle {
|
||||
// Sequence number
|
||||
int32_t seqno;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
Header* header() {
|
||||
return headerT<Header>();
|
||||
|
@ -400,37 +400,10 @@ js::DirectEvalFromIon(JSContext *cx,
|
||||
NullFramePtr() /* evalInFrame */, vp.address());
|
||||
}
|
||||
|
||||
// We once supported a second argument to eval to use as the scope chain
|
||||
// when evaluating the code string. Warn when such uses are seen so that
|
||||
// authors will know that support for eval(s, o) has been removed.
|
||||
static inline bool
|
||||
WarnOnTooManyArgs(JSContext *cx, const CallArgs &args)
|
||||
{
|
||||
if (args.length() > 1) {
|
||||
Rooted<JSScript*> script(cx, cx->currentScript());
|
||||
if (script && !script->warnedAboutTwoArgumentEval) {
|
||||
static const char TWO_ARGUMENT_WARNING[] =
|
||||
"Support for eval(code, scopeObject) has been removed. "
|
||||
"Use |with (scopeObject) eval(code);| instead.";
|
||||
if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
|
||||
return false;
|
||||
script->warnedAboutTwoArgumentEval = true;
|
||||
} else {
|
||||
// In the case of an indirect call without a caller frame, avoid a
|
||||
// potential warning-flood by doing nothing.
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::IndirectEval(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!WarnOnTooManyArgs(cx, args))
|
||||
return false;
|
||||
|
||||
Rooted<GlobalObject*> global(cx, &args.callee().global());
|
||||
return EvalKernel(cx, args, INDIRECT_EVAL, NullFramePtr(), global, NULL);
|
||||
}
|
||||
@ -447,9 +420,6 @@ js::DirectEval(JSContext *cx, const CallArgs &args)
|
||||
JS_ASSERT_IF(caller.isFunctionFrame(),
|
||||
caller.compartment() == caller.callee()->compartment());
|
||||
|
||||
if (!WarnOnTooManyArgs(cx, args))
|
||||
return false;
|
||||
|
||||
RootedObject scopeChain(cx, caller.scopeChain());
|
||||
return EvalKernel(cx, args, DIRECT_EVAL, caller, scopeChain, iter.pc());
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ class FileKind(object):
|
||||
|
||||
def get_all_filenames():
|
||||
'''Get a list of all the files in the (Mercurial or Git) repository.'''
|
||||
cmds = [['hg', 'manifest', '-q'], ['git', 'ls-files']]
|
||||
cmds = [['hg', 'manifest', '-q'], ['git', 'ls-files', '--full-name', '../..']]
|
||||
for cmd in cmds:
|
||||
try:
|
||||
all_filenames = subprocess.check_output(cmd, universal_newlines=True,
|
||||
|
@ -7,10 +7,10 @@ const ASM_TYPE_FAIL_STRING = "asm.js type error:";
|
||||
const ASM_DIRECTIVE_FAIL_STRING = "\"use asm\" is only meaningful in the Directive Prologue of a function body";
|
||||
|
||||
const USE_ASM = "'use asm';";
|
||||
const HEAP_IMPORTS = "var i8=new glob.Int8Array(b);var u8=new glob.Uint8Array(b);"+
|
||||
"var i16=new glob.Int16Array(b);var u16=new glob.Uint16Array(b);"+
|
||||
"var i32=new glob.Int32Array(b);var u32=new glob.Uint32Array(b);"+
|
||||
"var f32=new glob.Float32Array(b);var f64=new glob.Float64Array(b);";
|
||||
const HEAP_IMPORTS = "const i8=new glob.Int8Array(b);var u8=new glob.Uint8Array(b);"+
|
||||
"const i16=new glob.Int16Array(b);var u16=new glob.Uint16Array(b);"+
|
||||
"const i32=new glob.Int32Array(b);var u32=new glob.Uint32Array(b);"+
|
||||
"const f32=new glob.Float32Array(b);var f64=new glob.Float64Array(b);";
|
||||
const BUF_64KB = new ArrayBuffer(64 * 1024);
|
||||
|
||||
function asmCompile()
|
||||
|
@ -48,8 +48,11 @@ assertEq(f(), 2);
|
||||
assertEq(counter, 3);
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add1=imp.add1; function g(i) { i=i|0; return add1(i|0)|0 } return g'), null, imp)(9), 10);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'const add1=imp.add1; function g(i) { i=i|0; return add1(i|0)|0 } return g'), null, imp)(9), 10);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add3=imp.add3; function g() { var i=1,j=3,k=9; return add3(i|0,j|0,k|0)|0 } return g'), null, imp)(), 13);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'const add3=imp.add3; function g() { var i=1,j=3,k=9; return add3(i|0,j|0,k|0)|0 } return g'), null, imp)(), 13);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add3=imp.add3; function g() { var i=1.4,j=2.3,k=32.1; return +add3(i,j,k) } return g'), null, imp)(), 1.4+2.3+32.1);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'const add3=imp.add3; function g() { var i=1.4,j=2.3,k=32.1; return +add3(i,j,k) } return g'), null, imp)(), 1.4+2.3+32.1);
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var add3=imp.add3; function f(i,j,k) { i=i|0;j=+j;k=k|0; return add3(i|0,j,k|0)|0 } return f'), null, imp)(1, 2.5, 3), 6);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var addN=imp.addN; function f() { return +addN(1,2,3,4.1,5,6.1,7,8.1,9.1,10,11.1,12,13,14.1,15.1,16.1,17.1,18.1) } return f'), null, imp)(), 1+2+3+4.1+5+6.1+7+8.1+9.1+10+11.1+12+13+14.1+15.1+16.1+17.1+18.1);
|
||||
|
@ -27,18 +27,42 @@ assertAsmTypeFail(USE_ASM + "function f(i) {i=i|0} function g(i) { i=i|0; return
|
||||
assertAsmTypeFail(USE_ASM + "function f(i) {i=i|0} function g(i) { i=i|0; return tbl[i&1](3.0)|0 } var tbl=[f,f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "function f(d) {d=+d} function g(i) { i=i|0; return tbl[i&1](3)|0 } var tbl=[f,f]; return g");
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g(i) { i=i|0; return tbl[i&1]()|0 } var tbl=[f,f]; return g"))(0), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g(i) { i=i|0; return tbl[i&1]()|0 } const tbl=[f,f]; return g"))(0), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl[i&1]()|0 } var tbl=[f,g]; return h"))(1), 13);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl[i&1]()|0 } const tbl=[f,g]; return h"))(1), 13);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&1]()|0 } var tbl1=[f,g]; var tbl2=[g,f]; return h"))(1), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&1]()|0 } const tbl1=[f,g]; const tbl2=[g,f]; return h"))(1), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&3]()|0 } var tbl1=[f,g]; var tbl2=[g,g,g,f]; return h"))(3), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl2[i&3]()|0 } const tbl1=[f,g]; const tbl2=[g,g,g,f]; return h"))(3), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl1[i&1]()|0 } var tbl1=[f,g]; var tbl2=[g,g,g,f]; return h"))(1), 13);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() {return 13} function h(i) { i=i|0; return tbl1[i&1]()|0 } const tbl1=[f,g]; const tbl2=[g,g,g,f]; return h"))(1), 13);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=0,j=0; function f() {return i|0} function g() {return j|0} function h(x) { x=x|0; i=5;j=10; return tbl2[x&3]()|0 } var tbl1=[f,g]; var tbl2=[g,g,g,f]; return h"))(3), 5);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=0,j=0; function f() {return i|0} function g() {return j|0} function h(x) { x=x|0; i=5;j=10; return tbl2[x&3]()|0 } const tbl1=[f,g]; const tbl2=[g,g,g,f]; return h"))(3), 5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "var ffi=imp.ffi; function f() {return ffi()|0} function g() {return 13} function h(x) { x=x|0; return tbl2[x&3]()|0 } var tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 20);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "var ffi=imp.ffi; var i=0; function f() {return ((ffi()|0)+i)|0} function g() {return 13} function h(x) { x=x|0; i=2; return tbl2[x&3]()|0 } var tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 22);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "const ffi=imp.ffi; function f() {return ffi()|0} function g() {return 13} function h(x) { x=x|0; return tbl2[x&3]()|0 } const tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 20);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "var ffi=imp.ffi; var i=0; function f() {return ((ffi()|0)+i)|0} function g() {return 13} function h(x) { x=x|0; i=2; return tbl2[x&3]()|0 } var tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 22)
|
||||
;assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + "const ffi=imp.ffi; var i=0; function f() {return ((ffi()|0)+i)|0} function g() {return 13} function h(x) { x=x|0; i=2; return tbl2[x&3]()|0 } const tbl2=[g,g,g,f]; return h"), null, {ffi:function(){return 20}})(3), 22);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i) {i=i|0; return +((i+1)|0)} function g(d) { d=+d; return +(d+2.5) } function h(i,j) { i=i|0;j=j|0; return +tbl2[i&1](+tbl1[i&1](j)) } var tbl1=[f,f]; var tbl2=[g,g]; return h"))(0,10), 11+2.5);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f(i) {i=i|0; return +((i+1)|0)} function g(d) { d=+d; return +(d+2.5) } function h(i,j) { i=i|0;j=j|0; return +tbl2[i&1](+tbl1[i&1](j)) } const tbl1=[f,f]; const tbl2=[g,g]; return h"))(0,10), 11+2.5);
|
||||
|
||||
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0]()|0 } var tbl=[f]; return g");
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() { return tbl[0&0]()|0 } var tbl=[f]; return g"))(), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f() {return 42} function g() { return tbl[0&0]()|0 } const tbl=[f]; return g"))(), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f1() {return 42} function f2() {return 13} function g() { return tbl[1&1]()|0 } var tbl=[f1,f2]; return g"))(), 13);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "function f1() {return 42} function f2() {return 13} function g() { return tbl[1&1]()|0 } const tbl=[f1,f2]; return g"))(), 13);
|
||||
|
||||
// Test some literal constant paths.
|
||||
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&4294967295]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "const i=4294967295; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&-1]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "const i=-1; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&0x80000000]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "const i=0x80000000; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&-2147483648]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "const i=-2147483648; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
|
||||
assertAsmTypeFail(USE_ASM + "const i=0; function f() {return 42} function g() { return tbl[0&i]()|0 } var tbl=[f]; return g");
|
||||
// Limited by the inability to test really large tables.
|
||||
assertAsmTypeFail(USE_ASM + "function f() {return 42} function g() { return tbl[0&0x7fffffff]()|0 } var tbl=[f]; return g");
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "function f1(d) {d=+d; return +(d/2.0)} function f2(d) {d=+d; return +(d+10.0)} function g(i,j) { i=i|0;j=+j; return +tbl[i&1](+tbl[(i+1)&1](j)) } var tbl=[f1,f2]; return g"));
|
||||
assertEq(f(0,10.2), (10.2+10)/2);
|
||||
|
@ -1,15 +1,29 @@
|
||||
load(libdir + "asm.js");
|
||||
|
||||
assertAsmTypeFail(USE_ASM + "var i; function f(){} return f");
|
||||
assertAsmTypeFail(USE_ASM + "const i; function f(){} return f");
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=0; function f(){} return f"))(), undefined);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "const i=0; function f(){} return f"))(), undefined);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=42; function f(){ return i|0 } return f"))(), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "const i=42; function f(){ return i|0 } return f"))(), 42);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=4.2; function f(){ return +i } return f"))(), 4.2);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "const i=4.2; function f(){ return +i } return f"))(), 4.2);
|
||||
assertAsmTypeFail(USE_ASM + "var i=42; function f(){ return +(i+.1) } return f");
|
||||
assertAsmTypeFail(USE_ASM + "const i=42; function f(){ return +(i+.1) } return f");
|
||||
assertAsmTypeFail(USE_ASM + "var i=1.2; function f(){ return i|0 } return f");
|
||||
assertAsmTypeFail(USE_ASM + "const i=1.2; function f(){ return i|0 } return f");
|
||||
assertAsmTypeFail(USE_ASM + "var i=0; function f(e){ e=+e; i=e } return f");
|
||||
assertAsmTypeFail(USE_ASM + "const i=0; function f(e){ e=+e; i=e } return f");
|
||||
assertAsmTypeFail(USE_ASM + "var d=0.1; function f(i){ i=i|0; d=i } return f");
|
||||
assertAsmTypeFail(USE_ASM + "const d=0.1; function f(i){ i=i|0; d=i } return f");
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=13; function f(j) { j=j|0; i=j; return i|0 } return f"))(42), 42);
|
||||
assertAsmTypeFail(USE_ASM + "const i=13; function f(j) { j=j|0; i=j; return i|0 } return f");
|
||||
assertAsmTypeFail(USE_ASM + "const c=0,i=13; function f(j) { j=j|0; i=j; return i|0 } return f");
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var d=.1; function f(e) { e=+e; d=e; return +e } return f"))(42.1), 42.1);
|
||||
assertAsmTypeFail(USE_ASM + "const d=.1; function f(e) { e=+e; d=e; return +e } return f");
|
||||
assertAsmTypeFail(USE_ASM + "const c=0, d=.1; function f(e) { e=+e; d=e; return +e } return f");
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=13; function f(i, j) { i=i|0; j=j|0; i=j; return i|0 } return f"))(42,43), 43);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var i=13; function f(j) { j=j|0; var i=0; i=j; return i|0 } return f"))(42), 42);
|
||||
|
||||
var f = asmLink(asmCompile(USE_ASM + "var i=13; function f(j) { j=j|0; if ((j|0) != -1) { i=j } else { return i|0 } return 0 } return f"));
|
||||
assertEq(f(-1), 13);
|
||||
@ -17,19 +31,27 @@ assertEq(f(42), 0);
|
||||
assertEq(f(-1), 42);
|
||||
|
||||
assertAsmTypeFail('global', USE_ASM + "var i=global; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + "const i=global; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + "var i=global|0; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + "const i=global|0; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + "var j=0;var i=j.i|0; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + "var i=global.i|0; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + "const i=global.i|0; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + "var i=global.i|0; function f() { return i|0 } return f");
|
||||
assertAsmTypeFail('global', USE_ASM + 'var i=global.Infinity; function f() { i = 0.0 } return f');
|
||||
assertAsmTypeFail('global', USE_ASM + 'const i=global.Infinity; function f() { i = 0.0 } return f');
|
||||
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), undefined);
|
||||
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), undefined);
|
||||
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), null);
|
||||
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), null);
|
||||
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), 3);
|
||||
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {});
|
||||
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {Infinity:NaN});
|
||||
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {Infinity:-Infinity});
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), {Infinity:Infinity})(), Infinity);
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), {Infinity:Infinity})(), Infinity);
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.Infinity; function f() { return +i } return f'), this)(), Infinity);
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.Infinity; function f() { return +i } return f'), this)(), Infinity);
|
||||
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), undefined);
|
||||
assertAsmLinkAlwaysFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), null);
|
||||
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), 3);
|
||||
@ -37,10 +59,14 @@ assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f()
|
||||
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), {Infinity:Infinity});
|
||||
assertAsmLinkFail(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), {Infinity:-Infinity});
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), {NaN:NaN})(), NaN);
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.NaN; function f() { return +i } return f'), {NaN:NaN})(), NaN);
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'var i=global.NaN; function f() { return +i } return f'), this)(), NaN);
|
||||
assertEq(asmLink(asmCompile('global', USE_ASM + 'const i=global.NaN; function f() { return +i } return f'), this)(), NaN);
|
||||
|
||||
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'var t = new glob.Int32Array(buf); function f() {} return f'), {get Int32Array(){return Int32Array}}, null, new ArrayBuffer(4096))
|
||||
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'const t = new glob.Int32Array(buf); function f() {} return f'), {get Int32Array(){return Int32Array}}, null, new ArrayBuffer(4096))
|
||||
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'var t = new glob.Int32Array(buf); function f() {} return f'), new Proxy({}, {get:function() {return Int32Array}}), null, new ArrayBuffer(4096))
|
||||
assertAsmLinkFail(asmCompile('glob','foreign','buf', USE_ASM + 'const t = new glob.Int32Array(buf); function f() {} return f'), new Proxy({}, {get:function() {return Int32Array}}), null, new ArrayBuffer(4096))
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var t = glob.Math.sin; function f() {} return f'), {get Math(){return Math}});
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var t = glob.Math.sin; function f() {} return f'), new Proxy({}, {get:function(){return Math}}));
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var t = glob.Math.sin; function f() {} return f'), {Math:{get sin(){return Math.sin}}});
|
||||
@ -61,9 +87,13 @@ assertAsmLinkAlwaysFail(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; fu
|
||||
assertAsmLinkAlwaysFail(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f"), this, null);
|
||||
assertAsmLinkFail(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f"), this, 42);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f")(null, {i:42})), 42);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=imp.i|0; function f() { return i|0 } return f")(null, {i:42})), 42);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=imp.i|0; function f() { return i|0 } return f")(null, {i:1.4})), 1);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=imp.i|0; function f() { return i|0 } return f")(null, {i:1.4})), 1);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(null, {i:42})), 42);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(null, {i:42})), 42);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "var i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
|
||||
assertEq(asmLink(asmCompile('global', 'imp', USE_ASM + "const i=+imp.i; function f() { return +i } return f")(this, {i:1.4})), 1.4);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + "var g=0; function f() { var i=42; while (1) { break; } g = i; return g|0 } return f"))(), 42);
|
||||
|
||||
var f1 = asmCompile('global', 'foreign', 'heap', USE_ASM + 'var i32 = new global.Int32Array(heap); function g() { return i32[4]|0 } return g');
|
||||
|
@ -453,3 +453,81 @@ assertEq(new Int32Array(buf)[0], 1);
|
||||
|
||||
// Bug 882012
|
||||
assertEq(asmLink(asmCompile('stdlib', 'foreign', 'heap', USE_ASM + "var id=foreign.id;var doubles=new stdlib.Float64Array(heap);function g(){doubles[0]=+id(2.0);return +doubles[0];}return g"), this, {id: function(x){return x;}}, BUF_64KB)(), 2.0);
|
||||
|
||||
|
||||
// Some literal constant paths.
|
||||
|
||||
var buf = new ArrayBuffer(8192);
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>4294967295]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>-1]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>0x80000000]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0>>-2147483648]|0; } return f');
|
||||
|
||||
new Uint32Array(buf)[0] = 0xAA;
|
||||
new Uint32Array(buf)[0x5A>>2] = 0xA5;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&4294967295)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&-1)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&0x80000000)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x5A&-2147483648)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u32[(0x5A&i)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(4294967295&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u32[(i&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(-1&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u32[(i&0x5A)>>2]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(0x80000000&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u32[(i&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[(-2147483648&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u32[(-2147483648&0x5A)>>2]|0; } return f'), this, null, buf)(),0xAA);
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[4294967295>>2]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u32[i>>2]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[-1>>2]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u32[i>>2]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[0x80000000>>2]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u32[i>>2]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u32[-2147483648>>2]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u32[-2147483648>>2]|0; } return f'), this, null, buf)(),0);
|
||||
|
||||
var buf = new ArrayBuffer(8192);
|
||||
new Uint8Array(buf)[0] = 0xAA;
|
||||
new Uint8Array(buf)[0x5A] = 0xA5;
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&4294967295]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&-1]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&0x80000000]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x5A&-2147483648]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[0x5A&i]|0; } return f'), this, null, buf)(),0xAA);
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[4294967295&0x5A]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-1&0x5A]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xA5);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x80000000&0x5A]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-2147483648&0x5A]|0; } return f'), this, null, buf)(),0xAA);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[i&0x5A]|0; } return f'), this, null, buf)(),0xAA);
|
||||
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[4294967295]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[i]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-1]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[i]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x80000000]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[i]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-2147483648]|0; } return f');
|
||||
assertAsmTypeFail('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[i]|0; } return f');
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[4294967295>>0]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=4294967295; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-1>>0]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-1; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[0x80000000>>0]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=0x80000000; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f() { return u8[-2147483648>>0]|0; } return f'), this, null, buf)(),0);
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'const i=-2147483648; function f() { return u8[i>>0]|0; } return f'), this, null, buf)(),0);
|
||||
|
||||
|
@ -41,6 +41,10 @@ assertEq(asmLink(asmCompile(USE_ASM + 'function f(i) { i=i|0; return (i+-2147483
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'function f(i) { i=i|0; return (i+4294967295)|0 } return f'))(0), 4294967295|0);
|
||||
|
||||
assertAsmTypeFail(USE_ASM + 'var i=-2147483649; function f() { return i|0 } return f');
|
||||
assertAsmTypeFail(USE_ASM + 'const i=-2147483649; function f() { return i|0 } return f');
|
||||
assertAsmTypeFail(USE_ASM + 'var i=4294967296; function f() { return i|0 } return f');
|
||||
assertAsmTypeFail(USE_ASM + 'const i=4294967296; function f() { return i|0 } return f');
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'var i=-2147483648; function f() { return i|0 } return f'))(), -2147483648);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'const i=-2147483648; function f() { return i|0 } return f'))(), -2147483648);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'var i=4294967295; function f() { return i|0 } return f'))(), 4294967295|0);
|
||||
assertEq(asmLink(asmCompile(USE_ASM + 'const i=4294967295; function f() { return i|0 } return f'))(), 4294967295|0);
|
||||
|
@ -9,6 +9,7 @@ function testUnary(f, g) {
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:Math.sqrt}});
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:null}});
|
||||
testUnary(asmLink(asmCompile('glob', USE_ASM + 'var sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:Math.sin}}), Math.sin);
|
||||
testUnary(asmLink(asmCompile('glob', USE_ASM + 'const sq=glob.Math.sin; function f(d) { d=+d; return +sq(d) } return f'), {Math:{sin:Math.sin}}), Math.sin);
|
||||
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var co=glob.Math.cos; function f(d) { d=+d; return +co(d) } return f'), {Math:{cos:Math.sqrt}});
|
||||
assertAsmLinkFail(asmCompile('glob', USE_ASM + 'var co=glob.Math.cos; function f(d) { d=+d; return +co(d) } return f'), {Math:{cos:null}});
|
||||
|
4
js/src/jit-test/tests/baseline/bug916039.js
Normal file
4
js/src/jit-test/tests/baseline/bug916039.js
Normal file
@ -0,0 +1,4 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
assertEq(eval("this"), undefined);
|
||||
})();
|
3
js/src/jit-test/tests/proxy/bug897403.js
Normal file
3
js/src/jit-test/tests/proxy/bug897403.js
Normal file
@ -0,0 +1,3 @@
|
||||
var f = (function () {}).bind({});
|
||||
var p = new Proxy(f, {});
|
||||
Object.defineProperty(p, "caller", {get: function(){}});
|
@ -146,7 +146,7 @@ CallArgList(ParseNode *pn)
|
||||
static inline ParseNode *
|
||||
VarListHead(ParseNode *pn)
|
||||
{
|
||||
JS_ASSERT(pn->isKind(PNK_VAR));
|
||||
JS_ASSERT(pn->isKind(PNK_VAR) || pn->isKind(PNK_CONST));
|
||||
return ListHead(pn);
|
||||
}
|
||||
|
||||
@ -370,9 +370,10 @@ PeekToken(AsmJSParser &parser)
|
||||
}
|
||||
|
||||
static bool
|
||||
ParseVarStatement(AsmJSParser &parser, ParseNode **var)
|
||||
ParseVarOrConstStatement(AsmJSParser &parser, ParseNode **var)
|
||||
{
|
||||
if (PeekToken(parser) != TOK_VAR) {
|
||||
TokenKind tk = PeekToken(parser);
|
||||
if (tk != TOK_VAR && tk != TOK_CONST) {
|
||||
*var = NULL;
|
||||
return true;
|
||||
}
|
||||
@ -381,7 +382,7 @@ ParseVarStatement(AsmJSParser &parser, ParseNode **var)
|
||||
if (!*var)
|
||||
return false;
|
||||
|
||||
JS_ASSERT((*var)->isKind(PNK_VAR));
|
||||
JS_ASSERT((*var)->isKind(PNK_VAR) || (*var)->isKind(PNK_CONST));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -823,7 +824,7 @@ ExtractNumericLiteral(ParseNode *pn)
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsLiteralUint32(ParseNode *pn, uint32_t *u32)
|
||||
IsLiteralInt(ParseNode *pn, uint32_t *u32)
|
||||
{
|
||||
if (!IsNumericLiteral(pn))
|
||||
return false;
|
||||
@ -832,9 +833,9 @@ IsLiteralUint32(ParseNode *pn, uint32_t *u32)
|
||||
switch (literal.which()) {
|
||||
case NumLit::Fixnum:
|
||||
case NumLit::BigUnsigned:
|
||||
case NumLit::NegativeInt:
|
||||
*u32 = uint32_t(literal.toInt32());
|
||||
return true;
|
||||
case NumLit::NegativeInt:
|
||||
case NumLit::Double:
|
||||
case NumLit::OutOfRangeInt:
|
||||
return false;
|
||||
@ -1019,6 +1020,9 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
struct {
|
||||
uint32_t index_;
|
||||
VarType::Which type_;
|
||||
bool isConst_;
|
||||
bool isLitConst_;
|
||||
Value litConstValue_;
|
||||
} var;
|
||||
uint32_t funcIndex_;
|
||||
uint32_t funcPtrTableIndex_;
|
||||
@ -1045,6 +1049,19 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
JS_ASSERT(which_ == Variable);
|
||||
return u.var.index_;
|
||||
}
|
||||
bool varIsConstant() const {
|
||||
JS_ASSERT(which_ == Variable);
|
||||
return u.var.isConst_;
|
||||
}
|
||||
bool varIsLitConstant() const {
|
||||
JS_ASSERT(which_ == Variable);
|
||||
return u.var.isLitConst_;
|
||||
}
|
||||
const Value &litConstValue() const {
|
||||
JS_ASSERT(which_ == Variable);
|
||||
JS_ASSERT(u.var.isLitConst_);
|
||||
return u.var.litConstValue_;
|
||||
}
|
||||
uint32_t funcIndex() const {
|
||||
JS_ASSERT(which_ == Function);
|
||||
return u.funcIndex_;
|
||||
@ -1361,7 +1378,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
void initImportArgumentName(PropertyName *n) { module_->initImportArgumentName(n); }
|
||||
void initBufferArgumentName(PropertyName *n) { module_->initBufferArgumentName(n); }
|
||||
|
||||
bool addGlobalVarInitConstant(PropertyName *varName, VarType type, const Value &v) {
|
||||
bool addGlobalVarInitConstant(PropertyName *varName, VarType type, const Value &v,
|
||||
bool isConst) {
|
||||
uint32_t index;
|
||||
if (!module_->addGlobalVarInitConstant(v, &index))
|
||||
return false;
|
||||
@ -1370,9 +1388,14 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
return false;
|
||||
global->u.var.index_ = index;
|
||||
global->u.var.type_ = type.which();
|
||||
global->u.var.isConst_ = isConst;
|
||||
global->u.var.isLitConst_ = isConst;
|
||||
if (isConst)
|
||||
global->u.var.litConstValue_ = v;
|
||||
return globals_.putNew(varName, global);
|
||||
}
|
||||
bool addGlobalVarImport(PropertyName *varName, PropertyName *fieldName, AsmJSCoercion coercion) {
|
||||
bool addGlobalVarImport(PropertyName *varName, PropertyName *fieldName, AsmJSCoercion coercion,
|
||||
bool isConst) {
|
||||
uint32_t index;
|
||||
if (!module_->addGlobalVarImport(fieldName, coercion, &index))
|
||||
return false;
|
||||
@ -1381,6 +1404,8 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
return false;
|
||||
global->u.var.index_ = index;
|
||||
global->u.var.type_ = VarType(coercion).which();
|
||||
global->u.var.isConst_ = isConst;
|
||||
global->u.var.isLitConst_ = false;
|
||||
return globals_.putNew(varName, global);
|
||||
}
|
||||
bool addFunction(PropertyName *name, MoveRef<Signature> sig, Func **func) {
|
||||
@ -1990,9 +2015,16 @@ class FunctionCompiler
|
||||
{
|
||||
if (!curBlock_)
|
||||
return NULL;
|
||||
if (global.varIsLitConstant()) {
|
||||
JS_ASSERT(global.litConstValue().isNumber());
|
||||
MConstant *constant = MConstant::New(global.litConstValue());
|
||||
curBlock_->add(constant);
|
||||
return constant;
|
||||
}
|
||||
MIRType type = global.varType().toMIRType();
|
||||
unsigned globalDataOffset = module().globalVarIndexToGlobalDataOffset(global.varIndex());
|
||||
MAsmJSLoadGlobalVar *load = MAsmJSLoadGlobalVar::New(type, globalDataOffset);
|
||||
MAsmJSLoadGlobalVar *load = MAsmJSLoadGlobalVar::New(type, globalDataOffset,
|
||||
global.varIsConstant());
|
||||
curBlock_->add(load);
|
||||
return load;
|
||||
}
|
||||
@ -2692,7 +2724,8 @@ CheckPrecedingStatements(ModuleCompiler &m, ParseNode *stmtList)
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode)
|
||||
CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
|
||||
bool isConst)
|
||||
{
|
||||
NumLit literal = ExtractNumericLiteral(initNode);
|
||||
VarType type;
|
||||
@ -2708,7 +2741,7 @@ CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseN
|
||||
case NumLit::OutOfRangeInt:
|
||||
return m.fail(initNode, "global initializer is out of representable integer range");
|
||||
}
|
||||
return m.addGlobalVarInitConstant(varName, type, literal.value());
|
||||
return m.addGlobalVarInitConstant(varName, type, literal.value(), isConst);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2744,7 +2777,8 @@ CheckTypeAnnotation(ModuleCompiler &m, ParseNode *coercionNode, AsmJSCoercion *c
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode)
|
||||
CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
|
||||
bool isConst)
|
||||
{
|
||||
AsmJSCoercion coercion;
|
||||
ParseNode *coercedExpr;
|
||||
@ -2763,7 +2797,7 @@ CheckGlobalVariableInitImport(ModuleCompiler &m, PropertyName *varName, ParseNod
|
||||
if (!IsUseOfName(base, importName))
|
||||
return m.failName(coercedExpr, "base of import expression must be '%s'", importName);
|
||||
|
||||
return m.addGlobalVarImport(varName, field, coercion);
|
||||
return m.addGlobalVarImport(varName, field, coercion, isConst);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -2850,7 +2884,7 @@ CheckGlobalDotImport(ModuleCompiler &m, PropertyName *varName, ParseNode *initNo
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckModuleGlobal(ModuleCompiler &m, ParseNode *var)
|
||||
CheckModuleGlobal(ModuleCompiler &m, ParseNode *var, bool isConst)
|
||||
{
|
||||
if (!IsDefinition(var))
|
||||
return m.fail(var, "import variable names must be unique");
|
||||
@ -2863,10 +2897,10 @@ CheckModuleGlobal(ModuleCompiler &m, ParseNode *var)
|
||||
return m.fail(var, "module import needs initializer");
|
||||
|
||||
if (IsNumericLiteral(initNode))
|
||||
return CheckGlobalVariableInitConstant(m, var->name(), initNode);
|
||||
return CheckGlobalVariableInitConstant(m, var->name(), initNode, isConst);
|
||||
|
||||
if (initNode->isKind(PNK_BITOR) || initNode->isKind(PNK_POS))
|
||||
return CheckGlobalVariableInitImport(m, var->name(), initNode);
|
||||
return CheckGlobalVariableInitImport(m, var->name(), initNode, isConst);
|
||||
|
||||
if (initNode->isKind(PNK_NEW))
|
||||
return CheckNewArrayView(m, var->name(), initNode);
|
||||
@ -2882,12 +2916,12 @@ CheckModuleGlobals(ModuleCompiler &m)
|
||||
{
|
||||
while (true) {
|
||||
ParseNode *varStmt;
|
||||
if (!ParseVarStatement(m.parser(), &varStmt))
|
||||
if (!ParseVarOrConstStatement(m.parser(), &varStmt))
|
||||
return false;
|
||||
if (!varStmt)
|
||||
break;
|
||||
for (ParseNode *var = VarListHead(varStmt); var; var = NextNode(var)) {
|
||||
if (!CheckModuleGlobal(m, var))
|
||||
if (!CheckModuleGlobal(m, var, varStmt->isKind(PNK_CONST)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -3106,6 +3140,30 @@ CheckVarRef(FunctionCompiler &f, ParseNode *varRef, MDefinition **def, Type *typ
|
||||
return f.failName(varRef, "'%s' not found in local or asm.js module scope", name);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsLiteralOrConstInt(FunctionCompiler &f, ParseNode *pn, uint32_t *u32)
|
||||
{
|
||||
if (IsLiteralInt(pn, u32))
|
||||
return true;
|
||||
|
||||
if (pn->getKind() != PNK_NAME)
|
||||
return false;
|
||||
|
||||
PropertyName *name = pn->name();
|
||||
const ModuleCompiler::Global *global = f.lookupGlobal(name);
|
||||
if (!global || global->which() != ModuleCompiler::Global::Variable ||
|
||||
!global->varIsLitConstant()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Value &v = global->litConstValue();
|
||||
if (!v.isInt32())
|
||||
return false;
|
||||
|
||||
*u32 = (uint32_t) v.toInt32();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
FoldMaskedArrayIndex(FunctionCompiler &f, ParseNode **indexExpr, int32_t *mask,
|
||||
NeedsBoundsCheck *needsBoundsCheck)
|
||||
@ -3114,7 +3172,7 @@ FoldMaskedArrayIndex(FunctionCompiler &f, ParseNode **indexExpr, int32_t *mask,
|
||||
ParseNode *maskNode = BinaryRight(*indexExpr);
|
||||
|
||||
uint32_t mask2;
|
||||
if (IsLiteralUint32(maskNode, &mask2)) {
|
||||
if (IsLiteralOrConstInt(f, maskNode, &mask2)) {
|
||||
// Flag the access to skip the bounds check if the mask ensures that an 'out of
|
||||
// bounds' access can not occur based on the current heap length constraint.
|
||||
if (mask2 == 0 ||
|
||||
@ -3147,7 +3205,7 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType
|
||||
*viewType = global->viewType();
|
||||
|
||||
uint32_t pointer;
|
||||
if (IsLiteralUint32(indexExpr, &pointer)) {
|
||||
if (IsLiteralOrConstInt(f, indexExpr, &pointer)) {
|
||||
if (pointer > (uint32_t(INT32_MAX) >> TypedArrayShift(*viewType)))
|
||||
return f.fail(indexExpr, "constant index out of range");
|
||||
pointer <<= TypedArrayShift(*viewType);
|
||||
@ -3171,7 +3229,7 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType
|
||||
ParseNode *pointerNode = BinaryLeft(indexExpr);
|
||||
|
||||
uint32_t shift;
|
||||
if (!IsLiteralUint32(shiftNode, &shift))
|
||||
if (!IsLiteralInt(shiftNode, &shift))
|
||||
return f.failf(shiftNode, "shift amount must be constant");
|
||||
|
||||
unsigned requiredShift = TypedArrayShift(*viewType);
|
||||
@ -3184,7 +3242,7 @@ CheckArrayAccess(FunctionCompiler &f, ParseNode *elem, ArrayBufferView::ViewType
|
||||
// Fold a 'literal constant right shifted' now, and skip the bounds check if
|
||||
// currently possible. This handles the optimization of many of these uses without
|
||||
// the need for range analysis, and saves the generation of a MBitAnd op.
|
||||
if (IsLiteralUint32(pointerNode, &pointer) && pointer <= uint32_t(INT32_MAX)) {
|
||||
if (IsLiteralOrConstInt(f, pointerNode, &pointer) && pointer <= uint32_t(INT32_MAX)) {
|
||||
// Cases: b[c>>n], and b[(c&m)>>n]
|
||||
pointer &= mask;
|
||||
if (pointer < f.m().minHeapLength())
|
||||
@ -3297,6 +3355,8 @@ CheckAssignName(FunctionCompiler &f, ParseNode *lhs, ParseNode *rhs, MDefinition
|
||||
} else if (const ModuleCompiler::Global *global = f.lookupGlobal(name)) {
|
||||
if (global->which() != ModuleCompiler::Global::Variable)
|
||||
return f.failName(lhs, "'%s' is not a mutable variable", name);
|
||||
if (global->varIsConstant())
|
||||
return f.failName(lhs, "'%s' is a constant variable and not mutable", name);
|
||||
if (!(rhsType <= global->varType())) {
|
||||
return f.failf(lhs, "%s is not a subtype of %s",
|
||||
rhsType.toChars(), global->varType().toType().toChars());
|
||||
@ -3560,7 +3620,7 @@ CheckFuncPtrCall(FunctionCompiler &f, ParseNode *callNode, RetType retType, MDef
|
||||
ParseNode *maskNode = BinaryRight(indexExpr);
|
||||
|
||||
uint32_t mask;
|
||||
if (!IsLiteralUint32(maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
|
||||
if (!IsLiteralInt(maskNode, &mask) || mask == UINT32_MAX || !IsPowerOfTwo(mask + 1))
|
||||
return f.fail(maskNode, "function-pointer table index mask value must be a power of two");
|
||||
|
||||
MDefinition *indexDef;
|
||||
@ -5187,7 +5247,7 @@ CheckFuncPtrTables(ModuleCompiler &m)
|
||||
{
|
||||
while (true) {
|
||||
ParseNode *varStmt;
|
||||
if (!ParseVarStatement(m.parser(), &varStmt))
|
||||
if (!ParseVarOrConstStatement(m.parser(), &varStmt))
|
||||
return false;
|
||||
if (!varStmt)
|
||||
break;
|
||||
|
@ -69,6 +69,9 @@ BaselineCompiler::compile()
|
||||
IonSpew(IonSpew_BaselineScripts, "Baseline compiling script %s:%d (%p)",
|
||||
script->filename(), script->lineno, script.get());
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting baseline code for script %s:%d",
|
||||
script->filename(), script->lineno);
|
||||
|
||||
if (cx->typeInferenceEnabled() && !script->ensureHasBytecodeTypeMap(cx))
|
||||
return Method_Error;
|
||||
|
||||
@ -968,8 +971,8 @@ BaselineCompiler::emit_JSOP_THIS()
|
||||
// Keep this value in R0
|
||||
frame.pushThis();
|
||||
|
||||
// In strict mode function or self-hosted function, |this| is left alone.
|
||||
if (function() && (function()->strict() || function()->isSelfHostedBuiltin()))
|
||||
// In strict mode code or self-hosted functions, |this| is left alone.
|
||||
if (script->strict || (function() && function()->isSelfHostedBuiltin()))
|
||||
return true;
|
||||
|
||||
Label skipIC;
|
||||
|
@ -5512,6 +5512,8 @@ CodeGenerator::visitRestPar(LRestPar *lir)
|
||||
bool
|
||||
CodeGenerator::generateAsmJS()
|
||||
{
|
||||
IonSpew(IonSpew_Codegen, "# Emitting asm.js code");
|
||||
|
||||
// The caller (either another asm.js function or the external-entry
|
||||
// trampoline) has placed all arguments in registers and on the stack
|
||||
// according to the system ABI. The MAsmJSParameters which represent these
|
||||
@ -5552,6 +5554,10 @@ CodeGenerator::generateAsmJS()
|
||||
bool
|
||||
CodeGenerator::generate()
|
||||
{
|
||||
IonSpew(IonSpew_Codegen, "# Emitting code for script %s:%d",
|
||||
gen->info().script()->filename(),
|
||||
gen->info().script()->lineno);
|
||||
|
||||
if (!safepoints_.init(graph.totalSlotCount()))
|
||||
return false;
|
||||
|
||||
|
@ -227,15 +227,19 @@ IonRuntime::initialize(JSContext *cx)
|
||||
if (!functionWrappers_ || !functionWrappers_->init())
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting exception tail stub");
|
||||
exceptionTail_ = generateExceptionTailStub(cx);
|
||||
if (!exceptionTail_)
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting bailout tail stub");
|
||||
bailoutTail_ = generateBailoutTailStub(cx);
|
||||
if (!bailoutTail_)
|
||||
return false;
|
||||
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
IonSpew(IonSpew_Codegen, "# Emitting bailout tables");
|
||||
|
||||
// Initialize some Ion-only stubs that require floating-point support.
|
||||
if (!bailoutTables_.reserve(FrameSizeClass::ClassLimit().classId()))
|
||||
return false;
|
||||
@ -250,41 +254,50 @@ IonRuntime::initialize(JSContext *cx)
|
||||
return false;
|
||||
}
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting bailout handler");
|
||||
bailoutHandler_ = generateBailoutHandler(cx);
|
||||
if (!bailoutHandler_)
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting invalidator");
|
||||
invalidator_ = generateInvalidator(cx);
|
||||
if (!invalidator_)
|
||||
return false;
|
||||
}
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting sequential arguments rectifier");
|
||||
argumentsRectifier_ = generateArgumentsRectifier(cx, SequentialExecution, &argumentsRectifierReturnAddr_);
|
||||
if (!argumentsRectifier_)
|
||||
return false;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
IonSpew(IonSpew_Codegen, "# Emitting parallel arguments rectifier");
|
||||
parallelArgumentsRectifier_ = generateArgumentsRectifier(cx, ParallelExecution, NULL);
|
||||
if (!parallelArgumentsRectifier_)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting EnterJIT sequence");
|
||||
enterJIT_ = generateEnterJIT(cx, EnterJitOptimized);
|
||||
if (!enterJIT_)
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting EnterBaselineJIT sequence");
|
||||
enterBaselineJIT_ = generateEnterJIT(cx, EnterJitBaseline);
|
||||
if (!enterBaselineJIT_)
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting Pre Barrier for Value");
|
||||
valuePreBarrier_ = generatePreBarrier(cx, MIRType_Value);
|
||||
if (!valuePreBarrier_)
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting Pre Barrier for Shape");
|
||||
shapePreBarrier_ = generatePreBarrier(cx, MIRType_Shape);
|
||||
if (!shapePreBarrier_)
|
||||
return false;
|
||||
|
||||
IonSpew(IonSpew_Codegen, "# Emitting VM function wrappers");
|
||||
for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) {
|
||||
if (!generateVMWrapper(cx, *fun))
|
||||
return false;
|
||||
|
@ -3748,8 +3748,6 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
|
||||
MTypeBarrier *barrier = MTypeBarrier::New(callInfo.thisArg(), cloneTypeSet(types), Bailout_Normal);
|
||||
current->add(barrier);
|
||||
callInfo.setThis(barrier);
|
||||
// object or missing
|
||||
JS_ASSERT(barrier->type() == MIRType_Object || barrier->type() == MIRType_Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8434,23 +8434,33 @@ class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
|
||||
|
||||
class MAsmJSLoadGlobalVar : public MNullaryInstruction
|
||||
{
|
||||
MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset)
|
||||
: globalDataOffset_(globalDataOffset)
|
||||
MAsmJSLoadGlobalVar(MIRType type, unsigned globalDataOffset, bool isConstant)
|
||||
: globalDataOffset_(globalDataOffset), isConstant_(isConstant)
|
||||
{
|
||||
JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double);
|
||||
setResultType(type);
|
||||
if (isConstant)
|
||||
setMovable();
|
||||
}
|
||||
|
||||
unsigned globalDataOffset_;
|
||||
bool isConstant_;
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(AsmJSLoadGlobalVar);
|
||||
|
||||
static MAsmJSLoadGlobalVar *New(MIRType type, unsigned globalDataOffset) {
|
||||
return new MAsmJSLoadGlobalVar(type, globalDataOffset);
|
||||
static MAsmJSLoadGlobalVar *New(MIRType type, unsigned globalDataOffset, bool isConstant) {
|
||||
return new MAsmJSLoadGlobalVar(type, globalDataOffset, isConstant);
|
||||
}
|
||||
|
||||
unsigned globalDataOffset() const { return globalDataOffset_; }
|
||||
|
||||
AliasSet getAliasSet() const {
|
||||
if (isConstant_)
|
||||
return AliasSet::None();
|
||||
else
|
||||
return AliasSet::Store(AliasSet::Any);
|
||||
}
|
||||
};
|
||||
|
||||
class MAsmJSStoreGlobalVar : public MUnaryInstruction
|
||||
|
@ -307,7 +307,7 @@ js::fun_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
|
||||
|
||||
PropertyOp getter;
|
||||
StrictPropertyOp setter;
|
||||
unsigned attrs = JSPROP_PERMANENT;
|
||||
unsigned attrs = JSPROP_PERMANENT | JSPROP_SHARED;
|
||||
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
|
||||
return false;
|
||||
if (fun->isInterpreted() ? fun->strict() : fun->isBoundFunction()) {
|
||||
|
@ -569,9 +569,6 @@ class JSScript : public js::gc::Cell
|
||||
bool funHasExtensibleScope:1; /* see FunctionContextFlags */
|
||||
bool funNeedsDeclEnvObject:1; /* see FunctionContextFlags */
|
||||
bool funHasAnyAliasedFormal:1; /* true if any formalIsAliased(i) */
|
||||
bool warnedAboutTwoArgumentEval:1; /* have warned about use of
|
||||
obsolete eval(s, o) in
|
||||
this script */
|
||||
bool warnedAboutUndefinedProp:1; /* have warned about uses of
|
||||
undefined properties in this
|
||||
script */
|
||||
|
@ -262,20 +262,22 @@ var cosh_data = [
|
||||
[1875817529344, 28.953212876533797]
|
||||
];
|
||||
|
||||
var sloppy_tolerance = 1000; // FIXME
|
||||
|
||||
for (var [x, y] of cosh_data)
|
||||
assertNear(Math.acosh(x), y);
|
||||
assertNear(Math.acosh(x), y, sloppy_tolerance);
|
||||
|
||||
assertNear(Math.acosh(1e300), 691.4686750787737, sloppy_tolerance);
|
||||
assertNear(Math.acosh(1.0000000001), 0.000014142136208675862, sloppy_tolerance);
|
||||
|
||||
for (var i = 0; i <= 100; i++) {
|
||||
var x = (i - 50) / 5;
|
||||
var y = Math.cosh(x);
|
||||
var z = Math.acosh(y);
|
||||
assertNear(z, Math.abs(x));
|
||||
assertNear(z, Math.abs(x), sloppy_tolerance);
|
||||
}
|
||||
|
||||
for (var i = 1; i < 20; i++)
|
||||
assertNear(Math.acosh(Math.cosh(i)), i);
|
||||
|
||||
assertNear(Math.acosh(1e300), 691.4686750787737);
|
||||
assertNear(Math.acosh(1.0000000001), 0.000014142136208675862);
|
||||
assertNear(Math.acosh(Math.cosh(i)), i, sloppy_tolerance);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
@ -282,24 +282,24 @@ var sinh_data = [
|
||||
[1581915832320, 28.78280496108106]
|
||||
];
|
||||
|
||||
var sloppy_tolerance = 1000; // FIXME
|
||||
|
||||
for (var [x, y] of sinh_data)
|
||||
assertNear(Math.asinh(x), y);
|
||||
assertNear(Math.asinh(x), y, sloppy_tolerance);
|
||||
|
||||
assertNear(Math.asinh(1e300), 691.4686750787737, sloppy_tolerance);
|
||||
assertNear(Math.asinh(1e-300), 1e-300, sloppy_tolerance);
|
||||
assertNear(Math.asinh(1e-5), 0.000009999999999833334, sloppy_tolerance);
|
||||
assertNear(Math.asinh(0.3), 0.29567304756342244, sloppy_tolerance);
|
||||
assertNear(Math.asinh(1), 0.881373587019543, sloppy_tolerance);
|
||||
|
||||
for (var i = 0; i <= 80; i++) {
|
||||
var x = (i - 40) / 4;
|
||||
var y = Math.sinh(x);
|
||||
var z = Math.asinh(y);
|
||||
assertNear(z, x);
|
||||
assertNear(Math.asinh(Math.sinh(x)), x, sloppy_tolerance);
|
||||
}
|
||||
|
||||
for (var i = -20; i < 20; i++)
|
||||
assertNear(Math.asinh(Math.sinh(i)), i);
|
||||
|
||||
assertNear(Math.asinh(1e300), 691.4686750787737);
|
||||
assertNear(Math.asinh(1e-300), 1e-300);
|
||||
assertNear(Math.asinh(1e-5), 0.000009999999999833334);
|
||||
assertNear(Math.asinh(0.3), 0.29567304756342244);
|
||||
assertNear(Math.asinh(1), 0.881373587019543);
|
||||
assertNear(Math.asinh(Math.sinh(i)), i, sloppy_tolerance);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
||||
|
@ -1,6 +1,3 @@
|
||||
for (var i = -1; i < 1; i += 0.05)
|
||||
assertNear(Math.atanh(Math.tanh(i)), i);
|
||||
|
||||
var tanh_data = [
|
||||
[-0.9999983310699463, -6.998237084679027],
|
||||
[-0.9999978542327881, -6.87257975132917],
|
||||
@ -269,10 +266,15 @@ var tanh_data = [
|
||||
[1e-10, 1e-10],
|
||||
];
|
||||
|
||||
for (var [x, y] of tanh_data)
|
||||
assertNear(Math.atanh(x), y);
|
||||
var sloppy_tolerance = 10; // FIXME
|
||||
|
||||
assertNear(Math.atanh(+3 / 5), +Math.log(2));
|
||||
assertNear(Math.atanh(-3 / 5), -Math.log(2));
|
||||
for (var [x, y] of tanh_data)
|
||||
assertNear(Math.atanh(x), y, sloppy_tolerance);
|
||||
|
||||
assertNear(Math.atanh(+3 / 5), +Math.log(2), sloppy_tolerance);
|
||||
assertNear(Math.atanh(-3 / 5), -Math.log(2), sloppy_tolerance);
|
||||
|
||||
for (var i = -1; i < 1; i += 0.05)
|
||||
assertNear(Math.atanh(Math.tanh(i)), i, sloppy_tolerance);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
@ -1,8 +1,10 @@
|
||||
assertEq(Math.cbrt(1), 1);
|
||||
assertEq(Math.cbrt(-1), -1);
|
||||
|
||||
assertNear(Math.cbrt(1e-300), 1e-100);
|
||||
assertNear(Math.cbrt(-1e-300), -1e-100);
|
||||
var sloppy_tolerance = 200; // FIXME
|
||||
|
||||
assertNear(Math.cbrt(1e-300), 1e-100, sloppy_tolerance);
|
||||
assertNear(Math.cbrt(-1e-300), -1e-100, sloppy_tolerance);
|
||||
|
||||
var cbrt_data = [
|
||||
[ Math.E, 1.3956124250860895 ],
|
||||
@ -12,7 +14,6 @@ var cbrt_data = [
|
||||
];
|
||||
|
||||
for (var [x, y] of cbrt_data)
|
||||
assertNear(Math.cbrt(x), y);
|
||||
assertNear(Math.cbrt(x), y, sloppy_tolerance);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
for (var i = -20; i < 20; i++)
|
||||
assertNear(Math.cosh(i), (Math.exp(i) + Math.exp(-i)) / 2);
|
||||
var sloppy_tolerance = 100;
|
||||
|
||||
assertNear(Math.cosh(1e5), Infinity);
|
||||
assertNear(Math.cosh(1e-30), 1);
|
||||
assertNear(Math.cosh(1e-10), 1);
|
||||
assertEq(Math.cosh(1000), Infinity);
|
||||
assertEq(Math.cosh(Number.MAX_VALUE), Infinity);
|
||||
assertNear(Math.cosh(1e-30), 1, sloppy_tolerance);
|
||||
assertNear(Math.cosh(1e-10), 1, sloppy_tolerance);
|
||||
|
||||
var cosh_data = [
|
||||
[0.0016914556651292944, 1.0000014305114746],
|
||||
@ -270,6 +270,9 @@ var cosh_data = [
|
||||
];
|
||||
|
||||
for (var [x, y] of cosh_data)
|
||||
assertNear(Math.cosh(x), y);
|
||||
assertNear(Math.cosh(x), y, sloppy_tolerance);
|
||||
|
||||
for (var i = -20; i < 20; i++)
|
||||
assertNear(Math.cosh(i), (Math.exp(i) + Math.exp(-i)) / 2, sloppy_tolerance);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
@ -1,17 +1,16 @@
|
||||
// |reftest| skip
|
||||
// Math.hypot is disabled pending the resolution of spec issues (bug 896264).
|
||||
|
||||
for (var i = -20; i < 20; i++)
|
||||
for (var i = -20; i < 20; i++) {
|
||||
assertEq(Math.hypot(+0, i), Math.abs(i));
|
||||
|
||||
for (var i = -20; i < 20; i++)
|
||||
assertEq(Math.hypot(-0, i), Math.abs(i));
|
||||
|
||||
for (var i = 1, j = 1; i < 2; i += 0.05, j += 0.05)
|
||||
assertNear(Math.hypot(i, j), Math.sqrt(i * i + j * j));
|
||||
}
|
||||
|
||||
assertNear(Math.hypot(1e300, 1e300), 1.4142135623730952e+300);
|
||||
assertNear(Math.hypot(1e-300, 1e-300), 1.414213562373095e-300);
|
||||
assertNear(Math.hypot(1e3, 1e-3), 1000.0000000005);
|
||||
|
||||
for (var i = 1, j = 1; i < 2; i += 0.05, j += 0.05)
|
||||
assertNear(Math.hypot(i, j), Math.sqrt(i * i + j * j));
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
@ -1,9 +1,9 @@
|
||||
for (var i = -10; i < 10; i++)
|
||||
assertNear(Math.log10(Math.pow(10, i)), i);
|
||||
|
||||
assertNear(Math.log10(2), 0.3010299956639812);
|
||||
assertNear(Math.log10(7), 0.8450980400142568);
|
||||
assertNear(Math.log10(Math.E), Math.LOG10E);
|
||||
|
||||
for (var i = -10; i < 10; i++)
|
||||
assertNear(Math.log10(Math.pow(10, i)), i);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
||||
|
||||
|
@ -2,10 +2,73 @@
|
||||
const ONE_PLUS_EPSILON = 1 + Math.pow(2, -52); // 0.9999999999999999
|
||||
const ONE_MINUS_EPSILON = 1 - Math.pow(2, -53); // 1.0000000000000002
|
||||
|
||||
function assertNear(actual, expected) {
|
||||
var error = Math.abs(actual - expected);
|
||||
{
|
||||
var fail = function (msg) {
|
||||
var exc = new Error(msg);
|
||||
try {
|
||||
// Try to improve on exc.fileName and .lineNumber; leave exc.stack
|
||||
// alone. We skip two frames: fail() and its caller, an assertX()
|
||||
// function.
|
||||
var frames = exc.stack.trim().split("\n");
|
||||
if (frames.length > 2) {
|
||||
var m = /@([^@:]*):([0-9]+)$/.exec(frames[2]);
|
||||
if (m) {
|
||||
exc.fileName = m[1];
|
||||
exc.lineNumber = +m[2];
|
||||
}
|
||||
}
|
||||
} catch (ignore) { throw ignore;}
|
||||
throw exc;
|
||||
};
|
||||
|
||||
if (error > 1e-300 && error > Math.abs(actual) * 1e-12)
|
||||
throw 'Assertion failed: got "' + actual + '", expected "' + expected + '" (rel error = ' + (error / Math.abs(actual)) + ')';
|
||||
var ENDIAN; // 0 for little-endian, 1 for big-endian.
|
||||
|
||||
// Return the difference between the IEEE 754 bit-patterns for a and b.
|
||||
//
|
||||
// This is meaningful when a and b are both finite and have the same
|
||||
// sign. Then the following hold:
|
||||
//
|
||||
// * If a === b, then diff(a, b) === 0.
|
||||
//
|
||||
// * If a !== b, then diff(a, b) === 1 + the number of representable values
|
||||
// between a and b.
|
||||
//
|
||||
var f = new Float64Array([0, 0]);
|
||||
var u = new Uint32Array(f.buffer);
|
||||
var diff = function (a, b) {
|
||||
f[0] = a;
|
||||
f[1] = b;
|
||||
//print(u[1].toString(16) + u[0].toString(16) + " " + u[3].toString(16) + u[2].toString(16));
|
||||
return Math.abs((u[3-ENDIAN] - u[1-ENDIAN]) * 0x100000000 + u[2+ENDIAN] - u[0+ENDIAN]);
|
||||
};
|
||||
|
||||
// Set ENDIAN to the platform's endianness.
|
||||
ENDIAN = 0; // try little-endian first
|
||||
if (diff(2, 4) === 0x100000) // exact wrong answer we'll get on a big-endian platform
|
||||
ENDIAN = 1;
|
||||
assertEq(diff(2,4), 0x10000000000000);
|
||||
assertEq(diff(0, Number.MIN_VALUE), 1);
|
||||
assertEq(diff(1, ONE_PLUS_EPSILON), 1);
|
||||
assertEq(diff(1, ONE_MINUS_EPSILON), 1);
|
||||
|
||||
var assertNear = function assertNear(a, b, tolerance=1) {
|
||||
if (!Number.isFinite(b)) {
|
||||
fail("second argument to assertNear (expected value) must be a finite number");
|
||||
} else if (Number.isNaN(a)) {
|
||||
fail("got NaN, expected a number near " + b);
|
||||
} else if (!Number.isFinite(a)) {
|
||||
if (b * Math.sign(a) < Number.MAX_VALUE)
|
||||
fail("got " + a + ", expected a number near " + b);
|
||||
} else {
|
||||
// When the two arguments do not have the same sign bit, diff()
|
||||
// returns some huge number. So if b is positive or negative 0,
|
||||
// make target the zero that has the same sign bit as a.
|
||||
var target = b === 0 ? a * 0 : b;
|
||||
var err = diff(a, target);
|
||||
if (err > tolerance) {
|
||||
fail("got " + a + ", expected a number near " + b +
|
||||
" (relative error: " + err + ")");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
var sloppy_tolerance = 100;
|
||||
for (var i = -20; i < 20; i++)
|
||||
assertNear(Math.sinh(i), (Math.exp(i) - Math.exp(-i)) / 2);
|
||||
assertNear(Math.sinh(i), (Math.exp(i) - Math.exp(-i)) / 2, sloppy_tolerance);
|
||||
|
||||
assertNear(Math.sinh(1e5), Infinity);
|
||||
assertNear(Math.sinh(1e-30), 1e-30);
|
||||
assertNear(Math.sinh(1e-10), 1e-10);
|
||||
assertEq(Math.sinh(1000), Infinity);
|
||||
assertEq(Math.sinh(Number.MAX_VALUE), Infinity);
|
||||
assertNear(Math.sinh(1e-30), 1e-30, sloppy_tolerance);
|
||||
assertNear(Math.sinh(1e-10), 1e-10, sloppy_tolerance);
|
||||
|
||||
var sinh_data = [
|
||||
[-6.902103625349695, -497.1816406250001],
|
||||
@ -290,7 +292,7 @@ var sinh_data = [
|
||||
];
|
||||
|
||||
for (var [x, y] of sinh_data)
|
||||
assertNear(Math.sinh(x), y);
|
||||
assertNear(Math.sinh(x), y, sloppy_tolerance);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
||||
|
@ -1,5 +1,10 @@
|
||||
for (var i = -20; i < 20; i++)
|
||||
assertNear(Math.tanh(i), (Math.exp(i) - Math.exp(-i)) / (Math.exp(i) + Math.exp(-i)));
|
||||
var sloppy_tolerance = 4;
|
||||
|
||||
for (var i = -20; i < 20; i++) {
|
||||
assertNear(Math.tanh(i),
|
||||
(Math.exp(i) - Math.exp(-i)) / (Math.exp(i) + Math.exp(-i)),
|
||||
sloppy_tolerance);
|
||||
}
|
||||
|
||||
assertEq(Math.tanh(1e300), 1);
|
||||
|
||||
@ -272,6 +277,6 @@ var tanh_data = [
|
||||
];
|
||||
|
||||
for (var [x, y] of tanh_data)
|
||||
assertNear(Math.tanh(y), x);
|
||||
assertNear(Math.tanh(y), x, sloppy_tolerance);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "ImageLayers.h"
|
||||
#include "ImageContainer.h"
|
||||
#include "nsCanvasFrame.h"
|
||||
#include "StickyScrollContainer.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
|
||||
#include <stdint.h>
|
||||
@ -3133,42 +3134,29 @@ nsDisplayFixedPosition::~nsDisplayFixedPosition() {
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<Layer> layer =
|
||||
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
|
||||
void nsDisplayFixedPosition::SetFixedPositionLayerData(Layer* const aLayer,
|
||||
nsIFrame* aViewportFrame,
|
||||
nsSize aViewportSize,
|
||||
nsPresContext* aPresContext,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
// Find out the rect of the viewport frame relative to the reference frame.
|
||||
// This, in conjunction with the container scale, will correspond to the
|
||||
// coordinate-space of the built layer.
|
||||
float factor = aPresContext->AppUnitsPerDevPixel();
|
||||
nsPoint origin = aViewportFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
||||
LayerRect anchorRect(NSAppUnitsToFloatPixels(origin.x, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(origin.y, factor) *
|
||||
aContainerParameters.mYScale,
|
||||
NSAppUnitsToFloatPixels(aViewportSize.width, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(aViewportSize.height, factor) *
|
||||
aContainerParameters.mYScale);
|
||||
|
||||
// Work out the anchor point for this fixed position layer. We assume that
|
||||
// any positioning set (left/top/right/bottom) indicates that the
|
||||
// corresponding side of its container should be the anchor point,
|
||||
// defaulting to top-left.
|
||||
nsIFrame* viewportFrame = mFixedPosFrame->GetParent();
|
||||
nsPresContext *presContext = viewportFrame->PresContext();
|
||||
|
||||
// Fixed position frames are reflowed into the scroll-port size if one has
|
||||
// been set.
|
||||
nsSize containingBlockSize = viewportFrame->GetSize();
|
||||
if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
|
||||
containingBlockSize = presContext->PresShell()->
|
||||
GetScrollPositionClampingScrollPortSize();
|
||||
}
|
||||
|
||||
// Find out the rect of the viewport frame relative to the reference frame.
|
||||
// This, in conjunction with the container scale, will correspond to the
|
||||
// coordinate-space of the built layer.
|
||||
float factor = presContext->AppUnitsPerDevPixel();
|
||||
nsPoint origin = viewportFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
||||
LayerRect anchorRect(NSAppUnitsToFloatPixels(origin.x, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(origin.y, factor) *
|
||||
aContainerParameters.mYScale,
|
||||
NSAppUnitsToFloatPixels(containingBlockSize.width, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(containingBlockSize.height, factor) *
|
||||
aContainerParameters.mYScale);
|
||||
|
||||
LayerPoint anchor = anchorRect.TopLeft();
|
||||
|
||||
const nsStylePosition* position = mFixedPosFrame->StylePosition();
|
||||
@ -3177,11 +3165,11 @@ nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
if (position->mOffset.GetBottomUnit() != eStyleUnit_Auto)
|
||||
anchor.y = anchorRect.YMost();
|
||||
|
||||
layer->SetFixedPositionAnchor(anchor);
|
||||
aLayer->SetFixedPositionAnchor(anchor);
|
||||
|
||||
// Also make sure the layer is aware of any fixed position margins that have
|
||||
// been set.
|
||||
nsMargin fixedMargins = presContext->PresShell()->GetContentDocumentFixedPositionMargins();
|
||||
nsMargin fixedMargins = aPresContext->PresShell()->GetContentDocumentFixedPositionMargins();
|
||||
LayerMargin fixedLayerMargins(NSAppUnitsToFloatPixels(fixedMargins.top, factor) *
|
||||
aContainerParameters.mYScale,
|
||||
NSAppUnitsToFloatPixels(fixedMargins.right, factor) *
|
||||
@ -3203,7 +3191,29 @@ nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
fixedLayerMargins.top = -1;
|
||||
}
|
||||
|
||||
layer->SetFixedPositionMargins(fixedLayerMargins);
|
||||
aLayer->SetFixedPositionMargins(fixedLayerMargins);
|
||||
}
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayFixedPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<Layer> layer =
|
||||
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
|
||||
|
||||
nsIFrame* viewportFrame = mFixedPosFrame->GetParent();
|
||||
nsPresContext *presContext = viewportFrame->PresContext();
|
||||
|
||||
// Fixed position frames are reflowed into the scroll-port size if one has
|
||||
// been set.
|
||||
nsSize viewportSize = viewportFrame->GetSize();
|
||||
if (presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
|
||||
viewportSize = presContext->PresShell()->
|
||||
GetScrollPositionClampingScrollPortSize();
|
||||
}
|
||||
|
||||
SetFixedPositionLayerData(layer, viewportFrame, viewportSize, presContext,
|
||||
aContainerParameters);
|
||||
|
||||
return layer.forget();
|
||||
}
|
||||
@ -3221,6 +3231,76 @@ bool nsDisplayFixedPosition::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayI
|
||||
return true;
|
||||
}
|
||||
|
||||
nsDisplayStickyPosition::nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame,
|
||||
nsIFrame* aStickyPosFrame,
|
||||
nsDisplayList* aList)
|
||||
: nsDisplayFixedPosition(aBuilder, aFrame, aStickyPosFrame, aList) {
|
||||
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
|
||||
}
|
||||
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
nsDisplayStickyPosition::~nsDisplayStickyPosition() {
|
||||
MOZ_COUNT_DTOR(nsDisplayStickyPosition);
|
||||
}
|
||||
#endif
|
||||
|
||||
already_AddRefed<Layer>
|
||||
nsDisplayStickyPosition::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) {
|
||||
nsRefPtr<Layer> layer =
|
||||
nsDisplayOwnLayer::BuildLayer(aBuilder, aManager, aContainerParameters);
|
||||
|
||||
StickyScrollContainer* stickyScrollContainer = StickyScrollContainer::
|
||||
GetStickyScrollContainerForFrame(mFrame);
|
||||
if (!stickyScrollContainer) {
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
nsIFrame* scrollFrame = do_QueryFrame(stickyScrollContainer->ScrollFrame());
|
||||
nsPresContext* presContext = scrollFrame->PresContext();
|
||||
|
||||
// Sticky position frames whose scroll frame is the root scroll frame are
|
||||
// reflowed into the scroll-port size if one has been set.
|
||||
nsSize scrollFrameSize = scrollFrame->GetSize();
|
||||
if (scrollFrame == presContext->PresShell()->GetRootScrollFrame() &&
|
||||
presContext->PresShell()->IsScrollPositionClampingScrollPortSizeSet()) {
|
||||
scrollFrameSize = presContext->PresShell()->
|
||||
GetScrollPositionClampingScrollPortSize();
|
||||
}
|
||||
|
||||
SetFixedPositionLayerData(layer, scrollFrame, scrollFrameSize, presContext,
|
||||
aContainerParameters);
|
||||
|
||||
ViewID scrollId = nsLayoutUtils::FindOrCreateIDFor(
|
||||
stickyScrollContainer->ScrollFrame()->GetScrolledFrame()->GetContent());
|
||||
|
||||
float factor = presContext->AppUnitsPerDevPixel();
|
||||
nsRect outer;
|
||||
nsRect inner;
|
||||
stickyScrollContainer->GetScrollRanges(mFrame, &outer, &inner);
|
||||
LayerRect stickyOuter(NSAppUnitsToFloatPixels(outer.x, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(outer.y, factor) *
|
||||
aContainerParameters.mYScale,
|
||||
NSAppUnitsToFloatPixels(outer.width, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(outer.height, factor) *
|
||||
aContainerParameters.mYScale);
|
||||
LayerRect stickyInner(NSAppUnitsToFloatPixels(inner.x, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(inner.y, factor) *
|
||||
aContainerParameters.mYScale,
|
||||
NSAppUnitsToFloatPixels(inner.width, factor) *
|
||||
aContainerParameters.mXScale,
|
||||
NSAppUnitsToFloatPixels(inner.height, factor) *
|
||||
aContainerParameters.mYScale);
|
||||
layer->SetStickyPositionData(scrollId, stickyOuter, stickyInner);
|
||||
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
nsDisplayScrollLayer::nsDisplayScrollLayer(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aList,
|
||||
nsIFrame* aForFrame,
|
||||
|
@ -2569,9 +2569,30 @@ public:
|
||||
NS_DISPLAY_DECL_NAME("FixedPosition", TYPE_FIXED_POSITION)
|
||||
|
||||
protected:
|
||||
void SetFixedPositionLayerData(Layer* const aLayer, nsIFrame* aViewportFrame,
|
||||
nsSize aViewportSize, nsPresContext* aPresContext,
|
||||
const ContainerParameters& aContainerParameters);
|
||||
nsIFrame* mFixedPosFrame;
|
||||
};
|
||||
|
||||
/**
|
||||
* A display item used to represent sticky position elements. The contents
|
||||
* gets its own layer and creates a stacking context, and the layer will have
|
||||
* position-related metadata set on it.
|
||||
*/
|
||||
class nsDisplayStickyPosition : public nsDisplayFixedPosition {
|
||||
public:
|
||||
nsDisplayStickyPosition(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
|
||||
nsIFrame* aStickyPosFrame, nsDisplayList* aList);
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayStickyPosition();
|
||||
#endif
|
||||
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
/**
|
||||
* This potentially creates a layer for the given list of items, whose
|
||||
* visibility is determined by the displayport for the given frame instead of
|
||||
|
@ -77,6 +77,7 @@ struct nsRect;
|
||||
class nsRegion;
|
||||
class nsRefreshDriver;
|
||||
class nsARefreshObserver;
|
||||
class nsAPostRefreshObserver;
|
||||
#ifdef ACCESSIBILITY
|
||||
class nsAccessibilityService;
|
||||
namespace mozilla {
|
||||
@ -1363,13 +1364,13 @@ public:
|
||||
*/
|
||||
protected:
|
||||
virtual bool AddRefreshObserverExternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
mozFlushType aFlushType);
|
||||
bool AddRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
mozFlushType aFlushType);
|
||||
virtual bool RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
mozFlushType aFlushType);
|
||||
bool RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType);
|
||||
mozFlushType aFlushType);
|
||||
|
||||
/**
|
||||
* Do computations necessary to determine if font size inflation is enabled.
|
||||
@ -1380,7 +1381,7 @@ protected:
|
||||
|
||||
public:
|
||||
bool AddRefreshObserver(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType) {
|
||||
mozFlushType aFlushType) {
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
return AddRefreshObserverInternal(aObserver, aFlushType);
|
||||
#else
|
||||
@ -1389,7 +1390,7 @@ public:
|
||||
}
|
||||
|
||||
bool RemoveRefreshObserver(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType) {
|
||||
mozFlushType aFlushType) {
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
return RemoveRefreshObserverInternal(aObserver, aFlushType);
|
||||
#else
|
||||
@ -1397,6 +1398,9 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool AddPostRefreshObserver(nsAPostRefreshObserver* aObserver);
|
||||
virtual bool RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Initialize and shut down static variables.
|
||||
*/
|
||||
|
@ -8221,8 +8221,8 @@ nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType)
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
return presContext ? presContext->RefreshDriver()->
|
||||
AddRefreshObserver(aObserver, aFlushType) : false;
|
||||
return presContext &&
|
||||
presContext->RefreshDriver()->AddRefreshObserver(aObserver, aFlushType);
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
@ -8237,8 +8237,8 @@ nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver* aObserver,
|
||||
mozFlushType aFlushType)
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
return presContext ? presContext->RefreshDriver()->
|
||||
RemoveRefreshObserver(aObserver, aFlushType) : false;
|
||||
return presContext &&
|
||||
presContext->RefreshDriver()->RemoveRefreshObserver(aObserver, aFlushType);
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
@ -8248,6 +8248,28 @@ nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver* aObserver,
|
||||
return RemoveRefreshObserverInternal(aObserver, aFlushType);
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
nsIPresShell::AddPostRefreshObserver(nsAPostRefreshObserver* aObserver)
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (!presContext) {
|
||||
return false;
|
||||
}
|
||||
presContext->RefreshDriver()->AddPostRefreshObserver(aObserver);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
nsIPresShell::RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver)
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (!presContext) {
|
||||
return false;
|
||||
}
|
||||
presContext->RefreshDriver()->RemovePostRefreshObserver(aObserver);
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// End of protected and private methods on the PresShell
|
||||
//------------------------------------------------------
|
||||
|
@ -323,7 +323,6 @@ public:
|
||||
|
||||
virtual void AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver) MOZ_OVERRIDE;
|
||||
|
||||
|
||||
// This data is stored as a content property (nsGkAtoms::scrolling) on
|
||||
// mContentToScrollTo when we have a pending ScrollIntoView.
|
||||
struct ScrollIntoViewData {
|
||||
|
@ -753,9 +753,7 @@ nsRefreshDriver::AddRefreshObserver(nsARefreshObserver* aObserver,
|
||||
{
|
||||
ObserverArray& array = ArrayFor(aFlushType);
|
||||
bool success = array.AppendElement(aObserver) != nullptr;
|
||||
|
||||
EnsureTimerStarted(false);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@ -767,6 +765,18 @@ nsRefreshDriver::RemoveRefreshObserver(nsARefreshObserver* aObserver,
|
||||
return array.RemoveElement(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::AddPostRefreshObserver(nsAPostRefreshObserver* aObserver)
|
||||
{
|
||||
mPostRefreshObservers.AppendElement(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver)
|
||||
{
|
||||
mPostRefreshObservers.RemoveElement(aObserver);
|
||||
}
|
||||
|
||||
bool
|
||||
nsRefreshDriver::AddImageRequest(imgIRequest* aRequest)
|
||||
{
|
||||
@ -1198,6 +1208,10 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mPostRefreshObservers.Length(); ++i) {
|
||||
mPostRefreshObservers[i]->DidRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ PLDHashOperator
|
||||
|
@ -26,16 +26,17 @@ class nsPresContext;
|
||||
class nsIPresShell;
|
||||
class nsIDocument;
|
||||
class imgIRequest;
|
||||
class nsIRunnable;
|
||||
|
||||
namespace mozilla {
|
||||
class RefreshDriverTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract base class to be implemented by callers wanting to be
|
||||
* notified at refresh times. When nothing needs to be painted, callers
|
||||
* may not be notified.
|
||||
*/
|
||||
namespace mozilla {
|
||||
class RefreshDriverTimer;
|
||||
}
|
||||
|
||||
class nsARefreshObserver {
|
||||
public:
|
||||
// AddRef and Release signatures that match nsISupports. Implementors
|
||||
@ -50,6 +51,16 @@ public:
|
||||
virtual void WillRefresh(mozilla::TimeStamp aTime) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstract base class to be implemented by callers wanting to be notified
|
||||
* that a refresh has occurred. Callers must ensure an observer is removed
|
||||
* before it is destroyed.
|
||||
*/
|
||||
class nsAPostRefreshObserver {
|
||||
public:
|
||||
virtual void DidRefresh() = 0;
|
||||
};
|
||||
|
||||
class nsRefreshDriver MOZ_FINAL : public nsISupports {
|
||||
public:
|
||||
nsRefreshDriver(nsPresContext *aPresContext);
|
||||
@ -101,11 +112,21 @@ public:
|
||||
*
|
||||
* The refresh driver does NOT own a reference to these observers;
|
||||
* they must remove themselves before they are destroyed.
|
||||
*
|
||||
* The observer will be called even if there is no other activity.
|
||||
*/
|
||||
bool AddRefreshObserver(nsARefreshObserver *aObserver,
|
||||
mozFlushType aFlushType);
|
||||
mozFlushType aFlushType);
|
||||
bool RemoveRefreshObserver(nsARefreshObserver *aObserver,
|
||||
mozFlushType aFlushType);
|
||||
mozFlushType aFlushType);
|
||||
|
||||
/**
|
||||
* Add an observer that will be called after each refresh. The caller
|
||||
* must remove the observer before it is deleted. This does not trigger
|
||||
* refresh driver ticks.
|
||||
*/
|
||||
void AddPostRefreshObserver(nsAPostRefreshObserver *aObserver);
|
||||
void RemovePostRefreshObserver(nsAPostRefreshObserver *aObserver);
|
||||
|
||||
/**
|
||||
* Add/Remove imgIRequest versions of observers.
|
||||
@ -295,6 +316,7 @@ private:
|
||||
nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
|
||||
// nsTArray on purpose, because we want to be able to swap.
|
||||
nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
|
||||
nsTArray<nsAPostRefreshObserver*> mPostRefreshObservers;
|
||||
|
||||
// Helper struct for processing image requests
|
||||
struct ImageRequestParameters {
|
||||
|
@ -219,12 +219,53 @@ StickyScrollContainer::ComputePosition(nsIFrame* aFrame) const
|
||||
return position;
|
||||
}
|
||||
|
||||
void
|
||||
StickyScrollContainer::GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter,
|
||||
nsRect* aInner) const
|
||||
{
|
||||
nsRect stick;
|
||||
nsRect contain;
|
||||
ComputeStickyLimits(aFrame, &stick, &contain);
|
||||
|
||||
aOuter->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
|
||||
aInner->SetRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
|
||||
|
||||
const nsPoint normalPosition = aFrame->GetNormalPosition();
|
||||
|
||||
// Bottom and top
|
||||
if (stick.YMost() != nscoord_MAX/2) {
|
||||
aOuter->SetTopEdge(contain.y - stick.YMost());
|
||||
aInner->SetTopEdge(normalPosition.y - stick.YMost());
|
||||
}
|
||||
|
||||
if (stick.y != nscoord_MIN/2) {
|
||||
aInner->SetBottomEdge(normalPosition.y - stick.y);
|
||||
aOuter->SetBottomEdge(contain.YMost() - stick.y);
|
||||
}
|
||||
|
||||
// Right and left
|
||||
if (stick.XMost() != nscoord_MAX/2) {
|
||||
aOuter->SetLeftEdge(contain.x - stick.XMost());
|
||||
aInner->SetLeftEdge(normalPosition.x - stick.XMost());
|
||||
}
|
||||
|
||||
if (stick.x != nscoord_MIN/2) {
|
||||
aInner->SetRightEdge(normalPosition.x - stick.x);
|
||||
aOuter->SetRightEdge(contain.XMost() - stick.x);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StickyScrollContainer::UpdatePositions(nsPoint aScrollPosition,
|
||||
nsIFrame* aSubtreeRoot)
|
||||
{
|
||||
NS_ASSERTION(!aSubtreeRoot || aSubtreeRoot == do_QueryFrame(mScrollFrame),
|
||||
"If reflowing, should be reflowing the scroll frame");
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsIFrame* scrollFrameAsFrame = do_QueryFrame(mScrollFrame);
|
||||
NS_ASSERTION(!aSubtreeRoot || aSubtreeRoot == scrollFrameAsFrame,
|
||||
"If reflowing, should be reflowing the scroll frame");
|
||||
}
|
||||
#endif
|
||||
mScrollPosition = aScrollPosition;
|
||||
|
||||
OverflowChangedTracker oct;
|
||||
|
@ -44,6 +44,10 @@ public:
|
||||
mFrames.RemoveElement(aFrame);
|
||||
}
|
||||
|
||||
nsIScrollableFrame* ScrollFrame() const {
|
||||
return mScrollFrame;
|
||||
}
|
||||
|
||||
// Compute the offsets for a sticky position element
|
||||
static void ComputeStickyOffsets(nsIFrame* aFrame);
|
||||
|
||||
@ -53,6 +57,12 @@ public:
|
||||
*/
|
||||
nsPoint ComputePosition(nsIFrame* aFrame) const;
|
||||
|
||||
/**
|
||||
* Compute where a frame should not scroll with the page, represented by the
|
||||
* difference of two rectangles.
|
||||
*/
|
||||
void GetScrollRanges(nsIFrame* aFrame, nsRect* aOuter, nsRect* aInner) const;
|
||||
|
||||
/**
|
||||
* Compute and set the position of all sticky frames, given the current
|
||||
* scroll position of the scroll frame. If not in reflow, aSubtreeRoot should
|
||||
|
@ -1736,6 +1736,12 @@ WrapPreserve3DListInternal(nsIFrame* aFrame, nsDisplayListBuilder *aBuilder, nsD
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsScrollFrameActive(nsIScrollableFrame* aScrollableFrame)
|
||||
{
|
||||
return aScrollableFrame && aScrollableFrame->IsScrollingActive();
|
||||
}
|
||||
|
||||
static nsresult
|
||||
WrapPreserve3DList(nsIFrame* aFrame, nsDisplayListBuilder* aBuilder, nsDisplayList *aList)
|
||||
{
|
||||
@ -1813,10 +1819,14 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
bool useOpacity = HasOpacity() && !nsSVGUtils::CanOptimizeOpacity(this);
|
||||
bool usingSVGEffects = nsSVGIntegrationUtils::UsingEffectsForFrame(this);
|
||||
bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
|
||||
IsScrollFrameActive(nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
|
||||
nsLayoutUtils::SCROLLABLE_SAME_DOC |
|
||||
nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
|
||||
|
||||
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
|
||||
|
||||
if (isTransformed || useOpacity || usingSVGEffects) {
|
||||
if (isTransformed || useOpacity || usingSVGEffects || useStickyPosition) {
|
||||
// We don't need to pass ancestor clipping down to our children;
|
||||
// everything goes inside a display item's child list, and the display
|
||||
// item itself will be clipped.
|
||||
@ -1935,6 +1945,13 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
|
||||
}
|
||||
/* If we have sticky positioning, wrap it in a sticky position item.
|
||||
*/
|
||||
if (useStickyPosition) {
|
||||
resultList.AppendNewToTop(
|
||||
new (aBuilder) nsDisplayStickyPosition(aBuilder, this, this,
|
||||
&resultList));
|
||||
}
|
||||
|
||||
/* If we're going to apply a transformation and don't have preserve-3d set, wrap
|
||||
* everything in an nsDisplayTransform. If there's nothing in the list, don't add
|
||||
@ -1962,13 +1979,6 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
aList->AppendToTop(&resultList);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsRootScrollFrameActive(nsIPresShell* aPresShell)
|
||||
{
|
||||
nsIScrollableFrame* sf = aPresShell->GetRootScrollFrameAsScrollable();
|
||||
return sf && sf->IsScrollingActive();
|
||||
}
|
||||
|
||||
static nsDisplayItem*
|
||||
WrapInWrapList(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList)
|
||||
@ -2127,7 +2137,8 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
// active, that's pointless and the extra layer(s) created may be wasteful.
|
||||
bool buildFixedPositionItem = disp->mPosition == NS_STYLE_POSITION_FIXED &&
|
||||
!child->GetParent()->GetParent() && !aBuilder->IsInFixedPosition() &&
|
||||
IsRootScrollFrameActive(PresContext()->PresShell()) && !isSVG;
|
||||
IsScrollFrameActive(PresContext()->PresShell()->GetRootScrollFrameAsScrollable()) &&
|
||||
!isSVG;
|
||||
|
||||
nsDisplayListBuilder::AutoBuildingDisplayList
|
||||
buildingForChild(aBuilder, child, pseudoStackingContext, buildFixedPositionItem);
|
||||
|
@ -148,6 +148,28 @@ NS_DECLARE_FRAME_PROPERTY(UninflatedTextRunProperty, nullptr)
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY(FontSizeInflationProperty, nullptr)
|
||||
|
||||
class GlyphObserver : public gfxFont::GlyphChangeObserver {
|
||||
public:
|
||||
GlyphObserver(gfxFont* aFont, nsTextFrame* aFrame)
|
||||
: gfxFont::GlyphChangeObserver(aFont), mFrame(aFrame) {}
|
||||
virtual void NotifyGlyphsChanged() MOZ_OVERRIDE;
|
||||
private:
|
||||
nsTextFrame* mFrame;
|
||||
};
|
||||
|
||||
static void DestroyGlyphObserverList(void* aPropertyValue)
|
||||
{
|
||||
delete static_cast<nsTArray<nsAutoPtr<GlyphObserver> >*>(aPropertyValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* This property is set on text frames with TEXT_IN_TEXTRUN_USER_DATA set that
|
||||
* have potentially-animated glyphs.
|
||||
* The only reason this list is in a property is to automatically destroy the
|
||||
* list when the frame is deleted, unregistering the observers.
|
||||
*/
|
||||
NS_DECLARE_FRAME_PROPERTY(TextFrameGlyphObservers, DestroyGlyphObserverList);
|
||||
|
||||
// The following flags are set during reflow
|
||||
|
||||
// This bit is set on the first frame in a continuation indicating
|
||||
@ -506,6 +528,26 @@ UnhookTextRunFromFrames(gfxTextRun* aTextRun, nsTextFrame* aStartContinuation)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GlyphObserver::NotifyGlyphsChanged()
|
||||
{
|
||||
nsIPresShell* shell = mFrame->PresContext()->PresShell();
|
||||
for (nsIFrame* f = mFrame; f;
|
||||
f = nsLayoutUtils::GetNextContinuationOrSpecialSibling(f)) {
|
||||
if (f != mFrame && f->HasAnyStateBits(TEXT_IN_TEXTRUN_USER_DATA)) {
|
||||
// f will have its own GlyphObserver (if needed) so we can stop here.
|
||||
break;
|
||||
}
|
||||
f->InvalidateFrame();
|
||||
// Theoretically we could just update overflow areas, perhaps using
|
||||
// OverflowChangedTracker, but that would do a bunch of work eagerly that
|
||||
// we should probably do lazily here since there could be a lot
|
||||
// of text frames affected and we'd like to coalesce the work. So that's
|
||||
// not easy to do well.
|
||||
shell->FrameNeedsReflow(f, nsIPresShell::eResize, NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
}
|
||||
|
||||
class FrameTextRunCache;
|
||||
|
||||
static FrameTextRunCache *gTextRuns = nullptr;
|
||||
@ -772,6 +814,63 @@ IsAllNewlines(const nsTextFragment* aFrag)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
CreateObserverForAnimatedGlyphs(nsTextFrame* aFrame, const nsTArray<gfxFont*>& aFonts)
|
||||
{
|
||||
if (!(aFrame->GetStateBits() & TEXT_IN_TEXTRUN_USER_DATA)) {
|
||||
// Maybe the textrun was created for uninflated text.
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsAutoPtr<GlyphObserver> >* observers =
|
||||
new nsTArray<nsAutoPtr<GlyphObserver> >();
|
||||
for (uint32_t i = 0, count = aFonts.Length(); i < count; ++i) {
|
||||
observers->AppendElement(new GlyphObserver(aFonts[i], aFrame));
|
||||
}
|
||||
aFrame->Properties().Set(TextFrameGlyphObservers(), observers);
|
||||
// We are lazy and don't try to remove a property value that might be
|
||||
// obsolete due to style changes or font selection changes. That is
|
||||
// likely to be rarely needed, and we don't want to eat the overhead of
|
||||
// doing it for the overwhelmingly common case of no property existing.
|
||||
// (And we're out of state bits to conveniently use for a fast property
|
||||
// existence check.) The only downside is that in some rare cases we might
|
||||
// keep fonts alive for longer than necessary, or unnecessarily invalidate
|
||||
// frames.
|
||||
}
|
||||
|
||||
static void
|
||||
CreateObserversForAnimatedGlyphs(gfxTextRun* aTextRun)
|
||||
{
|
||||
if (!aTextRun->GetUserData()) {
|
||||
return;
|
||||
}
|
||||
nsTArray<gfxFont*> fontsWithAnimatedGlyphs;
|
||||
uint32_t numGlyphRuns;
|
||||
const gfxTextRun::GlyphRun* glyphRuns =
|
||||
aTextRun->GetGlyphRuns(&numGlyphRuns);
|
||||
for (uint32_t i = 0; i < numGlyphRuns; ++i) {
|
||||
gfxFont* font = glyphRuns[i].mFont;
|
||||
if (font->GlyphsMayChange() && !fontsWithAnimatedGlyphs.Contains(font)) {
|
||||
fontsWithAnimatedGlyphs.AppendElement(font);
|
||||
}
|
||||
}
|
||||
if (fontsWithAnimatedGlyphs.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aTextRun->GetFlags() & nsTextFrameUtils::TEXT_IS_SIMPLE_FLOW) {
|
||||
CreateObserverForAnimatedGlyphs(static_cast<nsTextFrame*>(
|
||||
static_cast<nsIFrame*>(aTextRun->GetUserData())), fontsWithAnimatedGlyphs);
|
||||
} else {
|
||||
TextRunUserData* userData =
|
||||
static_cast<TextRunUserData*>(aTextRun->GetUserData());
|
||||
for (uint32_t i = 0; i < userData->mMappedFlowCount; ++i) {
|
||||
CreateObserverForAnimatedGlyphs(userData->mMappedFlows[i].mStartFrame,
|
||||
fontsWithAnimatedGlyphs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class accumulates state as we scan a paragraph of text. It detects
|
||||
* textrun boundaries (changes from text to non-text, hard
|
||||
@ -927,6 +1026,10 @@ public:
|
||||
static_cast<nsTransformedTextRun*>(mTextRun);
|
||||
transformedTextRun->FinishSettingProperties(mContext);
|
||||
}
|
||||
// The way nsTransformedTextRun is implemented, its glyph runs aren't
|
||||
// available until after nsTransformedTextRun::FinishSettingProperties()
|
||||
// is called. So that's why we defer checking for animated glyphs to here.
|
||||
CreateObserversForAnimatedGlyphs(mTextRun);
|
||||
}
|
||||
|
||||
gfxTextRun* mTextRun;
|
||||
|
@ -30,14 +30,14 @@ fuzzy-if(Android,2,4) == right-3.html right-3-ref.html
|
||||
== scrollframe-reflow-1.html scrollframe-reflow-1-ref.html
|
||||
== scrollframe-reflow-2.html scrollframe-reflow-2-ref.html
|
||||
== scrollframe-auto-1.html scrollframe-auto-1-ref.html
|
||||
== stacking-context-1.html stacking-context-1-ref.html
|
||||
fuzzy-if(Android,2,3) == stacking-context-1.html stacking-context-1-ref.html
|
||||
== top-bottom-1.html top-bottom-1-ref.html
|
||||
== top-bottom-2.html top-bottom-2-ref.html
|
||||
== top-bottom-3.html top-bottom-3-ref.html
|
||||
== left-right-1.html left-right-1-ref.html
|
||||
== left-right-2.html left-right-2-ref.html
|
||||
== left-right-3.html left-right-3-ref.html
|
||||
== containing-block-1.html containing-block-1-ref.html
|
||||
fuzzy-if(Android,4,1) == containing-block-1.html containing-block-1-ref.html
|
||||
== overconstrained-1.html overconstrained-1-ref.html
|
||||
== overconstrained-2.html overconstrained-2-ref.html
|
||||
== overconstrained-3.html overconstrained-3-ref.html
|
||||
|
@ -28,6 +28,7 @@ function testDisabled() {
|
||||
is(document.body.style[p], "", p + " not settable to " + props[p]);
|
||||
document.body.style[p] = "";
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function testEnabled() {
|
||||
@ -43,6 +44,8 @@ function testEnabled() {
|
||||
);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set': [['gfx.font_rendering.opentype_svg.enabled', true]]},
|
||||
testEnabled
|
||||
|
@ -113,6 +113,43 @@
|
||||
#define ARCH_CPU_MIPSEL 1
|
||||
#define ARCH_CPU_32_BITS 1
|
||||
#define ARCH_CPU_LITTLE_ENDIAN 1
|
||||
#elif defined(__powerpc64__)
|
||||
#define ARCH_CPU_PPC_FAMILY 1
|
||||
#define ARCH_CPU_PPC64 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#define ARCH_CPU_BIG_ENDIAN 1
|
||||
#elif defined(__ppc__) || defined(__powerpc__)
|
||||
#define ARCH_CPU_PPC_FAMILY 1
|
||||
#define ARCH_CPU_PPC 1
|
||||
#define ARCH_CPU_32_BITS 1
|
||||
#define ARCH_CPU_BIG_ENDIAN 1
|
||||
#elif defined(__sparc64__)
|
||||
#define ARCH_CPU_SPARC_FAMILY 1
|
||||
#define ARCH_CPU_SPARC 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#elif defined(__sparc__)
|
||||
#define ARCH_CPU_SPARC_FAMILY 1
|
||||
#define ARCH_CPU_SPARC 1
|
||||
#define ARCH_CPU_32_BITS 1
|
||||
#elif defined(__mips__)
|
||||
#define ARCH_CPU_MIPS_FAMILY 1
|
||||
#define ARCH_CPU_MIPS 1
|
||||
#define ARCH_CPU_32_BITS 1
|
||||
#elif defined(__hppa__)
|
||||
#define ARCH_CPU_HPPA 1
|
||||
#define ARCH_CPU_32_BITS 1
|
||||
#elif defined(__ia64__)
|
||||
#define ARCH_CPU_IA64 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#elif defined(__s390x__)
|
||||
#define ARCH_CPU_S390X 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#elif defined(__s390__)
|
||||
#define ARCH_CPU_S390 1
|
||||
#define ARCH_CPU_32_BITS 1
|
||||
#elif defined(__alpha__)
|
||||
#define ARCH_CPU_ALPHA 1
|
||||
#define ARCH_CPU_64_BITS 1
|
||||
#else
|
||||
#error Please add support for your architecture in build/build_config.h
|
||||
#endif
|
||||
|
@ -67,7 +67,10 @@ public class GeckoEvent {
|
||||
REMOVE_OBSERVER(34),
|
||||
LOW_MEMORY(35),
|
||||
NETWORK_LINK_CHANGE(36),
|
||||
TELEMETRY_HISTOGRAM_ADD(37);
|
||||
TELEMETRY_HISTOGRAM_ADD(37),
|
||||
PREFERENCES_OBSERVE(39),
|
||||
PREFERENCES_GET(40),
|
||||
PREFERENCES_REMOVE_OBSERVERS(41);
|
||||
|
||||
public final int value;
|
||||
|
||||
@ -186,6 +189,8 @@ public class GeckoEvent {
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
private String[] mPrefNames;
|
||||
|
||||
private GeckoEvent(NativeGeckoEvent event) {
|
||||
mType = event.value;
|
||||
}
|
||||
@ -689,6 +694,26 @@ public class GeckoEvent {
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createPreferencesObserveEvent(int requestId, String[] prefNames) {
|
||||
GeckoEvent event = new GeckoEvent(NativeGeckoEvent.PREFERENCES_OBSERVE);
|
||||
event.mCount = requestId;
|
||||
event.mPrefNames = prefNames;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createPreferencesGetEvent(int requestId, String[] prefNames) {
|
||||
GeckoEvent event = new GeckoEvent(NativeGeckoEvent.PREFERENCES_GET);
|
||||
event.mCount = requestId;
|
||||
event.mPrefNames = prefNames;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createPreferencesRemoveObserversEvent(int requestId) {
|
||||
GeckoEvent event = new GeckoEvent(NativeGeckoEvent.PREFERENCES_REMOVE_OBSERVERS);
|
||||
event.mCount = requestId;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createLowMemoryEvent(int level) {
|
||||
GeckoEvent event = new GeckoEvent(NativeGeckoEvent.LOW_MEMORY);
|
||||
event.mMetaState = level;
|
||||
|
@ -676,9 +676,7 @@ public class GeckoPreferences
|
||||
|
||||
// Initialize preferences by requesting the preference values from Gecko
|
||||
private int getGeckoPreferences(final PreferenceGroup screen, ArrayList<String> prefs) {
|
||||
JSONArray jsonPrefs = new JSONArray(prefs);
|
||||
|
||||
return PrefsHelper.getPrefs(jsonPrefs, new PrefsHelper.PrefHandlerBase() {
|
||||
return PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
|
||||
private Preference getField(String prefName) {
|
||||
return screen.findPreference(prefName);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import org.json.JSONObject;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -27,20 +28,18 @@ public final class PrefsHelper {
|
||||
private static int sUniqueRequestId = 1;
|
||||
|
||||
public static int getPref(String prefName, PrefHandler callback) {
|
||||
JSONArray prefs = new JSONArray();
|
||||
prefs.put(prefName);
|
||||
return getPrefs(prefs, callback);
|
||||
return getPrefsInternal(new String[] { prefName }, callback);
|
||||
}
|
||||
|
||||
public static int getPrefs(String[] prefNames, PrefHandler callback) {
|
||||
JSONArray prefs = new JSONArray();
|
||||
for (String p : prefNames) {
|
||||
prefs.put(p);
|
||||
}
|
||||
return getPrefs(prefs, callback);
|
||||
return getPrefsInternal(prefNames, callback);
|
||||
}
|
||||
|
||||
public static int getPrefs(JSONArray prefNames, PrefHandler callback) {
|
||||
public static int getPrefs(ArrayList<String> prefNames, PrefHandler callback) {
|
||||
return getPrefsInternal(prefNames.toArray(new String[prefNames.size()]), callback);
|
||||
}
|
||||
|
||||
private static int getPrefsInternal(String[] prefNames, PrefHandler callback) {
|
||||
int requestId;
|
||||
synchronized (PrefsHelper.class) {
|
||||
ensureRegistered();
|
||||
@ -50,25 +49,12 @@ public final class PrefsHelper {
|
||||
}
|
||||
|
||||
GeckoEvent event;
|
||||
try {
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", Integer.toString(requestId));
|
||||
message.put("preferences", prefNames);
|
||||
event = GeckoEvent.createBroadcastEvent(callback.isObserver() ?
|
||||
"Preferences:Observe" : "Preferences:Get", message.toString());
|
||||
GeckoAppShell.sendEventToGecko(event);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Error while composing Preferences:" +
|
||||
(callback.isObserver() ? "Observe" : "Get") + " message", e);
|
||||
|
||||
// if we failed to send the message, drop our reference to the callback because
|
||||
// otherwise it will leak since we will never get the response
|
||||
synchronized (PrefsHelper.class) {
|
||||
sCallbacks.remove(requestId);
|
||||
}
|
||||
|
||||
return -1;
|
||||
if (callback.isObserver()) {
|
||||
event = GeckoEvent.createPreferencesObserveEvent(requestId, prefNames);
|
||||
} else {
|
||||
event = GeckoEvent.createPreferencesGetEvent(requestId, prefNames);
|
||||
}
|
||||
GeckoAppShell.sendEventToGecko(event);
|
||||
|
||||
return requestId;
|
||||
}
|
||||
|
@ -35,6 +35,18 @@ public class RobocopAPI {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(subject, data));
|
||||
}
|
||||
|
||||
public void preferencesGetEvent(int requestId, String[] prefNames) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesGetEvent(requestId, prefNames));
|
||||
}
|
||||
|
||||
public void preferencesObserveEvent(int requestId, String[] prefNames) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesObserveEvent(requestId, prefNames));
|
||||
}
|
||||
|
||||
public void preferencesRemoveObserversEvent(int requestId) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesRemoveObserversEvent(requestId));
|
||||
}
|
||||
|
||||
public void setDrawListener(GeckoLayerClient.DrawListener listener) {
|
||||
GeckoAppShell.getLayerView().getLayerClient().setDrawListener(listener);
|
||||
}
|
||||
|
@ -64,13 +64,12 @@ abstract class Axis {
|
||||
}
|
||||
|
||||
static void initPrefs() {
|
||||
JSONArray prefs = new JSONArray();
|
||||
prefs.put(PREF_SCROLLING_FRICTION_FAST);
|
||||
prefs.put(PREF_SCROLLING_FRICTION_SLOW);
|
||||
prefs.put(PREF_SCROLLING_MAX_EVENT_ACCELERATION);
|
||||
prefs.put(PREF_SCROLLING_OVERSCROLL_DECEL_RATE);
|
||||
prefs.put(PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT);
|
||||
prefs.put(PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE);
|
||||
final String[] prefs = { PREF_SCROLLING_FRICTION_FAST,
|
||||
PREF_SCROLLING_FRICTION_SLOW,
|
||||
PREF_SCROLLING_MAX_EVENT_ACCELERATION,
|
||||
PREF_SCROLLING_OVERSCROLL_DECEL_RATE,
|
||||
PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT,
|
||||
PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE };
|
||||
|
||||
PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
|
||||
Map<String, Integer> mPrefs = new HashMap<String, Integer>();
|
||||
|
@ -61,19 +61,18 @@ final class DisplayPortCalculator {
|
||||
}
|
||||
|
||||
static void initPrefs() {
|
||||
JSONArray prefs = new JSONArray();
|
||||
prefs.put(PREF_DISPLAYPORT_STRATEGY);
|
||||
prefs.put(PREF_DISPLAYPORT_FM_MULTIPLIER);
|
||||
prefs.put(PREF_DISPLAYPORT_FM_DANGER_X);
|
||||
prefs.put(PREF_DISPLAYPORT_FM_DANGER_Y);
|
||||
prefs.put(PREF_DISPLAYPORT_VB_MULTIPLIER);
|
||||
prefs.put(PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD);
|
||||
prefs.put(PREF_DISPLAYPORT_VB_REVERSE_BUFFER);
|
||||
prefs.put(PREF_DISPLAYPORT_VB_DANGER_X_BASE);
|
||||
prefs.put(PREF_DISPLAYPORT_VB_DANGER_Y_BASE);
|
||||
prefs.put(PREF_DISPLAYPORT_VB_DANGER_X_INCR);
|
||||
prefs.put(PREF_DISPLAYPORT_VB_DANGER_Y_INCR);
|
||||
prefs.put(PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD);
|
||||
final String[] prefs = { PREF_DISPLAYPORT_STRATEGY,
|
||||
PREF_DISPLAYPORT_FM_MULTIPLIER,
|
||||
PREF_DISPLAYPORT_FM_DANGER_X,
|
||||
PREF_DISPLAYPORT_FM_DANGER_Y,
|
||||
PREF_DISPLAYPORT_VB_MULTIPLIER,
|
||||
PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD,
|
||||
PREF_DISPLAYPORT_VB_REVERSE_BUFFER,
|
||||
PREF_DISPLAYPORT_VB_DANGER_X_BASE,
|
||||
PREF_DISPLAYPORT_VB_DANGER_Y_BASE,
|
||||
PREF_DISPLAYPORT_VB_DANGER_X_INCR,
|
||||
PREF_DISPLAYPORT_VB_DANGER_Y_INCR,
|
||||
PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD };
|
||||
|
||||
PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
|
||||
private Map<String, Integer> mValues = new HashMap<String, Integer>();
|
||||
|
@ -59,21 +59,18 @@ public class testAddonManager extends PixelTest {
|
||||
mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
|
||||
|
||||
// Wait for confirmation of the pref change before proceeding with the test.
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put("extensions.getAddons.browseAddons");
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", "testAddonManager");
|
||||
message.put("preferences", getPrefData);
|
||||
final String[] prefNames = { "extensions.getAddons.browseAddons" };
|
||||
final int ourRequestId = 0x7357;
|
||||
Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Get", message.toString());
|
||||
mActions.sendPreferencesGetEvent(ourRequestId, prefNames);
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
// Wait until we get the correct "Preferences:Data" event
|
||||
while (!requestId.equals("testAddonManager")) {
|
||||
while (requestId != ourRequestId) {
|
||||
data = new JSONObject(eventExpecter.blockForEventData());
|
||||
requestId = data.getString("requestId");
|
||||
requestId = data.getInt("requestId");
|
||||
}
|
||||
eventExpecter.unregisterListener();
|
||||
|
||||
|
@ -29,7 +29,7 @@ import org.json.JSONObject;
|
||||
*/
|
||||
public class testDistribution extends ContentProviderTest {
|
||||
private static final String MOCK_PACKAGE = "mock-package.zip";
|
||||
private static final String PREF_REQUEST_ID = "testDistribution";
|
||||
private static final int PREF_REQUEST_ID = 0x7357;
|
||||
|
||||
private Activity mActivity;
|
||||
|
||||
@ -86,28 +86,23 @@ public class testDistribution extends ContentProviderTest {
|
||||
String prefTestInt = "distribution.test.int";
|
||||
|
||||
try {
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put(prefID);
|
||||
getPrefData.put(prefAbout);
|
||||
getPrefData.put(prefVersion);
|
||||
getPrefData.put(prefTestBoolean);
|
||||
getPrefData.put(prefTestString);
|
||||
getPrefData.put(prefTestInt);
|
||||
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", PREF_REQUEST_ID);
|
||||
message.put("preferences", getPrefData);
|
||||
final String[] prefNames = { prefID,
|
||||
prefAbout,
|
||||
prefVersion,
|
||||
prefTestBoolean,
|
||||
prefTestString,
|
||||
prefTestInt };
|
||||
|
||||
Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Get", message.toString());
|
||||
mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames);
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
// Wait until we get the correct "Preferences:Data" event
|
||||
while (!requestId.equals(PREF_REQUEST_ID)) {
|
||||
while (requestId != PREF_REQUEST_ID) {
|
||||
data = new JSONObject(eventExpecter.blockForEventData());
|
||||
requestId = data.getString("requestId");
|
||||
requestId = data.getInt("requestId");
|
||||
}
|
||||
eventExpecter.unregisterListener();
|
||||
|
||||
@ -172,23 +167,18 @@ public class testDistribution extends ContentProviderTest {
|
||||
mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
|
||||
|
||||
// Wait for confirmation of the pref change.
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put(prefUseragentLocale);
|
||||
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", PREF_REQUEST_ID);
|
||||
message.put("preferences", getPrefData);
|
||||
final String[] prefNames = { prefUseragentLocale };
|
||||
|
||||
Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Get", message.toString());
|
||||
mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames);
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
// Wait until we get the correct "Preferences:Data" event
|
||||
while (!requestId.equals(PREF_REQUEST_ID)) {
|
||||
while (requestId != PREF_REQUEST_ID) {
|
||||
data = new JSONObject(eventExpecter.blockForEventData());
|
||||
requestId = data.getString("requestId");
|
||||
requestId = data.getInt("requestId");
|
||||
}
|
||||
eventExpecter.unregisterListener();
|
||||
|
||||
@ -204,25 +194,18 @@ public class testDistribution extends ContentProviderTest {
|
||||
String prefLocalizeableOverride = "distribution.test.localizeable-override";
|
||||
|
||||
try {
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put(prefAbout);
|
||||
getPrefData.put(prefLocalizeable);
|
||||
getPrefData.put(prefLocalizeableOverride);
|
||||
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", PREF_REQUEST_ID);
|
||||
message.put("preferences", getPrefData);
|
||||
final String[] prefNames = { prefAbout, prefLocalizeable, prefLocalizeableOverride };
|
||||
|
||||
Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Get", message.toString());
|
||||
mActions.sendPreferencesGetEvent(PREF_REQUEST_ID, prefNames);
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
// Wait until we get the correct "Preferences:Data" event
|
||||
while (!requestId.equals(PREF_REQUEST_ID)) {
|
||||
while (requestId != PREF_REQUEST_ID) {
|
||||
data = new JSONObject(eventExpecter.blockForEventData());
|
||||
requestId = data.getString("requestId");
|
||||
requestId = data.getInt("requestId");
|
||||
}
|
||||
eventExpecter.unregisterListener();
|
||||
|
||||
|
@ -81,22 +81,19 @@ public class testDoorHanger extends BaseTest {
|
||||
boolean offlineAllowedByDefault = true;
|
||||
try {
|
||||
// Save offline-allow-by-default preferences first
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put("offline-apps.allow_by_default");
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", "testDoorHanger");
|
||||
message.put("preferences", getPrefData);
|
||||
final String[] prefNames = { "offline-apps.allow_by_default" };
|
||||
final int ourRequestId = 0x7357;
|
||||
|
||||
Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Get", message.toString());
|
||||
mActions.sendPreferencesGetEvent(ourRequestId, prefNames);
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
// Wait until we get the correct "Preferences:Data" event
|
||||
while (!requestId.equals("testDoorHanger")) {
|
||||
while (requestId != ourRequestId) {
|
||||
data = new JSONObject(eventExpecter.blockForEventData());
|
||||
requestId = data.getString("requestId");
|
||||
requestId = data.getInt("requestId");
|
||||
}
|
||||
eventExpecter.unregisterListener();
|
||||
|
||||
|
@ -126,21 +126,18 @@ public class testPasswordEncrypt extends BaseTest {
|
||||
mActions.sendGeckoEvent("Preferences:Set", jsonPref.toString());
|
||||
|
||||
// Wait for confirmation of the pref change before proceeding with the test.
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put("privacy.masterpassword.enabled");
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", "testPasswordEncrypt");
|
||||
message.put("preferences", getPrefData);
|
||||
final String[] prefNames = { "privacy.masterpassword.enabled" };
|
||||
final int ourRequestId = 0x73577;
|
||||
Actions.RepeatedEventExpecter eventExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Get", message.toString());
|
||||
mActions.sendPreferencesGetEvent(ourRequestId, prefNames);
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
// Wait until we get the correct "Preferences:Data" event
|
||||
while (!requestId.equals("testPasswordEncrypt")) {
|
||||
while (requestId != ourRequestId) {
|
||||
data = new JSONObject(eventExpecter.blockForEventData());
|
||||
requestId = data.getString("requestId");
|
||||
requestId = data.getInt("requestId");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
mAsserter.ok(false, "exception in toggleMasterPassword", ex.toString());
|
||||
|
@ -16,7 +16,7 @@ import org.json.JSONObject;
|
||||
*/
|
||||
public class testPrefsObserver extends BaseTest {
|
||||
private static final String PREF_TEST_PREF = "robocop.tests.dummy";
|
||||
private static final String PREF_REQUEST_ID = "testPrefsObserver";
|
||||
private static final int PREF_OBSERVE_REQUEST_ID = 0x7357;
|
||||
private static final long PREF_TIMEOUT = 10000;
|
||||
|
||||
private Actions.RepeatedEventExpecter mExpecter;
|
||||
@ -40,15 +40,15 @@ public class testPrefsObserver extends BaseTest {
|
||||
mAsserter.dumpLog("Waiting to check pref");
|
||||
|
||||
JSONObject data = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
while (!requestId.equals(PREF_REQUEST_ID)) {
|
||||
while (requestId != PREF_OBSERVE_REQUEST_ID) {
|
||||
data = new JSONObject(mExpecter.blockForEventData());
|
||||
if (!mExpecter.eventReceived()) {
|
||||
mAsserter.ok(false, "Checking pref is correct value", "Didn't receive pref");
|
||||
return;
|
||||
}
|
||||
requestId = data.getString("requestId");
|
||||
requestId = data.getInt("requestId");
|
||||
}
|
||||
|
||||
JSONObject pref = data.getJSONArray("preferences").getJSONObject(0);
|
||||
@ -61,16 +61,16 @@ public class testPrefsObserver extends BaseTest {
|
||||
mAsserter.dumpLog("Checking pref observer is removed");
|
||||
|
||||
JSONObject pref = null;
|
||||
String requestId = "";
|
||||
int requestId = -1;
|
||||
|
||||
while (!requestId.equals(PREF_REQUEST_ID)) {
|
||||
while (requestId != PREF_OBSERVE_REQUEST_ID) {
|
||||
String data = mExpecter.blockForEventDataWithTimeout(PREF_TIMEOUT);
|
||||
if (data == null) {
|
||||
mAsserter.ok(true, "Verifying pref is unobserved", "Didn't get unobserved pref");
|
||||
return;
|
||||
}
|
||||
pref = new JSONObject(data);
|
||||
requestId = pref.getString("requestId");
|
||||
requestId = pref.getInt("requestId");
|
||||
}
|
||||
|
||||
mAsserter.ok(false, "Received unobserved pref change", "");
|
||||
@ -80,19 +80,14 @@ public class testPrefsObserver extends BaseTest {
|
||||
mAsserter.dumpLog("Setting up pref observer");
|
||||
|
||||
// Setup the pref observer
|
||||
JSONArray getPrefData = new JSONArray();
|
||||
getPrefData.put(PREF_TEST_PREF);
|
||||
JSONObject message = new JSONObject();
|
||||
message.put("requestId", PREF_REQUEST_ID);
|
||||
message.put("preferences", getPrefData);
|
||||
mExpecter = mActions.expectGeckoEvent("Preferences:Data");
|
||||
mActions.sendGeckoEvent("Preferences:Observe", message.toString());
|
||||
mActions.sendPreferencesObserveEvent(PREF_OBSERVE_REQUEST_ID, new String[] { PREF_TEST_PREF });
|
||||
}
|
||||
|
||||
public void removePrefObserver() {
|
||||
mAsserter.dumpLog("Removing pref observer");
|
||||
|
||||
mActions.sendGeckoEvent("Preferences:RemoveObservers", PREF_REQUEST_ID);
|
||||
mActions.sendPreferencesRemoveObserversEvent(PREF_OBSERVE_REQUEST_ID);
|
||||
}
|
||||
|
||||
public void testPrefsObserver() {
|
||||
|
@ -279,10 +279,7 @@ var BrowserApp = {
|
||||
Services.obs.addObserver(this, "Session:Stop", false);
|
||||
Services.obs.addObserver(this, "SaveAs:PDF", false);
|
||||
Services.obs.addObserver(this, "Browser:Quit", false);
|
||||
Services.obs.addObserver(this, "Preferences:Get", false);
|
||||
Services.obs.addObserver(this, "Preferences:Set", false);
|
||||
Services.obs.addObserver(this, "Preferences:Observe", false);
|
||||
Services.obs.addObserver(this, "Preferences:RemoveObservers", false);
|
||||
Services.obs.addObserver(this, "ScrollTo:FocusedInput", false);
|
||||
Services.obs.addObserver(this, "Sanitize:ClearData", false);
|
||||
Services.obs.addObserver(this, "FullScreen:Exit", false);
|
||||
@ -993,16 +990,17 @@ var BrowserApp = {
|
||||
|
||||
notifyPrefObservers: function(aPref) {
|
||||
this._prefObservers[aPref].forEach(function(aRequestId) {
|
||||
let request = { requestId : aRequestId,
|
||||
preferences : [aPref] };
|
||||
this.getPreferences(request);
|
||||
this.getPreferences(aRequestId, [aPref], 1);
|
||||
}, this);
|
||||
},
|
||||
|
||||
getPreferences: function getPreferences(aPrefsRequest, aListen) {
|
||||
handlePreferencesRequest: function handlePreferencesRequest(aRequestId,
|
||||
aPrefNames,
|
||||
aListen) {
|
||||
|
||||
let prefs = [];
|
||||
|
||||
for (let prefName of aPrefsRequest.preferences) {
|
||||
for (let prefName of aPrefNames) {
|
||||
let pref = {
|
||||
name: prefName,
|
||||
type: "",
|
||||
@ -1011,9 +1009,9 @@ var BrowserApp = {
|
||||
|
||||
if (aListen) {
|
||||
if (this._prefObservers[prefName])
|
||||
this._prefObservers[prefName].push(aPrefsRequest.requestId);
|
||||
this._prefObservers[prefName].push(aRequestId);
|
||||
else
|
||||
this._prefObservers[prefName] = [ aPrefsRequest.requestId ];
|
||||
this._prefObservers[prefName] = [ aRequestId ];
|
||||
Services.prefs.addObserver(prefName, this, false);
|
||||
}
|
||||
|
||||
@ -1120,31 +1118,11 @@ var BrowserApp = {
|
||||
|
||||
sendMessageToJava({
|
||||
type: "Preferences:Data",
|
||||
requestId: aPrefsRequest.requestId, // opaque request identifier, can be any string/int/whatever
|
||||
requestId: aRequestId, // opaque request identifier, can be any string/int/whatever
|
||||
preferences: prefs
|
||||
});
|
||||
},
|
||||
|
||||
removePreferenceObservers: function removePreferenceObservers(aRequestId) {
|
||||
let newPrefObservers = [];
|
||||
for (let prefName in this._prefObservers) {
|
||||
let requestIds = this._prefObservers[prefName];
|
||||
// Remove the requestID from the preference handlers
|
||||
let i = requestIds.indexOf(aRequestId);
|
||||
if (i >= 0) {
|
||||
requestIds.splice(i, 1);
|
||||
}
|
||||
|
||||
// If there are no more request IDs, remove the observer
|
||||
if (requestIds.length == 0) {
|
||||
Services.prefs.removeObserver(prefName, this);
|
||||
} else {
|
||||
newPrefObservers[prefName] = requestIds;
|
||||
}
|
||||
}
|
||||
this._prefObservers = newPrefObservers;
|
||||
},
|
||||
|
||||
setPreferences: function setPreferences(aPref) {
|
||||
let json = JSON.parse(aPref);
|
||||
|
||||
@ -1443,22 +1421,10 @@ var BrowserApp = {
|
||||
this.saveAsPDF(browser);
|
||||
break;
|
||||
|
||||
case "Preferences:Get":
|
||||
this.getPreferences(JSON.parse(aData));
|
||||
break;
|
||||
|
||||
case "Preferences:Set":
|
||||
this.setPreferences(aData);
|
||||
break;
|
||||
|
||||
case "Preferences:Observe":
|
||||
this.getPreferences(JSON.parse(aData), true);
|
||||
break;
|
||||
|
||||
case "Preferences:RemoveObservers":
|
||||
this.removePreferenceObservers(aData);
|
||||
break;
|
||||
|
||||
case "ScrollTo:FocusedInput":
|
||||
// these messages come from a change in the viewable area and not user interaction
|
||||
// we allow scrolling to the selected input, but not zooming the page
|
||||
@ -1532,6 +1498,34 @@ var BrowserApp = {
|
||||
return this.getTabForId(tabId);
|
||||
},
|
||||
|
||||
getPreferences: function getPreferences(requestId, prefNames, count) {
|
||||
this.handlePreferencesRequest(requestId, prefNames, false);
|
||||
},
|
||||
|
||||
observePreferences: function observePreferences(requestId, prefNames, count) {
|
||||
this.handlePreferencesRequest(requestId, prefNames, true);
|
||||
},
|
||||
|
||||
removePreferenceObservers: function removePreferenceObservers(aRequestId) {
|
||||
let newPrefObservers = [];
|
||||
for (let prefName in this._prefObservers) {
|
||||
let requestIds = this._prefObservers[prefName];
|
||||
// Remove the requestID from the preference handlers
|
||||
let i = requestIds.indexOf(aRequestId);
|
||||
if (i >= 0) {
|
||||
requestIds.splice(i, 1);
|
||||
}
|
||||
|
||||
// If there are no more request IDs, remove the observer
|
||||
if (requestIds.length == 0) {
|
||||
Services.prefs.removeObserver(prefName, this);
|
||||
} else {
|
||||
newPrefObservers[prefName] = requestIds;
|
||||
}
|
||||
}
|
||||
this._prefObservers = newPrefObservers;
|
||||
},
|
||||
|
||||
// This method will print a list from fromIndex to toIndex, optionally
|
||||
// selecting selIndex(if fromIndex<=selIndex<=toIndex)
|
||||
showHistory: function(fromIndex, toIndex, selIndex) {
|
||||
|
@ -168,29 +168,19 @@ class TreeMetadataEmitter(LoggingMixin):
|
||||
if program:
|
||||
yield Program(sandbox, program, sandbox['CONFIG']['BIN_SUFFIX'])
|
||||
|
||||
for manifest in sandbox.get('XPCSHELL_TESTS_MANIFESTS', []):
|
||||
yield XpcshellManifests(sandbox, manifest)
|
||||
|
||||
for ipdl in sandbox.get('IPDL_SOURCES', []):
|
||||
yield IPDLFile(sandbox, ipdl)
|
||||
|
||||
for local_include in sandbox.get('LOCAL_INCLUDES', []):
|
||||
yield LocalInclude(sandbox, local_include)
|
||||
|
||||
for webidl in sandbox.get('WEBIDL_FILES', []):
|
||||
yield WebIDLFile(sandbox, webidl)
|
||||
|
||||
for webidl in sandbox.get('GENERATED_EVENTS_WEBIDL_FILES', []):
|
||||
yield GeneratedEventWebIDLFile(sandbox, webidl)
|
||||
|
||||
for webidl in sandbox.get('TEST_WEBIDL_FILES', []):
|
||||
yield TestWebIDLFile(sandbox, webidl)
|
||||
|
||||
for webidl in sandbox.get('PREPROCESSED_WEBIDL_FILES', []):
|
||||
yield PreprocessedWebIDLFile(sandbox, webidl)
|
||||
|
||||
for webidl in sandbox.get('GENERATED_WEBIDL_FILES', []):
|
||||
yield GeneratedWebIDLFile(sandbox, webidl)
|
||||
simple_lists = [
|
||||
('GENERATED_EVENTS_WEBIDL_FILES', GeneratedEventWebIDLFile),
|
||||
('GENERATED_WEBIDL_FILES', GeneratedWebIDLFile),
|
||||
('IPDL_SOURCES', IPDLFile),
|
||||
('LOCAL_INCLUDES', LocalInclude),
|
||||
('PREPROCESSED_WEBIDL_FILES', PreprocessedWebIDLFile),
|
||||
('TEST_WEBIDL_FILES', TestWebIDLFile),
|
||||
('WEBIDL_FILES', WebIDLFile),
|
||||
('XPCSHELL_TESTS_MANIFESTS', XpcshellManifests),
|
||||
]
|
||||
for sandbox_var, klass in simple_lists:
|
||||
for name in sandbox.get(sandbox_var, []):
|
||||
yield klass(sandbox, name)
|
||||
|
||||
def _emit_directory_traversal_from_sandbox(self, sandbox):
|
||||
o = DirectoryTraversal(sandbox)
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsICertOverrideService.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#ifndef MOZ_DISABLE_CRYPTOLEGACY
|
||||
#include "nsIDOMNode.h"
|
||||
@ -871,9 +871,9 @@ static CipherPref CipherPrefs[] = {
|
||||
};
|
||||
|
||||
static void
|
||||
setNonPkixOcspEnabled(int32_t ocspEnabled, nsIPrefBranch * pref)
|
||||
setNonPkixOcspEnabled(int32_t ocspEnabled)
|
||||
{
|
||||
// Note: this preference is numeric vs bolean because previously we
|
||||
// Note: this preference is numeric vs boolean because previously we
|
||||
// supported more than two options.
|
||||
if (!ocspEnabled) {
|
||||
CERT_DisableOCSPChecking(CERT_GetDefaultCertDB());
|
||||
@ -886,7 +886,7 @@ setNonPkixOcspEnabled(int32_t ocspEnabled, nsIPrefBranch * pref)
|
||||
|
||||
#define CRL_DOWNLOAD_DEFAULT false
|
||||
#define OCSP_ENABLED_DEFAULT 1
|
||||
#define OCSP_REQUIRED_DEFAULT 0
|
||||
#define OCSP_REQUIRED_DEFAULT false
|
||||
#define FRESH_REVOCATION_REQUIRED_DEFAULT false
|
||||
#define MISSING_CERT_DOWNLOAD_DEFAULT false
|
||||
#define FIRST_REVO_METHOD_DEFAULT "ocsp"
|
||||
@ -894,56 +894,39 @@ setNonPkixOcspEnabled(int32_t ocspEnabled, nsIPrefBranch * pref)
|
||||
#define OCSP_STAPLING_ENABLED_DEFAULT true
|
||||
|
||||
// Caller must hold a lock on nsNSSComponent::mutex when calling this function
|
||||
void nsNSSComponent::setValidationOptions(nsIPrefBranch * pref)
|
||||
void nsNSSComponent::setValidationOptions()
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
nsresult rv;
|
||||
|
||||
bool crlDownloading;
|
||||
rv = pref->GetBoolPref("security.CRL_download.enabled", &crlDownloading);
|
||||
if (NS_FAILED(rv))
|
||||
crlDownloading = CRL_DOWNLOAD_DEFAULT;
|
||||
|
||||
int32_t ocspEnabled;
|
||||
rv = pref->GetIntPref("security.OCSP.enabled", &ocspEnabled);
|
||||
// 0 = disabled, 1 = enabled,
|
||||
// 2 = enabled with given default responder
|
||||
if (NS_FAILED(rv))
|
||||
ocspEnabled = OCSP_ENABLED_DEFAULT;
|
||||
bool crlDownloading = Preferences::GetBool("security.CRL_download.enabled",
|
||||
CRL_DOWNLOAD_DEFAULT);
|
||||
// 0 = disabled, 1 = enabled
|
||||
int32_t ocspEnabled = Preferences::GetInt("security.OCSP.enabled",
|
||||
OCSP_ENABLED_DEFAULT);
|
||||
|
||||
bool ocspRequired;
|
||||
rv = pref->GetBoolPref("security.OCSP.require", &ocspRequired);
|
||||
if (NS_FAILED(rv))
|
||||
ocspRequired = OCSP_REQUIRED_DEFAULT;
|
||||
bool ocspRequired = Preferences::GetBool("security.OCSP.require",
|
||||
OCSP_REQUIRED_DEFAULT);
|
||||
bool anyFreshRequired = Preferences::GetBool("security.fresh_revocation_info.require",
|
||||
FRESH_REVOCATION_REQUIRED_DEFAULT);
|
||||
bool aiaDownloadEnabled = Preferences::GetBool("security.missing_cert_download.enabled",
|
||||
MISSING_CERT_DOWNLOAD_DEFAULT);
|
||||
|
||||
bool anyFreshRequired;
|
||||
rv = pref->GetBoolPref("security.fresh_revocation_info.require", &anyFreshRequired);
|
||||
if (NS_FAILED(rv))
|
||||
anyFreshRequired = FRESH_REVOCATION_REQUIRED_DEFAULT;
|
||||
|
||||
bool aiaDownloadEnabled;
|
||||
rv = pref->GetBoolPref("security.missing_cert_download.enabled", &aiaDownloadEnabled);
|
||||
if (NS_FAILED(rv))
|
||||
aiaDownloadEnabled = MISSING_CERT_DOWNLOAD_DEFAULT;
|
||||
|
||||
nsCString firstNetworkRevo;
|
||||
rv = pref->GetCharPref("security.first_network_revocation_method", getter_Copies(firstNetworkRevo));
|
||||
if (NS_FAILED(rv))
|
||||
nsCString firstNetworkRevo =
|
||||
Preferences::GetCString("security.first_network_revocation_method");
|
||||
if (firstNetworkRevo.IsEmpty()) {
|
||||
firstNetworkRevo = FIRST_REVO_METHOD_DEFAULT;
|
||||
|
||||
bool ocspStaplingEnabled;
|
||||
rv = pref->GetBoolPref("security.ssl.enable_ocsp_stapling", &ocspStaplingEnabled);
|
||||
if (NS_FAILED(rv)) {
|
||||
ocspStaplingEnabled = OCSP_STAPLING_ENABLED_DEFAULT;
|
||||
}
|
||||
|
||||
bool ocspStaplingEnabled = Preferences::GetBool("security.ssl.enable_ocsp_stapling",
|
||||
OCSP_STAPLING_ENABLED_DEFAULT);
|
||||
if (!ocspEnabled) {
|
||||
ocspStaplingEnabled = false;
|
||||
}
|
||||
PublicSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
|
||||
PrivateSSLState()->SetOCSPStaplingEnabled(ocspStaplingEnabled);
|
||||
|
||||
setNonPkixOcspEnabled(ocspEnabled, pref);
|
||||
|
||||
|
||||
setNonPkixOcspEnabled(ocspEnabled);
|
||||
|
||||
CERT_SetOCSPFailureMode( ocspRequired ?
|
||||
ocspMode_FailureIsVerificationFailure
|
||||
: ocspMode_FailureIsNotAVerificationFailure);
|
||||
@ -971,16 +954,16 @@ void nsNSSComponent::setValidationOptions(nsIPrefBranch * pref)
|
||||
// Enable the TLS versions given in the prefs, defaulting to SSL 3.0 and
|
||||
// TLS 1.0 when the prefs aren't set or when they are set to invalid values.
|
||||
nsresult
|
||||
nsNSSComponent::setEnabledTLSVersions(nsIPrefBranch * prefBranch)
|
||||
nsNSSComponent::setEnabledTLSVersions()
|
||||
{
|
||||
// keep these values in sync with security-prefs.js and firefox.js
|
||||
static const int32_t PSM_DEFAULT_MIN_TLS_VERSION = 0;
|
||||
static const int32_t PSM_DEFAULT_MAX_TLS_VERSION = 1;
|
||||
|
||||
int32_t minVersion = PSM_DEFAULT_MIN_TLS_VERSION;
|
||||
int32_t maxVersion = PSM_DEFAULT_MAX_TLS_VERSION;
|
||||
mPrefBranch->GetIntPref("security.tls.version.min", &minVersion);
|
||||
mPrefBranch->GetIntPref("security.tls.version.max", &maxVersion);
|
||||
int32_t minVersion = Preferences::GetInt("security.tls.version.min",
|
||||
PSM_DEFAULT_MIN_TLS_VERSION);
|
||||
int32_t maxVersion = Preferences::GetInt("security.tls.version.max",
|
||||
PSM_DEFAULT_MAX_TLS_VERSION);
|
||||
|
||||
// 0 means SSL 3.0, 1 means TLS 1.0, 2 means TLS 1.1, etc.
|
||||
minVersion += SSL_LIBRARY_VERSION_3_0;
|
||||
@ -1016,13 +999,11 @@ NS_IMETHODIMP
|
||||
nsNSSComponent::SkipOcspOff()
|
||||
{
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
int32_t ocspEnabled;
|
||||
if (NS_FAILED(mPrefBranch->GetIntPref("security.OCSP.enabled", &ocspEnabled)))
|
||||
ocspEnabled = OCSP_ENABLED_DEFAULT;
|
||||
// 0 = disabled, 1 = enabled,
|
||||
// 2 = enabled with given default responder
|
||||
|
||||
setNonPkixOcspEnabled(ocspEnabled, mPrefBranch);
|
||||
// 0 = disabled, 1 = enabled
|
||||
int32_t ocspEnabled = Preferences::GetInt("security.OCSP.enabled",
|
||||
OCSP_ENABLED_DEFAULT);
|
||||
|
||||
setNonPkixOcspEnabled(ocspEnabled);
|
||||
|
||||
if (ocspEnabled)
|
||||
SSL_ClearSessionCache();
|
||||
@ -1050,6 +1031,14 @@ static void configureMD5(bool enabled)
|
||||
}
|
||||
}
|
||||
|
||||
static const bool SUPPRESS_WARNING_PREF_DEFAULT = false;
|
||||
static const bool MD5_ENABLED_DEFAULT = false;
|
||||
static const bool TLS_SESSION_TICKETS_ENABLED_DEFAULT = true;
|
||||
static const bool REQUIRE_SAFE_NEGOTIATION_DEFAULT = false;
|
||||
static const bool ALLOW_UNRESTRICTED_RENEGO_DEFAULT = false;
|
||||
static const bool FALSE_START_ENABLED_DEFAULT = true;
|
||||
static const bool CIPHER_ENABLED_DEFAULT = false;
|
||||
|
||||
nsresult
|
||||
nsNSSComponent::InitializeNSS(bool showWarningBox)
|
||||
{
|
||||
@ -1119,17 +1108,13 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
|
||||
}
|
||||
|
||||
#ifndef NSS_NO_LIBPKIX
|
||||
rv = mPrefBranch->GetBoolPref("security.use_libpkix_verification", &globalConstFlagUsePKIXVerification);
|
||||
if (NS_FAILED(rv))
|
||||
globalConstFlagUsePKIXVerification = USE_NSS_LIBPKIX_DEFAULT;
|
||||
globalConstFlagUsePKIXVerification =
|
||||
Preferences::GetBool("security.use_libpkix_verification", USE_NSS_LIBPKIX_DEFAULT);
|
||||
#endif
|
||||
|
||||
bool supress_warning_preference = false;
|
||||
rv = mPrefBranch->GetBoolPref("security.suppress_nss_rw_impossible_warning", &supress_warning_preference);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
supress_warning_preference = false;
|
||||
}
|
||||
bool suppressWarningPref =
|
||||
Preferences::GetBool("security.suppress_nss_rw_impossible_warning",
|
||||
SUPPRESS_WARNING_PREF_DEFAULT);
|
||||
|
||||
// init phase 2, init calls to NSS library
|
||||
|
||||
@ -1155,7 +1140,7 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
|
||||
if (init_rv != SECSuccess) {
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("can not init NSS r/w in %s\n", profileStr.get()));
|
||||
|
||||
if (supress_warning_preference) {
|
||||
if (suppressWarningPref) {
|
||||
which_nss_problem = problem_none;
|
||||
}
|
||||
else {
|
||||
@ -1193,38 +1178,44 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
|
||||
SharedSSLState::GlobalInit();
|
||||
|
||||
// Register an observer so we can inform NSS when these prefs change
|
||||
mPrefBranch->AddObserver("security.", this, false);
|
||||
Preferences::AddStrongObserver(this, "security.");
|
||||
|
||||
SSL_OptionSetDefault(SSL_ENABLE_SSL2, false);
|
||||
SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, false);
|
||||
|
||||
rv = setEnabledTLSVersions(mPrefBranch);
|
||||
rv = setEnabledTLSVersions();
|
||||
if (NS_FAILED(rv)) {
|
||||
nsPSMInitPanic::SetPanic();
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
bool enabled = true; // XXX: see bug 733644
|
||||
|
||||
mPrefBranch->GetBoolPref("security.enable_md5_signatures", &enabled);
|
||||
configureMD5(enabled);
|
||||
bool md5Enabled = Preferences::GetBool("security.enable_md5_signatures",
|
||||
MD5_ENABLED_DEFAULT);
|
||||
configureMD5(md5Enabled);
|
||||
|
||||
// Configure TLS session tickets
|
||||
mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
|
||||
bool tlsSessionTicketsEnabled =
|
||||
Preferences::GetBool("security.enable_tls_session_tickets",
|
||||
TLS_SESSION_TICKETS_ENABLED_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, tlsSessionTicketsEnabled);
|
||||
|
||||
mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
|
||||
SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
|
||||
bool requireSafeNegotiation =
|
||||
Preferences::GetBool("security.ssl.require_safe_negotiation",
|
||||
REQUIRE_SAFE_NEGOTIATION_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
|
||||
|
||||
mPrefBranch->GetBoolPref(
|
||||
"security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref",
|
||||
&enabled);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
|
||||
enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
|
||||
bool allowUnrestrictedRenego =
|
||||
Preferences::GetBool("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref",
|
||||
ALLOW_UNRESTRICTED_RENEGO_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
|
||||
allowUnrestrictedRenego ?
|
||||
SSL_RENEGOTIATE_UNRESTRICTED :
|
||||
SSL_RENEGOTIATE_REQUIRES_XTN);
|
||||
|
||||
#ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
|
||||
mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
|
||||
bool falseStartEnabled = Preferences::GetBool("security.ssl.enable_false_start",
|
||||
FALSE_START_ENABLED_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, falseStartEnabled);
|
||||
#endif
|
||||
|
||||
// Disable any ciphers that NSS might have enabled by default
|
||||
@ -1234,13 +1225,11 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
|
||||
SSL_CipherPrefSetDefault(cipher_id, false);
|
||||
}
|
||||
|
||||
bool cipherEnabled;
|
||||
// Now only set SSL/TLS ciphers we knew about at compile time
|
||||
for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
|
||||
rv = mPrefBranch->GetBoolPref(cp->pref, &enabled);
|
||||
if (NS_FAILED(rv))
|
||||
enabled = false;
|
||||
|
||||
SSL_CipherPrefSetDefault(cp->id, enabled);
|
||||
cipherEnabled = Preferences::GetBool(cp->pref, CIPHER_ENABLED_DEFAULT);
|
||||
SSL_CipherPrefSetDefault(cp->id, cipherEnabled);
|
||||
}
|
||||
|
||||
// Enable ciphers for PKCS#12
|
||||
@ -1254,7 +1243,7 @@ nsNSSComponent::InitializeNSS(bool showWarningBox)
|
||||
PORT_SetUCS2_ASCIIConversionFunction(pip_ucs2_ascii_conversion_fn);
|
||||
|
||||
// dynamic options from prefs
|
||||
setValidationOptions(mPrefBranch);
|
||||
setValidationOptions();
|
||||
|
||||
mHttpForNSS.initTable();
|
||||
mHttpForNSS.registerHttpClient();
|
||||
@ -1300,9 +1289,7 @@ nsNSSComponent::ShutdownNSS()
|
||||
PK11_SetPasswordFunc((PK11PasswordFunc)nullptr);
|
||||
mHttpForNSS.unregisterHttpClient();
|
||||
|
||||
if (mPrefBranch) {
|
||||
mPrefBranch->RemoveObserver("security.", this);
|
||||
}
|
||||
Preferences::RemoveObserver(this, "security.");
|
||||
|
||||
#ifndef MOZ_DISABLE_CRYPTOLEGACY
|
||||
ShutdownSmartCardThreads();
|
||||
@ -1323,7 +1310,9 @@ nsNSSComponent::ShutdownNSS()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const bool SEND_LM_DEFAULT = false;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSComponent::Init()
|
||||
{
|
||||
@ -1359,13 +1348,8 @@ nsNSSComponent::Init()
|
||||
getter_Copies(result));
|
||||
}
|
||||
|
||||
if (!mPrefBranch) {
|
||||
mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
NS_ASSERTION(mPrefBranch, "Unable to get pref service");
|
||||
}
|
||||
|
||||
bool sendLM = false;
|
||||
mPrefBranch->GetBoolPref("network.ntlm.send-lm-response", &sendLM);
|
||||
bool sendLM = Preferences::GetBool("network.ntlm.send-lm-response",
|
||||
SEND_LM_DEFAULT);
|
||||
nsNTLMAuthModule::SetSendLM(sendLM);
|
||||
|
||||
// Do that before NSS init, to make sure we won't get unloaded.
|
||||
@ -1635,31 +1619,40 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
else if (nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0) {
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
bool clearSessionCache = false;
|
||||
bool enabled;
|
||||
NS_ConvertUTF16toUTF8 prefName(someData);
|
||||
|
||||
if (prefName.Equals("security.tls.version.min") ||
|
||||
prefName.Equals("security.tls.version.max")) {
|
||||
(void) setEnabledTLSVersions(mPrefBranch);
|
||||
(void) setEnabledTLSVersions();
|
||||
clearSessionCache = true;
|
||||
} else if (prefName.Equals("security.enable_md5_signatures")) {
|
||||
mPrefBranch->GetBoolPref("security.enable_md5_signatures", &enabled);
|
||||
configureMD5(enabled);
|
||||
bool md5Enabled = Preferences::GetBool("security.enable_md5_signatures",
|
||||
MD5_ENABLED_DEFAULT);
|
||||
configureMD5(md5Enabled);
|
||||
clearSessionCache = true;
|
||||
} else if (prefName.Equals("security.enable_tls_session_tickets")) {
|
||||
mPrefBranch->GetBoolPref("security.enable_tls_session_tickets", &enabled);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, enabled);
|
||||
bool tlsSessionTicketsEnabled =
|
||||
Preferences::GetBool("security.enable_tls_session_tickets",
|
||||
TLS_SESSION_TICKETS_ENABLED_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_SESSION_TICKETS, tlsSessionTicketsEnabled);
|
||||
} else if (prefName.Equals("security.ssl.require_safe_negotiation")) {
|
||||
mPrefBranch->GetBoolPref("security.ssl.require_safe_negotiation", &enabled);
|
||||
SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, enabled);
|
||||
bool requireSafeNegotiation =
|
||||
Preferences::GetBool("security.ssl.require_safe_negotiation",
|
||||
REQUIRE_SAFE_NEGOTIATION_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_REQUIRE_SAFE_NEGOTIATION, requireSafeNegotiation);
|
||||
} else if (prefName.Equals("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref")) {
|
||||
mPrefBranch->GetBoolPref("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref", &enabled);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
|
||||
enabled ? SSL_RENEGOTIATE_UNRESTRICTED : SSL_RENEGOTIATE_REQUIRES_XTN);
|
||||
bool allowUnrestrictedRenego =
|
||||
Preferences::GetBool("security.ssl.allow_unrestricted_renego_everywhere__temporarily_available_pref",
|
||||
ALLOW_UNRESTRICTED_RENEGO_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_RENEGOTIATION,
|
||||
allowUnrestrictedRenego ?
|
||||
SSL_RENEGOTIATE_UNRESTRICTED :
|
||||
SSL_RENEGOTIATE_REQUIRES_XTN);
|
||||
#ifdef SSL_ENABLE_FALSE_START // Requires NSS 3.12.8
|
||||
} else if (prefName.Equals("security.ssl.enable_false_start")) {
|
||||
mPrefBranch->GetBoolPref("security.ssl.enable_false_start", &enabled);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, enabled);
|
||||
bool falseStartEnabled = Preferences::GetBool("security.ssl.enable_false_start",
|
||||
FALSE_START_ENABLED_DEFAULT);
|
||||
SSL_OptionSetDefault(SSL_ENABLE_FALSE_START, falseStartEnabled);
|
||||
#endif
|
||||
} else if (prefName.Equals("security.OCSP.enabled")
|
||||
|| prefName.Equals("security.CRL_download.enabled")
|
||||
@ -1669,17 +1662,18 @@ nsNSSComponent::Observe(nsISupports *aSubject, const char *aTopic,
|
||||
|| prefName.Equals("security.OCSP.require")
|
||||
|| prefName.Equals("security.ssl.enable_ocsp_stapling")) {
|
||||
MutexAutoLock lock(mutex);
|
||||
setValidationOptions(mPrefBranch);
|
||||
setValidationOptions();
|
||||
} else if (prefName.Equals("network.ntlm.send-lm-response")) {
|
||||
bool sendLM = false;
|
||||
mPrefBranch->GetBoolPref("network.ntlm.send-lm-response", &sendLM);
|
||||
bool sendLM = Preferences::GetBool("network.ntlm.send-lm-response",
|
||||
SEND_LM_DEFAULT);
|
||||
nsNTLMAuthModule::SetSendLM(sendLM);
|
||||
} else {
|
||||
/* Look through the cipher table and set according to pref setting */
|
||||
bool cipherEnabled;
|
||||
for (CipherPref* cp = CipherPrefs; cp->pref; ++cp) {
|
||||
if (prefName.Equals(cp->pref)) {
|
||||
mPrefBranch->GetBoolPref(cp->pref, &enabled);
|
||||
SSL_CipherPrefSetDefault(cp->id, enabled);
|
||||
cipherEnabled = Preferences::GetBool(cp->pref, CIPHER_ENABLED_DEFAULT);
|
||||
SSL_CipherPrefSetDefault(cp->id, cipherEnabled);
|
||||
clearSessionCache = true;
|
||||
break;
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "nsISignatureVerifier.h"
|
||||
#include "nsIEntropyCollector.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#ifndef MOZ_DISABLE_CRYPTOLEGACY
|
||||
@ -185,8 +184,8 @@ private:
|
||||
void InstallLoadableRoots();
|
||||
void UnloadLoadableRoots();
|
||||
void CleanupIdentityInfo();
|
||||
void setValidationOptions(nsIPrefBranch * pref);
|
||||
nsresult setEnabledTLSVersions(nsIPrefBranch * pref);
|
||||
void setValidationOptions();
|
||||
nsresult setEnabledTLSVersions();
|
||||
nsresult InitializePIPNSSBundle();
|
||||
nsresult ConfigureInternalPKCS11Token();
|
||||
nsresult RegisterObservers();
|
||||
@ -203,7 +202,6 @@ private:
|
||||
|
||||
nsCOMPtr<nsIStringBundle> mPIPNSSBundle;
|
||||
nsCOMPtr<nsIStringBundle> mNSSErrorsBundle;
|
||||
nsCOMPtr<nsIPrefBranch> mPrefBranch;
|
||||
bool mNSSInitialized;
|
||||
bool mObserversRegistered;
|
||||
static int mInstanceCount;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user