Merge inbound to m-c.

This commit is contained in:
Ryan VanderMeulen 2014-04-15 12:25:27 -04:00
commit 0d4470969a
69 changed files with 1018 additions and 662 deletions

View File

@ -814,7 +814,7 @@ class Automation(object):
xrePath = None, certPath = None,
debuggerInfo = None, symbolsPath = None,
timeout = -1, maxTime = None, onLaunch = None,
webapprtChrome = False, hide_subtests=None):
webapprtChrome = False, hide_subtests=None, screenshotOnFail=False):
"""
Run the app, log the duration it took to execute, return the status code.
Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.

View File

@ -51,10 +51,6 @@ enum {
// bit is set, and if so it indicates whether we're only whitespace or
// not.
NS_TEXT_IS_ONLY_WHITESPACE = DATA_NODE_FLAG_BIT(3),
// This bit is set to indicate that we must create frames for this text node
// even if it's only whitespace next to a block boundary.
NS_CREATE_FRAME_FOR_IGNORABLE_WHITESPACE = DATA_NODE_FLAG_BIT(4)
};
// Make sure we have enough space for those bits

View File

@ -2751,8 +2751,10 @@ GetTextFrameForContent(nsIContent* aContent)
{
nsIPresShell* presShell = aContent->OwnerDoc()->GetShell();
if (presShell) {
nsIFrame* frame = presShell->FrameConstructor()->EnsureFrameForTextNode(
presShell->FrameConstructor()->EnsureFrameForTextNode(
static_cast<nsGenericDOMDataNode*>(aContent));
aContent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
nsIFrame* frame = aContent->GetPrimaryFrame();
if (frame && frame->GetType() == nsGkAtoms::textFrame) {
return static_cast<nsTextFrame*>(frame);
}
@ -2804,7 +2806,7 @@ static void CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
return;
}
aStartParent->GetCurrentDoc()->FlushPendingNotifications(Flush_Layout);
aStartParent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
// Recheck whether we're still in the document
if (!aStartParent->IsInDoc()) {

View File

@ -26,7 +26,7 @@
#define MAX_DROPPED_FRAMES 25
// Try not to spend more than this much time in a single call to DecodeVideoFrame.
#define MAX_VIDEO_DECODE_SECONDS 3.0
#define MAX_VIDEO_DECODE_SECONDS 0.1
using namespace mozilla::gfx;
using namespace android;

View File

@ -8,7 +8,7 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
* Code below is vtt.js the JS WebVTT implementation.
* Current source code can be found at http://github.com/mozilla/vtt.js
*
* Code taken from commit 2edc263af6003d539eb2ce442d6102e5d8b75fb5
* Code taken from commit 65ae2daaf6ec7e710f591214893bb03d8b7a94b5
*/
/**
* Copyright 2013 vtt.js Contributors
@ -129,8 +129,7 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
// Accept a setting if its a valid (signed) integer.
integer: function(k, v) {
if (/^-?\d+$/.test(v)) { // integer
// Only take values in the range of -1000 ~ 1000
this.set(k, Math.min(Math.max(parseInt(v, 10), -1000), 1000));
this.set(k, parseInt(v, 10));
}
},
// Accept a setting if its a valid percentage.
@ -810,8 +809,6 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
// compute things with such as if it overlaps or intersects with another Element.
// Can initialize it with either a StyleBox or another BoxPosition.
function BoxPosition(obj) {
var self = this;
// Either a BoxPosition was passed in and we need to copy it, or a StyleBox
// was passed in and we need to copy the results of 'getBoundingClientRect'
// as the object returned is readonly. All co-ordinate values are in reference
@ -837,26 +834,27 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
this.lineHeight = lh !== undefined ? lh : obj.lineHeight;
}
// Move the box along a particular axis. If no amount to move is passed, via
// the val parameter, then the default amount is the line height of the box.
BoxPosition.prototype.move = function(axis, val) {
val = val !== undefined ? val : this.lineHeight;
// Move the box along a particular axis. Optionally pass in an amount to move
// the box. If no amount is passed then the default is the line height of the
// box.
BoxPosition.prototype.move = function(axis, toMove) {
toMove = toMove !== undefined ? toMove : this.lineHeight;
switch (axis) {
case "+x":
this.left += val;
this.right += val;
this.left += toMove;
this.right += toMove;
break;
case "-x":
this.left -= val;
this.right -= val;
this.left -= toMove;
this.right -= toMove;
break;
case "+y":
this.top += val;
this.bottom += val;
this.top += toMove;
this.bottom += toMove;
break;
case "-y":
this.top -= val;
this.bottom -= val;
this.top -= toMove;
this.bottom -= toMove;
break;
}
};
@ -981,12 +979,6 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
return bestPosition || specifiedPosition;
}
function reverseAxis(axis) {
return axis.map(function(a) {
return a.indexOf("+") !== -1 ? a.replace("+", "-") : a.replace("-", "+");
});
}
var boxPosition = new BoxPosition(styleBox),
cue = styleBox.cue,
linePos = computeLinePos(cue),
@ -994,32 +986,47 @@ this.EXPORTED_SYMBOLS = ["WebVTT"];
// If we have a line number to align the cue to.
if (cue.snapToLines) {
var size;
switch (cue.vertical) {
case "":
axis = [ "+y", "-y" ];
size = "height";
break;
case "rl":
axis = [ "+x", "-x" ];
size = "width";
break;
case "lr":
axis = [ "-x", "+x" ];
size = "width";
break;
}
var step = boxPosition.lineHeight,
position = step * Math.round(linePos),
maxPosition = containerBox[size] + step,
initialAxis = axis[0];
// If the specified intial position is greater then the max position then
// clamp the box to the amount of steps it would take for the box to
// reach the max position.
if (Math.abs(position) > maxPosition) {
position = position < 0 ? -1 : 1;
position *= Math.ceil(maxPosition / step) * step;
}
// If computed line position returns negative then line numbers are
// relative to the bottom of the video instead of the top. Therefore, we
// need to increase our initial position by the length or width of the
// video, depending on the writing direction, and reverse our axis directions.
var initialPosition = boxPosition.lineHeight * Math.floor(linePos + 0.5),
initialAxis = axis[0];
if (linePos < 0) {
initialPosition += cue.vertical === "" ? containerBox.height : containerBox.width;
axis = reverseAxis(axis);
position += cue.vertical === "" ? containerBox.height : containerBox.width;
axis = axis.reverse();
}
// Move the box to the specified position. This may not be its best
// position.
boxPosition.move(initialAxis, initialPosition);
boxPosition.move(initialAxis, position);
} else {
// If we have a percentage line value for the cue.

View File

@ -127,7 +127,9 @@ NS_IMETHODIMP_(bool)
SVGMaskElement::IsAttributeMapped(const nsIAtom* name) const
{
static const MappedAttributeEntry* const map[] = {
sColorMap,
sFEFloodMap,
sFillStrokeMap,
sFiltersMap,
sFontSpecificationMap,
sGradientStopMap,

View File

@ -138,10 +138,13 @@ NS_IMETHODIMP_(bool)
SVGPatternElement::IsAttributeMapped(const nsIAtom* name) const
{
static const MappedAttributeEntry* const map[] = {
sColorMap,
sFEFloodMap,
sFillStrokeMap,
sFiltersMap,
sFontSpecificationMap,
sGradientStopMap,
sGraphicsMap,
sLightingEffectsMap,
sMarkersMap,
sTextContentElementsMap,

View File

@ -120,7 +120,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=826058
app.ondownloadapplied = app.ondownloadavailable = null;
continueTest();
};
app.checkForUpdate();
request = app.checkForUpdate();
request.onerror = mozAppsError;
request.onsuccess = function() {
ok(true, "Got onsuccess");
continueTest();
};
yield undefined;
yield undefined;
icons = app.manifest.icons;

View File

@ -939,6 +939,20 @@ TabChild::Init()
NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);
webProgress->AddProgressListener(this, nsIWebProgress::NOTIFY_LOCATION);
// Few lines before, baseWindow->Create() will end up creating a new
// window root in nsGlobalWindow::SetDocShell.
// Then this chrome event handler, will be inherited to inner windows.
// We want to also set it to the docshell so that inner windows
// and any code that has access to the docshell
// can all listen to the same chrome event handler.
// XXX: ideally, we would set a chrome event handler earlier,
// and all windows, even the root one, will use the docshell one.
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(WebNavigation());
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsCOMPtr<EventTarget> chromeHandler =
do_QueryInterface(window->GetChromeEventHandler());
docShell->SetChromeEventHandler(chromeHandler);
return NS_OK;
}

View File

@ -1,2 +1,3 @@
[test_NuwaProcessCreation.html]
run-if = toolkit == 'gonk'
[test_child_docshell.html]

View File

@ -0,0 +1,85 @@
<!DOCTYPE HTML>
<html>
<!--
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7">
"use strict";
SimpleTest.waitForExplicitFinish();
SpecialPowers.addPermission("browser", true, document);
SpecialPowers.pushPrefEnv({'set':[
["dom.mozBrowserFramesEnabled", true],
["dom.ipc.tabs.disabled", false]
]}, function () {
var iframe = document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
iframe.setAttribute("remote", "true");
SpecialPowers.wrap(iframe).mozbrowser = true;
document.documentElement.appendChild(iframe);
var mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
mm.addMessageListener("chromeEventHandler", function (msg) {
msg = SpecialPowers.wrap(msg);
var result = msg.json;
is(result.processType, SpecialPowers.Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT,
"The frame script is running in a real distinct child process");
ok(result.hasCorrectInterface,
"docshell.chromeEventHandler has nsIDOMEventTarget interface");
});
mm.addMessageListener("DOMWindowCreatedReceived", function (msg) {
msg = SpecialPowers.wrap(msg);
ok(true, "the chrome event handler looks functional");
var result = msg.json;
ok(result.stableChromeEventHandler, "docShell.chromeEventHandler is stable");
ok(result.iframeHasNewDocShell, "iframe spawns a new docShell");
ok(result.iframeHasSameChromeEventHandler, "but iframe has the same chrome event handler");
SimpleTest.finish();
});
// Inject a frame script in the child process:
mm.loadFrameScript('data:,new ' + function ContentScriptScope() {
var processType = Components.classes["@mozilla.org/xre/runtime;1"]
.getService(Components.interfaces.nsIXULRuntime)
.processType;
var chromeEventHandler = docShell.chromeEventHandler;
sendAsyncMessage("chromeEventHandler", {
processType: Services.appinfo.processType,
hasCorrectInterface: chromeEventHandler instanceof Components.interfaces.nsIDOMEventTarget
});
/*
Ensure that this chromeEventHandler actually works,
by creating a new window and listening for its DOMWindowCreated event
*/
chromeEventHandler.addEventListener("DOMWindowCreated", function listener(evt) {
if (evt.target == content.document) {
return;
}
chromeEventHandler.removeEventListener("DOMWindowCreated", listener);
let new_win = evt.target.defaultView;
let new_docShell = new_win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
sendAsyncMessage("DOMWindowCreatedReceived", {
stableChromeEventHandler: chromeEventHandler === docShell.chromeEventHandler,
iframeHasNewDocShell: new_docShell !== docShell,
iframeHasSameChromeEventHandler: new_docShell.chromeEventHandler === chromeEventHandler
});
});
let i = content.document.createElement("iframe");
i.setAttribute("src", "data:text/html,foo");
content.document.documentElement.appendChild(i);
}, false);
});
</script>
</body>
</html>

View File

@ -8,7 +8,7 @@
#include "nsWebBrowser.h"
#include "nsDocShellTreeOwner.h"
#include "nsIAllocator.h"
#include "nsMemory.h"
#include "nsPIDOMWindow.h"
nsCommandHandler::nsCommandHandler() :
@ -118,7 +118,7 @@ NS_IMETHODIMP nsCommandHandler::Exec(const char *aCommand, const char *aStatus,
// Return an empty string
const char szEmpty[] = "";
*aResult = (char *) nsAllocator::Clone(szEmpty, sizeof(szEmpty));
*aResult = (char *) nsMemory::Clone(szEmpty, sizeof(szEmpty));
return NS_OK;
}
@ -141,7 +141,7 @@ NS_IMETHODIMP nsCommandHandler::Query(const char *aCommand, const char *aStatus,
// Return an empty string
const char szEmpty[] = "";
*aResult = (char *) nsAllocator::Clone(szEmpty, sizeof(szEmpty));
*aResult = (char *) nsMemory::Clone(szEmpty, sizeof(szEmpty));
return NS_OK;
}

View File

@ -48,63 +48,11 @@
*/
#include "mozilla/mozalloc.h"
#include "mozHunspellAllocator.h"
extern void HunspellReportMemoryAllocation(void*);
extern void HunspellReportMemoryDeallocation(void*);
inline void* hunspell_malloc(size_t size)
{
void* result = moz_malloc(size);
HunspellReportMemoryAllocation(result);
return result;
}
#define malloc(size) hunspell_malloc(size)
inline void* hunspell_calloc(size_t count, size_t size)
{
void* result = moz_calloc(count, size);
HunspellReportMemoryAllocation(result);
return result;
}
#define calloc(count, size) hunspell_calloc(count, size)
inline void hunspell_free(void* ptr)
{
HunspellReportMemoryDeallocation(ptr);
moz_free(ptr);
}
#define free(ptr) hunspell_free(ptr)
inline void* hunspell_realloc(void* ptr, size_t size)
{
HunspellReportMemoryDeallocation(ptr);
void* result = moz_realloc(ptr, size);
if (result) {
HunspellReportMemoryAllocation(result);
} else {
// realloc failed; undo the HunspellReportMemoryDeallocation from above
HunspellReportMemoryAllocation(ptr);
}
return result;
}
#define realloc(ptr, size) hunspell_realloc(ptr, size)
inline char* hunspell_strdup(const char* str)
{
char* result = moz_strdup(str);
HunspellReportMemoryAllocation(result);
return result;
}
#define strdup(str) hunspell_strdup(str)
#if defined(HAVE_STRNDUP)
inline char* hunspell_strndup(const char* str, size_t size)
{
char* result = moz_strndup(str, size);
HunspellReportMemoryAllocation(result);
return result;
}
#define strndup(str, size) hunspell_strndup(str, size)
#endif
#define malloc(size) HunspellAllocator::CountingMalloc(size)
#define calloc(count, size) HunspellAllocator::CountingCalloc(count, size)
#define free(ptr) HunspellAllocator::CountingFree(ptr)
#define realloc(ptr, size) HunspellAllocator::CountingRealloc(ptr, size)
#endif

View File

@ -96,22 +96,14 @@ NS_IMPL_CYCLE_COLLECTION_3(mozHunspell,
mEncoder,
mDecoder)
int64_t mozHunspell::sAmount = 0;
// WARNING: hunspell_alloc_hooks.h uses these two functions.
void HunspellReportMemoryAllocation(void* ptr) {
mozHunspell::OnAlloc(ptr);
}
void HunspellReportMemoryDeallocation(void* ptr) {
mozHunspell::OnFree(ptr);
}
template<> mozilla::Atomic<size_t> mozilla::CountingAllocatorBase<HunspellAllocator>::sAmount(0);
mozHunspell::mozHunspell()
: mHunspell(nullptr)
{
#ifdef DEBUG
// There must be only one instance of this class, due to |sAmount|
// being static.
// There must be only one instance of this class: it reports memory based on
// a single static count in HunspellAllocator.
static bool hasRun = false;
MOZ_ASSERT(!hasRun);
hasRun = true;

View File

@ -73,6 +73,7 @@
#include "nsInterfaceHashtable.h"
#include "nsWeakReference.h"
#include "nsCycleCollectionParticipant.h"
#include "mozHunspellAllocator.h"
#define MOZ_HUNSPELL_CONTRACTID "@mozilla.org/spellchecker/engine;1"
#define MOZ_HUNSPELL_CID \
@ -101,17 +102,11 @@ public:
// helper method for converting a word to the charset of the dictionary
nsresult ConvertCharset(const char16_t* aStr, char ** aDst);
MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
static void OnAlloc(void* ptr) { sAmount += MallocSizeOfOnAlloc(ptr); }
static void OnFree (void* ptr) { sAmount -= MallocSizeOfOnFree (ptr); }
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData)
{
return MOZ_COLLECT_REPORT(
"explicit/spell-check", KIND_HEAP, UNITS_BYTES, sAmount,
"explicit/spell-check", KIND_HEAP, UNITS_BYTES, HunspellAllocator::MemoryAllocated(),
"Memory used by the spell-checking engine.");
}
@ -131,8 +126,6 @@ protected:
nsCOMArray<nsIFile> mDynamicDirectories;
Hunspell *mHunspell;
static int64_t sAmount;
};
#endif

View File

@ -0,0 +1,16 @@
/* -*- 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 mozHunspellAllocator_h__
#define mozHunspellAllocator_h__
#include "nsIMemoryReporter.h"
class HunspellAllocator : public mozilla::CountingAllocatorBase<HunspellAllocator>
{
};
#endif

View File

@ -309,8 +309,15 @@ DrawTargetSkia::DrawSurface(SourceSurface *aSurface,
const DrawSurfaceOptions &aSurfOptions,
const DrawOptions &aOptions)
{
RefPtr<SourceSurface> dataSurface;
if (!(aSurface->GetType() == SurfaceType::SKIA || aSurface->GetType() == SurfaceType::DATA)) {
return;
dataSurface = aSurface->GetDataSurface();
if (!dataSurface) {
gfxDebug() << *this << ": DrawSurface() can't draw surface";
return;
}
aSurface = dataSurface.get();
}
if (aSource.IsEmpty()) {

View File

@ -331,6 +331,10 @@ static void ReleaseImageClientNow(ImageClient* aClient)
// static
void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient)
{
if (!IsCreated()) {
return;
}
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&ReleaseImageClientNow, aClient));
@ -345,6 +349,10 @@ static void ReleaseTextureClientNow(TextureClient* aClient)
// static
void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient)
{
if (!IsCreated()) {
return;
}
sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
FROM_HERE,
NewRunnableFunction(&ReleaseTextureClientNow, aClient));
@ -364,6 +372,10 @@ static void UpdateImageClientNow(ImageClient* aClient, ImageContainer* aContaine
void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient,
ImageContainer* aContainer)
{
if (!IsCreated()) {
return;
}
if (InImageBridgeChildThread()) {
UpdateImageClientNow(aClient, aContainer);
return;
@ -388,6 +400,10 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer,
//static
void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer, bool aExceptFront)
{
if (!IsCreated()) {
return;
}
if (InImageBridgeChildThread()) {
FlushAllImagesNow(aClient, aContainer, aExceptFront);
return;
@ -577,15 +593,14 @@ bool ImageBridgeChild::StartUpOnThread(Thread* aThread)
void ImageBridgeChild::DestroyBridge()
{
if (!IsCreated()) {
return;
}
NS_ABORT_IF_FALSE(!InImageBridgeChildThread(),
"This method must not be called in this thread.");
// ...because we are about to dispatch synchronous messages to the
// ImageBridgeChild thread.
if (!IsCreated()) {
return;
}
ReentrantMonitor barrier("ImageBridgeDestroyTask lock");
ReentrantMonitorAutoEnter autoMon(barrier);
@ -607,7 +622,8 @@ void ImageBridgeChild::DestroyBridge()
bool InImageBridgeChildThread()
{
return sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
return ImageBridgeChild::IsCreated() &&
sImageBridgeChildThread->thread_id() == PlatformThread::CurrentId();
}
MessageLoop * ImageBridgeChild::GetMessageLoop() const

View File

@ -40,67 +40,40 @@ using namespace mozilla::gfx;
static FT_Library gPlatformFTLibrary = nullptr;
class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter
class FreetypeReporter MOZ_FINAL : public nsIMemoryReporter,
public CountingAllocatorBase<FreetypeReporter>
{
public:
NS_DECL_ISUPPORTS
FreetypeReporter()
static void* Malloc(FT_Memory, long size)
{
#ifdef DEBUG
// There must be only one instance of this class, due to |sAmount|
// being static.
static bool hasRun = false;
MOZ_ASSERT(!hasRun);
hasRun = true;
#endif
return CountingMalloc(size);
}
MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
static void* CountingAlloc(FT_Memory, long size)
static void Free(FT_Memory, void* p)
{
void *p = malloc(size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
}
static void CountingFree(FT_Memory, void* p)
{
sAmount -= MallocSizeOfOnFree(p);
free(p);
return CountingFree(p);
}
static void*
CountingRealloc(FT_Memory, long cur_size, long new_size, void* p)
Realloc(FT_Memory, long cur_size, long new_size, void* p)
{
sAmount -= MallocSizeOfOnFree(p);
void *pnew = realloc(p, new_size);
if (pnew) {
sAmount += MallocSizeOfOnAlloc(pnew);
} else {
// realloc failed; undo the decrement from above
sAmount += MallocSizeOfOnAlloc(p);
}
return pnew;
return CountingRealloc(p, new_size);
}
NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData)
{
return MOZ_COLLECT_REPORT(
"explicit/freetype", KIND_HEAP, UNITS_BYTES, sAmount,
"explicit/freetype", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
"Memory used by Freetype.");
}
private:
static int64_t sAmount;
};
NS_IMPL_ISUPPORTS1(FreetypeReporter, nsIMemoryReporter)
int64_t FreetypeReporter::sAmount = 0;
template<> Atomic<size_t> CountingAllocatorBase<FreetypeReporter>::sAmount(0);
static FT_MemoryRec_ sFreetypeMemoryRecord;
@ -108,9 +81,9 @@ gfxAndroidPlatform::gfxAndroidPlatform()
{
// A custom allocator. It counts allocations, enabling memory reporting.
sFreetypeMemoryRecord.user = nullptr;
sFreetypeMemoryRecord.alloc = FreetypeReporter::CountingAlloc;
sFreetypeMemoryRecord.free = FreetypeReporter::CountingFree;
sFreetypeMemoryRecord.realloc = FreetypeReporter::CountingRealloc;
sFreetypeMemoryRecord.alloc = FreetypeReporter::Malloc;
sFreetypeMemoryRecord.free = FreetypeReporter::Free;
sFreetypeMemoryRecord.realloc = FreetypeReporter::Realloc;
// These two calls are equivalent to FT_Init_FreeType(), but allow us to
// provide a custom memory allocator.

View File

@ -491,12 +491,6 @@ gfxPlatform::Shutdown()
mozilla::gl::GLContextProviderEGL::Shutdown();
#endif
// This will block this thread untill the ImageBridge protocol is completely
// deleted.
ImageBridgeChild::ShutDown();
CompositorParent::ShutDown();
delete gGfxPlatformPrefsLock;
gfxPrefs::DestroySingleton();
@ -749,7 +743,6 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
}
}
bool dependsOnData = false;
if (!srcBuffer) {
nsRefPtr<gfxImageSurface> imgSurface = aSurface->GetAsImageSurface();
@ -803,10 +796,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
if (copy) {
srcBuffer = copy;
} else {
srcBuffer = Factory::CreateWrappingDataSourceSurface(imgSurface->Data(),
imgSurface->Stride(),
size, format);
dependsOnData = true;
return GetWrappedDataSourceSurface(aSurface);
}
}
@ -814,39 +804,55 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
return nullptr;
}
if (!dependsOnData) {
#if MOZ_TREE_CAIRO
cairo_surface_t *nullSurf =
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_surface_set_user_data(nullSurf,
&kSourceSurface,
imgSurface,
nullptr);
cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
cairo_surface_destroy(nullSurf);
cairo_surface_t *nullSurf =
cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
cairo_surface_set_user_data(nullSurf,
&kSourceSurface,
imgSurface,
nullptr);
cairo_surface_attach_snapshot(imgSurface->CairoSurface(), nullSurf, SourceSnapshotDetached);
cairo_surface_destroy(nullSurf);
#else
cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
cairo_surface_set_mime_data(imgSurface->CairoSurface(), "mozilla/magic", (const unsigned char*) "data", 4, SourceSnapshotDetached, imgSurface.get());
#endif
}
}
if (dependsOnData) {
// If we wrapped the underlying data of aSurface, then we need to add user data
// to make sure aSurface stays alive until we are done with the data.
DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
srcSurfUD->mSurface = aSurface;
srcBuffer->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
} else {
// Otherwise add user data to aSurface so we can cache lookups in the future.
SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
srcSurfUD->mBackendType = aTarget->GetType();
srcSurfUD->mSrcSurface = srcBuffer;
aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
}
// Add user data to aSurface so we can cache lookups in the future.
SourceSurfaceUserData *srcSurfUD = new SourceSurfaceUserData;
srcSurfUD->mBackendType = aTarget->GetType();
srcSurfUD->mSrcSurface = srcBuffer;
aSurface->SetData(&kSourceSurface, srcSurfUD, SourceBufferDestroy);
return srcBuffer;
}
RefPtr<DataSourceSurface>
gfxPlatform::GetWrappedDataSourceSurface(gfxASurface* aSurface)
{
nsRefPtr<gfxImageSurface> image = aSurface->GetAsImageSurface();
if (!image) {
return nullptr;
}
RefPtr<DataSourceSurface> result =
Factory::CreateWrappingDataSourceSurface(image->Data(),
image->Stride(),
ToIntSize(image->GetSize()),
ImageFormatToSurfaceFormat(image->Format()));
if (!result) {
return nullptr;
}
// If we wrapped the underlying data of aSurface, then we need to add user data
// to make sure aSurface stays alive until we are done with the data.
DependentSourceSurfaceUserData *srcSurfUD = new DependentSourceSurfaceUserData;
srcSurfUD->mSurface = aSurface;
result->AddUserData(&kThebesSurface, srcSurfUD, SourceSurfaceDestroyed);
return result;
}
TemporaryRef<ScaledFont>
gfxPlatform::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
{

View File

@ -45,6 +45,7 @@ class SkiaGLGlue;
namespace gfx {
class DrawTarget;
class SourceSurface;
class DataSourceSurface;
class ScaledFont;
class DrawEventRecorder;
@ -221,6 +222,9 @@ public:
static void ClearSourceSurfaceForSurface(gfxASurface *aSurface);
static mozilla::RefPtr<mozilla::gfx::DataSourceSurface>
GetWrappedDataSourceSurface(gfxASurface *aSurface);
virtual mozilla::TemporaryRef<mozilla::gfx::ScaledFont>
GetScaledFontForFont(mozilla::gfx::DrawTarget* aTarget, gfxFont *aFont);

View File

@ -73,6 +73,10 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len);
#define INITIAL_PROTECTION_FLAGS (PROT_READ | PROT_WRITE | PROT_EXEC)
#endif
namespace JSC {
enum CodeKind { ION_CODE = 0, BASELINE_CODE, REGEXP_CODE, OTHER_CODE };
}
#if ENABLE_ASSEMBLER
//#define DEBUG_STRESS_JSC_ALLOCATOR
@ -85,8 +89,6 @@ namespace JSC {
class ExecutableAllocator;
enum CodeKind { ION_CODE = 0, BASELINE_CODE, REGEXP_CODE, OTHER_CODE };
// These are reference-counted. A new one starts with a count of 1.
class ExecutablePool {

View File

@ -0,0 +1,15 @@
if (!getBuildConfiguration().parallelJS)
quit(0);
test([0], "map", function (... Object) {
var x = [];
for (var i = 0; i < 10; i++) {
x[i] = {};
}
});
function test(arr, op, func) {
for (var i = 0; i < 1000; i++) {
arr[op + "Par"].apply(arr, [func, undefined]);
}
}

View File

@ -482,6 +482,8 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
AutoValueVector &startFrameFormals, MutableHandleFunction nextCallee,
jsbytecode **callPC, const ExceptionBailoutInfo *excInfo)
{
MOZ_ASSERT(script->hasBaselineScript());
// If excInfo is non-nullptr, we are bailing out to a catch or finally block
// and this is the frame where we will resume. Usually the expression stack
// should be empty in this case but there can be iterators on the stack.
@ -1544,6 +1546,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
if (iter.isBaselineJS()) {
BaselineFrame *frame = iter.baselineFrame();
MOZ_ASSERT(frame->script()->hasBaselineScript());
// If the frame doesn't even have a scope chain set yet, then it's resuming
// into the the prologue before the scope chain is initialized. Any

View File

@ -1594,6 +1594,7 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
// Read the initial frame out of the C stack.
callee_ = frame_->maybeCallee();
script_ = frame_->script();
MOZ_ASSERT(script_->hasBaselineScript());
// Settle on the outermost frame without evaluating any instructions before
// looking for a pc.
@ -1652,6 +1653,7 @@ InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
// for the executed script, if they are clones. The actual script
// exists though, just make sure the function points to it.
script_ = callee_->existingScript();
MOZ_ASSERT(script_->hasBaselineScript());
pc_ = script_->offsetToPC(si_.pcOffset());
}

View File

@ -113,7 +113,7 @@ class Registers
return Names[code];
}
static const char *GetName(uint32_t i) {
MOZ_ASSERT(i < Total);
JS_ASSERT(i < Total);
return GetName(Code(i));
}
@ -191,38 +191,62 @@ class Registers
typedef uint32_t PackedRegisterMask;
// MIPS32 uses pairs of even and odd float registers as double precision
// registers. Example: f0 (double) is composed of f0 and f1 (single).
// This port only uses even registers to avoid allocation problems.
// MIPS32 can have two types of floating-point coprocessors:
// - 32 bit floating-point coprocessor - In this case, there are 32 single
// precision registers and pairs of even and odd float registers are used as
// double precision registers. Example: f0 (double) is composed of
// f0 and f1 (single).
// - 64 bit floating-point coprocessor - In this case, there are 32 double
// precision register which can also be used as single precision registers.
// When using O32 ABI, floating-point coprocessor is 32 bit
// When using N32 ABI, floating-point coprocessor is 64 bit.
class FloatRegisters
{
public:
enum FPRegisterID {
f0 = 0, // f0, f2 - Return values
f0 = 0,
f1,
f2,
f4, // f4 - f10, f16, f18 - Temporaries
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f12, // f12, f14 - Arguments
f11,
f12,
f13,
f14,
f15,
f16,
f17,
f18,
f20, // f20 - f30 - Saved registers
f19,
f20,
f21,
f22,
f23,
f24,
f25,
f26,
f27,
f28,
f29,
f30,
f31,
invalid_freg
};
typedef FPRegisterID Code;
static const char *GetName(Code code) {
static const char * const Names[] = { "f0", "f2", "f4", "f6",
"f8", "f10", "f12", "f14",
"f16", "f18", "f20", "f22",
"f24", "f26", "f28", "f30"};
static const char * const Names[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13",
"f14", "f15", "f16", "f17", "f18", "f19",
"f20", "f21", "f22", "f23", "f24", "f25",
"f26", "f27", "f28", "f29", "f30", "f31"};
return Names[code];
}
static const char *GetName(uint32_t i) {
@ -234,10 +258,12 @@ class FloatRegisters
static const Code Invalid = invalid_freg;
static const uint32_t Total = 16;
static const uint32_t Total = 32;
// :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
// only. For now we don't allocate odd regs for O32 ABI.
static const uint32_t Allocatable = 14;
static const uint32_t AllMask = 0xffff;
static const uint32_t AllMask = 0xffffffff;
static const uint32_t VolatileMask =
(1 << FloatRegisters::f0) |
@ -260,10 +286,28 @@ class FloatRegisters
static const uint32_t WrapperMask = VolatileMask;
// f18 and f16 are MIPS scratch float registers.
// :TODO: (Bug 972836) // Fix this once odd regs can be used as float32
// only. For now we don't allocate odd regs for O32 ABI.
static const uint32_t NonAllocatableMask =
(1 << f16) |
(1 << f18);
(1 << FloatRegisters::f1) |
(1 << FloatRegisters::f3) |
(1 << FloatRegisters::f5) |
(1 << FloatRegisters::f7) |
(1 << FloatRegisters::f9) |
(1 << FloatRegisters::f11) |
(1 << FloatRegisters::f13) |
(1 << FloatRegisters::f15) |
(1 << FloatRegisters::f17) |
(1 << FloatRegisters::f19) |
(1 << FloatRegisters::f21) |
(1 << FloatRegisters::f23) |
(1 << FloatRegisters::f25) |
(1 << FloatRegisters::f27) |
(1 << FloatRegisters::f29) |
(1 << FloatRegisters::f31) |
// f18 and f16 are MIPS scratch float registers.
(1 << FloatRegisters::f16) |
(1 << FloatRegisters::f18);
// Registers that can be allocated without being saved, generally.
static const uint32_t TempMask = VolatileMask & ~NonAllocatableMask;

View File

@ -56,16 +56,7 @@ uint32_t
js::jit::RT(FloatRegister r)
{
JS_ASSERT(r.code() < FloatRegisters::Total);
return (2 * r.code()) << RTShift;
}
// Use to code odd float registers.
// :TODO: Bug 972836, It will be removed once we can use odd regs.
uint32_t
js::jit::RT(uint32_t regCode)
{
JS_ASSERT((regCode & ~RegMask) == 0);
return regCode << RTShift;
return r.code() << RTShift;
}
uint32_t
@ -79,16 +70,7 @@ uint32_t
js::jit::RD(FloatRegister r)
{
JS_ASSERT(r.code() < FloatRegisters::Total);
return (2 * r.code()) << RDShift;
}
// Use to code odd float registers.
// :TODO: Bug 972836, It will be removed once we can use odd regs.
uint32_t
js::jit::RD(uint32_t regCode)
{
JS_ASSERT((regCode & ~RegMask) == 0);
return regCode << RDShift;
return r.code() << RDShift;
}
uint32_t
@ -102,7 +84,7 @@ uint32_t
js::jit::SA(FloatRegister r)
{
JS_ASSERT(r.code() < FloatRegisters::Total);
return (2 * r.code()) << SAShift;
return r.code() << SAShift;
}
Register
@ -973,39 +955,6 @@ Assembler::as_mfc1(Register rt, FloatRegister fs)
return writeInst(InstReg(op_cop1, rs_mfc1, rt, fs).encode());
}
// :TODO: Bug 972836, Remove _Odd functions once we can use odd regs.
BufferOffset
Assembler::as_ls_Odd(FloatRegister fd, Register base, int32_t off)
{
JS_ASSERT(Imm16::isInSignedRange(off));
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_lwc1 | RS(base) | RT(fd.code() * 2 + 1) | Imm16(off).encode());
}
BufferOffset
Assembler::as_ss_Odd(FloatRegister fd, Register base, int32_t off)
{
JS_ASSERT(Imm16::isInSignedRange(off));
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_swc1 | RS(base) | RT(fd.code() * 2 + 1) | Imm16(off).encode());
}
BufferOffset
Assembler::as_mtc1_Odd(Register rt, FloatRegister fs)
{
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_cop1 | rs_mtc1 | RT(rt) | RD(fs.code() * 2 + 1));
}
BufferOffset
Assembler::as_mfc1_Odd(Register rt, FloatRegister fs)
{
// Hardcoded because it will be removed once we can use odd regs.
return writeInst(op_cop1 | rs_mfc1 | RT(rt) | RD(fs.code() * 2 + 1));
}
// FP convert instructions
BufferOffset
Assembler::as_ceilws(FloatRegister fd, FloatRegister fs)

View File

@ -861,16 +861,14 @@ class Assembler
BufferOffset as_mfc1(Register rt, FloatRegister fs);
protected:
// These instructions should only be used to access the odd part of
// 64-bit register pair. Do not use odd registers as 32-bit registers.
// :TODO: Bug 972836, Remove _Odd functions once we can use odd regs.
BufferOffset as_ls_Odd(FloatRegister fd, Register base, int32_t off);
BufferOffset as_ss_Odd(FloatRegister fd, Register base, int32_t off);
BufferOffset as_mtc1_Odd(Register rt, FloatRegister fs);
public:
// Made public because CodeGenerator uses it to check for -0
BufferOffset as_mfc1_Odd(Register rt, FloatRegister fs);
// This is used to access the odd regiter form the pair of single
// precision registers that make one double register.
FloatRegister getOddPair(FloatRegister reg) {
JS_ASSERT(reg.code() % 2 == 0);
return FloatRegister::FromCode(reg.code() + 1);
}
public:
// FP convert instructions
BufferOffset as_ceilws(FloatRegister fd, FloatRegister fs);
BufferOffset as_floorws(FloatRegister fd, FloatRegister fs);

View File

@ -114,7 +114,7 @@ MacroAssemblerMIPS::convertDoubleToInt32(const FloatRegister &src, const Registe
// Test and bail for -0.0, when integer result is 0
// Move the top word of the double into the output reg, if it is
// non-zero, then the original value was -0.0
as_mfc1_Odd(dest, src);
moveFromDoubleHi(src, dest);
ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
bind(&notZero);
}
@ -141,7 +141,7 @@ MacroAssemblerMIPS::convertFloat32ToInt32(const FloatRegister &src, const Regist
// Test and bail for -0.0, when integer result is 0
// Move the top word of the double into the output reg,
// if it is non-zero, then the original value was -0.0
as_mfc1_Odd(dest, src);
moveFromDoubleHi(src, dest);
ma_b(dest, Imm32(INT32_MIN), fail, Assembler::Equal);
bind(&notZero);
}
@ -1296,7 +1296,7 @@ MacroAssemblerMIPS::ma_lis(FloatRegister dest, float value)
Imm32 imm(mozilla::BitwiseCast<uint32_t>(value));
ma_li(ScratchRegister, imm);
as_mtc1(ScratchRegister, dest);
moveToFloat32(ScratchRegister, dest);
}
void
@ -1310,41 +1310,41 @@ MacroAssemblerMIPS::ma_lid(FloatRegister dest, double value)
// put hi part of 64 bit value into the odd register
if (intStruct.hi == 0) {
as_mtc1_Odd(zero, dest);
moveToDoubleHi(zero, dest);
} else {
ma_li(ScratchRegister, Imm32(intStruct.hi));
as_mtc1_Odd(ScratchRegister, dest);
moveToDoubleHi(ScratchRegister, dest);
}
// put low part of 64 bit value into the even register
if (intStruct.lo == 0) {
as_mtc1(zero, dest);
moveToDoubleLo(zero, dest);
} else {
ma_li(ScratchRegister, Imm32(intStruct.lo));
as_mtc1(ScratchRegister, dest);
moveToDoubleLo(ScratchRegister, dest);
}
}
void
MacroAssemblerMIPS::ma_liNegZero(FloatRegister dest)
{
as_mtc1(zero, dest);
moveToDoubleLo(zero, dest);
ma_li(ScratchRegister, Imm32(INT_MIN));
as_mtc1_Odd(ScratchRegister, dest);
moveToDoubleHi(ScratchRegister, dest);
}
void
MacroAssemblerMIPS::ma_mv(FloatRegister src, ValueOperand dest)
{
as_mfc1(dest.payloadReg(), src);
as_mfc1_Odd(dest.typeReg(), src);
moveFromDoubleLo(src, dest.payloadReg());
moveFromDoubleHi(src, dest.typeReg());
}
void
MacroAssemblerMIPS::ma_mv(ValueOperand src, FloatRegister dest)
{
as_mtc1(src.payloadReg(), dest);
as_mtc1_Odd(src.typeReg(), dest);
moveToDoubleLo(src.payloadReg(), dest);
moveToDoubleHi(src.typeReg(), dest);
}
void
@ -1369,12 +1369,12 @@ MacroAssemblerMIPS::ma_ld(FloatRegister ft, Address address)
int32_t off2 = address.offset + TAG_OFFSET;
if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) {
as_ls(ft, address.base, Imm16(address.offset).encode());
as_ls_Odd(ft, address.base, Imm16(off2).encode());
as_ls(getOddPair(ft), address.base, Imm16(off2).encode());
} else {
ma_li(ScratchRegister, Imm32(address.offset));
as_addu(ScratchRegister, address.base, ScratchRegister);
as_ls(ft, ScratchRegister, PAYLOAD_OFFSET);
as_ls_Odd(ft, ScratchRegister, TAG_OFFSET);
as_ls(getOddPair(ft), ScratchRegister, TAG_OFFSET);
}
}
@ -1384,12 +1384,12 @@ MacroAssemblerMIPS::ma_sd(FloatRegister ft, Address address)
int32_t off2 = address.offset + TAG_OFFSET;
if (Imm16::isInSignedRange(address.offset) && Imm16::isInSignedRange(off2)) {
as_ss(ft, address.base, Imm16(address.offset).encode());
as_ss_Odd(ft, address.base, Imm16(off2).encode());
as_ss(getOddPair(ft), address.base, Imm16(off2).encode());
} else {
ma_li(ScratchRegister, Imm32(address.offset));
as_addu(ScratchRegister, address.base, ScratchRegister);
as_ss(ft, ScratchRegister, PAYLOAD_OFFSET);
as_ss_Odd(ft, ScratchRegister, TAG_OFFSET);
as_ss(getOddPair(ft), ScratchRegister, TAG_OFFSET);
}
}
@ -1540,6 +1540,72 @@ MacroAssemblerMIPSCompat::freeStack(Register amount)
as_addu(StackPointer, StackPointer, amount);
}
void
MacroAssembler::PushRegsInMask(RegisterSet set)
{
int32_t diffF = set.fpus().size() * sizeof(double);
int32_t diffG = set.gprs().size() * sizeof(intptr_t);
reserveStack(diffG);
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
diffG -= sizeof(intptr_t);
storePtr(*iter, Address(StackPointer, diffG));
}
MOZ_ASSERT(diffG == 0);
// Double values have to be aligned. We reserve extra space so that we can
// start writing from the first aligned location.
// We reserve a whole extra double so that the buffer has even size.
ma_and(SecondScratchReg, sp, Imm32(~(StackAlignment - 1)));
reserveStack(diffF + sizeof(double));
for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
// Use assembly s.d because we have alligned the stack.
// :TODO: (Bug 972836) Fix this once odd regs can be used as
// float32 only. For now we skip saving odd regs for O32 ABI.
// :TODO: (Bug 985881) Make a switch for N32 ABI.
if ((*iter).code() % 2 == 0)
as_sd(*iter, SecondScratchReg, -diffF);
diffF -= sizeof(double);
}
MOZ_ASSERT(diffF == 0);
}
void
MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore)
{
int32_t diffG = set.gprs().size() * sizeof(intptr_t);
int32_t diffF = set.fpus().size() * sizeof(double);
const int32_t reservedG = diffG;
const int32_t reservedF = diffF;
// Read the buffer form the first aligned location.
ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(StackAlignment - 1)));
for (FloatRegisterForwardIterator iter(set.fpus()); iter.more(); iter++) {
// :TODO: (Bug 972836) Fix this once odd regs can be used as
// float32 only. For now we skip loading odd regs for O32 ABI.
// :TODO: (Bug 985881) Make a switch for N32 ABI.
if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
// Use assembly l.d because we have alligned the stack.
as_ld(*iter, SecondScratchReg, -diffF);
diffF -= sizeof(double);
}
freeStack(reservedF + sizeof(double));
MOZ_ASSERT(diffF == 0);
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); iter++) {
diffG -= sizeof(intptr_t);
if (!ignore.has(*iter))
loadPtr(Address(StackPointer, diffG), *iter);
}
freeStack(reservedG);
MOZ_ASSERT(diffG == 0);
}
void
MacroAssemblerMIPSCompat::add32(Register src, Register dest)
{
@ -2324,17 +2390,17 @@ void
MacroAssemblerMIPSCompat::unboxDouble(const ValueOperand &operand, const FloatRegister &dest)
{
MOZ_ASSERT(dest != ScratchFloatReg);
as_mtc1(operand.payloadReg(), dest);
as_mtc1_Odd(operand.typeReg(), dest);
moveToDoubleLo(operand.payloadReg(), dest);
moveToDoubleHi(operand.typeReg(), dest);
}
void
MacroAssemblerMIPSCompat::unboxDouble(const Address &src, const FloatRegister &dest)
{
ma_lw(ScratchRegister, Address(src.base, src.offset + PAYLOAD_OFFSET));
as_mtc1(ScratchRegister, dest);
moveToDoubleLo(ScratchRegister, dest);
ma_lw(ScratchRegister, Address(src.base, src.offset + TAG_OFFSET));
as_mtc1_Odd(ScratchRegister, dest);
moveToDoubleHi(ScratchRegister, dest);
}
void
@ -2380,8 +2446,8 @@ MacroAssemblerMIPSCompat::unboxPrivate(const ValueOperand &src, Register dest)
void
MacroAssemblerMIPSCompat::boxDouble(const FloatRegister &src, const ValueOperand &dest)
{
as_mfc1(dest.payloadReg(), src);
as_mfc1_Odd(dest.typeReg(), src);
moveFromDoubleLo(src, dest.payloadReg());
moveFromDoubleHi(src, dest.typeReg());
}
void

View File

@ -234,6 +234,32 @@ class MacroAssemblerMIPS : public Assembler
void ma_bc1d(FloatRegister lhs, FloatRegister rhs, Label *label, DoubleCondition c,
JumpKind jumpKind = LongJump, FPConditionBit fcc = FCC0);
// These fuctions abstract the access to high part of the double precision
// float register. It is intended to work on both 32 bit and 64 bit
// floating point coprocessor.
// :TODO: (Bug 985881) Modify this for N32 ABI to use mthc1 and mfhc1
void moveToDoubleHi(Register src, FloatRegister dest) {
as_mtc1(src, getOddPair(dest));
}
void moveFromDoubleHi(FloatRegister src, Register dest) {
as_mfc1(dest, getOddPair(src));
}
void moveToDoubleLo(Register src, FloatRegister dest) {
as_mtc1(src, dest);
}
void moveFromDoubleLo(FloatRegister src, Register dest) {
as_mfc1(dest, src);
}
void moveToFloat32(Register src, FloatRegister dest) {
as_mtc1(src, dest);
}
void moveFromFloat32(FloatRegister src, Register dest) {
as_mfc1(dest, src);
}
protected:
void branchWithCode(InstImm code, Label *label, JumpKind jumpKind);
Condition ma_cmp(Register rd, Register lhs, Register rhs, Condition c);
@ -993,8 +1019,8 @@ public:
}
void zeroDouble(FloatRegister reg) {
as_mtc1(zero, reg);
as_mtc1_Odd(zero, reg);
moveToDoubleLo(zero, reg);
moveToDoubleHi(zero, reg);
}
void clampIntToUint8(Register reg) {

View File

@ -212,7 +212,7 @@ MoveEmitterMIPS::emitFloat32Move(const MoveOperand &from, const MoveOperand &to)
} else if (to.isGeneralReg()) {
// This should only be used when passing float parameter in a1,a2,a3
MOZ_ASSERT(to.reg() == a1 || to.reg() == a2 || to.reg() == a3);
masm.as_mfc1(to.reg(), from.floatReg());
masm.moveFromFloat32(from.floatReg(), to.reg());
} else {
MOZ_ASSERT(to.isMemory());
masm.storeFloat32(from.floatReg(), getAdjustedAddress(to));
@ -248,9 +248,9 @@ MoveEmitterMIPS::emitDoubleMove(const MoveOperand &from, const MoveOperand &to)
// Two moves are added for one double parameter by
// MacroAssemblerMIPSCompat::passABIArg
if(to.reg() == a2)
masm.as_mfc1(a2, from.floatReg());
masm.moveFromDoubleLo(from.floatReg(), a2);
else if(to.reg() == a3)
masm.as_mfc1_Odd(a3, from.floatReg());
masm.moveFromDoubleHi(from.floatReg(), a3);
else
MOZ_ASSUME_UNREACHABLE("Invalid emitDoubleMove arguments.");
} else {

View File

@ -680,10 +680,11 @@ class JSObject : public js::ObjectImpl
JS_ASSERT(dstStart + count <= getDenseCapacity());
#if defined(DEBUG) && defined(JSGC_GENERATIONAL)
JS::shadow::Runtime *rt = JS::shadow::Runtime::asShadowRuntime(runtimeFromAnyThread());
JS_ASSERT(!js::gc::IsInsideNursery(rt, this));
for (uint32_t index = 0; index < count; ++index) {
const JS::Value& value = src[index];
if (value.isMarkable())
JS_ASSERT(js::gc::IsInsideNursery(rt, value.toGCThing()));
JS_ASSERT(!js::gc::IsInsideNursery(rt, value.toGCThing()));
}
#endif
memcpy(&elements[dstStart], src, count * sizeof(js::HeapSlot));

View File

@ -1167,7 +1167,9 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
}
bool hasIonScript() const {
return ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
bool res = ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
MOZ_ASSERT_IF(res, baseline);
return res;
}
bool canIonCompile() const {
return ion != ION_DISABLED_SCRIPT;
@ -1191,11 +1193,14 @@ class JSScript : public js::gc::BarrieredCell<JSScript>
if (hasIonScript())
js::jit::IonScript::writeBarrierPre(tenuredZone(), ion);
ion = ionScript;
MOZ_ASSERT_IF(hasIonScript(), hasBaselineScript());
updateBaselineOrIonRaw();
}
bool hasBaselineScript() const {
return baseline && baseline != BASELINE_DISABLED_SCRIPT;
bool res = baseline && baseline != BASELINE_DISABLED_SCRIPT;
MOZ_ASSERT_IF(!res, !ion || ion == ION_DISABLED_SCRIPT);
return res;
}
bool canBaselineCompile() const {
return baseline != BASELINE_DISABLED_SCRIPT;

View File

@ -168,6 +168,7 @@ JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselin
if (hasBaselineScript())
js::jit::BaselineScript::writeBarrierPre(tenuredZone(), baseline);
#endif
MOZ_ASSERT(!hasIonScript());
baseline = baselineScript;
updateBaselineOrIonRaw();
}

View File

@ -2375,18 +2375,16 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
{
PROFILER_LABEL("ContainerState", "ProcessDisplayItems");
const nsIFrame* lastAnimatedGeometryRoot = nullptr;
nsPoint topLeft;
const nsIFrame* lastAnimatedGeometryRoot = mContainerReferenceFrame;
nsPoint topLeft(0,0);
// When NO_COMPONENT_ALPHA is set, items will be flattened into a single
// layer, so we need to choose which active scrolled root to use for all
// items.
if (aFlags & NO_COMPONENT_ALPHA) {
if (!ChooseAnimatedGeometryRoot(aList, &lastAnimatedGeometryRoot)) {
lastAnimatedGeometryRoot = mContainerReferenceFrame;
if (ChooseAnimatedGeometryRoot(aList, &lastAnimatedGeometryRoot)) {
topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
}
topLeft = lastAnimatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);
}
int32_t maxLayers = nsDisplayItem::MaxActiveLayers();
@ -2426,7 +2424,14 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
animatedGeometryRoot = lastAnimatedGeometryRoot;
} else {
forceInactive = false;
animatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
if (mManager->IsWidgetLayerManager()) {
animatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder);
} else {
// For inactive layer subtrees, splitting content into ThebesLayers
// based on animated geometry roots is pointless. It's more efficient
// to build the minimum number of layers.
animatedGeometryRoot = mContainerReferenceFrame;
}
if (animatedGeometryRoot != lastAnimatedGeometryRoot) {
lastAnimatedGeometryRoot = animatedGeometryRoot;
topLeft = animatedGeometryRoot->GetOffsetToCrossDoc(mContainerReferenceFrame);

View File

@ -1425,6 +1425,7 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
, mCountersDirty(false)
, mIsDestroyingFrameTree(false)
, mHasRootAbsPosContainingBlock(false)
, mAlwaysCreateFramesForIgnorableWhitespace(false)
{
#ifdef DEBUG
static bool gFirstTime = true;
@ -5552,16 +5553,13 @@ nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
// due to dynamic changes.
// We don't do it for SVG text, since we might need to position and
// measure the white space glyphs due to x/y/dx/dy attributes.
// We check that NS_CREATE_FRAME_FOR_IGNORABLE_WHITESPACE is not set on
// the node. This lets us disable this optimization for specific nodes
// (e.g. nodes whose geometry is being queried via DOM APIs).
if (AtLineBoundary(aIter) &&
!styleContext->StyleText()->WhiteSpaceOrNewlineIsSignificant() &&
aIter.List()->ParentHasNoXBLChildren() &&
!(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
(item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
!(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
!item.mContent->HasFlag(NS_CREATE_FRAME_FOR_IGNORABLE_WHITESPACE) &&
!mAlwaysCreateFramesForIgnorableWhitespace &&
item.IsWhitespace(aState))
return;
@ -7784,13 +7782,15 @@ nsIFrame*
nsCSSFrameConstructor::EnsureFrameForTextNode(nsGenericDOMDataNode* aContent)
{
if (aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
!aContent->HasFlag(NS_CREATE_FRAME_FOR_IGNORABLE_WHITESPACE)) {
!mAlwaysCreateFramesForIgnorableWhitespace) {
// Text frame may have been suppressed. Disable suppression and signal
// that a flush should be performed.
aContent->SetFlags(NS_CREATE_FRAME_FOR_IGNORABLE_WHITESPACE);
// that a flush should be performed. We do this on a document-wide
// basis so that pages that repeatedly query metrics for
// collapsed-whitespace text nodes don't trigger pathological behavior.
mAlwaysCreateFramesForIgnorableWhitespace = true;
nsAutoScriptBlocker blocker;
BeginUpdate();
RecreateFramesForContent(aContent, false);
ReconstructDocElementHierarchy();
EndUpdate();
}
return aContent->GetPrimaryFrame();

View File

@ -1801,6 +1801,7 @@ private:
bool mIsDestroyingFrameTree : 1;
// This is true if mDocElementContainingBlock supports absolute positioning
bool mHasRootAbsPosContainingBlock : 1;
bool mAlwaysCreateFramesForIgnorableWhitespace : 1;
nsCOMPtr<nsILayoutHistoryState> mTempFrameTreeState;
};

View File

@ -3098,18 +3098,23 @@ void nsDisplayWrapList::Paint(nsDisplayListBuilder* aBuilder,
NS_ERROR("nsDisplayWrapList should have been flattened away for painting");
}
/**
* Returns true if all descendant display items can be placed in the same
* ThebesLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
* and they all have the expected animated geometry root.
*/
static LayerState
RequiredLayerStateForChildrenInternal(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters,
const nsDisplayList& aList,
nsIFrame* aAnimatedGeometryRoot)
RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters,
const nsDisplayList& aList,
nsIFrame* aExpectedAnimatedGeometryRootForChildren)
{
LayerState result = LAYER_INACTIVE;
for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
nsIFrame* f = i->Frame();
if (result == LAYER_INACTIVE &&
nsLayoutUtils::GetAnimatedGeometryRootFor(f) != aAnimatedGeometryRoot) {
nsLayoutUtils::GetAnimatedGeometryRootFor(i, aBuilder) !=
aExpectedAnimatedGeometryRootForChildren) {
result = LAYER_ACTIVE;
}
@ -3125,8 +3130,8 @@ RequiredLayerStateForChildrenInternal(nsDisplayListBuilder* aBuilder,
nsDisplayList* list = i->GetSameCoordinateSystemChildren();
if (list) {
LayerState childState =
RequiredLayerStateForChildrenInternal(aBuilder, aManager, aParameters, *list,
aAnimatedGeometryRoot);
RequiredLayerStateForChildren(aBuilder, aManager, aParameters, *list,
aExpectedAnimatedGeometryRootForChildren);
if (childState > result) {
result = childState;
}
@ -3136,18 +3141,6 @@ RequiredLayerStateForChildrenInternal(nsDisplayListBuilder* aBuilder,
return result;
}
LayerState
nsDisplayWrapList::RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters,
const nsDisplayList& aList,
nsIFrame* aItemFrame)
{
return RequiredLayerStateForChildrenInternal(
aBuilder, aManager, aParameters, aList,
nsLayoutUtils::GetAnimatedGeometryRootFor(aItemFrame));
}
nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
{
nsRect bounds;
@ -3324,7 +3317,8 @@ nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
if (NeedsActiveLayer())
return LAYER_ACTIVE;
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList, mFrame);
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters, mList,
nsLayoutUtils::GetAnimatedGeometryRootFor(this, aBuilder));
}
bool
@ -4793,11 +4787,12 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
return LAYER_ACTIVE;
}
return mStoredList.RequiredLayerStateForChildren(aBuilder,
aManager,
aParameters,
*mStoredList.GetChildren(),
mFrame);
// Expect the child display items to have this frame as their animated
// geometry root (since it will be their reference frame). If they have a
// different animated geometry root, we'll make this an active layer so the
// animation can be accelerated.
return RequiredLayerStateForChildren(aBuilder, aManager, aParameters,
*mStoredList.GetChildren(), Frame());
}
bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,

View File

@ -2618,17 +2618,6 @@ public:
return nullptr;
}
/**
* Returns true if all descendant display items can be placed in the same
* ThebesLayer --- GetLayerState returns LAYER_INACTIVE or LAYER_NONE,
* and they all have the given aAnimatedGeometryRoot.
*/
static LayerState RequiredLayerStateForChildren(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerLayerParameters& aParameters,
const nsDisplayList& aList,
nsIFrame* aItemFrame);
protected:
nsDisplayWrapList() {}

View File

@ -577,11 +577,12 @@ nsLayoutUtils::IsTextAlignTrueValueEnabled()
void
nsLayoutUtils::UnionChildOverflow(nsIFrame* aFrame,
nsOverflowAreas& aOverflowAreas)
nsOverflowAreas& aOverflowAreas,
FrameChildListIDs aSkipChildLists)
{
// Iterate over all children except pop-ups.
const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
nsIFrame::kSelectPopupList);
FrameChildListIDs skip = aSkipChildLists |
nsIFrame::kSelectPopupList | nsIFrame::kPopupList;
for (nsIFrame::ChildListIterator childLists(aFrame);
!childLists.IsDone(); childLists.Next()) {
if (skip.Contains(childLists.CurrentID())) {
@ -1529,23 +1530,24 @@ nsLayoutUtils::IsFixedPosFrameInDisplayPort(const nsIFrame* aFrame, nsRect* aDis
return ViewportHasDisplayPort(aFrame->PresContext(), aDisplayPort);
}
nsIFrame*
nsLayoutUtils::GetAnimatedGeometryRootFor(nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor)
static nsIFrame*
GetAnimatedGeometryRootForFrame(nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor)
{
nsIFrame* f = aFrame;
nsIFrame* stickyFrame = nullptr;
while (f != aStopAtAncestor) {
if (IsPopup(f))
if (nsLayoutUtils::IsPopup(f))
break;
if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(f))
break;
if (!f->GetParent() && ViewportHasDisplayPort(f->PresContext())) {
if (!f->GetParent() &&
nsLayoutUtils::ViewportHasDisplayPort(f->PresContext())) {
// Viewport frames in a display port need to be animated geometry roots
// for background-attachment:fixed elements.
break;
}
nsIFrame* parent = GetCrossDocParentFrame(f);
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(f);
if (!parent)
break;
nsIAtom* parentType = parent->GetType();
@ -1576,7 +1578,7 @@ nsLayoutUtils::GetAnimatedGeometryRootFor(nsIFrame* aFrame,
}
}
// Fixed-pos frames are parented by the viewport frame, which has no parent
if (IsFixedPosFrameInDisplayPort(f)) {
if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(f)) {
return f;
}
f = parent;
@ -1593,7 +1595,7 @@ nsLayoutUtils::GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
nsDisplayScrollLayer* scrollLayerItem =
static_cast<nsDisplayScrollLayer*>(aItem);
nsIFrame* scrolledFrame = scrollLayerItem->GetScrolledFrame();
return nsLayoutUtils::GetAnimatedGeometryRootFor(scrolledFrame,
return GetAnimatedGeometryRootForFrame(scrolledFrame,
aBuilder->FindReferenceFrameFor(scrolledFrame));
}
if (aItem->ShouldFixToViewport(aBuilder)) {
@ -1604,10 +1606,10 @@ nsLayoutUtils::GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
nsIFrame* viewportFrame =
nsLayoutUtils::GetClosestFrameOfType(f, nsGkAtoms::viewportFrame);
NS_ASSERTION(viewportFrame, "no viewport???");
return nsLayoutUtils::GetAnimatedGeometryRootFor(viewportFrame,
return GetAnimatedGeometryRootForFrame(viewportFrame,
aBuilder->FindReferenceFrameFor(viewportFrame));
}
return nsLayoutUtils::GetAnimatedGeometryRootFor(f, aItem->ReferenceFrame());
return GetAnimatedGeometryRootForFrame(f, aItem->ReferenceFrame());
}
// static
@ -5406,20 +5408,9 @@ nsLayoutUtils::SurfaceFromElement(nsIImageLoadingContent* aElement,
return result;
if (wantImageSurface) {
IntSize size(imgWidth, imgHeight);
RefPtr<DataSourceSurface> output = Factory::CreateDataSourceSurface(size, SurfaceFormat::B8G8R8A8);
RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO,
output->GetData(),
size,
output->Stride(),
SurfaceFormat::B8G8R8A8);
RefPtr<SourceSurface> source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, gfxsurf);
dt->CopySurface(source, IntRect(0, 0, imgWidth, imgHeight), IntPoint());
dt->Flush();
result.mSourceSurface = output;
} else {
result.mSourceSurface = gfxPlatform::GetPlatform()->GetWrappedDataSourceSurface(gfxsurf);
}
if (!result.mSourceSurface) {
result.mSourceSurface = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTarget, gfxsurf);
}
} else {

View File

@ -10,6 +10,7 @@
#include "nsChangeHint.h"
#include "nsAutoPtr.h"
#include "nsFrameList.h"
#include "mozilla/layout/FrameChildList.h"
#include "nsThreadUtils.h"
#include "nsIPrincipal.h"
#include "GraphicsFilter.h"
@ -474,28 +475,22 @@ public:
nsRect* aDisplayPort = nullptr);
/**
* Finds the nearest ancestor frame that is considered to have (or will have)
* "animated geometry". For example the scrolled frames of scrollframes which
* are actively being scrolled fall into this category. Frames with certain
* CSS properties that are being animated (e.g. 'left'/'top' etc) are also
* placed in this category. Frames with animated CSS transforms are not
* put in this category because they can be handled directly by
* nsDisplayTransform.
* Stop searching at aStopAtAncestor if there is no such ancestor before it
* in the ancestor chain.
* Finds the nearest ancestor frame to aItem that is considered to have (or
* will have) "animated geometry". For example the scrolled frames of
* scrollframes which are actively being scrolled fall into this category.
* Frames with certain CSS properties that are being animated (e.g.
* 'left'/'top' etc) are also placed in this category.
* Frames with different active geometry roots are in different ThebesLayers,
* so that we can animate the geometry root by changing its transform (either
* on the main thread or in the compositor).
* This function is idempotent: a frame returned by GetAnimatedGeometryRootFor
* is always returned again if you pass it to GetAnimatedGeometryRootFor.
* The animated geometry root is required to be a descendant (or equal to)
* aItem's ReferenceFrame(), which means that we will fall back to
* returning aItem->ReferenceFrame() when we can't find another animated
* geometry root.
*/
static nsIFrame* GetAnimatedGeometryRootFor(nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor = nullptr);
static nsIFrame* GetAnimatedGeometryRootFor(nsDisplayItem* aItem,
nsDisplayListBuilder* aBuilder);
/**
* GetScrollableFrameFor returns the scrollable frame for a scrolled frame
*/
@ -1905,11 +1900,14 @@ public:
}
/**
* Unions the overflow areas of all non-popup children of aFrame with
* aOverflowAreas.
* Unions the overflow areas of the children of aFrame with aOverflowAreas.
* aSkipChildLists specifies any child lists that should be skipped.
* kSelectPopupList and kPopupList are always skipped.
*/
static void UnionChildOverflow(nsIFrame* aFrame,
nsOverflowAreas& aOverflowAreas);
nsOverflowAreas& aOverflowAreas,
mozilla::layout::FrameChildListIDs aSkipChildLists =
mozilla::layout::FrameChildListIDs());
/**
* Return the font size inflation *ratio* for a given frame. This is

View File

@ -241,6 +241,7 @@ NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowOutOfFlowsProperty)
NS_DECLARE_FRAME_PROPERTY_FRAMELIST(PushedFloatProperty)
NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OutsideBulletProperty)
NS_DECLARE_FRAME_PROPERTY(InsideBulletProperty, nullptr)
NS_DECLARE_FRAME_PROPERTY(BottomEdgeOfChildrenProperty, nullptr)
//----------------------------------------------------------------------
@ -1452,6 +1453,14 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
aMetrics.Height() = std::max(0, aMetrics.Height());
*aBottomEdgeOfChildren = bottomEdgeOfChildren;
FrameProperties properties = Properties();
if (bottomEdgeOfChildren != aMetrics.Height() - borderPadding.bottom) {
properties.Set(BottomEdgeOfChildrenProperty(),
NS_INT32_TO_PTR(bottomEdgeOfChildren));
} else {
properties.Delete(BottomEdgeOfChildrenProperty());
}
#ifdef DEBUG_blocks
if (CRAZY_SIZE(aMetrics.Width()) || CRAZY_SIZE(aMetrics.Height())) {
ListTag(stdout);
@ -1460,6 +1469,22 @@ nsBlockFrame::ComputeFinalSize(const nsHTMLReflowState& aReflowState,
#endif
}
static void
ConsiderBottomEdgeOfChildren(nscoord aBottomEdgeOfChildren,
nsOverflowAreas& aOverflowAreas)
{
// Factor in the bottom edge of the children. Child frames will be added
// to the overflow area as we iterate through the lines, but their margins
// won't, so we need to account for bottom margins here.
// REVIEW: For now, we do this for both visual and scrollable area,
// although when we make scrollable overflow area not be a subset of
// visual, we can change this.
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
nsRect& o = aOverflowAreas.Overflow(otype);
o.height = std::max(o.YMost(), aBottomEdgeOfChildren) - o.y;
}
}
void
nsBlockFrame::ComputeOverflowAreas(const nsRect& aBounds,
const nsStyleDisplay* aDisplay,
@ -1487,17 +1512,9 @@ nsBlockFrame::ComputeOverflowAreas(const nsRect& aBounds,
areas.UnionAllWith(outsideBullet->GetRect());
}
// Factor in the bottom edge of the children. Child frames will be added
// to the overflow area as we iterate through the lines, but their margins
// won't, so we need to account for bottom margins here.
// REVIEW: For now, we do this for both visual and scrollable area,
// although when we make scrollable overflow area not be a subset of
// visual, we can change this.
NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
nsRect& o = areas.Overflow(otype);
o.height = std::max(o.YMost(), aBottomEdgeOfChildren) - o.y;
}
ConsiderBottomEdgeOfChildren(aBottomEdgeOfChildren, areas);
}
#ifdef NOISY_COMBINED_AREA
ListTag(stdout);
printf(": ca=%d,%d,%d,%d\n", area.x, area.y, area.width, area.height);
@ -1509,6 +1526,9 @@ nsBlockFrame::ComputeOverflowAreas(const nsRect& aBounds,
bool
nsBlockFrame::UpdateOverflow()
{
nsRect rect(nsPoint(0, 0), GetSize());
nsOverflowAreas overflowAreas(rect, rect);
// We need to update the overflow areas of lines manually, as they
// get cached and re-used otherwise. Lines aren't exposed as normal
// frame children, so calling UnionChildOverflow alone will end up
@ -1516,7 +1536,8 @@ nsBlockFrame::UpdateOverflow()
for (line_iterator line = begin_lines(), line_end = end_lines();
line != line_end;
++line) {
nsOverflowAreas lineAreas;
nsRect bounds = line->mBounds;
nsOverflowAreas lineAreas(bounds, bounds);
int32_t n = line->GetChildCount();
for (nsIFrame* lineFrame = line->mFirstChild;
@ -1532,13 +1553,26 @@ nsBlockFrame::UpdateOverflow()
}
line->SetOverflowAreas(lineAreas);
overflowAreas.UnionWith(lineAreas);
}
// Line cursor invariants depend on the overflow areas of the lines, so
// we must clear the line cursor since those areas may have changed.
ClearLineCursor();
return nsBlockFrameSuper::UpdateOverflow();
// Union with child frames, skipping the principal and float lists
// since we already handled those using the line boxes.
nsLayoutUtils::UnionChildOverflow(this, overflowAreas,
kPrincipalList | kFloatList);
bool found;
nscoord bottomEdgeOfChildren = NS_PTR_TO_INT32(
Properties().Get(BottomEdgeOfChildrenProperty(), &found));
if (found) {
ConsiderBottomEdgeOfChildren(bottomEdgeOfChildren, overflowAreas);
}
return FinishAndStoreOverflow(overflowAreas, GetSize());
}
void

View File

@ -4478,6 +4478,17 @@ nsIFrame::SetView(nsView* aView)
if (aView) {
aView->SetFrame(this);
#ifdef DEBUG
nsIAtom* frameType = GetType();
NS_ASSERTION(frameType == nsGkAtoms::scrollFrame ||
frameType == nsGkAtoms::subDocumentFrame ||
frameType == nsGkAtoms::listControlFrame ||
frameType == nsGkAtoms::objectFrame ||
frameType == nsGkAtoms::viewportFrame ||
frameType == nsGkAtoms::menuPopupFrame,
"Only specific frame types can have an nsView");
#endif
// Set a property on the frame
Properties().Set(ViewProperty(), aView);

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<style>
#container {
position: absolute;
width: 200px;
height: 200px;
overflow: scroll;
}
#image {
width: 100px;
height: 100px;
margin: 100px;
background: blue;
display: inline-block;
}
#cursor {
position: absolute;
left: 10px;
top: 0;
width: 10px;
height: 10px;
background: red;
}
</style>
</head>
<body>
<div id='container'>
<div id='image'></div>
<div id='cursor'></div>
</div>
</body>
</html>

View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<style>
#container {
position: absolute;
width: 200px;
height: 200px;
overflow: scroll;
}
#image {
width: 100px;
height: 100px;
margin: 100px;
background: blue;
display: inline-block;
}
#cursor {
position: absolute;
left: 0;
top: 0;
width: 10px;
height: 10px;
background: red;
}
</style>
</head>
<body>
<div id='container'>
<div id='image'></div>
<div id='cursor'></div>
</div>
</body>
<script>
var x = image.getBoundingClientRect();
cursor.style.left = '10px';
</script>
</html>

View File

@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>
<head>
<style>
#container {
position: absolute;
width: 200px;
height: 200px;
overflow: scroll;
}
#image {
width: 100px;
height: 100px;
margin: 100px;
background: blue;
display: inline-block;
}
#cursor {
position: absolute;
left: 0;
top: 0;
width: 10px;
height: 10px;
background: red;
}
</style>
</head>
<body>
<div id='container'>
<div style="position:relative">
<div id='image'></div>
<div id='cursor'></div>
</div>
</div>
</body>
<script>
var x = image.getBoundingClientRect();
cursor.style.left = '10px';
</script>
</html>

View File

@ -1804,6 +1804,8 @@ skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above
== 983084-2.html 983084-2-ref.html
== 983084-3.html 983084-1-ref.html
== 983691-1.html 983691-ref.html
== 985303-1a.html 985303-1-ref.html
== 985303-1b.html 985303-1-ref.html
== 987680-1.html 987680-1-ref.html
fuzzy-if(/^Windows\x20NT\x206\.2/.test(http.oscpu),1,24) == 991046-1.html 991046-1-ref.html
pref(layout.css.overflow-clip-box.enabled,true) == 992447.html 992447-ref.html

View File

@ -1,22 +1,18 @@
<!DOCTYPE html>
<html class="reftest-wait reftest-print">
<head>
<script type="text/javascript">
window.onload = function() {
var canvas = document.getElementById('canvas');
canvas.mozPrintCallback = function(obj) {
var ctx = obj.context;
ctx.fillStyle = 'rgb(255, 0, 0)';
ctx.fillRect(0, 0, 10, 10);
obj.done();
};
setTimeout(function() {
document.documentElement.className = "reftest-print"
}, 100);
};
</script>
</head>
<body>
<canvas id="canvas" width="10px" height="10px"></canvas>
<canvas id="canvas" width="10" height="10"></canvas>
<script>
var canvas = document.getElementById('canvas');
canvas.mozPrintCallback = function(obj) {
setTimeout(function() {
var ctx = obj.context;
ctx.fillStyle = 'rgb(255, 0, 0)';
ctx.fillRect(0, 0, 10, 10);
obj.done();
document.documentElement.classList.toggle("reftest-wait");
}, 0);
};
</script>
</body>
</html>

View File

@ -24,7 +24,7 @@ fails-if(B2G) == 115199-1.html 115199-1-ref.html # reftest-print doesn't work on
== 115199-2a.html 115199-2-ref.html
== 115199-2b.html 115199-2-ref.html
== 652178-1.html 652178-1-ref2.html
fails-if(B2G) fuzzy-if(cocoaWidget,1,5000) fuzzy-if(/^Windows\x20NT\x206\.1/.test(http.oscpu),255,100) == 745025-1.html 745025-1-ref.html # reftest-print doesn't work on B2G
skip-if(B2G) fuzzy-if(cocoaWidget,1,5000) == 745025-1.html 745025-1-ref.html # reftest-print doesn't work on B2G
== 820496-1.html 820496-1-ref.html
# NOTE: These tests don't yet rigorously test what they're

View File

@ -1,19 +1,19 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=779029 -->
<title>Test that the x/y/width/height attributes work on the mask element</title>
<mask id="mask" x="20%" y="20%" width="60%" height="60%">
<rect width="1000" height="1000" fill="white"/>
</mask>
<rect width="100%" height="100%" fill="lime"/>
<rect x="50" y="50" width="100" height="100" fill="red" mask="url(#mask)"/>
<rect x="70" y="70" width="60" height="60" fill="lime"/>
</svg>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=779029 -->
<title>Test that the x/y/width/height attributes work on the mask element</title>
<mask id="mask" x="20%" y="20%" width="60%" height="60%">
<rect width="1000" height="1000" fill="white"/>
</mask>
<rect width="100%" height="100%" fill="lime"/>
<rect x="50" y="50" width="100" height="100" fill="red" mask="url(#mask)"/>
<rect x="70" y="70" width="60" height="60" fill="lime"/>
</svg>

Before

Width:  |  Height:  |  Size: 693 B

After

Width:  |  Height:  |  Size: 674 B

View File

@ -0,0 +1,18 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=995813 -->
<title>Test mapped attributes work on the mask element</title>
<mask id="mask" fill="white" maskContentUnits="objectBoundingBox">
<rect width="100%" height="100%"/>
</mask>
<rect width="100%" height="100%" fill="red"/>
<rect width="100%" height="100%" fill="lime" mask="url(#mask)"/>
</svg>

After

Width:  |  Height:  |  Size: 580 B

View File

@ -0,0 +1,18 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- From https://bugzilla.mozilla.org/show_bug.cgi?id=995813 -->
<title>Test mapped attributes work on the pattern element</title>
<pattern id="pattern" width="100%" height="100%" fill="lime" patternContentUnits="objectBoundingBox">
<rect width="100%" height="100%"/>
</pattern>
<rect width="100%" height="100%" fill="red"/>
<rect width="100%" height="100%" fill="url(#pattern)"/>
</svg>

After

Width:  |  Height:  |  Size: 612 B

View File

@ -197,6 +197,7 @@ pref(svg.marker-improvements.enabled,true) == marker-orientation-02.svg marker-o
== mask-basic-01.svg pass.svg
== mask-basic-02.svg mask-basic-02-ref.svg
== mask-basic-03.svg pass.svg
== mask-basic-04.svg pass.svg
== mask-extref-dataURI-01.svg pass.svg
== mask-containing-masked-content-01.svg pass.svg
== mask-transformed-01.svg mask-transformed-01-ref.svg
@ -246,6 +247,7 @@ fuzzy-if(azureQuartz,6,47) == path-01.svg path-01-ref.svg
== path-08.svg pass.svg
== pathLength-01.svg pass.svg
== pathLength-02.svg pass.svg
== pattern-basic-01.svg pass.svg
== pattern-invalid-01.svg pattern-invalid-01-ref.svg
== pattern-live-01a.svg pattern-live-01-ref.svg
== pattern-live-01b.svg pattern-live-01-ref.svg

View File

@ -531,8 +531,10 @@ The suggested first lines for any printing test is
<style>html{font-size:12pt}</style>
The reftest-print class on the root element triggers the reftest to
switch into page mode on load. Fixing the font size is suggested,
although not required, because the pages are a fixed size in inches.
switch into page mode. Fixing the font size is suggested, although not
required, because the pages are a fixed size in inches. The switch to page mode
happens on load if the reftest-wait class is not present; otherwise it happens
immediately after firing the MozReftestInvalidate event.
The underlying layout support for this mode isn't really complete; it
doesn't use exactly the same codepath as real print preview/print. In

View File

@ -443,6 +443,12 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
notification.initEvent("MozReftestInvalidate", true, false);
contentRootElement.dispatchEvent(notification);
}
if (!inPrintMode && doPrintMode(contentRootElement)) {
LogInfo("MakeProgress: setting up print mode");
setupPrintMode();
}
if (hasReftestWait && !shouldWaitForReftestWaitRemoval(contentRootElement)) {
// MozReftestInvalidate handler removed reftest-wait.
// We expect something to have been invalidated...
@ -478,10 +484,6 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
}
state = STATE_WAITING_TO_FINISH;
if (!inPrintMode && doPrintMode(contentRootElement)) {
LogInfo("MakeProgress: setting up print mode");
setupPrintMode();
}
// Try next state
MakeProgress();
return;

View File

@ -15,7 +15,7 @@
#include <math.h>
#include "common.h"
#if defined ( WIN32 )
#if (defined(_WIN32) || defined(__WIN32__))
#define __func__ __FUNCTION__
#endif
@ -488,15 +488,23 @@ test_drain(void)
int is_windows_7()
{
#ifdef __WIN32__
#include <windows.h>
DWORD version = GetVersion();
DWORD major = (DWORD) (LOBYTE(LOWORD(version)));
DWORD minor = (DWORD) (HIBYTE(LOWORD(version)));
#if (defined(_WIN32) || defined(__WIN32__))
OSVERSIONINFOEX osvi;
DWORDLONG condition_mask = 0;
return (major == 6) && (minor == 1);
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
// NT 6.1 is Windows 7
osvi.dwMajorVersion = 6;
osvi.dwMinorVersion = 1;
VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, VER_EQUAL);
VER_SET_CONDITION(condition_mask, VER_MINORVERSION, VER_EQUAL);
return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, condition_mask);
#else
return-0;
return 0;
#endif
}

View File

@ -1753,7 +1753,8 @@ void
PeerConnectionImpl::SetSignalingState_m(PCImplSignalingState aSignalingState)
{
PC_AUTO_ENTER_API_CALL_NO_CHECK();
if (mSignalingState == aSignalingState) {
if (mSignalingState == aSignalingState ||
mSignalingState == PCImplSignalingState::SignalingClosed) {
return;
}

View File

@ -80,6 +80,11 @@ static struct sock_filter seccomp_filter[] = {
ALLOW_SYSCALL(_llseek),
#endif
ALLOW_SYSCALL(lseek),
// Android also uses 32-bit ftruncate.
ALLOW_SYSCALL(ftruncate),
#if SYSCALL_EXISTS(ftruncate64)
ALLOW_SYSCALL(ftruncate64),
#endif
/* ioctl() is for GL. Remove when GL proxy is implemented.
* Additionally ioctl() might be a place where we want to have
@ -209,7 +214,6 @@ static struct sock_filter seccomp_filter[] = {
ALLOW_SYSCALL(pread64),
ALLOW_SYSCALL(statfs),
ALLOW_SYSCALL(pipe),
ALLOW_SYSCALL(ftruncate),
ALLOW_SYSCALL(getrlimit),
ALLOW_SYSCALL(shutdown),
ALLOW_SYSCALL(getpeername),

View File

@ -184,7 +184,7 @@ class MochitestRunner(MozbuildObject):
return mochitest.run_remote_mochitests(parser, options)
def run_desktop_test(self, context, suite=None, test_paths=None, debugger=None,
debugger_args=None, slowscript=False, shuffle=False, keep_open=False,
debugger_args=None, slowscript=False, screenshot_on_fail = False, shuffle=False, keep_open=False,
rerun_failures=False, no_autorun=False, repeat=0, run_until_failure=False,
slow=False, chunk_by_dir=0, total_chunks=None, this_chunk=None,
jsdebugger=False, debug_on_failure=False, start_at=None, end_at=None,
@ -293,6 +293,7 @@ class MochitestRunner(MozbuildObject):
options.autorun = not no_autorun
options.closeWhenDone = not keep_open
options.slowscript = slowscript
options.screenshotOnFail = screenshot_on_fail
options.shuffle = shuffle
options.consoleLevel = 'INFO'
options.repeat = repeat
@ -411,6 +412,10 @@ def MochitestCommand(func):
help='Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; when not set, recoverable but misleading SIGSEGV instances may occur in Ion/Odin JIT code')
func = slowscript(func)
screenshot_on_fail = CommandArgument('--screenshot-on-fail', action='store_true',
help='Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots.')
func = screenshot_on_fail(func)
shuffle = CommandArgument('--shuffle', action='store_true',
help='Shuffle execution order.')
func = shuffle(func)

View File

@ -397,6 +397,12 @@ class MochitestOptions(optparse.OptionParser):
"when not set, recoverable but misleading SIGSEGV instances "
"may occur in Ion/Odin JIT code."
}],
[["--screenshot-on-fail"],
{ "action": "store_true",
"default": False,
"dest": "screenshotOnFail",
"help": "Take screenshots on all test failures. Set $MOZ_UPLOAD_DIR to a directory for storing the screenshots."
}],
[["--quiet"],
{ "action": "store_true",
"default": False,

View File

@ -890,7 +890,8 @@ class Mochitest(MochitestUtilsMixin):
timeout=-1,
onLaunch=None,
webapprtChrome=False,
hide_subtests=False):
hide_subtests=False,
screenshotOnFail=False):
"""
Run the app, log the duration it took to execute, return the status code.
Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
@ -980,6 +981,7 @@ class Mochitest(MochitestUtilsMixin):
utilityPath=utilityPath,
symbolsPath=symbolsPath,
dump_screen_on_timeout=not debuggerInfo,
dump_screen_on_fail=screenshotOnFail,
hide_subtests=hide_subtests,
shutdownLeaks=shutdownLeaks,
)
@ -1159,7 +1161,8 @@ class Mochitest(MochitestUtilsMixin):
timeout=timeout,
onLaunch=onLaunch,
webapprtChrome=options.webapprtChrome,
hide_subtests=options.hide_subtests
hide_subtests=options.hide_subtests,
screenshotOnFail=options.screenshotOnFail
)
except KeyboardInterrupt:
log.info("runtests.py | Received keyboard interrupt.\n");
@ -1212,7 +1215,7 @@ class Mochitest(MochitestUtilsMixin):
class OutputHandler(object):
"""line output handler for mozrunner"""
def __init__(self, harness, utilityPath, symbolsPath=None, dump_screen_on_timeout=True,
def __init__(self, harness, utilityPath, symbolsPath=None, dump_screen_on_timeout=True, dump_screen_on_fail=False,
hide_subtests=False, shutdownLeaks=None):
"""
harness -- harness instance
@ -1224,6 +1227,7 @@ class Mochitest(MochitestUtilsMixin):
self.utilityPath = utilityPath
self.symbolsPath = symbolsPath
self.dump_screen_on_timeout = dump_screen_on_timeout
self.dump_screen_on_fail = dump_screen_on_fail
self.hide_subtests = hide_subtests
self.shutdownLeaks = shutdownLeaks
@ -1249,6 +1253,7 @@ class Mochitest(MochitestUtilsMixin):
return [self.fix_stack,
self.format,
self.dumpScreenOnTimeout,
self.dumpScreenOnFail,
self.metro_subprocess_id,
self.trackShutdownLeaks,
self.check_test_failure,
@ -1321,7 +1326,13 @@ class Mochitest(MochitestUtilsMixin):
return line.rstrip().decode("UTF-8", "ignore")
def dumpScreenOnTimeout(self, line):
if self.dump_screen_on_timeout and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line:
if not self.dump_screen_on_fail and self.dump_screen_on_timeout and "TEST-UNEXPECTED-FAIL" in line and "Test timed out" in line:
self.log_output_buffer()
self.harness.dumpScreen(self.utilityPath)
return line
def dumpScreenOnFail(self, line):
if self.dump_screen_on_fail and "TEST-UNEXPECTED-FAIL" in line:
self.log_output_buffer()
self.harness.dumpScreen(self.utilityPath)
return line

View File

@ -14,7 +14,7 @@ log = mozlog.getLogger('cppunittests')
class CPPUnitTests(object):
# Time (seconds) to wait for test process to complete
TEST_PROC_TIMEOUT = 1200
TEST_PROC_TIMEOUT = 900
# Time (seconds) in which process will be killed if it produces no output.
TEST_PROC_NO_OUTPUT_TIMEOUT = 300

View File

@ -511,6 +511,7 @@ ifeq ($(MOZ_WIDGET_TOOLKIT),android)
endif
$(NSINSTALL) $(topsrcdir)/startupcache/test/TestStartupCacheTelemetry.js $(PKG_STAGE)/cppunittests
$(NSINSTALL) $(topsrcdir)/startupcache/test/TestStartupCacheTelemetry.manifest $(PKG_STAGE)/cppunittests
cp -RL $(DIST)/bin/jsapi-tests$(BIN_SUFFIX) $(PKG_STAGE)/cppunittests
stage-jittest: make-stage-dir
$(NSINSTALL) -D $(PKG_STAGE)/jit-test/tests

View File

@ -780,6 +780,7 @@ AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI,
size.width = surface->GetSize().width;
size.height = surface->GetSize().height;
dataSurface = surface->GetDataSurface();
NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
}
// Allocate a new buffer that we own and can use out of line in

View File

@ -49,7 +49,6 @@ EXPORTS += [
'nsDebugImpl.h',
'nsError.h',
'nsGZFileWriter.h',
'nsIAllocator.h',
'nsIID.h',
'nsInterfaceRequestorAgg.h',
'nsISizeOf.h',

View File

@ -10,7 +10,6 @@
#ifndef nsAllocator_h__
#define nsAllocator_h__
#include "nsIAllocator.h"
#include "nsAgg.h"
#include "nsIFactory.h"

View File

@ -1,23 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* XXX This file is obsolete. Use nsIMemory.idl or nsMemory.h instead.
*/
#ifndef nsIAllocator_h___
#define nsIAllocator_h___
#include "nsMemory.h"
#define nsIAllocator nsIMemory
#define nsAllocator nsMemory
#define GetGlobalAllocator GetGlobalMemoryService
#define NS_IALLOCATOR_IID NS_GET_IID(nsIMemory)
#define NS_ALLOCATOR_CONTRACTID NS_MEMORY_CONTRACTID
#define NS_ALLOCATOR_CID NS_MEMORY_CID
#endif /* nsIAllocator_h___ */

View File

@ -401,6 +401,7 @@ interface nsIMemoryReporterManager : nsISupports
#include "js/TypeDecls.h"
#include "nsStringGlue.h"
#include "nsTArray.h"
#include "mozilla/Atomics.h"
class nsPIDOMWindow;
@ -530,6 +531,116 @@ void RunReportersForThisProcess();
return moz_malloc_size_of(aPtr); \
}
namespace mozilla {
// This CRTP class handles several details of wrapping allocators and should
// be preferred to manually counting with MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC
// and MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE. The typical use is in a memory
// reporter for a particular third party library:
//
// class MyMemoryReporter : public CountingAllocatorBase<MyMemoryReporter>
// {
// ...
// NS_IMETHODIMP
// CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
// {
// return MOZ_COLLECT_REPORTER(
// "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES,
// MemoryAllocated(),
// "A description of what we are reporting."
// }
// };
//
// ...somewhere later in the code...
// SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc,
// MyMemoryReporter::CountingFree);
template<typename T>
class CountingAllocatorBase
{
public:
CountingAllocatorBase()
{
#ifdef DEBUG
// There must be only one instance of this class, due to |sAmount| being
// static.
static bool hasRun = false;
MOZ_ASSERT(!hasRun);
hasRun = true;
#endif
}
static size_t
MemoryAllocated()
{
return sAmount;
}
static void*
CountingMalloc(size_t size)
{
void* p = malloc(size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
}
static void*
CountingCalloc(size_t nmemb, size_t size)
{
void* p = calloc(nmemb, size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
}
static void*
CountingRealloc(void* p, size_t size)
{
size_t oldsize = MallocSizeOfOnFree(p);
void *pnew = realloc(p, size);
if (pnew) {
size_t newsize = MallocSizeOfOnAlloc(pnew);
sAmount += newsize - oldsize;
} else if (size == 0) {
// We asked for a 0-sized (re)allocation of some existing pointer
// and received NULL in return. 0-sized allocations are permitted
// to either return NULL or to allocate a unique object per call (!).
// For a malloc implementation that chooses the second strategy,
// that allocation may fail (unlikely, but possible).
//
// Given a NULL return value and an allocation size of 0, then, we
// don't know if that means the original pointer was freed or if
// the allocation of the unique object failed. If the original
// pointer was freed, then we have nothing to do here. If the
// allocation of the unique object failed, the original pointer is
// still valid and we ought to undo the decrement from above.
// However, we have no way of knowing how the underlying realloc
// implementation is behaving. Assuming that the original pointer
// was freed is the safest course of action. We do, however, need
// to note that we freed memory.
sAmount -= oldsize;
} else {
// realloc failed. The amount allocated hasn't changed.
}
return pnew;
}
static void
CountingFree(void* p)
{
sAmount -= MallocSizeOfOnFree(p);
free(p);
}
private:
// |sAmount| can be (implicitly) accessed by multiple threads, so it
// must be thread-safe.
static Atomic<size_t> sAmount;
MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
};
}
// This macro assumes the presence of appropriate |aHandleReport| and |aData|
// variables.
#define MOZ_COLLECT_REPORT(path, kind, units, amount, description) \

View File

@ -126,6 +126,9 @@ extern nsresult nsStringInputStreamConstructor(nsISupports *, REFNSIID, void **)
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/SystemMemoryReporter.h"
#include "mozilla/layers/ImageBridgeChild.h"
#include "mozilla/layers/CompositorParent.h"
#ifdef MOZ_VISUAL_EVENT_TRACER
#include "mozilla/VisualEventTracer.h"
#endif
@ -338,215 +341,81 @@ NS_InitXPCOM(nsIServiceManager* *result,
return NS_InitXPCOM2(result, binDirectory, nullptr);
}
class ICUReporter MOZ_FINAL : public nsIMemoryReporter
class ICUReporter MOZ_FINAL : public nsIMemoryReporter,
public CountingAllocatorBase<ICUReporter>
{
public:
NS_DECL_ISUPPORTS
ICUReporter()
{
#ifdef DEBUG
// There must be only one instance of this class, due to |sAmount|
// being static.
static bool hasRun = false;
MOZ_ASSERT(!hasRun);
hasRun = true;
#endif
sAmount = 0;
}
static void* Alloc(const void*, size_t size)
{
void* p = malloc(size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
return CountingMalloc(size);
}
static void* Realloc(const void*, void* p, size_t size)
{
sAmount -= MallocSizeOfOnFree(p);
void *pnew = realloc(p, size);
if (pnew) {
sAmount += MallocSizeOfOnAlloc(pnew);
} else {
// realloc failed; undo the decrement from above
sAmount += MallocSizeOfOnAlloc(p);
}
return pnew;
return CountingRealloc(p, size);
}
static void Free(const void*, void* p)
{
sAmount -= MallocSizeOfOnFree(p);
free(p);
return CountingFree(p);
}
private:
// |sAmount| can be (implicitly) accessed by multiple JSRuntimes, so it
// must be thread-safe.
static Atomic<size_t> sAmount;
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
NS_IMETHODIMP
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
{
return MOZ_COLLECT_REPORT(
"explicit/icu", KIND_HEAP, UNITS_BYTES, sAmount,
"explicit/icu", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
"Memory used by ICU, a Unicode and globalization support library.");
}
};
NS_IMPL_ISUPPORTS1(ICUReporter, nsIMemoryReporter)
/* static */ Atomic<size_t> ICUReporter::sAmount;
/* static */ template<> Atomic<size_t> CountingAllocatorBase<ICUReporter>::sAmount(0);
class OggReporter MOZ_FINAL : public nsIMemoryReporter
class OggReporter MOZ_FINAL : public nsIMemoryReporter,
public CountingAllocatorBase<OggReporter>
{
public:
NS_DECL_ISUPPORTS
OggReporter()
{
#ifdef DEBUG
// There must be only one instance of this class, due to |sAmount|
// being static.
static bool hasRun = false;
MOZ_ASSERT(!hasRun);
hasRun = true;
#endif
sAmount = 0;
}
static void* Alloc(size_t size)
{
void* p = malloc(size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
}
static void* Realloc(void* p, size_t size)
{
sAmount -= MallocSizeOfOnFree(p);
void *pnew = realloc(p, size);
if (pnew) {
sAmount += MallocSizeOfOnAlloc(pnew);
} else {
// realloc failed; undo the decrement from above
sAmount += MallocSizeOfOnAlloc(p);
}
return pnew;
}
static void* Calloc(size_t nmemb, size_t size)
{
void* p = calloc(nmemb, size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
}
static void Free(void* p)
{
sAmount -= MallocSizeOfOnFree(p);
free(p);
}
private:
// |sAmount| can be (implicitly) accessed by multiple threads, so it
// must be thread-safe.
static Atomic<size_t> sAmount;
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
NS_IMETHODIMP
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
{
return MOZ_COLLECT_REPORT(
"explicit/media/libogg", KIND_HEAP, UNITS_BYTES, sAmount,
"explicit/media/libogg", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
"Memory allocated through libogg for Ogg, Theora, and related media files.");
}
};
NS_IMPL_ISUPPORTS1(OggReporter, nsIMemoryReporter)
/* static */ Atomic<size_t> OggReporter::sAmount;
/* static */ template<> Atomic<size_t> CountingAllocatorBase<OggReporter>::sAmount(0);
#ifdef MOZ_VPX
class VPXReporter MOZ_FINAL : public nsIMemoryReporter
class VPXReporter MOZ_FINAL : public nsIMemoryReporter,
public CountingAllocatorBase<VPXReporter>
{
public:
NS_DECL_ISUPPORTS
VPXReporter()
{
#ifdef DEBUG
// There must be only one instance of this class, due to |sAmount|
// being static.
static bool hasRun = false;
MOZ_ASSERT(!hasRun);
hasRun = true;
#endif
sAmount = 0;
}
static void* Alloc(size_t size)
{
void* p = malloc(size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
}
static void* Realloc(void* p, size_t size)
{
sAmount -= MallocSizeOfOnFree(p);
void *pnew = realloc(p, size);
if (pnew) {
sAmount += MallocSizeOfOnAlloc(pnew);
} else {
// realloc failed; undo the decrement from above
sAmount += MallocSizeOfOnAlloc(p);
}
return pnew;
}
static void* Calloc(size_t nmemb, size_t size)
{
void* p = calloc(nmemb, size);
sAmount += MallocSizeOfOnAlloc(p);
return p;
}
static void Free(void* p)
{
sAmount -= MallocSizeOfOnFree(p);
free(p);
}
private:
// |sAmount| can be (implicitly) accessed by multiple threads, so it
// must be thread-safe.
static Atomic<size_t> sAmount;
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc)
MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree)
NS_IMETHODIMP
CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData)
{
return MOZ_COLLECT_REPORT(
"explicit/media/libvpx", KIND_HEAP, UNITS_BYTES, sAmount,
"explicit/media/libvpx", KIND_HEAP, UNITS_BYTES, MemoryAllocated(),
"Memory allocated through libvpx for WebM media files.");
}
};
NS_IMPL_ISUPPORTS1(VPXReporter, nsIMemoryReporter)
/* static */ Atomic<size_t> VPXReporter::sAmount;
/* static */ template<> Atomic<size_t> CountingAllocatorBase<VPXReporter>::sAmount(0);
#endif /* MOZ_VPX */
EXPORT_XPCOM_API(nsresult)
@ -703,17 +572,17 @@ NS_InitXPCOM2(nsIServiceManager* *result,
mozilla::SetICUMemoryFunctions();
// Do the same for libogg.
ogg_set_mem_functions(OggReporter::Alloc,
OggReporter::Calloc,
OggReporter::Realloc,
OggReporter::Free);
ogg_set_mem_functions(OggReporter::CountingMalloc,
OggReporter::CountingCalloc,
OggReporter::CountingRealloc,
OggReporter::CountingFree);
#ifdef MOZ_VPX
// And for VPX.
vpx_mem_set_functions(VPXReporter::Alloc,
VPXReporter::Calloc,
VPXReporter::Realloc,
VPXReporter::Free,
vpx_mem_set_functions(VPXReporter::CountingMalloc,
VPXReporter::CountingCalloc,
VPXReporter::CountingRealloc,
VPXReporter::CountingFree,
memcpy,
memset,
memmove);
@ -876,6 +745,11 @@ ShutdownXPCOM(nsIServiceManager* servMgr)
}
}
// This must happen after the shutdown of media and widgets, which
// are triggered by the NS_XPCOM_SHUTDOWN_OBSERVER_ID notification.
mozilla::layers::ImageBridgeChild::ShutDown();
mozilla::layers::CompositorParent::ShutDown();
NS_ProcessPendingEvents(thread);
mozilla::scache::StartupCache::DeleteSingleton();
if (observerService)