Merge mozilla-central to autoland

This commit is contained in:
Carsten "Tomcat" Book 2017-06-08 15:24:16 +02:00
Родитель 865c58e29c b9d94b34d4
Коммит cb5ce9d807
59 изменённых файлов: 1459 добавлений и 719 удалений

Просмотреть файл

@ -49,6 +49,7 @@ RCINCLUDE = 'AccessibleHandler.rc'
# we add the prefix "Proxy" to all of the generated counterparts.
DEFINES['ENTRY_PREFIX'] = 'Proxy'
DEFINES['REGISTER_PROXY_DLL'] = True
LIBRARY_DEFINES['MOZ_MSCOM_REMARSHAL_NO_HANDLER'] = True
# We want to generate distinct UUIDs on a per-channel basis, so we need
# finer granularity than the standard preprocessor definitions offer.

Просмотреть файл

@ -540,7 +540,8 @@ BrowserGlue.prototype = {
this._flashHangCount = 0;
this._firstWindowReady = new Promise(resolve => this._firstWindowLoaded = resolve);
if (AppConstants.platform == "macosx") {
if (AppConstants.platform == "macosx" ||
(AppConstants.platform == "win" && AppConstants.RELEASE_OR_BETA)) {
// Handles prompting to inform about incompatibilites when accessibility
// and e10s are active together.
E10SAccessibilityCheck.init();

Просмотреть файл

@ -12,13 +12,14 @@ const {
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const Actions = require("../actions/index");
const { FILTER_SEARCH_DELAY, FILTER_FLAGS } = require("../constants");
const { FILTER_SEARCH_DELAY } = require("../constants");
const {
getDisplayedRequestsSummary,
getRequestFilterTypes,
isNetworkDetailsToggleButtonDisabled,
} = require("../selectors/index");
const { autocompleteProvider } = require("../utils/filter-text-utils");
const { L10N } = require("../utils/l10n");
// Components
@ -92,11 +93,6 @@ const Toolbar = createClass({
);
});
// Setup autocomplete list
let negativeAutocompleteList = FILTER_FLAGS.map((item) => `-${item}`);
let autocompleteList = [...FILTER_FLAGS, ...negativeAutocompleteList]
.map((item) => `${item}:`);
return (
span({ className: "devtools-toolbar devtools-toolbar-container" },
span({ className: "devtools-toolbar-group" },
@ -114,7 +110,7 @@ const Toolbar = createClass({
placeholder: SEARCH_PLACE_HOLDER,
type: "filter",
onChange: setRequestFilterText,
autocompleteList,
autocompleteProvider,
}),
button({
className: toggleButtonClassName.join(" "),

Просмотреть файл

@ -242,6 +242,50 @@ function isFreetextMatch(item, text) {
return match;
}
/**
* Generates an autocomplete list for the search-box for network monitor
*
* It expects an entire string of the searchbox ie "is:cached pr".
* The string is then tokenized into "is:cached" and "pr"
*
* @param {string} filter - The entire search string of the search box
* @return {Array} - The output is an array of objects as below
* [{value: "is:cached protocol", displayValue: "protocol"}[, ...]]
* `value` is used to update the search-box input box for given item
* `displayValue` is used to render the autocomplete list
*/
function autocompleteProvider(filter) {
if (!filter) {
return [];
}
let negativeAutocompleteList = FILTER_FLAGS.map((item) => `-${item}`);
let baseList = [...FILTER_FLAGS, ...negativeAutocompleteList]
.map((item) => `${item}:`);
// The last token is used to filter the base autocomplete list
let tokens = filter.split(/\s+/g);
let lastToken = tokens[tokens.length - 1];
let previousTokens = tokens.slice(0, tokens.length - 1);
// Autocomplete list is not generated for empty lastToken
if (!lastToken) {
return [];
}
return baseList
.filter((item) => {
return item.toLowerCase().startsWith(lastToken.toLowerCase())
&& item.toLowerCase() !== lastToken.toLowerCase();
})
.sort()
.map(item => ({
value: [...previousTokens, item].join(" "),
displayValue: item,
}));
}
module.exports = {
isFreetextMatch,
autocompleteProvider,
};

Просмотреть файл

@ -10,7 +10,15 @@ module.exports = createClass({
displayName: "AutocompletePopup",
propTypes: {
list: PropTypes.array.isRequired,
/**
* autocompleteProvider takes search-box's entire input text as `filter` argument
* ie. "is:cached pr"
* returned value is array of objects like below
* [{value: "is:cached protocol", displayValue: "protocol"}[, ...]]
* `value` is used to update the search-box input box for given item
* `displayValue` is used to render the autocomplete list
*/
autocompleteProvider: PropTypes.func.isRequired,
filter: PropTypes.string.isRequired,
onItemSelected: PropTypes.func.isRequired,
},
@ -32,14 +40,11 @@ module.exports = createClass({
}
},
computeState({ filter, list }) {
let filteredList = list.filter((item) => {
return item.toLowerCase().startsWith(filter.toLowerCase())
&& item.toLowerCase() !== filter.toLowerCase();
}).sort();
let selectedIndex = filteredList.length == 1 ? 0 : -1;
computeState({ autocompleteProvider, filter }) {
let list = autocompleteProvider(filter);
let selectedIndex = list.length == 1 ? 0 : -1;
return { filteredList, selectedIndex };
return { list, selectedIndex };
},
/**
@ -55,8 +60,7 @@ module.exports = createClass({
* This method is public.
*/
jumpToBottom() {
let selectedIndex = this.state.filteredList.length - 1;
this.setState({ selectedIndex });
this.setState({ selectedIndex: this.state.list.length - 1 });
},
/**
@ -67,14 +71,14 @@ module.exports = createClass({
* @param {number} increment - No. of hops in the direction
*/
jumpBy(increment = 1) {
let { filteredList, selectedIndex } = this.state;
let { list, selectedIndex } = this.state;
let nextIndex = selectedIndex + increment;
if (increment > 0) {
// Positive cycling
nextIndex = nextIndex > filteredList.length - 1 ? 0 : nextIndex;
nextIndex = nextIndex > list.length - 1 ? 0 : nextIndex;
} else if (increment < 0) {
// Inverse cycling
nextIndex = nextIndex < 0 ? filteredList.length - 1 : nextIndex;
nextIndex = nextIndex < 0 ? list.length - 1 : nextIndex;
}
this.setState({selectedIndex: nextIndex});
},
@ -85,7 +89,7 @@ module.exports = createClass({
*/
select() {
if (this.refs.selected) {
this.props.onItemSelected(this.refs.selected.textContent);
this.props.onItemSelected(this.refs.selected.dataset.value);
}
},
@ -95,13 +99,13 @@ module.exports = createClass({
},
render() {
let { filteredList } = this.state;
let { list } = this.state;
return filteredList.length > 0 && dom.div(
return list.length > 0 && dom.div(
{ className: "devtools-autocomplete-popup devtools-monospace" },
dom.ul(
{ className: "devtools-autocomplete-listbox" },
filteredList.map((item, i) => {
list.map((item, i) => {
let isSelected = this.state.selectedIndex == i;
let itemClassList = ["autocomplete-item"];
@ -111,10 +115,11 @@ module.exports = createClass({
return dom.li({
key: i,
"data-index": i,
"data-value": item.value,
className: itemClassList.join(" "),
ref: isSelected ? "selected" : null,
onMouseDown: this.onMouseDown,
}, item);
}, item.displayValue);
})
)
);

Просмотреть файл

@ -22,13 +22,7 @@ module.exports = createClass({
onChange: PropTypes.func,
placeholder: PropTypes.string,
type: PropTypes.string,
autocompleteList: PropTypes.array,
},
getDefaultProps() {
return {
autocompleteList: [],
};
autocompleteProvider: PropTypes.func,
},
getInitialState() {
@ -66,6 +60,7 @@ module.exports = createClass({
onChange() {
if (this.state.value !== this.refs.input.value) {
this.setState({
focused: true,
value: this.refs.input.value,
});
}
@ -102,10 +97,8 @@ module.exports = createClass({
},
onKeyDown(e) {
let { autocompleteList } = this.props;
let { autocomplete } = this.refs;
if (autocompleteList.length == 0) {
if (!autocomplete || autocomplete.state.list.length <= 0) {
return;
}
@ -144,13 +137,12 @@ module.exports = createClass({
let {
type = "search",
placeholder,
autocompleteList
autocompleteProvider,
} = this.props;
let { value } = this.state;
let divClassList = ["devtools-searchbox", "has-clear-btn"];
let inputClassList = [`devtools-${type}input`];
let showAutocomplete =
autocompleteList.length > 0 && this.state.focused && value !== "";
let showAutocomplete = autocompleteProvider && this.state.focused && value !== "";
if (value !== "") {
inputClassList.push("filled");
@ -173,7 +165,7 @@ module.exports = createClass({
onClick: this.onClearButtonClick
}),
showAutocomplete && AutocompletePopup({
list: autocompleteList,
autocompleteProvider,
filter: value,
ref: "autocomplete",
onItemSelected: (itemValue) => {

Просмотреть файл

@ -43,7 +43,8 @@ window.onload = async function () {
);
const { component, $ } = await createComponentTest(SearchBox, {
type: "search",
autocompleteList: [
autocompleteProvider: (filter) => {
let baseList = [
"foo",
"BAR",
"baZ",
@ -56,7 +57,30 @@ window.onload = async function () {
"a3",
"a4",
"a5",
],
];
if (!filter) {
return [];
}
let tokens = filter.split(/\s+/g);
let lastToken = tokens[tokens.length - 1];
let previousTokens = tokens.slice(0, tokens.length - 1);
if (!lastToken) {
return [];
}
return baseList
.filter((item) => {
return item.toLowerCase().startsWith(lastToken.toLowerCase())
&& item.toLowerCase() !== lastToken.toLowerCase();
})
.sort()
.map(item => ({
value: [...previousTokens, item].join(" "),
displayValue: item,
}));
},
onChange: () => null,
});
const { refs } = component;
@ -150,6 +174,8 @@ window.onload = async function () {
ok(!$(".devtools-autocomplete-popup"), "Enter/Return hides the popup");
// Escape should remove the autocomplete component
synthesizeKey("VK_BACK_SPACE", {});
await forceRender(component);
synthesizeKey("VK_ESCAPE", {});
await forceRender(component);
ok(!$(".devtools-autocomplete-popup"),
@ -182,10 +208,25 @@ window.onload = async function () {
ok(!$(".devtools-autocomplete-popup"), "Mouse click on item hides the popup");
}
async function testTokenizedAutocomplete() {
// Test for string "pqr ab" which should show list of ABC, abc
sendString(" ab");
await forceRender(component);
compareAutocompleteList($(".devtools-autocomplete-listbox"), ["ABC", "abc"]);
// Select the first element, value now should be "pqr ABC"
synthesizeMouseAtCenter(
$(".devtools-autocomplete-listbox .autocomplete-item:nth-child(1)"),
{}, window
);
is(component.state.value, "pqr ABC", "Post Tokenization value selection");
}
add_task(async function () {
await testSearchBoxWithAutocomplete();
await testKeyEventsWithAutocomplete();
await testMouseEventsWithAutocomplete();
await testTokenizedAutocomplete();
});
};
</script>

Просмотреть файл

@ -81,6 +81,7 @@ const ErrorDocs = {
JSMSG_BAD_URI: "Malformed_URI",
JSMSG_DEPRECATED_DELETE_OPERAND: "Delete_in_strict_mode",
JSMSG_MISSING_FORMAL: "Missing_formal_parameter",
JSMSG_CANT_TRUNCATE_ARRAY: "Non_configurable_array_element",
};
const MIXED_CONTENT_LEARN_MORE = "https://developer.mozilla.org/docs/Web/Security/Mixed_content";

Просмотреть файл

@ -414,8 +414,10 @@ DOMIntersectionObserver::Update(nsIDocument* aDocument, DOMHighResTimeStamp time
if (intersectionRect.isSome() && !isSameDoc) {
nsRect rect = intersectionRect.value();
nsPresContext* presContext = targetFrame->PresContext();
nsLayoutUtils::TransformRect(rootFrame,
presContext->PresShell()->GetRootScrollFrame(), rect);
nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
if (rootScrollFrame) {
nsLayoutUtils::TransformRect(rootFrame, rootScrollFrame, rect);
}
intersectionRect = Some(rect);
}
}

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xhtml:div id="target"></xhtml:div>
</window>

Просмотреть файл

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<iframe id="iframe" src="1370968-inner.xul"></iframe>
<script>
var io = new IntersectionObserver(function () {
}, { });
var iframe = document.getElementById('iframe');
iframe.onload = function () {
io.observe(iframe.contentDocument.getElementById('target'));
};
</script>
</body>
</html>

Просмотреть файл

@ -201,10 +201,6 @@ load 1154598.xhtml
load 1157995.html
load 1158412.html
load 1181619.html
load structured_clone_container_throws.html
HTTP(..) load xhr_abortinprogress.html
load xhr_empty_datauri.html
load xhr_html_nullresponse.html
load 1230422.html
load 1251361.html
load 1304437.html
@ -212,7 +208,12 @@ pref(dom.IntersectionObserver.enabled,true) load 1324209.html
pref(dom.IntersectionObserver.enabled,true) load 1326194-1.html
pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
pref(dom.IntersectionObserver.enabled,true) load 1332939.html
pref(dom.IntersectionObserver.enabled,true) load 1353529.xul
pref(dom.webcomponents.enabled,true) load 1341693.html
pref(dom.IntersectionObserver.enabled,true) load 1353529.xul
pref(dom.IntersectionObserver.enabled,true) load 1369363.xul
load 1370072.html
pref(dom.IntersectionObserver.enabled,true) load 1370968.html
load structured_clone_container_throws.html
HTTP(..) load xhr_abortinprogress.html
load xhr_empty_datauri.html
load xhr_html_nullresponse.html

Просмотреть файл

@ -56,6 +56,8 @@
#include "nsGlobalWindow.h"
#include "nsScriptNameSpaceManager.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/MainThreadIdlePeriod.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/ErrorEvent.h"
@ -63,7 +65,7 @@
#include "nsAXPCNativeCallContext.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/SystemGroup.h"
#include "nsRefreshDriver.h"
#include "nsJSPrincipals.h"
#ifdef XP_MACOSX
@ -111,21 +113,24 @@ const size_t gStackSize = 8192;
// Maximum amount of time that should elapse between incremental GC slices
#define NS_INTERSLICE_GC_DELAY 100 // ms
// If we haven't painted in 100ms, or we're in e10s parent process and
// user isn't active, we allow for a longer GC budget.
#define NS_INTERSLICE_GC_BUDGET 40 // ms
// The amount of time we wait between a request to CC (after GC ran)
// and doing the actual CC.
#define NS_CC_DELAY 6000 // ms
#define NS_CC_SKIPPABLE_DELAY 250 // ms
// ForgetSkippable is usually fast, so we can use small budgets.
// This isn't a real budget but a hint to CollectorRunner whether there
// is enough time to call ForgetSkippable.
static const int64_t kForgetSkippableSliceDuration = 2;
// Maximum amount of time that should elapse between incremental CC slices
static const int64_t kICCIntersliceDelay = 32; // ms
// Time budget for an incremental CC slice
// Time budget for an incremental CC slice when using timer to run it.
static const int64_t kICCSliceBudget = 5; // ms
// Minimum budget for an incremental CC slice when using idle time to run it.
static const int64_t kIdleICCSliceBudget = 3; // ms
// Maximum total duration for an ICC
static const uint32_t kMaxICCDuration = 2000; // ms
@ -144,14 +149,16 @@ static const uint32_t kMaxICCDuration = 2000; // ms
// Large value used to specify that a script should run essentially forever
#define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
class CollectorRunner;
// if you add statics here, add them to the list in StartupJSEnvironment
static nsITimer *sGCTimer;
static nsITimer *sShrinkingGCTimer;
static nsITimer *sCCTimer;
static nsITimer *sICCTimer;
static StaticRefPtr<CollectorRunner> sCCRunner;
static StaticRefPtr<CollectorRunner> sICCRunner;
static nsITimer *sFullGCTimer;
static nsITimer *sInterSliceGCTimer;
static StaticRefPtr<CollectorRunner> sInterSliceGCRunner;
static TimeStamp sLastCCEndTime;
@ -176,7 +183,7 @@ static uint32_t sCCollectedZonesWaitingForGC;
static uint32_t sLikelyShortLivingObjectsNeedingGC;
static bool sPostGCEventsToConsole;
static bool sPostGCEventsToObserver;
static int32_t sCCTimerFireCount = 0;
static int32_t sCCRunnerFireCount = 0;
static uint32_t sMinForgetSkippableTime = UINT32_MAX;
static uint32_t sMaxForgetSkippableTime = 0;
static uint32_t sTotalForgetSkippableTime = 0;
@ -188,7 +195,6 @@ static bool sNeedsFullCC = false;
static bool sNeedsFullGC = false;
static bool sNeedsGCAfterCC = false;
static bool sIncrementalCC = false;
static bool sDidPaintAfterPreviousICCSlice = false;
static int32_t sActiveIntersliceGCBudget = 0; // ms;
static nsScriptNameSpaceManager *gNameSpaceManager;
@ -223,6 +229,178 @@ static bool sIsCompactingOnUserInactive = false;
static int32_t sExpensiveCollectorPokes = 0;
static const int32_t kPokesBetweenExpensiveCollectorTriggers = 5;
// Return true if some meaningful work was done.
typedef bool (*CollectorRunnerCallback) (TimeStamp aDeadline, void* aData);
// Repeating callback runner for CC and GC.
class CollectorRunner final : public IdleRunnable
{
public:
static already_AddRefed<CollectorRunner>
Create(CollectorRunnerCallback aCallback, uint32_t aDelay,
int64_t aBudget, bool aRepeating, void* aData = nullptr)
{
RefPtr<CollectorRunner> runner =
new CollectorRunner(aCallback, aDelay, aBudget, aRepeating, aData);
runner->Schedule(false); // Initial scheduling shouldn't use idle dispatch.
return runner.forget();
}
NS_IMETHOD Run() override
{
if (!mCallback) {
return NS_OK;
}
// Deadline is null when called from timer.
bool deadLineWasNull = mDeadline.IsNull();
bool didRun = false;
if (deadLineWasNull || ((TimeStamp::Now() + mBudget) < mDeadline)) {
CancelTimer();
didRun = mCallback(mDeadline, mData);
}
if (mCallback && (mRepeating || !didRun)) {
// If we didn't do meaningful work, don't schedule using immediate
// idle dispatch, since that could lead to a loop until the idle
// period ends.
Schedule(didRun);
}
return NS_OK;
}
static void
TimedOut(nsITimer* aTimer, void* aClosure)
{
RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
runnable->Run();
}
void SetDeadline(mozilla::TimeStamp aDeadline) override
{
mDeadline = aDeadline;
};
void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
{
if (mTimerActive) {
return;
}
mTarget = aTarget;
if (!mTimer) {
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
} else {
mTimer->Cancel();
}
if (mTimer) {
mTimer->SetTarget(mTarget);
mTimer->InitWithFuncCallback(TimedOut, this, aDelay,
nsITimer::TYPE_ONE_SHOT);
mTimerActive = true;
}
}
nsresult Cancel() override
{
CancelTimer();
mTimer = nullptr;
mScheduleTimer = nullptr;
mCallback = nullptr;
return NS_OK;
}
static void
ScheduleTimedOut(nsITimer* aTimer, void* aClosure)
{
RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
runnable->Schedule(true);
}
void Schedule(bool aAllowIdleDispatch)
{
if (!mCallback) {
return;
}
if (sShuttingDown) {
Cancel();
return;
}
mDeadline = TimeStamp();
TimeStamp now = TimeStamp::Now();
TimeStamp hint = nsRefreshDriver::GetIdleDeadlineHint(now);
if (hint != now) {
// RefreshDriver is ticking, let it schedule the idle dispatch.
nsRefreshDriver::DispatchIdleRunnableAfterTick(this, mDelay);
// Ensure we get called at some point, even if RefreshDriver is stopped.
SetTimer(mDelay, mTarget);
} else {
// RefreshDriver doesn't seem to be running.
if (aAllowIdleDispatch) {
nsCOMPtr<nsIRunnable> runnable = this;
NS_IdleDispatchToCurrentThread(runnable.forget(), mDelay);
SetTimer(mDelay, mTarget);
} else {
if (!mScheduleTimer) {
mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (!mScheduleTimer) {
return;
}
} else {
mScheduleTimer->Cancel();
}
// We weren't allowed to do idle dispatch immediately, do it after a
// short timeout.
mScheduleTimer->InitWithFuncCallback(ScheduleTimedOut, this, 16,
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY);
}
}
}
private:
explicit CollectorRunner(CollectorRunnerCallback aCallback,
uint32_t aDelay, int64_t aBudget,
bool aRepeating, void* aData)
: mCallback(aCallback), mDelay(aDelay)
, mBudget(TimeDuration::FromMilliseconds(aBudget))
, mRepeating(aRepeating), mTimerActive(false), mData(aData)
{
}
~CollectorRunner()
{
CancelTimer();
}
void CancelTimer()
{
nsRefreshDriver::CancelIdleRunnable(this);
if (mTimer) {
mTimer->Cancel();
}
if (mScheduleTimer) {
mScheduleTimer->Cancel();
}
mTimerActive = false;
}
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsITimer> mScheduleTimer;
nsCOMPtr<nsIEventTarget> mTarget;
CollectorRunnerCallback mCallback;
uint32_t mDelay;
TimeStamp mDeadline;
TimeDuration mBudget;
bool mRepeating;
bool mTimerActive;
void* mData;
};
static const char*
ProcessNameForCollectorLog()
{
@ -299,10 +477,10 @@ KillTimers()
{
nsJSContext::KillGCTimer();
nsJSContext::KillShrinkingGCTimer();
nsJSContext::KillCCTimer();
nsJSContext::KillICCTimer();
nsJSContext::KillCCRunner();
nsJSContext::KillICCRunner();
nsJSContext::KillFullGCTimer();
nsJSContext::KillInterSliceGCTimer();
nsJSContext::KillInterSliceGCRunner();
}
// If we collected a substantial amount of cycles, poke the GC since more objects
@ -1451,7 +1629,7 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
//static
void
nsJSContext::RunCycleCollectorSlice()
nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline)
{
if (!NS_IsMainThread()) {
return;
@ -1467,33 +1645,40 @@ nsJSContext::RunCycleCollectorSlice()
js::SliceBudget budget = js::SliceBudget::unlimited();
if (sIncrementalCC) {
int64_t baseBudget = kICCSliceBudget;
if (!aDeadline.IsNull()) {
baseBudget = int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds());
}
if (gCCStats.mBeginTime.IsNull()) {
// If no CC is in progress, use the standard slice time.
budget = js::SliceBudget(js::TimeBudget(kICCSliceBudget));
budget = js::SliceBudget(js::TimeBudget(baseBudget));
} else {
TimeStamp now = TimeStamp::Now();
// Only run a limited slice if we're within the max running time.
uint32_t runningTime = TimeBetween(gCCStats.mBeginTime, now);
if (runningTime < kMaxICCDuration) {
// Try to make up for a delay in running this slice.
float sliceDelayMultiplier = TimeBetween(gCCStats.mEndSliceTime, now) / (float)kICCIntersliceDelay;
float delaySliceBudget = kICCSliceBudget * sliceDelayMultiplier;
const float maxSlice = MainThreadIdlePeriod::GetLongIdlePeriod();
// Increase slice budgets up to |maxLaterSlice| as we approach
// Try to make up for a delay in running this slice.
float sliceDelayMultiplier =
TimeBetween(gCCStats.mEndSliceTime, now) / (float)kICCIntersliceDelay;
float delaySliceBudget =
std::min(baseBudget * sliceDelayMultiplier, maxSlice);
// Increase slice budgets up to |maxSlice| as we approach
// half way through the ICC, to avoid large sync CCs.
float percentToHalfDone = std::min(2.0f * runningTime / kMaxICCDuration, 1.0f);
const float maxLaterSlice = 40.0f;
float laterSliceBudget = maxLaterSlice * percentToHalfDone;
float laterSliceBudget = maxSlice * percentToHalfDone;
budget = js::SliceBudget(js::TimeBudget(std::max({delaySliceBudget,
laterSliceBudget, (float)kICCSliceBudget})));
laterSliceBudget, (float)baseBudget})));
}
}
}
nsCycleCollector_collectSlice(budget, sDidPaintAfterPreviousICCSlice);
sDidPaintAfterPreviousICCSlice = false;
nsCycleCollector_collectSlice(budget);
gCCStats.FinishCycleCollectionSlice();
}
@ -1529,11 +1714,11 @@ nsJSContext::GetMaxCCSliceTimeSinceClear()
return gCCStats.mMaxSliceTimeSinceClear;
}
static void
ICCTimerFired(nsITimer* aTimer, void* aClosure)
static bool
ICCRunnerFired(TimeStamp aDeadline, void* aData)
{
if (sDidShutdown) {
return;
return false;
}
// Ignore ICC timer fires during IGC. Running ICC during an IGC will cause us
@ -1543,14 +1728,15 @@ ICCTimerFired(nsITimer* aTimer, void* aClosure)
PRTime now = PR_Now();
if (sCCLockedOutTime == 0) {
sCCLockedOutTime = now;
return;
return false;
}
if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
return;
return false;
}
}
nsJSContext::RunCycleCollectorSlice();
nsJSContext::RunCycleCollectorSlice(aDeadline);
return true;
}
//static
@ -1562,22 +1748,16 @@ nsJSContext::BeginCycleCollectionCallback()
gCCStats.mBeginTime = gCCStats.mBeginSliceTime.IsNull() ? TimeStamp::Now() : gCCStats.mBeginSliceTime;
gCCStats.mSuspected = nsCycleCollector_suspectedCount();
KillCCTimer();
KillCCRunner();
gCCStats.RunForgetSkippable();
MOZ_ASSERT(!sICCTimer, "Tried to create a new ICC timer when one already existed.");
MOZ_ASSERT(!sICCRunner, "Tried to create a new ICC timer when one already existed.");
// Create an ICC timer even if ICC is globally disabled, because we could be manually triggering
// an incremental collection, and we want to be sure to finish it.
CallCreateInstance("@mozilla.org/timer;1", &sICCTimer);
if (sICCTimer) {
sICCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
sICCTimer->InitWithNamedFuncCallback(ICCTimerFired, nullptr,
kICCIntersliceDelay,
nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
"ICCTimerFired");
}
sICCRunner = CollectorRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
kIdleICCSliceBudget, true);
}
static_assert(NS_GC_DELAY > kMaxICCDuration, "A max duration ICC shouldn't reduce GC delay to 0");
@ -1588,7 +1768,7 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
{
MOZ_ASSERT(NS_IsMainThread());
nsJSContext::KillICCTimer();
nsJSContext::KillICCRunner();
// Update timing information for the current slice before we log it, if
// we previously called PrepareForCycleCollectionSlice(). During shutdown
@ -1736,16 +1916,24 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
}
// static
void
InterSliceGCTimerFired(nsITimer *aTimer, void *aClosure)
bool
InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData)
{
nsJSContext::KillInterSliceGCTimer();
int64_t budget = XRE_IsE10sParentProcess() && nsContentUtils::GetUserIsInteracting() && sActiveIntersliceGCBudget ?
sActiveIntersliceGCBudget : NS_INTERSLICE_GC_BUDGET;
nsJSContext::GarbageCollectNow(JS::gcreason::INTER_SLICE_GC,
nsJSContext::KillInterSliceGCRunner();
MOZ_ASSERT(sActiveIntersliceGCBudget > 0);
int64_t budget = sActiveIntersliceGCBudget;
if (!aDeadline.IsNull()) {
budget = int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds());
}
uintptr_t reason = reinterpret_cast<uintptr_t>(aData);
nsJSContext::GarbageCollectNow(aData ?
static_cast<JS::gcreason::Reason>(reason) :
JS::gcreason::INTER_SLICE_GC,
nsJSContext::IncrementalGC,
nsJSContext::NonShrinkingGC,
budget);
return true;
}
// static
@ -1753,9 +1941,12 @@ void
GCTimerFired(nsITimer *aTimer, void *aClosure)
{
nsJSContext::KillGCTimer();
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure);
nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason>(reason),
nsJSContext::IncrementalGC);
// Now start the actual GC after initial timer has fired.
sInterSliceGCRunner = CollectorRunner::Create(InterSliceGCRunnerFired,
NS_INTERSLICE_GC_DELAY,
sActiveIntersliceGCBudget,
false,
aClosure);
}
// static
@ -1778,11 +1969,11 @@ ShouldTriggerCC(uint32_t aSuspected)
TimeUntilNow(sLastCCEndTime) > NS_CC_FORCED);
}
static void
CCTimerFired(nsITimer *aTimer, void *aClosure)
static bool
CCRunnerFired(TimeStamp aDeadline, void* aData)
{
if (sDidShutdown) {
return;
return false;
}
static uint32_t ccDelay = NS_CC_DELAY;
@ -1791,48 +1982,53 @@ CCTimerFired(nsITimer *aTimer, void *aClosure)
PRTime now = PR_Now();
if (sCCLockedOutTime == 0) {
// Reset sCCTimerFireCount so that we run forgetSkippable
// Reset sCCRunnerFireCount so that we run forgetSkippable
// often enough before CC. Because of reduced ccDelay
// forgetSkippable will be called just a few times.
// NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling
// forgetSkippable and CycleCollectNow eventually.
sCCTimerFireCount = 0;
sCCRunnerFireCount = 0;
sCCLockedOutTime = now;
return;
return false;
}
if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
return;
return false;
}
}
++sCCTimerFireCount;
++sCCRunnerFireCount;
bool didDoWork = false;
// During early timer fires, we only run forgetSkippable. During the first
// late timer fire, we decide if we are going to have a second and final
// late timer fire, where we may begin to run the CC. Should run at least one
// early timer fire to allow cleanup before the CC.
int32_t numEarlyTimerFires = std::max((int32_t)ccDelay / NS_CC_SKIPPABLE_DELAY - 2, 1);
bool isLateTimerFire = sCCTimerFireCount > numEarlyTimerFires;
bool isLateTimerFire = sCCRunnerFireCount > numEarlyTimerFires;
uint32_t suspected = nsCycleCollector_suspectedCount();
if (isLateTimerFire && ShouldTriggerCC(suspected)) {
if (sCCTimerFireCount == numEarlyTimerFires + 1) {
if (sCCRunnerFireCount == numEarlyTimerFires + 1) {
FireForgetSkippable(suspected, true);
didDoWork = true;
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
// Our efforts to avoid a CC have failed, so we return to let the
// timer fire once more to trigger a CC.
return;
return didDoWork;
}
} else {
// We are in the final timer fire and still meet the conditions for
// triggering a CC. Let RunCycleCollectorSlice finish the current IGC, if
// any because that will allow us to include the GC time in the CC pause.
nsJSContext::RunCycleCollectorSlice();
nsJSContext::RunCycleCollectorSlice(aDeadline);
didDoWork = true;
}
} else if (((sPreviousSuspectedCount + 100) <= suspected) ||
(sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS)) {
// Only do a forget skippable if there are more than a few new objects
// or we're doing the initial forget skippables.
FireForgetSkippable(suspected, false);
didDoWork = true;
}
if (isLateTimerFire) {
@ -1841,8 +2037,10 @@ CCTimerFired(nsITimer *aTimer, void *aClosure)
// We have either just run the CC or decided we don't want to run the CC
// next time, so kill the timer.
sPreviousSuspectedCount = 0;
nsJSContext::KillCCTimer();
nsJSContext::KillCCRunner();
}
return didDoWork;
}
// static
@ -1889,13 +2087,13 @@ ReadyToTriggerExpensiveCollectorTimer()
}
// Check all of the various collector timers and see if they are waiting to fire.
// For the synchronous collector timers, sGCTimer and sCCTimer, we only want to trigger
// the collection occasionally, because they are expensive. The incremental collector
// timers, sInterSliceGCTimer and sICCTimer, are fast and need to be run many times, so
// Check all of the various collector timers/runners and see if they are waiting to fire.
// For the synchronous collector timers/runners, sGCTimer and sCCRunner, we only want to
// trigger the collection occasionally, because they are expensive. The incremental collector
// timers, sInterSliceGCRunner and sICCRunner, are fast and need to be run many times, so
// always run their corresponding timer.
// This does not check sFullGCTimer, as that's an even more expensive collection we run
// This does not check sFullGCTimer, as that's a more expensive collection we run
// on a long timer.
// static
@ -1913,8 +2111,8 @@ nsJSContext::RunNextCollectorTimer()
return;
}
if (sInterSliceGCTimer) {
InterSliceGCTimerFired(nullptr, nullptr);
if (sInterSliceGCRunner) {
InterSliceGCRunnerFired(TimeStamp(), nullptr);
return;
}
@ -1922,15 +2120,15 @@ nsJSContext::RunNextCollectorTimer()
// anything if a GC is in progress.
MOZ_ASSERT(!sCCLockedOut, "Don't check the CC timers if the CC is locked out.");
if (sCCTimer) {
if (sCCRunner) {
if (ReadyToTriggerExpensiveCollectorTimer()) {
CCTimerFired(nullptr, nullptr);
CCRunnerFired(TimeStamp(), nullptr);
}
return;
}
if (sICCTimer) {
ICCTimerFired(nullptr, nullptr);
if (sICCRunner) {
ICCRunnerFired(TimeStamp(), nullptr);
return;
}
}
@ -1952,12 +2150,12 @@ nsJSContext::PokeGC(JS::gcreason::Reason aReason,
sNeedsFullGC = true;
}
if (sGCTimer || sInterSliceGCTimer) {
if (sGCTimer || sInterSliceGCRunner) {
// There's already a timer for GC'ing, just return
return;
}
if (sCCTimer) {
if (sCCRunner) {
// Make sure CC is called...
sNeedsFullCC = true;
// and GC after it.
@ -1965,7 +2163,7 @@ nsJSContext::PokeGC(JS::gcreason::Reason aReason,
return;
}
if (sICCTimer) {
if (sICCRunner) {
// Make sure GC is called after the current CC completes.
// No need to set sNeedsFullCC because we are currently running a CC.
sNeedsGCAfterCC = true;
@ -1991,6 +2189,7 @@ nsJSContext::PokeGC(JS::gcreason::Reason aReason,
: NS_GC_DELAY),
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
"GCTimerFired");
first = false;
}
@ -2020,24 +2219,19 @@ nsJSContext::PokeShrinkingGC()
void
nsJSContext::MaybePokeCC()
{
if (sCCTimer || sICCTimer || sShuttingDown || !sHasRunGC) {
if (sCCRunner || sICCRunner || sShuttingDown || !sHasRunGC) {
return;
}
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
sCCTimerFireCount = 0;
CallCreateInstance("@mozilla.org/timer;1", &sCCTimer);
if (!sCCTimer) {
return;
}
sCCRunnerFireCount = 0;
// We can kill some objects before running forgetSkippable.
nsCycleCollector_dispatchDeferredDeletion();
sCCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
sCCTimer->InitWithNamedFuncCallback(CCTimerFired, nullptr,
NS_CC_SKIPPABLE_DELAY,
nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
"CCTimerFired");
sCCRunner =
CollectorRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
kForgetSkippableSliceDuration, true);
}
}
@ -2061,11 +2255,11 @@ nsJSContext::KillFullGCTimer()
}
void
nsJSContext::KillInterSliceGCTimer()
nsJSContext::KillInterSliceGCRunner()
{
if (sInterSliceGCTimer) {
sInterSliceGCTimer->Cancel();
NS_RELEASE(sInterSliceGCTimer);
if (sInterSliceGCRunner) {
sInterSliceGCRunner->Cancel();
sInterSliceGCRunner = nullptr;
}
}
@ -2081,24 +2275,24 @@ nsJSContext::KillShrinkingGCTimer()
//static
void
nsJSContext::KillCCTimer()
nsJSContext::KillCCRunner()
{
sCCLockedOutTime = 0;
if (sCCTimer) {
sCCTimer->Cancel();
NS_RELEASE(sCCTimer);
if (sCCRunner) {
sCCRunner->Cancel();
sCCRunner = nullptr;
}
}
//static
void
nsJSContext::KillICCTimer()
nsJSContext::KillICCRunner()
{
sCCLockedOutTime = 0;
if (sICCTimer) {
sICCTimer->Cancel();
NS_RELEASE(sICCTimer);
if (sICCRunner) {
sICCRunner->Cancel();
sICCRunner = nullptr;
}
}
@ -2170,8 +2364,8 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
sCCLockedOut = false;
sIsCompactingOnUserInactive = false;
// May need to kill the inter-slice GC timer
nsJSContext::KillInterSliceGCTimer();
// May need to kill the inter-slice GC runner
nsJSContext::KillInterSliceGCRunner();
sCCollectedWaitingForGC = 0;
sCCollectedZonesWaitingForGC = 0;
@ -2212,15 +2406,11 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
case JS::GC_SLICE_END:
// Schedule another GC slice if the GC has more work to do.
nsJSContext::KillInterSliceGCTimer();
nsJSContext::KillInterSliceGCRunner();
if (!sShuttingDown && !aDesc.isComplete_) {
CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer);
sInterSliceGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
sInterSliceGCTimer->InitWithNamedFuncCallback(InterSliceGCTimerFired,
nullptr,
NS_INTERSLICE_GC_DELAY,
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
"InterSliceGCTimerFired");
sInterSliceGCRunner =
CollectorRunner::Create(InterSliceGCRunnerFired, NS_INTERSLICE_GC_DELAY,
sActiveIntersliceGCBudget, false);
}
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
@ -2274,7 +2464,7 @@ void
mozilla::dom::StartupJSEnvironment()
{
// initialize all our statics, so that we can restart XPCOM
sGCTimer = sShrinkingGCTimer = sFullGCTimer = sCCTimer = sICCTimer = nullptr;
sGCTimer = sShrinkingGCTimer = sFullGCTimer = nullptr;
sCCLockedOut = false;
sCCLockedOutTime = 0;
sLastCCEndTime = TimeStamp();
@ -2609,52 +2799,6 @@ nsJSContext::EnsureStatics()
sIsInitialized = true;
}
void
nsJSContext::NotifyDidPaint()
{
sDidPaintAfterPreviousICCSlice = true;
if (sICCTimer) {
static uint32_t sCount = 0;
// 16 here is the common value for refresh driver tick frequency.
static const uint32_t kTicksPerSliceDelay = kICCIntersliceDelay / 16;
if (++sCount % kTicksPerSliceDelay != 0) {
// Don't trigger CC slice all the time after paint, but often still.
// The key point is to trigger it right after paint, especially when
// we're running RefreshDriver constantly.
return;
}
sICCTimer->Cancel();
ICCTimerFired(nullptr, nullptr);
if (sICCTimer) {
sICCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
sICCTimer->InitWithNamedFuncCallback(ICCTimerFired, nullptr,
kICCIntersliceDelay,
nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
"ICCTimerFired");
}
} else if (sCCTimer) {
static uint32_t sCount = 0;
static const uint32_t kTicksPerForgetSkippableDelay =
NS_CC_SKIPPABLE_DELAY / 16;
if (++sCount % kTicksPerForgetSkippableDelay != 0) {
// The comment above about triggering CC slice applies to forget skippable
// too.
return;
}
sCCTimer->Cancel();
CCTimerFired(nullptr, nullptr);
if (sCCTimer) {
sCCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
sCCTimer->InitWithNamedFuncCallback(CCTimerFired, nullptr,
NS_CC_SKIPPABLE_DELAY,
nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
"CCTimerFired");
}
}
}
nsScriptNameSpaceManager*
mozilla::dom::GetNameSpaceManager()
{

Просмотреть файл

@ -15,6 +15,7 @@
#include "nsIXPConnect.h"
#include "nsIArray.h"
#include "mozilla/Attributes.h"
#include "mozilla/TimeStamp.h"
#include "nsThreadUtils.h"
#include "xpcpublic.h"
@ -91,7 +92,7 @@ public:
int32_t aExtraForgetSkippableCalls = 0);
// Run a cycle collector slice, using a heuristic to decide how long to run it.
static void RunCycleCollectorSlice();
static void RunCycleCollectorSlice(mozilla::TimeStamp aDeadline);
// Run a cycle collector slice, using the given work budget.
static void RunCycleCollectorWorkSlice(int64_t aWorkBudget);
@ -113,10 +114,10 @@ public:
static void KillShrinkingGCTimer();
static void MaybePokeCC();
static void KillCCTimer();
static void KillICCTimer();
static void KillCCRunner();
static void KillICCRunner();
static void KillFullGCTimer();
static void KillInterSliceGCTimer();
static void KillInterSliceGCRunner();
// Calling LikelyShortLivingObjectCreated() makes a GC more likely.
static void LikelyShortLivingObjectCreated();
@ -131,7 +132,6 @@ public:
return global ? mGlobalObjectRef.get() : nullptr;
}
static void NotifyDidPaint();
protected:
virtual ~nsJSContext();

Просмотреть файл

@ -490,6 +490,7 @@ ContentChild* ContentChild::sSingleton;
ContentChild::ContentChild()
: mID(uint64_t(-1))
#if defined(XP_WIN) && defined(ACCESSIBILITY)
, mMainChromeTid(0)
, mMsaaID(0)
#endif
, mCanOverrideProcessName(true)
@ -1390,6 +1391,7 @@ StartMacOSContentSandbox()
}
nsAutoCString tempDirPath;
tempDir->Normalize();
rv = tempDir->GetNativePath(tempDirPath);
if (NS_FAILED(rv)) {
MOZ_CRASH("Failed to get NS_OS_TEMP_DIR path");
@ -2422,10 +2424,14 @@ ContentChild::RecvFlushMemory(const nsString& reason)
}
mozilla::ipc::IPCResult
ContentChild::RecvActivateA11y(const uint32_t& aMsaaID)
ContentChild::RecvActivateA11y(const uint32_t& aMainChromeTid,
const uint32_t& aMsaaID)
{
#ifdef ACCESSIBILITY
#ifdef XP_WIN
MOZ_ASSERT(aMainChromeTid != 0);
mMainChromeTid = aMainChromeTid;
MOZ_ASSERT(aMsaaID != 0);
mMsaaID = aMsaaID;
#endif // XP_WIN

Просмотреть файл

@ -388,7 +388,8 @@ public:
virtual mozilla::ipc::IPCResult RecvFlushMemory(const nsString& reason) override;
virtual mozilla::ipc::IPCResult RecvActivateA11y(const uint32_t& aMsaaID) override;
virtual mozilla::ipc::IPCResult RecvActivateA11y(const uint32_t& aMainChromeTid,
const uint32_t& aMsaaID) override;
virtual mozilla::ipc::IPCResult RecvShutdownA11y() override;
virtual mozilla::ipc::IPCResult RecvGarbageCollect() override;
@ -499,6 +500,8 @@ public:
ContentParentId GetID() const { return mID; }
#if defined(XP_WIN) && defined(ACCESSIBILITY)
uint32_t GetChromeMainThreadId() const { return mMainChromeTid; }
uint32_t GetMsaaID() const { return mMsaaID; }
#endif
@ -699,6 +702,11 @@ private:
ContentParentId mID;
#if defined(XP_WIN) && defined(ACCESSIBILITY)
/**
* The thread ID of the main thread in the chrome process.
*/
uint32_t mMainChromeTid;
/**
* This is an a11y-specific unique id for the content process that is
* generated by the chrome process.

Просмотреть файл

@ -1364,10 +1364,15 @@ ContentParent::Init()
// process.
if (nsIPresShell::IsAccessibilityActive()) {
#if defined(XP_WIN)
Unused <<
SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
#if defined(RELEASE_OR_BETA)
// On Windows we currently only enable a11y in the content process
// for testing purposes.
if (Preferences::GetBool(kForceEnableE10sPref, false))
#endif
Unused << SendActivateA11y(::GetCurrentThreadId(),
a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
#else
Unused << SendActivateA11y(0);
Unused << SendActivateA11y(0, 0);
#endif
}
#endif
@ -2772,10 +2777,15 @@ ContentParent::Observe(nsISupports* aSubject,
// Make sure accessibility is running in content process when
// accessibility gets initiated in chrome process.
#if defined(XP_WIN)
Unused <<
SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
#if defined(RELEASE_OR_BETA)
// On Windows we currently only enable a11y in the content process
// for testing purposes.
if (Preferences::GetBool(kForceEnableE10sPref, false))
#endif
Unused << SendActivateA11y(::GetCurrentThreadId(),
a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
#else
Unused << SendActivateA11y(0);
Unused << SendActivateA11y(0, 0);
#endif
} else {
// If possible, shut down accessibility in content process when

Просмотреть файл

@ -443,11 +443,13 @@ child:
/**
* Start accessibility engine in content process.
* @param aTid is the thread ID of the chrome process main thread. Only used
* on Windows; pass 0 on other platforms.
* @param aMsaaID is an a11y-specific unique id for the content process
* that is generated by the chrome process. Only used on
* Windows; pass 0 on other platforms.
*/
async ActivateA11y(uint32_t aMsaaID);
async ActivateA11y(uint32_t aMainChromeTid, uint32_t aMsaaID);
/**
* Shutdown accessibility engine in content process (if not in use).

Просмотреть файл

@ -303,8 +303,7 @@ SVGMarkerElement::GetPreserveAspectRatio()
gfx::Matrix
SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
float aX, float aY, float aAutoAngle,
bool aIsStart)
const nsSVGMark& aMark)
{
float scale = mEnumAttributes[MARKERUNITS].GetAnimValue() ==
SVG_MARKERUNITS_STROKEWIDTH ? aStrokeWidth : 1.0f;
@ -312,10 +311,10 @@ SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
float angle;
switch (mOrientType.GetAnimValueInternal()) {
case SVG_MARKER_ORIENT_AUTO:
angle = aAutoAngle;
angle = aMark.angle;
break;
case SVG_MARKER_ORIENT_AUTO_START_REVERSE:
angle = aAutoAngle + (aIsStart ? M_PI : 0.0f);
angle = aMark.angle + (aMark.type == nsSVGMark::eStart ? M_PI : 0.0f);
break;
default: // SVG_MARKER_ORIENT_ANGLE
angle = mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0f;
@ -324,7 +323,7 @@ SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
return gfx::Matrix(cos(angle) * scale, sin(angle) * scale,
-sin(angle) * scale, cos(angle) * scale,
aX, aY);
aMark.x, aMark.y);
}
nsSVGViewBoxRect

Просмотреть файл

@ -18,6 +18,7 @@
#include "mozilla/dom/SVGAnimatedEnumeration.h"
class nsSVGMarkerFrame;
struct nsSVGMark;
nsresult NS_NewSVGMarkerElement(nsIContent **aResult,
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
@ -121,9 +122,7 @@ public:
virtual bool HasValidDimensions() const override;
// public helpers
gfx::Matrix GetMarkerTransform(float aStrokeWidth,
float aX, float aY, float aAutoAngle,
bool aIsStart);
gfx::Matrix GetMarkerTransform(float aStrokeWidth, const nsSVGMark& aMark);
nsSVGViewBoxRect GetViewBoxRect();
gfx::Matrix GetViewBoxTransform();

Просмотреть файл

@ -894,6 +894,11 @@ public:
* normally return the same SourceSurface object.
*/
virtual already_AddRefed<SourceSurface> Snapshot() = 0;
// Snapshots the contents and returns an alpha mask
// based on the RGB values.
virtual already_AddRefed<SourceSurface> IntoLuminanceSource(LuminanceType aLuminanceType,
float aOpacity);
virtual IntSize GetSize() = 0;
/**

Просмотреть файл

@ -9,9 +9,162 @@
#include "DrawTargetCapture.h"
#ifdef BUILD_ARM_NEON
#include "mozilla/arm.h"
#endif
namespace mozilla {
namespace gfx {
/**
* Byte offsets of channels in a native packed gfxColor or cairo image surface.
*/
#ifdef IS_BIG_ENDIAN
#define GFX_ARGB32_OFFSET_A 0
#define GFX_ARGB32_OFFSET_R 1
#define GFX_ARGB32_OFFSET_G 2
#define GFX_ARGB32_OFFSET_B 3
#else
#define GFX_ARGB32_OFFSET_A 3
#define GFX_ARGB32_OFFSET_R 2
#define GFX_ARGB32_OFFSET_G 1
#define GFX_ARGB32_OFFSET_B 0
#endif
// c = n / 255
// c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
static const uint8_t gsRGBToLinearRGBMap[256] = {
0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7,
8, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 12, 12, 12, 13,
13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 17, 18, 18, 19, 19, 20,
20, 21, 22, 22, 23, 23, 24, 24,
25, 25, 26, 27, 27, 28, 29, 29,
30, 30, 31, 32, 32, 33, 34, 35,
35, 36, 37, 37, 38, 39, 40, 41,
41, 42, 43, 44, 45, 45, 46, 47,
48, 49, 50, 51, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 76, 77, 78, 79,
80, 81, 82, 84, 85, 86, 87, 88,
90, 91, 92, 93, 95, 96, 97, 99,
100, 101, 103, 104, 105, 107, 108, 109,
111, 112, 114, 115, 116, 118, 119, 121,
122, 124, 125, 127, 128, 130, 131, 133,
134, 136, 138, 139, 141, 142, 144, 146,
147, 149, 151, 152, 154, 156, 157, 159,
161, 163, 164, 166, 168, 170, 171, 173,
175, 177, 179, 181, 183, 184, 186, 188,
190, 192, 194, 196, 198, 200, 202, 204,
206, 208, 210, 212, 214, 216, 218, 220,
222, 224, 226, 229, 231, 233, 235, 237,
239, 242, 244, 246, 248, 250, 253, 255
};
static void
ComputesRGBLuminanceMask(const uint8_t *aSourceData,
int32_t aSourceStride,
uint8_t *aDestData,
int32_t aDestStride,
const IntSize &aSize,
float aOpacity)
{
int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
int32_t sourceOffset = aSourceStride - 4 * aSize.width;
const uint8_t *sourcePixel = aSourceData;
int32_t destOffset = aDestStride - aSize.width;
uint8_t *destPixel = aDestData;
for (int32_t y = 0; y < aSize.height; y++) {
for (int32_t x = 0; x < aSize.width; x++) {
uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
if (a) {
*destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R] +
greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
} else {
*destPixel = 0;
}
sourcePixel += 4;
destPixel++;
}
sourcePixel += sourceOffset;
destPixel += destOffset;
}
}
static void
ComputeLinearRGBLuminanceMask(const uint8_t *aSourceData,
int32_t aSourceStride,
uint8_t *aDestData,
int32_t aDestStride,
const IntSize &aSize,
float aOpacity)
{
int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
int32_t sourceOffset = aSourceStride - 4 * aSize.width;
const uint8_t *sourcePixel = aSourceData;
int32_t destOffset = aDestStride - aSize.width;
uint8_t *destPixel = aDestData;
for (int32_t y = 0; y < aSize.height; y++) {
for (int32_t x = 0; x < aSize.width; x++) {
uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
// unpremultiply
if (a) {
if (a == 255) {
/* sRGB -> linearRGB -> intensity */
*destPixel =
static_cast<uint8_t>
((gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_R]] *
redFactor +
gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_G]] *
greenFactor +
gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_B]] *
blueFactor) >> 8);
} else {
uint8_t tempPixel[4];
tempPixel[GFX_ARGB32_OFFSET_B] =
(255 * sourcePixel[GFX_ARGB32_OFFSET_B]) / a;
tempPixel[GFX_ARGB32_OFFSET_G] =
(255 * sourcePixel[GFX_ARGB32_OFFSET_G]) / a;
tempPixel[GFX_ARGB32_OFFSET_R] =
(255 * sourcePixel[GFX_ARGB32_OFFSET_R]) / a;
/* sRGB -> linearRGB -> intensity */
*destPixel =
static_cast<uint8_t>
(((gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_R]] *
redFactor +
gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_G]] *
greenFactor +
gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_B]] *
blueFactor) >> 8) * (a / 255.0f));
}
} else {
*destPixel = 0;
}
sourcePixel += 4;
destPixel++;
}
sourcePixel += sourceOffset;
destPixel += destOffset;
}
}
already_AddRefed<DrawTargetCapture>
DrawTarget::CreateCaptureDT(const IntSize& aSize)
{
@ -64,6 +217,51 @@ DrawTarget::StrokeGlyphs(ScaledFont* aFont,
Stroke(path, aPattern, aStrokeOptions, aOptions);
}
already_AddRefed<SourceSurface>
DrawTarget::IntoLuminanceSource(LuminanceType aMaskType, float aOpacity)
{
RefPtr<SourceSurface> surface = Snapshot();
IntSize size = surface->GetSize();
RefPtr<DataSourceSurface> maskSurface = surface->GetDataSurface();
DataSourceSurface::MappedSurface map;
if (!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
return nullptr;
}
// Create alpha channel mask for output
RefPtr<DataSourceSurface> destMaskSurface =
Factory::CreateDataSourceSurface(size, SurfaceFormat::A8);
if (!destMaskSurface) {
return nullptr;
}
DataSourceSurface::MappedSurface destMap;
if (!destMaskSurface->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
return nullptr;
}
switch (aMaskType) {
case LuminanceType::LUMINANCE:
{
ComputesRGBLuminanceMask(map.mData, map.mStride,
destMap.mData, destMap.mStride,
size, aOpacity);
break;
}
case LuminanceType::LINEARRGB:
{
ComputeLinearRGBLuminanceMask(map.mData, map.mStride,
destMap.mData, destMap.mStride,
size, aOpacity);
break;
}
}
maskSurface->Unmap();
destMaskSurface->Unmap();
return destMaskSurface.forget();
}
} // namespace gfx
} // namespace mozilla

Просмотреть файл

@ -99,6 +99,38 @@ DrawTargetD2D1::Snapshot()
return snapshot.forget();
}
void
DrawTargetD2D1::EnsureLuminanceEffect()
{
if (mLuminanceEffect.get()) {
return;
}
HRESULT hr = mDC->CreateEffect(CLSID_D2D1LuminanceToAlpha,
getter_AddRefs(mLuminanceEffect));
if (FAILED(hr)) {
gfxWarning() << "Failed to create luminance effect. Code: " << hexa(hr);
}
}
already_AddRefed<SourceSurface>
DrawTargetD2D1::IntoLuminanceSource(LuminanceType aLuminanceType, float aOpacity)
{
//return DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity);
if (aLuminanceType != LuminanceType::LUMINANCE) {
return DrawTarget::IntoLuminanceSource(aLuminanceType, aOpacity);
}
// Create the luminance effect
EnsureLuminanceEffect();
mLuminanceEffect->SetInput(0, mBitmap);
RefPtr<ID2D1Image> luminanceOutput;
mLuminanceEffect->GetOutput(getter_AddRefs(luminanceOutput));
return MakeAndAddRef<SourceSurfaceD2D1>(luminanceOutput, mDC, SurfaceFormat::A8, mSize);
}
// Command lists are kept around by device contexts until EndDraw is called,
// this can cause issues with memory usage (see bug 1238328). EndDraw/BeginDraw
// are expensive though, especially relatively when little work is done, so
@ -348,20 +380,48 @@ DrawTargetD2D1::MaskSurface(const Pattern &aSource,
PrepareForDrawing(aOptions.mCompositionOp, aSource);
IntSize size = IntSize::Truncate(aMask->GetSize().width, aMask->GetSize().height);
Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
HRESULT hr = image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
if (!bitmap || FAILED(hr)) {
// D2D says if we have an actual ID2D1Image and not a bitmap underlying the object,
// we can't query for a bitmap. Instead, Push/PopLayer
gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces. Falling back to push/pop layer";
RefPtr<ID2D1Brush> source = CreateBrushForPattern(aSource, aOptions.mAlpha);
RefPtr<ID2D1ImageBrush> maskBrush;
hr = mDC->CreateImageBrush(image,
D2D1::ImageBrushProperties(D2D1::RectF(0, 0, size.width, size.height)),
D2D1::BrushProperties(1.0f, D2D1::IdentityMatrix()),
getter_AddRefs(maskBrush));
MOZ_ASSERT(SUCCEEDED(hr));
mDC->PushLayer(D2D1::LayerParameters1(D2D1::InfiniteRect(), nullptr,
D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
D2D1::IdentityMatrix(),
1.0f, maskBrush, D2D1_LAYER_OPTIONS1_NONE),
nullptr);
mDC->FillRectangle(D2DRect(dest), source);
mDC->PopLayer();
FinalizeDrawing(aOptions.mCompositionOp, aSource);
return;
} else {
// If this is a data source surface, we might have created a partial bitmap
// for this surface and only uploaded part of the mask. In that case,
// we have to fixup our sizes here.
size.width = bitmap->GetSize().width;
size.height = bitmap->GetSize().height;
dest.width = size.width;
dest.height = size.height;
}
// FillOpacityMask only works if the antialias mode is MODE_ALIASED
mDC->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
image->QueryInterface((ID2D1Bitmap**)getter_AddRefs(bitmap));
if (!bitmap) {
gfxWarning() << "FillOpacityMask only works with Bitmap source surfaces.";
return;
}
IntSize size = IntSize::Truncate(bitmap->GetSize().width, bitmap->GetSize().height);
Rect maskRect = Rect(0.f, 0.f, Float(size.width), Float(size.height));
Rect dest = Rect(aOffset.x, aOffset.y, Float(size.width), Float(size.height));
RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect));
@ -1871,7 +1931,6 @@ DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTrans
bool aUserSpace)
{
RefPtr<ID2D1Image> image;
switch (aSurface->GetType()) {
case SurfaceType::D2D1_1_IMAGE:
{

Просмотреть файл

@ -36,6 +36,8 @@ public:
virtual DrawTargetType GetType() const override { return DrawTargetType::HARDWARE_RASTER; }
virtual BackendType GetBackendType() const override { return BackendType::DIRECT2D1_1; }
virtual already_AddRefed<SourceSurface> Snapshot() override;
virtual already_AddRefed<SourceSurface> IntoLuminanceSource(LuminanceType aLuminanceType,
float aOpacity) override;
virtual IntSize GetSize() override { return mSize; }
virtual void Flush() override;
@ -295,6 +297,10 @@ private:
static IDWriteFactory *mDWriteFactory;
// This value is uesed to verify if the DrawTarget is created by a stale device.
uint32_t mDeviceSeq;
// List of effects we use
void EnsureLuminanceEffect();
RefPtr<ID2D1Effect> mLuminanceEffect;
};
}

Просмотреть файл

@ -278,6 +278,12 @@ enum class SamplingBounds : int8_t {
BOUNDED
};
// Moz2d version for SVG mask types
enum class LuminanceType : int8_t {
LUMINANCE,
LINEARRGB,
};
/* Color is stored in non-premultiplied form */
struct Color
{

Просмотреть файл

@ -19,7 +19,9 @@
#include "nsRect.h"
#include "nspr.h"
#include "png.h"
#include "RasterImage.h"
#include "SurfaceCache.h"
#include "SurfacePipeFactory.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/Telemetry.h"
@ -569,6 +571,13 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
// Post our size to the superclass
decoder->PostSize(frameRect.width, frameRect.height);
if (width >
SurfaceCache::MaximumCapacity()/(bit_depth > 8 ? 16:8)) {
// libpng needs space to allocate two row buffers
png_error(decoder->mPNG, "Image is too wide");
}
if (decoder->HasError()) {
// Setting the size led to an error.
png_error(decoder->mPNG, "Sizing error");
@ -735,6 +744,11 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
if (interlace_type == PNG_INTERLACE_ADAM7) {
if (frameRect.height < INT32_MAX / (frameRect.width * int32_t(channels))) {
const size_t bufferSize = channels * frameRect.width * frameRect.height;
if (bufferSize > SurfaceCache::MaximumCapacity()) {
png_error(decoder->mPNG, "Insufficient memory to deinterlace image");
}
decoder->interlacebuf = static_cast<uint8_t*>(malloc(bufferSize));
}
if (!decoder->interlacebuf) {

Просмотреть файл

@ -6,11 +6,13 @@
#define INITGUID
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Move.h"
#include "mozilla/mscom/DispatchForwarder.h"
#include "mozilla/mscom/Interceptor.h"
#include "mozilla/mscom/InterceptorLog.h"
#include "mozilla/mscom/MainThreadInvoker.h"
#include "mozilla/mscom/Objref.h"
#include "mozilla/mscom/Registration.h"
#include "mozilla/mscom/Utils.h"
#include "MainThreadUtils.h"
@ -20,6 +22,7 @@
#include "nsDirectoryServiceUtils.h"
#include "nsRefPtrHashtable.h"
#include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace mscom {
@ -142,6 +145,7 @@ Interceptor::GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
aDestContext == MSHCTX_DIFFERENTMACHINE) {
return E_INVALIDARG;
}
MOZ_ASSERT(mEventSink);
return mEventSink->GetHandler(WrapNotNull(aHandlerClsid));
}
@ -177,12 +181,60 @@ Interceptor::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
DWORD dwDestContext, void* pvDestContext,
DWORD mshlflags)
{
HRESULT hr = mStdMarshal->MarshalInterface(pStm, riid, pv, dwDestContext,
HRESULT hr;
#if defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
// Save the current stream position
LARGE_INTEGER seekTo;
seekTo.QuadPart = 0;
ULARGE_INTEGER objrefPos;
hr = pStm->Seek(seekTo, STREAM_SEEK_CUR, &objrefPos);
if (FAILED(hr)) {
return hr;
}
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
hr = mStdMarshal->MarshalInterface(pStm, riid, pv, dwDestContext,
pvDestContext, mshlflags);
if (FAILED(hr)) {
return hr;
}
#if defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
if (XRE_IsContentProcess()) {
const DWORD chromeMainTid =
dom::ContentChild::GetSingleton()->GetChromeMainThreadId();
/*
* CoGetCallerTID() gives us the caller's thread ID when that thread resides
* in a single-threaded apartment. Since our chrome main thread does live
* inside an STA, we will therefore be able to check whether the caller TID
* equals our chrome main thread TID. This enables us to distinguish
* between our chrome thread vs other out-of-process callers.
*/
DWORD callerTid;
if (::CoGetCallerTID(&callerTid) == S_FALSE && callerTid != chromeMainTid) {
// The caller isn't our chrome process, so do not provide a handler.
// First, seek back to the stream position that we prevously saved.
seekTo.QuadPart = objrefPos.QuadPart;
hr = pStm->Seek(seekTo, STREAM_SEEK_SET, nullptr);
if (FAILED(hr)) {
return hr;
}
// Now strip out the handler.
if (!StripHandlerFromOBJREF(WrapNotNull(pStm))) {
return E_FAIL;
}
return S_OK;
}
}
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
return mEventSink->WriteHandlerPayload(WrapNotNull(pStm));
}

Просмотреть файл

@ -453,6 +453,7 @@ MainThreadHandoff::GetHandler(NotNull<CLSID*> aHandlerClsid)
if (!mHandlerProvider) {
return E_NOTIMPL;
}
return mHandlerProvider->GetHandler(aHandlerClsid);
}

249
ipc/mscom/Objref.cpp Normal file
Просмотреть файл

@ -0,0 +1,249 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/mscom/Objref.h"
#include "mozilla/Assertions.h"
#include "mozilla/mscom/Utils.h"
#include "mozilla/UniquePtr.h"
#include <guiddef.h>
#include <objidl.h>
namespace {
#pragma pack(push, 1)
typedef uint64_t OID;
typedef uint64_t OXID;
typedef GUID IPID;
struct STDOBJREF
{
uint32_t mFlags;
uint32_t mPublicRefs;
OXID mOxid;
OID mOid;
IPID mIpid;
};
enum STDOBJREF_FLAGS
{
SORF_PING = 0,
SORF_NOPING = 0x1000
};
struct DUALSTRINGARRAY
{
static size_t SizeFromNumEntries(const uint16_t aNumEntries)
{
return sizeof(mNumEntries) + sizeof(mSecurityOffset) +
aNumEntries * sizeof(uint16_t);
}
size_t SizeOf() const
{
return SizeFromNumEntries(mNumEntries);
}
uint16_t mNumEntries;
uint16_t mSecurityOffset;
uint16_t mStringArray[1]; // Length is mNumEntries
};
struct OBJREF_STANDARD
{
size_t SizeOf() const
{
return sizeof(mStd) + mResAddr.SizeOf();
}
STDOBJREF mStd;
DUALSTRINGARRAY mResAddr;
};
struct OBJREF_HANDLER
{
size_t SizeOf() const
{
return sizeof(mStd) + sizeof(mClsid) + mResAddr.SizeOf();
}
STDOBJREF mStd;
CLSID mClsid;
DUALSTRINGARRAY mResAddr;
};
enum OBJREF_FLAGS
{
OBJREF_TYPE_STANDARD = 0x00000001UL,
OBJREF_TYPE_HANDLER = 0x00000002UL,
OBJREF_TYPE_CUSTOM = 0x00000004UL,
OBJREF_TYPE_EXTENDED = 0x00000008UL,
};
struct OBJREF
{
size_t SizeOf() const
{
size_t size = sizeof(mSignature) + sizeof(mFlags) + sizeof(mIid);
switch (mFlags) {
case OBJREF_TYPE_STANDARD:
size += mObjRefStd.SizeOf();
break;
case OBJREF_TYPE_HANDLER:
size += mObjRefHandler.SizeOf();
break;
default:
MOZ_ASSERT_UNREACHABLE("Unsupported OBJREF type");
return 0;
}
return size;
}
uint32_t mSignature;
uint32_t mFlags;
IID mIid;
union {
OBJREF_STANDARD mObjRefStd;
OBJREF_HANDLER mObjRefHandler;
// There are others but we're not supporting them here
};
};
enum OBJREF_SIGNATURES
{
OBJREF_SIGNATURE = 0x574F454DUL
};
#pragma pack(pop)
struct ByteArrayDeleter
{
void operator()(void* aPtr)
{
delete[] reinterpret_cast<uint8_t*>(aPtr);
}
};
template <typename T>
using VarStructUniquePtr = mozilla::UniquePtr<T, ByteArrayDeleter>;
} // anonymous namespace
namespace mozilla {
namespace mscom {
bool
StripHandlerFromOBJREF(NotNull<IStream*> aStream)
{
// Get current stream position
LARGE_INTEGER seekTo;
seekTo.QuadPart = 0;
ULARGE_INTEGER objrefPos;
HRESULT hr = aStream->Seek(seekTo, STREAM_SEEK_CUR, &objrefPos);
if (FAILED(hr)) {
return false;
}
ULONG bytesRead;
uint32_t signature;
hr = aStream->Read(&signature, sizeof(signature), &bytesRead);
if (FAILED(hr) || bytesRead != sizeof(signature) ||
signature != OBJREF_SIGNATURE) {
return false;
}
uint32_t type;
hr = aStream->Read(&type, sizeof(type), &bytesRead);
if (FAILED(hr) || bytesRead != sizeof(type) ||
type != OBJREF_TYPE_HANDLER) {
return false;
}
IID iid;
hr = aStream->Read(&iid, sizeof(iid), &bytesRead);
if (FAILED(hr) || bytesRead != sizeof(iid) || !IsValidGUID(iid)) {
return false;
}
// Seek past fixed-size STDOBJREF and CLSID
seekTo.QuadPart = sizeof(STDOBJREF) + sizeof(CLSID);
hr = aStream->Seek(seekTo, STREAM_SEEK_CUR, nullptr);
if (FAILED(hr)) {
return hr;
}
uint16_t numEntries;
hr = aStream->Read(&numEntries, sizeof(numEntries), &bytesRead);
if (FAILED(hr) || bytesRead != sizeof(numEntries)) {
return false;
}
// We'll try to use a stack buffer if resAddrSize <= kMinDualStringArraySize
const uint32_t kMinDualStringArraySize = 12;
uint16_t staticResAddrBuf[kMinDualStringArraySize / sizeof(uint16_t)];
size_t resAddrSize = DUALSTRINGARRAY::SizeFromNumEntries(numEntries);
DUALSTRINGARRAY* resAddr;
VarStructUniquePtr<DUALSTRINGARRAY> dynamicResAddrBuf;
if (resAddrSize <= kMinDualStringArraySize) {
resAddr = reinterpret_cast<DUALSTRINGARRAY*>(staticResAddrBuf);
} else {
dynamicResAddrBuf.reset(
reinterpret_cast<DUALSTRINGARRAY*>(new uint8_t[resAddrSize]));
resAddr = dynamicResAddrBuf.get();
}
resAddr->mNumEntries = numEntries;
// Because we've already read numEntries
ULONG bytesToRead = resAddrSize - sizeof(numEntries);
hr = aStream->Read(&resAddr->mSecurityOffset, bytesToRead, &bytesRead);
if (FAILED(hr) || bytesRead != bytesToRead) {
return false;
}
// Signature doesn't change so we'll seek past that
seekTo.QuadPart = objrefPos.QuadPart + sizeof(signature);
hr = aStream->Seek(seekTo, STREAM_SEEK_SET, nullptr);
if (FAILED(hr)) {
return false;
}
ULONG bytesWritten;
uint32_t newType = OBJREF_TYPE_STANDARD;
hr = aStream->Write(&newType, sizeof(newType), &bytesWritten);
if (FAILED(hr) || bytesWritten != sizeof(newType)) {
return false;
}
// Skip past IID and STDOBJREF since those don't change
seekTo.QuadPart = sizeof(IID) + sizeof(STDOBJREF);
hr = aStream->Seek(seekTo, STREAM_SEEK_CUR, nullptr);
if (FAILED(hr)) {
return false;
}
hr = aStream->Write(resAddr, resAddrSize, &bytesWritten);
if (FAILED(hr) || bytesWritten != resAddrSize) {
return false;
}
return true;
}
} // namespace mscom
} // namespace mozilla

32
ipc/mscom/Objref.h Normal file
Просмотреть файл

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_mscom_Objref_h
#define mozilla_mscom_Objref_h
#include "mozilla/NotNull.h"
struct IStream;
namespace mozilla {
namespace mscom {
/**
* Given a buffer containing a serialized proxy to an interface with a handler,
* this function strips out the handler and converts it to a standard one.
* @param aStream IStream whose pointer is positioned at the beginning of the
* OBJREF to be stripped. There should be nothing else written
* to the stream past the current OBJREF.
* @return true if the handler was successfully stripped, otherwise false.
*/
bool
StripHandlerFromOBJREF(NotNull<IStream*> aStream);
} // namespace mscom
} // namespace mozilla
#endif // mozilla_mscom_Objref_h

Просмотреть файл

@ -4,10 +4,12 @@
* 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/. */
#ifdef ACCESSIBILITY
#if defined(ACCESSIBILITY)
#include "mozilla/mscom/Registration.h"
#if defined(MOZILLA_INTERNAL_API)
#include "nsTArray.h"
#endif
#endif
#include "mozilla/mscom/Utils.h"
#include "mozilla/RefPtr.h"
@ -139,6 +141,8 @@ IsVtableIndexFromParentInterface(REFIID aInterface, unsigned long aVtableIndex)
return result;
}
#if defined(MOZILLA_INTERNAL_API)
bool
IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom,
unsigned long aVtableIndexHint)
@ -223,6 +227,8 @@ IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom,
return false;
}
#endif // defined(MOZILLA_INTERNAL_API)
#endif // defined(ACCESSIBILITY)
} // namespace mscom

Просмотреть файл

@ -11,9 +11,7 @@
#include "nsString.h"
#endif // defined(MOZILLA_INTERNAL_API)
#if defined(ACCESSIBILITY)
#include <guiddef.h>
#endif // defined(ACCESSIBILITY)
struct IUnknown;
@ -31,8 +29,10 @@ void GUIDToString(REFGUID aGuid, nsAString& aOutString);
#if defined(ACCESSIBILITY)
bool IsVtableIndexFromParentInterface(REFIID aInterface,
unsigned long aVtableIndex);
#if defined(MOZILLA_INTERNAL_API)
bool IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom,
unsigned long aVtableIndexHint);
#endif // defined(MOZILLA_INTERNAL_API)
#endif // defined(ACCESSIBILITY)
} // namespace mscom

Просмотреть файл

@ -12,6 +12,7 @@ EXPORTS.mozilla.mscom += [
'COMPtrHolder.h',
'EnsureMTA.h',
'MainThreadRuntime.h',
'Objref.h',
'ProxyStream.h',
'Ptr.h',
'Utils.h',
@ -21,6 +22,7 @@ UNIFIED_SOURCES += [
'AgileReference.cpp',
'EnsureMTA.cpp',
'MainThreadRuntime.cpp',
'Objref.cpp',
'ProxyStream.cpp',
'Utils.cpp',
]
@ -70,6 +72,8 @@ LOCAL_INCLUDES += [
'/xpcom/build',
]
DEFINES['MOZ_MSCOM_REMARSHAL_NO_HANDLER'] = True
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/mscom/Objref.h"
#include "nsWindowsHelpers.h"
#include <objbase.h>
@ -48,7 +49,7 @@ Handler::Handler(IUnknown* aOuter, HRESULT* aResult)
return;
}
// mInnerMarshal is a weak ref
// mUnmarshal is a weak ref
mUnmarshal->Release();
}
@ -169,14 +170,28 @@ Handler::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
RefPtr<IUnknown> unkToMarshal;
HRESULT hr;
REFIID marshalAs = MarshalAs(riid);
if (marshalAs == riid) {
unkToMarshal = static_cast<IUnknown*>(pv);
} else {
hr = mInnerUnk->QueryInterface(marshalAs, getter_AddRefs(unkToMarshal));
#if defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
LARGE_INTEGER seekTo;
seekTo.QuadPart = 0;
ULARGE_INTEGER objrefPos;
// Save the current position as it points to the location where the OBJREF
// will be written.
hr = pStm->Seek(seekTo, STREAM_SEEK_CUR, &objrefPos);
if (FAILED(hr)) {
return hr;
}
// When marshaling without a handler, we just use the riid as passed in.
REFIID marshalAs = riid;
#else
REFIID marshalAs = MarshalAs(riid);
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
hr = mInnerUnk->QueryInterface(marshalAs, getter_AddRefs(unkToMarshal));
if (FAILED(hr)) {
return hr;
}
hr = mUnmarshal->MarshalInterface(pStm, marshalAs, unkToMarshal.get(),
@ -185,6 +200,22 @@ Handler::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
return hr;
}
#if defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
// Now the OBJREF has been written, so seek back to its beginning (the
// position that we saved earlier).
seekTo.QuadPart = objrefPos.QuadPart;
hr = pStm->Seek(seekTo, STREAM_SEEK_SET, nullptr);
if (FAILED(hr)) {
return hr;
}
// Now strip out the handler.
if (!StripHandlerFromOBJREF(WrapNotNull(pStm))) {
return E_FAIL;
}
return S_OK;
#else
if (!HasPayload()) {
return S_OK;
}
@ -192,6 +223,7 @@ Handler::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
// Unfortunately when COM re-marshals a proxy that prevouisly had a payload,
// we must re-serialize it.
return WriteHandlerPayload(pStm, marshalAs);
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
}
HRESULT

Просмотреть файл

@ -8,8 +8,10 @@ Library('mscom_oop')
SOURCES += [
'../ActivationContext.cpp',
'../Objref.cpp',
'../Registration.cpp',
'../StructStream.cpp',
'../Utils.cpp',
]
UNIFIED_SOURCES += [
@ -26,6 +28,7 @@ OS_LIBS += [
LIBRARY_DEFINES['UNICODE'] = True
LIBRARY_DEFINES['_UNICODE'] = True
LIBRARY_DEFINES['MOZ_NO_MOZALLOC'] = True
LIBRARY_DEFINES['MOZ_MSCOM_REMARSHAL_NO_HANDLER'] = True
DISABLE_STL_WRAPPING = True
NO_EXPAND_LIBS = True

Просмотреть файл

@ -341,6 +341,7 @@ class JSFunction : public js::NativeObject
MOZ_ASSERT(atom);
MOZ_ASSERT(!hasGuessedAtom());
MOZ_ASSERT(!isClassConstructor());
MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
atom_ = atom;
flags_ |= HAS_COMPILE_TIME_NAME;
}
@ -355,6 +356,7 @@ class JSFunction : public js::NativeObject
MOZ_ASSERT(atom);
MOZ_ASSERT(!hasCompileTimeName());
MOZ_ASSERT(!hasGuessedAtom());
MOZ_ASSERT(js::AtomIsMarked(zone(), atom));
atom_ = atom;
flags_ |= HAS_GUESSED_ATOM;
}

Просмотреть файл

@ -266,9 +266,10 @@ DeleteScopeData(ConcreteScopeData* data)
template <typename ConcreteScope, XDRMode mode>
/* static */ bool
Scope::XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
MutableHandle<typename ConcreteScope::Data*> data)
MutableHandle<typename ConcreteScope::Data*> data, uint32_t* lengthOut)
{
MOZ_ASSERT(!data);
MOZ_ASSERT(!*lengthOut);
JSContext* cx = xdr->cx();
@ -281,11 +282,13 @@ Scope::XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
if (mode == XDR_ENCODE) {
data.set(&scope->data());
} else {
if (length) {
data.set(NewEmptyScopeData<ConcreteScope>(cx, length).release());
if (!data)
return false;
data->length = length;
}
}
for (uint32_t i = 0; i < length; i++) {
if (!XDRBindingName(xdr, &data->names[i])) {
@ -298,6 +301,7 @@ Scope::XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
}
}
*lengthOut = length;
return true;
}
@ -559,7 +563,8 @@ LexicalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
JSContext* cx = xdr->cx();
Rooted<Data*> data(cx);
if (!XDRSizedBindingNames<LexicalScope>(xdr, scope.as<LexicalScope>(), &data))
uint32_t length = 0;
if (!XDRSizedBindingNames<LexicalScope>(xdr, scope.as<LexicalScope>(), &data, &length))
return false;
{
@ -583,6 +588,9 @@ LexicalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
return false;
if (mode == XDR_DECODE) {
if (!data)
return false;
scope.set(create(cx, kind, data, firstFrameSlot, enclosing));
if (!scope)
return false;
@ -743,7 +751,8 @@ FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosin
{
JSContext* cx = xdr->cx();
Rooted<Data*> data(cx);
if (!XDRSizedBindingNames<FunctionScope>(xdr, scope.as<FunctionScope>(), &data))
uint32_t length = 0;
if (!XDRSizedBindingNames<FunctionScope>(xdr, scope.as<FunctionScope>(), &data, &length))
return false;
{
@ -754,30 +763,35 @@ FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosin
uint8_t needsEnvironment;
uint8_t hasParameterExprs;
uint16_t nonPositionalFormalStart;
uint16_t varStart;
uint32_t nextFrameSlot;
if (mode == XDR_ENCODE) {
needsEnvironment = scope->hasEnvironment();
hasParameterExprs = data->hasParameterExprs;
nonPositionalFormalStart = data->nonPositionalFormalStart;
varStart = data->varStart;
nextFrameSlot = data->nextFrameSlot;
}
if (!xdr->codeUint8(&needsEnvironment))
return false;
if (!xdr->codeUint8(&hasParameterExprs))
return false;
if (!xdr->codeUint16(&data->nonPositionalFormalStart))
if (!xdr->codeUint16(&nonPositionalFormalStart))
return false;
if (!xdr->codeUint16(&data->varStart))
if (!xdr->codeUint16(&varStart))
return false;
if (!xdr->codeUint32(&nextFrameSlot))
return false;
if (mode == XDR_DECODE) {
if (!data->length) {
MOZ_ASSERT(!data->nonPositionalFormalStart);
MOZ_ASSERT(!data->varStart);
MOZ_ASSERT(!data->nextFrameSlot);
DeleteScopeData(data.get());
data = nullptr;
MOZ_ASSERT(!length == !data);
if (length) {
data->nonPositionalFormalStart = nonPositionalFormalStart;
data->varStart = varStart;
} else {
MOZ_ASSERT(!nonPositionalFormalStart);
MOZ_ASSERT(!varStart);
}
scope.set(create(cx, data, hasParameterExprs, needsEnvironment, fun, enclosing));
@ -786,6 +800,7 @@ FunctionScope::XDR(XDRState<mode>* xdr, HandleFunction fun, HandleScope enclosin
// nextFrameSlot is used only for this correctness check.
MOZ_ASSERT(nextFrameSlot == scope->as<FunctionScope>().data().nextFrameSlot);
MOZ_ASSERT_IF(!data, !nextFrameSlot);
}
}
@ -871,7 +886,8 @@ VarScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
{
JSContext* cx = xdr->cx();
Rooted<Data*> data(cx);
if (!XDRSizedBindingNames<VarScope>(xdr, scope.as<VarScope>(), &data))
uint32_t length = 0;
if (!XDRSizedBindingNames<VarScope>(xdr, scope.as<VarScope>(), &data, &length))
return false;
{
@ -896,12 +912,7 @@ VarScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
return false;
if (mode == XDR_DECODE) {
if (!data->length) {
MOZ_ASSERT(!data->nextFrameSlot);
DeleteScopeData(data.get());
data = nullptr;
}
MOZ_ASSERT(!length == !data);
scope.set(create(cx, kind, data, firstFrameSlot, needsEnvironment, enclosing));
if (!scope)
return false;
@ -974,7 +985,8 @@ GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope)
JSContext* cx = xdr->cx();
Rooted<Data*> data(cx);
if (!XDRSizedBindingNames<GlobalScope>(xdr, scope.as<GlobalScope>(), &data))
uint32_t length = 0;
if (!XDRSizedBindingNames<GlobalScope>(xdr, scope.as<GlobalScope>(), &data, &length))
return false;
{
@ -983,20 +995,31 @@ GlobalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, MutableHandleScope scope)
DeleteScopeData(data.get());
});
if (!xdr->codeUint32(&data->varStart))
uint32_t varStart;
uint32_t letStart;
uint32_t constStart;
if (mode == XDR_ENCODE) {
varStart = data->varStart;
letStart = data->letStart;
constStart = data->constStart;
}
if (!xdr->codeUint32(&varStart))
return false;
if (!xdr->codeUint32(&data->letStart))
if (!xdr->codeUint32(&letStart))
return false;
if (!xdr->codeUint32(&data->constStart))
if (!xdr->codeUint32(&constStart))
return false;
if (mode == XDR_DECODE) {
if (!data->length) {
MOZ_ASSERT(!data->varStart);
MOZ_ASSERT(!data->letStart);
MOZ_ASSERT(!data->constStart);
DeleteScopeData(data.get());
data = nullptr;
MOZ_ASSERT(!length == !data);
if (length) {
data->varStart = varStart;
data->letStart = letStart;
data->constStart = constStart;
} else {
MOZ_ASSERT(!varStart);
MOZ_ASSERT(!letStart);
MOZ_ASSERT(!constStart);
}
scope.set(create(cx, kind, data));
@ -1106,16 +1129,12 @@ EvalScope::XDR(XDRState<mode>* xdr, ScopeKind kind, HandleScope enclosing,
DeleteScopeData(data.get());
});
if (!XDRSizedBindingNames<EvalScope>(xdr, scope.as<EvalScope>(), &data))
uint32_t length = 0;
if (!XDRSizedBindingNames<EvalScope>(xdr, scope.as<EvalScope>(), &data, &length))
return false;
if (mode == XDR_DECODE) {
if (!data->length) {
MOZ_ASSERT(!data->nextFrameSlot);
DeleteScopeData(data.get());
data = nullptr;
}
MOZ_ASSERT(!length == !data);
scope.set(create(cx, kind, data, enclosing));
if (!scope)
return false;

Просмотреть файл

@ -248,7 +248,8 @@ class Scope : public js::gc::TenuredCell
template <typename ConcreteScope, XDRMode mode>
static bool XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope,
MutableHandle<typename ConcreteScope::Data*> data);
MutableHandle<typename ConcreteScope::Data*> data,
uint32_t* lengthOut);
Shape* maybeCloneEnvironmentShape(JSContext* cx);

Просмотреть файл

@ -1697,6 +1697,46 @@ nsRefreshDriver::RunFrameRequestCallbacks(TimeStamp aNowTime)
}
}
struct RunnableWithDelay
{
nsCOMPtr<nsIRunnable> mRunnable;
uint32_t mDelay;
};
static AutoTArray<RunnableWithDelay, 8>* sPendingIdleRunnables = nullptr;
void
nsRefreshDriver::DispatchIdleRunnableAfterTick(nsIRunnable* aRunnable,
uint32_t aDelay)
{
if (!sPendingIdleRunnables) {
sPendingIdleRunnables = new AutoTArray<RunnableWithDelay, 8>();
}
RunnableWithDelay rwd = {aRunnable, aDelay};
sPendingIdleRunnables->AppendElement(rwd);
}
void
nsRefreshDriver::CancelIdleRunnable(nsIRunnable* aRunnable)
{
if (!sPendingIdleRunnables) {
return;
}
for (uint32_t i = 0; i < sPendingIdleRunnables->Length(); ++i) {
if ((*sPendingIdleRunnables)[i].mRunnable == aRunnable) {
sPendingIdleRunnables->RemoveElementAt(i);
break;
}
}
if (sPendingIdleRunnables->IsEmpty()) {
delete sPendingIdleRunnables;
sPendingIdleRunnables = nullptr;
}
}
void
nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
{
@ -1959,7 +1999,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
}
}
bool notifyGC = false;
bool dispatchRunnablesAfterTick = false;
if (mViewManagerFlushIsPending) {
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
@ -1998,7 +2038,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
timelines->AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::END);
}
notifyGC = true;
dispatchRunnablesAfterTick = true;
}
#ifndef ANDROID /* bug 1142079 */
@ -2017,10 +2057,14 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
ScheduleViewManagerFlush();
}
if (notifyGC && nsContentUtils::XPConnect()) {
GeckoProfilerTracingRAII tracer("Paint", "NotifyDidPaint");
nsContentUtils::XPConnect()->NotifyDidPaint();
nsJSContext::NotifyDidPaint();
if (dispatchRunnablesAfterTick && sPendingIdleRunnables) {
AutoTArray<RunnableWithDelay, 8>* runnables = sPendingIdleRunnables;
sPendingIdleRunnables = nullptr;
for (uint32_t i = 0; i < runnables->Length(); ++i) {
NS_IdleDispatchToCurrentThread((*runnables)[i].mRunnable.forget(),
(*runnables)[i].mDelay);
}
delete runnables;
}
}

Просмотреть файл

@ -33,6 +33,7 @@ class nsIDocument;
class imgIRequest;
class nsIDOMEvent;
class nsINode;
class nsIRunnable;
namespace mozilla {
class RefreshDriverTimer;
@ -333,6 +334,10 @@ public:
*/
static mozilla::TimeStamp GetIdleDeadlineHint(mozilla::TimeStamp aDefault);
static void DispatchIdleRunnableAfterTick(nsIRunnable* aRunnable,
uint32_t aDelay);
static void CancelIdleRunnable(nsIRunnable* aRunnable);
bool SkippedPaints() const
{
return mSkippedPaints;

Просмотреть файл

@ -14,7 +14,7 @@ fuzzy-if(skiaContent,1,30000) == mask-mode-a.html mask-mode-ref.html
fuzzy-if(skiaContent,1,30000) == mask-mode-b.html mask-mode-ref.html
fuzzy-if(skiaContent,1,30000) == mask-mode-c.html mask-mode-ref.html
fuzzy-if(skiaContent,1,30000) == mask-mode-d.html mask-mode-ref.html
fuzzy-if(skiaContent,1,30000) == mask-mode-to-mask-type.html mask-mode-to-mask-type-ref.html
fuzzy-if(skiaContent,1,30000) fuzzy-if(d2d,1,30000) == mask-mode-to-mask-type.html mask-mode-to-mask-type-ref.html
# mask-image test cases
== mask-image-1a.html mask-image-1-ref.html
@ -27,8 +27,8 @@ fuzzy-if(skiaContent||winWidget,1,20000) == mask-image-2.html mask-image-2-ref.h
fuzzy-if(skiaContent||winWidget,1,43) == mask-image-3c.html mask-image-3-ref.html
fuzzy-if(skiaContent||winWidget,1,43) == mask-image-3d.html mask-image-3-ref.html
== mask-image-3e.html mask-image-3-ref.html
fuzzy-if(skiaContent||winWidget,50,85) fuzzy-if(webrender,1,126) == mask-image-3f.html mask-image-3-ref.html
fuzzy-if(skiaContent||winWidget,50,85) fuzzy-if(webrender,1,126) == mask-image-3g.html mask-image-3-ref.html
fuzzy-if(skiaContent||winWidget,50,85) fuzzy-if(webrender,1,126) fuzzy-if(d2d,255,1) == mask-image-3f.html mask-image-3-ref.html
fuzzy-if(skiaContent||winWidget,50,85) fuzzy-if(webrender,1,126) fuzzy-if(d2d,255,1) == mask-image-3g.html mask-image-3-ref.html
pref(layout.css.clip-path-shapes.enabled,true) fuzzy-if(winWidget,1,3) fuzzy-if(skiaContent,2,12) == mask-image-3h.html mask-image-3-ref.html
fuzzy-if(skiaContent,71,203) == mask-image-3i.html mask-image-3-ref.html
== mask-image-4a.html blank.html

Просмотреть файл

@ -668,12 +668,12 @@ SVGGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
"Number of Marker frames should be equal to eTypeCount");
for (uint32_t i = 0; i < num; i++) {
nsSVGMark& mark = marks[i];
const nsSVGMark& mark = marks[i];
nsSVGMarkerFrame* frame = markerFrames[mark.type];
if (frame) {
SVGBBox mbbox =
frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this,
&marks[i], strokeWidth);
mark, strokeWidth);
MOZ_ASSERT(mbbox.IsFinite(), "bbox is about to go bad");
bbox.UnionEdges(mbbox);
}
@ -896,10 +896,10 @@ SVGGeometryFrame::PaintMarkers(gfxContext& aContext,
"Number of Marker frames should be equal to eTypeCount");
for (uint32_t i = 0; i < num; i++) {
nsSVGMark& mark = marks[i];
const nsSVGMark& mark = marks[i];
nsSVGMarkerFrame* frame = markerFrames[mark.type];
if (frame) {
frame->PaintMark(aContext, aTransform, this, &mark, strokeWidth,
frame->PaintMark(aContext, aTransform, this, mark, strokeWidth,
aImgParams);
}
}

Просмотреть файл

@ -66,10 +66,6 @@ UNIFIED_SOURCES += [
'SVGViewFrame.cpp',
]
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
SOURCES += ['nsSVGMaskFrameNEON.cpp']
SOURCES['nsSVGMaskFrameNEON.cpp'].flags += CONFIG['NEON_FLAGS']
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'../../widget',

Просмотреть файл

@ -80,11 +80,9 @@ nsSVGMarkerFrame::GetCanvasTM()
gfxMatrix markedTM = mMarkedFrame->GetCanvasTM();
mInUse2 = false;
Matrix markerTM = content->GetMarkerTransform(mStrokeWidth, mX, mY,
mAutoAngle, mIsStart);
Matrix viewBoxTM = content->GetViewBoxTransform();
return ThebesMatrix(viewBoxTM * markerTM) * markedTM;
return ThebesMatrix(viewBoxTM * mMarkerTM) * markedTM;
}
static nsIFrame*
@ -99,8 +97,8 @@ GetAnonymousChildFrame(nsIFrame* aFrame)
void
nsSVGMarkerFrame::PaintMark(gfxContext& aContext,
const gfxMatrix& aToMarkedFrameUserSpace,
SVGGeometryFrame *aMarkedFrame,
nsSVGMark *aMark, float aStrokeWidth,
SVGGeometryFrame* aMarkedFrame,
const nsSVGMark& aMark, float aStrokeWidth,
imgDrawingParams& aImgParams)
{
// If the flag is set when we get here, it means this marker frame
@ -124,18 +122,11 @@ nsSVGMarkerFrame::PaintMark(gfxContext& aContext,
return;
}
mStrokeWidth = aStrokeWidth;
mX = aMark->x;
mY = aMark->y;
mAutoAngle = aMark->angle;
mIsStart = aMark->type == nsSVGMark::eStart;
Matrix viewBoxTM = marker->GetViewBoxTransform();
Matrix markerTM = marker->GetMarkerTransform(mStrokeWidth, mX, mY,
mAutoAngle, mIsStart);
mMarkerTM = marker->GetMarkerTransform(aStrokeWidth, aMark);
gfxMatrix markTM = ThebesMatrix(viewBoxTM) * ThebesMatrix(markerTM) *
gfxMatrix markTM = ThebesMatrix(viewBoxTM) * ThebesMatrix(mMarkerTM) *
aToMarkedFrameUserSpace;
if (StyleDisplay()->IsScrollableOverflow()) {
@ -158,10 +149,10 @@ nsSVGMarkerFrame::PaintMark(gfxContext& aContext,
}
SVGBBox
nsSVGMarkerFrame::GetMarkBBoxContribution(const Matrix &aToBBoxUserspace,
nsSVGMarkerFrame::GetMarkBBoxContribution(const Matrix& aToBBoxUserspace,
uint32_t aFlags,
SVGGeometryFrame *aMarkedFrame,
const nsSVGMark *aMark,
SVGGeometryFrame* aMarkedFrame,
const nsSVGMark& aMark,
float aStrokeWidth)
{
SVGBBox bbox;
@ -185,17 +176,10 @@ nsSVGMarkerFrame::GetMarkBBoxContribution(const Matrix &aToBBoxUserspace,
return bbox;
}
mStrokeWidth = aStrokeWidth;
mX = aMark->x;
mY = aMark->y;
mAutoAngle = aMark->angle;
mIsStart = aMark->type == nsSVGMark::eStart;
Matrix markerTM =
content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle, mIsStart);
mMarkerTM = content->GetMarkerTransform(aStrokeWidth, aMark);
Matrix viewBoxTM = content->GetViewBoxTransform();
Matrix tm = viewBoxTM * markerTM * aToBBoxUserspace;
Matrix tm = viewBoxTM * mMarkerTM * aToBBoxUserspace;
nsSVGDisplayableFrame* child = do_QueryFrame(GetAnonymousChildFrame(this));
// When we're being called to obtain the invalidation area, we need to

Просмотреть файл

@ -79,15 +79,15 @@ public:
// nsSVGMarkerFrame methods:
void PaintMark(gfxContext& aContext,
const gfxMatrix& aToMarkedFrameUserSpace,
mozilla::SVGGeometryFrame *aMarkedFrame,
nsSVGMark *aMark,
mozilla::SVGGeometryFrame* aMarkedFrame,
const nsSVGMark& aMark,
float aStrokeWidth,
imgDrawingParams& aImgParams);
SVGBBox GetMarkBBoxContribution(const Matrix &aToBBoxUserspace,
SVGBBox GetMarkBBoxContribution(const Matrix& aToBBoxUserspace,
uint32_t aFlags,
mozilla::SVGGeometryFrame *aMarkedFrame,
const nsSVGMark *aMark,
mozilla::SVGGeometryFrame* aMarkedFrame,
const nsSVGMark& aMark,
float aStrokeWidth);
// Update the style on our anonymous box child.
@ -98,8 +98,7 @@ public:
private:
// stuff needed for callback
mozilla::SVGGeometryFrame *mMarkedFrame;
float mStrokeWidth, mX, mY, mAutoAngle;
bool mIsStart; // whether the callback is for a marker-start marker
Matrix mMarkerTM;
// nsSVGContainerFrame methods:
virtual gfxMatrix GetCanvasTM() override;

Просмотреть файл

@ -14,162 +14,28 @@
#include "mozilla/RefPtr.h"
#include "nsSVGEffects.h"
#include "mozilla/dom/SVGMaskElement.h"
#ifdef BUILD_ARM_NEON
#include "mozilla/arm.h"
#include "nsSVGMaskFrameNEON.h"
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::image;
// c = n / 255
// c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
static const uint8_t gsRGBToLinearRGBMap[256] = {
0, 0, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7,
8, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 12, 12, 12, 13,
13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 17, 18, 18, 19, 19, 20,
20, 21, 22, 22, 23, 23, 24, 24,
25, 25, 26, 27, 27, 28, 29, 29,
30, 30, 31, 32, 32, 33, 34, 35,
35, 36, 37, 37, 38, 39, 40, 41,
41, 42, 43, 44, 45, 45, 46, 47,
48, 49, 50, 51, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 76, 77, 78, 79,
80, 81, 82, 84, 85, 86, 87, 88,
90, 91, 92, 93, 95, 96, 97, 99,
100, 101, 103, 104, 105, 107, 108, 109,
111, 112, 114, 115, 116, 118, 119, 121,
122, 124, 125, 127, 128, 130, 131, 133,
134, 136, 138, 139, 141, 142, 144, 146,
147, 149, 151, 152, 154, 156, 157, 159,
161, 163, 164, 166, 168, 170, 171, 173,
175, 177, 179, 181, 183, 184, 186, 188,
190, 192, 194, 196, 198, 200, 202, 204,
206, 208, 210, 212, 214, 216, 218, 220,
222, 224, 226, 229, 231, 233, 235, 237,
239, 242, 244, 246, 248, 250, 253, 255
};
static void
ComputesRGBLuminanceMask(const uint8_t *aSourceData,
int32_t aSourceStride,
uint8_t *aDestData,
int32_t aDestStride,
const IntSize &aSize,
float aOpacity)
static LuminanceType
GetLuminanceType(uint8_t aNSMaskType)
{
#ifdef BUILD_ARM_NEON
if (mozilla::supports_neon()) {
ComputesRGBLuminanceMask_NEON(aSourceData, aSourceStride,
aDestData, aDestStride,
aSize, aOpacity);
return;
switch (aNSMaskType) {
case NS_STYLE_MASK_TYPE_LUMINANCE:
return LuminanceType::LUMINANCE;
case NS_STYLE_COLOR_INTERPOLATION_LINEARRGB:
return LuminanceType::LINEARRGB;
default:
{
NS_WARNING("Unknown SVG mask type, defaulting to luminance");
return LuminanceType::LUMINANCE;
}
#endif
int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
int32_t sourceOffset = aSourceStride - 4 * aSize.width;
const uint8_t *sourcePixel = aSourceData;
int32_t destOffset = aDestStride - aSize.width;
uint8_t *destPixel = aDestData;
for (int32_t y = 0; y < aSize.height; y++) {
for (int32_t x = 0; x < aSize.width; x++) {
uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
if (a) {
*destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R] +
greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
} else {
*destPixel = 0;
}
sourcePixel += 4;
destPixel++;
}
sourcePixel += sourceOffset;
destPixel += destOffset;
}
}
static void
ComputeLinearRGBLuminanceMask(const uint8_t *aSourceData,
int32_t aSourceStride,
uint8_t *aDestData,
int32_t aDestStride,
const IntSize &aSize,
float aOpacity)
{
int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
int32_t sourceOffset = aSourceStride - 4 * aSize.width;
const uint8_t *sourcePixel = aSourceData;
int32_t destOffset = aDestStride - aSize.width;
uint8_t *destPixel = aDestData;
for (int32_t y = 0; y < aSize.height; y++) {
for (int32_t x = 0; x < aSize.width; x++) {
uint8_t a = sourcePixel[GFX_ARGB32_OFFSET_A];
// unpremultiply
if (a) {
if (a == 255) {
/* sRGB -> linearRGB -> intensity */
*destPixel =
static_cast<uint8_t>
((gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_R]] *
redFactor +
gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_G]] *
greenFactor +
gsRGBToLinearRGBMap[sourcePixel[GFX_ARGB32_OFFSET_B]] *
blueFactor) >> 8);
} else {
uint8_t tempPixel[4];
tempPixel[GFX_ARGB32_OFFSET_B] =
(255 * sourcePixel[GFX_ARGB32_OFFSET_B]) / a;
tempPixel[GFX_ARGB32_OFFSET_G] =
(255 * sourcePixel[GFX_ARGB32_OFFSET_G]) / a;
tempPixel[GFX_ARGB32_OFFSET_R] =
(255 * sourcePixel[GFX_ARGB32_OFFSET_R]) / a;
/* sRGB -> linearRGB -> intensity */
*destPixel =
static_cast<uint8_t>
(((gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_R]] *
redFactor +
gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_G]] *
greenFactor +
gsRGBToLinearRGBMap[tempPixel[GFX_ARGB32_OFFSET_B]] *
blueFactor) >> 8) * (a / 255.0f));
}
} else {
*destPixel = 0;
}
sourcePixel += 4;
destPixel++;
}
sourcePixel += sourceOffset;
destPixel += destOffset;
}
}
//----------------------------------------------------------------------
// Implementation
nsIFrame*
NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{
@ -258,44 +124,20 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(MaskParams& aParams)
nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m, aParams.imgParams);
}
if (StyleSVG()->mColorInterpolation ==
NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
maskType = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
}
RefPtr<SourceSurface> surface;
if (maskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot();
RefPtr<SourceSurface> maskSnapshot =
maskDT->IntoLuminanceSource(GetLuminanceType(maskType),
aParams.opacity);
if (!maskSnapshot) {
return nullptr;
}
RefPtr<DataSourceSurface> maskSurface = maskSnapshot->GetDataSurface();
DataSourceSurface::MappedSurface map;
if (!maskSurface->Map(DataSourceSurface::MapType::READ, &map)) {
return nullptr;
}
// Create alpha channel mask for output
RefPtr<DataSourceSurface> destMaskSurface =
Factory::CreateDataSourceSurface(maskSurfaceSize, SurfaceFormat::A8);
if (!destMaskSurface) {
return nullptr;
}
DataSourceSurface::MappedSurface destMap;
if (!destMaskSurface->Map(DataSourceSurface::MapType::WRITE, &destMap)) {
return nullptr;
}
if (StyleSVG()->mColorInterpolation ==
NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
ComputeLinearRGBLuminanceMask(map.mData, map.mStride,
destMap.mData, destMap.mStride,
maskSurfaceSize, aParams.opacity);
} else {
ComputesRGBLuminanceMask(map.mData, map.mStride,
destMap.mData, destMap.mStride,
maskSurfaceSize, aParams.opacity);
}
maskSurface->Unmap();
destMaskSurface->Unmap();
surface = destMaskSurface.forget();
surface = maskSnapshot.forget();
} else {
maskDT->SetTransform(Matrix());
maskDT->FillRect(Rect(0, 0, maskSurfaceSize.width, maskSurfaceSize.height), ColorPattern(Color(1.0f, 1.0f, 1.0f, aParams.opacity)), DrawOptions(1, CompositionOp::OP_IN));

Просмотреть файл

@ -16,21 +16,6 @@
class gfxContext;
/**
* Byte offsets of channels in a native packed gfxColor or cairo image surface.
*/
#ifdef IS_BIG_ENDIAN
#define GFX_ARGB32_OFFSET_A 0
#define GFX_ARGB32_OFFSET_R 1
#define GFX_ARGB32_OFFSET_G 2
#define GFX_ARGB32_OFFSET_B 3
#else
#define GFX_ARGB32_OFFSET_A 3
#define GFX_ARGB32_OFFSET_R 2
#define GFX_ARGB32_OFFSET_G 1
#define GFX_ARGB32_OFFSET_B 0
#endif
class nsSVGMaskFrame final : public nsSVGContainerFrame
{
friend nsIFrame*

Просмотреть файл

@ -1,73 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSVGMaskFrameNEON.h"
#include "nsSVGMaskFrame.h"
#include <arm_neon.h>
using namespace mozilla::gfx;
void
ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
int32_t aSourceStride,
uint8_t *aDestData,
int32_t aDestStride,
const IntSize &aSize,
float aOpacity)
{
int32_t redFactor = 55 * aOpacity; // 255 * 0.2125 * opacity
int32_t greenFactor = 183 * aOpacity; // 255 * 0.7154 * opacity
int32_t blueFactor = 18 * aOpacity; // 255 * 0.0721
const uint8_t *sourcePixel = aSourceData;
int32_t sourceOffset = aSourceStride - 4 * aSize.width;
uint8_t *destPixel = aDestData;
int32_t destOffset = aDestStride - aSize.width;
sourcePixel = aSourceData;
int32_t remainderWidth = aSize.width % 8;
int32_t roundedWidth = aSize.width - remainderWidth;
uint16x8_t temp;
uint8x8_t gray;
uint8x8_t redVector = vdup_n_u8(redFactor);
uint8x8_t greenVector = vdup_n_u8(greenFactor);
uint8x8_t blueVector = vdup_n_u8(blueFactor);
uint8x8_t fullBitVector = vdup_n_u8(255);
uint8x8_t oneVector = vdup_n_u8(1);
for (int32_t y = 0; y < aSize.height; y++) {
// Calculate luminance by neon with 8 pixels per loop
for (int32_t x = 0; x < roundedWidth; x += 8) {
uint8x8x4_t argb = vld4_u8(sourcePixel);
temp = vmull_u8(argb.val[GFX_ARGB32_OFFSET_R], redVector); // temp = red * redFactor
temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_G], greenVector); // temp += green * greenFactor
temp = vmlal_u8(temp, argb.val[GFX_ARGB32_OFFSET_B], blueVector); // temp += blue * blueFactor
gray = vshrn_n_u16(temp, 8); // gray = temp >> 8
// Check alpha value
uint8x8_t alphaVector = vtst_u8(argb.val[GFX_ARGB32_OFFSET_A], fullBitVector);
gray = vmul_u8(gray, vand_u8(alphaVector, oneVector));
// Put the result to the 8 pixels
vst1_u8(destPixel, gray);
sourcePixel += 8 * 4;
destPixel += 8;
}
// Calculate the rest pixels of the line by cpu
for (int32_t x = 0; x < remainderWidth; x++) {
if (sourcePixel[GFX_ARGB32_OFFSET_A] > 0) {
*destPixel = (redFactor * sourcePixel[GFX_ARGB32_OFFSET_R]+
greenFactor * sourcePixel[GFX_ARGB32_OFFSET_G] +
blueFactor * sourcePixel[GFX_ARGB32_OFFSET_B]) >> 8;
} else {
*destPixel = 0;
}
sourcePixel += 4;
destPixel++;
}
sourcePixel += sourceOffset;
destPixel += destOffset;
}
}

Просмотреть файл

@ -1,19 +0,0 @@
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* this source code form is subject to the terms of the mozilla public
* license, v. 2.0. if a copy of the mpl was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __NS_SVGMASKFRAMENEON_H__
#define __NS_SVGMASKFRAMENEON_H__
#include "mozilla/gfx/Point.h"
void
ComputesRGBLuminanceMask_NEON(const uint8_t *aSourceData,
int32_t aSourceStride,
uint8_t *aDestData,
int32_t aDestStride,
const mozilla::gfx::IntSize &aSize,
float aOpacity);
#endif /* __NS_SVGMASKFRAMENEON_H__ */

Просмотреть файл

@ -144,7 +144,7 @@ function StartTestURI(type, uri, timeout)
// the JS ref tests disable the normal browser chrome and do not otherwise
// create substatial DOM garbage, the CC tends not to run enough normally.
++gTestCount;
if (gTestCount % 1000 == 0) {
if (gTestCount % 250 == 0) {
CU.forceGC();
CU.forceCC();
}

Просмотреть файл

@ -8,12 +8,15 @@
#define MOZ_EMBEDDED_LIBPNG
/* Limit image dimensions (bug #251381, #591822, #967656, and #1283961) */
#define PNG_USER_LIMITS_SUPPORTED
#ifndef MOZ_PNG_MAX_WIDTH
# define MOZ_PNG_MAX_WIDTH 0x7fffffffL /* Unlimited */
#endif
#ifndef MOZ_PNG_MAX_HEIGHT
# define MOZ_PNG_MAX_HEIGHT 0x7fffffffL /* Unlimited */
#endif
/* but allow nsPNGDecoder to override the limits (bug #1368407) */
#define PNG_SET_USER_LIMITS_SUPPORTED
#define PNG_API_RULE 0
#define PNG_COST_SHIFT 3

Просмотреть файл

@ -1394,7 +1394,7 @@ pref("javascript.options.mem.high_water_mark", 128);
pref("javascript.options.mem.max", -1);
pref("javascript.options.mem.gc_per_zone", true);
pref("javascript.options.mem.gc_incremental", true);
pref("javascript.options.mem.gc_incremental_slice_ms", 10);
pref("javascript.options.mem.gc_incremental_slice_ms", 5);
pref("javascript.options.mem.gc_compacting", true);
pref("javascript.options.mem.log", false);
pref("javascript.options.mem.notify", false);

Просмотреть файл

@ -5,48 +5,34 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Get bookmark service
try {
var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
} catch (ex) {
do_throw("Could not get nav-bookmarks-service\n");
}
let bm = PlacesUtils.bookmarks;
var gTestRoot;
var gURI;
var gItemId1;
var gItemId2;
// Test that Bookmarks fetch properly orders its results based on
// the last modified value. Note we cannot rely on dateAdded due to
// the low PR_Now() resolution.
// main
function run_test() {
gURI = uri("http://foo.tld.com/");
gTestRoot = bmsvc.createFolder(bmsvc.placesRoot, "test folder",
bmsvc.DEFAULT_INDEX);
add_task(async function sort_bookmark_by_relevance() {
let now = new Date();
let modifiedTime = new Date(now.setHours(now.getHours() - 2));
// test getBookmarkIdsForURI
// getBookmarkIdsForURI sorts by the most recently added/modified (descending)
//
// we cannot rely on dateAdded growing when doing so in a simple iteration,
// see PR_Now() documentation
do_test_pending();
let url = "http://foo.tld.com/";
let parentGuid = (await bm.insert({type: bm.TYPE_FOLDER,
title: "test folder",
parentGuid: bm.unfiledGuid})).guid;
let item1Guid = (await bm.insert({url,
parentGuid})).guid;
let item2Guid = (await bm.insert({url,
parentGuid,
dateAdded: modifiedTime,
lastModified: modifiedTime})).guid;
let bms = [];
await bm.fetch({url}, bm1 => bms.push(bm1));
Assert.equal(bms[0].guid, item1Guid);
Assert.equal(bms[1].guid, item2Guid);
await bm.update({guid: item2Guid, title: "modified"});
gItemId1 = bmsvc.insertBookmark(gTestRoot, gURI, bmsvc.DEFAULT_INDEX, "");
do_timeout(100, phase2);
}
function phase2() {
gItemId2 = bmsvc.insertBookmark(gTestRoot, gURI, bmsvc.DEFAULT_INDEX, "");
var b = bmsvc.getBookmarkIdsForURI(gURI);
do_check_eq(b[0], gItemId2);
do_check_eq(b[1], gItemId1);
do_timeout(100, phase3);
}
function phase3() {
// trigger last modified change
bmsvc.setItemTitle(gItemId1, "");
var b = bmsvc.getBookmarkIdsForURI(gURI);
do_check_eq(b[0], gItemId1);
do_check_eq(b[1], gItemId2);
do_test_finished();
}
let bms1 = [];
await bm.fetch({url}, bm2 => bms1.push(bm2));
Assert.equal(bms1[0].guid, item2Guid);
Assert.equal(bms1[1].guid, item1Guid);
});

Просмотреть файл

@ -527,7 +527,11 @@ add_task(async function test_subprocess_pathSearch() {
add_task(async function test_subprocess_workdir() {
let procDir = await OS.File.getCurrentDirectory();
let tmpDir = OS.Constants.Path.tmpDir;
let tmpDirFile = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
tmpDirFile.initWithPath(OS.Constants.Path.tmpDir);
tmpDirFile.normalize();
let tmpDir = tmpDirFile.path;
notEqual(procDir, tmpDir,
"Current process directory must not be the current temp directory");

Просмотреть файл

@ -5019,9 +5019,7 @@ MultiprocessBlockPolicy() {
return gMultiprocessBlockPolicy;
}
#if defined(XP_WIN)
// These checks are currently only in use under WinXP
if (false) { // !IsVistaOrLater()
#if defined(XP_WIN) && defined(RELEASE_OR_BETA)
bool disabledForA11y = false;
/**
* Avoids enabling e10s if accessibility has recently loaded. Performs the
@ -5049,11 +5047,11 @@ MultiprocessBlockPolicy() {
disabledForA11y = true;
}
}
if (disabledForA11y) {
gMultiprocessBlockPolicy = kE10sDisabledForAccessibility;
return gMultiprocessBlockPolicy;
}
}
#endif
/*

Просмотреть файл

@ -28,6 +28,7 @@ void AddQuarantineMetadataToFile(const CFStringRef filePath,
const CFURLRef sourceURL,
const CFURLRef referrerURL,
const bool isFromWeb);
CFURLRef GetTemporaryFolderCFURLRef();
} // namespace CocoaFileUtils

Просмотреть файл

@ -257,4 +257,11 @@ void AddQuarantineMetadataToFile(const CFStringRef filePath,
::CFRelease(mutQuarantineProps);
}
CFURLRef GetTemporaryFolderCFURLRef()
{
NSString* tempDir = ::NSTemporaryDirectory();
return tempDir == nil ? NULL : (CFURLRef)[NSURL fileURLWithPath:tempDir
isDirectory:YES];
}
} // namespace CocoaFileUtils

Просмотреть файл

@ -27,6 +27,9 @@
#include <stdlib.h>
#include <sys/param.h>
#include "prenv.h"
#if defined(MOZ_WIDGET_COCOA)
#include "CocoaFileUtils.h"
#endif
#endif
@ -766,10 +769,20 @@ GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory,
nsresult
GetOSXFolderType(short aDomain, OSType aFolderType, nsIFile** aLocalFile)
{
OSErr err;
FSRef fsRef;
nsresult rv = NS_ERROR_FAILURE;
if (aFolderType == kTemporaryFolderType) {
NS_NewLocalFile(EmptyString(), true, aLocalFile);
nsCOMPtr<nsILocalFileMac> localMacFile(do_QueryInterface(*aLocalFile));
if (localMacFile) {
rv = localMacFile->InitWithCFURL(
CocoaFileUtils::GetTemporaryFolderCFURLRef());
}
return rv;
}
OSErr err;
FSRef fsRef;
err = ::FSFindFolder(aDomain, aFolderType, kCreateFolder, &fsRef);
if (err == noErr) {
NS_NewLocalFile(EmptyString(), true, aLocalFile);

Просмотреть файл

@ -25,6 +25,10 @@ function test_normalized_vs_non_normalized()
if (!exists)
return;
// the test logic below assumes we're starting with a normalized path, but the
// default location on macos is a symbolic link, so resolve it before starting
tmp1.normalize();
// this has the same exact path as tmp1, it should equal tmp1
var tmp2 = new LocalFile(tmp1.path);
do_check_true(tmp1.equals(tmp2));