mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c.
This commit is contained in:
commit
0d4470969a
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -127,7 +127,9 @@ NS_IMETHODIMP_(bool)
|
||||
SVGMaskElement::IsAttributeMapped(const nsIAtom* name) const
|
||||
{
|
||||
static const MappedAttributeEntry* const map[] = {
|
||||
sColorMap,
|
||||
sFEFloodMap,
|
||||
sFillStrokeMap,
|
||||
sFiltersMap,
|
||||
sFontSpecificationMap,
|
||||
sGradientStopMap,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,3 @@
|
||||
[test_NuwaProcessCreation.html]
|
||||
run-if = toolkit == 'gonk'
|
||||
[test_child_docshell.html]
|
||||
|
85
dom/ipc/tests/test_child_docshell.html
Normal file
85
dom/ipc/tests/test_child_docshell.html
Normal 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>
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
16
extensions/spellcheck/hunspell/src/mozHunspellAllocator.h
Normal file
16
extensions/spellcheck/hunspell/src/mozHunspellAllocator.h
Normal 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
|
@ -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()) {
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
15
js/src/jit-test/tests/gc/bug-992866.js
Normal file
15
js/src/jit-test/tests/gc/bug-992866.js
Normal 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]);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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(¬Zero);
|
||||
}
|
||||
@ -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(¬Zero);
|
||||
}
|
||||
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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() {}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
34
layout/reftests/bugs/985303-1-ref.html
Normal file
34
layout/reftests/bugs/985303-1-ref.html
Normal 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>
|
38
layout/reftests/bugs/985303-1a.html
Normal file
38
layout/reftests/bugs/985303-1a.html
Normal 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>
|
40
layout/reftests/bugs/985303-1b.html
Normal file
40
layout/reftests/bugs/985303-1b.html
Normal 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>
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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 |
18
layout/reftests/svg/mask-basic-04.svg
Normal file
18
layout/reftests/svg/mask-basic-04.svg
Normal 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 |
18
layout/reftests/svg/pattern-basic-01.svg
Normal file
18
layout/reftests/svg/pattern-basic-01.svg
Normal 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 |
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -49,7 +49,6 @@ EXPORTS += [
|
||||
'nsDebugImpl.h',
|
||||
'nsError.h',
|
||||
'nsGZFileWriter.h',
|
||||
'nsIAllocator.h',
|
||||
'nsIID.h',
|
||||
'nsInterfaceRequestorAgg.h',
|
||||
'nsISizeOf.h',
|
||||
|
@ -10,7 +10,6 @@
|
||||
#ifndef nsAllocator_h__
|
||||
#define nsAllocator_h__
|
||||
|
||||
#include "nsIAllocator.h"
|
||||
#include "nsAgg.h"
|
||||
#include "nsIFactory.h"
|
||||
|
||||
|
@ -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___ */
|
@ -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) \
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user