import changes from `dev' branch of rmottola/Arctic-Fox:

- Bug 1125514 - Use jemalloc's metadata statistics to compute bookkeeping. r=glandium (541dbcfc6f)
- Bug 1201462 - Don't count arena allocated metadata once per bin. r=glandium (57e7c31081)
- back some warnings (377df69d65)
- Bug 1219501. In imagelib, initialize the number of cores to at least 1 in case of error. r=seth (3d7d1635f0)
- Bug 1219501. Limit total number of image decoding threads to 32 regardless of number asked for. r=seth (829a7a623d)
- Bug 1213744 (Part 1) - Support zero-size frame rects and detecting the end of the frame in Downscaler. r=tn (05e29075cc)
- Bug 1213744 (Part 2) - Clamp the GIF frame rect to the visible rect for DDD and don't decode outside it. r=tn (8a25e10a3e)
- Bug 1194837. Don't use the inverse orientation matrix when computing the image space invalidate rect. r=seth (cb5e4c2643)
- Bug 1214054 - Don't fire DECODE_COMPLETE in VectorImage::OnSVGDocumetError(). r=dholbert (bb7c34e46f)
- Bug 1195878 - If we detect animation during a full decode, drop the results of the full decode on the floor. r=tn (a765af2b68)
- Bug 1210553 - Remove the alternate flags arguments from SurfaceCache's Lookup functions. r=dholbert (15c6124f98)
- Bug 1217320 - Remove more XPIDL signature comments in .cpp files. r=froydnj (411ac93047)
- Bug 1186796 - Replace nsBaseHashtable::EnumerateRead() calls in image/ with iterators r=njn (665773ae6d)
- Bug 1186792 - Replace nsBaseHashtable::EnumerateRead() calls in hal/ with iterators. r=dhylands. (d57c6b11da)
- Bug 1187142 - Replace nsBaseHashtable::Enumerate() calls in hal/ with iterators. r=dhylands. (ec05c5b125)
- Bug 1186793 - Replace nsBaseHashtable::EnumerateRead() calls in gfx/ with iterators r=njn (9b3cdd92ce)
- Bug 1215900 - Fix clang's -Wimplicit-fallthrough warnings in gfx/ipc/ GfxMessageUtils.h. r=mstange (f55605f1fe)
- Bug 618898 - Part 1: Add WGL_NV_DX_interop. r=jgilbert (73390398ed)
- Bug 618898 - Add D3D11SharedSurfaceInterop. r=jgilbert (3dde956b85)
- Bug 1208513 - Resurrect SharedSurface_GLTexture for use on iOS r=jgilbert (b0fdc90414)
- Bug 1150760 - Don't call workaround unless necessary. - r=kamidphish (9bdd135931)
- Bug 1151106 - let debugger stop on each iteration of a "for(;;)" loop; r=jimb (b1b921c3a7)
- Bug 1223652 - Remove redundant else block after return statement in CGBlockScopeList::findEnclosingScope. r=arai (f1368bfc73)
- Bug 1219515 - IonMonkey: Fix ThrowIfNotConstructing was not declared. r=evilpie (1d6cedad10)
- Bug 1224044 - Use stable hashing in SavedFramePtrHasher r=terrence (4389cf1b70)
- Bug 1206596: Change js::SavedStacks to use mozilla::FastBernoulliTrial. r=fitzgen (1c4a8d1929)
- Bug 1206357: Add mfbt/FastBernoulliTrial.h, implementing efficient random sampling. r=waldo (7143e53dba)
- No bug: Fix comment in mfbt/FastBernoulliTrial.h. DONTBUILD r=me (e3343f8d9d)
- Bug 1217919 - Separate dynamic module scopes from those of function calls r=shu (521f6826e5)
- Bug 1202568 - Cherry-pick warning fixes from upstream double-conversion. r=Ms2ger (ef738f753b)
- add back some disabled android stuff (0351b0c518)
- Bug 1135261 - return new window from window.open in desktop runtime; r=marco,smaug,junior,wesj (fa4d8f2468)
- Bug 898075 - Remove the mozbrowserasyncscroll event from Gecko. r=botond,kanru,sicking (b1fdcb7630)
- namespace (91374d2db8)
This commit is contained in:
2022-12-30 09:29:16 +08:00
parent 8823358c83
commit 9af8eeaf15
112 changed files with 2250 additions and 1165 deletions
-1
View File
@@ -966,7 +966,6 @@ pref("apz.allow_zooming", true);
// Gaia relies heavily on scroll events for now, so lets fire them
// more often than the default value (100).
pref("apz.asyncscroll.throttle", 40);
pref("apz.pan_repaint_interval", 16);
// APZ physics settings, tuned by UX designers
+3
View File
@@ -17,3 +17,6 @@ FINAL_LIBRARY = 'browsercomps'
LOCAL_INCLUDES += [
'../build',
]
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
+3
View File
@@ -39,3 +39,6 @@ if CONFIG['OS_ARCH'] == 'WINNT':
# GTK2: Need to link with glib for GNOME shell service
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('cocoa', 'gtk2', 'gtk3'):
OS_LIBS += CONFIG['TK_LIBS']
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
+7
View File
@@ -12,8 +12,15 @@ SOURCES += [
'DirectoryProvider.cpp',
]
XPCSHELL_TESTS_MANIFESTS += [
'tests/unit/xpcshell.ini',
]
FINAL_LIBRARY = 'browsercomps'
LOCAL_INCLUDES += [
'../build'
]
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
@@ -0,0 +1,20 @@
/* 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/. */
var Cc = Components.classes;
var Ci = Components.interfaces;
var gProfD = do_get_profile();
var gDirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
var gPrefSvc = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
function writeTestFile(aParent, aName) {
let file = aParent.clone();
file.append(aName);
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
return file;
}
@@ -0,0 +1,14 @@
/* 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/. */
// We need to run this test separately since DirectoryProvider persists BMarks
function run_test() {
let dir = gProfD.clone();
let tfile = writeTestFile(dir, "bookmarkfile.test");
gPrefSvc.setCharPref("browser.bookmarks.file", tfile.path);
let bmarks = gDirSvc.get("BMarks", Ci.nsIFile);
do_check_true(tfile.equals(bmarks));
}
@@ -0,0 +1,21 @@
/* 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/. */
function test_bookmarkhtml() {
let bmarks = gProfD.clone();
bmarks.append("bookmarks.html");
let tbmarks = gDirSvc.get("BMarks", Ci.nsIFile);
do_check_true(bmarks.equals(tbmarks));
}
function run_test() {
[test_bookmarkhtml
].forEach(function(f) {
do_test_pending();
print("Running test: " + f.name);
f();
do_test_finished();
});
}
@@ -0,0 +1,8 @@
[DEFAULT]
head = head_dirprovider.js
tail =
firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_bookmark_pref.js]
[test_keys.js]
-3
View File
@@ -435,9 +435,6 @@ Exception::ToString(nsACString& _retval)
return NS_OK;
}
/* void initialize (in AUTF8String aMessage, in nsresult aResult,
* in AUTF8String aName, in nsIStackFrame aLocation,
* in nsISupports aData, in nsIException aInner); */
NS_IMETHODIMP
Exception::Initialize(const nsACString& aMessage, nsresult aResult,
const nsACString& aName, nsIStackFrame *aLocation,
-1
View File
@@ -7525,7 +7525,6 @@ nsIDocument::GetDocumentURIObject() const
}
// readonly attribute DOMString compatMode;
// Returns "BackCompat" if we are in quirks mode, "CSS1Compat" if we are
// in almost standards or full standards mode. See bug 105640. This was
// implemented to match MSIE's compatMode property.
+2 -77
View File
@@ -117,7 +117,7 @@ DispatchCustomDOMEvent(Element* aFrameElement, const nsAString& aEventName,
}
event->SetTrusted(true);
// Dispatch the event.
*aStatus = nsEventStatus_eConsumeNoDefault;
// We don't initialize aStatus here, as our callers have already done so.
nsresult rv =
EventDispatcher::DispatchDOMEvent(aFrameElement, nullptr,
static_cast<Event*>(event),
@@ -177,7 +177,7 @@ BrowserElementParent::DispatchOpenWindowEvent(Element* aOpenerFrameElement,
return BrowserElementParent::OPEN_WINDOW_CANCELLED;
}
nsEventStatus status;
nsEventStatus status = nsEventStatus_eIgnore;
bool dispatchSucceeded =
DispatchCustomDOMEvent(aOpenerFrameElement,
NS_LITERAL_STRING("mozbrowseropenwindow"),
@@ -299,79 +299,4 @@ BrowserElementParent::OpenWindowInProcess(nsIDOMWindow* aOpenerWindow,
return !!*aReturnWindow ? opened : BrowserElementParent::OPEN_WINDOW_CANCELLED;
}
class DispatchAsyncScrollEventRunnable : public nsRunnable
{
public:
DispatchAsyncScrollEventRunnable(TabParent* aTabParent,
const CSSRect& aContentRect,
const CSSSize& aContentSize)
: mTabParent(aTabParent)
, mContentRect(aContentRect)
, mContentSize(aContentSize)
{}
NS_IMETHOD Run();
private:
RefPtr<TabParent> mTabParent;
const CSSRect mContentRect;
const CSSSize mContentSize;
};
NS_IMETHODIMP DispatchAsyncScrollEventRunnable::Run()
{
nsCOMPtr<Element> frameElement = mTabParent->GetOwnerElement();
NS_ENSURE_STATE(frameElement);
nsIDocument *doc = frameElement->OwnerDoc();
nsCOMPtr<nsIGlobalObject> globalObject = doc->GetScopeObject();
NS_ENSURE_TRUE(globalObject, NS_ERROR_UNEXPECTED);
// Create the event's detail object.
AsyncScrollEventDetail detail;
detail.mLeft = mContentRect.x;
detail.mTop = mContentRect.y;
detail.mWidth = mContentRect.width;
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);
if (!ToJSValue(cx, detail, &val)) {
MOZ_CRASH("Failed to convert dictionary to JS::Value due to OOM.");
return NS_ERROR_FAILURE;
}
nsEventStatus status = nsEventStatus_eIgnore;
DispatchCustomDOMEvent(frameElement,
NS_LITERAL_STRING("mozbrowserasyncscroll"),
cx,
val, &status);
return NS_OK;
}
bool
BrowserElementParent::DispatchAsyncScrollEvent(TabParent* aTabParent,
const CSSRect& aContentRect,
const CSSSize& aContentSize)
{
// Do not dispatch a mozbrowserasyncscroll event of a widget to its embedder
nsCOMPtr<Element> frameElement = aTabParent->GetOwnerElement();
NS_ENSURE_TRUE(frameElement, false);
nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(frameElement);
if (browserFrame && browserFrame->GetReallyIsWidget()) {
return true;
}
RefPtr<DispatchAsyncScrollEventRunnable> runnable =
new DispatchAsyncScrollEventRunnable(aTabParent, aContentRect,
aContentSize);
return NS_SUCCEEDED(NS_DispatchToMainThread(runnable));
}
} // namespace mozilla
@@ -109,26 +109,6 @@ public:
const nsACString& aFeatures,
nsIDOMWindow** aReturnWindow);
/**
* Fire a mozbrowserasyncscroll CustomEvent on the given TabParent's frame element.
* This event's detail is an AsyncScrollEventDetail dictionary.
*
* @param aContentRect: The portion of the page which is currently visible
* onscreen in CSS pixels.
*
* @param aContentSize: The content width/height in CSS pixels.
*
* aContentRect.top + aContentRect.height may be larger than aContentSize.height.
* This indicates that the content is over-scrolled, which occurs when the
* page "rubber-bands" after being scrolled all the way to the bottom.
* Similarly, aContentRect.left + aContentRect.width may be greater than
* contentSize.width, and both left and top may be negative.
*/
static bool
DispatchAsyncScrollEvent(dom::TabParent* aTabParent,
const CSSRect& aContentRect,
const CSSSize& aContentSize);
private:
static OpenWindowResult
DispatchOpenWindowEvent(dom::Element* aOpenerFrameElement,
-3
View File
@@ -5322,9 +5322,6 @@ CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
JS::ToInt32(dirtyHeight));
}
// void putImageData (in ImageData d, in float x, in float y);
// void putImageData (in ImageData d, in double x, in double y, in double dirtyX, in double dirtyY, in double dirtyWidth, in double dirtyHeight);
nsresult
CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
dom::Uint8ClampedArray* aArray,
-6
View File
@@ -59,8 +59,6 @@ NS_IMETHODIMP GamepadServiceTest::RemoveGamepad(uint32_t aIndex)
return NS_OK;
}
/* void newButtonEvent (in uint32_t index, in uint32_t button,
in boolean pressed); */
NS_IMETHODIMP GamepadServiceTest::NewButtonEvent(uint32_t aIndex,
uint32_t aButton,
bool aPressed)
@@ -69,8 +67,6 @@ NS_IMETHODIMP GamepadServiceTest::NewButtonEvent(uint32_t aIndex,
return NS_OK;
}
/* void newButtonEvent (in uint32_t index, in uint32_t button,
in boolean pressed, double value); */
NS_IMETHODIMP GamepadServiceTest::NewButtonValueEvent(uint32_t aIndex,
uint32_t aButton,
bool aPressed,
@@ -80,8 +76,6 @@ NS_IMETHODIMP GamepadServiceTest::NewButtonValueEvent(uint32_t aIndex,
return NS_OK;
}
/* void newAxisMoveEvent (in uint32_t index, in uint32_t axis,
in double value); */
NS_IMETHODIMP GamepadServiceTest::NewAxisMoveEvent(uint32_t aIndex,
uint32_t aAxis,
double aValue)
-2
View File
@@ -3199,8 +3199,6 @@ ConvertToMidasInternalCommand(const nsAString & inCommandID,
}
/* TODO: don't let this call do anything if the page is not done loading */
/* boolean execCommand(in DOMString commandID, in boolean doShowUI,
in DOMString value); */
NS_IMETHODIMP
nsHTMLDocument::ExecCommand(const nsAString& commandID,
bool doShowUI,
-1
View File
@@ -156,7 +156,6 @@ DOMSVGPathSeg::IndexIsValid()
// Implementation of DOMSVGPathSeg sub-classes below this point
#define IMPL_PROP_WITH_TYPE(segName, propName, index, type) \
/* attribute type propName; */ \
type \
DOMSVGPathSeg##segName::propName() \
{ \
@@ -233,7 +233,6 @@ StumblerInfo::DumpStumblerInfo()
target->Dispatch(event, NS_DISPATCH_NORMAL);
}
/* void notifyGetCellInfoList (in uint32_t count, [array, size_is (count)] in nsICellInfo result); */
NS_IMETHODIMP
StumblerInfo::NotifyGetCellInfoList(uint32_t count, nsICellInfo** aCellInfos)
{
@@ -248,7 +247,6 @@ StumblerInfo::NotifyGetCellInfoList(uint32_t count, nsICellInfo** aCellInfos)
return NS_OK;
}
/* void notifyGetCellInfoListFailed (in DOMString error); */
NS_IMETHODIMP StumblerInfo::NotifyGetCellInfoListFailed(const nsAString& error)
{
MOZ_ASSERT(NS_IsMainThread());
@@ -7,15 +7,6 @@
* liability, trademark and document use rules apply.
*/
dictionary AsyncScrollEventDetail {
float top = 0;
float left = 0;
float width = 0;
float height = 0;
float scrollWidth = 0;
float scrollHeight = 0;
};
dictionary OpenWindowEventDetail {
DOMString url = "";
DOMString name = "";
-4
View File
@@ -85,10 +85,6 @@ NS_IMETHODIMP nsTransactionList::ItemIsBatch(int32_t aIndex, bool *aIsBatch)
return item->GetIsBatch(aIsBatch);
}
/* void getData (in long aIndex,
[optional] out unsigned long aLength,
[array, size_is (aLength), retval]
out nsISupports aData); */
NS_IMETHODIMP nsTransactionList::GetData(int32_t aIndex,
uint32_t *aLength,
nsISupports ***aData)
@@ -327,9 +327,6 @@ NS_IMETHODIMP nsWebBrowserPersist::SetProgressListener(
return NS_OK;
}
/* void saveURI (in nsIURI aURI, in nsISupports aCacheKey, in nsIURI aReferrer,
in nsIInputStream aPostData, in wstring aExtraHeaders,
in nsISupports aFile, in nsILoadContext aPrivayContext); */
NS_IMETHODIMP nsWebBrowserPersist::SaveURI(
nsIURI *aURI, nsISupports *aCacheKey,
nsIURI *aReferrer, uint32_t aReferrerPolicy,
@@ -905,8 +902,6 @@ nsWebBrowserPersist::OnDataAvailable(
// nsWebBrowserPersist::nsIProgressEventSink
//*****************************************************************************
/* void onProgress (in nsIRequest request, in nsISupports ctxt,
in long long aProgress, in long long aProgressMax); */
NS_IMETHODIMP nsWebBrowserPersist::OnProgress(
nsIRequest *request, nsISupports *ctxt, int64_t aProgress,
int64_t aProgressMax)
@@ -958,8 +953,6 @@ NS_IMETHODIMP nsWebBrowserPersist::OnProgress(
return NS_OK;
}
/* void onStatus (in nsIRequest request, in nsISupports ctxt,
in nsresult status, in wstring statusArg); */
NS_IMETHODIMP nsWebBrowserPersist::OnStatus(
nsIRequest *request, nsISupports *ctxt, nsresult status,
const char16_t *statusArg)
-3
View File
@@ -5668,7 +5668,6 @@
#define LOCAL_GLX_X_VISUAL_TYPE_EXT 0x22
#define LOCAL_GLX_Y_INVERTED_EXT 0x20D4
// WGL
#define LOCAL_WGL_ACCELERATION_ARB 0x2003
#define LOCAL_WGL_ACCELERATION_EXT 0x2003
@@ -5949,6 +5948,4 @@
#define LOCAL_WGL_VIDEO_OUT_STACKED_FIELDS_1_2 0x20CB
#define LOCAL_WGL_VIDEO_OUT_STACKED_FIELDS_2_1 0x20CC
#endif // GLCONSTS_H_
+48 -15
View File
@@ -141,9 +141,11 @@ WGLLibrary::EnsureInitialized()
return false;
}
const GLLibraryLoader::PlatformLookupFunction lookupFunc =
(GLLibraryLoader::PlatformLookupFunction) fGetProcAddress;
// Now we can grab all the other symbols that we couldn't without having
// a context current.
GLLibraryLoader::SymLoadStruct pbufferSymbols[] = {
{ (PRFuncPtr*) &fCreatePbuffer, { "wglCreatePbufferARB", "wglCreatePbufferEXT", nullptr } },
{ (PRFuncPtr*) &fDestroyPbuffer, { "wglDestroyPbufferARB", "wglDestroyPbufferEXT", nullptr } },
@@ -159,16 +161,12 @@ WGLLibrary::EnsureInitialized()
{ nullptr, { nullptr } }
};
if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pbufferSymbols[0],
(GLLibraryLoader::PlatformLookupFunction)fGetProcAddress))
{
if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pbufferSymbols[0], lookupFunc)) {
// this isn't an error, just means that pbuffers aren't supported
fCreatePbuffer = nullptr;
}
if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pixFmtSymbols[0],
(GLLibraryLoader::PlatformLookupFunction)fGetProcAddress))
{
if (!GLLibraryLoader::LoadSymbols(mOGLLibrary, &pixFmtSymbols[0], lookupFunc)) {
// this isn't an error, just means that we don't have the pixel format extension
fChoosePixelFormat = nullptr;
}
@@ -183,14 +181,49 @@ WGLLibrary::EnsureInitialized()
{ nullptr, { nullptr } }
};
if (GLLibraryLoader::LoadSymbols(mOGLLibrary, &extensionsSymbols[0],
(GLLibraryLoader::PlatformLookupFunction)fGetProcAddress)) {
const char *wglExts = fGetExtensionsString(mWindowDC);
if (wglExts && HasExtension(wglExts, "WGL_ARB_create_context")) {
GLLibraryLoader::LoadSymbols(mOGLLibrary, &robustnessSymbols[0],
(GLLibraryLoader::PlatformLookupFunction)fGetProcAddress);
if (HasExtension(wglExts, "WGL_ARB_create_context_robustness")) {
mHasRobustness = true;
GLLibraryLoader::SymLoadStruct dxInteropSymbols[] = {
{ (PRFuncPtr *)&fDXSetResourceShareHandle,{ "wglDXSetResourceShareHandleNV", nullptr } },
{ (PRFuncPtr *)&fDXOpenDevice, { "wglDXOpenDeviceNV", nullptr } },
{ (PRFuncPtr *)&fDXCloseDevice, { "wglDXCloseDeviceNV", nullptr } },
{ (PRFuncPtr *)&fDXRegisterObject, { "wglDXRegisterObjectNV", nullptr } },
{ (PRFuncPtr *)&fDXUnregisterObject, { "wglDXUnregisterObjectNV", nullptr } },
{ (PRFuncPtr *)&fDXObjectAccess, { "wglDXObjectAccessNV", nullptr } },
{ (PRFuncPtr *)&fDXLockObjects, { "wglDXLockObjectsNV", nullptr } },
{ (PRFuncPtr *)&fDXUnlockObjects, { "wglDXUnlockObjectsNV", nullptr } },
{ nullptr, { nullptr } }
};
if (GLLibraryLoader::LoadSymbols(mOGLLibrary, &extensionsSymbols[0], lookupFunc))
{
const char* extString = fGetExtensionsString(mWindowDC);
MOZ_ASSERT(extString);
MOZ_ASSERT(HasExtension(extString, "WGL_ARB_extensions_string"));
if (HasExtension(extString, "WGL_ARB_context_create")) {
if (GLLibraryLoader::LoadSymbols(mOGLLibrary, &robustnessSymbols[0], lookupFunc)) {
if (HasExtension(extString, "WGL_ARB_create_context_robustness")) {
mHasRobustness = true;
}
} else {
NS_ERROR("WGL supports ARB_create_context without supplying its functions.");
fCreateContextAttribs = nullptr;
}
}
if (HasExtension(extString, "WGL_NV_DX_interop")) {
if (GLLibraryLoader::LoadSymbols(mOGLLibrary, &dxInteropSymbols[0], lookupFunc)) {
mHasDXInterop = true;
mHasDXInterop2 = HasExtension(extString, "WGL_NV_DX_interop2");
} else {
NS_ERROR("WGL supports NV_DX_interop without supplying its functions.");
fDXSetResourceShareHandle = nullptr;
fDXOpenDevice = nullptr;
fDXCloseDevice = nullptr;
fDXRegisterObject = nullptr;
fDXUnregisterObject = nullptr;
fDXObjectAccess = nullptr;
fDXLockObjects = nullptr;
fDXUnlockObjects = nullptr;
}
}
}
+5
View File
@@ -70,4 +70,9 @@
#define LOCAL_EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
#define LOCAL_EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
// WGL_NV_DX_interop
#define LOCAL_WGL_ACCESS_READ_ONLY 0x0000
#define LOCAL_WGL_ACCESS_READ_WRITE 0x0001
#define LOCAL_WGL_ACCESS_WRITE_DISCARD 0x0002
#endif
+14 -5
View File
@@ -19,7 +19,8 @@
#include "mozilla/layers/TextureClientSharedSurface.h"
#ifdef XP_WIN
#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
#include "SharedSurfaceANGLE.h" // for SurfaceFactory_ANGLEShareHandle
#include "SharedSurfaceD3D11Interop.h" // for SurfaceFactory_D3D11Interop
#include "gfxWindowsPlatform.h"
#endif
@@ -82,6 +83,8 @@ GLScreenBuffer::CreateFactory(GLContext* gl,
#elif defined(GL_PROVIDER_GLX)
if (sGLXLibrary.UseSurfaceSharing())
factory = SurfaceFactory_GLXDrawable::Create(gl, caps, forwarder, flags);
#elif defined(MOZ_WIDGET_UIKIT)
factory = MakeUnique<SurfaceFactory_GLTexture>(mGLContext, caps, forwarder, mFlags);
#else
if (gl->GetContextType() == GLContextType::EGL) {
if (XRE_IsParentProcess()) {
@@ -101,6 +104,10 @@ GLScreenBuffer::CreateFactory(GLContext* gl,
{
factory = SurfaceFactory_ANGLEShareHandle::Create(gl, caps, forwarder, flags);
}
if (!factory && gfxPrefs::WebGLDXGLEnabled()) {
factory = SurfaceFactory_D3D11Interop::Create(gl, caps, forwarder, flags);
}
#endif
break;
}
@@ -525,6 +532,12 @@ GLScreenBuffer::Swap(const gfx::IntSize& size)
if (!newBack)
return false;
// In the case of DXGL interop, the new surface needs to be acquired before
// it is attached so that the interop surface is locked, which populates
// the GL renderbuffer. This results in the renderbuffer being ready and
// attachment to framebuffer succeeds in Attach() call.
newBack->Surf()->ProducerAcquire();
if (!Attach(newBack->Surf(), size))
return false;
// Attach was successful.
@@ -532,10 +545,6 @@ GLScreenBuffer::Swap(const gfx::IntSize& size)
mFront = mBack;
mBack = newBack;
if (mBack) {
mBack->Surf()->ProducerAcquire();
}
if (ShouldPreserveBuffer() &&
mFront &&
mBack &&
+509
View File
@@ -0,0 +1,509 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* 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 "SharedSurfaceD3D11Interop.h"
#include <d3d11.h>
#include "GLContext.h"
#include "WGLLibrary.h"
namespace mozilla {
namespace gl {
/*
Sample Code for WGL_NV_DX_interop2:
Example: Render to Direct3D 11 backbuffer with openGL:
// create D3D11 device, context and swap chain.
ID3D11Device *device;
ID3D11DeviceContext *devCtx;
IDXGISwapChain *swapChain;
DXGI_SWAP_CHAIN_DESC scd;
<set appropriate swap chain parameters in scd>
hr = D3D11CreateDeviceAndSwapChain(NULL, // pAdapter
D3D_DRIVER_TYPE_HARDWARE, // DriverType
NULL, // Software
0, // Flags (Do not set D3D11_CREATE_DEVICE_SINGLETHREADED)
NULL, // pFeatureLevels
0, // FeatureLevels
D3D11_SDK_VERSION, // SDKVersion
&scd, // pSwapChainDesc
&swapChain, // ppSwapChain
&device, // ppDevice
NULL, // pFeatureLevel
&devCtx); // ppImmediateContext
// Fetch the swapchain backbuffer
ID3D11Texture2D *dxColorbuffer;
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID *)&dxColorbuffer);
// Create depth stencil texture
ID3D11Texture2D *dxDepthBuffer;
D3D11_TEXTURE2D_DESC depthDesc;
depthDesc.Usage = D3D11_USAGE_DEFAULT;
<set other depthDesc parameters appropriately>
// Create Views
ID3D11RenderTargetView *colorBufferView;
D3D11_RENDER_TARGET_VIEW_DESC rtd;
<set rtd parameters appropriately>
device->CreateRenderTargetView(dxColorbuffer, &rtd, &colorBufferView);
ID3D11DepthStencilView *depthBufferView;
D3D11_DEPTH_STENCIL_VIEW_DESC dsd;
<set dsd parameters appropriately>
device->CreateDepthStencilView(dxDepthBuffer, &dsd, &depthBufferView);
// Attach back buffer and depth texture to redertarget for the device.
devCtx->OMSetRenderTargets(1, &colorBufferView, depthBufferView);
// Register D3D11 device with GL
HANDLE gl_handleD3D;
gl_handleD3D = wglDXOpenDeviceNV(device);
// register the Direct3D color and depth/stencil buffers as
// renderbuffers in opengl
GLuint gl_names[2];
HANDLE gl_handles[2];
glGenRenderbuffers(2, gl_names);
gl_handles[0] = wglDXRegisterObjectNV(gl_handleD3D, dxColorBuffer,
gl_names[0],
GL_RENDERBUFFER,
WGL_ACCESS_READ_WRITE_NV);
gl_handles[1] = wglDXRegisterObjectNV(gl_handleD3D, dxDepthBuffer,
gl_names[1],
GL_RENDERBUFFER,
WGL_ACCESS_READ_WRITE_NV);
// attach the Direct3D buffers to an FBO
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, gl_names[0]);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, gl_names[1]);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, gl_names[1]);
while (!done) {
<direct3d renders to the render targets>
// lock the render targets for GL access
wglDXLockObjectsNVX(gl_handleD3D, 2, gl_handles);
<opengl renders to the render targets>
// unlock the render targets
wglDXUnlockObjectsNVX(gl_handleD3D, 2, gl_handles);
<direct3d renders to the render targets and presents
the results on the screen>
}
*/
////////////////////////////////////////////////////////////////////////////////
// DXGL Device
class DXGLDevice : public RefCounted<DXGLDevice>
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(DXGLDevice)
WGLLibrary* const mWGL;
const RefPtr<ID3D11Device> mD3D; // Only needed for lifetime guarantee.
const HANDLE mDXGLDeviceHandle;
static already_AddRefed<DXGLDevice> Open(WGLLibrary* wgl)
{
MOZ_ASSERT(wgl->HasDXInterop2());
gfxWindowsPlatform* plat = gfxWindowsPlatform::GetPlatform();
RefPtr<ID3D11Device> d3d = plat->GetD3D11ContentDevice();
if (!d3d) {
NS_WARNING("Failed to create D3D11 device.");
return nullptr;
}
HANDLE dxglDeviceHandle = wgl->fDXOpenDevice(d3d);
if (!dxglDeviceHandle) {
NS_WARNING("Failed to open D3D device for use by WGL.");
return nullptr;
}
return MakeAndAddRef<DXGLDevice>(wgl, d3d, dxglDeviceHandle);
}
DXGLDevice(WGLLibrary* wgl, const RefPtr<ID3D11Device>& d3d, HANDLE dxglDeviceHandle)
: mWGL(wgl)
, mD3D(d3d)
, mDXGLDeviceHandle(dxglDeviceHandle)
{ }
~DXGLDevice() {
if (!mWGL->fDXCloseDevice(mDXGLDeviceHandle)) {
#ifdef DEBUG
uint32_t error = GetLastError();
printf_stderr("wglDXCloseDevice(0x%x) failed: GetLastError(): 0x%x\n",
mDXGLDeviceHandle, error);
#endif
MOZ_CRASH();
}
}
HANDLE RegisterObject(void* dxObject, GLuint name, GLenum type, GLenum access) const {
HANDLE ret = mWGL->fDXRegisterObject(mDXGLDeviceHandle, dxObject, name, type,
access);
if (!ret) {
#ifdef DEBUG
uint32_t error = GetLastError();
printf_stderr("wglDXRegisterObject(0x%x, 0x%x, %u, 0x%x, 0x%x) failed:"
" GetLastError(): 0x%x\n", mDXGLDeviceHandle, dxObject, name,
type, access, error);
#endif
MOZ_CRASH();
}
return ret;
}
bool UnregisterObject(HANDLE hObject) const {
bool ret = mWGL->fDXUnregisterObject(mDXGLDeviceHandle, hObject);
if (!ret) {
#ifdef DEBUG
uint32_t error = GetLastError();
printf_stderr("wglDXUnregisterObject(0x%x, 0x%x) failed: GetLastError():"
" 0x%x\n", mDXGLDeviceHandle, hObject, error);
#endif
MOZ_CRASH();
}
return ret;
}
bool LockObject(HANDLE hObject) const {
bool ret = mWGL->fDXLockObjects(mDXGLDeviceHandle, 1, &hObject);
if (!ret) {
#ifdef DEBUG
uint32_t error = GetLastError();
printf_stderr("wglDXLockObjects(0x%x, 1, {0x%x}) failed: GetLastError():"
" 0x%x\n", mDXGLDeviceHandle, hObject, error);
#endif
MOZ_CRASH();
}
return ret;
}
bool UnlockObject(HANDLE hObject) const {
bool ret = mWGL->fDXUnlockObjects(mDXGLDeviceHandle, 1, &hObject);
if (!ret) {
#ifdef DEBUG
uint32_t error = GetLastError();
printf_stderr("wglDXUnlockObjects(0x%x, 1, {0x%x}) failed: GetLastError():"
" 0x%x\n", mDXGLDeviceHandle, hObject, error);
#endif
MOZ_CRASH();
}
return ret;
}
};
////////////////////////////////////////////////////////////////////////////////
// Shared Surface
/*static*/ UniquePtr<SharedSurface_D3D11Interop>
SharedSurface_D3D11Interop::Create(const RefPtr<DXGLDevice>& dxgl,
GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha)
{
auto& d3d = *dxgl->mD3D;
// Create a texture in case we need to readback.
DXGI_FORMAT format = hasAlpha ? DXGI_FORMAT_B8G8R8A8_UNORM
: DXGI_FORMAT_B8G8R8X8_UNORM;
CD3D11_TEXTURE2D_DESC desc(format, size.width, size.height, 1, 1);
desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
RefPtr<ID3D11Texture2D> textureD3D;
HRESULT hr = d3d.CreateTexture2D(&desc, nullptr, getter_AddRefs(textureD3D));
if (FAILED(hr)) {
NS_WARNING("Failed to create texture for CanvasLayer!");
return nullptr;
}
RefPtr<IDXGIResource> textureDXGI;
hr = textureD3D->QueryInterface(__uuidof(IDXGIResource), getter_AddRefs(textureDXGI));
if (FAILED(hr)) {
NS_WARNING("Failed to open texture for sharing!");
return nullptr;
}
RefPtr<IDXGIKeyedMutex> keyedMutex;
hr = textureD3D->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(keyedMutex));
if (FAILED(hr)) {
NS_WARNING("Failed to obtained keyed mutex from texture!");
return nullptr;
}
HANDLE sharedHandle;
textureDXGI->GetSharedHandle(&sharedHandle);
GLuint renderbufferGL = 0;
gl->MakeCurrent();
gl->fGenRenderbuffers(1, &renderbufferGL);
HANDLE objectWGL = dxgl->RegisterObject(textureD3D, renderbufferGL,
LOCAL_GL_RENDERBUFFER,
LOCAL_WGL_ACCESS_WRITE_DISCARD_NV);
if (!objectWGL) {
NS_WARNING("Failed to register D3D object with WGL.");
return nullptr;
}
GLuint fence = 0;
if (gl->IsExtensionSupported(GLContext::NV_fence)) {
gl->MakeCurrent();
gl->fGenFences(1, &fence);
}
typedef SharedSurface_D3D11Interop ptrT;
UniquePtr<ptrT> ret ( new ptrT(gl, size, hasAlpha, renderbufferGL, dxgl, objectWGL,
textureD3D, sharedHandle, keyedMutex, fence) );
return Move(ret);
}
SharedSurface_D3D11Interop::SharedSurface_D3D11Interop(GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha,
GLuint renderbufferGL,
const RefPtr<DXGLDevice>& dxgl,
HANDLE objectWGL,
const RefPtr<ID3D11Texture2D>& textureD3D,
HANDLE sharedHandle,
const RefPtr<IDXGIKeyedMutex>& keyedMutex,
GLuint fence)
: SharedSurface(SharedSurfaceType::DXGLInterop2,
AttachmentType::GLRenderbuffer,
gl,
size,
hasAlpha,
true)
, mProdRB(renderbufferGL)
, mDXGL(dxgl)
, mObjectWGL(objectWGL)
, mTextureD3D(textureD3D)
, mSharedHandle(sharedHandle)
, mKeyedMutex(keyedMutex)
, mFence(fence)
, mLockedForGL(false)
{ }
SharedSurface_D3D11Interop::~SharedSurface_D3D11Interop()
{
MOZ_ASSERT(!mLockedForGL);
mGL->fDeleteRenderbuffers(1, &mProdRB);
if (!mDXGL->UnregisterObject(mObjectWGL)) {
NS_WARNING("Failed to release a DXGL object, possibly leaking it.");
}
if (mFence) {
mGL->MakeCurrent();
mGL->fDeleteFences(1, &mFence);
}
// mDXGL is closed when it runs out of refs.
}
void
SharedSurface_D3D11Interop::LockProdImpl()
{ }
void
SharedSurface_D3D11Interop::UnlockProdImpl()
{ }
void
SharedSurface_D3D11Interop::Fence()
{
// TODO fence properly. This kills performance.
mGL->fFinish();
}
bool
SharedSurface_D3D11Interop::WaitSync()
{
return true;
}
bool
SharedSurface_D3D11Interop::PollSync()
{
return true;
}
void
SharedSurface_D3D11Interop::ProducerAcquireImpl()
{
MOZ_ASSERT(!mLockedForGL);
if (mKeyedMutex) {
const uint64_t keyValue = 0;
const DWORD timeoutMs = 10000;
HRESULT hr = mKeyedMutex->AcquireSync(keyValue, timeoutMs);
if (hr == WAIT_TIMEOUT) {
// Doubt we should do this? Maybe Wait for ever?
MOZ_CRASH("d3d11Interop timeout");
}
}
// Now we have the mutex, we can lock for GL.
MOZ_ALWAYS_TRUE(mDXGL->LockObject(mObjectWGL));
mLockedForGL = true;
}
void
SharedSurface_D3D11Interop::ProducerReleaseImpl()
{
MOZ_ASSERT(mLockedForGL);
mGL->fFlush();
MOZ_ALWAYS_TRUE(mDXGL->UnlockObject(mObjectWGL));
mLockedForGL = false;
// Now we have unlocked for GL, we can release to consumer.
if (mKeyedMutex) {
mKeyedMutex->ReleaseSync(0);
}
Fence();
}
void
SharedSurface_D3D11Interop::ConsumerAcquireImpl()
{
if (!mConsumerTexture) {
RefPtr<ID3D11Texture2D> tex;
RefPtr<ID3D11Device> device = gfxWindowsPlatform::GetPlatform()->GetD3D11Device();
HRESULT hr = device->OpenSharedResource(mSharedHandle,
__uuidof(ID3D11Texture2D),
(void**)(ID3D11Texture2D**) getter_AddRefs(tex));
if (SUCCEEDED(hr)) {
mConsumerTexture = tex;
RefPtr<IDXGIKeyedMutex> mutex;
hr = tex->QueryInterface((IDXGIKeyedMutex**) getter_AddRefs(mutex));
if (SUCCEEDED(hr)) {
mConsumerKeyedMutex = mutex;
}
}
}
if (mConsumerKeyedMutex) {
const uint64_t keyValue = 0;
const DWORD timeoutMs = 10000;
HRESULT hr = mConsumerKeyedMutex->AcquireSync(keyValue, timeoutMs);
if (hr == WAIT_TIMEOUT) {
MOZ_CRASH();
}
}
}
void
SharedSurface_D3D11Interop::ConsumerReleaseImpl()
{
if (mConsumerKeyedMutex) {
mConsumerKeyedMutex->ReleaseSync(0);
}
}
void
SharedSurface_D3D11Interop::Fence_ContentThread_Impl()
{
if (mFence) {
MOZ_ASSERT(mGL->IsExtensionSupported(GLContext::NV_fence));
mGL->fSetFence(mFence, LOCAL_GL_ALL_COMPLETED_NV);
mGL->fFlush();
return;
}
Fence();
}
bool
SharedSurface_D3D11Interop::WaitSync_ContentThread_Impl()
{
if (mFence) {
mGL->MakeCurrent();
mGL->fFinishFence(mFence);
return true;
}
return WaitSync();
}
bool
SharedSurface_D3D11Interop::PollSync_ContentThread_Impl()
{
if (mFence) {
mGL->MakeCurrent();
return mGL->fTestFence(mFence);
}
return PollSync();
}
bool
SharedSurface_D3D11Interop::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
{
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::B8G8R8A8
: gfx::SurfaceFormat::B8G8R8X8;
*out_descriptor = layers::SurfaceDescriptorD3D10((WindowsHandle)GetSharedHandle(),
format, mSize);
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
// Factory
/*static*/ UniquePtr<SurfaceFactory_D3D11Interop>
SurfaceFactory_D3D11Interop::Create(GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags)
{
WGLLibrary* wgl = &sWGLLib;
if (!wgl || !wgl->HasDXInterop2())
return nullptr;
RefPtr<DXGLDevice> dxgl = DXGLDevice::Open(wgl);
if (!dxgl) {
NS_WARNING("Failed to open D3D device for use by WGL.");
return nullptr;
}
typedef SurfaceFactory_D3D11Interop ptrT;
UniquePtr<ptrT> ret(new ptrT(gl, caps, allocator, flags, dxgl));
return Move(ret);
}
SurfaceFactory_D3D11Interop::SurfaceFactory_D3D11Interop(GLContext* gl,
const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags,
const RefPtr<DXGLDevice>& dxgl)
: SurfaceFactory(SharedSurfaceType::DXGLInterop2, gl, caps, allocator, flags)
, mDXGL(dxgl)
{ }
SurfaceFactory_D3D11Interop::~SurfaceFactory_D3D11Interop()
{ }
} // namespace gl
} // namespace mozilla
+123
View File
@@ -0,0 +1,123 @@
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */
/* 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 SHARED_SURFACE_D3D11_INTEROP_H_
#define SHARED_SURFACE_D3D11_INTEROP_H_
#include <windows.h>
#include "SharedSurface.h"
struct ID3D11Device;
struct ID3D11ShaderResourceView;
namespace mozilla {
namespace gl {
class DXGLDevice;
class GLContext;
class WGLLibrary;
class SharedSurface_D3D11Interop
: public SharedSurface
{
const GLuint mProdRB;
const RefPtr<DXGLDevice> mDXGL;
const HANDLE mObjectWGL;
const HANDLE mSharedHandle;
const RefPtr<ID3D11Texture2D> mTextureD3D;
RefPtr<IDXGIKeyedMutex> mKeyedMutex;
RefPtr<IDXGIKeyedMutex> mConsumerKeyedMutex;
RefPtr<ID3D11Texture2D> mConsumerTexture;
const GLuint mFence;
protected:
bool mLockedForGL;
public:
static UniquePtr<SharedSurface_D3D11Interop> Create(const RefPtr<DXGLDevice>& dxgl,
GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha);
static SharedSurface_D3D11Interop* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::DXGLInterop2);
return (SharedSurface_D3D11Interop*)surf;
}
protected:
SharedSurface_D3D11Interop(GLContext* gl,
const gfx::IntSize& size,
bool hasAlpha,
GLuint renderbufferGL,
const RefPtr<DXGLDevice>& dxgl,
HANDLE objectWGL,
const RefPtr<ID3D11Texture2D>& textureD3D,
HANDLE sharedHandle,
const RefPtr<IDXGIKeyedMutex>& keyedMutex,
GLuint fence);
public:
virtual ~SharedSurface_D3D11Interop();
virtual void LockProdImpl() override;
virtual void UnlockProdImpl() override;
virtual void Fence() override;
virtual void ProducerAcquireImpl() override;
virtual void ProducerReleaseImpl() override;
virtual void ConsumerAcquireImpl() override;
virtual void ConsumerReleaseImpl() override;
virtual bool WaitSync() override;
virtual bool PollSync() override;
virtual void Fence_ContentThread_Impl() override;
virtual bool WaitSync_ContentThread_Impl() override;
virtual bool PollSync_ContentThread_Impl() override;
virtual GLuint ProdRenderbuffer() override {
return mProdRB;
}
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
// Implementation-specific functions below:
HANDLE GetSharedHandle() const {
return mSharedHandle;
}
};
class SurfaceFactory_D3D11Interop
: public SurfaceFactory
{
public:
const RefPtr<DXGLDevice> mDXGL;
static UniquePtr<SurfaceFactory_D3D11Interop> Create(GLContext* gl,
const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags);
protected:
SurfaceFactory_D3D11Interop(GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags,
const RefPtr<DXGLDevice>& dxgl);
public:
virtual ~SurfaceFactory_D3D11Interop();
protected:
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_D3D11Interop::Create(mDXGL, mGL, size, hasAlpha);
}
};
} /* namespace gl */
} /* namespace mozilla */
#endif /* SHARED_SURFACE_D3D11_INTEROP_H_ */
+83
View File
@@ -95,6 +95,7 @@ SharedSurface_Basic::~SharedSurface_Basic()
mGL->fDeleteTextures(1, &mTex);
}
////////////////////////////////////////////////////////////////////////
SurfaceFactory_Basic::SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& caps,
@@ -102,6 +103,88 @@ SurfaceFactory_Basic::SurfaceFactory_Basic(GLContext* gl, const SurfaceCaps& cap
: SurfaceFactory(SharedSurfaceType::Basic, gl, caps, nullptr, flags)
{ }
////////////////////////////////////////////////////////////////////////
// SharedSurface_GLTexture
/*static*/ UniquePtr<SharedSurface_GLTexture>
SharedSurface_GLTexture::Create(GLContext* prodGL,
const GLFormats& formats,
const IntSize& size,
bool hasAlpha)
{
MOZ_ASSERT(prodGL);
prodGL->MakeCurrent();
UniquePtr<SharedSurface_GLTexture> ret;
GLContext::LocalErrorScope localError(*prodGL);
GLuint tex = CreateTextureForOffscreen(prodGL, formats, size);
GLenum err = localError.GetError();
MOZ_ASSERT_IF(err, err == LOCAL_GL_OUT_OF_MEMORY);
if (err) {
prodGL->fDeleteTextures(1, &tex);
return Move(ret);
}
ret.reset(new SharedSurface_GLTexture(prodGL, size,
hasAlpha, tex));
return Move(ret);
}
SharedSurface_GLTexture::~SharedSurface_GLTexture()
{
if (!mGL->MakeCurrent())
return;
if (mTex) {
mGL->fDeleteTextures(1, &mTex);
}
if (mSync) {
mGL->fDeleteSync(mSync);
}
}
void
SharedSurface_GLTexture::ProducerReleaseImpl()
{
mGL->MakeCurrent();
if (mGL->IsExtensionSupported(GLContext::ARB_sync)) {
if (mSync) {
mGL->fDeleteSync(mSync);
mSync = 0;
}
mSync = mGL->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
if (mSync) {
mGL->fFlush();
return;
}
}
MOZ_ASSERT(!mSync);
mGL->fFinish();
}
bool
SharedSurface_GLTexture::ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor)
{
*out_descriptor = layers::SurfaceDescriptorSharedGLTexture(ProdTexture(),
ProdTextureTarget(),
(uintptr_t)mSync,
mSize,
mHasAlpha);
// Transfer ownership of the fence to the host
mSync = nullptr;
return true;
}
} // namespace gl
} /* namespace mozilla */
+72
View File
@@ -93,6 +93,78 @@ public:
}
};
// Using shared GL textures:
class SharedSurface_GLTexture
: public SharedSurface
{
public:
static UniquePtr<SharedSurface_GLTexture> Create(GLContext* prodGL,
const GLFormats& formats,
const gfx::IntSize& size,
bool hasAlpha);
static SharedSurface_GLTexture* Cast(SharedSurface* surf) {
MOZ_ASSERT(surf->mType == SharedSurfaceType::SharedGLTexture);
return (SharedSurface_GLTexture*)surf;
}
protected:
const GLuint mTex;
GLsync mSync;
SharedSurface_GLTexture(GLContext* prodGL,
const gfx::IntSize& size,
bool hasAlpha,
GLuint tex)
: SharedSurface(SharedSurfaceType::SharedGLTexture,
AttachmentType::GLTexture,
prodGL,
size,
hasAlpha, true)
, mTex(tex)
, mSync(0)
{
}
public:
virtual ~SharedSurface_GLTexture();
virtual void LockProdImpl() override {}
virtual void UnlockProdImpl() override {}
virtual void ProducerReleaseImpl() override;
virtual void Fence() override {}
virtual bool WaitSync() override { MOZ_CRASH("should not be called"); }
virtual bool PollSync() override { MOZ_CRASH("should not be called"); }
virtual GLuint ProdTexture() override {
return mTex;
}
virtual bool ToSurfaceDescriptor(layers::SurfaceDescriptor* const out_descriptor) override;
};
class SurfaceFactory_GLTexture
: public SurfaceFactory
{
public:
SurfaceFactory_GLTexture(GLContext* prodGL,
const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
const layers::TextureFlags& flags)
: SurfaceFactory(SharedSurfaceType::SharedGLTexture, prodGL, caps, allocator, flags)
{
}
virtual UniquePtr<SharedSurface> CreateShared(const gfx::IntSize& size) override {
bool hasAlpha = mReadCaps.alpha;
return SharedSurface_GLTexture::Create(mGL, mFormats, size, hasAlpha);
}
};
} // namespace gl
} /* namespace mozilla */
+15 -6
View File
@@ -55,6 +55,16 @@ SharedSurface_IOSurface::CopyTexImage2D(GLenum target, GLint level, GLenum inter
if (width == 0 || height == 0)
return false;
switch (internalformat) {
case LOCAL_GL_ALPHA:
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_LUMINANCE_ALPHA:
break;
default:
return false;
}
MOZ_ASSERT(mGL->IsCurrent());
ScopedTexture destTex(mGL);
@@ -90,23 +100,22 @@ SharedSurface_IOSurface::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei hei
// from that.
MOZ_ASSERT(mGL->IsCurrent());
ScopedTexture destTex(mGL);
{
ScopedFramebufferForTexture srcFB(mGL, ProdTexture(), ProdTextureTarget());
ScopedBindFramebuffer bindFB(mGL, srcFB.FB());
ScopedBindTexture bindTex(mGL, destTex.Texture());
mGL->fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
mHasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB,
x, y,
width, height, 0);
mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0,
mHasAlpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB,
x, y,
width, height, 0);
}
ScopedFramebufferForTexture destFB(mGL, destTex.Texture());
ScopedBindFramebuffer bindFB(mGL, destFB.FB());
mGL->fReadPixels(0, 0, width, height, format, type, pixels);
mGL->raw_fReadPixels(0, 0, width, height, format, type, pixels);
return true;
}
+1
View File
@@ -77,6 +77,7 @@ enum class SharedSurfaceType : uint8_t {
Gralloc,
IOSurface,
GLXDrawable,
SharedGLTexture,
Max
};
+48 -10
View File
@@ -14,14 +14,16 @@ namespace gl {
class WGLLibrary
{
public:
WGLLibrary()
: mInitialized(false),
mOGLLibrary(nullptr),
mHasRobustness(false),
mWindow (0),
mWindowDC(0),
mWindowGLContext(0),
mWindowPixelFormat (0)
WGLLibrary()
: mInitialized(false)
, mOGLLibrary(nullptr)
, mHasRobustness(false)
, mHasDXInterop(false)
, mHasDXInterop2(false)
, mWindow (0)
, mWindowDC(0)
, mWindowGLContext(0)
, mWindowPixelFormat(0)
{}
typedef HGLRC (GLAPIENTRY * PFNWGLCREATECONTEXTPROC) (HDC);
@@ -62,10 +64,45 @@ public:
typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSPROC) (HDC hdc, HGLRC hShareContext, const int *attribList);
PFNWGLCREATECONTEXTATTRIBSPROC fCreateContextAttribs;
// WGL_NV_DX_interop:
// BOOL wglDXSetResourceShareHandleNV(void *dxObject, HANDLE shareHandle);
typedef BOOL (WINAPI * PFNWGLDXSETRESOURCESHAREHANDLEPROC) (void* dxObject, HANDLE shareHandle);
PFNWGLDXSETRESOURCESHAREHANDLEPROC fDXSetResourceShareHandle;
// HANDLE wglDXOpenDeviceNV(void *dxDevice);
typedef HANDLE (WINAPI * PFNWGLDXOPENDEVICEPROC) (void* dxDevice);
PFNWGLDXOPENDEVICEPROC fDXOpenDevice;
// BOOL wglDXCloseDeviceNV(HANDLE hDevice);
typedef BOOL (WINAPI * PFNWGLDXCLOSEDEVICEPROC) (HANDLE hDevice);
PFNWGLDXCLOSEDEVICEPROC fDXCloseDevice;
// HANDLE wglDXRegisterObjectNV(HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);
typedef HANDLE (WINAPI * PFNWGLDXREGISTEROBJECTPROC) (HANDLE hDevice, void* dxObject, GLuint name, GLenum type, GLenum access);
PFNWGLDXREGISTEROBJECTPROC fDXRegisterObject;
// BOOL wglDXUnregisterObjectNV(HANDLE hDevice, HANDLE hObject);
typedef BOOL (WINAPI * PFNWGLDXUNREGISTEROBJECT) (HANDLE hDevice, HANDLE hObject);
PFNWGLDXUNREGISTEROBJECT fDXUnregisterObject;
// BOOL wglDXObjectAccessNV(HANDLE hObject, GLenum access);
typedef BOOL (WINAPI * PFNWGLDXOBJECTACCESSPROC) (HANDLE hObject, GLenum access);
PFNWGLDXOBJECTACCESSPROC fDXObjectAccess;
// BOOL wglDXLockObjectsNV(HANDLE hDevice, GLint count, HANDLE *hObjects);
typedef BOOL (WINAPI * PFNWGLDXLOCKOBJECTSPROC) (HANDLE hDevice, GLint count, HANDLE* hObjects);
PFNWGLDXLOCKOBJECTSPROC fDXLockObjects;
// BOOL wglDXUnlockObjectsNV(HANDLE hDevice, GLint count, HANDLE *hObjects);
typedef BOOL (WINAPI * PFNWGLDXUNLOCKOBJECTSPROC) (HANDLE hDevice, GLint count, HANDLE* hObjects);
PFNWGLDXUNLOCKOBJECTSPROC fDXUnlockObjects;
bool EnsureInitialized();
HWND CreateDummyWindow(HDC *aWindowDC = nullptr);
bool HasRobustness() const { return mHasRobustness; }
bool HasDXInterop() const { return mHasDXInterop; }
bool HasDXInterop2() const { return mHasDXInterop2; }
bool IsInitialized() const { return mInitialized; }
HWND GetWindow() const { return mWindow; }
HDC GetWindowDC() const {return mWindowDC; }
@@ -77,6 +114,8 @@ private:
bool mInitialized;
PRLibrary *mOGLLibrary;
bool mHasRobustness;
bool mHasDXInterop;
bool mHasDXInterop2;
HWND mWindow;
HDC mWindowDC;
@@ -86,8 +125,7 @@ private:
};
// a global WGLLibrary instance
extern WGLLibrary sWGLLibrary;
extern WGLLibrary sWGLLib;
} /* namespace gl */
} /* namespace mozilla */
+2
View File
@@ -68,11 +68,13 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
EXPORTS += [
'GLContextWGL.h',
'SharedSurfaceANGLE.h', # Needs <windows.h> for `HANDLE`.
'SharedSurfaceD3D11Interop.h',
'WGLLibrary.h',
]
UNIFIED_SOURCES += [
'GLContextProviderWGL.cpp',
'SharedSurfaceANGLE.cpp',
'SharedSurfaceD3D11Interop.cpp',
]
if CONFIG['MOZ_ENABLE_SKIA_GPU']:
EXPORTS += ['SkiaGLGlue.h']
+36 -47
View File
@@ -891,51 +891,6 @@ struct ParamTraits<mozilla::layers::EventRegions>
}
};
struct MessageAndAttributeMap
{
Message* msg;
const mozilla::gfx::AttributeMap& map;
};
static bool
WriteAttribute(mozilla::gfx::AttributeName aName,
mozilla::gfx::AttributeType aType,
void* aUserData)
{
MessageAndAttributeMap* msgAndMap =
static_cast<MessageAndAttributeMap*>(aUserData);
WriteParam(msgAndMap->msg, aType);
WriteParam(msgAndMap->msg, aName);
switch (aType) {
#define HANDLE_TYPE(typeName) \
case mozilla::gfx::AttributeType::e##typeName: \
WriteParam(msgAndMap->msg, msgAndMap->map.Get##typeName(aName)); \
break;
HANDLE_TYPE(Bool)
HANDLE_TYPE(Uint)
HANDLE_TYPE(Float)
HANDLE_TYPE(Size)
HANDLE_TYPE(IntSize)
HANDLE_TYPE(IntPoint)
HANDLE_TYPE(Matrix)
HANDLE_TYPE(Matrix5x4)
HANDLE_TYPE(Point3D)
HANDLE_TYPE(Color)
HANDLE_TYPE(AttributeMap)
HANDLE_TYPE(Floats)
#undef HANDLE_TYPE
default:
MOZ_CRASH("unhandled attribute type");
}
return true;
}
template <>
struct ParamTraits<mozilla::gfx::AttributeMap>
{
@@ -944,8 +899,41 @@ struct ParamTraits<mozilla::gfx::AttributeMap>
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.Count());
MessageAndAttributeMap msgAndMap = { aMsg, aParam };
aParam.EnumerateRead(WriteAttribute, &msgAndMap);
for (auto iter = aParam.ConstIter(); !iter.Done(); iter.Next()) {
mozilla::gfx::AttributeName name =
mozilla::gfx::AttributeName(iter.Key());
mozilla::gfx::AttributeType type =
mozilla::gfx::AttributeMap::GetType(iter.UserData());
WriteParam(aMsg, type);
WriteParam(aMsg, name);
switch (type) {
#define CASE_TYPE(typeName) \
case mozilla::gfx::AttributeType::e##typeName: \
WriteParam(aMsg, aParam.Get##typeName(name)); \
break;
CASE_TYPE(Bool)
CASE_TYPE(Uint)
CASE_TYPE(Float)
CASE_TYPE(Size)
CASE_TYPE(IntSize)
CASE_TYPE(IntPoint)
CASE_TYPE(Matrix)
CASE_TYPE(Matrix5x4)
CASE_TYPE(Point3D)
CASE_TYPE(Color)
CASE_TYPE(AttributeMap)
CASE_TYPE(Floats)
#undef CASE_TYPE
default:
MOZ_CRASH("unhandled attribute type");
}
}
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
@@ -973,6 +961,7 @@ struct ParamTraits<mozilla::gfx::AttributeMap>
return false; \
} \
aResult->Set(name, value); \
break; \
}
HANDLE_TYPE(bool, Bool)
@@ -74,15 +74,6 @@ public:
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId) = 0;
/**
* Requests sending a mozbrowserasyncscroll domevent to embedder.
* |aContentRect| is in CSS pixels, relative to the current cssPage.
* |aScrollableSize| is the current content width/height in CSS pixels.
*/
virtual void SendAsyncScrollDOMEvent(bool aIsRootContent,
const CSSRect &aContentRect,
const CSSSize &aScrollableSize) = 0;
/**
* Schedules a runnable to run on the controller/UI thread at some time
* in the future.
@@ -104,14 +104,6 @@ using mozilla::gfx::PointTyped;
* \li\b apz.allow_checkerboarding
* Pref that allows or disallows checkerboarding
*
* \li\b apz.asyncscroll.throttle
* The time period that throttles mozbrowserasyncscroll event.\n
* Units: milliseconds
*
* \li\b apz.asyncscroll.timeout
* The timeout for mAsyncScrollTimeoutTask delay task.\n
* Units: milliseconds
*
* \li\b apz.axis_lock.mode
* The preferred axis locking style. See AxisLockMode for possible values.
*
@@ -824,10 +816,6 @@ AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId,
mPanDirRestricted(false),
mZoomConstraints(false, false, MIN_ZOOM, MAX_ZOOM),
mLastSampleTime(GetFrameTime()),
mLastAsyncScrollTime(GetFrameTime()),
mLastAsyncScrollOffset(0, 0),
mCurrentAsyncScrollOffset(0, 0),
mAsyncScrollTimeoutTask(nullptr),
mState(NOTHING),
mNotificationBlockers(0),
mInputQueue(aInputQueue),
@@ -1285,7 +1273,6 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
// events.
if (mState != NOTHING) {
ReentrantMonitorAutoEnter lock(mMonitor);
SendAsyncScrollEvent();
}
switch (mState) {
@@ -2711,7 +2698,6 @@ void AsyncPanZoomController::RequestContentRepaint(FrameMetrics& aFrameMetrics,
return;
}
SendAsyncScrollEvent();
if (aThrottled) {
mPaintThrottler->PostTask(
FROM_HERE,
@@ -2755,16 +2741,6 @@ AsyncPanZoomController::DispatchRepaintRequest(const FrameMetrics& aFrameMetrics
}
}
void
AsyncPanZoomController::FireAsyncScrollOnTimeout()
{
if (mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
ReentrantMonitorAutoEnter lock(mMonitor);
SendAsyncScrollEvent();
}
mAsyncScrollTimeoutTask = nullptr;
}
bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
Vector<Task*>* aOutDeferredTasks)
{
@@ -2791,7 +2767,6 @@ bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
} else {
mAnimation = nullptr;
SetState(NOTHING);
SendAsyncScrollEvent();
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
@@ -2870,8 +2845,6 @@ bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
LogRendertraceRect(GetGuid(), "viewport", "red",
CSSRect(mFrameMetrics.GetScrollOffset(),
mFrameMetrics.CalculateCompositedSizeInCssPixels()));
mCurrentAsyncScrollOffset = mFrameMetrics.GetScrollOffset();
}
// Execute any deferred tasks queued up by mAnimation's Sample() (called by
@@ -2887,32 +2860,6 @@ bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
// we want to ask the compositor to schedule a new composite.
requestAnimationFrame |= (mAnimation != nullptr);
// Cancel the mAsyncScrollTimeoutTask because we will fire a
// mozbrowserasyncscroll event or renew the mAsyncScrollTimeoutTask again.
if (mAsyncScrollTimeoutTask) {
mAsyncScrollTimeoutTask->Cancel();
mAsyncScrollTimeoutTask = nullptr;
}
// Fire the mozbrowserasyncscroll event immediately if it's been
// sAsyncScrollThrottleTime ms since the last time we fired the event and the
// current scroll offset is different than the mLastAsyncScrollOffset we sent
// with the last event.
// Otherwise, start a timer to fire the event sAsyncScrollTimeout ms from now.
TimeDuration delta = aSampleTime - mLastAsyncScrollTime;
if (delta.ToMilliseconds() > gfxPrefs::APZAsyncScrollThrottleTime() &&
mCurrentAsyncScrollOffset != mLastAsyncScrollOffset) {
ReentrantMonitorAutoEnter lock(mMonitor);
mLastAsyncScrollTime = aSampleTime;
mLastAsyncScrollOffset = mCurrentAsyncScrollOffset;
SendAsyncScrollEvent();
} else {
mAsyncScrollTimeoutTask =
NewRunnableMethod(this, &AsyncPanZoomController::FireAsyncScrollOnTimeout);
MessageLoop::current()->PostDelayedTask(FROM_HERE,
mAsyncScrollTimeoutTask,
gfxPrefs::APZAsyncScrollTimeout());
}
return requestAnimationFrame;
}
@@ -3408,27 +3355,6 @@ void AsyncPanZoomController::PostDelayedTask(Task* aTask, int aDelayMs) {
}
}
void AsyncPanZoomController::SendAsyncScrollEvent() {
RefPtr<GeckoContentController> controller = GetGeckoContentController();
if (!controller) {
return;
}
bool isRootContent;
CSSRect contentRect;
CSSSize scrollableSize;
{
ReentrantMonitorAutoEnter lock(mMonitor);
isRootContent = mFrameMetrics.IsRootContent();
scrollableSize = mFrameMetrics.GetScrollableRect().Size();
contentRect = mFrameMetrics.CalculateCompositedRectInCssPixels();
contentRect.MoveTo(mCurrentAsyncScrollOffset);
}
controller->SendAsyncScrollDOMEvent(isRootContent, contentRect, scrollableSize);
}
bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid)
{
return aGuid == GetGuid();
@@ -261,12 +261,6 @@ public:
const ParentLayerPoint& aVelocity,
double aEstimatedPaintDuration);
/**
* Send an mozbrowserasyncscroll event.
* *** The monitor must be held while calling this.
*/
void SendAsyncScrollEvent();
nsEventStatus HandleDragEvent(const MouseInput& aEvent,
const AsyncDragMetrics& aDragMetrics);
@@ -617,14 +611,6 @@ protected:
*/
const RefPtr<InputQueue>& GetInputQueue() const;
/**
* Timeout function for mozbrowserasyncscroll event. Because we throttle
* mozbrowserasyncscroll events in some conditions, this function ensures
* that the last mozbrowserasyncscroll event will be fired after a period of
* time.
*/
void FireAsyncScrollOnTimeout();
/**
* Convert ScreenPoint relative to the screen to CSSPoint relative
* to the parent document. This excludes the transient compositor transform.
@@ -731,19 +717,6 @@ private:
// to allow panning by moving multiple fingers (thus moving the focus point).
ParentLayerPoint mLastZoomFocus;
// The last time and offset we fire the mozbrowserasyncscroll event when
// compositor has sampled the content transform for this frame.
TimeStamp mLastAsyncScrollTime;
CSSPoint mLastAsyncScrollOffset;
// The current offset drawn on the screen, it may not be sent since we have
// throttling policy for mozbrowserasyncscroll event.
CSSPoint mCurrentAsyncScrollOffset;
// The delay task triggered by the throttling mozbrowserasyncscroll event
// ensures the last mozbrowserasyncscroll event is always been fired.
CancelableTask* mAsyncScrollTimeoutTask;
RefPtr<AsyncPanZoomAnimation> mAnimation;
friend class Axis;
@@ -67,7 +67,6 @@ public:
MOCK_METHOD3(HandleDoubleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
MOCK_METHOD3(HandleSingleTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&));
MOCK_METHOD4(HandleLongTap, void(const CSSPoint&, Modifiers, const ScrollableLayerGuid&, uint64_t));
MOCK_METHOD3(SendAsyncScrollDOMEvent, void(bool aIsRoot, const CSSRect &aContentRect, const CSSSize &aScrollableSize));
MOCK_METHOD2(PostDelayedTask, void(Task* aTask, int aDelayMs));
MOCK_METHOD3(NotifyAPZStateChange, void(const ScrollableLayerGuid& aGuid, APZStateChange aChange, int aArg));
MOCK_METHOD0(NotifyFlushComplete, void());
@@ -791,10 +790,8 @@ protected:
MakeApzcZoomable();
if (aShouldTriggerPinch) {
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
} else {
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtMost(2));
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
}
@@ -927,7 +924,6 @@ TEST_F(APZCBasicTester, Overzoom) {
MakeApzcZoomable();
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
PinchWithPinchInputAndCheckStatus(apzc, 50, 50, 0.5, true);
@@ -1056,10 +1052,8 @@ protected:
void DoPanTest(bool aShouldTriggerScroll, bool aShouldBeConsumed, uint32_t aBehavior)
{
if (aShouldTriggerScroll) {
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
} else {
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
}
@@ -1169,7 +1163,6 @@ TEST_F(APZCPanningTester, PanWithPreventDefault) {
}
TEST_F(APZCBasicTester, Fling) {
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(AtLeast(1));
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
int touchStart = 50;
@@ -1591,7 +1584,6 @@ protected:
void DoLongPressPreventDefaultTest(uint32_t aBehavior) {
MakeApzcUnzoomable();
EXPECT_CALL(*mcc, SendAsyncScrollDOMEvent(_,_,_)).Times(0);
EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(0);
int touchX = 10,
@@ -49,8 +49,6 @@ public:
virtual void HandleLongTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId) override;
virtual void SendAsyncScrollDOMEvent(bool aIsRootContent, const mozilla::CSSRect &aContentRect,
const mozilla::CSSSize &aScrollableSize) override {}
virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
APZStateChange aChange,
int aArg) override;
+1
View File
@@ -210,6 +210,7 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
case SurfaceDescriptor::TEGLImageDescriptor:
case SurfaceDescriptor::TSurfaceTextureDescriptor:
case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
return CreateTextureHostOGL(aDesc, aDeallocator, aFlags);
case SurfaceDescriptor::TNewSurfaceDescriptorGralloc:
+9
View File
@@ -82,6 +82,14 @@ struct EGLImageDescriptor {
bool hasAlpha;
};
struct SurfaceDescriptorSharedGLTexture {
uint32_t texture;
uint32_t target;
uintptr_t fence;
IntSize size;
bool hasAlpha;
};
struct NewSurfaceDescriptorGralloc {
MaybeMagicGrallocBufferHandle buffer;
bool isOpaque;
@@ -116,6 +124,7 @@ union SurfaceDescriptor {
EGLImageDescriptor;
SurfaceDescriptorMacIOSurface;
NewSurfaceDescriptorGralloc;
SurfaceDescriptorSharedGLTexture;
null_t;
};
+81
View File
@@ -104,6 +104,16 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
break;
}
#endif
case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: {
const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture();
result = new GLTextureHost(aFlags, desc.texture(),
desc.target(),
(GLsync)desc.fence(),
desc.size(),
desc.hasAlpha());
break;
}
default: return nullptr;
}
return result.forget();
@@ -645,5 +655,76 @@ EGLImageTextureHost::GetFormat() const
return mTextureSource->GetFormat();
}
//
GLTextureHost::GLTextureHost(TextureFlags aFlags,
GLuint aTextureHandle,
GLenum aTarget,
GLsync aSync,
gfx::IntSize aSize,
bool aHasAlpha)
: TextureHost(aFlags)
, mTexture(aTextureHandle)
, mTarget(aTarget)
, mSync(aSync)
, mSize(aSize)
, mHasAlpha(aHasAlpha)
, mCompositor(nullptr)
{}
GLTextureHost::~GLTextureHost()
{}
gl::GLContext*
GLTextureHost::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
bool
GLTextureHost::Lock()
{
if (!mCompositor) {
return false;
}
if (mSync) {
gl()->MakeCurrent();
gl()->fWaitSync(mSync, 0, LOCAL_GL_TIMEOUT_IGNORED);
gl()->fDeleteSync(mSync);
mSync = 0;
}
if (!mTextureSource) {
gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8
: gfx::SurfaceFormat::R8G8B8X8;
mTextureSource = new GLTextureSource(mCompositor,
mTexture,
mTarget,
mSize,
format,
false /* owned by the client */);
}
return true;
}
void
GLTextureHost::SetCompositor(Compositor* aCompositor)
{
MOZ_ASSERT(aCompositor);
CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
mCompositor = glCompositor;
if (mTextureSource) {
mTextureSource->SetCompositor(glCompositor);
}
}
gfx::SurfaceFormat
GLTextureHost::GetFormat() const
{
MOZ_ASSERT(mTextureSource);
return mTextureSource->GetFormat();
}
} // namespace layers
} // namespace mozilla
+50
View File
@@ -278,6 +278,56 @@ protected:
bool mExternallyOwned;
};
class GLTextureHost : public TextureHost
{
public:
GLTextureHost(TextureFlags aFlags,
GLuint aTextureHandle,
GLenum aTarget,
GLsync aSync,
gfx::IntSize aSize,
bool aHasAlpha);
virtual ~GLTextureHost();
// We don't own anything.
virtual void DeallocateDeviceData() override {}
virtual void SetCompositor(Compositor* aCompositor) override;
virtual bool Lock() override;
virtual void Unlock() override {}
virtual gfx::SurfaceFormat GetFormat() const override;
virtual bool BindTextureSource(CompositableTextureSourceRef& aTexture) override
{
aTexture = mTextureSource;
return !!aTexture;
}
virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override
{
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
gl::GLContext* gl() const;
virtual gfx::IntSize GetSize() const override { return mSize; }
virtual const char* Name() override { return "GLTextureHost"; }
protected:
const GLuint mTexture;
const GLenum mTarget;
GLsync mSync;
const gfx::IntSize mSize;
const bool mHasAlpha;
RefPtr<CompositorOGL> mCompositor;
RefPtr<GLTextureSource> mTextureSource;
};
////////////////////////////////////////////////////////////////////////
// SurfaceTexture
+31 -66
View File
@@ -2047,20 +2047,13 @@ AttributeMap::~AttributeMap()
{
}
static PLDHashOperator
CopyAttribute(const uint32_t& aAttributeName,
Attribute* aAttribute,
void* aAttributes)
{
typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
Map* map = static_cast<Map*>(aAttributes);
map->Put(aAttributeName, new Attribute(*aAttribute));
return PL_DHASH_NEXT;
}
AttributeMap::AttributeMap(const AttributeMap& aOther)
{
aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
const uint32_t& attributeName = iter.Key();
Attribute* attribute = iter.UserData();
mMap.Put(attributeName, new Attribute(*attribute));
}
}
AttributeMap&
@@ -2068,34 +2061,15 @@ AttributeMap::operator=(const AttributeMap& aOther)
{
if (this != &aOther) {
mMap.Clear();
aOther.mMap.EnumerateRead(CopyAttribute, &mMap);
for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
const uint32_t& attributeName = iter.Key();
Attribute* attribute = iter.UserData();
mMap.Put(attributeName, new Attribute(*attribute));
}
}
return *this;
}
namespace {
struct MatchingMap {
typedef nsClassHashtable<nsUint32HashKey, Attribute> Map;
const Map& map;
bool matches;
};
} // namespace
static PLDHashOperator
CheckAttributeEquality(const uint32_t& aAttributeName,
Attribute* aAttribute,
void* aMatchingMap)
{
MatchingMap& matchingMap = *static_cast<MatchingMap*>(aMatchingMap);
Attribute* matchingAttribute = matchingMap.map.Get(aAttributeName);
if (!matchingAttribute ||
*matchingAttribute != *aAttribute) {
matchingMap.matches = false;
return PL_DHASH_STOP;
}
return PL_DHASH_NEXT;
}
bool
AttributeMap::operator==(const AttributeMap& aOther) const
{
@@ -2103,37 +2077,16 @@ AttributeMap::operator==(const AttributeMap& aOther) const
return false;
}
MatchingMap matchingMap = { mMap, true };
aOther.mMap.EnumerateRead(CheckAttributeEquality, &matchingMap);
return matchingMap.matches;
}
for (auto iter = aOther.mMap.Iter(); !iter.Done(); iter.Next()) {
const uint32_t& attributeName = iter.Key();
Attribute* attribute = iter.UserData();
Attribute* matchingAttribute = mMap.Get(attributeName);
if (!matchingAttribute || *matchingAttribute != *attribute) {
return false;
}
}
namespace {
struct HandlerWithUserData
{
AttributeMap::AttributeHandleCallback handler;
void* userData;
};
} // namespace
static PLDHashOperator
PassAttributeToHandleCallback(const uint32_t& aAttributeName,
Attribute* aAttribute,
void* aHandlerWithUserData)
{
HandlerWithUserData* handlerWithUserData =
static_cast<HandlerWithUserData*>(aHandlerWithUserData);
return handlerWithUserData->handler(AttributeName(aAttributeName),
aAttribute->Type(),
handlerWithUserData->userData) ?
PL_DHASH_NEXT : PL_DHASH_STOP;
}
void
AttributeMap::EnumerateRead(AttributeMap::AttributeHandleCallback aCallback, void* aUserData) const
{
HandlerWithUserData handlerWithUserData = { aCallback, aUserData };
mMap.EnumerateRead(PassAttributeToHandleCallback, &handlerWithUserData);
return true;
}
uint32_t
@@ -2142,6 +2095,18 @@ AttributeMap::Count() const
return mMap.Count();
}
nsClassHashtable<nsUint32HashKey, FilterAttribute>::Iterator
AttributeMap::ConstIter() const
{
return mMap.ConstIter();
}
/* static */ AttributeType
AttributeMap::GetType(FilterAttribute* aAttribute)
{
return aAttribute->Type();
}
#define MAKE_ATTRIBUTE_HANDLERS_BASIC(type, typeLabel, defaultValue) \
type \
AttributeMap::Get##typeLabel(AttributeName aName) const { \
+4 -2
View File
@@ -221,10 +221,12 @@ public:
AttributeMap GetAttributeMap(AttributeName aName) const;
const nsTArray<float>& GetFloats(AttributeName aName) const;
typedef bool (*AttributeHandleCallback)(AttributeName aName, AttributeType aType, void* aUserData);
void EnumerateRead(AttributeHandleCallback aCallback, void* aUserData) const;
uint32_t Count() const;
nsClassHashtable<nsUint32HashKey, FilterAttribute>::Iterator ConstIter() const;
static AttributeType GetType(FilterAttribute* aAttribute);
private:
mutable nsClassHashtable<nsUint32HashKey, FilterAttribute> mMap;
};
+1 -2
View File
@@ -139,8 +139,6 @@ private:
// The apz prefs are explained in AsyncPanZoomController.cpp
DECL_GFX_PREF(Live, "apz.allow_checkerboarding", APZAllowCheckerboarding, bool, true);
DECL_GFX_PREF(Live, "apz.allow_zooming", APZAllowZooming, bool, false);
DECL_GFX_PREF(Live, "apz.asyncscroll.throttle", APZAsyncScrollThrottleTime, int32_t, 100);
DECL_GFX_PREF(Live, "apz.asyncscroll.timeout", APZAsyncScrollTimeout, int32_t, 300);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle", APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold", APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.axis_lock.direct_pan_angle", APZAllowedDirectPanAngle, float, float(M_PI / 3.0) /* 60 degrees */);
@@ -411,6 +409,7 @@ private:
DECL_GFX_PREF(Live, "webgl.default-no-alpha", WebGLDefaultNoAlpha, bool, false);
DECL_GFX_PREF(Live, "webgl.disable-angle", WebGLDisableANGLE, bool, false);
DECL_GFX_PREF(Live, "webgl.disable-extensions", WebGLDisableExtensions, bool, false);
DECL_GFX_PREF(Live, "webgl.dxgl.enabled", WebGLDXGLEnabled, bool, false);
DECL_GFX_PREF(Live, "webgl.disable-fail-if-major-performance-caveat",
WebGLDisableFailIfMajorPerformanceCaveat, bool, false);
+33 -39
View File
@@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
@@ -54,46 +55,21 @@ WakeLockInfoFromLockCount(const nsAString& aTopic, const LockCount& aLockCount)
return info;
}
PLDHashOperator
CountWakeLocks(const uint64_t& aKey, LockCount aCount, void* aUserArg)
static void
CountWakeLocks(ProcessLockTable* aTable, LockCount* aTotalCount)
{
MOZ_ASSERT(aUserArg);
for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
const uint64_t& key = iter.Key();
LockCount count = iter.UserData();
LockCount* totalCount = static_cast<LockCount*>(aUserArg);
totalCount->numLocks += aCount.numLocks;
totalCount->numHidden += aCount.numHidden;
aTotalCount->numLocks += count.numLocks;
aTotalCount->numHidden += count.numHidden;
// This is linear in the number of processes, but that should be small.
if (!totalCount->processes.Contains(aKey)) {
totalCount->processes.AppendElement(aKey);
}
return PL_DHASH_NEXT;
}
static PLDHashOperator
RemoveChildFromList(const nsAString& aKey, nsAutoPtr<ProcessLockTable>& aTable,
void* aUserArg)
{
MOZ_ASSERT(aUserArg);
PLDHashOperator op = PL_DHASH_NEXT;
uint64_t childID = *static_cast<uint64_t*>(aUserArg);
if (aTable->Get(childID, nullptr)) {
aTable->Remove(childID);
LockCount totalCount;
aTable->EnumerateRead(CountWakeLocks, &totalCount);
if (!totalCount.numLocks) {
op = PL_DHASH_REMOVE;
}
if (sActiveListeners) {
NotifyWakeLockChange(WakeLockInfoFromLockCount(aKey, totalCount));
// This is linear in the number of processes, but that should be small.
if (!aTotalCount->processes.Contains(key)) {
aTotalCount->processes.AppendElement(key);
}
}
return op;
}
class ClearHashtableOnShutdown final : public nsIObserver {
@@ -144,7 +120,25 @@ CleanupOnContentShutdown::Observe(nsISupports* aSubject, const char* aTopic, con
nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
&childID);
if (NS_SUCCEEDED(rv)) {
sLockTable->Enumerate(RemoveChildFromList, &childID);
for (auto iter = sLockTable->Iter(); !iter.Done(); iter.Next()) {
nsAutoPtr<ProcessLockTable>& table = iter.Data();
if (table->Get(childID, nullptr)) {
table->Remove(childID);
LockCount totalCount;
CountWakeLocks(table, &totalCount);
if (sActiveListeners) {
NotifyWakeLockChange(WakeLockInfoFromLockCount(iter.Key(),
totalCount));
}
if (totalCount.numLocks == 0) {
iter.Remove();
}
}
}
} else {
NS_WARNING("ipc:content-shutdown message without childID property");
}
@@ -222,7 +216,7 @@ ModifyWakeLock(const nsAString& aTopic,
sLockTable->Put(aTopic, table);
} else {
table->Get(aProcessID, &processCount);
table->EnumerateRead(CountWakeLocks, &totalCount);
CountWakeLocks(table, &totalCount);
}
MOZ_ASSERT(processCount.numLocks >= processCount.numHidden);
@@ -279,7 +273,7 @@ GetWakeLockInfo(const nsAString& aTopic, WakeLockInformation* aWakeLockInfo)
return;
}
LockCount totalCount;
table->EnumerateRead(CountWakeLocks, &totalCount);
CountWakeLocks(table, &totalCount);
*aWakeLockInfo = WakeLockInfoFromLockCount(aTopic, totalCount);
}
+3
View File
@@ -177,3 +177,6 @@ CFLAGS += CONFIG['GLIB_CFLAGS']
CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
CXXFLAGS += CONFIG['GLIB_CFLAGS']
CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
+4 -1
View File
@@ -302,7 +302,7 @@ private:
DecodePool::Initialize()
{
MOZ_ASSERT(NS_IsMainThread());
sNumCores = PR_GetNumberOfProcessors();
sNumCores = max<int32_t>(PR_GetNumberOfProcessors(), 1);
DecodePool::Singleton();
}
@@ -346,6 +346,9 @@ DecodePool::DecodePool()
} else {
limit = static_cast<uint32_t>(prefLimit);
}
if (limit > 32) {
limit = 32;
}
// Initialize the thread pool.
for (uint32_t i = 0 ; i < limit ; ++i) {
+9 -4
View File
@@ -74,8 +74,8 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize,
mFrameRect = aFrameRect.valueOr(nsIntRect(nsIntPoint(), aOriginalSize));
MOZ_ASSERT(mFrameRect.x >= 0 && mFrameRect.y >= 0 &&
mFrameRect.width > 0 && mFrameRect.height > 0,
"Frame rect must have positive components");
mFrameRect.width >= 0 && mFrameRect.height >= 0,
"Frame rect must have non-negative components");
MOZ_ASSERT(nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height)
.Contains(mFrameRect),
"Frame rect must fit inside image");
@@ -164,8 +164,13 @@ Downscaler::ResetForNextProgressivePass()
mCurrentInLine = 0;
mLinesInBuffer = 0;
// If we have a vertical offset, commit rows to shift us past it.
SkipToRow(mFrameRect.y);
if (mFrameRect.IsEmpty()) {
// Our frame rect is zero size; commit rows until the end of the image.
SkipToRow(mOriginalSize.height - 1);
} else {
// If we have a vertical offset, commit rows to shift us past it.
SkipToRow(mFrameRect.y);
}
}
static void
+3
View File
@@ -83,6 +83,8 @@ public:
bool aHasAlpha,
bool aFlipVertically = false);
bool IsFrameComplete() const { return mCurrentInLine >= mOriginalSize.height; }
/// Retrieves the buffer into which the Decoder should write each row.
uint8_t* RowBuffer()
{
@@ -161,6 +163,7 @@ public:
return NS_ERROR_FAILURE;
}
bool IsFrameComplete() const { return false; }
uint8_t* RowBuffer() { return nullptr; }
void ClearRow(uint32_t = 0) { }
void CommitRow() { }
+1 -1
View File
@@ -343,7 +343,7 @@ OrientedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect)
}
// Transform the invalidation rect into the correct orientation.
gfxMatrix matrix(OrientationMatrix(innerSize, /* aInvert = */ true));
gfxMatrix matrix(OrientationMatrix(innerSize));
gfxRect invalidRect(matrix.TransformBounds(gfxRect(rect.x, rect.y,
rect.width, rect.height)));
invalidRect.RoundOut();
+6 -1
View File
@@ -27,7 +27,12 @@ class AsyncNotifyRunnable;
class AsyncNotifyCurrentStateRunnable;
class Image;
// Image progress bitflags.
/**
* Image progress bitflags.
*
* See CheckProgressConsistency() for the invariants we enforce about the
* ordering dependencies betweeen these flags.
*/
enum {
FLAG_SIZE_AVAILABLE = 1u << 0, // STATUS_SIZE_AVAILABLE
FLAG_DECODE_COMPLETE = 1u << 1, // STATUS_DECODE_COMPLETE
+41 -37
View File
@@ -173,7 +173,6 @@ RasterImage::Init(const char* aMimeType,
}
//******************************************************************************
// [notxpcom] void requestRefresh ([const] in TimeStamp aTime);
NS_IMETHODIMP_(void)
RasterImage::RequestRefresh(const TimeStamp& aTime)
{
@@ -297,31 +296,22 @@ RasterImage::LookupFrameInternal(uint32_t aFrameNum,
return mAnim->GetCompositedFrame(aFrameNum);
}
Maybe<SurfaceFlags> alternateFlags;
if (IsOpaque()) {
// If we're opaque, we can always substitute a frame that was decoded with a
// different decode flag for premultiplied alpha, because that can only
// matter for frames with transparency.
alternateFlags.emplace(ToSurfaceFlags(aFlags) ^
SurfaceFlags::NO_PREMULTIPLY_ALPHA);
}
SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags);
// We don't want any substitution for sync decodes (except the premultiplied
// alpha optimization above), so we use SurfaceCache::Lookup in this case.
// We don't want any substitution for sync decodes, so we use
// SurfaceCache::Lookup in this case.
if (aFlags & FLAG_SYNC_DECODE) {
return SurfaceCache::Lookup(ImageKey(this),
RasterSurfaceKey(aSize,
ToSurfaceFlags(aFlags),
aFrameNum),
alternateFlags);
surfaceFlags,
aFrameNum));
}
// We'll return the best match we can find to the requested frame.
return SurfaceCache::LookupBestMatch(ImageKey(this),
RasterSurfaceKey(aSize,
ToSurfaceFlags(aFlags),
aFrameNum),
alternateFlags);
surfaceFlags,
aFrameNum));
}
DrawableFrameRef
@@ -331,6 +321,12 @@ RasterImage::LookupFrame(uint32_t aFrameNum,
{
MOZ_ASSERT(NS_IsMainThread());
// If we're opaque, we don't need to care about premultiplied alpha, because
// that can only matter for frames with transparency.
if (IsOpaque()) {
aFlags &= ~FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
}
IntSize requestedSize = CanDownscaleDuringDecode(aSize, aFlags)
? aSize : mSize;
if (requestedSize.IsEmpty()) {
@@ -559,8 +555,6 @@ RasterImage::CopyFrame(uint32_t aWhichFrame, uint32_t aFlags)
}
//******************************************************************************
/* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
* in uint32_t aFlags); */
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
RasterImage::GetFrame(uint32_t aWhichFrame,
uint32_t aFlags)
@@ -823,14 +817,14 @@ RasterImage::OnAddedFrame(uint32_t aNewFrameCount,
}
}
void
bool
RasterImage::SetMetadata(const ImageMetadata& aMetadata,
bool aFromMetadataDecode)
{
MOZ_ASSERT(NS_IsMainThread());
if (mError) {
return;
return true;
}
if (aMetadata.HasSize()) {
@@ -838,7 +832,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
if (size.width < 0 || size.height < 0) {
NS_WARNING("Image has negative intrinsic size");
DoError();
return;
return true;
}
MOZ_ASSERT(aMetadata.HasOrientation());
@@ -849,7 +843,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
NS_WARNING("Image changed size or orientation on redecode! "
"This should not happen!");
DoError();
return;
return true;
}
// Set the size and flag that we have it.
@@ -871,7 +865,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
// discovered that it actually was during the full decode. This is a
// rare failure that only occurs for corrupt images. To recover, we need
// to discard all existing surfaces and redecode.
RecoverFromInvalidFrames(mSize, DECODE_FLAGS_DEFAULT);
return false;
}
}
@@ -893,6 +887,8 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata,
Set("hotspotX", intwrapx);
Set("hotspotY", intwrapy);
}
return true;
}
NS_IMETHODIMP
@@ -986,7 +982,6 @@ RasterImage::ResetAnimation()
}
//******************************************************************************
// [notxpcom] void setAnimationStartTime ([const] in TimeStamp aTime);
NS_IMETHODIMP_(void)
RasterImage::SetAnimationStartTime(const TimeStamp& aTime)
{
@@ -1294,17 +1289,24 @@ RasterImage::Decode(const IntSize& aSize, uint32_t aFlags)
decoderFlags |= DecoderFlags::IS_REDECODE;
}
SurfaceFlags surfaceFlags = ToSurfaceFlags(aFlags);
if (IsOpaque()) {
// If there's no transparency, it doesn't matter whether we premultiply
// alpha or not.
surfaceFlags &= ~SurfaceFlags::NO_PREMULTIPLY_ALPHA;
}
// Create a decoder.
RefPtr<Decoder> decoder;
if (mAnim) {
decoder = DecoderFactory::CreateAnimationDecoder(mDecoderType, this,
mSourceBuffer, decoderFlags,
ToSurfaceFlags(aFlags),
surfaceFlags,
mRequestedResolution);
} else {
decoder = DecoderFactory::CreateDecoder(mDecoderType, this, mSourceBuffer,
targetSize, decoderFlags,
ToSurfaceFlags(aFlags),
surfaceFlags,
mRequestedSampleSize,
mRequestedResolution);
}
@@ -1478,15 +1480,6 @@ RasterImage::DrawInternal(DrawableFrameRef&& aFrameRef,
}
//******************************************************************************
/* [noscript] void draw(in gfxContext aContext,
* in Filter aFilter,
* [const] in gfxMatrix aUserSpaceToImageSpace,
* [const] in gfxRect aFill,
* [const] in IntRect aSubimage,
* [const] in IntSize aViewportSize,
* [const] in SVGImageContext aSVGContext,
* in uint32_t aWhichFrame,
* in uint32_t aFlags); */
NS_IMETHODIMP_(DrawResult)
RasterImage::Draw(gfxContext* aContext,
const IntSize& aSize,
@@ -1724,7 +1717,18 @@ RasterImage::FinalizeDecoder(Decoder* aDecoder)
}
// Record all the metadata the decoder gathered about this image.
SetMetadata(aDecoder->GetImageMetadata(), wasMetadata);
bool metadataOK = SetMetadata(aDecoder->GetImageMetadata(), wasMetadata);
if (!metadataOK) {
// This indicates a serious error that requires us to discard all existing
// surfaces and redecode to recover. We'll drop the results from this
// decoder on the floor, since they aren't valid.
aDecoder->TakeProgress();
aDecoder->TakeInvalidRect();
RecoverFromInvalidFrames(mSize,
FromSurfaceFlags(aDecoder->GetSurfaceFlags()));
return;
}
MOZ_ASSERT(mError || mHasSize || !aDecoder->HasSize(),
"SetMetadata should've gotten a size");
+4 -1
View File
@@ -324,8 +324,11 @@ private:
* @param aMetadata The metadata to set on this image.
* @param aFromMetadataDecode True if this metadata came from a metadata
* decode; false if it came from a full decode.
* @return |true| unless a catastrophic failure was discovered. If |false| is
* returned, it indicates that the image is corrupt in a way that requires all
* surfaces to be discarded to recover.
*/
void SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode);
bool SetMetadata(const ImageMetadata& aMetadata, bool aFromMetadataDecode);
/**
* In catastrophic circumstances like a GPU driver crash, the contents of our
-5
View File
@@ -200,9 +200,6 @@ SVGDocumentWrapper::TickRefreshDriver()
/** nsIStreamListener methods **/
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt,
in nsIInputStream inStr, in unsigned long sourceOffset,
in unsigned long count); */
NS_IMETHODIMP
SVGDocumentWrapper::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt,
nsIInputStream* inStr,
@@ -236,8 +233,6 @@ SVGDocumentWrapper::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt,
in nsresult status); */
NS_IMETHODIMP
SVGDocumentWrapper::OnStopRequest(nsIRequest* aRequest, nsISupports* ctxt,
nsresult status)
+103 -163
View File
@@ -275,8 +275,7 @@ public:
}
Pair<already_AddRefed<CachedSurface>, MatchType>
LookupBestMatch(const SurfaceKey& aSurfaceKey,
const Maybe<SurfaceFlags>& aAlternateFlags)
LookupBestMatch(const SurfaceKey& aSurfaceKey)
{
// Try for an exact match first.
RefPtr<CachedSurface> exactMatch;
@@ -286,15 +285,74 @@ public:
}
// There's no perfect match, so find the best match we can.
MatchContext matchContext(aSurfaceKey, aAlternateFlags);
ForEach(TryToImproveMatch, &matchContext);
RefPtr<CachedSurface> bestMatch;
for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
CachedSurface* surface = iter.UserData();
const SurfaceKey& idealKey = aSurfaceKey;
// We never match a placeholder.
if (surface->IsPlaceholder()) {
continue;
}
// Matching the animation time and SVG context is required.
if (aSurfaceKey.AnimationTime() != idealKey.AnimationTime() ||
aSurfaceKey.SVGContext() != idealKey.SVGContext()) {
continue;
}
// Matching the flags is required.
if (aSurfaceKey.Flags() != idealKey.Flags()) {
continue;
}
// Anything is better than nothing! (Within the constraints we just
// checked, of course.)
if (!bestMatch) {
bestMatch = surface;
continue;
}
MOZ_ASSERT(bestMatch, "Should have a current best match");
// Always prefer completely decoded surfaces.
bool bestMatchIsDecoded = bestMatch->IsDecoded();
if (bestMatchIsDecoded && !surface->IsDecoded()) {
continue;
}
if (!bestMatchIsDecoded && surface->IsDecoded()) {
bestMatch = surface;
continue;
}
SurfaceKey bestMatchKey = bestMatch->GetSurfaceKey();
// Compare sizes. We use an area-based heuristic here instead of computing a
// truly optimal answer, since it seems very unlikely to make a difference
// for realistic sizes.
int64_t idealArea = idealKey.Size().width * idealKey.Size().height;
int64_t surfaceArea = aSurfaceKey.Size().width * aSurfaceKey.Size().height;
int64_t bestMatchArea =
bestMatchKey.Size().width * bestMatchKey.Size().height;
// If the best match is smaller than the ideal size, prefer bigger sizes.
if (bestMatchArea < idealArea) {
if (surfaceArea > bestMatchArea) {
bestMatch = surface;
}
continue;
}
// Other, prefer sizes closer to the ideal size, but still not smaller.
if (idealArea <= surfaceArea && surfaceArea < bestMatchArea) {
bestMatch = surface;
continue;
}
// This surface isn't an improvement over the current best match.
}
MatchType matchType;
if (matchContext.mBestMatch) {
if (bestMatch) {
if (!exactMatch) {
// No exact match, but we found a substitute.
matchType = MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND;
} else if (exactMatch != matchContext.mBestMatch) {
} else if (exactMatch != bestMatch) {
// The exact match is still decoding, but we found a substitute.
matchType = MatchType::SUBSTITUTE_BECAUSE_PENDING;
} else {
@@ -303,8 +361,7 @@ public:
}
} else {
if (exactMatch) {
// We found an "exact match", but since TryToImproveMatch didn't return
// it, it must have been a placeholder.
// We found an "exact match", it must have been a placeholder.
MOZ_ASSERT(exactMatch->IsPlaceholder());
matchType = MatchType::PENDING;
} else {
@@ -313,103 +370,18 @@ public:
}
}
return MakePair(matchContext.mBestMatch.forget(), matchType);
return MakePair(bestMatch.forget(), matchType);
}
void ForEach(SurfaceTable::EnumReadFunction aFunction, void* aData)
SurfaceTable::Iterator ConstIter() const
{
mSurfaces.EnumerateRead(aFunction, aData);
return mSurfaces.ConstIter();
}
void SetLocked(bool aLocked) { mLocked = aLocked; }
bool IsLocked() const { return mLocked; }
private:
struct MatchContext
{
MatchContext(const SurfaceKey& aIdealKey,
const Maybe<SurfaceFlags>& aAlternateFlags)
: mIdealKey(aIdealKey)
, mAlternateFlags(aAlternateFlags)
{ }
const SurfaceKey& mIdealKey;
const Maybe<SurfaceFlags> mAlternateFlags;
RefPtr<CachedSurface> mBestMatch;
};
static PLDHashOperator TryToImproveMatch(const SurfaceKey& aSurfaceKey,
CachedSurface* aSurface,
void* aContext)
{
auto context = static_cast<MatchContext*>(aContext);
const SurfaceKey& idealKey = context->mIdealKey;
// We never match a placeholder.
if (aSurface->IsPlaceholder()) {
return PL_DHASH_NEXT;
}
// Matching the animation time and SVG context is required.
if (aSurfaceKey.AnimationTime() != idealKey.AnimationTime() ||
aSurfaceKey.SVGContext() != idealKey.SVGContext()) {
return PL_DHASH_NEXT;
}
// Matching the flags is required, but we can match the alternate flags as
// well if some were provided.
if (aSurfaceKey.Flags() != idealKey.Flags() &&
Some(aSurfaceKey.Flags()) != context->mAlternateFlags) {
return PL_DHASH_NEXT;
}
// Anything is better than nothing! (Within the constraints we just
// checked, of course.)
if (!context->mBestMatch) {
context->mBestMatch = aSurface;
return PL_DHASH_NEXT;
}
MOZ_ASSERT(context->mBestMatch, "Should have a current best match");
// Always prefer completely decoded surfaces.
bool bestMatchIsDecoded = context->mBestMatch->IsDecoded();
if (bestMatchIsDecoded && !aSurface->IsDecoded()) {
return PL_DHASH_NEXT;
}
if (!bestMatchIsDecoded && aSurface->IsDecoded()) {
context->mBestMatch = aSurface;
return PL_DHASH_NEXT;
}
SurfaceKey bestMatchKey = context->mBestMatch->GetSurfaceKey();
// Compare sizes. We use an area-based heuristic here instead of computing a
// truly optimal answer, since it seems very unlikely to make a difference
// for realistic sizes.
int64_t idealArea = idealKey.Size().width * idealKey.Size().height;
int64_t surfaceArea = aSurfaceKey.Size().width * aSurfaceKey.Size().height;
int64_t bestMatchArea =
bestMatchKey.Size().width * bestMatchKey.Size().height;
// If the best match is smaller than the ideal size, prefer bigger sizes.
if (bestMatchArea < idealArea) {
if (surfaceArea > bestMatchArea) {
context->mBestMatch = aSurface;
}
return PL_DHASH_NEXT;
}
// Other, prefer sizes closer to the ideal size, but still not smaller.
if (idealArea <= surfaceArea && surfaceArea < bestMatchArea) {
context->mBestMatch = aSurface;
return PL_DHASH_NEXT;
}
// This surface isn't an improvement over the current best match.
return PL_DHASH_NEXT;
}
SurfaceTable mSurfaces;
bool mLocked;
};
@@ -635,8 +607,7 @@ public:
}
LookupResult LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<SurfaceFlags>& aAlternateFlags)
const SurfaceKey& aSurfaceKey)
{
RefPtr<ImageSurfaceCache> cache = GetImageCache(aImageKey);
if (!cache) {
@@ -654,8 +625,7 @@ public:
DrawableFrameRef ref;
MatchType matchType = MatchType::NOT_FOUND;
while (true) {
Tie(surface, matchType) =
cache->LookupBestMatch(aSurfaceKey, aAlternateFlags);
Tie(surface, matchType) = cache->LookupBestMatch(aSurfaceKey);
if (!surface) {
return LookupResult(matchType); // Lookup in the per-image cache missed.
@@ -671,12 +641,13 @@ public:
Remove(surface);
}
MOZ_ASSERT((matchType == MatchType::EXACT) ==
(surface->GetSurfaceKey() == aSurfaceKey ||
(aAlternateFlags &&
surface->GetSurfaceKey() ==
aSurfaceKey.WithNewFlags(*aAlternateFlags))),
"Result differs in a way other than size or alternate flags");
MOZ_ASSERT_IF(matchType == MatchType::EXACT,
surface->GetSurfaceKey() == aSurfaceKey);
MOZ_ASSERT_IF(matchType == MatchType::SUBSTITUTE_BECAUSE_NOT_FOUND ||
matchType == MatchType::SUBSTITUTE_BECAUSE_PENDING,
surface->GetSurfaceKey().SVGContext() == aSurfaceKey.SVGContext() &&
surface->GetSurfaceKey().AnimationTime() == aSurfaceKey.AnimationTime() &&
surface->GetSurfaceKey().Flags() == aSurfaceKey.Flags());
if (matchType == MatchType::EXACT) {
MarkUsed(surface, cache);
@@ -728,9 +699,7 @@ public:
}
cache->SetLocked(false);
// Unlock all the surfaces the per-image cache is holding.
cache->ForEach(DoUnlockSurface, this);
DoUnlockSurfaces(cache);
}
void UnlockSurfaces(const ImageKey aImageKey)
@@ -742,9 +711,7 @@ public:
// (Note that we *don't* unlock the per-image cache here; that's the
// difference between this and UnlockImage.)
// Unlock all the surfaces the per-image cache is holding.
cache->ForEach(DoUnlockSurface, this);
DoUnlockSurfaces(cache);
}
void RemoveImage(const ImageKey aImageKey)
@@ -759,7 +726,9 @@ public:
// removing an element from the costs array. Since n is expected to be
// small, performance should be good, but if usage patterns change we should
// change the data structure used for mCosts.
cache->ForEach(DoStopTracking, this);
for (auto iter = cache->ConstIter(); !iter.Done(); iter.Next()) {
StopTracking(iter.UserData());
}
// The per-image cache isn't needed anymore, so remove it as well.
// This implicitly unlocks the image if it was locked.
@@ -815,31 +784,6 @@ public:
StartTracking(aSurface);
}
static PLDHashOperator DoStopTracking(const SurfaceKey&,
CachedSurface* aSurface,
void* aCache)
{
static_cast<SurfaceCacheImpl*>(aCache)->StopTracking(aSurface);
return PL_DHASH_NEXT;
}
static PLDHashOperator DoUnlockSurface(const SurfaceKey&,
CachedSurface* aSurface,
void* aCache)
{
if (aSurface->IsPlaceholder() || !aSurface->IsLocked()) {
return PL_DHASH_NEXT;
}
auto cache = static_cast<SurfaceCacheImpl*>(aCache);
cache->StopTracking(aSurface);
aSurface->SetLocked(false);
cache->StartTracking(aSurface);
return PL_DHASH_NEXT;
}
NS_IMETHOD
CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData,
@@ -888,16 +832,9 @@ public:
// Report all surfaces in the per-image cache.
CachedSurface::SurfaceMemoryReport report(aCounters, aMallocSizeOf);
cache->ForEach(DoCollectSizeOfSurface, &report);
}
static PLDHashOperator DoCollectSizeOfSurface(const SurfaceKey&,
CachedSurface* aSurface,
void* aReport)
{
auto report = static_cast<CachedSurface::SurfaceMemoryReport*>(aReport);
report->Add(aSurface);
return PL_DHASH_NEXT;
for (auto iter = cache->ConstIter(); !iter.Done(); iter.Next()) {
report.Add(iter.UserData());
}
}
private:
@@ -927,6 +864,20 @@ private:
}
}
void DoUnlockSurfaces(ImageSurfaceCache* aCache)
{
// Unlock all the surfaces the per-image cache is holding.
for (auto iter = aCache->ConstIter(); !iter.Done(); iter.Next()) {
CachedSurface* surface = iter.UserData();
if (surface->IsPlaceholder() || !surface->IsLocked()) {
continue;
}
StopTracking(surface);
surface->SetLocked(false);
StartTracking(surface);
}
}
struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2>
{
explicit SurfaceTracker(uint32_t aSurfaceCacheExpirationTimeMS)
@@ -1049,37 +1000,26 @@ SurfaceCache::Shutdown()
/* static */ LookupResult
SurfaceCache::Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<SurfaceFlags>& aAlternateFlags
/* = Nothing() */)
const SurfaceKey& aSurfaceKey)
{
if (!sInstance) {
return LookupResult(MatchType::NOT_FOUND);
}
MutexAutoLock lock(sInstance->GetMutex());
LookupResult result = sInstance->Lookup(aImageKey, aSurfaceKey);
if (!result && aAlternateFlags) {
result = sInstance->Lookup(aImageKey,
aSurfaceKey.WithNewFlags(*aAlternateFlags));
}
return result;
return sInstance->Lookup(aImageKey, aSurfaceKey);
}
/* static */ LookupResult
SurfaceCache::LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<SurfaceFlags>& aAlternateFlags
/* = Nothing() */)
const SurfaceKey& aSurfaceKey)
{
if (!sInstance) {
return LookupResult(MatchType::NOT_FOUND);
}
MutexAutoLock lock(sInstance->GetMutex());
return sInstance->LookupBestMatch(aImageKey, aSurfaceKey, aAlternateFlags);
return sInstance->LookupBestMatch(aImageKey, aSurfaceKey);
}
/* static */ InsertOutcome
+3 -23
View File
@@ -69,11 +69,6 @@ public:
float AnimationTime() const { return mAnimationTime; }
SurfaceFlags Flags() const { return mFlags; }
SurfaceKey WithNewFlags(SurfaceFlags aFlags) const
{
return SurfaceKey(mSize, mSVGContext, mAnimationTime, aFlags);
}
private:
SurfaceKey(const IntSize& aSize,
const Maybe<SVGImageContext>& aSVGContext,
@@ -181,38 +176,25 @@ struct SurfaceCache
* @param aSurfaceKey Key data which uniquely identifies the requested
* surface.
*
* @param aAlternateFlags If not Nothing(), a different set of flags than the
* ones specified in @aSurfaceKey which are also
* acceptable to the caller. This is more efficient
* than calling Lookup() twice, which requires taking a
* lock each time.
*
* @return a LookupResult, which will either contain a
* DrawableFrameRef to the requested surface, or an
* empty DrawableFrameRef if the surface was not found.
*/
static LookupResult Lookup(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<SurfaceFlags>& aAlternateFlags
= Nothing());
const SurfaceKey& aSurfaceKey);
/**
* Looks up the best matching surface in the cache and returns a drawable
* reference to the imgFrame containing it.
*
* Returned surfaces may vary from the requested surface only in terms of
* size, unless @aAlternateFlags is specified.
* size.
*
* @param aImageKey Key data identifying which image the surface belongs
* to.
*
* @param aSurfaceKey Key data which identifies the ideal surface to return.
*
* @param aAlternateFlags If not Nothing(), a different set of flags than the
* ones specified in @aSurfaceKey which are also
* acceptable to the caller. This is much more
* efficient than calling LookupBestMatch() twice.
*
* @return a LookupResult, which will either contain a
* DrawableFrameRef to a surface similar to the
* requested surface, or an empty DrawableFrameRef if
@@ -221,9 +203,7 @@ struct SurfaceCache
* returned surface exactly matches @aSurfaceKey.
*/
static LookupResult LookupBestMatch(const ImageKey aImageKey,
const SurfaceKey& aSurfaceKey,
const Maybe<SurfaceFlags>& aAlternateFlags
= Nothing());
const SurfaceKey& aSurfaceKey);
/**
* Insert a surface into the cache. If a surface with the same ImageKey and
+17
View File
@@ -50,6 +50,23 @@ ToSurfaceFlags(uint32_t aFlags)
return flags;
}
/**
* Given a set of SurfaceFlags, returns a set of imgIContainer FLAG_* flags with
* the corresponding flags set.
*/
inline uint32_t
FromSurfaceFlags(SurfaceFlags aFlags)
{
uint32_t flags = imgIContainer::DECODE_FLAGS_DEFAULT;
if (aFlags & SurfaceFlags::NO_PREMULTIPLY_ALPHA) {
flags |= imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA;
}
if (aFlags & SurfaceFlags::NO_COLORSPACE_CONVERSION) {
flags |= imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION;
}
return flags;
}
} // namespace image
} // namespace mozilla
+1 -17
View File
@@ -683,8 +683,6 @@ VectorImage::IsOpaque()
}
//******************************************************************************
/* [noscript] SourceSurface getFrame(in uint32_t aWhichFrame,
* in uint32_t aFlags; */
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
VectorImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags)
{
@@ -793,13 +791,6 @@ struct SVGDrawingParameters
};
//******************************************************************************
/* [noscript] void draw(in gfxContext aContext,
* [const] in nsIntSize aSize,
* [const] in ImageRegion aRegion,
* in uint32_t aWhichFrame,
* in Filter aFilter,
* [const] in MaybeSVGImageContext aSVGContext,
* in uint32_t aFlags); */
NS_IMETHODIMP_(DrawResult)
VectorImage::Draw(gfxContext* aContext,
const nsIntSize& aSize,
@@ -1125,8 +1116,6 @@ VectorImage::OnStartRequest(nsIRequest* aRequest, nsISupports* aCtxt)
}
//******************************************************************************
/* void onStopRequest(in nsIRequest request, in nsISupports ctxt,
in nsresult status); */
NS_IMETHODIMP
VectorImage::OnStopRequest(nsIRequest* aRequest, nsISupports* aCtxt,
nsresult aStatus)
@@ -1219,9 +1208,7 @@ VectorImage::OnSVGDocumentError()
if (mProgressTracker) {
// Notify observers about the error and unblock page load.
Progress progress = FLAG_DECODE_COMPLETE |
FLAG_ONLOAD_UNBLOCKED |
FLAG_HAS_ERROR;
Progress progress = FLAG_ONLOAD_UNBLOCKED | FLAG_HAS_ERROR;
// Merge in any saved progress from OnImageDataComplete.
if (mLoadProgress) {
@@ -1237,9 +1224,6 @@ VectorImage::OnSVGDocumentError()
// nsIStreamListener method
//******************************************************************************
/* void onDataAvailable(in nsIRequest request, in nsISupports ctxt,
in nsIInputStream inStr, in unsigned long sourceOffset,
in unsigned long count); */
NS_IMETHODIMP
VectorImage::OnDataAvailable(nsIRequest* aRequest, nsISupports* aCtxt,
nsIInputStream* aInStr, uint64_t aSourceOffset,
+26 -3
View File
@@ -207,7 +207,7 @@ nsGIFDecoder2::BeginGIF()
}
bool
nsGIFDecoder2::CheckForTransparency(IntRect aFrameRect)
nsGIFDecoder2::CheckForTransparency(const IntRect& aFrameRect)
{
// Check if the image has a transparent color in its palette.
if (mGIFStruct.is_transparent) {
@@ -231,6 +231,22 @@ nsGIFDecoder2::CheckForTransparency(IntRect aFrameRect)
return false;
}
IntRect
nsGIFDecoder2::ClampToImageRect(const IntRect& aRect)
{
IntRect imageRect(0, 0, mGIFStruct.screen_width, mGIFStruct.screen_height);
IntRect visibleFrameRect = aRect.Intersect(imageRect);
// If there's no intersection, |visibleFrameRect| will be an empty rect
// positioned at the maximum of |imageRect|'s and |aRect|'s coordinates, which
// is not what we want. Force it to (0, 0) in that case.
if (visibleFrameRect.IsEmpty()) {
visibleFrameRect.MoveTo(0, 0);
}
return visibleFrameRect;
}
//******************************************************************************
nsresult
nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
@@ -275,8 +291,8 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth)
}
if (mDownscaler) {
rv = mDownscaler->BeginFrame(GetSize(), Some(frameRect), mImageData,
hasTransparency);
rv = mDownscaler->BeginFrame(GetSize(), Some(ClampToImageRect(frameRect)),
mImageData, hasTransparency);
}
return rv;
@@ -487,6 +503,9 @@ nsGIFDecoder2::DoLzw(const uint8_t* q)
if (!mGIFStruct.rows_remaining) {
return true;
}
if (MOZ_UNLIKELY(mDownscaler && mDownscaler->IsFrameComplete())) {
return true;
}
// Copy all the decoder state variables into locals so the compiler
// won't worry about them being aliased. The locals will be homed
@@ -543,6 +562,10 @@ nsGIFDecoder2::DoLzw(const uint8_t* q)
return (mGIFStruct.rows_remaining == 0);
}
if (MOZ_UNLIKELY(mDownscaler && mDownscaler->IsFrameComplete())) {
goto END;
}
if (oldcode == -1) {
if (code >= MAX_BITS) {
return false;
+2 -1
View File
@@ -50,7 +50,8 @@ private:
bool DoLzw(const uint8_t* q);
bool SetHold(const uint8_t* buf, uint32_t count,
const uint8_t* buf2 = nullptr, uint32_t count2 = 0);
bool CheckForTransparency(gfx::IntRect aFrameRect);
bool CheckForTransparency(const gfx::IntRect& aFrameRect);
gfx::IntRect ClampToImageRect(const gfx::IntRect& aFrameRect);
inline int ClearCode() const { return 1 << mGIFStruct.datasize; }
-2
View File
@@ -268,8 +268,6 @@ nsJPEGEncoder::Read(char* aBuf, uint32_t aCount, uint32_t* _retval)
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
}
/* [noscript] unsigned long readSegments (in nsWriteSegmentFun aWriter, in
voidPtr aClosure, in unsigned long aCount); */
NS_IMETHODIMP
nsJPEGEncoder::ReadSegments(nsWriteSegmentFun aWriter,
void* aClosure, uint32_t aCount, uint32_t* _retval)
-5
View File
@@ -544,17 +544,12 @@ nsPNGEncoder::Available(uint64_t* _retval)
return NS_OK;
}
/* [noscript] unsigned long read (in charPtr aBuf,
in unsigned long aCount); */
NS_IMETHODIMP
nsPNGEncoder::Read(char* aBuf, uint32_t aCount, uint32_t* _retval)
{
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
}
/* [noscript] unsigned long readSegments (in nsWriteSegmentFun aWriter,
in voidPtr aClosure,
in unsigned long aCount); */
NS_IMETHODIMP
nsPNGEncoder::ReadSegments(nsWriteSegmentFun aWriter,
void* aClosure, uint32_t aCount,
+33 -68
View File
@@ -76,8 +76,16 @@ public:
nsTArray<ImageMemoryCounter> uncached;
for (uint32_t i = 0; i < mKnownLoaders.Length(); i++) {
mKnownLoaders[i]->mChromeCache.EnumerateRead(DoRecordCounter, &chrome);
mKnownLoaders[i]->mCache.EnumerateRead(DoRecordCounter, &content);
for (auto iter = mKnownLoaders[i]->mChromeCache.Iter(); !iter.Done(); iter.Next()) {
imgCacheEntry* entry = iter.UserData();
RefPtr<imgRequest> req = entry->GetRequest();
RecordCounterForRequest(req, &chrome, !entry->HasNoProxies());
}
for (auto iter = mKnownLoaders[i]->mCache.Iter(); !iter.Done(); iter.Next()) {
imgCacheEntry* entry = iter.UserData();
RefPtr<imgRequest> req = entry->GetRequest();
RecordCounterForRequest(req, &content, !entry->HasNoProxies());
}
MutexAutoLock lock(mKnownLoaders[i]->mUncachedImagesMutex);
for (auto iter = mKnownLoaders[i]->mUncachedImages.Iter();
!iter.Done();
@@ -110,8 +118,29 @@ public:
size_t n = 0;
for (uint32_t i = 0; i < imgLoader::sMemReporter->mKnownLoaders.Length();
i++) {
imgLoader::sMemReporter->mKnownLoaders[i]->
mCache.EnumerateRead(DoRecordCounterUsedDecoded, &n);
for (auto iter = imgLoader::sMemReporter->mKnownLoaders[i]->mCache.Iter();
!iter.Done();
iter.Next()) {
imgCacheEntry* entry = iter.UserData();
if (entry->HasNoProxies()) {
continue;
}
RefPtr<imgRequest> req = entry->GetRequest();
RefPtr<Image> image = req->GetImage();
if (!image) {
continue;
}
// Both this and EntryImageSizes measure images/content/raster/used/decoded
// memory. This function's measurement is secondary -- the result doesn't
// go in the "explicit" tree -- so we use moz_malloc_size_of instead of
// ImagesMallocSizeOf to prevent DMD from seeing it reported twice.
ImageMemoryCounter counter(image, moz_malloc_size_of, /* aIsUsed = */ true);
n += counter.Values().DecodedHeap();
n += counter.Values().DecodedNonHeap();
}
}
return n;
}
@@ -406,17 +435,6 @@ private:
aValue, desc, aData);
}
static PLDHashOperator DoRecordCounter(const ImageCacheKey&,
imgCacheEntry* aEntry,
void* aUserArg)
{
RefPtr<imgRequest> req = aEntry->GetRequest();
RecordCounterForRequest(req,
static_cast<nsTArray<ImageMemoryCounter>*>(aUserArg),
!aEntry->HasNoProxies());
return PL_DHASH_NEXT;
}
static void RecordCounterForRequest(imgRequest* aRequest,
nsTArray<ImageMemoryCounter>* aArray,
bool aIsUsed)
@@ -430,33 +448,6 @@ private:
aArray->AppendElement(Move(counter));
}
static PLDHashOperator DoRecordCounterUsedDecoded(const ImageCacheKey&,
imgCacheEntry* aEntry,
void* aUserArg)
{
if (aEntry->HasNoProxies()) {
return PL_DHASH_NEXT;
}
RefPtr<imgRequest> req = aEntry->GetRequest();
RefPtr<Image> image = req->GetImage();
if (!image) {
return PL_DHASH_NEXT;
}
// Both this and EntryImageSizes measure images/content/raster/used/decoded
// memory. This function's measurement is secondary -- the result doesn't
// go in the "explicit" tree -- so we use moz_malloc_size_of instead of
// ImagesMallocSizeOf to prevent DMD from seeing it reported twice.
ImageMemoryCounter counter(image, moz_malloc_size_of, /* aIsUsed = */ true);
auto n = static_cast<size_t*>(aUserArg);
*n += counter.Values().DecodedHeap();
*n += counter.Values().DecodedNonHeap();
return PL_DHASH_NEXT;
}
};
NS_IMPL_ISUPPORTS(imgMemoryReporter, nsIMemoryReporter)
@@ -2107,15 +2098,6 @@ imgLoader::LoadImageXPCOM(nsIURI* aURI,
return rv;
}
// imgIRequest loadImage(in nsIURI aURI,
// in nsIURI aInitialDocumentURL,
// in nsIURI aReferrerURI,
// in nsIPrincipal aLoadingPrincipal,
// in nsILoadGroup aLoadGroup,
// in imgINotificationObserver aObserver,
// in nsISupports aCX,
// in nsLoadFlags aLoadFlags,
// in nsISupports cacheKey);
nsresult
imgLoader::LoadImage(nsIURI* aURI,
nsIURI* aInitialDocumentURI,
@@ -2396,11 +2378,6 @@ imgLoader::LoadImage(nsIURI* aURI,
return NS_OK;
}
/* imgIRequest
loadImageWithChannelXPCOM(in nsIChannel channel,
in imgINotificationObserver aObserver,
in nsISupports cx,
out nsIStreamListener); */
NS_IMETHODIMP
imgLoader::LoadImageWithChannelXPCOM(nsIChannel* channel,
imgINotificationObserver* aObserver,
@@ -2915,8 +2892,6 @@ ProxyListener::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
return mDestListener->OnStartRequest(aRequest, ctxt);
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt,
in nsresult status); */
NS_IMETHODIMP
ProxyListener::OnStopRequest(nsIRequest* aRequest,
nsISupports* ctxt,
@@ -2931,10 +2906,6 @@ ProxyListener::OnStopRequest(nsIRequest* aRequest,
/** nsIStreamListener methods **/
/* void onDataAvailable (in nsIRequest request, in nsISupports ctxt,
in nsIInputStream inStr,
in unsigned long long sourceOffset,
in unsigned long count); */
NS_IMETHODIMP
ProxyListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt,
nsIInputStream* inStr, uint64_t sourceOffset,
@@ -3139,8 +3110,6 @@ imgCacheValidator::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
return mDestListener->OnStartRequest(aRequest, ctxt);
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt,
in nsresult status); */
NS_IMETHODIMP
imgCacheValidator::OnStopRequest(nsIRequest* aRequest,
nsISupports* ctxt,
@@ -3159,10 +3128,6 @@ imgCacheValidator::OnStopRequest(nsIRequest* aRequest,
/** nsIStreamListener methods **/
/* void
onDataAvailable (in nsIRequest request, in nsISupports ctxt,
in nsIInputStream inStr, in unsigned long long sourceOffset,
in unsigned long count); */
NS_IMETHODIMP
imgCacheValidator::OnDataAvailable(nsIRequest* aRequest, nsISupports* ctxt,
nsIInputStream* inStr,
-2
View File
@@ -804,8 +804,6 @@ imgRequest::OnStartRequest(nsIRequest* aRequest, nsISupports* ctxt)
return NS_OK;
}
/* void onStopRequest (in nsIRequest request, in nsISupports ctxt,
nsresult status); */
NS_IMETHODIMP
imgRequest::OnStopRequest(nsIRequest* aRequest,
nsISupports* ctxt, nsresult status)
-7
View File
@@ -136,9 +136,6 @@ nsScriptableUnicodeConverter::ConvertToUnicode(const nsACString& aSrc, nsAString
_retval);
}
/* AString convertFromByteArray([const,array,size_is(aCount)] in octet aData,
in unsigned long aCount);
*/
NS_IMETHODIMP
nsScriptableUnicodeConverter::ConvertFromByteArray(const uint8_t* aData,
uint32_t aCount,
@@ -180,10 +177,6 @@ nsScriptableUnicodeConverter::ConvertFromByteArray(const uint8_t* aData,
}
/* void convertToByteArray(in AString aString,
[optional] out unsigned long aLen,
[array, size_is(aLen),retval] out octet aData);
*/
NS_IMETHODIMP
nsScriptableUnicodeConverter::ConvertToByteArray(const nsAString& aString,
uint32_t* aLen,
+1 -1
View File
@@ -887,7 +887,7 @@ SetSavedStacksRNGState(JSContext* cx, unsigned argc, Value* vp)
if (!ToInt32(cx, args[0], &seed))
return false;
cx->compartment()->savedStacks().setRNGState((seed ^ RNG_MULTIPLIER) & RNG_MASK);
cx->compartment()->savedStacks().setRNGState(seed, seed * 33);
return true;
}
+9 -4
View File
@@ -5747,6 +5747,13 @@ BytecodeEmitter::emitCStyleFor(ParseNode* pn, ptrdiff_t top)
if (!emitTree(forHead->pn_kid2))
return false;
} else if (!forHead->pn_kid3) {
// If there is no condition clause and no update clause, mark
// the loop-ending "goto" with the location of the "for".
// This ensures that the debugger will stop on each loop
// iteration.
if (!updateSourceCoordNotes(pn->pn_pos.begin))
return false;
}
/* Set the first note offset so we can find the loop condition. */
@@ -8474,11 +8481,9 @@ CGBlockScopeList::findEnclosingScope(uint32_t index)
// scope contains POS, it should still be open, so its length should
// be zero.
return list[index].index;
} else {
// Conversely, if the length is not zero, it should not contain
// POS.
MOZ_ASSERT_IF(inPrologue == list[index].endInPrologue, list[index].end <= pos);
}
// Conversely, if the length is not zero, it should not contain POS.
MOZ_ASSERT_IF(inPrologue == list[index].endInPrologue, list[index].end <= pos);
}
return BlockScopeNote::NoBlockScopeIndex;
@@ -0,0 +1,43 @@
// Test how stepping interacts with for(;;) statements.
let g = newGlobal();
// We want a for(;;) loop whose body is evaluated at least once, to
// see whether the loop head is hit a second time.
g.eval(`function f() {
let x = 0;
debugger; // +0
for(;;) { // +1
if (x++ == 1) break; // +2
} // +3
debugger; // +4
}`);
let dbg = Debugger(g);
function test(s, expected) {
let result = '';
dbg.onDebuggerStatement = function(frame) {
// On the second debugger statement, we're done.
dbg.onDebuggerStatement = function(frame) {
frame.onStep = undefined;
};
let debugLine = frame.script.getOffsetLocation(frame.offset).lineNumber;
frame.onStep = function() {
// Only examine stops at entry points for the line.
let lineNo = this.script.getOffsetLocation(this.offset).lineNumber;
if (this.script.getLineOffsets(lineNo).indexOf(this.offset) < 0) {
return undefined;
}
let delta = this.script.getOffsetLocation(this.offset).lineNumber - debugLine;
result += delta;
};
};
g.eval(s);
assertEq(result, expected);
}
test('f()', '2124');
@@ -32,5 +32,5 @@ dbg.memory.trackingAllocationSites = true;
// probability is fine.
measure(0.0, 0);
measure(1.0, 100);
measure(0.1, 9);
measure(0.5, 51);
measure(0.1, 7);
measure(0.5, 44);
@@ -22,3 +22,4 @@ function test(code) {
test('while (false)\n;');
test('for (;false;)\n;');
test('for (;;) break;\n;');
@@ -10,6 +10,8 @@
#include "jsobjinlines.h"
#include "vm/NativeObject-inl.h"
using namespace js;
using JS::IsArrayAnswer;
+1 -1
View File
@@ -8014,7 +8014,7 @@ DebuggerEnv_getCallee(JSContext* cx, unsigned argc, Value* vp)
return true;
JSObject& scope = env->as<DebugScopeObject>().scope();
if (!scope.is<CallObject>() || scope.is<ModuleEnvironmentObject>())
if (!scope.is<CallObject>())
return true;
CallObject& callobj = scope.as<CallObject>();
+1 -1
View File
@@ -184,7 +184,7 @@ class SavedFrame : public NativeObject {
struct SavedFrame::HashPolicy
{
typedef SavedFrame::Lookup Lookup;
typedef PointerHasher<SavedFrame*, 3> SavedFramePtrHasher;
typedef MovableCellHasher<SavedFrame*> SavedFramePtrHasher;
typedef PointerHasher<JSPrincipals*, 3> JSPrincipalsPtrHasher;
static HashNumber hash(const Lookup& lookup);
+12 -53
View File
@@ -6,6 +6,7 @@
#include "vm/SavedStacks.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/Move.h"
@@ -986,6 +987,10 @@ SavedFrame::toStringMethod(JSContext* cx, unsigned argc, Value* vp)
bool
SavedStacks::init()
{
uint64_t seed[2];
random_generateSeed(seed, mozilla::ArrayLength(seed));
bernoulli.setRandomState(seed[0], seed[1]);
if (!pcLocationMap.init())
return false;
@@ -1030,26 +1035,8 @@ SavedStacks::sweep(JSRuntime* rt)
{
if (frames.initialized()) {
for (SavedFrame::Set::Enum e(frames); !e.empty(); e.popFront()) {
JSObject* obj = e.front().unbarrieredGet();
JSObject* temp = obj;
if (IsAboutToBeFinalizedUnbarriered(&obj)) {
if (IsAboutToBeFinalized(&e.mutableFront()))
e.removeFront();
} else {
SavedFrame* frame = &obj->as<SavedFrame>();
SavedFrame* parent = frame->getParent();
bool parentMoved = parent && IsForwarded(parent);
if (parentMoved)
parent = Forwarded(parent);
if (obj != temp || parentMoved) {
MOZ_ASSERT(!IsForwarded(frame));
SavedFrame::Lookup newLocation(*frame);
newLocation.parent = parent;
e.rekeyFront(newLocation, ReadBarriered<SavedFrame*>(frame));
}
}
}
}
@@ -1421,7 +1408,7 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
mozilla::DebugOnly<Debugger**> begin = dbgs->begin();
mozilla::DebugOnly<bool> foundAnyDebuggers = false;
allocationSamplingProbability = 0;
double probability = 0;
for (Debugger** dbgp = dbgs->begin(); dbgp < dbgs->end(); dbgp++) {
// The set of debuggers had better not change while we're iterating,
// such that the vector gets reallocated.
@@ -1429,11 +1416,13 @@ SavedStacks::chooseSamplingProbability(JSCompartment* compartment)
if ((*dbgp)->trackingAllocationSites && (*dbgp)->enabled) {
foundAnyDebuggers = true;
allocationSamplingProbability = std::max((*dbgp)->allocationSamplingProbability,
allocationSamplingProbability);
probability = std::max((*dbgp)->allocationSamplingProbability,
probability);
}
}
MOZ_ASSERT(foundAnyDebuggers);
bernoulli.setProbability(probability);
}
JSObject*
@@ -1442,38 +1431,8 @@ SavedStacksMetadataCallback(JSContext* cx, JSObject* target)
RootedObject obj(cx, target);
SavedStacks& stacks = cx->compartment()->savedStacks();
if (stacks.allocationSkipCount > 0) {
stacks.allocationSkipCount--;
if (!stacks.bernoulli.trial())
return nullptr;
}
if (stacks.allocationSamplingProbability == 0.0)
return nullptr;
// If the sampling probability is set to 1.0, we are always taking a sample
// and can therefore leave allocationSkipCount at 0.
if (stacks.allocationSamplingProbability != 1.0) {
// Rather than generating a random number on every allocation to decide
// if we want to sample that particular allocation (which would be
// expensive), we calculate the number of allocations to skip before
// taking the next sample.
//
// P = the probability we sample any given event.
//
// ~P = 1-P, the probability we don't sample a given event.
//
// (~P)^n = the probability that we skip at least the next n events.
//
// let X = random between 0 and 1.
//
// floor(log base ~P of X) = n, aka the number of events we should skip
// until we take the next sample. Any value for X less than (~P)^n
// yields a skip count greater than n, so the likelihood of a skip count
// greater than n is (~P)^n, as required.
double notSamplingProb = 1.0 - stacks.allocationSamplingProbability;
stacks.allocationSkipCount = std::floor(std::log(random_nextDouble(&stacks.rngState)) /
std::log(notSamplingProb));
}
AutoEnterOOMUnsafeRegion oomUnsafe;
RootedSavedFrame frame(cx);
+6 -7
View File
@@ -7,6 +7,8 @@
#ifndef vm_SavedStacks_h
#define vm_SavedStacks_h
#include "mozilla/FastBernoulliTrial.h"
#include "jscntxt.h"
#include "jsmath.h"
#include "jswrapper.h"
@@ -152,12 +154,11 @@ class SavedStacks {
JS::ubi::StackFrame& ubiFrame,
MutableHandleObject outSavedFrameStack);
public:
SavedStacks()
: frames(),
allocationSamplingProbability(1.0),
allocationSkipCount(0),
rngState(0),
bernoulli(1.0, 0x59fdad7f6b4cc573, 0x91adf38db96a9354),
creatingSavedFrame(false)
{ }
@@ -170,16 +171,14 @@ class SavedStacks {
void trace(JSTracer* trc);
uint32_t count();
void clear();
void setRNGState(uint64_t state) { rngState = state; }
void setRNGState(uint64_t state0, uint64_t state1) { bernoulli.setRandomState(state0, state1); }
void chooseSamplingProbability(JSCompartment*);
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
private:
SavedFrame::Set frames;
double allocationSamplingProbability;
uint32_t allocationSkipCount;
uint64_t rngState;
mozilla::FastBernoulliTrial bernoulli;
bool creatingSavedFrame;
// Similar to mozilla::ReentrancyGuard, but instead of asserting against
+7 -5
View File
@@ -27,7 +27,7 @@ NearestEnclosingExtensibleLexicalScope(JSObject* scope)
inline void
ScopeObject::setAliasedVar(JSContext* cx, ScopeCoordinate sc, PropertyName* name, const Value& v)
{
MOZ_ASSERT(is<CallObject>() || is<ClonedBlockObject>());
MOZ_ASSERT(is<LexicalScopeBase>() || is<ClonedBlockObject>());
JS_STATIC_ASSERT(CallObject::RESERVED_SLOTS == BlockObject::RESERVED_SLOTS);
// name may be null if we don't need to track side effects on the object.
@@ -48,7 +48,8 @@ ScopeObject::setAliasedVar(JSContext* cx, ScopeCoordinate sc, PropertyName* name
}
inline void
CallObject::setAliasedVar(JSContext* cx, AliasedFormalIter fi, PropertyName* name, const Value& v)
LexicalScopeBase::setAliasedVar(JSContext* cx, AliasedFormalIter fi, PropertyName* name,
const Value& v)
{
MOZ_ASSERT(name == fi->name());
setSlot(fi.scopeSlot(), v);
@@ -57,7 +58,8 @@ CallObject::setAliasedVar(JSContext* cx, AliasedFormalIter fi, PropertyName* nam
}
inline void
CallObject::setAliasedVarFromArguments(JSContext* cx, const Value& argsValue, jsid id, const Value& v)
LexicalScopeBase::setAliasedVarFromArguments(JSContext* cx, const Value& argsValue, jsid id,
const Value& v)
{
setSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue), v);
if (isSingleton())
@@ -65,7 +67,7 @@ CallObject::setAliasedVarFromArguments(JSContext* cx, const Value& argsValue, js
}
inline void
CallObject::initRemainingSlotsToUninitializedLexicals(uint32_t begin)
LexicalScopeBase::initRemainingSlotsToUninitializedLexicals(uint32_t begin)
{
uint32_t end = slotSpan();
for (uint32_t slot = begin; slot < end; slot++)
@@ -73,7 +75,7 @@ CallObject::initRemainingSlotsToUninitializedLexicals(uint32_t begin)
}
inline void
CallObject::initAliasedLexicalsToThrowOnTouch(JSScript* script)
LexicalScopeBase::initAliasedLexicalsToThrowOnTouch(JSScript* script)
{
initRemainingSlotsToUninitializedLexicals(script->bindings.aliasedBodyLevelLexicalBegin());
}
+4 -6
View File
@@ -125,7 +125,7 @@ js::ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc)
void
ScopeObject::setEnclosingScope(HandleObject obj)
{
MOZ_ASSERT_IF(obj->is<CallObject>() || obj->is<DeclEnvObject>() || obj->is<BlockObject>(),
MOZ_ASSERT_IF(obj->is<LexicalScopeBase>() || obj->is<DeclEnvObject>() || obj->is<BlockObject>(),
obj->isDelegate());
setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*obj));
}
@@ -1776,9 +1776,7 @@ class DebugScopeProxy : public BaseProxyHandler
static bool isFunctionScope(const JSObject& scope)
{
return scope.is<CallObject>() &&
!scope.is<ModuleEnvironmentObject>() &&
!scope.as<CallObject>().isForEval();
return scope.is<CallObject>() && !scope.as<CallObject>().isForEval();
}
/*
@@ -2203,7 +2201,7 @@ bool
DebugScopeObject::isForDeclarative() const
{
ScopeObject& s = scope();
return s.is<CallObject>() || s.is<BlockObject>() || s.is<DeclEnvObject>();
return s.is<LexicalScopeBase>() || s.is<BlockObject>() || s.is<DeclEnvObject>();
}
bool
@@ -2224,7 +2222,7 @@ DebugScopeObject::isOptimizedOut() const
if (s.is<ClonedBlockObject>())
return !s.as<ClonedBlockObject>().staticBlock().needsClone();
if (s.is<CallObject>() && !s.is<ModuleEnvironmentObject>()) {
if (s.is<CallObject>()) {
return !s.as<CallObject>().isForEval() &&
!s.as<CallObject>().callee().needsCallObject() &&
!maybeSnapshot();
+41 -32
View File
@@ -221,7 +221,9 @@ ScopeCoordinateFunctionScript(JSScript* script, jsbytecode* pc);
* | | |
* | | DeclEnvObject Holds name of recursive/needsCallObject named lambda
* | |
* | CallObject Scope of entire function or strict eval
* | LexicalScopeBase Shared base for function and modules scopes
* | | |
* | | CallObject Scope of entire function or strict eval
* | |
* | ModuleEnvironmentObject Module top-level scope on run-time scope chain
* |
@@ -287,7 +289,36 @@ class ScopeObject : public NativeObject
}
};
class CallObject : public ScopeObject
class LexicalScopeBase : public ScopeObject
{
protected:
inline void initRemainingSlotsToUninitializedLexicals(uint32_t begin);
inline void initAliasedLexicalsToThrowOnTouch(JSScript* script);
public:
/* Get/set the aliased variable referred to by 'fi'. */
const Value& aliasedVar(AliasedFormalIter fi) {
return getSlot(fi.scopeSlot());
}
inline void setAliasedVar(JSContext* cx, AliasedFormalIter fi, PropertyName* name,
const Value& v);
/*
* When an aliased var (var accessed by nested closures) is also aliased by
* the arguments object, it must of course exist in one canonical location
* and that location is always the CallObject. For this to work, the
* ArgumentsObject stores special MagicValue in its array for forwarded-to-
* CallObject variables. This MagicValue's payload is the slot of the
* CallObject to access.
*/
const Value& aliasedVarFromArguments(const Value& argsValue) {
return getSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue));
}
inline void setAliasedVarFromArguments(JSContext* cx, const Value& argsValue, jsid id,
const Value& v);
};
class CallObject : public LexicalScopeBase
{
protected:
static const uint32_t CALLEE_SLOT = 1;
@@ -295,9 +326,6 @@ class CallObject : public ScopeObject
static CallObject*
create(JSContext* cx, HandleScript script, HandleObject enclosing, HandleFunction callee);
inline void initRemainingSlotsToUninitializedLexicals(uint32_t begin);
inline void initAliasedLexicalsToThrowOnTouch(JSScript* script);
public:
static const Class class_;
@@ -347,27 +375,6 @@ class CallObject : public ScopeObject
return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
}
/* Get/set the aliased variable referred to by 'bi'. */
const Value& aliasedVar(AliasedFormalIter fi) {
return getSlot(fi.scopeSlot());
}
inline void setAliasedVar(JSContext* cx, AliasedFormalIter fi, PropertyName* name,
const Value& v);
/*
* When an aliased var (var accessed by nested closures) is also aliased by
* the arguments object, it must of course exist in one canonical location
* and that location is always the CallObject. For this to work, the
* ArgumentsObject stores special MagicValue in its array for forwarded-to-
* CallObject variables. This MagicValue's payload is the slot of the
* CallObject to access.
*/
const Value& aliasedVarFromArguments(const Value& argsValue) {
return getSlot(ArgumentsObject::SlotFromMagicScopeSlotValue(argsValue));
}
inline void setAliasedVarFromArguments(JSContext* cx, const Value& argsValue, jsid id,
const Value& v);
/* For jit access. */
static size_t offsetOfCallee() {
return getFixedSlotOffset(CALLEE_SLOT);
@@ -378,13 +385,15 @@ class CallObject : public ScopeObject
}
};
class ModuleEnvironmentObject : public CallObject
class ModuleEnvironmentObject : public LexicalScopeBase
{
static const uint32_t MODULE_SLOT = CallObject::CALLEE_SLOT;
static const uint32_t MODULE_SLOT = 1;
public:
static const Class class_;
static const uint32_t RESERVED_SLOTS = 2;
static ModuleEnvironmentObject* create(ExclusiveContext* cx, HandleModuleObject module);
ModuleObject& module();
IndirectBindingMap& importBindings();
@@ -1261,9 +1270,9 @@ JSObject::is<js::NestedScopeObject>() const
template<>
inline bool
JSObject::is<js::CallObject>() const
JSObject::is<js::LexicalScopeBase>() const
{
return getClass() == &js::CallObject::class_ ||
return is<js::CallObject>() ||
is<js::ModuleEnvironmentObject>();
}
@@ -1271,7 +1280,7 @@ template<>
inline bool
JSObject::is<js::ScopeObject>() const
{
return is<js::CallObject>() ||
return is<js::LexicalScopeBase>() ||
is<js::DeclEnvObject>() ||
is<js::NestedScopeObject>() ||
is<js::RuntimeLexicalErrorObject>() ||
@@ -1342,7 +1351,7 @@ IsStaticGlobalLexicalScope(JSObject* scope)
inline const Value&
ScopeObject::aliasedVar(ScopeCoordinate sc)
{
MOZ_ASSERT(is<CallObject>() || is<ClonedBlockObject>());
MOZ_ASSERT(is<LexicalScopeBase>() || is<ClonedBlockObject>());
return getSlot(sc.slot());
}
+1 -4
View File
@@ -35,10 +35,7 @@ namespace js {
static inline bool
IsCacheableNonGlobalScope(JSObject* obj)
{
bool cacheable =
(obj->is<CallObject>() && !obj->is<ModuleEnvironmentObject>()) ||
obj->is<BlockObject>() ||
obj->is<DeclEnvObject>();
bool cacheable = obj->is<CallObject>() || obj->is<BlockObject>() || obj->is<DeclEnvObject>();
MOZ_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty);
return cacheable;
@@ -1056,8 +1056,6 @@ mozJSComponentLoader::Import(const nsACString& registryLocation,
return rv;
}
/* [noscript] JSObjectPtr importInto(in AUTF8String registryLocation,
in JSObjectPtr targetObj); */
NS_IMETHODIMP
mozJSComponentLoader::ImportInto(const nsACString& aLocation,
JSObject* aTargetObj,
-14
View File
@@ -1150,13 +1150,6 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin
return NS_OK;
}
/* bool call(in nsIXPConnectWrappedNative wrapper,
* in JSContextPtr cx,
* in JSObjectPtr obj,
* in uint32_t argc,
* in JSValPtr argv,
* in JSValPtr vp);
*/
NS_IMETHODIMP
nsXPCComponents_utils_Sandbox::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
JSObject* objArg, const CallArgs& args, bool* _retval)
@@ -1165,13 +1158,6 @@ nsXPCComponents_utils_Sandbox::Call(nsIXPConnectWrappedNative* wrapper, JSContex
return CallOrConstruct(wrapper, cx, obj, args, _retval);
}
/* bool construct(in nsIXPConnectWrappedNative wrapper,
* in JSContextPtr cx,
* in JSObjectPtr obj,
* in uint32_t argc,
* in JSValPtr argv,
* in JSValPtr vp);
*/
NS_IMETHODIMP
nsXPCComponents_utils_Sandbox::Construct(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
JSObject* objArg, const CallArgs& args, bool* _retval)
-30
View File
@@ -115,8 +115,6 @@ private:
nsCOMArray<nsIInterfaceInfo> mInterfaces;
};
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_Interfaces::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -342,8 +340,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_InterfacesByID::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -571,8 +567,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_Classes::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -780,8 +774,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_ClassesByID::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -1012,8 +1004,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_Results::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -1204,8 +1194,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_ID::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -1403,8 +1391,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_Exception::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -1770,8 +1756,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCConstructor::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -1997,8 +1981,6 @@ private:
};
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
nsXPCComponents_Constructor::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -2486,9 +2468,6 @@ nsXPCComponents_Utils::SetSandboxMetadata(HandleValue sandboxVal,
return NS_OK;
}
/* JSObject import (in AUTF8String registryLocation,
* [optional] in JSObject targetObj);
*/
NS_IMETHODIMP
nsXPCComponents_Utils::Import(const nsACString& registryLocation,
HandleValue targetObj,
@@ -2503,8 +2482,6 @@ nsXPCComponents_Utils::Import(const nsACString& registryLocation,
return moduleloader->Import(registryLocation, targetObj, cx, optionalArgc, retval);
}
/* boolean isModuleLoaded (in AUTF8String registryLocation);
*/
NS_IMETHODIMP
nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation, bool* retval)
{
@@ -2515,8 +2492,6 @@ nsXPCComponents_Utils::IsModuleLoaded(const nsACString& registryLocation, bool*
return moduleloader->IsModuleLoaded(registryLocation, retval);
}
/* unload (in AUTF8String registryLocation);
*/
NS_IMETHODIMP
nsXPCComponents_Utils::Unload(const nsACString & registryLocation)
{
@@ -2527,9 +2502,6 @@ nsXPCComponents_Utils::Unload(const nsACString & registryLocation)
return moduleloader->Unload(registryLocation);
}
/*
* JSObject importGlobalProperties (in jsval aPropertyList);
*/
NS_IMETHODIMP
nsXPCComponents_Utils::ImportGlobalProperties(HandleValue aPropertyList,
JSContext* cx)
@@ -2714,8 +2686,6 @@ nsXPCComponents_Utils::GetJSTestingFunctions(JSContext* cx,
return NS_OK;
}
/* jsval callFunctionWithStack(in jsval function, in nsIStackFrame stack,
in AString asyncCause); */
NS_IMETHODIMP
nsXPCComponents_Utils::CallFunctionWithAsyncStack(HandleValue function,
nsIStackFrame* stack,
-2
View File
@@ -79,8 +79,6 @@ BackstagePass::Enumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
}
/***************************************************************************/
/* void getInterfaces (out uint32_t count, [array, size_is (count), retval]
out nsIIDPtr array); */
NS_IMETHODIMP
BackstagePass::GetInterfaces(uint32_t* aCount, nsIID * **aArray)
{
@@ -188,9 +188,6 @@ NS_IMETHODIMP nsXPCTestParams::TestJsval(JS::Handle<JS::Value> a,
return NS_OK;
}
/* void testShortArray (in unsigned long aLength, [array, size_is (aLength)] in short a,
* inout unsigned long bLength, [array, size_is (bLength)] inout short b,
* out unsigned long rvLength, [array, size_is (rvLength), retval] out short rv); */
NS_IMETHODIMP nsXPCTestParams::TestShortArray(uint32_t aLength, int16_t* a,
uint32_t* bLength, int16_t** b,
uint32_t* rvLength, int16_t** rv)
@@ -198,9 +195,6 @@ NS_IMETHODIMP nsXPCTestParams::TestShortArray(uint32_t aLength, int16_t* a,
BUFFER_METHOD_IMPL(int16_t, 0, TAKE_OWNERSHIP_NOOP);
}
/* void testDoubleArray (in unsigned long aLength, [array, size_is (aLength)] in double a,
* inout unsigned long bLength, [array, size_is (bLength)] inout double b,
* out unsigned long rvLength, [array, size_is (rvLength), retval] out double rv); */
NS_IMETHODIMP nsXPCTestParams::TestDoubleArray(uint32_t aLength, double* a,
uint32_t* bLength, double** b,
uint32_t* rvLength, double** rv)
@@ -208,9 +202,6 @@ NS_IMETHODIMP nsXPCTestParams::TestDoubleArray(uint32_t aLength, double* a,
BUFFER_METHOD_IMPL(double, 0, TAKE_OWNERSHIP_NOOP);
}
/* void testStringArray (in unsigned long aLength, [array, size_is (aLength)] in string a,
* inout unsigned long bLength, [array, size_is (bLength)] inout string b,
* out unsigned long rvLength, [array, size_is (rvLength), retval] out string rv); */
NS_IMETHODIMP nsXPCTestParams::TestStringArray(uint32_t aLength, const char * *a,
uint32_t* bLength, char * **b,
uint32_t* rvLength, char * **rv)
@@ -218,9 +209,6 @@ NS_IMETHODIMP nsXPCTestParams::TestStringArray(uint32_t aLength, const char * *a
BUFFER_METHOD_IMPL(char*, 0, TAKE_OWNERSHIP_STRING);
}
/* void testWstringArray (in unsigned long aLength, [array, size_is (aLength)] in wstring a,
* inout unsigned long bLength, [array, size_is (bLength)] inout wstring b,
* out unsigned long rvLength, [array, size_is (rvLength), retval] out wstring rv); */
NS_IMETHODIMP nsXPCTestParams::TestWstringArray(uint32_t aLength, const char16_t * *a,
uint32_t* bLength, char16_t * **b,
uint32_t* rvLength, char16_t * **rv)
@@ -228,9 +216,6 @@ NS_IMETHODIMP nsXPCTestParams::TestWstringArray(uint32_t aLength, const char16_t
BUFFER_METHOD_IMPL(char16_t*, 0, TAKE_OWNERSHIP_WSTRING);
}
/* void testInterfaceArray (in unsigned long aLength, [array, size_is (aLength)] in nsIXPCTestInterfaceA a,
* inout unsigned long bLength, [array, size_is (bLength)] inout nsIXPCTestInterfaceA b,
* out unsigned long rvLength, [array, size_is (rvLength), retval] out nsIXPCTestInterfaceA rv); */
NS_IMETHODIMP nsXPCTestParams::TestInterfaceArray(uint32_t aLength, nsIXPCTestInterfaceA** a,
uint32_t* bLength, nsIXPCTestInterfaceA * **b,
uint32_t* rvLength, nsIXPCTestInterfaceA * **rv)
@@ -238,9 +223,6 @@ NS_IMETHODIMP nsXPCTestParams::TestInterfaceArray(uint32_t aLength, nsIXPCTestIn
BUFFER_METHOD_IMPL(nsIXPCTestInterfaceA*, 0, TAKE_OWNERSHIP_INTERFACE);
}
/* void testSizedString (in unsigned long aLength, [size_is (aLength)] in string a,
* inout unsigned long bLength, [size_is (bLength)] inout string b,
* out unsigned long rvLength, [size_is (rvLength), retval] out string rv); */
NS_IMETHODIMP nsXPCTestParams::TestSizedString(uint32_t aLength, const char * a,
uint32_t* bLength, char * *b,
uint32_t* rvLength, char * *rv)
@@ -248,9 +230,6 @@ NS_IMETHODIMP nsXPCTestParams::TestSizedString(uint32_t aLength, const char * a,
BUFFER_METHOD_IMPL(char, 1, TAKE_OWNERSHIP_NOOP);
}
/* void testSizedWstring (in unsigned long aLength, [size_is (aLength)] in wstring a,
* inout unsigned long bLength, [size_is (bLength)] inout wstring b,
* out unsigned long rvLength, [size_is (rvLength), retval] out wstring rv); */
NS_IMETHODIMP nsXPCTestParams::TestSizedWstring(uint32_t aLength, const char16_t * a,
uint32_t* bLength, char16_t * *b,
uint32_t* rvLength, char16_t * *rv)
@@ -258,9 +237,6 @@ NS_IMETHODIMP nsXPCTestParams::TestSizedWstring(uint32_t aLength, const char16_t
BUFFER_METHOD_IMPL(char16_t, 1, TAKE_OWNERSHIP_NOOP);
}
/* void testInterfaceIs (in nsIIDPtr aIID, [iid_is (aIID)] in nsQIResult a,
* inout nsIIDPtr bIID, [iid_is (bIID)] inout nsQIResult b,
* out nsIIDPtr rvIID, [iid_is (rvIID), retval] out nsQIResult rv); */
NS_IMETHODIMP nsXPCTestParams::TestInterfaceIs(const nsIID* aIID, void* a,
nsIID** bIID, void** b,
nsIID** rvIID, void** rv)
@@ -294,12 +270,6 @@ NS_IMETHODIMP nsXPCTestParams::TestInterfaceIs(const nsIID* aIID, void* a,
return NS_OK;
}
/* void testInterfaceIsArray (in unsigned long aLength, in nsIIDPtr aIID,
* [array, size_is (aLength), iid_is (aIID)] in nsQIResult a,
* inout unsigned long bLength, inout nsIIDPtr bIID,
* [array, size_is (bLength), iid_is (bIID)] inout nsQIResult b,
* out unsigned long rvLength, out nsIIDPtr rvIID,
* [retval, array, size_is (rvLength), iid_is (rvIID)] out nsQIResult rv); */
NS_IMETHODIMP nsXPCTestParams::TestInterfaceIsArray(uint32_t aLength, const nsIID* aIID,
void** a,
uint32_t* bLength, nsIID** bIID,
@@ -327,9 +297,6 @@ NS_IMETHODIMP nsXPCTestParams::TestOutAString(nsAString & o)
return NS_OK;
}
/*
* ACString testStringArrayOptionalSize([array, size_is(aLength)] in string a, [optional] in unsigned long aLength);
*/
NS_IMETHODIMP nsXPCTestParams::TestStringArrayOptionalSize(const char * *a, uint32_t length, nsACString& out)
{
out.Truncate();
+8 -19
View File
@@ -34,6 +34,10 @@
#include "ClientLayerManager.h"
#include "FrameLayerBuilder.h"
#ifdef MOZ_ANDROID_APZ
#include "AndroidBridge.h"
#endif
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::layers;
@@ -197,29 +201,14 @@ public:
void ClearRenderFrame() { mRenderFrame = nullptr; }
virtual void SendAsyncScrollDOMEvent(bool aIsRootContent,
const CSSRect& aContentRect,
const CSSSize& aContentSize) override
{
if (MessageLoop::current() != mUILoop) {
mUILoop->PostTask(
FROM_HERE,
NewRunnableMethod(this,
&RemoteContentController::SendAsyncScrollDOMEvent,
aIsRootContent, aContentRect, aContentSize));
return;
}
if (mRenderFrame && aIsRootContent) {
TabParent* browser = TabParent::GetFrom(mRenderFrame->Manager());
BrowserElementParent::DispatchAsyncScrollEvent(browser, aContentRect,
aContentSize);
}
}
virtual void PostDelayedTask(Task* aTask, int aDelayMs) override
{
#ifdef MOZ_ANDROID_APZ
AndroidBridge::Bridge()->PostTaskToUiThread(aTask, aDelayMs);
#else
(MessageLoop::current() ? MessageLoop::current() : mUILoop)->
PostDelayedTask(FROM_HERE, aTask, aDelayMs);
#endif
}
virtual bool GetTouchSensitiveRegion(CSSRect* aOutRegion) override
-10
View File
@@ -1333,7 +1333,6 @@ nsCSSFontFaceStyleDecl::GetPropertyValue(nsCSSFontDesc aFontDescID,
}
// attribute DOMString cssText;
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetCssText(nsAString & aCssText)
{
@@ -1363,7 +1362,6 @@ nsCSSFontFaceStyleDecl::SetCssText(const nsAString & aCssText)
return NS_ERROR_NOT_IMPLEMENTED; // bug 443978
}
// DOMString getPropertyValue (in DOMString propertyName);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetPropertyValue(const nsAString & propertyName,
nsAString & aResult)
@@ -1380,7 +1378,6 @@ nsCSSFontFaceStyleDecl::GetAuthoredPropertyValue(const nsAString& propertyName,
return GetPropertyValue(nsCSSProps::LookupFontDesc(propertyName), aResult);
}
// nsIDOMCSSValue getPropertyCSSValue (in DOMString propertyName);
already_AddRefed<dom::CSSValue>
nsCSSFontFaceStyleDecl::GetPropertyCSSValue(const nsAString & propertyName,
ErrorResult& aRv)
@@ -1390,7 +1387,6 @@ nsCSSFontFaceStyleDecl::GetPropertyCSSValue(const nsAString & propertyName,
return nullptr;
}
// DOMString removeProperty (in DOMString propertyName) raises (DOMException);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::RemoveProperty(const nsAString & propertyName,
nsAString & aResult)
@@ -1410,7 +1406,6 @@ nsCSSFontFaceStyleDecl::RemoveProperty(const nsAString & propertyName,
return NS_OK;
}
// DOMString getPropertyPriority (in DOMString propertyName);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetPropertyPriority(const nsAString & propertyName,
nsAString & aResult)
@@ -1420,8 +1415,6 @@ nsCSSFontFaceStyleDecl::GetPropertyPriority(const nsAString & propertyName,
return NS_OK;
}
// void setProperty (in DOMString propertyName, in DOMString value,
// in DOMString priority) raises (DOMException);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::SetProperty(const nsAString & propertyName,
const nsAString & value,
@@ -1430,7 +1423,6 @@ nsCSSFontFaceStyleDecl::SetProperty(const nsAString & propertyName,
return NS_ERROR_NOT_IMPLEMENTED; // bug 443978
}
// readonly attribute unsigned long length;
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetLength(uint32_t *aLength)
{
@@ -1445,7 +1437,6 @@ nsCSSFontFaceStyleDecl::GetLength(uint32_t *aLength)
return NS_OK;
}
// DOMString item (in unsigned long index);
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::Item(uint32_t aIndex, nsAString& aReturn)
{
@@ -1476,7 +1467,6 @@ nsCSSFontFaceStyleDecl::IndexedGetter(uint32_t index, bool& aFound, nsAString &
aFound = false;
}
// readonly attribute nsIDOMCSSRule parentRule;
NS_IMETHODIMP
nsCSSFontFaceStyleDecl::GetParentRule(nsIDOMCSSRule** aParentRule)
{
+1 -1
View File
@@ -28,7 +28,7 @@ class nsStyleContext;
namespace mozilla {
class WritingMode;
class LogicalMargin;
}
} // namespace mozilla
struct nsTableReflowState;
struct BCPropertyData;
+13 -5
View File
@@ -91,8 +91,8 @@ malloc_good_size_impl(size_t size)
return je_(nallocx)(size, 0);
}
static size_t
compute_bin_unused(unsigned int narenas)
static void
compute_bin_unused_and_bookkeeping(jemalloc_stats_t *stats, unsigned int narenas)
{
size_t bin_unused = 0;
@@ -104,6 +104,9 @@ compute_bin_unused(unsigned int narenas)
unsigned int nbins; // number of bins per arena
unsigned int i, j;
size_t stats_metadata;
size_t stats_ametadata = 0; // total internal allocations in all arenas
// narenas also counts uninitialized arenas, and initialized arenas
// are not guaranteed to be adjacent
VARIABLE_ARRAY(bool, initialized, narenas);
@@ -128,7 +131,13 @@ compute_bin_unused(unsigned int narenas)
}
}
return bin_unused;
CTL_GET("stats.metadata", stats_metadata);
/* get the summation for all arenas, i == narenas */
CTL_I_GET("stats.arenas.0.metadata.allocated", stats_ametadata, narenas);
stats->bookkeeping = stats_metadata - stats_ametadata;
stats->bin_unused = bin_unused;
}
MOZ_JEMALLOC_API void
@@ -150,7 +159,6 @@ jemalloc_stats_impl(jemalloc_stats_t *stats)
CTL_GET("stats.allocated", allocated);
CTL_GET("stats.mapped", mapped);
CTL_GET("opt.lg_chunk", lg_chunk);
CTL_GET("stats.bookkeeping", stats->bookkeeping);
/* get the summation for all arenas, i == narenas */
CTL_I_GET("stats.arenas.0.pdirty", pdirty, narenas);
@@ -160,7 +168,7 @@ jemalloc_stats_impl(jemalloc_stats_t *stats)
stats->allocated = allocated;
stats->waste = active - allocated;
stats->page_cache = pdirty * page;
stats->bin_unused = compute_bin_unused(narenas);
compute_bin_unused_and_bookkeeping(stats, narenas);
stats->waste -= stats->bin_unused;
}
+3
View File
@@ -33,3 +33,6 @@ if CONFIG['_MSC_VER']:
# This further prevents the CRT name from getting into the .obj file,
# by avoiding pulling in a bunch of string code that uses the CRT.
DEFINES['mozilla_Char16_h'] = True
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wshadow']
+376
View File
@@ -0,0 +1,376 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 mozilla_FastBernoulliTrial_h
#define mozilla_FastBernoulliTrial_h
#include "mozilla/Assertions.h"
#include "mozilla/XorShift128PlusRNG.h"
#include <cmath>
#include <stdint.h>
namespace mozilla {
/**
* class FastBernoulliTrial: Efficient sampling with uniform probability
*
* When gathering statistics about a program's behavior, we may be observing
* events that occur very frequently (e.g., function calls or memory
* allocations) and we may be gathering information that is somewhat expensive
* to produce (e.g., call stacks). Sampling all the events could have a
* significant impact on the program's performance.
*
* Why not just sample every N'th event? This technique is called "systematic
* sampling"; it's simple and efficient, and it's fine if we imagine a
* patternless stream of events. But what if we're sampling allocations, and the
* program happens to have a loop where each iteration does exactly N
* allocations? You would end up sampling the same allocation every time through
* the loop; the entire rest of the loop becomes invisible to your measurements!
* More generally, if each iteration does M allocations, and M and N have any
* common divisor at all, most allocation sites will never be sampled. If
* they're both even, say, the odd-numbered allocations disappear from your
* results.
*
* Ideally, we'd like each event to have some probability P of being sampled,
* independent of its neighbors and of its position in the sequence. This is
* called "Bernoulli sampling", and it doesn't suffer from any of the problems
* mentioned above.
*
* One disadvantage of Bernoulli sampling is that you can't be sure exactly how
* many samples you'll get: technically, it's possible that you might sample
* none of them, or all of them. But if the number of events N is large, these
* aren't likely outcomes; you can generally expect somewhere around P * N
* events to be sampled.
*
* The other disadvantage of Bernoulli sampling is that you have to generate a
* random number for every event, which can be slow.
*
* [significant pause]
*
* BUT NOT WITH THIS CLASS! FastBernoulliTrial lets you do true Bernoulli
* sampling, while generating a fresh random number only when we do decide to
* sample an event, not on every trial. When it decides not to sample, a call to
* |FastBernoulliTrial::trial| is nothing but decrementing a counter and
* comparing it to zero. So the lower your sampling probability is, the less
* overhead FastBernoulliTrial imposes.
*
* Probabilities of 0 and 1 are handled efficiently. (In neither case need we
* ever generate a random number at all.)
*
* The essential API:
*
* - FastBernoulliTrial(double P)
* Construct an instance that selects events with probability P.
*
* - FastBernoulliTrial::trial()
* Return true with probability P. Call this each time an event occurs, to
* decide whether to sample it or not.
*
* - FastBernoulliTrial::trial(size_t n)
* Equivalent to calling trial() |n| times, and returning true if any of those
* calls do. However, like trial, this runs in fast constant time.
*
* What is this good for? In some applications, some events are "bigger" than
* others. For example, large allocations are more significant than small
* allocations. Perhaps we'd like to imagine that we're drawing allocations
* from a stream of bytes, and performing a separate Bernoulli trial on every
* byte from the stream. We can accomplish this by calling |t.trial(S)| for
* the number of bytes S, and sampling the event if that returns true.
*
* Of course, this style of sampling needs to be paired with analysis and
* presentation that makes the size of the event apparent, lest trials with
* large values for |n| appear to be indistinguishable from those with small
* values for |n|.
*/
class FastBernoulliTrial {
/*
* This comment should just read, "Generate skip counts with a geometric
* distribution", and leave everyone to go look that up and see why it's the
* right thing to do, if they don't know already.
*
* BUT IF YOU'RE CURIOUS, COMMENTS ARE FREE...
*
* Instead of generating a fresh random number for every trial, we can
* randomly generate a count of how many times we should return false before
* the next time we return true. We call this a "skip count". Once we've
* returned true, we generate a fresh skip count, and begin counting down
* again.
*
* Here's an awesome fact: by exercising a little care in the way we generate
* skip counts, we can produce results indistinguishable from those we would
* get "rolling the dice" afresh for every trial.
*
* In short, skip counts in Bernoulli trials of probability P obey a geometric
* distribution. If a random variable X is uniformly distributed from [0..1),
* then std::floor(std::log(X) / std::log(1-P)) has the appropriate geometric
* distribution for the skip counts.
*
* Why that formula?
*
* Suppose we're to return |true| with some probability P, say, 0.3. Spread
* all possible futures along a line segment of length 1. In portion P of
* those cases, we'll return true on the next call to |trial|; the skip count
* is 0. For the remaining portion 1-P of cases, the skip count is 1 or more.
*
* skip: 0 1 or more
* |------------------^-----------------------------------------|
* portion: 0.3 0.7
* P 1-P
*
* But the "1 or more" section of the line is subdivided the same way: *within
* that section*, in portion P the second call to |trial()| returns true, and in
* portion 1-P it returns false a second time; the skip count is two or more.
* So we return true on the second call in proportion 0.7 * 0.3, and skip at
* least the first two in proportion 0.7 * 0.7.
*
* skip: 0 1 2 or more
* |------------------^------------^----------------------------|
* portion: 0.3 0.7 * 0.3 0.7 * 0.7
* P (1-P)*P (1-P)^2
*
* We can continue to subdivide:
*
* skip >= 0: |------------------------------------------------- (1-P)^0 --|
* skip >= 1: | ------------------------------- (1-P)^1 --|
* skip >= 2: | ------------------ (1-P)^2 --|
* skip >= 3: | ^ ---------- (1-P)^3 --|
* skip >= 4: | . --- (1-P)^4 --|
* .
* ^X, see below
*
* In other words, the likelihood of the next n calls to |trial| returning
* false is (1-P)^n. The longer a run we require, the more the likelihood
* drops. Further calls may return false too, but this is the probability
* we'll skip at least n.
*
* This is interesting, because we can pick a point along this line segment
* and see which skip count's range it falls within; the point X above, for
* example, is within the ">= 2" range, but not within the ">= 3" range, so it
* designates a skip count of 2. So if we pick points on the line at random
* and use the skip counts they fall under, that will be indistinguishable
* from generating a fresh random number between 0 and 1 for each trial and
* comparing it to P.
*
* So to find the skip count for a point X, we must ask: To what whole power
* must we raise 1-P such that we include X, but the next power would exclude
* it? This is exactly std::floor(std::log(X) / std::log(1-P)).
*
* Our algorithm is then, simply: When constructed, compute an initial skip
* count. Return false from |trial| that many times, and then compute a new skip
* count.
*
* For a call to |trial(n)|, if the skip count is greater than n, return false
* and subtract n from the skip count. If the skip count is less than n,
* return true and compute a new skip count. Since each trial is independent,
* it doesn't matter by how much n overshoots the skip count; we can actually
* compute a new skip count at *any* time without affecting the distribution.
* This is really beautiful.
*/
public:
/**
* Construct a fast Bernoulli trial generator. Calls to |trial()| return true
* with probability |aProbability|. Use |aState0| and |aState1| to seed the
* random number generator; both may not be zero.
*/
FastBernoulliTrial(double aProbability, uint64_t aState0, uint64_t aState1)
: mGenerator(aState0, aState1)
{
setProbability(aProbability);
}
/**
* Return true with probability |mProbability|. Call this each time an event
* occurs, to decide whether to sample it or not. The lower |mProbability| is,
* the faster this function runs.
*/
bool trial() {
if (mSkipCount) {
mSkipCount--;
return false;
}
return chooseSkipCount();
}
/**
* Equivalent to calling trial() |n| times, and returning true if any of those
* calls do. However, like trial, this runs in fast constant time.
*
* What is this good for? In some applications, some events are "bigger" than
* others. For example, large allocations are more significant than small
* allocations. Perhaps we'd like to imagine that we're drawing allocations
* from a stream of bytes, and performing a separate Bernoulli trial on every
* byte from the stream. We can accomplish this by calling |t.trial(S)| for
* the number of bytes S, and sampling the event if that returns true.
*
* Of course, this style of sampling needs to be paired with analysis and
* presentation that makes the "size" of the event apparent, lest trials with
* large values for |n| appear to be indistinguishable from those with small
* values for |n|, despite being potentially much more likely to be sampled.
*/
bool trial(size_t aCount) {
if (mSkipCount > aCount) {
mSkipCount -= aCount;
return false;
}
return chooseSkipCount();
}
void setRandomState(uint64_t aState0, uint64_t aState1) {
mGenerator.setState(aState0, aState1);
}
void setProbability(double aProbability) {
MOZ_ASSERT(0 <= aProbability && aProbability <= 1);
mProbability = aProbability;
if (0 < mProbability && mProbability < 1) {
/*
* Let's look carefully at how this calculation plays out in floating-
* point arithmetic. We'll assume IEEE, but the final C++ code we arrive
* at would still be fine if our numbers were mathematically perfect. So,
* while we've considered IEEE's edge cases, we haven't done anything that
* should be actively bad when using other representations.
*
* (In the below, read comparisons as exact mathematical comparisons: when
* we say something "equals 1", that means it's exactly equal to 1. We
* treat approximation using intervals with open boundaries: saying a
* value is in (0,1) doesn't specify how close to 0 or 1 the value gets.
* When we use closed boundaries like [2**-53, 1], we're careful to ensure
* the boundary values are actually representable.)
*
* - After the comparison above, we know mProbability is in (0,1).
*
* - The gaps below 1 are 2**-53, so that interval is (0, 1-2**-53].
*
* - Because the floating-point gaps near 1 are wider than those near
* zero, there are many small positive doubles ε such that 1-ε rounds to
* exactly 1. However, 2**-53 can be represented exactly. So
* 1-mProbability is in [2**-53, 1].
*
* - log(1 - mProbability) is thus in (-37, 0].
*
* That range includes zero, but when we use mInvLogNotProbability, it
* would be helpful if we could trust that it's negative. So when log(1
* - mProbability) is 0, we'll just set mProbability to 0, so that
* mInvLogNotProbability is not used in chooseSkipCount.
*
* - How much of the range of mProbability does this cause us to ignore?
* The only value for which log returns 0 is exactly 1; the slope of log
* at 1 is 1, so for small ε such that 1 - ε != 1, log(1 - ε) is -ε,
* never 0. The gaps near one are larger than the gaps near zero, so if
* 1 - ε wasn't 1, then -ε is representable. So if log(1 - mProbability)
* isn't 0, then 1 - mProbability isn't 1, which means that mProbability
* is at least 2**-53, as discussed earlier. This is a sampling
* likelihood of roughly one in ten trillion, which is unlikely to be
* distinguishable from zero in practice.
*
* So by forbidding zero, we've tightened our range to (-37, -2**-53].
*
* - Finally, 1 / log(1 - mProbability) is in [-2**53, -1/37). This all
* falls readily within the range of an IEEE double.
*
* ALL THAT HAVING BEEN SAID: here are the five lines of actual code:
*/
double logNotProbability = std::log(1 - mProbability);
if (logNotProbability == 0.0)
mProbability = 0.0;
else
mInvLogNotProbability = 1 / logNotProbability;
}
chooseSkipCount();
}
private:
/* The likelihood that any given call to |trial| should return true. */
double mProbability;
/*
* The value of 1/std::log(1 - mProbability), cached for repeated use.
*
* If mProbability is exactly 0 or exactly 1, we don't use this value.
* Otherwise, we guarantee this value is in the range [-2**53, -1/37), i.e.
* definitely negative, as required by chooseSkipCount. See setProbability for
* the details.
*/
double mInvLogNotProbability;
/* Our random number generator. */
non_crypto::XorShift128PlusRNG mGenerator;
/* The number of times |trial| should return false before next returning true. */
size_t mSkipCount;
/*
* Choose the next skip count. This also returns the value that |trial| should
* return, since we have to check for the extreme values for mProbability
* anyway, and |trial| should never return true at all when mProbability is 0.
*/
bool chooseSkipCount() {
/*
* If the probability is 1.0, every call to |trial| returns true. Make sure
* mSkipCount is 0.
*/
if (mProbability == 1.0) {
mSkipCount = 0;
return true;
}
/*
* If the probabilility is zero, |trial| never returns true. Don't bother us
* for a while.
*/
if (mProbability == 0.0) {
mSkipCount = SIZE_MAX;
return false;
}
/*
* What sorts of values can this call to std::floor produce?
*
* Since mGenerator.nextDouble returns a value in [0, 1-2**-53], std::log
* returns a value in the range [-infinity, -2**-53], all negative. Since
* mInvLogNotProbability is negative (see its comments), the product is
* positive and possibly infinite. std::floor returns +infinity unchanged.
* So the result will always be positive.
*
* Converting a double to an integer that is out of range for that integer
* is undefined behavior, so we must clamp our result to SIZE_MAX, to ensure
* we get an acceptable value for mSkipCount.
*
* The clamp is written carefully. Note that if we had said:
*
* if (skipCount > SIZE_MAX)
* skipCount = SIZE_MAX;
*
* that leads to undefined behavior 64-bit machines: SIZE_MAX coerced to
* double is 2^64, not 2^64-1, so this doesn't actually set skipCount to a
* value that can be safely assigned to mSkipCount.
*
* Jakub Oleson cleverly suggested flipping the sense of the comparison: if
* we require that skipCount < SIZE_MAX, then because of the gaps (2048)
* between doubles at that magnitude, the highest double less than 2^64 is
* 2^64 - 2048, which is fine to store in a size_t.
*
* (On 32-bit machines, all size_t values can be represented exactly in
* double, so all is well.)
*/
double skipCount = std::floor(std::log(mGenerator.nextDouble())
* mInvLogNotProbability);
if (skipCount < SIZE_MAX)
mSkipCount = skipCount;
else
mSkipCount = SIZE_MAX;
return true;
}
};
} /* namespace mozilla */
#endif /* mozilla_FastBernoulliTrial_h */
@@ -1,23 +0,0 @@
Backport from upstream.
https://code.google.com/p/double-conversion/source/detail?r=4e24bb31bcc76d6d218f3056b4c24a109d367561
---
mfbt/double-conversion/utils.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/mfbt/double-conversion/utils.h
+++ b/mfbt/double-conversion/utils.h
@@ -58,11 +58,11 @@
defined(__mips__) || \
defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2) || \
- defined(_AARCH64EL_)
+ defined(__AARCH64EL__)
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
#if defined(_WIN32)
// Windows uses a 64bit wide floating point stack.
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
@@ -1,24 +0,0 @@
diff --git a/a/mfbt/double-conversion/strtod.cc b/inbound/mfbt/double-conversion/strtod.cc
index 9758989..97fa4a5 100644
--- a/a/mfbt/double-conversion/strtod.cc
+++ b/inbound/mfbt/double-conversion/strtod.cc
@@ -501,17 +501,19 @@ float Strtof(Vector<const char> buffer, int exponent) {
// if they would round to the same float. If the guess is not correct we have
// to look at four values (since two different doubles could be the correct
// double).
double double_next = Double(double_guess).NextDouble();
double double_previous = Double(double_guess).PreviousDouble();
float f1 = static_cast<float>(double_previous);
+#if defined(DEBUG)
float f2 = float_guess;
+#endif
float f3 = static_cast<float>(double_next);
float f4;
if (is_correct) {
f4 = f3;
} else {
double double_next2 = Double(double_next).NextDouble();
f4 = static_cast<float>(double_next2);
}
+1 -2
View File
@@ -506,9 +506,7 @@ float Strtof(Vector<const char> buffer, int exponent) {
double double_previous = Double(double_guess).PreviousDouble();
float f1 = static_cast<float>(double_previous);
#if defined(DEBUG)
float f2 = float_guess;
#endif
float f3 = static_cast<float>(double_next);
float f4;
if (is_correct) {
@@ -517,6 +515,7 @@ float Strtof(Vector<const char> buffer, int exponent) {
double double_next2 = Double(double_next).NextDouble();
f4 = static_cast<float>(double_next2);
}
(void) f2; // Mark variable as used.
ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
// If the guess doesn't lie near a single-precision boundary we can simply
-4
View File
@@ -21,7 +21,3 @@ patch -p3 < use-StandardInteger.patch
patch -p3 < use-mozilla-assertions.patch
patch -p3 < use-static_assert.patch
patch -p3 < ToPrecision-exponential.patch
patch -p3 < fix-gcc-warnings.patch
# Merged upstream, part of 2.0.1 version
patch -p3 < fix-aarch64-macro.patch
+5 -5
View File
@@ -60,7 +60,7 @@
defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
defined(__SH4__) || defined(__alpha__) || \
defined(_MIPS_ARCH_MIPS32R2) || \
defined(__AARCH64EL__)
defined(__AARCH64EL__) || defined(__aarch64__)
#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
#if defined(_WIN32)
@@ -141,8 +141,8 @@ template <typename T>
class Vector {
public:
Vector() : start_(NULL), length_(0) {}
Vector(T* data, int length) : start_(data), length_(length) {
ASSERT(length == 0 || (length > 0 && data != NULL));
Vector(T* data, int len) : start_(data), length_(len) {
ASSERT(len == 0 || (len > 0 && data != NULL));
}
// Returns a vector using the same backing storage as this one,
@@ -184,8 +184,8 @@ class Vector {
// buffer bounds on all operations in debug mode.
class StringBuilder {
public:
StringBuilder(char* buffer, int size)
: buffer_(buffer, size), position_(0) { }
StringBuilder(char* buffer, int buffer_size)
: buffer_(buffer, buffer_size), position_(0) { }
~StringBuilder() { if (!is_finalized()) Finalize(); }
+1
View File
@@ -39,6 +39,7 @@ EXPORTS.mozilla = [
'EnumeratedArray.h',
'EnumeratedRange.h',
'EnumSet.h',
'FastBernoulliTrial.h',
'FloatingPoint.h',
'Function.h',
'GuardObjects.h',
+209
View File
@@ -0,0 +1,209 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "mozilla/Assertions.h"
#include "mozilla/FastBernoulliTrial.h"
#include <math.h>
// Note that because we always provide FastBernoulliTrial with a fixed
// pseudorandom seed in these tests, the results here are completely
// deterministic.
//
// A non-optimized version of this test runs in .009s on my laptop. Using larger
// sample sizes lets us meet tighter bounds on the counts.
static void
TestProportions()
{
mozilla::FastBernoulliTrial bernoulli(1.0,
698079309544035222ULL,
6012389156611637584ULL);
for (size_t i = 0; i < 100; i++)
MOZ_RELEASE_ASSERT(bernoulli.trial());
{
bernoulli.setProbability(0.5);
size_t count = 0;
for (size_t i = 0; i < 1000; i++)
count += bernoulli.trial();
MOZ_RELEASE_ASSERT(count == 496);
}
{
bernoulli.setProbability(0.001);
size_t count = 0;
for (size_t i = 0; i < 1000; i++)
count += bernoulli.trial();
MOZ_RELEASE_ASSERT(count == 2);
}
{
bernoulli.setProbability(0.85);
size_t count = 0;
for (size_t i = 0; i < 1000; i++)
count += bernoulli.trial();
MOZ_RELEASE_ASSERT(count == 852);
}
bernoulli.setProbability(0.0);
for (size_t i = 0; i < 100; i++)
MOZ_RELEASE_ASSERT(!bernoulli.trial());
}
static void
TestHarmonics()
{
mozilla::FastBernoulliTrial bernoulli(0.1,
698079309544035222ULL,
6012389156611637584ULL);
const size_t n = 100000;
bool trials[n];
for (size_t i = 0; i < n; i++)
trials[i] = bernoulli.trial();
// For each harmonic and phase, check that the proportion sampled is
// within acceptable bounds.
for (size_t harmonic = 1; harmonic < 20; harmonic++) {
size_t expected = n / harmonic / 10;
size_t low_expected = expected * 85 / 100;
size_t high_expected = expected * 115 / 100;
for (size_t phase = 0; phase < harmonic; phase++) {
size_t count = 0;
for (size_t i = phase; i < n; i += harmonic)
count += trials[i];
MOZ_RELEASE_ASSERT(low_expected <= count && count <= high_expected);
}
}
}
static void
TestTrialN()
{
mozilla::FastBernoulliTrial bernoulli(0.01,
0x67ff17e25d855942ULL,
0x74f298193fe1c5b1ULL);
{
size_t count = 0;
for (size_t i = 0; i < 10000; i++)
count += bernoulli.trial(1);
// Expected value: 0.01 * 10000 == 100
MOZ_RELEASE_ASSERT(count == 97);
}
{
size_t count = 0;
for (size_t i = 0; i < 10000; i++)
count += bernoulli.trial(3);
// Expected value: (1 - (1 - 0.01) ** 3) == 0.0297,
// 0.0297 * 10000 == 297
MOZ_RELEASE_ASSERT(count == 304);
}
{
size_t count = 0;
for (size_t i = 0; i < 10000; i++)
count += bernoulli.trial(10);
// Expected value: (1 - (1 - 0.01) ** 10) == 0.0956,
// 0.0956 * 10000 == 956
MOZ_RELEASE_ASSERT(count == 936);
}
{
size_t count = 0;
for (size_t i = 0; i < 10000; i++)
count += bernoulli.trial(100);
// Expected value: (1 - (1 - 0.01) ** 100) == 0.6339
// 0.6339 * 10000 == 6339
MOZ_RELEASE_ASSERT(count == 6372);
}
{
size_t count = 0;
for (size_t i = 0; i < 10000; i++)
count += bernoulli.trial(1000);
// Expected value: (1 - (1 - 0.01) ** 1000) == 0.9999
// 0.9999 * 10000 == 9999
MOZ_RELEASE_ASSERT(count == 9998);
}
}
static void
TestChangeProbability()
{
mozilla::FastBernoulliTrial bernoulli(1.0,
0x67ff17e25d855942ULL,
0x74f298193fe1c5b1ULL);
// Establish a very high skip count.
bernoulli.setProbability(0.0);
// This should re-establish a zero skip count.
bernoulli.setProbability(1.0);
// So this should return true.
MOZ_RELEASE_ASSERT(bernoulli.trial());
}
static void
TestCuspProbabilities()
{
/*
* FastBernoulliTrial takes care to avoid screwing up on edge cases. The
* checks here all look pretty dumb, but they exercise paths in the code that
* could exhibit undefined behavior if coded naïvely.
*/
/*
* This should not be perceptibly different from 1; for 64-bit doubles, this
* is a one in ten trillion chance of the trial not succeeding. Overflows
* converting doubles to size_t skip counts may change this, though.
*/
mozilla::FastBernoulliTrial bernoulli(nextafter(1, 0),
0x67ff17e25d855942ULL,
0x74f298193fe1c5b1ULL);
for (size_t i = 0; i < 1000; i++)
MOZ_RELEASE_ASSERT(bernoulli.trial());
/*
* This should not be perceptibly different from 0; for 64-bit doubles,
* the FastBernoulliTrial will actually treat this as exactly zero.
*/
bernoulli.setProbability(nextafter(0, 1));
for (size_t i = 0; i < 1000; i++)
MOZ_RELEASE_ASSERT(!bernoulli.trial());
/*
* This should be a vanishingly low probability which FastBernoulliTrial does
* *not* treat as exactly zero.
*/
bernoulli.setProbability(1 - nextafter(1, 0));
for (size_t i = 0; i < 1000; i++)
MOZ_RELEASE_ASSERT(!bernoulli.trial());
}
int
main()
{
TestProportions();
TestHarmonics();
TestTrialN();
TestChangeProbability();
TestCuspProbabilities();
return 0;
}
+1
View File
@@ -16,6 +16,7 @@ CppUnitTests([
'TestCountZeroes',
'TestEndian',
'TestEnumSet',
'TestFastBernoulliTrial',
'TestFloatingPoint',
'TestFunction',
'TestInitializerList',
@@ -60,8 +60,6 @@ nsresult nsDeflateConverter::Init()
return NS_OK;
}
/* nsIInputStream convert (in nsIInputStream aFromStream, in string aFromType
* in string aToType, in nsISupports aCtxt); */
NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream,
const char *aFromType,
const char *aToType,
@@ -71,9 +69,6 @@ NS_IMETHODIMP nsDeflateConverter::Convert(nsIInputStream *aFromStream,
return NS_ERROR_NOT_IMPLEMENTED;
}
/* void asyncConvertData (in string aFromType, in string aToType,
* in nsIStreamListener aListener,
* in nsISupports aCtxt); */
NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char *aFromType,
const char *aToType,
nsIStreamListener *aListener,
@@ -100,10 +95,6 @@ NS_IMETHODIMP nsDeflateConverter::AsyncConvertData(const char *aFromType,
return rv;
}
/* void onDataAvailable (in nsIRequest aRequest, in nsISupports aContext,
* in nsIInputStream aInputStream,
* in unsigned long long aOffset,
* in unsigned long aCount); */
NS_IMETHODIMP nsDeflateConverter::OnDataAvailable(nsIRequest *aRequest,
nsISupports *aContext,
nsIInputStream *aInputStream,
@@ -148,8 +139,6 @@ NS_IMETHODIMP nsDeflateConverter::OnStartRequest(nsIRequest *aRequest,
return mListener->OnStartRequest(aRequest, mContext);
}
/* void onStopRequest (in nsIRequest aRequest, in nsISupports aContext,
* in nsresult aStatusCode); */
NS_IMETHODIMP nsDeflateConverter::OnStopRequest(nsIRequest *aRequest,
nsISupports *aContext,
nsresult aStatusCode)

Some files were not shown because too many files have changed in this diff Show More