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. # we add the prefix "Proxy" to all of the generated counterparts.
DEFINES['ENTRY_PREFIX'] = 'Proxy' DEFINES['ENTRY_PREFIX'] = 'Proxy'
DEFINES['REGISTER_PROXY_DLL'] = True 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 # We want to generate distinct UUIDs on a per-channel basis, so we need
# finer granularity than the standard preprocessor definitions offer. # finer granularity than the standard preprocessor definitions offer.

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

@ -540,7 +540,8 @@ BrowserGlue.prototype = {
this._flashHangCount = 0; this._flashHangCount = 0;
this._firstWindowReady = new Promise(resolve => this._firstWindowLoaded = resolve); 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 // Handles prompting to inform about incompatibilites when accessibility
// and e10s are active together. // and e10s are active together.
E10SAccessibilityCheck.init(); E10SAccessibilityCheck.init();

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

@ -12,13 +12,14 @@ const {
} = require("devtools/client/shared/vendor/react"); } = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux"); const { connect } = require("devtools/client/shared/vendor/react-redux");
const Actions = require("../actions/index"); const Actions = require("../actions/index");
const { FILTER_SEARCH_DELAY, FILTER_FLAGS } = require("../constants"); const { FILTER_SEARCH_DELAY } = require("../constants");
const { const {
getDisplayedRequestsSummary, getDisplayedRequestsSummary,
getRequestFilterTypes, getRequestFilterTypes,
isNetworkDetailsToggleButtonDisabled, isNetworkDetailsToggleButtonDisabled,
} = require("../selectors/index"); } = require("../selectors/index");
const { autocompleteProvider } = require("../utils/filter-text-utils");
const { L10N } = require("../utils/l10n"); const { L10N } = require("../utils/l10n");
// Components // 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 ( return (
span({ className: "devtools-toolbar devtools-toolbar-container" }, span({ className: "devtools-toolbar devtools-toolbar-container" },
span({ className: "devtools-toolbar-group" }, span({ className: "devtools-toolbar-group" },
@ -114,7 +110,7 @@ const Toolbar = createClass({
placeholder: SEARCH_PLACE_HOLDER, placeholder: SEARCH_PLACE_HOLDER,
type: "filter", type: "filter",
onChange: setRequestFilterText, onChange: setRequestFilterText,
autocompleteList, autocompleteProvider,
}), }),
button({ button({
className: toggleButtonClassName.join(" "), className: toggleButtonClassName.join(" "),

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

@ -242,6 +242,50 @@ function isFreetextMatch(item, text) {
return match; 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 = { module.exports = {
isFreetextMatch, isFreetextMatch,
autocompleteProvider,
}; };

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

@ -10,7 +10,15 @@ module.exports = createClass({
displayName: "AutocompletePopup", displayName: "AutocompletePopup",
propTypes: { 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, filter: PropTypes.string.isRequired,
onItemSelected: PropTypes.func.isRequired, onItemSelected: PropTypes.func.isRequired,
}, },
@ -32,14 +40,11 @@ module.exports = createClass({
} }
}, },
computeState({ filter, list }) { computeState({ autocompleteProvider, filter }) {
let filteredList = list.filter((item) => { let list = autocompleteProvider(filter);
return item.toLowerCase().startsWith(filter.toLowerCase()) let selectedIndex = list.length == 1 ? 0 : -1;
&& item.toLowerCase() !== filter.toLowerCase();
}).sort();
let selectedIndex = filteredList.length == 1 ? 0 : -1;
return { filteredList, selectedIndex }; return { list, selectedIndex };
}, },
/** /**
@ -55,8 +60,7 @@ module.exports = createClass({
* This method is public. * This method is public.
*/ */
jumpToBottom() { jumpToBottom() {
let selectedIndex = this.state.filteredList.length - 1; this.setState({ selectedIndex: this.state.list.length - 1 });
this.setState({ selectedIndex });
}, },
/** /**
@ -67,14 +71,14 @@ module.exports = createClass({
* @param {number} increment - No. of hops in the direction * @param {number} increment - No. of hops in the direction
*/ */
jumpBy(increment = 1) { jumpBy(increment = 1) {
let { filteredList, selectedIndex } = this.state; let { list, selectedIndex } = this.state;
let nextIndex = selectedIndex + increment; let nextIndex = selectedIndex + increment;
if (increment > 0) { if (increment > 0) {
// Positive cycling // Positive cycling
nextIndex = nextIndex > filteredList.length - 1 ? 0 : nextIndex; nextIndex = nextIndex > list.length - 1 ? 0 : nextIndex;
} else if (increment < 0) { } else if (increment < 0) {
// Inverse cycling // Inverse cycling
nextIndex = nextIndex < 0 ? filteredList.length - 1 : nextIndex; nextIndex = nextIndex < 0 ? list.length - 1 : nextIndex;
} }
this.setState({selectedIndex: nextIndex}); this.setState({selectedIndex: nextIndex});
}, },
@ -85,7 +89,7 @@ module.exports = createClass({
*/ */
select() { select() {
if (this.refs.selected) { 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() { 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" }, { className: "devtools-autocomplete-popup devtools-monospace" },
dom.ul( dom.ul(
{ className: "devtools-autocomplete-listbox" }, { className: "devtools-autocomplete-listbox" },
filteredList.map((item, i) => { list.map((item, i) => {
let isSelected = this.state.selectedIndex == i; let isSelected = this.state.selectedIndex == i;
let itemClassList = ["autocomplete-item"]; let itemClassList = ["autocomplete-item"];
@ -111,10 +115,11 @@ module.exports = createClass({
return dom.li({ return dom.li({
key: i, key: i,
"data-index": i, "data-index": i,
"data-value": item.value,
className: itemClassList.join(" "), className: itemClassList.join(" "),
ref: isSelected ? "selected" : null, ref: isSelected ? "selected" : null,
onMouseDown: this.onMouseDown, onMouseDown: this.onMouseDown,
}, item); }, item.displayValue);
}) })
) )
); );

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

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

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

@ -43,7 +43,8 @@ window.onload = async function () {
); );
const { component, $ } = await createComponentTest(SearchBox, { const { component, $ } = await createComponentTest(SearchBox, {
type: "search", type: "search",
autocompleteList: [ autocompleteProvider: (filter) => {
let baseList = [
"foo", "foo",
"BAR", "BAR",
"baZ", "baZ",
@ -56,7 +57,30 @@ window.onload = async function () {
"a3", "a3",
"a4", "a4",
"a5", "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, onChange: () => null,
}); });
const { refs } = component; const { refs } = component;
@ -150,6 +174,8 @@ window.onload = async function () {
ok(!$(".devtools-autocomplete-popup"), "Enter/Return hides the popup"); ok(!$(".devtools-autocomplete-popup"), "Enter/Return hides the popup");
// Escape should remove the autocomplete component // Escape should remove the autocomplete component
synthesizeKey("VK_BACK_SPACE", {});
await forceRender(component);
synthesizeKey("VK_ESCAPE", {}); synthesizeKey("VK_ESCAPE", {});
await forceRender(component); await forceRender(component);
ok(!$(".devtools-autocomplete-popup"), ok(!$(".devtools-autocomplete-popup"),
@ -182,10 +208,25 @@ window.onload = async function () {
ok(!$(".devtools-autocomplete-popup"), "Mouse click on item hides the popup"); 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 () { add_task(async function () {
await testSearchBoxWithAutocomplete(); await testSearchBoxWithAutocomplete();
await testKeyEventsWithAutocomplete(); await testKeyEventsWithAutocomplete();
await testMouseEventsWithAutocomplete(); await testMouseEventsWithAutocomplete();
await testTokenizedAutocomplete();
}); });
}; };
</script> </script>

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

@ -81,6 +81,7 @@ const ErrorDocs = {
JSMSG_BAD_URI: "Malformed_URI", JSMSG_BAD_URI: "Malformed_URI",
JSMSG_DEPRECATED_DELETE_OPERAND: "Delete_in_strict_mode", JSMSG_DEPRECATED_DELETE_OPERAND: "Delete_in_strict_mode",
JSMSG_MISSING_FORMAL: "Missing_formal_parameter", 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"; 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) { if (intersectionRect.isSome() && !isSameDoc) {
nsRect rect = intersectionRect.value(); nsRect rect = intersectionRect.value();
nsPresContext* presContext = targetFrame->PresContext(); nsPresContext* presContext = targetFrame->PresContext();
nsLayoutUtils::TransformRect(rootFrame, nsIFrame* rootScrollFrame = presContext->PresShell()->GetRootScrollFrame();
presContext->PresShell()->GetRootScrollFrame(), rect); if (rootScrollFrame) {
nsLayoutUtils::TransformRect(rootFrame, rootScrollFrame, rect);
}
intersectionRect = Some(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 1157995.html
load 1158412.html load 1158412.html
load 1181619.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 1230422.html
load 1251361.html load 1251361.html
load 1304437.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-1.html
pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html pref(dom.IntersectionObserver.enabled,true) load 1326194-2.html
pref(dom.IntersectionObserver.enabled,true) load 1332939.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.webcomponents.enabled,true) load 1341693.html
pref(dom.IntersectionObserver.enabled,true) load 1353529.xul
pref(dom.IntersectionObserver.enabled,true) load 1369363.xul pref(dom.IntersectionObserver.enabled,true) load 1369363.xul
load 1370072.html 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 "nsGlobalWindow.h"
#include "nsScriptNameSpaceManager.h" #include "nsScriptNameSpaceManager.h"
#include "mozilla/AutoRestore.h" #include "mozilla/AutoRestore.h"
#include "mozilla/MainThreadIdlePeriod.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/ErrorEvent.h" #include "mozilla/dom/ErrorEvent.h"
@ -63,7 +65,7 @@
#include "nsAXPCNativeCallContext.h" #include "nsAXPCNativeCallContext.h"
#include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/SystemGroup.h" #include "mozilla/SystemGroup.h"
#include "nsRefreshDriver.h"
#include "nsJSPrincipals.h" #include "nsJSPrincipals.h"
#ifdef XP_MACOSX #ifdef XP_MACOSX
@ -111,21 +113,24 @@ const size_t gStackSize = 8192;
// Maximum amount of time that should elapse between incremental GC slices // Maximum amount of time that should elapse between incremental GC slices
#define NS_INTERSLICE_GC_DELAY 100 // ms #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) // The amount of time we wait between a request to CC (after GC ran)
// and doing the actual CC. // and doing the actual CC.
#define NS_CC_DELAY 6000 // ms #define NS_CC_DELAY 6000 // ms
#define NS_CC_SKIPPABLE_DELAY 250 // 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 // Maximum amount of time that should elapse between incremental CC slices
static const int64_t kICCIntersliceDelay = 32; // ms 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 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 // Maximum total duration for an ICC
static const uint32_t kMaxICCDuration = 2000; // ms 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 // Large value used to specify that a script should run essentially forever
#define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32) #define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
class CollectorRunner;
// if you add statics here, add them to the list in StartupJSEnvironment // if you add statics here, add them to the list in StartupJSEnvironment
static nsITimer *sGCTimer; static nsITimer *sGCTimer;
static nsITimer *sShrinkingGCTimer; static nsITimer *sShrinkingGCTimer;
static nsITimer *sCCTimer; static StaticRefPtr<CollectorRunner> sCCRunner;
static nsITimer *sICCTimer; static StaticRefPtr<CollectorRunner> sICCRunner;
static nsITimer *sFullGCTimer; static nsITimer *sFullGCTimer;
static nsITimer *sInterSliceGCTimer; static StaticRefPtr<CollectorRunner> sInterSliceGCRunner;
static TimeStamp sLastCCEndTime; static TimeStamp sLastCCEndTime;
@ -176,7 +183,7 @@ static uint32_t sCCollectedZonesWaitingForGC;
static uint32_t sLikelyShortLivingObjectsNeedingGC; static uint32_t sLikelyShortLivingObjectsNeedingGC;
static bool sPostGCEventsToConsole; static bool sPostGCEventsToConsole;
static bool sPostGCEventsToObserver; static bool sPostGCEventsToObserver;
static int32_t sCCTimerFireCount = 0; static int32_t sCCRunnerFireCount = 0;
static uint32_t sMinForgetSkippableTime = UINT32_MAX; static uint32_t sMinForgetSkippableTime = UINT32_MAX;
static uint32_t sMaxForgetSkippableTime = 0; static uint32_t sMaxForgetSkippableTime = 0;
static uint32_t sTotalForgetSkippableTime = 0; static uint32_t sTotalForgetSkippableTime = 0;
@ -188,7 +195,6 @@ static bool sNeedsFullCC = false;
static bool sNeedsFullGC = false; static bool sNeedsFullGC = false;
static bool sNeedsGCAfterCC = false; static bool sNeedsGCAfterCC = false;
static bool sIncrementalCC = false; static bool sIncrementalCC = false;
static bool sDidPaintAfterPreviousICCSlice = false;
static int32_t sActiveIntersliceGCBudget = 0; // ms; static int32_t sActiveIntersliceGCBudget = 0; // ms;
static nsScriptNameSpaceManager *gNameSpaceManager; static nsScriptNameSpaceManager *gNameSpaceManager;
@ -223,6 +229,178 @@ static bool sIsCompactingOnUserInactive = false;
static int32_t sExpensiveCollectorPokes = 0; static int32_t sExpensiveCollectorPokes = 0;
static const int32_t kPokesBetweenExpensiveCollectorTriggers = 5; 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* static const char*
ProcessNameForCollectorLog() ProcessNameForCollectorLog()
{ {
@ -299,10 +477,10 @@ KillTimers()
{ {
nsJSContext::KillGCTimer(); nsJSContext::KillGCTimer();
nsJSContext::KillShrinkingGCTimer(); nsJSContext::KillShrinkingGCTimer();
nsJSContext::KillCCTimer(); nsJSContext::KillCCRunner();
nsJSContext::KillICCTimer(); nsJSContext::KillICCRunner();
nsJSContext::KillFullGCTimer(); nsJSContext::KillFullGCTimer();
nsJSContext::KillInterSliceGCTimer(); nsJSContext::KillInterSliceGCRunner();
} }
// If we collected a substantial amount of cycles, poke the GC since more objects // If we collected a substantial amount of cycles, poke the GC since more objects
@ -1451,7 +1629,7 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
//static //static
void void
nsJSContext::RunCycleCollectorSlice() nsJSContext::RunCycleCollectorSlice(TimeStamp aDeadline)
{ {
if (!NS_IsMainThread()) { if (!NS_IsMainThread()) {
return; return;
@ -1467,33 +1645,40 @@ nsJSContext::RunCycleCollectorSlice()
js::SliceBudget budget = js::SliceBudget::unlimited(); js::SliceBudget budget = js::SliceBudget::unlimited();
if (sIncrementalCC) { if (sIncrementalCC) {
int64_t baseBudget = kICCSliceBudget;
if (!aDeadline.IsNull()) {
baseBudget = int64_t((aDeadline - TimeStamp::Now()).ToMilliseconds());
}
if (gCCStats.mBeginTime.IsNull()) { if (gCCStats.mBeginTime.IsNull()) {
// If no CC is in progress, use the standard slice time. // If no CC is in progress, use the standard slice time.
budget = js::SliceBudget(js::TimeBudget(kICCSliceBudget)); budget = js::SliceBudget(js::TimeBudget(baseBudget));
} else { } else {
TimeStamp now = TimeStamp::Now(); TimeStamp now = TimeStamp::Now();
// Only run a limited slice if we're within the max running time. // Only run a limited slice if we're within the max running time.
uint32_t runningTime = TimeBetween(gCCStats.mBeginTime, now); uint32_t runningTime = TimeBetween(gCCStats.mBeginTime, now);
if (runningTime < kMaxICCDuration) { if (runningTime < kMaxICCDuration) {
// Try to make up for a delay in running this slice. const float maxSlice = MainThreadIdlePeriod::GetLongIdlePeriod();
float sliceDelayMultiplier = TimeBetween(gCCStats.mEndSliceTime, now) / (float)kICCIntersliceDelay;
float delaySliceBudget = kICCSliceBudget * sliceDelayMultiplier;
// 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. // half way through the ICC, to avoid large sync CCs.
float percentToHalfDone = std::min(2.0f * runningTime / kMaxICCDuration, 1.0f); float percentToHalfDone = std::min(2.0f * runningTime / kMaxICCDuration, 1.0f);
const float maxLaterSlice = 40.0f; float laterSliceBudget = maxSlice * percentToHalfDone;
float laterSliceBudget = maxLaterSlice * percentToHalfDone;
budget = js::SliceBudget(js::TimeBudget(std::max({delaySliceBudget, budget = js::SliceBudget(js::TimeBudget(std::max({delaySliceBudget,
laterSliceBudget, (float)kICCSliceBudget}))); laterSliceBudget, (float)baseBudget})));
} }
} }
} }
nsCycleCollector_collectSlice(budget, sDidPaintAfterPreviousICCSlice); nsCycleCollector_collectSlice(budget);
sDidPaintAfterPreviousICCSlice = false;
gCCStats.FinishCycleCollectionSlice(); gCCStats.FinishCycleCollectionSlice();
} }
@ -1529,11 +1714,11 @@ nsJSContext::GetMaxCCSliceTimeSinceClear()
return gCCStats.mMaxSliceTimeSinceClear; return gCCStats.mMaxSliceTimeSinceClear;
} }
static void static bool
ICCTimerFired(nsITimer* aTimer, void* aClosure) ICCRunnerFired(TimeStamp aDeadline, void* aData)
{ {
if (sDidShutdown) { if (sDidShutdown) {
return; return false;
} }
// Ignore ICC timer fires during IGC. Running ICC during an IGC will cause us // 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(); PRTime now = PR_Now();
if (sCCLockedOutTime == 0) { if (sCCLockedOutTime == 0) {
sCCLockedOutTime = now; sCCLockedOutTime = now;
return; return false;
} }
if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) { if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) {
return; return false;
} }
} }
nsJSContext::RunCycleCollectorSlice(); nsJSContext::RunCycleCollectorSlice(aDeadline);
return true;
} }
//static //static
@ -1562,22 +1748,16 @@ nsJSContext::BeginCycleCollectionCallback()
gCCStats.mBeginTime = gCCStats.mBeginSliceTime.IsNull() ? TimeStamp::Now() : gCCStats.mBeginSliceTime; gCCStats.mBeginTime = gCCStats.mBeginSliceTime.IsNull() ? TimeStamp::Now() : gCCStats.mBeginSliceTime;
gCCStats.mSuspected = nsCycleCollector_suspectedCount(); gCCStats.mSuspected = nsCycleCollector_suspectedCount();
KillCCTimer(); KillCCRunner();
gCCStats.RunForgetSkippable(); 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 // 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. // an incremental collection, and we want to be sure to finish it.
CallCreateInstance("@mozilla.org/timer;1", &sICCTimer); sICCRunner = CollectorRunner::Create(ICCRunnerFired, kICCIntersliceDelay,
if (sICCTimer) { kIdleICCSliceBudget, true);
sICCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
sICCTimer->InitWithNamedFuncCallback(ICCTimerFired, nullptr,
kICCIntersliceDelay,
nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
"ICCTimerFired");
}
} }
static_assert(NS_GC_DELAY > kMaxICCDuration, "A max duration ICC shouldn't reduce GC delay to 0"); 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()); MOZ_ASSERT(NS_IsMainThread());
nsJSContext::KillICCTimer(); nsJSContext::KillICCRunner();
// Update timing information for the current slice before we log it, if // Update timing information for the current slice before we log it, if
// we previously called PrepareForCycleCollectionSlice(). During shutdown // we previously called PrepareForCycleCollectionSlice(). During shutdown
@ -1736,16 +1916,24 @@ nsJSContext::EndCycleCollectionCallback(CycleCollectorResults &aResults)
} }
// static // static
void bool
InterSliceGCTimerFired(nsITimer *aTimer, void *aClosure) InterSliceGCRunnerFired(TimeStamp aDeadline, void* aData)
{ {
nsJSContext::KillInterSliceGCTimer(); nsJSContext::KillInterSliceGCRunner();
int64_t budget = XRE_IsE10sParentProcess() && nsContentUtils::GetUserIsInteracting() && sActiveIntersliceGCBudget ? MOZ_ASSERT(sActiveIntersliceGCBudget > 0);
sActiveIntersliceGCBudget : NS_INTERSLICE_GC_BUDGET; int64_t budget = sActiveIntersliceGCBudget;
nsJSContext::GarbageCollectNow(JS::gcreason::INTER_SLICE_GC, 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::IncrementalGC,
nsJSContext::NonShrinkingGC, nsJSContext::NonShrinkingGC,
budget); budget);
return true;
} }
// static // static
@ -1753,9 +1941,12 @@ void
GCTimerFired(nsITimer *aTimer, void *aClosure) GCTimerFired(nsITimer *aTimer, void *aClosure)
{ {
nsJSContext::KillGCTimer(); nsJSContext::KillGCTimer();
uintptr_t reason = reinterpret_cast<uintptr_t>(aClosure); // Now start the actual GC after initial timer has fired.
nsJSContext::GarbageCollectNow(static_cast<JS::gcreason::Reason>(reason), sInterSliceGCRunner = CollectorRunner::Create(InterSliceGCRunnerFired,
nsJSContext::IncrementalGC); NS_INTERSLICE_GC_DELAY,
sActiveIntersliceGCBudget,
false,
aClosure);
} }
// static // static
@ -1778,11 +1969,11 @@ ShouldTriggerCC(uint32_t aSuspected)
TimeUntilNow(sLastCCEndTime) > NS_CC_FORCED); TimeUntilNow(sLastCCEndTime) > NS_CC_FORCED);
} }
static void static bool
CCTimerFired(nsITimer *aTimer, void *aClosure) CCRunnerFired(TimeStamp aDeadline, void* aData)
{ {
if (sDidShutdown) { if (sDidShutdown) {
return; return false;
} }
static uint32_t ccDelay = NS_CC_DELAY; static uint32_t ccDelay = NS_CC_DELAY;
@ -1791,48 +1982,53 @@ CCTimerFired(nsITimer *aTimer, void *aClosure)
PRTime now = PR_Now(); PRTime now = PR_Now();
if (sCCLockedOutTime == 0) { 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 // often enough before CC. Because of reduced ccDelay
// forgetSkippable will be called just a few times. // forgetSkippable will be called just a few times.
// NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling // NS_MAX_CC_LOCKEDOUT_TIME limit guarantees that we end up calling
// forgetSkippable and CycleCollectNow eventually. // forgetSkippable and CycleCollectNow eventually.
sCCTimerFireCount = 0; sCCRunnerFireCount = 0;
sCCLockedOutTime = now; sCCLockedOutTime = now;
return; return false;
} }
if (now - sCCLockedOutTime < NS_MAX_CC_LOCKEDOUT_TIME) { 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 // 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, 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 // 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. // early timer fire to allow cleanup before the CC.
int32_t numEarlyTimerFires = std::max((int32_t)ccDelay / NS_CC_SKIPPABLE_DELAY - 2, 1); 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(); uint32_t suspected = nsCycleCollector_suspectedCount();
if (isLateTimerFire && ShouldTriggerCC(suspected)) { if (isLateTimerFire && ShouldTriggerCC(suspected)) {
if (sCCTimerFireCount == numEarlyTimerFires + 1) { if (sCCRunnerFireCount == numEarlyTimerFires + 1) {
FireForgetSkippable(suspected, true); FireForgetSkippable(suspected, true);
didDoWork = true;
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
// Our efforts to avoid a CC have failed, so we return to let the // Our efforts to avoid a CC have failed, so we return to let the
// timer fire once more to trigger a CC. // timer fire once more to trigger a CC.
return; return didDoWork;
} }
} else { } else {
// We are in the final timer fire and still meet the conditions for // We are in the final timer fire and still meet the conditions for
// triggering a CC. Let RunCycleCollectorSlice finish the current IGC, if // 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. // 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) || } else if (((sPreviousSuspectedCount + 100) <= suspected) ||
(sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS)) { (sCleanupsSinceLastGC < NS_MAJOR_FORGET_SKIPPABLE_CALLS)) {
// Only do a forget skippable if there are more than a few new objects // Only do a forget skippable if there are more than a few new objects
// or we're doing the initial forget skippables. // or we're doing the initial forget skippables.
FireForgetSkippable(suspected, false); FireForgetSkippable(suspected, false);
didDoWork = true;
} }
if (isLateTimerFire) { 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 // We have either just run the CC or decided we don't want to run the CC
// next time, so kill the timer. // next time, so kill the timer.
sPreviousSuspectedCount = 0; sPreviousSuspectedCount = 0;
nsJSContext::KillCCTimer(); nsJSContext::KillCCRunner();
} }
return didDoWork;
} }
// static // static
@ -1889,13 +2087,13 @@ ReadyToTriggerExpensiveCollectorTimer()
} }
// Check all of the various collector timers and see if they are waiting to fire. // Check all of the various collector timers/runners and see if they are waiting to fire.
// For the synchronous collector timers, sGCTimer and sCCTimer, we only want to trigger // For the synchronous collector timers/runners, sGCTimer and sCCRunner, we only want to
// the collection occasionally, because they are expensive. The incremental collector // 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 // timers, sInterSliceGCRunner and sICCRunner, are fast and need to be run many times, so
// always run their corresponding timer. // 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. // on a long timer.
// static // static
@ -1913,8 +2111,8 @@ nsJSContext::RunNextCollectorTimer()
return; return;
} }
if (sInterSliceGCTimer) { if (sInterSliceGCRunner) {
InterSliceGCTimerFired(nullptr, nullptr); InterSliceGCRunnerFired(TimeStamp(), nullptr);
return; return;
} }
@ -1922,15 +2120,15 @@ nsJSContext::RunNextCollectorTimer()
// anything if a GC is in progress. // anything if a GC is in progress.
MOZ_ASSERT(!sCCLockedOut, "Don't check the CC timers if the CC is locked out."); MOZ_ASSERT(!sCCLockedOut, "Don't check the CC timers if the CC is locked out.");
if (sCCTimer) { if (sCCRunner) {
if (ReadyToTriggerExpensiveCollectorTimer()) { if (ReadyToTriggerExpensiveCollectorTimer()) {
CCTimerFired(nullptr, nullptr); CCRunnerFired(TimeStamp(), nullptr);
} }
return; return;
} }
if (sICCTimer) { if (sICCRunner) {
ICCTimerFired(nullptr, nullptr); ICCRunnerFired(TimeStamp(), nullptr);
return; return;
} }
} }
@ -1952,12 +2150,12 @@ nsJSContext::PokeGC(JS::gcreason::Reason aReason,
sNeedsFullGC = true; sNeedsFullGC = true;
} }
if (sGCTimer || sInterSliceGCTimer) { if (sGCTimer || sInterSliceGCRunner) {
// There's already a timer for GC'ing, just return // There's already a timer for GC'ing, just return
return; return;
} }
if (sCCTimer) { if (sCCRunner) {
// Make sure CC is called... // Make sure CC is called...
sNeedsFullCC = true; sNeedsFullCC = true;
// and GC after it. // and GC after it.
@ -1965,7 +2163,7 @@ nsJSContext::PokeGC(JS::gcreason::Reason aReason,
return; return;
} }
if (sICCTimer) { if (sICCRunner) {
// Make sure GC is called after the current CC completes. // Make sure GC is called after the current CC completes.
// No need to set sNeedsFullCC because we are currently running a CC. // No need to set sNeedsFullCC because we are currently running a CC.
sNeedsGCAfterCC = true; sNeedsGCAfterCC = true;
@ -1991,6 +2189,7 @@ nsJSContext::PokeGC(JS::gcreason::Reason aReason,
: NS_GC_DELAY), : NS_GC_DELAY),
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY, nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
"GCTimerFired"); "GCTimerFired");
first = false; first = false;
} }
@ -2020,24 +2219,19 @@ nsJSContext::PokeShrinkingGC()
void void
nsJSContext::MaybePokeCC() nsJSContext::MaybePokeCC()
{ {
if (sCCTimer || sICCTimer || sShuttingDown || !sHasRunGC) { if (sCCRunner || sICCRunner || sShuttingDown || !sHasRunGC) {
return; return;
} }
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
sCCTimerFireCount = 0; sCCRunnerFireCount = 0;
CallCreateInstance("@mozilla.org/timer;1", &sCCTimer);
if (!sCCTimer) {
return;
}
// We can kill some objects before running forgetSkippable. // We can kill some objects before running forgetSkippable.
nsCycleCollector_dispatchDeferredDeletion(); nsCycleCollector_dispatchDeferredDeletion();
sCCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection)); sCCRunner =
sCCTimer->InitWithNamedFuncCallback(CCTimerFired, nullptr, CollectorRunner::Create(CCRunnerFired, NS_CC_SKIPPABLE_DELAY,
NS_CC_SKIPPABLE_DELAY, kForgetSkippableSliceDuration, true);
nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY,
"CCTimerFired");
} }
} }
@ -2061,11 +2255,11 @@ nsJSContext::KillFullGCTimer()
} }
void void
nsJSContext::KillInterSliceGCTimer() nsJSContext::KillInterSliceGCRunner()
{ {
if (sInterSliceGCTimer) { if (sInterSliceGCRunner) {
sInterSliceGCTimer->Cancel(); sInterSliceGCRunner->Cancel();
NS_RELEASE(sInterSliceGCTimer); sInterSliceGCRunner = nullptr;
} }
} }
@ -2081,24 +2275,24 @@ nsJSContext::KillShrinkingGCTimer()
//static //static
void void
nsJSContext::KillCCTimer() nsJSContext::KillCCRunner()
{ {
sCCLockedOutTime = 0; sCCLockedOutTime = 0;
if (sCCTimer) { if (sCCRunner) {
sCCTimer->Cancel(); sCCRunner->Cancel();
NS_RELEASE(sCCTimer); sCCRunner = nullptr;
} }
} }
//static //static
void void
nsJSContext::KillICCTimer() nsJSContext::KillICCRunner()
{ {
sCCLockedOutTime = 0; sCCLockedOutTime = 0;
if (sICCTimer) { if (sICCRunner) {
sICCTimer->Cancel(); sICCRunner->Cancel();
NS_RELEASE(sICCTimer); sICCRunner = nullptr;
} }
} }
@ -2170,8 +2364,8 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
sCCLockedOut = false; sCCLockedOut = false;
sIsCompactingOnUserInactive = false; sIsCompactingOnUserInactive = false;
// May need to kill the inter-slice GC timer // May need to kill the inter-slice GC runner
nsJSContext::KillInterSliceGCTimer(); nsJSContext::KillInterSliceGCRunner();
sCCollectedWaitingForGC = 0; sCCollectedWaitingForGC = 0;
sCCollectedZonesWaitingForGC = 0; sCCollectedZonesWaitingForGC = 0;
@ -2212,15 +2406,11 @@ DOMGCSliceCallback(JSContext* aCx, JS::GCProgress aProgress, const JS::GCDescrip
case JS::GC_SLICE_END: case JS::GC_SLICE_END:
// Schedule another GC slice if the GC has more work to do. // Schedule another GC slice if the GC has more work to do.
nsJSContext::KillInterSliceGCTimer(); nsJSContext::KillInterSliceGCRunner();
if (!sShuttingDown && !aDesc.isComplete_) { if (!sShuttingDown && !aDesc.isComplete_) {
CallCreateInstance("@mozilla.org/timer;1", &sInterSliceGCTimer); sInterSliceGCRunner =
sInterSliceGCTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection)); CollectorRunner::Create(InterSliceGCRunnerFired, NS_INTERSLICE_GC_DELAY,
sInterSliceGCTimer->InitWithNamedFuncCallback(InterSliceGCTimerFired, sActiveIntersliceGCBudget, false);
nullptr,
NS_INTERSLICE_GC_DELAY,
nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
"InterSliceGCTimerFired");
} }
if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) { if (ShouldTriggerCC(nsCycleCollector_suspectedCount())) {
@ -2274,7 +2464,7 @@ void
mozilla::dom::StartupJSEnvironment() mozilla::dom::StartupJSEnvironment()
{ {
// initialize all our statics, so that we can restart XPCOM // initialize all our statics, so that we can restart XPCOM
sGCTimer = sShrinkingGCTimer = sFullGCTimer = sCCTimer = sICCTimer = nullptr; sGCTimer = sShrinkingGCTimer = sFullGCTimer = nullptr;
sCCLockedOut = false; sCCLockedOut = false;
sCCLockedOutTime = 0; sCCLockedOutTime = 0;
sLastCCEndTime = TimeStamp(); sLastCCEndTime = TimeStamp();
@ -2609,52 +2799,6 @@ nsJSContext::EnsureStatics()
sIsInitialized = true; 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* nsScriptNameSpaceManager*
mozilla::dom::GetNameSpaceManager() mozilla::dom::GetNameSpaceManager()
{ {

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

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

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

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

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

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

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

@ -1364,10 +1364,15 @@ ContentParent::Init()
// process. // process.
if (nsIPresShell::IsAccessibilityActive()) { if (nsIPresShell::IsAccessibilityActive()) {
#if defined(XP_WIN) #if defined(XP_WIN)
Unused << #if defined(RELEASE_OR_BETA)
SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); // 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 #else
Unused << SendActivateA11y(0); Unused << SendActivateA11y(0, 0);
#endif #endif
} }
#endif #endif
@ -2772,10 +2777,15 @@ ContentParent::Observe(nsISupports* aSubject,
// Make sure accessibility is running in content process when // Make sure accessibility is running in content process when
// accessibility gets initiated in chrome process. // accessibility gets initiated in chrome process.
#if defined(XP_WIN) #if defined(XP_WIN)
Unused << #if defined(RELEASE_OR_BETA)
SendActivateA11y(a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); // 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 #else
Unused << SendActivateA11y(0); Unused << SendActivateA11y(0, 0);
#endif #endif
} else { } else {
// If possible, shut down accessibility in content process when // If possible, shut down accessibility in content process when

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

@ -443,11 +443,13 @@ child:
/** /**
* Start accessibility engine in content process. * 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 * @param aMsaaID is an a11y-specific unique id for the content process
* that is generated by the chrome process. Only used on * that is generated by the chrome process. Only used on
* Windows; pass 0 on other platforms. * 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). * Shutdown accessibility engine in content process (if not in use).

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

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

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

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

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

@ -894,6 +894,11 @@ public:
* normally return the same SourceSurface object. * normally return the same SourceSurface object.
*/ */
virtual already_AddRefed<SourceSurface> Snapshot() = 0; 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; virtual IntSize GetSize() = 0;
/** /**

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

@ -9,9 +9,162 @@
#include "DrawTargetCapture.h" #include "DrawTargetCapture.h"
#ifdef BUILD_ARM_NEON
#include "mozilla/arm.h"
#endif
namespace mozilla { namespace mozilla {
namespace gfx { 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> already_AddRefed<DrawTargetCapture>
DrawTarget::CreateCaptureDT(const IntSize& aSize) DrawTarget::CreateCaptureDT(const IntSize& aSize)
{ {
@ -64,6 +217,51 @@ DrawTarget::StrokeGlyphs(ScaledFont* aFont,
Stroke(path, aPattern, aStrokeOptions, aOptions); 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 gfx
} // namespace mozilla } // namespace mozilla

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

@ -99,6 +99,38 @@ DrawTargetD2D1::Snapshot()
return snapshot.forget(); 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, // Command lists are kept around by device contexts until EndDraw is called,
// this can cause issues with memory usage (see bug 1238328). EndDraw/BeginDraw // this can cause issues with memory usage (see bug 1238328). EndDraw/BeginDraw
// are expensive though, especially relatively when little work is done, so // are expensive though, especially relatively when little work is done, so
@ -348,20 +380,48 @@ DrawTargetD2D1::MaskSurface(const Pattern &aSource,
PrepareForDrawing(aOptions.mCompositionOp, 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 // FillOpacityMask only works if the antialias mode is MODE_ALIASED
mDC->SetAntialiasMode(D2D1_ANTIALIAS_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 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); RefPtr<ID2D1Brush> brush = CreateBrushForPattern(aSource, aOptions.mAlpha);
mDC->FillOpacityMask(bitmap, brush, D2D1_OPACITY_MASK_CONTENT_GRAPHICS, D2DRect(dest), D2DRect(maskRect)); 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) bool aUserSpace)
{ {
RefPtr<ID2D1Image> image; RefPtr<ID2D1Image> image;
switch (aSurface->GetType()) { switch (aSurface->GetType()) {
case SurfaceType::D2D1_1_IMAGE: case SurfaceType::D2D1_1_IMAGE:
{ {

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

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

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

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

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

@ -19,7 +19,9 @@
#include "nsRect.h" #include "nsRect.h"
#include "nspr.h" #include "nspr.h"
#include "png.h" #include "png.h"
#include "RasterImage.h" #include "RasterImage.h"
#include "SurfaceCache.h"
#include "SurfacePipeFactory.h" #include "SurfacePipeFactory.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "mozilla/Telemetry.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 // Post our size to the superclass
decoder->PostSize(frameRect.width, frameRect.height); 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()) { if (decoder->HasError()) {
// Setting the size led to an error. // Setting the size led to an error.
png_error(decoder->mPNG, "Sizing 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 (interlace_type == PNG_INTERLACE_ADAM7) {
if (frameRect.height < INT32_MAX / (frameRect.width * int32_t(channels))) { if (frameRect.height < INT32_MAX / (frameRect.width * int32_t(channels))) {
const size_t bufferSize = channels * frameRect.width * frameRect.height; 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)); decoder->interlacebuf = static_cast<uint8_t*>(malloc(bufferSize));
} }
if (!decoder->interlacebuf) { if (!decoder->interlacebuf) {

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

@ -6,11 +6,13 @@
#define INITGUID #define INITGUID
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Move.h" #include "mozilla/Move.h"
#include "mozilla/mscom/DispatchForwarder.h" #include "mozilla/mscom/DispatchForwarder.h"
#include "mozilla/mscom/Interceptor.h" #include "mozilla/mscom/Interceptor.h"
#include "mozilla/mscom/InterceptorLog.h" #include "mozilla/mscom/InterceptorLog.h"
#include "mozilla/mscom/MainThreadInvoker.h" #include "mozilla/mscom/MainThreadInvoker.h"
#include "mozilla/mscom/Objref.h"
#include "mozilla/mscom/Registration.h" #include "mozilla/mscom/Registration.h"
#include "mozilla/mscom/Utils.h" #include "mozilla/mscom/Utils.h"
#include "MainThreadUtils.h" #include "MainThreadUtils.h"
@ -20,6 +22,7 @@
#include "nsDirectoryServiceUtils.h" #include "nsDirectoryServiceUtils.h"
#include "nsRefPtrHashtable.h" #include "nsRefPtrHashtable.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsXULAppAPI.h"
namespace mozilla { namespace mozilla {
namespace mscom { namespace mscom {
@ -142,6 +145,7 @@ Interceptor::GetClassForHandler(DWORD aDestContext, void* aDestContextPtr,
aDestContext == MSHCTX_DIFFERENTMACHINE) { aDestContext == MSHCTX_DIFFERENTMACHINE) {
return E_INVALIDARG; return E_INVALIDARG;
} }
MOZ_ASSERT(mEventSink); MOZ_ASSERT(mEventSink);
return mEventSink->GetHandler(WrapNotNull(aHandlerClsid)); return mEventSink->GetHandler(WrapNotNull(aHandlerClsid));
} }
@ -177,12 +181,60 @@ Interceptor::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
DWORD dwDestContext, void* pvDestContext, DWORD dwDestContext, void* pvDestContext,
DWORD mshlflags) 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); pvDestContext, mshlflags);
if (FAILED(hr)) { if (FAILED(hr)) {
return 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)); return mEventSink->WriteHandlerPayload(WrapNotNull(pStm));
} }

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

@ -453,6 +453,7 @@ MainThreadHandoff::GetHandler(NotNull<CLSID*> aHandlerClsid)
if (!mHandlerProvider) { if (!mHandlerProvider) {
return E_NOTIMPL; return E_NOTIMPL;
} }
return mHandlerProvider->GetHandler(aHandlerClsid); 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 * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef ACCESSIBILITY #if defined(ACCESSIBILITY)
#include "mozilla/mscom/Registration.h" #include "mozilla/mscom/Registration.h"
#if defined(MOZILLA_INTERNAL_API)
#include "nsTArray.h" #include "nsTArray.h"
#endif #endif
#endif
#include "mozilla/mscom/Utils.h" #include "mozilla/mscom/Utils.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
@ -139,6 +141,8 @@ IsVtableIndexFromParentInterface(REFIID aInterface, unsigned long aVtableIndex)
return result; return result;
} }
#if defined(MOZILLA_INTERNAL_API)
bool bool
IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom, IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom,
unsigned long aVtableIndexHint) unsigned long aVtableIndexHint)
@ -223,6 +227,8 @@ IsInterfaceEqualToOrInheritedFrom(REFIID aInterface, REFIID aFrom,
return false; return false;
} }
#endif // defined(MOZILLA_INTERNAL_API)
#endif // defined(ACCESSIBILITY) #endif // defined(ACCESSIBILITY)
} // namespace mscom } // namespace mscom

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

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

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

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

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

@ -9,6 +9,7 @@
#include "mozilla/ArrayUtils.h" #include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/mscom/Objref.h"
#include "nsWindowsHelpers.h" #include "nsWindowsHelpers.h"
#include <objbase.h> #include <objbase.h>
@ -48,7 +49,7 @@ Handler::Handler(IUnknown* aOuter, HRESULT* aResult)
return; return;
} }
// mInnerMarshal is a weak ref // mUnmarshal is a weak ref
mUnmarshal->Release(); mUnmarshal->Release();
} }
@ -169,14 +170,28 @@ Handler::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
RefPtr<IUnknown> unkToMarshal; RefPtr<IUnknown> unkToMarshal;
HRESULT hr; HRESULT hr;
REFIID marshalAs = MarshalAs(riid); #if defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
if (marshalAs == riid) { LARGE_INTEGER seekTo;
unkToMarshal = static_cast<IUnknown*>(pv); seekTo.QuadPart = 0;
} else {
hr = mInnerUnk->QueryInterface(marshalAs, getter_AddRefs(unkToMarshal)); 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)) { if (FAILED(hr)) {
return 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(), hr = mUnmarshal->MarshalInterface(pStm, marshalAs, unkToMarshal.get(),
@ -185,6 +200,22 @@ Handler::MarshalInterface(IStream* pStm, REFIID riid, void* pv,
return hr; 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()) { if (!HasPayload()) {
return S_OK; 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, // Unfortunately when COM re-marshals a proxy that prevouisly had a payload,
// we must re-serialize it. // we must re-serialize it.
return WriteHandlerPayload(pStm, marshalAs); return WriteHandlerPayload(pStm, marshalAs);
#endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
} }
HRESULT HRESULT

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

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

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

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

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

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

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

@ -248,7 +248,8 @@ class Scope : public js::gc::TenuredCell
template <typename ConcreteScope, XDRMode mode> template <typename ConcreteScope, XDRMode mode>
static bool XDRSizedBindingNames(XDRState<mode>* xdr, Handle<ConcreteScope*> scope, 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); 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 void
nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime) 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) { if (mViewManagerFlushIsPending) {
RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get(); RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
@ -1998,7 +2038,7 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
timelines->AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::END); timelines->AddMarkerForDocShell(docShell, "Paint", MarkerTracingType::END);
} }
notifyGC = true; dispatchRunnablesAfterTick = true;
} }
#ifndef ANDROID /* bug 1142079 */ #ifndef ANDROID /* bug 1142079 */
@ -2017,10 +2057,14 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
ScheduleViewManagerFlush(); ScheduleViewManagerFlush();
} }
if (notifyGC && nsContentUtils::XPConnect()) { if (dispatchRunnablesAfterTick && sPendingIdleRunnables) {
GeckoProfilerTracingRAII tracer("Paint", "NotifyDidPaint"); AutoTArray<RunnableWithDelay, 8>* runnables = sPendingIdleRunnables;
nsContentUtils::XPConnect()->NotifyDidPaint(); sPendingIdleRunnables = nullptr;
nsJSContext::NotifyDidPaint(); 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 imgIRequest;
class nsIDOMEvent; class nsIDOMEvent;
class nsINode; class nsINode;
class nsIRunnable;
namespace mozilla { namespace mozilla {
class RefreshDriverTimer; class RefreshDriverTimer;
@ -333,6 +334,10 @@ public:
*/ */
static mozilla::TimeStamp GetIdleDeadlineHint(mozilla::TimeStamp aDefault); static mozilla::TimeStamp GetIdleDeadlineHint(mozilla::TimeStamp aDefault);
static void DispatchIdleRunnableAfterTick(nsIRunnable* aRunnable,
uint32_t aDelay);
static void CancelIdleRunnable(nsIRunnable* aRunnable);
bool SkippedPaints() const bool SkippedPaints() const
{ {
return mSkippedPaints; 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-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-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-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 test cases
== mask-image-1a.html mask-image-1-ref.html == 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-3c.html mask-image-3-ref.html
fuzzy-if(skiaContent||winWidget,1,43) == mask-image-3d.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 == 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) 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) == 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-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 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 fuzzy-if(skiaContent,71,203) == mask-image-3i.html mask-image-3-ref.html
== mask-image-4a.html blank.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"); "Number of Marker frames should be equal to eTypeCount");
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
nsSVGMark& mark = marks[i]; const nsSVGMark& mark = marks[i];
nsSVGMarkerFrame* frame = markerFrames[mark.type]; nsSVGMarkerFrame* frame = markerFrames[mark.type];
if (frame) { if (frame) {
SVGBBox mbbox = SVGBBox mbbox =
frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this, frame->GetMarkBBoxContribution(aToBBoxUserspace, aFlags, this,
&marks[i], strokeWidth); mark, strokeWidth);
MOZ_ASSERT(mbbox.IsFinite(), "bbox is about to go bad"); MOZ_ASSERT(mbbox.IsFinite(), "bbox is about to go bad");
bbox.UnionEdges(mbbox); bbox.UnionEdges(mbbox);
} }
@ -896,10 +896,10 @@ SVGGeometryFrame::PaintMarkers(gfxContext& aContext,
"Number of Marker frames should be equal to eTypeCount"); "Number of Marker frames should be equal to eTypeCount");
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
nsSVGMark& mark = marks[i]; const nsSVGMark& mark = marks[i];
nsSVGMarkerFrame* frame = markerFrames[mark.type]; nsSVGMarkerFrame* frame = markerFrames[mark.type];
if (frame) { if (frame) {
frame->PaintMark(aContext, aTransform, this, &mark, strokeWidth, frame->PaintMark(aContext, aTransform, this, mark, strokeWidth,
aImgParams); aImgParams);
} }
} }

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

@ -66,10 +66,6 @@ UNIFIED_SOURCES += [
'SVGViewFrame.cpp', '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' FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [ LOCAL_INCLUDES += [
'../../widget', '../../widget',

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

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

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

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

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

@ -14,162 +14,28 @@
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "nsSVGEffects.h" #include "nsSVGEffects.h"
#include "mozilla/dom/SVGMaskElement.h" #include "mozilla/dom/SVGMaskElement.h"
#ifdef BUILD_ARM_NEON
#include "mozilla/arm.h"
#include "nsSVGMaskFrameNEON.h"
#endif
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla::gfx; using namespace mozilla::gfx;
using namespace mozilla::image; using namespace mozilla::image;
// c = n / 255 static LuminanceType
// c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5 GetLuminanceType(uint8_t aNSMaskType)
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)
{ {
#ifdef BUILD_ARM_NEON switch (aNSMaskType) {
if (mozilla::supports_neon()) { case NS_STYLE_MASK_TYPE_LUMINANCE:
ComputesRGBLuminanceMask_NEON(aSourceData, aSourceStride, return LuminanceType::LUMINANCE;
aDestData, aDestStride, case NS_STYLE_COLOR_INTERPOLATION_LINEARRGB:
aSize, aOpacity); return LuminanceType::LINEARRGB;
return; 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* nsIFrame*
NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
{ {
@ -258,44 +124,20 @@ nsSVGMaskFrame::GetMaskForMaskedFrame(MaskParams& aParams)
nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m, aParams.imgParams); nsSVGUtils::PaintFrameWithEffects(kid, *tmpCtx, m, aParams.imgParams);
} }
if (StyleSVG()->mColorInterpolation ==
NS_STYLE_COLOR_INTERPOLATION_LINEARRGB) {
maskType = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
}
RefPtr<SourceSurface> surface; RefPtr<SourceSurface> surface;
if (maskType == NS_STYLE_MASK_TYPE_LUMINANCE) { if (maskType == NS_STYLE_MASK_TYPE_LUMINANCE) {
RefPtr<SourceSurface> maskSnapshot = maskDT->Snapshot(); RefPtr<SourceSurface> maskSnapshot =
maskDT->IntoLuminanceSource(GetLuminanceType(maskType),
aParams.opacity);
if (!maskSnapshot) { if (!maskSnapshot) {
return nullptr; return nullptr;
} }
surface = maskSnapshot.forget();
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();
} else { } else {
maskDT->SetTransform(Matrix()); 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)); 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; 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 class nsSVGMaskFrame final : public nsSVGContainerFrame
{ {
friend nsIFrame* 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 // 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. // create substatial DOM garbage, the CC tends not to run enough normally.
++gTestCount; ++gTestCount;
if (gTestCount % 1000 == 0) { if (gTestCount % 250 == 0) {
CU.forceGC(); CU.forceGC();
CU.forceCC(); CU.forceCC();
} }

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

@ -8,12 +8,15 @@
#define MOZ_EMBEDDED_LIBPNG #define MOZ_EMBEDDED_LIBPNG
/* Limit image dimensions (bug #251381, #591822, #967656, and #1283961) */ /* Limit image dimensions (bug #251381, #591822, #967656, and #1283961) */
#define PNG_USER_LIMITS_SUPPORTED
#ifndef MOZ_PNG_MAX_WIDTH #ifndef MOZ_PNG_MAX_WIDTH
# define MOZ_PNG_MAX_WIDTH 0x7fffffffL /* Unlimited */ # define MOZ_PNG_MAX_WIDTH 0x7fffffffL /* Unlimited */
#endif #endif
#ifndef MOZ_PNG_MAX_HEIGHT #ifndef MOZ_PNG_MAX_HEIGHT
# define MOZ_PNG_MAX_HEIGHT 0x7fffffffL /* Unlimited */ # define MOZ_PNG_MAX_HEIGHT 0x7fffffffL /* Unlimited */
#endif #endif
/* but allow nsPNGDecoder to override the limits (bug #1368407) */
#define PNG_SET_USER_LIMITS_SUPPORTED
#define PNG_API_RULE 0 #define PNG_API_RULE 0
#define PNG_COST_SHIFT 3 #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.max", -1);
pref("javascript.options.mem.gc_per_zone", true); pref("javascript.options.mem.gc_per_zone", true);
pref("javascript.options.mem.gc_incremental", 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.gc_compacting", true);
pref("javascript.options.mem.log", false); pref("javascript.options.mem.log", false);
pref("javascript.options.mem.notify", false); pref("javascript.options.mem.notify", false);

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

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

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

@ -527,7 +527,11 @@ add_task(async function test_subprocess_pathSearch() {
add_task(async function test_subprocess_workdir() { add_task(async function test_subprocess_workdir() {
let procDir = await OS.File.getCurrentDirectory(); 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, notEqual(procDir, tmpDir,
"Current process directory must not be the current temp directory"); "Current process directory must not be the current temp directory");

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

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

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

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

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

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

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

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

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

@ -25,6 +25,10 @@ function test_normalized_vs_non_normalized()
if (!exists) if (!exists)
return; 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 // this has the same exact path as tmp1, it should equal tmp1
var tmp2 = new LocalFile(tmp1.path); var tmp2 = new LocalFile(tmp1.path);
do_check_true(tmp1.equals(tmp2)); do_check_true(tmp1.equals(tmp2));