зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to m-c, a=merge
MozReview-Commit-ID: JM3dPUdZm4k
This commit is contained in:
Коммит
2113ba8f80
|
@ -37,7 +37,7 @@ XPCOMUtils.defineLazyGetter(this, "WeaveService", () =>
|
|||
RemotePrompt:false, SessionStore:false,
|
||||
ShellService:false, SimpleServiceDiscovery:false, TabCrashHandler:false,
|
||||
Task:false, UITour:false, WebChannel:false,
|
||||
WindowsRegistry:false, webrtcUI:false, UserAgentOverrides: false */
|
||||
WindowsRegistry:false, webrtcUI:false */
|
||||
|
||||
/**
|
||||
* IF YOU ADD OR REMOVE FROM THIS LIST, PLEASE UPDATE THE LIST ABOVE AS WELL.
|
||||
|
@ -92,7 +92,6 @@ let initializedModules = {};
|
|||
["WebChannel", "resource://gre/modules/WebChannel.jsm"],
|
||||
["WindowsRegistry", "resource://gre/modules/WindowsRegistry.jsm"],
|
||||
["webrtcUI", "resource:///modules/webrtcUI.jsm", "init"],
|
||||
["UserAgentOverrides", "resource://gre/modules/UserAgentOverrides.jsm"],
|
||||
].forEach(([name, resource, init]) => {
|
||||
if (init) {
|
||||
XPCOMUtils.defineLazyGetter(this, name, () => {
|
||||
|
@ -516,8 +515,6 @@ BrowserGlue.prototype = {
|
|||
// and e10s are active together.
|
||||
E10SAccessibilityCheck.init();
|
||||
}
|
||||
|
||||
UserAgentOverrides.init();
|
||||
},
|
||||
|
||||
// cleanup (called on application shutdown)
|
||||
|
@ -561,8 +558,6 @@ BrowserGlue.prototype = {
|
|||
os.removeObserver(this, "browser-search-engine-modified");
|
||||
os.removeObserver(this, "flash-plugin-hang");
|
||||
os.removeObserver(this, "xpi-signature-changed");
|
||||
|
||||
UserAgentOverrides.uninit();
|
||||
},
|
||||
|
||||
_onAppDefaults: function BG__onAppDefaults() {
|
||||
|
|
|
@ -361,6 +361,8 @@
|
|||
@RESPATH@/components/BrowserElementParent.js
|
||||
@RESPATH@/components/FeedProcessor.manifest
|
||||
@RESPATH@/components/FeedProcessor.js
|
||||
@RESPATH@/components/UAOverridesBootstrapper.js
|
||||
@RESPATH@/components/UAOverridesBootstrapper.manifest
|
||||
@RESPATH@/components/WellKnownOpportunisticUtils.js
|
||||
@RESPATH@/components/WellKnownOpportunisticUtils.manifest
|
||||
#ifndef XP_MACOSX
|
||||
|
|
|
@ -414,15 +414,17 @@ exports.getSnapshotTotals = function (census) {
|
|||
* The file selected by the user, or null, if cancelled.
|
||||
*/
|
||||
exports.openFilePicker = function ({ title, filters, defaultName, mode }) {
|
||||
mode = mode === "save" ? Ci.nsIFilePicker.modeSave : null;
|
||||
mode = mode === "open" ? Ci.nsIFilePicker.modeOpen : null;
|
||||
|
||||
if (mode == void 0) {
|
||||
let fpMode;
|
||||
if (mode === "save") {
|
||||
fpMode = Ci.nsIFilePicker.modeSave;
|
||||
} else if (mode === "open") {
|
||||
fpMode = Ci.nsIFilePicker.modeOpen;
|
||||
} else {
|
||||
throw new Error("No valid mode specified for nsIFilePicker.");
|
||||
}
|
||||
|
||||
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
|
||||
fp.init(window, title, mode);
|
||||
fp.init(window, title, fpMode);
|
||||
|
||||
for (let filter of (filters || [])) {
|
||||
fp.appendFilter(filter[0], filter[1]);
|
||||
|
|
|
@ -18,20 +18,18 @@ function waitForDeviceClosed() {
|
|||
if (!webrtcUI.showGlobalIndicator)
|
||||
return Promise.resolve();
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
const message = "webrtc:UpdateGlobalIndicators";
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster);
|
||||
ppmm.addMessageListener(message, function listener(aMessage) {
|
||||
info("Received " + message + " message");
|
||||
if (!aMessage.data.showGlobalIndicator) {
|
||||
ppmm.removeMessageListener(message, listener);
|
||||
deferred.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const message = "webrtc:UpdateGlobalIndicators";
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster);
|
||||
ppmm.addMessageListener(message, function listener(aMessage) {
|
||||
info("Received " + message + " message");
|
||||
if (!aMessage.data.showGlobalIndicator) {
|
||||
ppmm.removeMessageListener(message, listener);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
|
|
|
@ -12,7 +12,6 @@ var { TargetFactory } = require("devtools/client/framework/target");
|
|||
var { DebuggerServer } = require("devtools/server/main");
|
||||
var { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
|
||||
var Promise = require("promise");
|
||||
var Services = require("Services");
|
||||
var { WebAudioFront } = require("devtools/shared/fronts/webaudio");
|
||||
var DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
|
@ -65,7 +64,6 @@ function loadFrameScripts() {
|
|||
function addTab(aUrl, aWindow) {
|
||||
info("Adding tab: " + aUrl);
|
||||
|
||||
let deferred = Promise.defer();
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
|
||||
|
@ -73,52 +71,50 @@ function addTab(aUrl, aWindow) {
|
|||
let tab = targetBrowser.selectedTab = targetBrowser.addTab(aUrl);
|
||||
let linkedBrowser = tab.linkedBrowser;
|
||||
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
deferred.resolve(tab);
|
||||
return new Promise((resolve, reject) => {
|
||||
BrowserTestUtils.browserLoaded(linkedBrowser).then(function () {
|
||||
info("Tab added and finished loading: " + aUrl);
|
||||
resolve(tab);
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function removeTab(aTab, aWindow) {
|
||||
info("Removing tab.");
|
||||
|
||||
let deferred = Promise.defer();
|
||||
let targetWindow = aWindow || window;
|
||||
let targetBrowser = targetWindow.gBrowser;
|
||||
let tabContainer = targetBrowser.tabContainer;
|
||||
|
||||
tabContainer.addEventListener("TabClose", function (aEvent) {
|
||||
info("Tab removed and finished closing.");
|
||||
deferred.resolve();
|
||||
}, {once: true});
|
||||
return new Promise((resolve, reject) => {
|
||||
tabContainer.addEventListener("TabClose", function (aEvent) {
|
||||
info("Tab removed and finished closing.");
|
||||
resolve();
|
||||
}, {once: true});
|
||||
|
||||
targetBrowser.removeTab(aTab);
|
||||
return deferred.promise;
|
||||
targetBrowser.removeTab(aTab);
|
||||
});
|
||||
}
|
||||
|
||||
function once(aTarget, aEventName, aUseCapture = false) {
|
||||
info("Waiting for event: '" + aEventName + "' on " + aTarget + ".");
|
||||
|
||||
let deferred = Promise.defer();
|
||||
|
||||
for (let [add, remove] of [
|
||||
["on", "off"], // Use event emitter before DOM events for consistency
|
||||
["addEventListener", "removeEventListener"],
|
||||
["addListener", "removeListener"]
|
||||
]) {
|
||||
if ((add in aTarget) && (remove in aTarget)) {
|
||||
aTarget[add](aEventName, function onEvent(...aArgs) {
|
||||
aTarget[remove](aEventName, onEvent, aUseCapture);
|
||||
info("Got event: '" + aEventName + "' on " + aTarget + ".");
|
||||
deferred.resolve(...aArgs);
|
||||
}, aUseCapture);
|
||||
break;
|
||||
return new Promise((resolve, reject) => {
|
||||
for (let [add, remove] of [
|
||||
["on", "off"], // Use event emitter before DOM events for consistency
|
||||
["addEventListener", "removeEventListener"],
|
||||
["addListener", "removeListener"]
|
||||
]) {
|
||||
if ((add in aTarget) && (remove in aTarget)) {
|
||||
aTarget[add](aEventName, function onEvent(...aArgs) {
|
||||
aTarget[remove](aEventName, onEvent, aUseCapture);
|
||||
info("Got event: '" + aEventName + "' on " + aTarget + ".");
|
||||
resolve(...aArgs);
|
||||
}, aUseCapture);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
}
|
||||
|
||||
function reload(aTarget, aWaitForTargetEvent = "navigate") {
|
||||
|
@ -206,20 +202,21 @@ function teardown(aTarget) {
|
|||
// `onAdd` function that calls with the entire actors array on program link
|
||||
function getN(front, eventName, count, spread) {
|
||||
let actors = [];
|
||||
let deferred = Promise.defer();
|
||||
info(`Waiting for ${count} ${eventName} events`);
|
||||
front.on(eventName, function onEvent(...args) {
|
||||
let actor = args[0];
|
||||
if (actors.length !== count) {
|
||||
actors.push(spread ? args : actor);
|
||||
}
|
||||
info(`Got ${actors.length} / ${count} ${eventName} events`);
|
||||
if (actors.length === count) {
|
||||
front.off(eventName, onEvent);
|
||||
deferred.resolve(actors);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
front.on(eventName, function onEvent(...args) {
|
||||
let actor = args[0];
|
||||
if (actors.length !== count) {
|
||||
actors.push(spread ? args : actor);
|
||||
}
|
||||
info(`Got ${actors.length} / ${count} ${eventName} events`);
|
||||
if (actors.length === count) {
|
||||
front.off(eventName, onEvent);
|
||||
resolve(actors);
|
||||
}
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function get(front, eventName) { return getN(front, eventName, 1); }
|
||||
|
@ -236,19 +233,20 @@ function getNSpread(front, eventName, count) { return getN(front, eventName, cou
|
|||
* nodes and edges.
|
||||
*/
|
||||
function waitForGraphRendered(front, nodeCount, edgeCount, paramEdgeCount) {
|
||||
let deferred = Promise.defer();
|
||||
let eventName = front.EVENTS.UI_GRAPH_RENDERED;
|
||||
info(`Wait for graph rendered with ${nodeCount} nodes, ${edgeCount} edges`);
|
||||
front.on(eventName, function onGraphRendered(_, nodes, edges, pEdges) {
|
||||
let paramEdgesDone = paramEdgeCount != null ? paramEdgeCount === pEdges : true;
|
||||
info(`Got graph rendered with ${nodes} / ${nodeCount} nodes, ` +
|
||||
`${edges} / ${edgeCount} edges`);
|
||||
if (nodes === nodeCount && edges === edgeCount && paramEdgesDone) {
|
||||
front.off(eventName, onGraphRendered);
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
front.on(eventName, function onGraphRendered(_, nodes, edges, pEdges) {
|
||||
let paramEdgesDone = paramEdgeCount != null ? paramEdgeCount === pEdges : true;
|
||||
info(`Got graph rendered with ${nodes} / ${nodeCount} nodes, ` +
|
||||
`${edges} / ${edgeCount} edges`);
|
||||
if (nodes === nodeCount && edges === edgeCount && paramEdgesDone) {
|
||||
front.off(eventName, onGraphRendered);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkVariableView(view, index, hash, description = "") {
|
||||
|
@ -290,39 +288,38 @@ function checkVariableView(view, index, hash, description = "") {
|
|||
}
|
||||
|
||||
function modifyVariableView(win, view, index, prop, value) {
|
||||
let deferred = Promise.defer();
|
||||
let scope = view.getScopeAtIndex(index);
|
||||
let aVar = scope.get(prop);
|
||||
scope.expand();
|
||||
|
||||
win.on(win.EVENTS.UI_SET_PARAM, handleSetting);
|
||||
win.on(win.EVENTS.UI_SET_PARAM_ERROR, handleSetting);
|
||||
return new Promise((resolve, reject) => {
|
||||
win.on(win.EVENTS.UI_SET_PARAM, handleSetting);
|
||||
win.on(win.EVENTS.UI_SET_PARAM_ERROR, handleSetting);
|
||||
|
||||
// Focus and select the variable to begin editing
|
||||
win.focus();
|
||||
aVar.focus();
|
||||
EventUtils.sendKey("RETURN", win);
|
||||
|
||||
// Must wait for the scope DOM to be available to receive
|
||||
// events
|
||||
executeSoon(() => {
|
||||
info("Setting " + value + " for " + prop + "....");
|
||||
for (let c of (value + "")) {
|
||||
EventUtils.synthesizeKey(c, {}, win);
|
||||
}
|
||||
// Focus and select the variable to begin editing
|
||||
win.focus();
|
||||
aVar.focus();
|
||||
EventUtils.sendKey("RETURN", win);
|
||||
|
||||
// Must wait for the scope DOM to be available to receive
|
||||
// events
|
||||
executeSoon(() => {
|
||||
info("Setting " + value + " for " + prop + "....");
|
||||
for (let c of (value + "")) {
|
||||
EventUtils.synthesizeKey(c, {}, win);
|
||||
}
|
||||
EventUtils.sendKey("RETURN", win);
|
||||
});
|
||||
|
||||
function handleSetting(eventName) {
|
||||
win.off(win.EVENTS.UI_SET_PARAM, handleSetting);
|
||||
win.off(win.EVENTS.UI_SET_PARAM_ERROR, handleSetting);
|
||||
if (eventName === win.EVENTS.UI_SET_PARAM)
|
||||
resolve();
|
||||
if (eventName === win.EVENTS.UI_SET_PARAM_ERROR)
|
||||
reject();
|
||||
}
|
||||
});
|
||||
|
||||
function handleSetting(eventName) {
|
||||
win.off(win.EVENTS.UI_SET_PARAM, handleSetting);
|
||||
win.off(win.EVENTS.UI_SET_PARAM_ERROR, handleSetting);
|
||||
if (eventName === win.EVENTS.UI_SET_PARAM)
|
||||
deferred.resolve();
|
||||
if (eventName === win.EVENTS.UI_SET_PARAM_ERROR)
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function findGraphEdge(win, source, target, param) {
|
||||
|
@ -360,10 +357,10 @@ function isVisible(element) {
|
|||
* Used in debugging, returns a promise that resolves in `n` milliseconds.
|
||||
*/
|
||||
function wait(n) {
|
||||
let { promise, resolve } = Promise.defer();
|
||||
setTimeout(resolve, n);
|
||||
info("Waiting " + n / 1000 + " seconds.");
|
||||
return promise;
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(resolve, n);
|
||||
info("Waiting " + n / 1000 + " seconds.");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -372,7 +369,6 @@ function wait(n) {
|
|||
* the tabs have rendered, completing all RDP requests for the node.
|
||||
*/
|
||||
function clickGraphNode(panelWin, el, waitForToggle = false) {
|
||||
let { promise, resolve } = Promise.defer();
|
||||
let promises = [
|
||||
once(panelWin, panelWin.EVENTS.UI_INSPECTOR_NODE_SET),
|
||||
once(panelWin, panelWin.EVENTS.UI_PROPERTIES_TAB_RENDERED),
|
||||
|
@ -482,26 +478,24 @@ function waitForInspectorRender(panelWin, EVENTS) {
|
|||
* in potentially a different process.
|
||||
*/
|
||||
function evalInDebuggee(script) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
if (!mm) {
|
||||
throw new Error("`loadFrameScripts()` must be called when using MessageManager.");
|
||||
}
|
||||
|
||||
let id = generateUUID().toString();
|
||||
mm.sendAsyncMessage("devtools:test:eval", { script: script, id: id });
|
||||
mm.addMessageListener("devtools:test:eval:response", handler);
|
||||
return new Promise((resolve, reject) => {
|
||||
let id = generateUUID().toString();
|
||||
mm.sendAsyncMessage("devtools:test:eval", { script: script, id: id });
|
||||
mm.addMessageListener("devtools:test:eval:response", handler);
|
||||
|
||||
function handler({ data }) {
|
||||
if (id !== data.id) {
|
||||
return;
|
||||
function handler({ data }) {
|
||||
if (id !== data.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
mm.removeMessageListener("devtools:test:eval:response", handler);
|
||||
resolve(data.value);
|
||||
}
|
||||
|
||||
mm.removeMessageListener("devtools:test:eval:response", handler);
|
||||
deferred.resolve(data.value);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,10 +13,12 @@
|
|||
#include "mozilla/AnimationPerformanceWarning.h"
|
||||
#include "mozilla/AnimationTarget.h"
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/LayerAnimationInfo.h"
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "mozilla/RestyleManagerInlines.h"
|
||||
#include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "mozilla/StyleAnimationValue.h"
|
||||
#include "mozilla/TypeTraits.h" // For Forward<>
|
||||
|
@ -131,13 +133,6 @@ FindAnimationsForCompositor(const nsIFrame* aFrame,
|
|||
return false;
|
||||
}
|
||||
|
||||
// FIXME: Bug 1334036: stylo: Implement off-main-thread animations.
|
||||
if (aFrame->StyleContext()->StyleSource().IsServoComputedValues()) {
|
||||
NS_WARNING("stylo: return false in FindAnimationsForCompositor because "
|
||||
"haven't supported compositor-driven animations yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
// First check for newly-started transform animations that should be
|
||||
// synchronized with geometric animations. We need to do this before any
|
||||
// other early returns (the one above is ok) since we can only check this
|
||||
|
@ -172,7 +167,12 @@ FindAnimationsForCompositor(const nsIFrame* aFrame,
|
|||
Maybe<NonOwningAnimationTarget> pseudoElement =
|
||||
EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
|
||||
if (pseudoElement) {
|
||||
EffectCompositor::MaybeUpdateCascadeResults(pseudoElement->mElement,
|
||||
StyleBackendType backend =
|
||||
aFrame->StyleContext()->StyleSource().IsServoComputedValues()
|
||||
? StyleBackendType::Servo
|
||||
: StyleBackendType::Gecko;
|
||||
EffectCompositor::MaybeUpdateCascadeResults(backend,
|
||||
pseudoElement->mElement,
|
||||
pseudoElement->mPseudoType,
|
||||
aFrame->StyleContext());
|
||||
}
|
||||
|
@ -281,9 +281,6 @@ EffectCompositor::RequestRestyle(dom::Element* aElement,
|
|||
}
|
||||
|
||||
if (aRestyleType == RestyleType::Layer) {
|
||||
// FIXME: Bug 1334036: we call RequestRestyle for both stylo and gecko,
|
||||
// so we should make sure we use mAnimationGecneration properly on OMTA.
|
||||
// Prompt layers to re-sync their animations.
|
||||
mPresContext->RestyleManager()->IncrementAnimationGeneration();
|
||||
EffectSet* effectSet =
|
||||
EffectSet::GetEffectSet(aElement, aPseudoType);
|
||||
|
@ -315,7 +312,7 @@ EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
|
|||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"Restyle request during restyling should be requested only on "
|
||||
"the main-thread. e.g. after the parallel traversal");
|
||||
if (ServoStyleSet::IsInServoTraversal()) {
|
||||
if (ServoStyleSet::IsInServoTraversal() || mIsInPreTraverse) {
|
||||
MOZ_ASSERT(hint == eRestyle_CSSAnimations ||
|
||||
hint == eRestyle_CSSTransitions);
|
||||
|
||||
|
@ -385,7 +382,9 @@ EffectCompositor::MaybeUpdateAnimationRule(dom::Element* aElement,
|
|||
{
|
||||
// First update cascade results since that may cause some elements to
|
||||
// be marked as needing a restyle.
|
||||
MaybeUpdateCascadeResults(aElement, aPseudoType, aStyleContext);
|
||||
MaybeUpdateCascadeResults(StyleBackendType::Gecko,
|
||||
aElement, aPseudoType,
|
||||
aStyleContext);
|
||||
|
||||
auto& elementsToRestyle = mElementsToRestyle[aCascadeLevel];
|
||||
PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
|
||||
|
@ -586,7 +585,8 @@ EffectCompositor::AddStyleUpdatesTo(RestyleTracker& aTracker)
|
|||
}
|
||||
|
||||
for (auto& pseudoElem : elementsToRestyle) {
|
||||
MaybeUpdateCascadeResults(pseudoElem.mElement,
|
||||
MaybeUpdateCascadeResults(StyleBackendType::Gecko,
|
||||
pseudoElem.mElement,
|
||||
pseudoElem.mPseudoType,
|
||||
nullptr);
|
||||
|
||||
|
@ -647,7 +647,8 @@ EffectCompositor::ClearIsRunningOnCompositor(const nsIFrame *aFrame,
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
EffectCompositor::MaybeUpdateCascadeResults(Element* aElement,
|
||||
EffectCompositor::MaybeUpdateCascadeResults(StyleBackendType aBackendType,
|
||||
Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
|
@ -656,50 +657,12 @@ EffectCompositor::MaybeUpdateCascadeResults(Element* aElement,
|
|||
return;
|
||||
}
|
||||
|
||||
nsStyleContext* styleContext = aStyleContext;
|
||||
if (!styleContext) {
|
||||
dom::Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
|
||||
if (elementToRestyle) {
|
||||
nsIFrame* frame = elementToRestyle->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
styleContext = frame->StyleContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateCascadeResults(*effects, aElement, aPseudoType, styleContext);
|
||||
UpdateCascadeResults(aBackendType, *effects, aElement, aPseudoType,
|
||||
aStyleContext);
|
||||
|
||||
MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
EffectCompositor::MaybeUpdateCascadeResults(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
|
||||
MOZ_ASSERT(effects);
|
||||
if (!effects->CascadeNeedsUpdate()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Implement the rule node traversal for stylo in Bug 1334036.
|
||||
UpdateCascadeResults(*effects, aElement, aPseudoType, nullptr);
|
||||
|
||||
MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
EffectCompositor::UpdateCascadeResults(Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
|
||||
if (!effects) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateCascadeResults(*effects, aElement, aPseudoType, aStyleContext);
|
||||
}
|
||||
|
||||
/* static */ Maybe<NonOwningAnimationTarget>
|
||||
EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame)
|
||||
{
|
||||
|
@ -777,12 +740,35 @@ EffectCompositor::ComposeAnimationRule(dom::Element* aElement,
|
|||
"EffectSet should not change while composing style");
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
EffectCompositor::GetOverriddenProperties(nsStyleContext* aStyleContext,
|
||||
/* static */ nsCSSPropertyIDSet
|
||||
EffectCompositor::GetOverriddenProperties(StyleBackendType aBackendType,
|
||||
EffectSet& aEffectSet,
|
||||
nsCSSPropertyIDSet&
|
||||
aPropertiesOverridden)
|
||||
Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext)
|
||||
{
|
||||
MOZ_ASSERT(aBackendType != StyleBackendType::Servo || aElement,
|
||||
"Should have an element to get style data from if we are using"
|
||||
" the Servo backend");
|
||||
|
||||
nsCSSPropertyIDSet result;
|
||||
|
||||
Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
|
||||
if (aBackendType == StyleBackendType::Gecko && !aStyleContext) {
|
||||
if (elementToRestyle) {
|
||||
nsIFrame* frame = elementToRestyle->GetPrimaryFrame();
|
||||
if (frame) {
|
||||
aStyleContext = frame->StyleContext();
|
||||
}
|
||||
}
|
||||
|
||||
if (!aStyleContext) {
|
||||
return result;
|
||||
}
|
||||
} else if (aBackendType == StyleBackendType::Servo && !elementToRestyle) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack;
|
||||
{
|
||||
nsCSSPropertyIDSet propertiesToTrackAsSet;
|
||||
|
@ -804,16 +790,31 @@ EffectCompositor::GetOverriddenProperties(nsStyleContext* aStyleContext,
|
|||
}
|
||||
|
||||
if (propertiesToTrack.IsEmpty()) {
|
||||
return;
|
||||
return result;
|
||||
}
|
||||
|
||||
nsRuleNode::ComputePropertiesOverridingAnimation(propertiesToTrack,
|
||||
aStyleContext,
|
||||
aPropertiesOverridden);
|
||||
switch (aBackendType) {
|
||||
case StyleBackendType::Servo:
|
||||
Servo_GetProperties_Overriding_Animation(elementToRestyle,
|
||||
&propertiesToTrack,
|
||||
&result);
|
||||
break;
|
||||
case StyleBackendType::Gecko:
|
||||
nsRuleNode::ComputePropertiesOverridingAnimation(propertiesToTrack,
|
||||
aStyleContext,
|
||||
result);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unsupported style backend");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
|
||||
EffectCompositor::UpdateCascadeResults(StyleBackendType aBackendType,
|
||||
EffectSet& aEffectSet,
|
||||
Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext)
|
||||
|
@ -837,14 +838,11 @@ EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
|
|||
// We only do this for properties that we can animate on the compositor
|
||||
// since we will apply other properties on the main thread where the usual
|
||||
// cascade applies.
|
||||
nsCSSPropertyIDSet overriddenProperties;
|
||||
if (aStyleContext) {
|
||||
// FIXME: Bug 1334036 (OMTA) will implement a FFI to get the properties
|
||||
// overriding animation.
|
||||
MOZ_ASSERT(!aStyleContext->StyleSource().IsServoComputedValues(),
|
||||
"stylo: Not support get properties overriding animation yet.");
|
||||
GetOverriddenProperties(aStyleContext, aEffectSet, overriddenProperties);
|
||||
}
|
||||
nsCSSPropertyIDSet overriddenProperties =
|
||||
GetOverriddenProperties(aBackendType,
|
||||
aEffectSet,
|
||||
aElement, aPseudoType,
|
||||
aStyleContext);
|
||||
|
||||
// Returns a bitset the represents which properties from
|
||||
// LayerAnimationInfo::sRecords are present in |aPropertySet|.
|
||||
|
@ -949,35 +947,92 @@ EffectCompositor::SetPerformanceWarning(
|
|||
}
|
||||
|
||||
bool
|
||||
EffectCompositor::PreTraverse()
|
||||
EffectCompositor::PreTraverse(AnimationRestyleType aRestyleType)
|
||||
{
|
||||
return PreTraverseInSubtree(nullptr);
|
||||
return PreTraverseInSubtree(nullptr, aRestyleType);
|
||||
}
|
||||
|
||||
bool
|
||||
EffectCompositor::PreTraverseInSubtree(Element* aRoot)
|
||||
EffectCompositor::PreTraverseInSubtree(Element* aRoot,
|
||||
AnimationRestyleType aRestyleType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
|
||||
|
||||
AutoRestore<bool> guard(mIsInPreTraverse);
|
||||
mIsInPreTraverse = true;
|
||||
|
||||
// We need to force flush all throttled animations if we also have
|
||||
// non-animation restyles (since we'll want the up-to-date animation style
|
||||
// when we go to process them so we can trigger transitions correctly), and
|
||||
// if we are currently flushing all throttled animation restyles.
|
||||
bool flushThrottledRestyles =
|
||||
(aRoot && aRoot->HasDirtyDescendantsForServo()) ||
|
||||
aRestyleType == AnimationRestyleType::Full;
|
||||
|
||||
using ElementsToRestyleIterType =
|
||||
nsDataHashtable<PseudoElementHashEntry, bool>::Iterator;
|
||||
auto getNeededRestyleTarget = [&](const ElementsToRestyleIterType& aIter)
|
||||
-> NonOwningAnimationTarget {
|
||||
NonOwningAnimationTarget returnTarget;
|
||||
|
||||
// If aIter.Data() is false, the element only requested a throttled
|
||||
// (skippable) restyle, so we can skip it if flushThrottledRestyles is not
|
||||
// true.
|
||||
if (!flushThrottledRestyles && !aIter.Data()) {
|
||||
return returnTarget;
|
||||
}
|
||||
|
||||
const NonOwningAnimationTarget& target = aIter.Key();
|
||||
|
||||
// Ignore restyles that aren't in the flattened tree subtree rooted at
|
||||
// aRoot.
|
||||
if (aRoot &&
|
||||
!nsContentUtils::ContentIsFlattenedTreeDescendantOf(target.mElement,
|
||||
aRoot)) {
|
||||
return returnTarget;
|
||||
}
|
||||
|
||||
returnTarget = target;
|
||||
return returnTarget;
|
||||
};
|
||||
|
||||
bool foundElementsNeedingRestyle = false;
|
||||
|
||||
nsTArray<NonOwningAnimationTarget> elementsWithCascadeUpdates;
|
||||
for (size_t i = 0; i < kCascadeLevelCount; ++i) {
|
||||
CascadeLevel cascadeLevel = CascadeLevel(i);
|
||||
for (auto iter = mElementsToRestyle[cascadeLevel].Iter();
|
||||
!iter.Done(); iter.Next()) {
|
||||
bool postedRestyle = iter.Data();
|
||||
// Ignore throttled restyle.
|
||||
if (!postedRestyle) {
|
||||
auto& elementSet = mElementsToRestyle[cascadeLevel];
|
||||
for (auto iter = elementSet.Iter(); !iter.Done(); iter.Next()) {
|
||||
const NonOwningAnimationTarget& target = getNeededRestyleTarget(iter);
|
||||
if (!target.mElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NonOwningAnimationTarget target = iter.Key();
|
||||
EffectSet* effects = EffectSet::GetEffectSet(target.mElement,
|
||||
target.mPseudoType);
|
||||
if (!effects || !effects->CascadeNeedsUpdate()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore restyles that aren't in the flattened tree subtree rooted at
|
||||
// aRoot.
|
||||
if (aRoot &&
|
||||
!nsContentUtils::ContentIsFlattenedTreeDescendantOf(target.mElement,
|
||||
aRoot)) {
|
||||
elementsWithCascadeUpdates.AppendElement(target);
|
||||
}
|
||||
}
|
||||
|
||||
for (const NonOwningAnimationTarget& target: elementsWithCascadeUpdates) {
|
||||
MaybeUpdateCascadeResults(StyleBackendType::Servo,
|
||||
target.mElement,
|
||||
target.mPseudoType,
|
||||
nullptr);
|
||||
}
|
||||
elementsWithCascadeUpdates.Clear();
|
||||
|
||||
for (size_t i = 0; i < kCascadeLevelCount; ++i) {
|
||||
CascadeLevel cascadeLevel = CascadeLevel(i);
|
||||
auto& elementSet = mElementsToRestyle[cascadeLevel];
|
||||
for (auto iter = elementSet.Iter(); !iter.Done(); iter.Next()) {
|
||||
const NonOwningAnimationTarget& target = getNeededRestyleTarget(iter);
|
||||
if (!target.mElement) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -993,16 +1048,14 @@ EffectCompositor::PreTraverseInSubtree(Element* aRoot)
|
|||
|
||||
foundElementsNeedingRestyle = true;
|
||||
|
||||
EffectSet* effects =
|
||||
EffectSet::GetEffectSet(target.mElement, target.mPseudoType);
|
||||
EffectSet* effects = EffectSet::GetEffectSet(target.mElement,
|
||||
target.mPseudoType);
|
||||
if (!effects) {
|
||||
// Drop EffectSets that have been destroyed.
|
||||
iter.Remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
MaybeUpdateCascadeResults(target.mElement, target.mPseudoType);
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
effect->GetAnimation()->WillComposeStyle();
|
||||
}
|
||||
|
@ -1029,14 +1082,27 @@ EffectCompositor::PreTraverse(dom::Element* aElement,
|
|||
return found;
|
||||
}
|
||||
|
||||
AutoRestore<bool> guard(mIsInPreTraverse);
|
||||
mIsInPreTraverse = true;
|
||||
|
||||
PseudoElementHashEntry::KeyType key = { aElement, aPseudoType };
|
||||
|
||||
// We need to flush all throttled animation restyles too if we also have
|
||||
// non-animation restyles (since we'll want the up-to-date animation style
|
||||
// when we go to process them so we can trigger transitions correctly).
|
||||
Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType);
|
||||
bool flushThrottledRestyles = elementToRestyle &&
|
||||
elementToRestyle->HasDirtyDescendantsForServo();
|
||||
|
||||
for (size_t i = 0; i < kCascadeLevelCount; ++i) {
|
||||
CascadeLevel cascadeLevel = CascadeLevel(i);
|
||||
auto& elementSet = mElementsToRestyle[cascadeLevel];
|
||||
|
||||
if (!elementSet.Get(key)) {
|
||||
// Ignore throttled restyle and no restyle request.
|
||||
// Skip if we don't have a restyle, or if we only have a throttled
|
||||
// (skippable) restyle and we're not required to flush throttled restyles.
|
||||
bool hasUnthrottledRestyle = false;
|
||||
if (!elementSet.Get(key, &hasUnthrottledRestyle) ||
|
||||
(!flushThrottledRestyles && !hasUnthrottledRestyle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1048,7 +1114,9 @@ EffectCompositor::PreTraverse(dom::Element* aElement,
|
|||
|
||||
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
|
||||
if (effects) {
|
||||
MaybeUpdateCascadeResults(aElement, aPseudoType);
|
||||
MaybeUpdateCascadeResults(StyleBackendType::Servo,
|
||||
aElement, aPseudoType,
|
||||
nullptr);
|
||||
|
||||
for (KeyframeEffectReadOnly* effect : *effects) {
|
||||
effect->GetAnimation()->WillComposeStyle();
|
||||
|
|
|
@ -192,35 +192,22 @@ public:
|
|||
// but only if we have marked the cascade as needing an update due a
|
||||
// the change in the set of effects or a change in one of the effects'
|
||||
// "in effect" state.
|
||||
// |aStyleContext| may be nullptr in which case we will use the
|
||||
// nsStyleContext of the primary frame of the specified (pseudo-)element.
|
||||
//
|
||||
// When |aBackendType| is StyleBackendType::Gecko, |aStyleContext| is used to
|
||||
// find overridden properties. If it is nullptr, the nsStyleContext of the
|
||||
// primary frame of the specified (pseudo-)element, if available, is used.
|
||||
//
|
||||
// When |aBackendType| is StyleBackendType::Servo, we fetch the rule node
|
||||
// from the |aElement| (i.e. |aStyleContext| is ignored).
|
||||
//
|
||||
// This method does NOT detect if other styles that apply above the
|
||||
// animation level of the cascade have changed.
|
||||
static void
|
||||
MaybeUpdateCascadeResults(dom::Element* aElement,
|
||||
MaybeUpdateCascadeResults(StyleBackendType aBackendType,
|
||||
dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext);
|
||||
|
||||
// Variant of MaybeUpdateCascadeResults for the Servo backend.
|
||||
// The Servo backend doesn't use an nsStyleContext to get the rule node
|
||||
// to traverse the style tree to find !important rules and instead
|
||||
// gets the rule node from |aElement|.
|
||||
static void
|
||||
MaybeUpdateCascadeResults(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
// Update the mPropertiesWithImportantRules and
|
||||
// mPropertiesForAnimationsLevel members of the corresponding EffectSet.
|
||||
//
|
||||
// This can be expensive so we should only call it if styles that apply
|
||||
// above the animation level of the cascade might have changed. For all
|
||||
// other cases we should call MaybeUpdateCascadeResults.
|
||||
static void
|
||||
UpdateCascadeResults(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext);
|
||||
|
||||
// Helper to fetch the corresponding element and pseudo-type from a frame.
|
||||
//
|
||||
// For frames corresponding to pseudo-elements, the returned element is the
|
||||
|
@ -240,18 +227,27 @@ public:
|
|||
nsCSSPropertyID aProperty,
|
||||
const AnimationPerformanceWarning& aWarning);
|
||||
|
||||
// The type which represents what kind of animation restyle we want.
|
||||
enum class AnimationRestyleType {
|
||||
Throttled, // Restyle elements that have posted animation restyles.
|
||||
Full // Restyle all elements with animations (i.e. even if the
|
||||
// animations are throttled).
|
||||
};
|
||||
|
||||
// Do a bunch of stuff that we should avoid doing during the parallel
|
||||
// traversal (e.g. changing member variables) for all elements that we expect
|
||||
// to restyle on the next traversal.
|
||||
//
|
||||
// Returns true if there are elements needing a restyle for animation.
|
||||
bool PreTraverse();
|
||||
bool PreTraverse(AnimationRestyleType aRestyleType);
|
||||
|
||||
// Similar to the above but only for the (pseudo-)element.
|
||||
bool PreTraverse(dom::Element* aElement, CSSPseudoElementType aPseudoType);
|
||||
|
||||
// Similar to the above but for all elements in the subtree rooted
|
||||
// at aElement.
|
||||
bool PreTraverseInSubtree(dom::Element* aElement);
|
||||
bool PreTraverseInSubtree(dom::Element* aElement,
|
||||
AnimationRestyleType aRestyleType);
|
||||
|
||||
private:
|
||||
~EffectCompositor() = default;
|
||||
|
@ -268,14 +264,36 @@ private:
|
|||
|
||||
// Get the properties in |aEffectSet| that we are able to animate on the
|
||||
// compositor but which are also specified at a higher level in the cascade
|
||||
// than the animations level in |aStyleContext|.
|
||||
static void
|
||||
GetOverriddenProperties(nsStyleContext* aStyleContext,
|
||||
// than the animations level.
|
||||
//
|
||||
// When |aBackendType| is StyleBackendType::Gecko, we determine which
|
||||
// properties are specified using the provided |aStyleContext| and
|
||||
// |aElement| and |aPseudoType| are ignored. If |aStyleContext| is nullptr,
|
||||
// we automatically look up the style context of primary frame of the
|
||||
// (pseudo-)element.
|
||||
//
|
||||
// When |aBackendType| is StyleBackendType::Servo, we use the |StrongRuleNode|
|
||||
// stored on the (pseudo-)element indicated by |aElement| and |aPseudoType|.
|
||||
static nsCSSPropertyIDSet
|
||||
GetOverriddenProperties(StyleBackendType aBackendType,
|
||||
EffectSet& aEffectSet,
|
||||
nsCSSPropertyIDSet& aPropertiesOverridden);
|
||||
dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext);
|
||||
|
||||
// Update the mPropertiesWithImportantRules and
|
||||
// mPropertiesForAnimationsLevel members of the given EffectSet.
|
||||
//
|
||||
// This can be expensive so we should only call it if styles that apply
|
||||
// above the animation level of the cascade might have changed. For all
|
||||
// other cases we should call MaybeUpdateCascadeResults.
|
||||
//
|
||||
// As with MaybeUpdateCascadeResults, |aStyleContext| is only used
|
||||
// when |aBackendType| is StyleBackendType::Gecko. When |aBackendType| is
|
||||
// StyleBackendType::Servo, it is ignored.
|
||||
static void
|
||||
UpdateCascadeResults(EffectSet& aEffectSet,
|
||||
UpdateCascadeResults(StyleBackendType aBackendType,
|
||||
EffectSet& aEffectSet,
|
||||
dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsStyleContext* aStyleContext);
|
||||
|
@ -293,6 +311,8 @@ private:
|
|||
nsDataHashtable<PseudoElementHashEntry, bool>>
|
||||
mElementsToRestyle;
|
||||
|
||||
bool mIsInPreTraverse = false;
|
||||
|
||||
class AnimationStyleRuleProcessor final : public nsIStyleRuleProcessor
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -427,7 +427,7 @@ KeyframeEffectReadOnly::GetUnderlyingStyle(
|
|||
// If we are composing with composite operation that is not 'replace'
|
||||
// and we have not composed style for the property yet, we have to get
|
||||
// the base style for the property.
|
||||
result = BaseStyle(aProperty);
|
||||
result = BaseStyle(aProperty).mGecko;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1297,7 +1297,8 @@ KeyframeEffectReadOnly::GetKeyframes(JSContext*& aCx,
|
|||
// handle null nsCSSValues for longhand properties.
|
||||
DebugOnly<bool> uncomputeResult =
|
||||
StyleAnimationValue::UncomputeValue(
|
||||
propertyValue.mProperty, Move(BaseStyle(propertyValue.mProperty)),
|
||||
propertyValue.mProperty,
|
||||
Move(BaseStyle(propertyValue.mProperty).mGecko),
|
||||
cssValue);
|
||||
|
||||
MOZ_ASSERT(uncomputeResult,
|
||||
|
@ -1848,7 +1849,7 @@ KeyframeEffectReadOnly::ContainsAnimatedScale(const nsIFrame* aFrame) const
|
|||
continue;
|
||||
}
|
||||
|
||||
StyleAnimationValue baseStyle = BaseStyle(prop.mProperty);
|
||||
AnimationValue baseStyle = BaseStyle(prop.mProperty);
|
||||
if (baseStyle.IsNull()) {
|
||||
// If we failed to get the base style, we consider it has scale value
|
||||
// here just to be safe.
|
||||
|
|
|
@ -279,10 +279,18 @@ public:
|
|||
// |aFrame| is used for calculation of scale values.
|
||||
bool ContainsAnimatedScale(const nsIFrame* aFrame) const;
|
||||
|
||||
StyleAnimationValue BaseStyle(nsCSSPropertyID aProperty) const
|
||||
AnimationValue BaseStyle(nsCSSPropertyID aProperty) const
|
||||
{
|
||||
StyleAnimationValue result;
|
||||
DebugOnly<bool> hasProperty = mBaseStyleValues.Get(aProperty, &result);
|
||||
AnimationValue result;
|
||||
bool hasProperty = false;
|
||||
if (mDocument->IsStyledByServo()) {
|
||||
// We cannot use getters_AddRefs on RawServoAnimationValue because it is
|
||||
// an incomplete type, so Get() doesn't work. Instead, use GetWeak, and
|
||||
// then assign the raw pointer to a RefPtr.
|
||||
result.mServo = mBaseStyleValuesForServo.GetWeak(aProperty, &hasProperty);
|
||||
} else {
|
||||
hasProperty = mBaseStyleValues.Get(aProperty, &result.mGecko);
|
||||
}
|
||||
MOZ_ASSERT(hasProperty || result.IsNull());
|
||||
return result;
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -327,6 +327,10 @@ GeolocationInsecureRequestIsForbidden=A Geolocation request can only be fulfille
|
|||
LargeAllocationNonWin32=This page would be loaded in a new process due to a Large-Allocation header, however Large-Allocation process creation is disabled on non-Win32 platforms.
|
||||
# LOCALIZATION NOTE: Do not translate URL.createObjectURL(MediaStream).
|
||||
URLCreateObjectURL_MediaStream=URL.createObjectURL(MediaStream) is deprecated and will be removed soon.
|
||||
# LOCALIZATION NOTE: Do not translate MozAutoGainControl or autoGainControl.
|
||||
MozAutoGainControlWarning=mozAutoGainControl is deprecated. Use autoGainControl instead.
|
||||
# LOCALIZATION NOTE: Do not translate mozNoiseSuppression or noiseSuppression.
|
||||
MozNoiseSuppressionWarning=mozNoiseSuppression is deprecated. Use noiseSuppression instead.
|
||||
# LOCALIZATION NOTE: Do not translate xml:base.
|
||||
XMLBaseAttributeWarning=Use of xml:base attribute is deprecated and will be removed soon. Please remove any use of it.
|
||||
# LOCALIZATION NOTE: %S is the tag name of the element that starts the loop
|
||||
|
|
|
@ -2234,6 +2234,14 @@ MediaManager::GetUserMedia(nsPIDOMWindowInner* aWindow,
|
|||
|
||||
if (c.mAudio.IsMediaTrackConstraints()) {
|
||||
auto& ac = c.mAudio.GetAsMediaTrackConstraints();
|
||||
MediaConstraintsHelper::ConvertOldWithWarning(ac.mMozAutoGainControl,
|
||||
ac.mAutoGainControl,
|
||||
"MozAutoGainControlWarning",
|
||||
aWindow);
|
||||
MediaConstraintsHelper::ConvertOldWithWarning(ac.mMozNoiseSuppression,
|
||||
ac.mNoiseSuppression,
|
||||
"MozNoiseSuppressionWarning",
|
||||
aWindow);
|
||||
audioType = StringToEnum(dom::MediaSourceEnumValues::strings,
|
||||
ac.mMediaSource,
|
||||
MediaSourceEnum::Other);
|
||||
|
@ -3775,10 +3783,11 @@ SourceListener::CapturingBrowser() const
|
|||
}
|
||||
|
||||
already_AddRefed<PledgeVoid>
|
||||
SourceListener::ApplyConstraintsToTrack(nsPIDOMWindowInner* aWindow,
|
||||
TrackID aTrackID,
|
||||
const dom::MediaTrackConstraints& aConstraints,
|
||||
dom::CallerType aCallerType)
|
||||
SourceListener::ApplyConstraintsToTrack(
|
||||
nsPIDOMWindowInner* aWindow,
|
||||
TrackID aTrackID,
|
||||
const MediaTrackConstraints& aConstraintsPassedIn,
|
||||
dom::CallerType aCallerType)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RefPtr<PledgeVoid> p = new PledgeVoid();
|
||||
|
@ -3797,6 +3806,16 @@ SourceListener::ApplyConstraintsToTrack(nsPIDOMWindowInner* aWindow,
|
|||
p->Resolve(false);
|
||||
return p.forget();
|
||||
}
|
||||
MediaTrackConstraints c(aConstraintsPassedIn); // use a modifiable copy
|
||||
|
||||
MediaConstraintsHelper::ConvertOldWithWarning(c.mMozAutoGainControl,
|
||||
c.mAutoGainControl,
|
||||
"MozAutoGainControlWarning",
|
||||
aWindow);
|
||||
MediaConstraintsHelper::ConvertOldWithWarning(c.mMozNoiseSuppression,
|
||||
c.mNoiseSuppression,
|
||||
"MozNoiseSuppressionWarning",
|
||||
aWindow);
|
||||
|
||||
RefPtr<MediaManager> mgr = MediaManager::GetInstance();
|
||||
uint32_t id = mgr->mOutstandingVoidPledges.Append(*p);
|
||||
|
@ -3805,27 +3824,27 @@ SourceListener::ApplyConstraintsToTrack(nsPIDOMWindowInner* aWindow,
|
|||
|
||||
MediaManager::PostTask(NewTaskFrom([id, windowId,
|
||||
audioDevice, videoDevice,
|
||||
aConstraints, isChrome]() mutable {
|
||||
c, isChrome]() mutable {
|
||||
MOZ_ASSERT(MediaManager::IsInMediaThread());
|
||||
RefPtr<MediaManager> mgr = MediaManager::GetInstance();
|
||||
const char* badConstraint = nullptr;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (audioDevice) {
|
||||
rv = audioDevice->Restart(aConstraints, mgr->mPrefs, &badConstraint);
|
||||
rv = audioDevice->Restart(c, mgr->mPrefs, &badConstraint);
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE && !badConstraint) {
|
||||
nsTArray<RefPtr<AudioDevice>> audios;
|
||||
audios.AppendElement(audioDevice);
|
||||
badConstraint = MediaConstraintsHelper::SelectSettings(
|
||||
NormalizedConstraints(aConstraints), audios, isChrome);
|
||||
NormalizedConstraints(c), audios, isChrome);
|
||||
}
|
||||
} else {
|
||||
rv = videoDevice->Restart(aConstraints, mgr->mPrefs, &badConstraint);
|
||||
rv = videoDevice->Restart(c, mgr->mPrefs, &badConstraint);
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE && !badConstraint) {
|
||||
nsTArray<RefPtr<VideoDevice>> videos;
|
||||
videos.AppendElement(videoDevice);
|
||||
badConstraint = MediaConstraintsHelper::SelectSettings(
|
||||
NormalizedConstraints(aConstraints), videos, isChrome);
|
||||
NormalizedConstraints(c), videos, isChrome);
|
||||
}
|
||||
}
|
||||
NS_DispatchToMainThread(NewRunnableFrom([id, windowId, rv,
|
||||
|
|
|
@ -74,9 +74,10 @@ var tests = [
|
|||
|
||||
var mustSupport = [
|
||||
'width', 'height', 'frameRate', 'facingMode', 'deviceId',
|
||||
'echoCancellation', 'noiseSuppression', 'autoGainControl',
|
||||
|
||||
// Yet to add:
|
||||
// 'aspectRatio', 'frameRate', 'volume', 'sampleRate', 'sampleSize',
|
||||
// 'latency', 'groupId'
|
||||
// 'aspectRatio', 'volume', 'sampleRate', 'sampleSize', 'latency', 'groupId'
|
||||
|
||||
// http://fluffy.github.io/w3c-screen-share/#screen-based-video-constraints
|
||||
// OBE by http://w3c.github.io/mediacapture-screen-share
|
||||
|
@ -85,8 +86,6 @@ var mustSupport = [
|
|||
// Experimental https://bugzilla.mozilla.org/show_bug.cgi?id=1131568#c3
|
||||
'browserWindow', 'scrollWithPage',
|
||||
'viewportOffsetX', 'viewportOffsetY', 'viewportWidth', 'viewportHeight',
|
||||
|
||||
'echoCancellation', 'mozNoiseSuppression', 'mozAutoGainControl'
|
||||
];
|
||||
|
||||
var mustFailWith = (msg, reason, constraint, f) =>
|
||||
|
|
|
@ -215,8 +215,8 @@ MediaEngineWebRTCMicrophoneSource::MediaEngineWebRTCMicrophoneSource(
|
|||
mDeviceUUID.Assign(uuid);
|
||||
mListener = new mozilla::WebRTCAudioDataListener(this);
|
||||
mSettings.mEchoCancellation.Construct(0);
|
||||
mSettings.mMozAutoGainControl.Construct(0);
|
||||
mSettings.mMozNoiseSuppression.Construct(0);
|
||||
mSettings.mAutoGainControl.Construct(0);
|
||||
mSettings.mNoiseSuppression.Construct(0);
|
||||
// We'll init lazily as needed
|
||||
}
|
||||
|
||||
|
@ -286,8 +286,8 @@ MediaEngineWebRTCMicrophoneSource::UpdateSingleSource(
|
|||
|
||||
MediaEnginePrefs prefs = aPrefs;
|
||||
prefs.mAecOn = c.mEchoCancellation.Get(prefs.mAecOn);
|
||||
prefs.mAgcOn = c.mMozAutoGainControl.Get(prefs.mAgcOn);
|
||||
prefs.mNoiseOn = c.mMozNoiseSuppression.Get(prefs.mNoiseOn);
|
||||
prefs.mAgcOn = c.mAutoGainControl.Get(prefs.mAgcOn);
|
||||
prefs.mNoiseOn = c.mNoiseSuppression.Get(prefs.mNoiseOn);
|
||||
|
||||
LOG(("Audio config: aec: %d, agc: %d, noise: %d, delay: %d",
|
||||
prefs.mAecOn ? prefs.mAec : -1,
|
||||
|
@ -382,8 +382,8 @@ MediaEngineWebRTCMicrophoneSource::SetLastPrefs(
|
|||
|
||||
NS_DispatchToMainThread(media::NewRunnableFrom([that, aPrefs]() mutable {
|
||||
that->mSettings.mEchoCancellation.Value() = aPrefs.mAecOn;
|
||||
that->mSettings.mMozAutoGainControl.Value() = aPrefs.mAgcOn;
|
||||
that->mSettings.mMozNoiseSuppression.Value() = aPrefs.mNoiseOn;
|
||||
that->mSettings.mAutoGainControl.Value() = aPrefs.mAgcOn;
|
||||
that->mSettings.mNoiseSuppression.Value() = aPrefs.mNoiseOn;
|
||||
return NS_OK;
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaTrackConstraints.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "mozilla/dom/MediaStreamTrackBinding.h"
|
||||
|
||||
#include <limits>
|
||||
|
@ -371,11 +372,11 @@ FlattenedConstraints::FlattenedConstraints(const NormalizedConstraints& aOther)
|
|||
if (mEchoCancellation.Intersects(set.mEchoCancellation)) {
|
||||
mEchoCancellation.Intersect(set.mEchoCancellation);
|
||||
}
|
||||
if (mMozNoiseSuppression.Intersects(set.mMozNoiseSuppression)) {
|
||||
mMozNoiseSuppression.Intersect(set.mMozNoiseSuppression);
|
||||
if (mNoiseSuppression.Intersects(set.mNoiseSuppression)) {
|
||||
mNoiseSuppression.Intersect(set.mNoiseSuppression);
|
||||
}
|
||||
if (mMozAutoGainControl.Intersects(set.mMozAutoGainControl)) {
|
||||
mMozAutoGainControl.Intersect(set.mMozAutoGainControl);
|
||||
if (mAutoGainControl.Intersects(set.mAutoGainControl)) {
|
||||
mAutoGainControl.Intersect(set.mAutoGainControl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -469,4 +470,31 @@ MediaConstraintsHelper::FindBadConstraint(
|
|||
return FindBadConstraint(aConstraints, devices);
|
||||
}
|
||||
|
||||
void
|
||||
MediaConstraintsHelper::ConvertOldWithWarning(
|
||||
const dom::OwningBooleanOrConstrainBooleanParameters& old,
|
||||
dom::OwningBooleanOrConstrainBooleanParameters& to,
|
||||
const char* aMessageName,
|
||||
nsPIDOMWindowInner* aWindow) {
|
||||
if ((old.IsBoolean() ||
|
||||
old.GetAsConstrainBooleanParameters().mExact.WasPassed() ||
|
||||
old.GetAsConstrainBooleanParameters().mIdeal.WasPassed()) &&
|
||||
!(to.IsBoolean() ||
|
||||
to.GetAsConstrainBooleanParameters().mExact.WasPassed() ||
|
||||
to.GetAsConstrainBooleanParameters().mIdeal.WasPassed())) {
|
||||
nsCOMPtr<nsIDocument> doc = aWindow->GetDoc();
|
||||
if (doc) {
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("DOM"), doc,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
aMessageName);
|
||||
}
|
||||
if (old.IsBoolean()) {
|
||||
to.SetAsBoolean() = old.GetAsBoolean();
|
||||
} else {
|
||||
to.SetAsConstrainBooleanParameters() = old.GetAsConstrainBooleanParameters();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ public:
|
|||
BooleanRange mScrollWithPage;
|
||||
StringRange mDeviceId;
|
||||
LongRange mViewportOffsetX, mViewportOffsetY, mViewportWidth, mViewportHeight;
|
||||
BooleanRange mEchoCancellation, mMozNoiseSuppression, mMozAutoGainControl;
|
||||
BooleanRange mEchoCancellation, mNoiseSuppression, mAutoGainControl;
|
||||
private:
|
||||
typedef NormalizedConstraintSet T;
|
||||
public:
|
||||
|
@ -254,11 +254,11 @@ public:
|
|||
aOther.mViewportHeight, advanced, aList)
|
||||
, mEchoCancellation(&T::mEchoCancellation, "echoCancellation",
|
||||
aOther.mEchoCancellation, advanced, aList)
|
||||
, mMozNoiseSuppression(&T::mMozNoiseSuppression, "mozNoiseSuppression",
|
||||
aOther.mMozNoiseSuppression,
|
||||
advanced, aList)
|
||||
, mMozAutoGainControl(&T::mMozAutoGainControl, "mozAutoGainControl",
|
||||
aOther.mMozAutoGainControl, advanced, aList) {}
|
||||
, mNoiseSuppression(&T::mNoiseSuppression, "noiseSuppression",
|
||||
aOther.mNoiseSuppression,
|
||||
advanced, aList)
|
||||
, mAutoGainControl(&T::mAutoGainControl, "autoGainControl",
|
||||
aOther.mAutoGainControl, advanced, aList) {}
|
||||
};
|
||||
|
||||
template<> bool NormalizedConstraintSet::Range<bool>::Merge(const Range& aOther);
|
||||
|
@ -442,6 +442,15 @@ public:
|
|||
FindBadConstraint(const NormalizedConstraints& aConstraints,
|
||||
const MediaEngineSourceType& aMediaEngineSource,
|
||||
const nsString& aDeviceId);
|
||||
|
||||
// Warn on and convert use of deprecated constraints to new ones
|
||||
|
||||
static void
|
||||
ConvertOldWithWarning(
|
||||
const dom::OwningBooleanOrConstrainBooleanParameters& old,
|
||||
dom::OwningBooleanOrConstrainBooleanParameters& to,
|
||||
const char* aMessageName,
|
||||
nsPIDOMWindowInner* aWindow);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -55,6 +55,10 @@ dictionary MediaTrackConstraintSet {
|
|||
ConstrainLong viewportWidth;
|
||||
ConstrainLong viewportHeight;
|
||||
ConstrainBoolean echoCancellation;
|
||||
ConstrainBoolean noiseSuppression;
|
||||
ConstrainBoolean autoGainControl;
|
||||
|
||||
// Deprecated with warnings:
|
||||
ConstrainBoolean mozNoiseSuppression;
|
||||
ConstrainBoolean mozAutoGainControl;
|
||||
};
|
||||
|
|
|
@ -14,8 +14,8 @@ dictionary MediaTrackSettings {
|
|||
DOMString facingMode;
|
||||
DOMString deviceId;
|
||||
boolean echoCancellation;
|
||||
boolean mozNoiseSuppression;
|
||||
boolean mozAutoGainControl;
|
||||
boolean noiseSuppression;
|
||||
boolean autoGainControl;
|
||||
|
||||
// Mozilla-specific extensions:
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ dictionary MediaTrackSupportedConstraints {
|
|||
boolean sampleRate; // to be supported
|
||||
boolean sampleSize; // to be supported
|
||||
boolean echoCancellation = true;
|
||||
boolean mozNoiseSuppression = true;
|
||||
boolean mozAutoGainControl = true;
|
||||
boolean noiseSuppression = true;
|
||||
boolean autoGainControl = true;
|
||||
boolean latency; // to be supported
|
||||
boolean deviceId = true;
|
||||
boolean groupId; // to be supported
|
||||
|
|
|
@ -70,6 +70,7 @@ nsLanguageAtomService::GetLanguageGroup(nsIAtom* aLanguage,
|
|||
retVal = mLangToGroup.GetWeak(aLanguage);
|
||||
|
||||
if (!retVal) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should not append to cache off main thread");
|
||||
nsCOMPtr<nsIAtom> uncached = GetUncachedLanguageGroup(aLanguage, aError);
|
||||
retVal = uncached.get();
|
||||
|
||||
|
|
|
@ -207,7 +207,10 @@ function treatAsSafeArgument(entry, varName, csuName)
|
|||
["Gecko_DestroyShapeSource", "aShape", null],
|
||||
["Gecko_StyleShapeSource_SetURLValue", "aShape", null],
|
||||
["Gecko_nsFont_InitSystem", "aDest", null],
|
||||
["Gecko_nsStyleFont_FixupNoneGeneric", "aFont", null],
|
||||
["Gecko_StyleTransition_SetUnsupportedProperty", "aTransition", null],
|
||||
["Gecko_AddPropertyToSet", "aPropertySet", null],
|
||||
["Gecko_CalcStyleDifference", "aAnyStyleChanged", null],
|
||||
];
|
||||
for (var [entryMatch, varMatch, csuMatch] of whitelist) {
|
||||
assert(entryMatch || varMatch || csuMatch);
|
||||
|
@ -373,6 +376,7 @@ function ignoreContents(entry)
|
|||
"Gecko_GetOrCreateFinalKeyframe",
|
||||
"Gecko_NewStyleQuoteValues",
|
||||
"Gecko_NewCSSValueSharedList",
|
||||
"Gecko_NewNoneTransform",
|
||||
"Gecko_NewGridTemplateAreasValue",
|
||||
/nsCSSValue::SetCalcValue/,
|
||||
/CSSValueSerializeCalcOps::Append/,
|
||||
|
@ -391,6 +395,7 @@ function ignoreContents(entry)
|
|||
/LookAndFeel::GetColor/,
|
||||
"Gecko_CopyStyleContentsFrom",
|
||||
"Gecko_CSSValue_SetAbsoluteLength",
|
||||
/nsCSSPropertyIDSet::AddProperty/,
|
||||
];
|
||||
if (entry.matches(whitelist))
|
||||
return true;
|
||||
|
|
|
@ -42,7 +42,7 @@ if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']:
|
|||
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-shadow']
|
||||
CXXFLAGS += ['-Wno-shadow', '-fno-strict-aliasing']
|
||||
|
||||
# This is intended as a temporary workaround to enable VS2015.
|
||||
if CONFIG['_MSC_VER']:
|
||||
|
|
|
@ -145,7 +145,7 @@ USE_LIBS += [
|
|||
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-shadow', '-Werror=format']
|
||||
CXXFLAGS += ['-Wno-shadow', '-Werror=format', '-fno-strict-aliasing']
|
||||
|
||||
# This is intended as a temporary workaround to enable VS2015.
|
||||
if CONFIG['_MSC_VER']:
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "AnimationCommon.h" // For GetLayerAnimationInfo
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
|
@ -50,7 +49,6 @@
|
|||
#include "nsSMILAnimationController.h"
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "ChildIterator.h"
|
||||
#include "Layers.h"
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
#include "nsAccessibilityService.h"
|
||||
|
@ -1226,54 +1224,6 @@ ElementRestyler::ElementRestyler(nsPresContext* aPresContext,
|
|||
"an ancestor?");
|
||||
}
|
||||
|
||||
void
|
||||
ElementRestyler::AddLayerChangesForAnimation()
|
||||
{
|
||||
uint64_t frameGeneration =
|
||||
GeckoRestyleManager::GetAnimationGenerationForFrame(mFrame);
|
||||
|
||||
nsChangeHint hint = nsChangeHint(0);
|
||||
for (const LayerAnimationInfo::Record& layerInfo :
|
||||
LayerAnimationInfo::sRecords) {
|
||||
Layer* layer =
|
||||
FrameLayerBuilder::GetDedicatedLayer(mFrame, layerInfo.mLayerType);
|
||||
if (layer && frameGeneration != layer->GetAnimationGeneration()) {
|
||||
// If we have a transform layer but don't have any transform style, we
|
||||
// probably just removed the transform but haven't destroyed the layer
|
||||
// yet. In this case we will add the appropriate change hint
|
||||
// (nsChangeHint_UpdateContainingBlock) when we compare style contexts
|
||||
// so we can skip adding any change hint here. (If we *were* to add
|
||||
// nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
|
||||
// complain that we're updating a transform layer without a transform).
|
||||
if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
|
||||
!mFrame->StyleDisplay()->HasTransformStyle()) {
|
||||
continue;
|
||||
}
|
||||
hint |= layerInfo.mChangeHint;
|
||||
}
|
||||
|
||||
// We consider it's the first paint for the frame if we have an animation
|
||||
// for the property but have no layer.
|
||||
// Note that in case of animations which has properties preventing running
|
||||
// on the compositor, e.g., width or height, corresponding layer is not
|
||||
// created at all, but even in such cases, we normally set valid change
|
||||
// hint for such animations in each tick, i.e. restyles in each tick. As
|
||||
// a result, we usually do restyles for such animations in every tick on
|
||||
// the main-thread. The only animations which will be affected by this
|
||||
// explicit change hint are animations that have opacity/transform but did
|
||||
// not have those properies just before. e.g, setting transform by
|
||||
// setKeyframes or changing target element from other target which prevents
|
||||
// running on the compositor, etc.
|
||||
if (!layer &&
|
||||
nsLayoutUtils::HasEffectiveAnimation(mFrame, layerInfo.mProperty)) {
|
||||
hint |= layerInfo.mChangeHint;
|
||||
}
|
||||
}
|
||||
if (hint) {
|
||||
mChangeList->AppendChange(mFrame, mContent, hint);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
|
||||
nsStyleContext* aNewContext,
|
||||
|
@ -1879,7 +1829,7 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
|||
// Some changes to animations don't affect the computed style and yet still
|
||||
// require the layer to be updated. For example, pausing an animation via
|
||||
// the Web Animations API won't affect an element's style but still
|
||||
// requires us to pull the animation off the layer.
|
||||
// requires to update the animation on the layer.
|
||||
//
|
||||
// Although we only expect this code path to be called when computed style
|
||||
// is not changing, we can sometimes reach this at the end of a transition
|
||||
|
@ -1887,7 +1837,7 @@ ElementRestyler::Restyle(nsRestyleHint aRestyleHint)
|
|||
// AddLayerChangesForAnimation checks if mFrame has a transform style or not,
|
||||
// we need to call it *after* calling RestyleSelf to ensure the animated
|
||||
// transform has been removed first.
|
||||
AddLayerChangesForAnimation();
|
||||
RestyleManager::AddLayerChangesForAnimation(mFrame, mContent, *mChangeList);
|
||||
|
||||
if (haveMoreContinuations && hintToRestore) {
|
||||
// If we have more continuations with different style (e.g., because
|
||||
|
@ -3170,7 +3120,7 @@ ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint,
|
|||
{
|
||||
nsIContent* undisplayedParent = aUndisplayedParent;
|
||||
UndisplayedNode* undisplayed = aUndisplayed;
|
||||
TreeMatchContext::AutoAncestorPusher pusher(mTreeMatchContext);
|
||||
TreeMatchContext::AutoAncestorPusher pusher(&mTreeMatchContext);
|
||||
if (undisplayed) {
|
||||
pusher.PushAncestorAndStyleScope(undisplayedParent);
|
||||
}
|
||||
|
@ -3190,7 +3140,7 @@ ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint,
|
|||
// children element. Push the children element as an ancestor here because it does
|
||||
// not have a frame and would not otherwise be pushed as an ancestor.
|
||||
nsIContent* parent = undisplayed->mContent->GetParent();
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(&mTreeMatchContext);
|
||||
if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
|
||||
insertionPointPusher.PushAncestorAndStyleScope(parent);
|
||||
}
|
||||
|
@ -3398,7 +3348,7 @@ ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
|
|||
LOG_RESTYLE("RestyleContentChildren");
|
||||
|
||||
nsIFrame::ChildListIterator lists(aParent);
|
||||
TreeMatchContext::AutoAncestorPusher ancestorPusher(mTreeMatchContext);
|
||||
TreeMatchContext::AutoAncestorPusher ancestorPusher(&mTreeMatchContext);
|
||||
if (!lists.IsDone()) {
|
||||
ancestorPusher.PushAncestorAndStyleScope(mContent);
|
||||
}
|
||||
|
@ -3416,7 +3366,7 @@ ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
|
|||
// Check if the frame has a content because |child| may be a
|
||||
// nsPageFrame that does not have a content.
|
||||
nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(&mTreeMatchContext);
|
||||
if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
|
||||
insertionPointPusher.PushAncestorAndStyleScope(parent);
|
||||
}
|
||||
|
|
|
@ -584,8 +584,6 @@ private:
|
|||
/**
|
||||
* Helpers for Restyle().
|
||||
*/
|
||||
void AddLayerChangesForAnimation();
|
||||
|
||||
bool MoveStyleContextsForContentChildren(nsIFrame* aParent,
|
||||
nsStyleContext* aOldContext,
|
||||
nsTArray<nsStyleContext*>& aContextsToMove);
|
||||
|
|
|
@ -6946,10 +6946,7 @@ FlushThrottledStyles(nsIDocument *aDocument, void *aData)
|
|||
if (shell && shell->IsVisible()) {
|
||||
nsPresContext* presContext = shell->GetPresContext();
|
||||
if (presContext) {
|
||||
if (presContext->RestyleManager()->IsGecko()) {
|
||||
// XXX stylo: ServoRestyleManager doesn't support animations yet.
|
||||
presContext->RestyleManager()->AsGecko()->UpdateOnlyAnimationStyles();
|
||||
}
|
||||
presContext->RestyleManager()->UpdateOnlyAnimationStyles();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
|
||||
#include "mozilla/RestyleManager.h"
|
||||
#include "mozilla/RestyleManagerInlines.h"
|
||||
|
||||
#include "Layers.h"
|
||||
#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
|
||||
#include "mozilla/StyleSetHandleInlines.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIPresShellInlines.h"
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
RestyleManager::RestyleManager(StyleBackendType aType,
|
||||
|
@ -1771,6 +1775,62 @@ RestyleManager::IncrementAnimationGeneration()
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
RestyleManager::AddLayerChangesForAnimation(nsIFrame* aFrame,
|
||||
nsIContent* aContent,
|
||||
nsStyleChangeList&
|
||||
aChangeListToProcess)
|
||||
{
|
||||
if (!aFrame || !aContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t frameGeneration =
|
||||
RestyleManager::GetAnimationGenerationForFrame(aFrame);
|
||||
|
||||
nsChangeHint hint = nsChangeHint(0);
|
||||
for (const LayerAnimationInfo::Record& layerInfo :
|
||||
LayerAnimationInfo::sRecords) {
|
||||
layers::Layer* layer =
|
||||
FrameLayerBuilder::GetDedicatedLayer(aFrame, layerInfo.mLayerType);
|
||||
if (layer && frameGeneration != layer->GetAnimationGeneration()) {
|
||||
// If we have a transform layer but don't have any transform style, we
|
||||
// probably just removed the transform but haven't destroyed the layer
|
||||
// yet. In this case we will add the appropriate change hint
|
||||
// (nsChangeHint_UpdateContainingBlock) when we compare style contexts
|
||||
// so we can skip adding any change hint here. (If we *were* to add
|
||||
// nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
|
||||
// complain that we're updating a transform layer without a transform).
|
||||
if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
|
||||
!aFrame->StyleDisplay()->HasTransformStyle()) {
|
||||
continue;
|
||||
}
|
||||
hint |= layerInfo.mChangeHint;
|
||||
}
|
||||
|
||||
// We consider it's the first paint for the frame if we have an animation
|
||||
// for the property but have no layer.
|
||||
// Note that in case of animations which has properties preventing running
|
||||
// on the compositor, e.g., width or height, corresponding layer is not
|
||||
// created at all, but even in such cases, we normally set valid change
|
||||
// hint for such animations in each tick, i.e. restyles in each tick. As
|
||||
// a result, we usually do restyles for such animations in every tick on
|
||||
// the main-thread. The only animations which will be affected by this
|
||||
// explicit change hint are animations that have opacity/transform but did
|
||||
// not have those properies just before. e.g, setting transform by
|
||||
// setKeyframes or changing target element from other target which prevents
|
||||
// running on the compositor, etc.
|
||||
if (!layer &&
|
||||
nsLayoutUtils::HasEffectiveAnimation(aFrame, layerInfo.mProperty)) {
|
||||
hint |= layerInfo.mChangeHint;
|
||||
}
|
||||
}
|
||||
|
||||
if (hint) {
|
||||
aChangeListToProcess.AppendChange(aFrame, aContent, hint);
|
||||
}
|
||||
}
|
||||
|
||||
RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
|
||||
RestyleManager* aRestyleManager)
|
||||
: mRestyleManager(aRestyleManager)
|
||||
|
|
|
@ -180,6 +180,8 @@ public:
|
|||
const nsAttrValue* aOldValue);
|
||||
inline nsresult ReparentStyleContext(nsIFrame* aFrame);
|
||||
|
||||
inline void UpdateOnlyAnimationStyles();
|
||||
|
||||
// Get a counter that increments on every style change, that we use to
|
||||
// track whether off-main-thread animations are up-to-date.
|
||||
uint64_t GetAnimationGeneration() const { return mAnimationGeneration; }
|
||||
|
@ -194,6 +196,11 @@ public:
|
|||
// such as changes made through the Web Animations API.
|
||||
void IncrementAnimationGeneration();
|
||||
|
||||
static void AddLayerChangesForAnimation(nsIFrame* aFrame,
|
||||
nsIContent* aContent,
|
||||
nsStyleChangeList&
|
||||
aChangeListToProcess);
|
||||
|
||||
protected:
|
||||
RestyleManager(StyleBackendType aType, nsPresContext* aPresContext);
|
||||
|
||||
|
|
|
@ -79,6 +79,12 @@ RestyleManager::ReparentStyleContext(nsIFrame* aFrame)
|
|||
MOZ_STYLO_FORWARD(ReparentStyleContext, (aFrame));
|
||||
}
|
||||
|
||||
void
|
||||
RestyleManager::UpdateOnlyAnimationStyles()
|
||||
{
|
||||
MOZ_STYLO_FORWARD(UpdateOnlyAnimationStyles, ());
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_RestyleManagerInlines_h
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/ChildIterator.h"
|
||||
#include "mozilla/dom/ElementInlines.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsBulletFrame.h"
|
||||
#include "nsPlaceholderFrame.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
@ -203,6 +206,76 @@ struct ServoRestyleManager::TextPostTraversalState
|
|||
}
|
||||
};
|
||||
|
||||
static void
|
||||
UpdateBlockFramePseudoElements(nsBlockFrame* aFrame,
|
||||
ServoStyleSet& aStyleSet,
|
||||
nsStyleChangeList& aChangeList)
|
||||
{
|
||||
if (nsBulletFrame* bullet = aFrame->GetBullet()) {
|
||||
RefPtr<nsStyleContext> newContext =
|
||||
aStyleSet.ResolvePseudoElementStyle(
|
||||
aFrame->GetContent()->AsElement(),
|
||||
bullet->StyleContext()->GetPseudoType(),
|
||||
aFrame->StyleContext(),
|
||||
/* aPseudoElement = */ nullptr);
|
||||
|
||||
aFrame->UpdateStyleOfOwnedChildFrame(bullet, newContext, aChangeList);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateBackdropIfNeeded(nsIFrame* aFrame,
|
||||
ServoStyleSet& aStyleSet,
|
||||
nsStyleChangeList& aChangeList)
|
||||
{
|
||||
const nsStyleDisplay* display = aFrame->StyleContext()->StyleDisplay();
|
||||
if (display->mTopLayer != NS_STYLE_TOP_LAYER_TOP) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Elements in the top layer are guaranteed to have absolute or fixed
|
||||
// position per https://fullscreen.spec.whatwg.org/#new-stacking-layer.
|
||||
MOZ_ASSERT(display->IsAbsolutelyPositionedStyle());
|
||||
|
||||
nsIFrame* backdropPlaceholder =
|
||||
aFrame->GetChildList(nsIFrame::kBackdropList).FirstChild();
|
||||
if (!backdropPlaceholder) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(backdropPlaceholder->IsPlaceholderFrame());
|
||||
nsIFrame* backdropFrame =
|
||||
nsPlaceholderFrame::GetRealFrameForPlaceholder(backdropPlaceholder);
|
||||
MOZ_ASSERT(backdropFrame->IsBackdropFrame());
|
||||
MOZ_ASSERT(backdropFrame->StyleContext()->GetPseudoType() ==
|
||||
CSSPseudoElementType::backdrop);
|
||||
|
||||
RefPtr<nsStyleContext> newContext =
|
||||
aStyleSet.ResolvePseudoElementStyle(
|
||||
aFrame->GetContent()->AsElement(),
|
||||
CSSPseudoElementType::backdrop,
|
||||
aFrame->StyleContext(),
|
||||
/* aPseudoElement = */ nullptr);
|
||||
|
||||
aFrame->UpdateStyleOfOwnedChildFrame(backdropFrame,
|
||||
newContext,
|
||||
aChangeList);
|
||||
}
|
||||
|
||||
static void
|
||||
UpdateFramePseudoElementStyles(nsIFrame* aFrame,
|
||||
ServoStyleSet& aStyleSet,
|
||||
nsStyleChangeList& aChangeList)
|
||||
{
|
||||
if (aFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
|
||||
UpdateBlockFramePseudoElements(static_cast<nsBlockFrame*>(aFrame),
|
||||
aStyleSet,
|
||||
aChangeList);
|
||||
}
|
||||
|
||||
UpdateBackdropIfNeeded(aFrame, aStyleSet, aChangeList);
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::ProcessPostTraversal(Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
|
@ -314,7 +387,19 @@ ServoRestyleManager::ProcessPostTraversal(Element* aElement,
|
|||
|
||||
if (styleFrame) {
|
||||
styleFrame->UpdateStyleOfOwnedAnonBoxes(*aStyleSet, aChangeList, changeHint);
|
||||
UpdateFramePseudoElementStyles(styleFrame, *aStyleSet, aChangeList);
|
||||
}
|
||||
|
||||
// Some changes to animations don't affect the computed style and yet still
|
||||
// require the layer to be updated. For example, pausing an animation via
|
||||
// the Web Animations API won't affect an element's style but still
|
||||
// requires to update the animation on the layer.
|
||||
//
|
||||
// We can sometimes reach this when the animated style is being removed.
|
||||
// Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
|
||||
// style or not, we need to call it *after* setting |newContext| to
|
||||
// |styleFrame| to ensure the animated transform has been removed first.
|
||||
AddLayerChangesForAnimation(styleFrame, aElement, aChangeList);
|
||||
}
|
||||
|
||||
const bool descendantsNeedFrames =
|
||||
|
@ -429,7 +514,8 @@ ServoRestyleManager::FrameForPseudoElement(const nsIContent* aContent,
|
|||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::ProcessPendingRestyles()
|
||||
ServoRestyleManager::DoProcessPendingRestyles(TraversalRestyleBehavior
|
||||
aRestyleBehavior)
|
||||
{
|
||||
MOZ_ASSERT(PresContext()->Document(), "No document? Pshaw!");
|
||||
MOZ_ASSERT(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
|
||||
|
@ -451,6 +537,8 @@ ServoRestyleManager::ProcessPendingRestyles()
|
|||
|
||||
ServoStyleSet* styleSet = StyleSet();
|
||||
nsIDocument* doc = PresContext()->Document();
|
||||
bool animationOnly = aRestyleBehavior ==
|
||||
TraversalRestyleBehavior::ForAnimationOnly;
|
||||
|
||||
// Ensure the refresh driver is active during traversal to avoid mutating
|
||||
// mActiveTimer and mMostRecentRefresh time.
|
||||
|
@ -461,12 +549,15 @@ ServoRestyleManager::ProcessPendingRestyles()
|
|||
// in a loop because certain rare paths in the frame constructor (like
|
||||
// uninstalling XBL bindings) can trigger additional style validations.
|
||||
mInStyleRefresh = true;
|
||||
if (mHaveNonAnimationRestyles) {
|
||||
if (mHaveNonAnimationRestyles && !animationOnly) {
|
||||
++mAnimationGeneration;
|
||||
}
|
||||
|
||||
while (styleSet->StyleDocument()) {
|
||||
ClearSnapshots();
|
||||
while (animationOnly ? styleSet->StyleDocumentForAnimationOnly()
|
||||
: styleSet->StyleDocument()) {
|
||||
if (!animationOnly) {
|
||||
ClearSnapshots();
|
||||
}
|
||||
|
||||
// Recreate style contexts, and queue up change hints (which also handle
|
||||
// lazy frame construction).
|
||||
|
@ -487,6 +578,14 @@ ServoRestyleManager::ProcessPendingRestyles()
|
|||
ProcessRestyledFrames(currentChanges);
|
||||
MOZ_ASSERT(currentChanges.IsEmpty());
|
||||
for (ReentrantChange& change: newChanges) {
|
||||
if (!(change.mHint & nsChangeHint_ReconstructFrame) &&
|
||||
!change.mContent->GetPrimaryFrame()) {
|
||||
// SVG Elements post change hints without ensuring that the primary
|
||||
// frame will be there after that (see bug 1366142).
|
||||
//
|
||||
// Just ignore those, since we can't really process them.
|
||||
continue;
|
||||
}
|
||||
currentChanges.AppendChange(change.mContent->GetPrimaryFrame(),
|
||||
change.mContent, change.mHint);
|
||||
}
|
||||
|
@ -497,12 +596,14 @@ ServoRestyleManager::ProcessPendingRestyles()
|
|||
IncrementRestyleGeneration();
|
||||
}
|
||||
|
||||
ClearSnapshots();
|
||||
FlushOverflowChangedTracker();
|
||||
|
||||
mHaveNonAnimationRestyles = false;
|
||||
if (!animationOnly) {
|
||||
ClearSnapshots();
|
||||
styleSet->AssertTreeIsClean();
|
||||
mHaveNonAnimationRestyles = false;
|
||||
}
|
||||
mInStyleRefresh = false;
|
||||
styleSet->AssertTreeIsClean();
|
||||
|
||||
// Note: We are in the scope of |animationsWithDestroyedFrame|, so
|
||||
// |mAnimationsWithDestroyedFrame| is still valid.
|
||||
|
@ -510,6 +611,24 @@ ServoRestyleManager::ProcessPendingRestyles()
|
|||
mAnimationsWithDestroyedFrame->StopAnimationsForElementsWithoutFrames();
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::ProcessPendingRestyles()
|
||||
{
|
||||
DoProcessPendingRestyles(TraversalRestyleBehavior::Normal);
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::UpdateOnlyAnimationStyles()
|
||||
{
|
||||
// Bug 1365855: We also need to implement this for SMIL.
|
||||
bool doCSS = PresContext()->EffectCompositor()->HasPendingStyleUpdates();
|
||||
if (!doCSS) {
|
||||
return;
|
||||
}
|
||||
|
||||
DoProcessPendingRestyles(TraversalRestyleBehavior::ForAnimationOnly);
|
||||
}
|
||||
|
||||
void
|
||||
ServoRestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
|
||||
nsIContent* aChild)
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
nsRestyleHint aRestyleHint);
|
||||
void ProcessPendingRestyles();
|
||||
|
||||
void UpdateOnlyAnimationStyles();
|
||||
|
||||
void ContentInserted(nsINode* aContainer, nsIContent* aChild);
|
||||
void ContentAppended(nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent);
|
||||
|
@ -138,6 +140,8 @@ private:
|
|||
void ClearSnapshots();
|
||||
ServoElementSnapshot& SnapshotFor(mozilla::dom::Element* aElement);
|
||||
|
||||
void DoProcessPendingRestyles(TraversalRestyleBehavior aRestyleBehavior);
|
||||
|
||||
// We use a separate data structure from nsStyleChangeList because we need a
|
||||
// frame to create nsStyleChangeList entries, and the primary frame may not be
|
||||
// attached yet.
|
||||
|
|
|
@ -282,11 +282,13 @@ StaticPresData::GetFontPrefsForLangHelper(nsIAtom* aLanguage,
|
|||
}
|
||||
prefs = prefs->mNext;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should not append to cache off main thread");
|
||||
// nothing cached, so go on and fetch the prefs for this lang group:
|
||||
prefs = prefs->mNext = new LangGroupFontPrefs;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should not append to cache off main thread");
|
||||
|
||||
prefs->Initialize(langGroupAtom);
|
||||
|
||||
return prefs;
|
||||
|
|
|
@ -330,6 +330,32 @@ static int32_t FFWC_recursions=0;
|
|||
static int32_t FFWC_nextInFlows=0;
|
||||
#endif
|
||||
|
||||
// Wrapper class to handle stack-construction a TreeMatchContext only if we're
|
||||
// using the Gecko style system.
|
||||
class MOZ_STACK_CLASS TreeMatchContextHolder
|
||||
{
|
||||
public:
|
||||
explicit TreeMatchContextHolder(nsIDocument* aDocument)
|
||||
{
|
||||
if (!aDocument->IsStyledByServo()) {
|
||||
mMaybeTreeMatchContext.emplace(aDocument,
|
||||
TreeMatchContext::ForFrameConstruction);
|
||||
}
|
||||
}
|
||||
|
||||
bool Exists() const { return mMaybeTreeMatchContext.isSome(); }
|
||||
operator TreeMatchContext*() { return mMaybeTreeMatchContext.ptrOr(nullptr); }
|
||||
|
||||
TreeMatchContext* operator ->()
|
||||
{
|
||||
MOZ_ASSERT(mMaybeTreeMatchContext.isSome());
|
||||
return mMaybeTreeMatchContext.ptr();
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe<TreeMatchContext> mMaybeTreeMatchContext;
|
||||
};
|
||||
|
||||
// Returns true if aFrame is an anonymous flex/grid item.
|
||||
static inline bool
|
||||
IsAnonymousFlexOrGridItem(const nsIFrame* aFrame)
|
||||
|
@ -803,26 +829,35 @@ public:
|
|||
|
||||
nsCOMArray<nsIContent> mGeneratedTextNodesWithInitializer;
|
||||
|
||||
TreeMatchContext& mTreeMatchContext;
|
||||
// Selector matching context for. This is null when we're using the Servo style
|
||||
// system.
|
||||
TreeMatchContext* mTreeMatchContext;
|
||||
|
||||
// Constructor
|
||||
// Use the passed-in history state.
|
||||
//
|
||||
// aTreeMatchContext is null when we're using the Servo style system.
|
||||
nsFrameConstructorState(
|
||||
nsIPresShell* aPresShell,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
TreeMatchContext* aTreeMatchContext,
|
||||
nsContainerFrame* aFixedContainingBlock,
|
||||
nsContainerFrame* aAbsoluteContainingBlock,
|
||||
nsContainerFrame* aFloatContainingBlock,
|
||||
already_AddRefed<nsILayoutHistoryState> aHistoryState);
|
||||
// Get the history state from the pres context's pres shell.
|
||||
nsFrameConstructorState(nsIPresShell* aPresShell,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
TreeMatchContext* aTreeMatchContext,
|
||||
nsContainerFrame* aFixedContainingBlock,
|
||||
nsContainerFrame* aAbsoluteContainingBlock,
|
||||
nsContainerFrame* aFloatContainingBlock);
|
||||
|
||||
~nsFrameConstructorState();
|
||||
|
||||
bool HasAncestorFilter()
|
||||
{
|
||||
return mTreeMatchContext && mTreeMatchContext->mAncestorFilter.HasFilter();
|
||||
}
|
||||
|
||||
// Function to push the existing absolute containing block state and
|
||||
// create a new scope. Code that uses this function should get matching
|
||||
// logic in GetAbsoluteContainingBlock.
|
||||
|
@ -972,7 +1007,7 @@ protected:
|
|||
|
||||
nsFrameConstructorState::nsFrameConstructorState(
|
||||
nsIPresShell* aPresShell,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
TreeMatchContext* aTreeMatchContext,
|
||||
nsContainerFrame* aFixedContainingBlock,
|
||||
nsContainerFrame* aAbsoluteContainingBlock,
|
||||
nsContainerFrame* aFloatContainingBlock,
|
||||
|
@ -1012,7 +1047,7 @@ nsFrameConstructorState::nsFrameConstructorState(
|
|||
}
|
||||
|
||||
nsFrameConstructorState::nsFrameConstructorState(nsIPresShell* aPresShell,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
TreeMatchContext* aTreeMatchContext,
|
||||
nsContainerFrame* aFixedContainingBlock,
|
||||
nsContainerFrame* aAbsoluteContainingBlock,
|
||||
nsContainerFrame* aFloatContainingBlock)
|
||||
|
@ -2427,10 +2462,12 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
|||
|
||||
NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
|
||||
|
||||
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContextHolder matchContext(mDocument);
|
||||
// Initialize the ancestor filter with null for now; we'll push
|
||||
// aDocElement once we finish resolving style for it.
|
||||
matchContext.InitAncestors(nullptr);
|
||||
if (matchContext.Exists()) {
|
||||
matchContext->InitAncestors(nullptr);
|
||||
}
|
||||
nsFrameConstructorState state(mPresShell,
|
||||
matchContext,
|
||||
GetAbsoluteContainingBlock(mDocElementContainingBlock, FIXED_POS),
|
||||
|
@ -2876,7 +2913,7 @@ nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
|
|||
RefPtr<nsStyleContext> rootPseudoStyle;
|
||||
// we must create a state because if the scrollbars are GFX it needs the
|
||||
// state to build the scrollbar frames.
|
||||
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContextHolder matchContext(mDocument);
|
||||
nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
|
||||
|
||||
// Start off with the viewport as parent; we'll adjust it as needed.
|
||||
|
@ -3854,8 +3891,12 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
|
|||
nsIContent* parent = content->GetParent();
|
||||
|
||||
// Push display:contents ancestors.
|
||||
AutoDisplayContentsAncestorPusher adcp(aState.mTreeMatchContext,
|
||||
aState.mPresContext, parent);
|
||||
Maybe<AutoDisplayContentsAncestorPusher> adcp;
|
||||
if (aState.mTreeMatchContext) {
|
||||
adcp.emplace(*aState.mTreeMatchContext, aState.mPresContext, parent);
|
||||
} else {
|
||||
MOZ_ASSERT(content->IsStyledByServo());
|
||||
}
|
||||
|
||||
// Get the parent of the content and check if it is a XBL children element.
|
||||
// Push the children element as an ancestor here because it does
|
||||
|
@ -3865,8 +3906,9 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
|
|||
// AutoDisplayContentsAncestorPusher above.)
|
||||
TreeMatchContext::AutoAncestorPusher
|
||||
insertionPointPusher(aState.mTreeMatchContext);
|
||||
if (adcp.IsEmpty() && parent && nsContentUtils::IsContentInsertionPoint(parent)) {
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (adcp.isSome() && adcp->IsEmpty() && parent &&
|
||||
nsContentUtils::IsContentInsertionPoint(parent)) {
|
||||
if (aState.mTreeMatchContext->mAncestorFilter.HasFilter()) {
|
||||
insertionPointPusher.PushAncestorAndStyleScope(parent);
|
||||
} else {
|
||||
insertionPointPusher.PushStyleScope(parent);
|
||||
|
@ -3883,7 +3925,7 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
|
|||
// places.
|
||||
TreeMatchContext::AutoAncestorPusher
|
||||
ancestorPusher(aState.mTreeMatchContext);
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (aState.HasAncestorFilter()) {
|
||||
ancestorPusher.PushAncestorAndStyleScope(content);
|
||||
} else {
|
||||
ancestorPusher.PushStyleScope(content);
|
||||
|
@ -4601,7 +4643,7 @@ nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
|
|||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
if (scrollNAC.Length() > 0) {
|
||||
TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (aState.HasAncestorFilter()) {
|
||||
ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
|
||||
} else {
|
||||
ancestorPusher.PushStyleScope(aContent->AsElement());
|
||||
|
@ -5965,7 +6007,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
|||
}
|
||||
|
||||
TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (aState.HasAncestorFilter()) {
|
||||
ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
|
||||
} else {
|
||||
ancestorPusher.PushStyleScope(aContent->AsElement());
|
||||
|
@ -5992,7 +6034,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
|||
MOZ_ASSERT(parent, "Parent must be non-null because we are iterating children.");
|
||||
TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
|
||||
if (parent != aContent && parent->IsElement()) {
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (aState.HasAncestorFilter()) {
|
||||
ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
|
||||
} else {
|
||||
ancestorPusher.PushStyleScope(parent->AsElement());
|
||||
|
@ -7178,6 +7220,7 @@ nsCSSFrameConstructor::CreateNeededFrames(
|
|||
nsIContent* aContent,
|
||||
TreeMatchContext& aTreeMatchContext)
|
||||
{
|
||||
MOZ_ASSERT(!aContent->IsStyledByServo());
|
||||
NS_ASSERTION(!aContent->HasFlag(NODE_NEEDS_FRAME),
|
||||
"shouldn't get here with a content node that has needs frame bit set");
|
||||
NS_ASSERTION(aContent->HasFlag(NODE_DESCENDANTS_NEED_FRAMES),
|
||||
|
@ -7239,7 +7282,7 @@ nsCSSFrameConstructor::CreateNeededFrames(
|
|||
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
||||
if (child->HasFlag(NODE_DESCENDANTS_NEED_FRAMES)) {
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(
|
||||
aTreeMatchContext);
|
||||
&aTreeMatchContext);
|
||||
|
||||
// Handle stuff like xbl:children.
|
||||
if (child->GetParent() != aContent && child->GetParent()->IsElement()) {
|
||||
|
@ -7247,7 +7290,7 @@ nsCSSFrameConstructor::CreateNeededFrames(
|
|||
child->GetParent()->AsElement());
|
||||
}
|
||||
|
||||
TreeMatchContext::AutoAncestorPusher pusher(aTreeMatchContext);
|
||||
TreeMatchContext::AutoAncestorPusher pusher(&aTreeMatchContext);
|
||||
pusher.PushAncestorAndStyleScope(child);
|
||||
|
||||
CreateNeededFrames(child, aTreeMatchContext);
|
||||
|
@ -7622,13 +7665,12 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
|||
// We use the provided tree match context, or create a new one on the fly
|
||||
// otherwise.
|
||||
Maybe<TreeMatchContext> matchContext;
|
||||
if (!aProvidedTreeMatchContext) {
|
||||
if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
|
||||
matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
matchContext->InitAncestors(aContainer->AsElement());
|
||||
}
|
||||
nsFrameConstructorState state(mPresShell,
|
||||
aProvidedTreeMatchContext
|
||||
? *aProvidedTreeMatchContext : *matchContext,
|
||||
matchContext.ptrOr(aProvidedTreeMatchContext),
|
||||
GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
|
||||
GetAbsoluteContainingBlock(parentFrame, ABS_POS),
|
||||
GetFloatContainingBlock(parentFrame));
|
||||
|
@ -8129,13 +8171,12 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
|||
}
|
||||
|
||||
Maybe<TreeMatchContext> matchContext;
|
||||
if (!aProvidedTreeMatchContext) {
|
||||
if (!aProvidedTreeMatchContext && !aContainer->IsStyledByServo()) {
|
||||
matchContext.emplace(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
matchContext->InitAncestors(aContainer ? aContainer->AsElement() : nullptr);
|
||||
}
|
||||
nsFrameConstructorState state(mPresShell,
|
||||
aProvidedTreeMatchContext
|
||||
? *aProvidedTreeMatchContext : *matchContext,
|
||||
matchContext.ptrOr(aProvidedTreeMatchContext),
|
||||
GetAbsoluteContainingBlock(insertion.mParentFrame, FIXED_POS),
|
||||
GetAbsoluteContainingBlock(insertion.mParentFrame, ABS_POS),
|
||||
GetFloatContainingBlock(insertion.mParentFrame),
|
||||
|
@ -9095,7 +9136,7 @@ nsCSSFrameConstructor::CreateContinuingTableFrame(nsIPresShell* aPresShell,
|
|||
nsTableRowGroupFrame* headerFooterFrame;
|
||||
nsFrameItems childItems;
|
||||
|
||||
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContextHolder matchContext(mDocument);
|
||||
nsFrameConstructorState state(mPresShell,
|
||||
matchContext,
|
||||
GetAbsoluteContainingBlock(newFrame, FIXED_POS),
|
||||
|
@ -9370,7 +9411,7 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
|
|||
// This should not normally be possible (because fixed-pos elements should
|
||||
// be absolute containers) but fixed-pos tables currently aren't abs-pos
|
||||
// containers.
|
||||
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContextHolder matchContext(mDocument);
|
||||
nsFrameConstructorState state(mPresShell,
|
||||
matchContext,
|
||||
aParentFrame,
|
||||
|
@ -10916,8 +10957,12 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
|
|||
"Why is someone creating garbage anonymous content");
|
||||
|
||||
RefPtr<nsStyleContext> styleContext;
|
||||
TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper
|
||||
parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext);
|
||||
Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
|
||||
parentDisplayBasedStyleFixupSkipper;
|
||||
MOZ_ASSERT_IF(!aState.mTreeMatchContext, content->IsStyledByServo());
|
||||
if (aState.mTreeMatchContext) {
|
||||
parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
|
||||
}
|
||||
|
||||
// Make sure we eagerly performed the servo cascade when the anonymous
|
||||
// nodes were created.
|
||||
|
@ -11138,8 +11183,9 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
|
|||
// a flex/grid container frame, not just has display:flex/grid.
|
||||
Maybe<TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper>
|
||||
parentDisplayBasedStyleFixupSkipper;
|
||||
if (!isFlexOrGridContainer) {
|
||||
parentDisplayBasedStyleFixupSkipper.emplace(aState.mTreeMatchContext);
|
||||
MOZ_ASSERT_IF(!aState.mTreeMatchContext, aContent->IsStyledByServo());
|
||||
if (!isFlexOrGridContainer && aState.mTreeMatchContext) {
|
||||
parentDisplayBasedStyleFixupSkipper.emplace(*aState.mTreeMatchContext);
|
||||
}
|
||||
|
||||
InsertionPoint insertion(aFrame, nullptr);
|
||||
|
@ -11157,7 +11203,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
|
|||
if (parent != aContent && parent->IsElement()) {
|
||||
insertion.mContainer = child->GetFlattenedTreeParent();
|
||||
MOZ_ASSERT(insertion.mContainer == GetInsertionPoint(parent, child).mContainer);
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (aState.HasAncestorFilter()) {
|
||||
ancestorPusher.PushAncestorAndStyleScope(parent->AsElement());
|
||||
} else {
|
||||
ancestorPusher.PushStyleScope(parent->AsElement());
|
||||
|
@ -11681,8 +11727,7 @@ nsCSSFrameConstructor::CreateLetterFrame(nsContainerFrame* aBlockFrame,
|
|||
|
||||
NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame),
|
||||
"Containing block is confused");
|
||||
TreeMatchContext matchContext(mDocument,
|
||||
TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContextHolder matchContext(mDocument);
|
||||
nsFrameConstructorState state(mPresShell,
|
||||
matchContext,
|
||||
GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
|
||||
|
@ -12058,7 +12103,7 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
|
|||
// Construct a new frame
|
||||
if (nullptr != aParentFrame) {
|
||||
nsFrameItems frameItems;
|
||||
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContextHolder matchContext(mDocument);
|
||||
nsFrameConstructorState state(mPresShell,
|
||||
matchContext,
|
||||
GetAbsoluteContainingBlock(aParentFrame, FIXED_POS),
|
||||
|
@ -12407,7 +12452,7 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
|
|||
nsIContent* const parentContent = aParentItem.mContent;
|
||||
|
||||
TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (aState.HasAncestorFilter()) {
|
||||
ancestorPusher.PushAncestorAndStyleScope(parentContent->AsElement());
|
||||
} else {
|
||||
ancestorPusher.PushStyleScope(parentContent->AsElement());
|
||||
|
@ -12448,7 +12493,7 @@ nsCSSFrameConstructor::BuildInlineChildItems(nsFrameConstructorState& aState,
|
|||
MOZ_ASSERT(contentParent, "Parent must be non-null because we are iterating children.");
|
||||
TreeMatchContext::AutoAncestorPusher insertionPointPusher(aState.mTreeMatchContext);
|
||||
if (contentParent != parentContent && contentParent->IsElement()) {
|
||||
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
|
||||
if (aState.HasAncestorFilter()) {
|
||||
insertionPointPusher.PushAncestorAndStyleScope(contentParent->AsElement());
|
||||
} else {
|
||||
insertionPointPusher.PushStyleScope(contentParent->AsElement());
|
||||
|
@ -12945,7 +12990,7 @@ nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
|
|||
BeginUpdate();
|
||||
|
||||
nsFrameItems childItems;
|
||||
TreeMatchContext matchContext(mDocument, TreeMatchContext::ForFrameConstruction);
|
||||
TreeMatchContextHolder matchContext(mDocument);
|
||||
nsFrameConstructorState state(mPresShell, matchContext, nullptr, nullptr, nullptr);
|
||||
// We don't have a parent frame with a pending binding constructor here,
|
||||
// so no need to worry about ordering of the kids' constructors with it.
|
||||
|
|
|
@ -633,12 +633,9 @@ GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
|
|||
|
||||
// We need to factor in the scale of the base style if the base style
|
||||
// will be used on the compositor.
|
||||
StyleAnimationValue baseStyle = effect->BaseStyle(prop.mProperty);
|
||||
AnimationValue baseStyle = effect->BaseStyle(prop.mProperty);
|
||||
if (!baseStyle.IsNull()) {
|
||||
// FIXME: Bug 1334036: We need to get the baseStyle for
|
||||
// RawServoAnimationValue.
|
||||
UpdateMinMaxScale(aFrame, AnimationValue(baseStyle),
|
||||
aMinScale, aMaxScale);
|
||||
UpdateMinMaxScale(aFrame, baseStyle, aMinScale, aMaxScale);
|
||||
}
|
||||
|
||||
for (const AnimationPropertySegment& segment : prop.mSegments) {
|
||||
|
|
|
@ -237,6 +237,7 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
|
|||
mExistThrottledUpdates(false),
|
||||
// mImageAnimationMode is initialised below, in constructor body
|
||||
mImageAnimationModePref(imgIContainer::kNormalAnimMode),
|
||||
mFontGroupCacheDirty(true),
|
||||
mInterruptChecksToSkip(0),
|
||||
mElementsRestyled(0),
|
||||
mFramesConstructed(0),
|
||||
|
@ -623,6 +624,7 @@ nsPresContext::GetUserPreferences()
|
|||
mPrefScrollbarSide = Preferences::GetInt("layout.scrollbar.side");
|
||||
|
||||
mLangGroupFontPrefs.Reset();
|
||||
mFontGroupCacheDirty = true;
|
||||
StaticPresData::Get()->ResetCachedFontPrefs();
|
||||
|
||||
// * image animation
|
||||
|
@ -1066,6 +1068,7 @@ nsPresContext::UpdateCharSet(const nsCString& aCharSet)
|
|||
mLanguage = mLangService->GetLocaleLanguage();
|
||||
}
|
||||
mLangGroupFontPrefs.Reset();
|
||||
mFontGroupCacheDirty = true;
|
||||
}
|
||||
|
||||
switch (GET_BIDI_OPTION_TEXTTYPE(GetBidi())) {
|
||||
|
@ -1975,6 +1978,33 @@ void nsPresContext::StopEmulatingMedium()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::ForceCacheLang(nsIAtom *aLanguage)
|
||||
{
|
||||
// force it to be cached
|
||||
GetDefaultFont(kPresContext_DefaultVariableFont_ID, aLanguage);
|
||||
if (!mLanguagesUsed.Contains(aLanguage)) {
|
||||
mLanguagesUsed.PutEntry(aLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::CacheAllLangs()
|
||||
{
|
||||
if (mFontGroupCacheDirty) {
|
||||
nsCOMPtr<nsIAtom> thisLang = nsStyleFont::GetLanguage(this);
|
||||
GetDefaultFont(kPresContext_DefaultVariableFont_ID, thisLang.get());
|
||||
GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsGkAtoms::x_math);
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1362599#c12
|
||||
GetDefaultFont(kPresContext_DefaultVariableFont_ID, nsGkAtoms::Unicode);
|
||||
for (auto iter = mLanguagesUsed.Iter(); !iter.Done(); iter.Next()) {
|
||||
|
||||
GetDefaultFont(kPresContext_DefaultVariableFont_ID, iter.Get()->GetKey());
|
||||
}
|
||||
}
|
||||
mFontGroupCacheDirty = false;
|
||||
}
|
||||
|
||||
void
|
||||
nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint,
|
||||
nsRestyleHint aRestyleHint)
|
||||
|
@ -2311,14 +2341,8 @@ nsPresContext::FlushCounterStyles()
|
|||
PresShell()->NotifyCounterStylesAreDirty();
|
||||
PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW,
|
||||
eRestyle_ForceDescendants);
|
||||
if (mShell->StyleSet()->IsGecko()) {
|
||||
RefreshDriver()->AddPostRefreshObserver(
|
||||
new CounterStyleCleaner(RefreshDriver(), mCounterStyleManager));
|
||||
} else {
|
||||
NS_WARNING("stylo: Pseudo-element ::-moz-list-{number,bullet} are not "
|
||||
"restyled properly, so we cannot clean up retired objects. "
|
||||
"See bug 1364871.");
|
||||
}
|
||||
RefreshDriver()->AddPostRefreshObserver(
|
||||
new CounterStyleCleaner(RefreshDriver(), mCounterStyleManager));
|
||||
}
|
||||
mCounterStylesDirty = false;
|
||||
}
|
||||
|
|
|
@ -373,6 +373,9 @@ public:
|
|||
GetFontPrefsForLang(lang));
|
||||
}
|
||||
|
||||
void ForceCacheLang(nsIAtom *aLanguage);
|
||||
void CacheAllLangs();
|
||||
|
||||
/** Get a cached boolean pref, by its type */
|
||||
// * - initially created for bugs 31816, 20760, 22963
|
||||
bool GetCachedBoolPref(nsPresContext_CachedBoolPrefType aPrefType) const
|
||||
|
@ -1420,6 +1423,9 @@ protected:
|
|||
// link items.
|
||||
LangGroupFontPrefs mLangGroupFontPrefs;
|
||||
|
||||
bool mFontGroupCacheDirty;
|
||||
nsTHashtable<nsRefPtrHashKey<nsIAtom>> mLanguagesUsed;
|
||||
|
||||
nscoord mBorderWidthTable[3];
|
||||
|
||||
uint32_t mInterruptChecksToSkip;
|
||||
|
|
|
@ -10238,17 +10238,32 @@ nsFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
|
|||
RefPtr<nsStyleContext> newContext =
|
||||
aStyleSet.ResolveInheritingAnonymousBoxStyle(pseudo, StyleContext());
|
||||
|
||||
nsChangeHint childHint =
|
||||
UpdateStyleOfOwnedChildFrame(aChildFrame, newContext, aChangeList);
|
||||
|
||||
// Now that we've updated the style on aChildFrame, check whether it itself
|
||||
// has anon boxes to deal with.
|
||||
aChildFrame->UpdateStyleOfOwnedAnonBoxes(aStyleSet, aChangeList, childHint);
|
||||
}
|
||||
|
||||
nsChangeHint
|
||||
nsIFrame::UpdateStyleOfOwnedChildFrame(nsIFrame* aChildFrame,
|
||||
nsStyleContext* aNewStyleContext,
|
||||
nsStyleChangeList& aChangeList)
|
||||
{
|
||||
// Figure out whether we have an actual change. It's important that we do
|
||||
// this, for several reasons:
|
||||
//
|
||||
// 1) Even if all the child's changes are due to properties it inherits from
|
||||
// us, it's possible that no one ever asked us for those style structs and
|
||||
// hence changes to them aren't reflected in aHintForThisFrame at all.
|
||||
// 2) Extensions can add/remove stylesheets that change the styles of
|
||||
// anonymous boxed directly.
|
||||
//
|
||||
// 2) Content can change stylesheets that change the styles of pseudos, and
|
||||
// extensions can add/remove stylesheets that change the styles of
|
||||
// anonymous boxes directly.
|
||||
uint32_t equalStructs, samePointerStructs; // Not used, actually.
|
||||
nsChangeHint childHint = aChildFrame->StyleContext()->CalcStyleDifference(
|
||||
newContext,
|
||||
aNewStyleContext,
|
||||
&equalStructs,
|
||||
&samePointerStructs);
|
||||
if (childHint) {
|
||||
|
@ -10261,12 +10276,10 @@ nsFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
|
|||
}
|
||||
|
||||
for (nsIFrame* kid = aChildFrame; kid; kid = kid->GetNextContinuation()) {
|
||||
kid->SetStyleContext(newContext);
|
||||
kid->SetStyleContext(aNewStyleContext);
|
||||
}
|
||||
|
||||
// Now that we've updated the style on aChildFrame, check whether it itself
|
||||
// has anon boxes to deal with.
|
||||
aChildFrame->UpdateStyleOfOwnedAnonBoxes(aStyleSet, aChangeList, childHint);
|
||||
return childHint;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
|
|
@ -3262,6 +3262,18 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// A helper both for UpdateStyleOfChildAnonBox, and to update frame-backed
|
||||
// pseudo-elements in ServoRestyleManager.
|
||||
//
|
||||
// This gets a style context that will be the new style context for
|
||||
// `aChildFrame`, and takes care of updating it, calling CalcStyleDifference,
|
||||
// and adding to the change list as appropriate.
|
||||
//
|
||||
// Returns the generated change hint for the frame.
|
||||
nsChangeHint UpdateStyleOfOwnedChildFrame(nsIFrame* aChildFrame,
|
||||
nsStyleContext* aNewStyleContext,
|
||||
nsStyleChangeList& aChangeList);
|
||||
|
||||
/**
|
||||
* Hook subclasses can override to actually implement updating of style of
|
||||
* owned anon boxes.
|
||||
|
|
|
@ -566,13 +566,11 @@ AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty,
|
|||
// If the animation is additive or accumulates, we need to pass its base value
|
||||
// to the compositor.
|
||||
|
||||
StyleAnimationValue baseStyle =
|
||||
AnimationValue baseStyle =
|
||||
aAnimation->GetEffect()->AsKeyframeEffect()->BaseStyle(aProperty.mProperty);
|
||||
if (!baseStyle.IsNull()) {
|
||||
// FIXME: Bug 1334036: We need to get the baseValue for
|
||||
// RawServoAnimationValue.
|
||||
SetAnimatable(aProperty.mProperty,
|
||||
AnimationValue(baseStyle),
|
||||
baseStyle,
|
||||
aFrame, refBox,
|
||||
animation->baseStyle());
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
div::after { color: green; content: "Bar"; }
|
||||
</style>
|
||||
<div></div>
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
div::after { color: green }
|
||||
div.foo::after { content: "Bar" }
|
||||
</style>
|
||||
<div></div>
|
||||
<script>
|
||||
onload = function() {
|
||||
document.querySelector('div').classList.add('foo');
|
||||
}
|
||||
</script>
|
|
@ -830,7 +830,7 @@ fuzzy-if(skiaContent,2,21) == 398682-1.html 398682-1-ref.html
|
|||
== 399209-1.html 399209-1-ref.html
|
||||
== 399209-2.html 399209-2-ref.html
|
||||
== 399258-1.html 399258-1-ref.html
|
||||
fails-if(stylo) == 399384-1.html 399384-1-ref.html
|
||||
== 399384-1.html 399384-1-ref.html
|
||||
random-if(gtkWidget) == 399636-standards-css.html 399636-standards-ref.html # bug 429022
|
||||
random-if(gtkWidget) == 399636-standards-html.html 399636-standards-ref.html # bug 429022
|
||||
random-if(gtkWidget) == 399636-quirks-css.html 399636-quirks-ref.html # bug 429022
|
||||
|
@ -1857,7 +1857,7 @@ test-pref(layout.css.grid.enabled,true) == 1053035-1-grid.html 1053035-1-ref.htm
|
|||
== 1062792-1.html 1062792-1-ref.html
|
||||
== 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html
|
||||
test-pref(dom.webcomponents.enabled,true) == 1066554-1.html 1066554-1-ref.html
|
||||
fails-if(stylo) == 1069716-1.html 1069716-1-ref.html
|
||||
== 1069716-1.html 1069716-1-ref.html
|
||||
fails-if(webrender) == 1078262-1.html about:blank
|
||||
test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html
|
||||
== 1081185-1.html 1081185-1-ref.html
|
||||
|
@ -2004,3 +2004,4 @@ fails-if(stylo) == 1348481-3.html 1348481-ref.html
|
|||
== 1364280-2b.html 1364280-2-ref.html
|
||||
== 1364280-2c.html 1364280-2-ref.html
|
||||
== 1364335.html 1364335-ref.html
|
||||
== 1366144.html 1366144-ref.html
|
||||
|
|
|
@ -48,7 +48,7 @@ fails-if(webrender) != transform-floating-point-invalidation.html about:blank
|
|||
fails-if(webrender) != transform-floating-point-invalidation.html?reverse about:blank
|
||||
fails-if(webrender) != nudge-to-integer-invalidation.html about:blank
|
||||
fails-if(webrender) != nudge-to-integer-invalidation.html?reverse about:blank
|
||||
fails-if(webrender) skip-if(stylo) != clipped-animated-transform-1.html about:blank # Bug 1334036 (stylo)
|
||||
fails-if(webrender) skip-if(stylo) != clipped-animated-transform-1.html about:blank # Bug 1352628 (stylo)
|
||||
fails-if(webrender) != paintedlayer-recycling-1.html about:blank
|
||||
fails-if(webrender) != paintedlayer-recycling-2.html about:blank
|
||||
pref(layers.single-tile.enabled,false) fails-if(webrender) != paintedlayer-recycling-3.html about:blank
|
||||
|
|
|
@ -294,8 +294,8 @@ fails-if(stylo) == mathvariant-3.html mathvariant-3-ref.html
|
|||
== mathvariant-4.html mathvariant-4-ref.html
|
||||
== mathvariant-5.html mathvariant-5-ref.html
|
||||
== dtls-1.html dtls-1-ref.html
|
||||
== dtls-2.html dtls-2-ref.html
|
||||
== dtls-3.html dtls-3-ref.html
|
||||
fails-if(stylo) == dtls-2.html dtls-2-ref.html # bug 1366206
|
||||
fails-if(stylo) == dtls-3.html dtls-3-ref.html # bug 1366206
|
||||
== ssty-1.html ssty-1-ref.html
|
||||
== ssty-2.html ssty-2-ref.html
|
||||
== ssty-3.html ssty-3-ref.html
|
||||
|
|
|
@ -214,6 +214,10 @@ SERVO_BINDING_FUNC(Servo_Property_IsAnimatable, bool,
|
|||
nsCSSPropertyID property)
|
||||
SERVO_BINDING_FUNC(Servo_Property_IsDiscreteAnimatable, bool,
|
||||
nsCSSPropertyID property)
|
||||
SERVO_BINDING_FUNC(Servo_GetProperties_Overriding_Animation, void,
|
||||
RawGeckoElementBorrowed,
|
||||
RawGeckoCSSPropertyIDListBorrowed,
|
||||
nsCSSPropertyIDSetBorrowedMut)
|
||||
|
||||
// AnimationValues handling
|
||||
SERVO_BINDING_FUNC(Servo_AnimationValues_Interpolate,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ServoTypes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsStyleAutoArray.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
|
@ -35,6 +36,7 @@ struct PropertyStyleAnimationValuePair;
|
|||
using ComputedKeyframeValues = nsTArray<PropertyStyleAnimationValuePair>;
|
||||
} // namespace mozilla
|
||||
|
||||
class nsCSSPropertyIDSet;
|
||||
class nsCSSValue;
|
||||
struct nsFontFaceRuleContainer;
|
||||
class nsIDocument;
|
||||
|
@ -58,6 +60,7 @@ typedef nsTArray<nsFontFaceRuleContainer> RawGeckoFontFaceRuleList;
|
|||
typedef mozilla::AnimationPropertySegment RawGeckoAnimationPropertySegment;
|
||||
typedef mozilla::ComputedTiming RawGeckoComputedTiming;
|
||||
typedef nsTArray<const RawServoStyleRule*> RawGeckoServoStyleRuleList;
|
||||
typedef nsTArray<nsCSSPropertyID> RawGeckoCSSPropertyIDList;
|
||||
|
||||
// We have these helper types so that we can directly generate
|
||||
// things like &T or Borrowed<T> on the Rust side in the function, providing
|
||||
|
@ -139,6 +142,8 @@ DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoFontFaceRuleList)
|
|||
DECL_BORROWED_REF_TYPE_FOR(RawGeckoAnimationPropertySegment)
|
||||
DECL_BORROWED_REF_TYPE_FOR(RawGeckoComputedTiming)
|
||||
DECL_BORROWED_MUT_REF_TYPE_FOR(RawGeckoServoStyleRuleList)
|
||||
DECL_BORROWED_MUT_REF_TYPE_FOR(nsCSSPropertyIDSet)
|
||||
DECL_BORROWED_REF_TYPE_FOR(RawGeckoCSSPropertyIDList)
|
||||
|
||||
#undef DECL_ARC_REF_TYPE_FOR
|
||||
#undef DECL_OWNED_REF_TYPE_FOR
|
||||
|
|
|
@ -332,20 +332,18 @@ Gecko_GetImplementedPseudo(RawGeckoElementBorrowed aElement)
|
|||
|
||||
nsChangeHint
|
||||
Gecko_CalcStyleDifference(nsStyleContext* aOldStyleContext,
|
||||
ServoComputedValuesBorrowed aComputedValues)
|
||||
ServoComputedValuesBorrowed aComputedValues,
|
||||
bool* aAnyStyleChanged)
|
||||
{
|
||||
MOZ_ASSERT(aOldStyleContext);
|
||||
MOZ_ASSERT(aComputedValues);
|
||||
|
||||
// Eventually, we should compute things out of these flags like
|
||||
// ElementRestyler::RestyleSelf does and pass the result to the caller to
|
||||
// potentially halt traversal. See bug 1289868.
|
||||
uint32_t equalStructs, samePointerStructs;
|
||||
nsChangeHint result =
|
||||
aOldStyleContext->CalcStyleDifference(aComputedValues,
|
||||
&equalStructs,
|
||||
&samePointerStructs);
|
||||
|
||||
*aAnyStyleChanged = equalStructs != NS_STYLE_INHERIT_MASK;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -541,10 +539,22 @@ Gecko_UpdateAnimations(RawGeckoElementBorrowed aElement,
|
|||
UpdateTransitions(const_cast<dom::Element*>(aElement), pseudoType,
|
||||
oldServoValues, servoValues);
|
||||
}
|
||||
|
||||
if (aTasks & UpdateAnimationsTasks::EffectProperties) {
|
||||
presContext->EffectCompositor()->UpdateEffectProperties(
|
||||
servoValues, const_cast<dom::Element*>(aElement), pseudoType);
|
||||
}
|
||||
|
||||
if (aTasks & UpdateAnimationsTasks::CascadeResults) {
|
||||
// This task will be scheduled if we detected any changes to !important
|
||||
// rules. We post a restyle here so that we can update the cascade
|
||||
// results in the pre-traversal of the next restyle.
|
||||
presContext->EffectCompositor()
|
||||
->RequestRestyle(const_cast<Element*>(aElement),
|
||||
pseudoType,
|
||||
EffectCompositor::RestyleType::Standard,
|
||||
EffectCompositor::CascadeLevel::Animations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1732,6 +1742,15 @@ Gecko_NewCSSValueSharedList(uint32_t aLen)
|
|||
return list.forget().take();
|
||||
}
|
||||
|
||||
nsCSSValueSharedList*
|
||||
Gecko_NewNoneTransform()
|
||||
{
|
||||
RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
|
||||
list->mHead = new nsCSSValueList;
|
||||
list->mHead->mValue.SetNoneValue();
|
||||
return list.forget().take();
|
||||
}
|
||||
|
||||
void
|
||||
Gecko_CSSValue_SetAbsoluteLength(nsCSSValueBorrowedMut aCSSValue, nscoord aLen)
|
||||
{
|
||||
|
@ -2112,6 +2131,13 @@ Gecko_CSSFontFaceRule_GetCssText(const nsCSSFontFaceRule* aRule,
|
|||
aRule->GetCssText(*aResult);
|
||||
}
|
||||
|
||||
void
|
||||
Gecko_AddPropertyToSet(nsCSSPropertyIDSetBorrowedMut aPropertySet,
|
||||
nsCSSPropertyID aProperty)
|
||||
{
|
||||
aPropertySet->AddProperty(aProperty);
|
||||
}
|
||||
|
||||
NS_IMPL_FFI_REFCOUNTING(nsCSSFontFaceRule, CSSFontFaceRule);
|
||||
|
||||
nsCSSCounterStyleRule*
|
||||
|
|
|
@ -322,7 +322,8 @@ nsStyleContext* Gecko_GetStyleContext(RawGeckoElementBorrowed element,
|
|||
nsIAtom* aPseudoTagOrNull);
|
||||
mozilla::CSSPseudoElementType Gecko_GetImplementedPseudo(RawGeckoElementBorrowed element);
|
||||
nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
|
||||
ServoComputedValuesBorrowed newstyle);
|
||||
ServoComputedValuesBorrowed newstyle,
|
||||
bool* any_style_changed);
|
||||
nsChangeHint Gecko_HintsHandledForDescendants(nsChangeHint aHint);
|
||||
|
||||
// Get an element snapshot for a given element from the table.
|
||||
|
@ -453,6 +454,7 @@ nsStyleQuoteValues* Gecko_NewStyleQuoteValues(uint32_t len);
|
|||
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleQuoteValues, QuoteValues);
|
||||
|
||||
nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t len);
|
||||
nsCSSValueSharedList* Gecko_NewNoneTransform();
|
||||
|
||||
// Getter for nsCSSValue
|
||||
nsCSSValueBorrowedMut Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut css_value, int32_t index);
|
||||
|
@ -536,6 +538,8 @@ bool Gecko_MatchStringArgPseudo(RawGeckoElementBorrowed element,
|
|||
const char16_t* ident,
|
||||
bool* set_slow_selector);
|
||||
|
||||
void Gecko_AddPropertyToSet(nsCSSPropertyIDSetBorrowedMut, nsCSSPropertyID);
|
||||
|
||||
// Style-struct management.
|
||||
#define STYLE_STRUCT(name, checkdata_cb) \
|
||||
void Gecko_Construct_Default_nsStyle##name( \
|
||||
|
|
|
@ -159,6 +159,7 @@ whitelist-types = [
|
|||
"nsCSSFontFaceRule",
|
||||
"nsCSSKeyword",
|
||||
"nsCSSPropertyID",
|
||||
"nsCSSPropertyIDSet",
|
||||
"nsCSSProps",
|
||||
"nsCSSRect",
|
||||
"nsCSSRect_heap",
|
||||
|
@ -315,6 +316,7 @@ structs-types = [
|
|||
"mozilla::Side",
|
||||
"RawGeckoAnimationPropertySegment",
|
||||
"RawGeckoComputedTiming",
|
||||
"RawGeckoCSSPropertyIDList",
|
||||
"RawGeckoDocument",
|
||||
"RawGeckoElement",
|
||||
"RawGeckoKeyframeList",
|
||||
|
@ -353,6 +355,7 @@ structs-types = [
|
|||
"nsCSSFontFaceRule",
|
||||
"nsCSSKeyword",
|
||||
"nsCSSPropertyID",
|
||||
"nsCSSPropertyIDSet",
|
||||
"nsCSSShadowArray",
|
||||
"nsCSSUnit",
|
||||
"nsCSSValue",
|
||||
|
@ -437,11 +440,13 @@ servo-immutable-borrow-types = [
|
|||
"RawGeckoStyleAnimationList",
|
||||
]
|
||||
servo-borrow-types = [
|
||||
"nsCSSPropertyIDSet",
|
||||
"nsCSSValue",
|
||||
"nsTimingFunction",
|
||||
"RawGeckoAnimationPropertySegment",
|
||||
"RawGeckoAnimationValueList",
|
||||
"RawGeckoComputedTiming",
|
||||
"RawGeckoCSSPropertyIDList",
|
||||
"RawGeckoKeyframeList",
|
||||
"RawGeckoComputedKeyframeValuesList",
|
||||
"RawGeckoFontFaceRuleList",
|
||||
|
|
|
@ -48,6 +48,11 @@ ServoSpecifiedValues::SetIdentStringValue(nsCSSPropertyID aId,
|
|||
{
|
||||
nsCOMPtr<nsIAtom> atom = NS_Atomize(aValue);
|
||||
Servo_DeclarationBlock_SetIdentStringValue(mDecl, aId, atom);
|
||||
if (aId == eCSSProperty__x_lang) {
|
||||
// This forces the lang prefs result to be cached
|
||||
// so that we can access them off main thread during traversal
|
||||
mPresContext->ForceCacheLang(atom);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -267,10 +267,12 @@ ServoStyleSet::PreTraverseSync()
|
|||
mPresContext->Document()->GetUserFontSet();
|
||||
|
||||
UpdateStylistIfNeeded();
|
||||
mPresContext->CacheAllLangs();
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::PreTraverse(Element* aRoot)
|
||||
ServoStyleSet::PreTraverse(Element* aRoot,
|
||||
EffectCompositor::AnimationRestyleType aRestyleType)
|
||||
{
|
||||
PreTraverseSync();
|
||||
|
||||
|
@ -279,12 +281,13 @@ ServoStyleSet::PreTraverse(Element* aRoot)
|
|||
nsSMILAnimationController* smilController =
|
||||
mPresContext->Document()->GetAnimationController();
|
||||
if (aRoot) {
|
||||
mPresContext->EffectCompositor()->PreTraverseInSubtree(aRoot);
|
||||
mPresContext->EffectCompositor()
|
||||
->PreTraverseInSubtree(aRoot, aRestyleType);
|
||||
if (smilController) {
|
||||
smilController->PreTraverseInSubtree(aRoot);
|
||||
}
|
||||
} else {
|
||||
mPresContext->EffectCompositor()->PreTraverse();
|
||||
mPresContext->EffectCompositor()->PreTraverse(aRestyleType);
|
||||
if (smilController) {
|
||||
smilController->PreTraverse();
|
||||
}
|
||||
|
@ -310,10 +313,18 @@ ServoStyleSet::PrepareAndTraverseSubtree(
|
|||
bool isInitial = !aRoot->HasServoData();
|
||||
bool forReconstruct =
|
||||
aRestyleBehavior == TraversalRestyleBehavior::ForReconstruct;
|
||||
bool forAnimationOnly =
|
||||
aRestyleBehavior == TraversalRestyleBehavior::ForAnimationOnly;
|
||||
bool postTraversalRequired = Servo_TraverseSubtree(
|
||||
aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior);
|
||||
MOZ_ASSERT_IF(isInitial || forReconstruct, !postTraversalRequired);
|
||||
|
||||
// Don't need to trigger a second traversal if this restyle only needs
|
||||
// animation-only restyle.
|
||||
if (forAnimationOnly) {
|
||||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
auto root = const_cast<Element*>(aRoot);
|
||||
|
||||
// If there are still animation restyles needed, trigger a second traversal to
|
||||
|
@ -324,8 +335,10 @@ ServoStyleSet::PrepareAndTraverseSubtree(
|
|||
// traversal caused, for example, the font-size to change, the SMIL style
|
||||
// won't be updated until the next tick anyway.
|
||||
EffectCompositor* compositor = mPresContext->EffectCompositor();
|
||||
if (forReconstruct ? compositor->PreTraverseInSubtree(root)
|
||||
: compositor->PreTraverse()) {
|
||||
EffectCompositor::AnimationRestyleType restyleType =
|
||||
EffectCompositor::AnimationRestyleType::Throttled;
|
||||
if (forReconstruct ? compositor->PreTraverseInSubtree(root, restyleType)
|
||||
: compositor->PreTraverse(restyleType)) {
|
||||
if (Servo_TraverseSubtree(
|
||||
aRoot, mRawSet.get(), &snapshots, aRootBehavior, aRestyleBehavior)) {
|
||||
MOZ_ASSERT(!forReconstruct);
|
||||
|
@ -350,18 +363,6 @@ ServoStyleSet::PrepareAndTraverseSubtree(
|
|||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolveStyleFor(Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
LazyComputeBehavior aMayCompute,
|
||||
TreeMatchContext& aTreeMatchContext)
|
||||
{
|
||||
// aTreeMatchContext is used to speed up selector matching,
|
||||
// but if the element already has a ServoComputedValues computed in
|
||||
// advance, then we shouldn't need to use it.
|
||||
return ResolveStyleFor(aElement, aParentContext, aMayCompute);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
|
||||
nsStyleContext* aParentContext)
|
||||
|
@ -765,9 +766,13 @@ ServoStyleSet::AddDocStyleSheet(ServoStyleSheet* aSheet,
|
|||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ProbePseudoElementStyle(Element* aOriginatingElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext)
|
||||
nsStyleContext* aParentContext,
|
||||
Element* aPseudoElement)
|
||||
{
|
||||
UpdateStylistIfNeeded();
|
||||
if (aPseudoElement) {
|
||||
NS_ERROR("stylo: We don't support CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE yet");
|
||||
}
|
||||
|
||||
// NB: We ignore aParentContext, on the assumption that pseudo element styles
|
||||
// should just inherit from aOriginatingElement's primary style, which Servo
|
||||
|
@ -801,19 +806,6 @@ ServoStyleSet::ProbePseudoElementStyle(Element* aOriginatingElement,
|
|||
isBeforeOrAfter ? aOriginatingElement : nullptr);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ProbePseudoElementStyle(Element* aOriginatingElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
Element* aPseudoElement)
|
||||
{
|
||||
if (aPseudoElement) {
|
||||
NS_ERROR("stylo: We don't support CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE yet");
|
||||
}
|
||||
return ProbePseudoElementStyle(aOriginatingElement, aType, aParentContext);
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask)
|
||||
|
@ -851,6 +843,23 @@ ServoStyleSet::StyleDocument()
|
|||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
bool
|
||||
ServoStyleSet::StyleDocumentForAnimationOnly()
|
||||
{
|
||||
PreTraverse(nullptr, EffectCompositor::AnimationRestyleType::Full);
|
||||
|
||||
bool postTraversalRequired = false;
|
||||
DocumentStyleRootIterator iter(mPresContext->Document());
|
||||
while (Element* root = iter.GetNextStyleRoot()) {
|
||||
if (PrepareAndTraverseSubtree(root,
|
||||
TraversalRootBehavior::Normal,
|
||||
TraversalRestyleBehavior::ForAnimationOnly)) {
|
||||
postTraversalRequired = true;
|
||||
}
|
||||
}
|
||||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::StyleNewSubtree(Element* aRoot)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#ifndef mozilla_ServoStyleSet_h
|
||||
#define mozilla_ServoStyleSet_h
|
||||
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/PostTraversalTask.h"
|
||||
|
@ -118,12 +119,6 @@ public:
|
|||
nsStyleContext* aParentContext,
|
||||
LazyComputeBehavior aMayCompute);
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
LazyComputeBehavior aMayCompute,
|
||||
TreeMatchContext& aTreeMatchContext);
|
||||
|
||||
// Get a style context for a text node (which no rules will match).
|
||||
//
|
||||
// The returned style context will have nsCSSAnonBoxes::mozText as its pseudo.
|
||||
|
@ -215,16 +210,10 @@ public:
|
|||
nsresult AddDocStyleSheet(ServoStyleSheet* aSheet, nsIDocument* aDocument);
|
||||
|
||||
// check whether there is ::before/::after style for an element
|
||||
already_AddRefed<nsStyleContext>
|
||||
ProbePseudoElementStyle(dom::Element* aOriginatingElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext);
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ProbePseudoElementStyle(dom::Element* aOriginatingElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
dom::Element* aPseudoElement = nullptr);
|
||||
|
||||
// Test if style is dependent on content state
|
||||
|
@ -245,6 +234,15 @@ public:
|
|||
*/
|
||||
bool StyleDocument();
|
||||
|
||||
/**
|
||||
* Performs a Servo animation-only traversal to compute style for all nodes
|
||||
* with the animation-only dirty bit in the document.
|
||||
*
|
||||
* This will traverse all of the document's style roots (that is, its document
|
||||
* element, and the roots of the document-level native anonymous content).
|
||||
*/
|
||||
bool StyleDocumentForAnimationOnly();
|
||||
|
||||
/**
|
||||
* Eagerly styles a subtree of unstyled nodes that was just appended to the
|
||||
* tree. This is used in situations where we need the style immediately and
|
||||
|
@ -422,7 +420,9 @@ private:
|
|||
* When aRoot is null, the entire document is pre-traversed. Otherwise,
|
||||
* only the subtree rooted at aRoot is pre-traversed.
|
||||
*/
|
||||
void PreTraverse(dom::Element* aRoot = nullptr);
|
||||
void PreTraverse(dom::Element* aRoot = nullptr,
|
||||
EffectCompositor::AnimationRestyleType =
|
||||
EffectCompositor::AnimationRestyleType::Throttled);
|
||||
// Subset of the pre-traverse steps that involve syncing up data
|
||||
void PreTraverseSync();
|
||||
|
||||
|
|
|
@ -53,14 +53,16 @@ enum class TraversalRootBehavior {
|
|||
UnstyledChildrenOnly,
|
||||
};
|
||||
|
||||
// Indicates whether the Servo style system should perform normal processing or
|
||||
// whether it should traverse in a mode that doesn't generate any change hints,
|
||||
// which is what's required when handling frame reconstruction. The change
|
||||
// hints in this case are unneeded, since the old frames have already been
|
||||
// destroyed.
|
||||
// Indicates whether the Servo style system should perform normal processing,
|
||||
// animation-only processing (so we can flush any throttled animation styles),
|
||||
// or whether it should traverse in a mode that doesn't generate any change
|
||||
// hints, which is what's required when handling frame reconstruction.
|
||||
// The change hints in this case are unneeded, since the old frames have
|
||||
// already been destroyed.
|
||||
enum class TraversalRestyleBehavior {
|
||||
Normal,
|
||||
ForReconstruct,
|
||||
ForAnimationOnly,
|
||||
};
|
||||
|
||||
// Represents which tasks are performed in a SequentialTask of UpdateAnimations.
|
||||
|
|
|
@ -123,7 +123,7 @@ public:
|
|||
ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
LazyComputeBehavior aMayCompute,
|
||||
TreeMatchContext& aTreeMatchContext);
|
||||
TreeMatchContext* aTreeMatchContext);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ResolveStyleForText(nsIContent* aTextNode,
|
||||
nsStyleContext* aParentContext);
|
||||
|
@ -161,7 +161,7 @@ public:
|
|||
ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
TreeMatchContext* aTreeMatchContext,
|
||||
dom::Element* aPseudoElement = nullptr);
|
||||
inline nsRestyleHint HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask);
|
||||
|
|
|
@ -89,9 +89,14 @@ already_AddRefed<nsStyleContext>
|
|||
StyleSetHandle::Ptr::ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
LazyComputeBehavior aMayCompute,
|
||||
TreeMatchContext& aTreeMatchContext)
|
||||
TreeMatchContext* aTreeMatchContext)
|
||||
{
|
||||
FORWARD(ResolveStyleFor, (aElement, aParentContext, aMayCompute, aTreeMatchContext));
|
||||
if (IsGecko()) {
|
||||
MOZ_ASSERT(aTreeMatchContext);
|
||||
return AsGecko()->ResolveStyleFor(aElement, aParentContext, aMayCompute, *aTreeMatchContext);
|
||||
} else {
|
||||
return AsServo()->ResolveStyleFor(aElement, aParentContext, aMayCompute);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
|
@ -228,11 +233,17 @@ already_AddRefed<nsStyleContext>
|
|||
StyleSetHandle::Ptr::ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
TreeMatchContext* aTreeMatchContext,
|
||||
dom::Element* aPseudoElement)
|
||||
{
|
||||
FORWARD(ProbePseudoElementStyle, (aParentElement, aType, aParentContext,
|
||||
aTreeMatchContext, aPseudoElement));
|
||||
if (IsGecko()) {
|
||||
MOZ_ASSERT(aTreeMatchContext);
|
||||
return AsGecko()->ProbePseudoElementStyle(aParentElement, aType, aParentContext,
|
||||
*aTreeMatchContext, aPseudoElement);
|
||||
} else {
|
||||
return AsServo()->ProbePseudoElementStyle(aParentElement, aType, aParentContext,
|
||||
aPseudoElement);
|
||||
}
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
|
|
|
@ -226,10 +226,15 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
|||
return mCurrentStyleScope;
|
||||
}
|
||||
|
||||
/* Helper class for maintaining the ancestor state */
|
||||
/*
|
||||
* Helper class for maintaining the ancestor state.
|
||||
*
|
||||
* This class does nothing if aTreeMatchContext is null, which is the case for
|
||||
* the Servo style system.
|
||||
*/
|
||||
class MOZ_RAII AutoAncestorPusher {
|
||||
public:
|
||||
explicit AutoAncestorPusher(TreeMatchContext& aTreeMatchContext
|
||||
explicit AutoAncestorPusher(TreeMatchContext* aTreeMatchContext
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: mPushedAncestor(false)
|
||||
, mPushedStyleScope(false)
|
||||
|
@ -240,32 +245,52 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
|||
}
|
||||
|
||||
void PushAncestorAndStyleScope(mozilla::dom::Element* aElement) {
|
||||
if (!mTreeMatchContext) {
|
||||
MOZ_ASSERT_IF(aElement, aElement->IsStyledByServo());
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mElement);
|
||||
if (aElement) {
|
||||
mElement = aElement;
|
||||
mPushedAncestor = true;
|
||||
mPushedStyleScope = true;
|
||||
mTreeMatchContext.mAncestorFilter.PushAncestor(aElement);
|
||||
mTreeMatchContext.PushStyleScope(aElement);
|
||||
mTreeMatchContext->mAncestorFilter.PushAncestor(aElement);
|
||||
mTreeMatchContext->PushStyleScope(aElement);
|
||||
}
|
||||
}
|
||||
|
||||
void PushAncestorAndStyleScope(nsIContent* aContent) {
|
||||
if (!mTreeMatchContext) {
|
||||
MOZ_ASSERT_IF(aContent, aContent->IsStyledByServo());
|
||||
return;
|
||||
}
|
||||
|
||||
if (aContent && aContent->IsElement()) {
|
||||
PushAncestorAndStyleScope(aContent->AsElement());
|
||||
}
|
||||
}
|
||||
|
||||
void PushStyleScope(mozilla::dom::Element* aElement) {
|
||||
if (!mTreeMatchContext) {
|
||||
MOZ_ASSERT_IF(aElement, aElement->IsStyledByServo());
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mElement);
|
||||
if (aElement) {
|
||||
mElement = aElement;
|
||||
mPushedStyleScope = true;
|
||||
mTreeMatchContext.PushStyleScope(aElement);
|
||||
mTreeMatchContext->PushStyleScope(aElement);
|
||||
}
|
||||
}
|
||||
|
||||
void PushStyleScope(nsIContent* aContent) {
|
||||
if (!mTreeMatchContext) {
|
||||
MOZ_ASSERT_IF(aContent, aContent->IsStyledByServo());
|
||||
return;
|
||||
}
|
||||
|
||||
if (aContent && aContent->IsElement()) {
|
||||
PushStyleScope(aContent->AsElement());
|
||||
}
|
||||
|
@ -273,17 +298,17 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
|||
|
||||
~AutoAncestorPusher() {
|
||||
if (mPushedAncestor) {
|
||||
mTreeMatchContext.mAncestorFilter.PopAncestor();
|
||||
mTreeMatchContext->mAncestorFilter.PopAncestor();
|
||||
}
|
||||
if (mPushedStyleScope) {
|
||||
mTreeMatchContext.PopStyleScope(mElement);
|
||||
mTreeMatchContext->PopStyleScope(mElement);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool mPushedAncestor;
|
||||
bool mPushedStyleScope;
|
||||
TreeMatchContext& mTreeMatchContext;
|
||||
TreeMatchContext* mTreeMatchContext;
|
||||
mozilla::dom::Element* mElement;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
|
|
@ -1032,11 +1032,28 @@ nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
|
|||
|
||||
DebugOnly<int> styleStructCount = 1; // count Variables already
|
||||
|
||||
// Servo's optimization to stop the cascade when there are no style changes
|
||||
// that children need to be recascade for relies on comparing all of the
|
||||
// structs, not just those that are returned from PeekStyleData, although
|
||||
// if PeekStyleData does return null we still don't want to accumulate
|
||||
// any change hints for those structs.
|
||||
bool checkUnrequestedServoStructs = mSource.IsServoComputedValues();
|
||||
|
||||
#define DO_STRUCT_DIFFERENCE(struct_) \
|
||||
PR_BEGIN_MACRO \
|
||||
const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \
|
||||
bool unrequestedStruct; \
|
||||
if (this##struct_) { \
|
||||
unrequestedStruct = false; \
|
||||
structsFound |= NS_STYLE_INHERIT_BIT(struct_); \
|
||||
} else if (checkUnrequestedServoStructs) { \
|
||||
this##struct_ = \
|
||||
Servo_GetStyle##struct_(mSource.AsServoComputedValues()); \
|
||||
unrequestedStruct = true; \
|
||||
} else { \
|
||||
unrequestedStruct = false; \
|
||||
} \
|
||||
if (this##struct_) { \
|
||||
const nsStyle##struct_* other##struct_ = aNewContext->Style##struct_(); \
|
||||
if (this##struct_ == other##struct_) { \
|
||||
/* The very same struct, so we know that there will be no */ \
|
||||
|
@ -1045,7 +1062,9 @@ nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
|
|||
} else { \
|
||||
nsChangeHint difference = \
|
||||
this##struct_->CalcDifference(*other##struct_ EXTRA_DIFF_ARGS); \
|
||||
hint |= difference; \
|
||||
if (!unrequestedStruct) { \
|
||||
hint |= difference; \
|
||||
} \
|
||||
if (!difference) { \
|
||||
*aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
|
||||
} \
|
||||
|
|
|
@ -60,7 +60,9 @@ support-files = file_animations_effect_timing_iterations.html
|
|||
[test_animations_iterationstart.html]
|
||||
support-files = file_animations_iterationstart.html
|
||||
[test_animations_omta.html]
|
||||
skip-if = (stylo && !e10s) # mochitest expectations are different with non-e10s, bug 1361938, bug 1361663
|
||||
[test_animations_omta_start.html]
|
||||
skip-if = (stylo && !e10s) # mochitest expectations are different with non-e10s, bug 1362292
|
||||
[test_animations_pausing.html]
|
||||
support-files = file_animations_pausing.html
|
||||
[test_animations_playbackrate.html]
|
||||
|
|
|
@ -42,15 +42,7 @@ to mochitest command.
|
|||
* inserting keyframes rule doesn't trigger restyle bug 1364799:
|
||||
* test_rule_insertion.html `@keyframes` [36]
|
||||
* OMTA
|
||||
* test_animations_effect_timing_duration.html [1]
|
||||
* test_animations_effect_timing_enddelay.html [1]
|
||||
* test_animations_effect_timing_iterations.html [1]
|
||||
* test_animations_iterationstart.html [1]
|
||||
* test_animations_omta.html [1]
|
||||
* test_animations_omta_start.html [1]
|
||||
* test_animations_pausing.html [1]
|
||||
* test_animations_playbackrate.html [1]
|
||||
* test_animations_reverse.html [1]
|
||||
* test_animations_omta.html: bug 1361938, bug 1361663 [88]
|
||||
* SMIL Animation
|
||||
* test_restyles_in_smil_animation.html [2]
|
||||
* CSSOM support:
|
||||
|
@ -63,12 +55,12 @@ to mochitest command.
|
|||
* test_parser_diagnostics_unprintables.html [550]
|
||||
* Transition support:
|
||||
* test_transitions.html: pseudo elements [12]
|
||||
* test_transitions_and_reframes.html `pseudo-element`: bug 1366422 [4]
|
||||
* Events:
|
||||
* test_animations_event_order.html [2]
|
||||
* test_computed_style.html `gradient`: -webkit-prefixed gradient values [13]
|
||||
* test_bug829816.html: counter-{reset,increment} serialization difference bug 1363968 [8]
|
||||
* dynamic change on \@counter-style rule bug 1363590
|
||||
* test_counter_style.html [11]
|
||||
* test_counter_style.html asserts [11]
|
||||
* test_counter_descriptor_storage.html asserts [110]
|
||||
* symbols() function and string value on list-style-type bug 1363596
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.mozilla.gecko.customtabs;
|
|||
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
|
@ -58,7 +59,8 @@ public class ActionBarPresenter {
|
|||
@ColorInt
|
||||
private int mTextPrimaryColor = DEFAULT_TEXT_PRIMARY_COLOR;
|
||||
|
||||
ActionBarPresenter(@NonNull final ActionBar actionBar) {
|
||||
ActionBarPresenter(@NonNull final ActionBar actionBar, @ColorInt final int textColor) {
|
||||
mTextPrimaryColor = textColor;
|
||||
mActionBar = actionBar;
|
||||
mActionBar.setDisplayShowCustomEnabled(true);
|
||||
mActionBar.setDisplayShowTitleEnabled(false);
|
||||
|
@ -69,7 +71,8 @@ public class ActionBarPresenter {
|
|||
mTitleView = (TextView) customView.findViewById(R.id.custom_tabs_action_bar_title);
|
||||
mUrlView = (TextView) customView.findViewById(R.id.custom_tabs_action_bar_url);
|
||||
|
||||
onThemeChanged(mActionBar.getThemedContext().getTheme());
|
||||
mTitleView.setTextColor(mTextPrimaryColor);
|
||||
mUrlView.setTextColor(mTextPrimaryColor);
|
||||
|
||||
mIdentityPopup = new SiteIdentityPopup(mActionBar.getThemedContext());
|
||||
mIdentityPopup.setAnchor(customView);
|
||||
|
@ -137,9 +140,12 @@ public class ActionBarPresenter {
|
|||
btn.setScaleType(ImageView.ScaleType.FIT_CENTER);
|
||||
|
||||
if (tint) {
|
||||
DrawableCompat.setTint(icon, mTextPrimaryColor);
|
||||
Drawable wrapped = DrawableCompat.wrap(icon);
|
||||
DrawableCompat.setTint(wrapped, mTextPrimaryColor);
|
||||
btn.setImageDrawable(wrapped);
|
||||
} else {
|
||||
btn.setImageDrawable(icon);
|
||||
}
|
||||
btn.setImageDrawable(icon);
|
||||
|
||||
// menu id does not matter here. We can directly bind callback to the returned-view.
|
||||
final MenuItem item = menu.add(Menu.NONE, -1, Menu.NONE, "");
|
||||
|
@ -185,8 +191,9 @@ public class ActionBarPresenter {
|
|||
.getResources()
|
||||
.getDrawable(R.drawable.ic_close_light);
|
||||
|
||||
DrawableCompat.setTint(icon, mTextPrimaryColor);
|
||||
mActionBar.setHomeAsUpIndicator(icon);
|
||||
Drawable wrapped = DrawableCompat.wrap(icon);
|
||||
DrawableCompat.setTint(wrapped, mTextPrimaryColor);
|
||||
mActionBar.setHomeAsUpIndicator(wrapped);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,13 +236,4 @@ public class ActionBarPresenter {
|
|||
mUrlView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void onThemeChanged(@NonNull final Resources.Theme currentTheme) {
|
||||
// Theme might be light or dark. To get text color for custom-view.
|
||||
final TypedArray themeArray = currentTheme.obtainStyledAttributes(
|
||||
new int[]{android.R.attr.textColorPrimary});
|
||||
|
||||
mTextPrimaryColor = themeArray.getColor(0, DEFAULT_TEXT_PRIMARY_COLOR);
|
||||
themeArray.recycle();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,13 @@ import android.content.Intent;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Browser;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.StyleRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v4.util.SparseArrayCompat;
|
||||
import android.support.v7.app.ActionBar;
|
||||
|
@ -39,7 +38,6 @@ import org.mozilla.gecko.Tab;
|
|||
import org.mozilla.gecko.Tabs;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.TelemetryContract;
|
||||
import org.mozilla.gecko.gfx.DynamicToolbarAnimator;
|
||||
import org.mozilla.gecko.gfx.DynamicToolbarAnimator.PinReason;
|
||||
import org.mozilla.gecko.menu.GeckoMenu;
|
||||
import org.mozilla.gecko.menu.GeckoMenuInflater;
|
||||
|
@ -75,8 +73,6 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs
|
|||
|
||||
final SafeIntent intent = new SafeIntent(getIntent());
|
||||
|
||||
setThemeFromToolbarColor();
|
||||
|
||||
doorhangerOverlay = findViewById(R.id.custom_tabs_doorhanger_overlay);
|
||||
|
||||
mProgressView = (ProgressBar) findViewById(R.id.page_progress);
|
||||
|
@ -85,7 +81,7 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs
|
|||
final ActionBar actionBar = getSupportActionBar();
|
||||
bindNavigationCallback(toolbar);
|
||||
|
||||
actionBarPresenter = new ActionBarPresenter(actionBar);
|
||||
actionBarPresenter = new ActionBarPresenter(actionBar, getActionBarTextColor());
|
||||
actionBarPresenter.displayUrlOnly(intent.getDataString());
|
||||
actionBarPresenter.setBackgroundColor(IntentUtil.getToolbarColor(intent), getWindow());
|
||||
actionBarPresenter.setTextLongClickListener(new UrlCopyListener());
|
||||
|
@ -142,13 +138,9 @@ public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabs
|
|||
EventDispatcher.getInstance().dispatch("Telemetry:CustomTabsPing", data);
|
||||
}
|
||||
|
||||
private void setThemeFromToolbarColor() {
|
||||
final int color = ColorUtil.getReadableTextColor(IntentUtil.getToolbarColor(new SafeIntent(getIntent())));
|
||||
@StyleRes final int styleRes = (color == Color.BLACK)
|
||||
? R.style.GeckoCustomTabs_Light
|
||||
: R.style.GeckoCustomTabs;
|
||||
|
||||
setTheme(styleRes);
|
||||
@ColorInt
|
||||
private int getActionBarTextColor() {
|
||||
return ColorUtil.getReadableTextColor(IntentUtil.getToolbarColor(new SafeIntent(getIntent())));
|
||||
}
|
||||
|
||||
// Bug 1329145: 3rd party app could specify customized exit-animation to this activity.
|
||||
|
|
|
@ -125,13 +125,7 @@
|
|||
And ensure changes to CustomTabsActivity won't effect GeckoApp.
|
||||
-->
|
||||
|
||||
<style name="GeckoCustomTabs" parent="Theme.AppCompat.NoActionBar">
|
||||
<item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
|
||||
<item name="menuItemDefaultStyle">@style/Widget.MenuItemCustomTabs</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
</style>
|
||||
|
||||
<style name="GeckoCustomTabs.Light" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<style name="GeckoCustomTabs" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="menuItemActionBarStyle">@style/Widget.MenuItemActionBar</item>
|
||||
<item name="menuItemDefaultStyle">@style/Widget.MenuItemCustomTabs</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
|
|
|
@ -458,7 +458,6 @@ var BrowserApp = {
|
|||
CharacterEncoding.init();
|
||||
ActivityObserver.init();
|
||||
RemoteDebugger.init();
|
||||
UserAgentOverrides.init();
|
||||
DesktopUserAgent.init();
|
||||
Distribution.init();
|
||||
Tabs.init();
|
||||
|
|
|
@ -277,6 +277,8 @@
|
|||
@BINPATH@/components/BrowserElementParent.js
|
||||
@BINPATH@/components/FeedProcessor.manifest
|
||||
@BINPATH@/components/FeedProcessor.js
|
||||
@BINPATH@/components/UAOverridesBootstrapper.js
|
||||
@BINPATH@/components/UAOverridesBootstrapper.manifest
|
||||
@BINPATH@/components/WellKnownOpportunisticUtils.js
|
||||
@BINPATH@/components/WellKnownOpportunisticUtils.manifest
|
||||
@BINPATH@/components/mozProtocolHandler.js
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/UserAgentOverrides.jsm");
|
||||
|
||||
function UAOverridesBootstrapper() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
UAOverridesBootstrapper.prototype = {
|
||||
init: function uaob_init() {
|
||||
Services.obs.addObserver(this, "profile-change-net-teardown", false);
|
||||
UserAgentOverrides.init();
|
||||
},
|
||||
|
||||
observe: function uaob_observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "profile-change-net-teardown") {
|
||||
Services.obs.removeObserver(this, "profile-change-net-teardown");
|
||||
UserAgentOverrides.uninit();
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
classID: Components.ID("{965b0ca8-155b-11e7-93ae-92361f002671}")
|
||||
};
|
||||
|
||||
const components = [UAOverridesBootstrapper];
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
|
@ -0,0 +1,3 @@
|
|||
# UAOverridesBootstrapper.js
|
||||
component {965b0ca8-155b-11e7-93ae-92361f002671} UAOverridesBootstrapper.js process=main
|
||||
contract @mozilla.org/network/ua-overrides-bootstrapper;1 {965b0ca8-155b-11e7-93ae-92361f002671} process=main
|
|
@ -14,11 +14,15 @@ Components.utils.import("resource://gre/modules/Services.jsm");
|
|||
Components.utils.import("resource://gre/modules/UserAgentUpdates.jsm");
|
||||
|
||||
const PREF_OVERRIDES_ENABLED = "general.useragent.site_specific_overrides";
|
||||
const DEFAULT_UA = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler)
|
||||
.userAgent;
|
||||
const MAX_OVERRIDE_FOR_HOST_CACHE_SIZE = 250;
|
||||
|
||||
// lazy load nsHttpHandler to improve startup performance.
|
||||
XPCOMUtils.defineLazyGetter(this, "DEFAULT_UA", function() {
|
||||
return Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler)
|
||||
.userAgent;
|
||||
});
|
||||
|
||||
var gPrefBranch;
|
||||
var gOverrides = new Map;
|
||||
var gUpdatedOverrides;
|
||||
|
@ -45,18 +49,24 @@ this.UserAgentOverrides = {
|
|||
// The http-on-useragent-request notification is disallowed in content processes.
|
||||
}
|
||||
|
||||
UserAgentUpdates.init(function(overrides) {
|
||||
gOverrideForHostCache.clear();
|
||||
if (overrides) {
|
||||
for (let domain in overrides) {
|
||||
overrides[domain] = getUserAgentFromOverride(overrides[domain]);
|
||||
try {
|
||||
UserAgentUpdates.init(function(overrides) {
|
||||
gOverrideForHostCache.clear();
|
||||
if (overrides) {
|
||||
for (let domain in overrides) {
|
||||
overrides[domain] = getUserAgentFromOverride(overrides[domain]);
|
||||
}
|
||||
overrides.get = function(key) { return this[key]; };
|
||||
}
|
||||
overrides.get = function(key) { return this[key]; };
|
||||
}
|
||||
gUpdatedOverrides = overrides;
|
||||
});
|
||||
gUpdatedOverrides = overrides;
|
||||
});
|
||||
|
||||
buildOverrides();
|
||||
} catch (e) {
|
||||
// UserAgentOverrides is initialized before profile is ready.
|
||||
// UA override might not work correctly.
|
||||
}
|
||||
|
||||
buildOverrides();
|
||||
gInitialized = true;
|
||||
},
|
||||
|
||||
|
|
|
@ -119,6 +119,8 @@ LOCAL_INCLUDES += [
|
|||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'UAOverridesBootstrapper.js',
|
||||
'UAOverridesBootstrapper.manifest',
|
||||
'WellKnownOpportunisticUtils.js',
|
||||
'WellKnownOpportunisticUtils.manifest',
|
||||
]
|
||||
|
|
|
@ -333,6 +333,19 @@ nsHttpHandler::SetFastOpenOSSupport()
|
|||
mFastOpenSupported ? "" : "not"));
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpHandler::EnsureUAOverridesInit()
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupports> bootstrapper
|
||||
= do_GetService("@mozilla.org/network/ua-overrides-bootstrapper;1", &rv);
|
||||
MOZ_ASSERT(bootstrapper);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
nsHttpHandler::~nsHttpHandler()
|
||||
{
|
||||
LOG(("Deleting nsHttpHandler [this=%p]\n", this));
|
||||
|
@ -2103,6 +2116,11 @@ nsHttpHandler::NewProxiedChannel2(nsIURI *uri,
|
|||
net_EnsurePSMInit();
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess()) {
|
||||
// Load UserAgentOverrides.jsm before any HTTP request is issued.
|
||||
EnsureUAOverridesInit();
|
||||
}
|
||||
|
||||
uint64_t channelId;
|
||||
rv = NewChannelId(channelId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -403,6 +403,8 @@ private:
|
|||
void NotifyObservers(nsIHttpChannel *chan, const char *event);
|
||||
|
||||
void SetFastOpenOSSupport();
|
||||
|
||||
void EnsureUAOverridesInit();
|
||||
private:
|
||||
|
||||
// cached services
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
#include "ScopedNSSTypes.h"
|
||||
#include "SharedCertVerifier.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Tokenizer.h"
|
||||
#include "mozilla/dom/PContent.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "nsArrayEnumerator.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsISSLStatus.h"
|
||||
|
@ -28,11 +30,9 @@
|
|||
#include "nsReadableUtils.h"
|
||||
#include "nsSecurityHeaderParser.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsVariant.h"
|
||||
#include "plstr.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "prnetdb.h"
|
||||
#include "prprf.h"
|
||||
|
||||
// A note about the preload list:
|
||||
// When a site specifically disables HSTS by sending a header with
|
||||
|
@ -57,6 +57,131 @@ const char kHPKPKeySuffix[] = ":HPKP";
|
|||
|
||||
NS_IMPL_ISUPPORTS(SiteHSTSState, nsISiteSecurityState, nsISiteHSTSState)
|
||||
|
||||
namespace {
|
||||
|
||||
static bool
|
||||
stringIsBase64EncodingOf256bitValue(const nsCString& encodedString) {
|
||||
nsAutoCString binaryValue;
|
||||
nsresult rv = Base64Decode(encodedString, binaryValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return binaryValue.Length() == SHA256_LENGTH;
|
||||
}
|
||||
|
||||
class SSSTokenizer final : public Tokenizer
|
||||
{
|
||||
public:
|
||||
explicit SSSTokenizer(const nsACString& source)
|
||||
: Tokenizer(source)
|
||||
{
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
ReadBool(/*out*/ bool& value)
|
||||
{
|
||||
uint8_t rawValue;
|
||||
if (!ReadInteger(&rawValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rawValue != 0 && rawValue != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
value = (rawValue == 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
ReadState(/*out*/ SecurityPropertyState& state)
|
||||
{
|
||||
uint32_t rawValue;
|
||||
if (!ReadInteger(&rawValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state = static_cast<SecurityPropertyState>(rawValue);
|
||||
switch (state) {
|
||||
case SecurityPropertyKnockout:
|
||||
case SecurityPropertyNegative:
|
||||
case SecurityPropertySet:
|
||||
case SecurityPropertyUnset:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note: Ideally, this method would be able to read SHA256 strings without
|
||||
// reading all the way to EOF. Unfortunately, if a token starts with digits
|
||||
// mozilla::Tokenizer will by default not consider the digits part of the
|
||||
// string. This can be worked around by making mozilla::Tokenizer consider
|
||||
// digit characters as "word" characters as well, but this can't be changed at
|
||||
// run time, meaning parsing digits as a number will fail.
|
||||
MOZ_MUST_USE bool
|
||||
ReadUntilEOFAsSHA256Keys(/*out*/ nsTArray<nsCString>& keys)
|
||||
{
|
||||
nsAutoCString mergedKeys;
|
||||
if (!ReadUntil(Token::EndOfFile(), mergedKeys, EXCLUDE_LAST)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This check makes sure the Substring() calls below are always valid.
|
||||
static const uint32_t SHA256Base64Len = 44;
|
||||
if (mergedKeys.Length() % SHA256Base64Len != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mergedKeys.Length(); i += SHA256Base64Len) {
|
||||
nsAutoCString key(Substring(mergedKeys, i, SHA256Base64Len));
|
||||
if (!stringIsBase64EncodingOf256bitValue(key)) {
|
||||
return false;
|
||||
}
|
||||
keys.AppendElement(key);
|
||||
}
|
||||
|
||||
return !keys.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
// Parses a state string like "1500918564034,1,1" into its constituent parts.
|
||||
bool
|
||||
ParseHSTSState(const nsCString& stateString,
|
||||
/*out*/ PRTime& expireTime,
|
||||
/*out*/ SecurityPropertyState& state,
|
||||
/*out*/ bool& includeSubdomains)
|
||||
{
|
||||
SSSTokenizer tokenizer(stateString);
|
||||
|
||||
if (!tokenizer.ReadInteger(&expireTime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.CheckChar(',')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.ReadState(state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.CheckChar(',')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.ReadBool(includeSubdomains)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tokenizer.CheckEOF();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SiteHSTSState::SiteHSTSState(const nsCString& aHost,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
const nsCString& aStateString)
|
||||
|
@ -66,21 +191,9 @@ SiteHSTSState::SiteHSTSState(const nsCString& aHost,
|
|||
, mHSTSState(SecurityPropertyUnset)
|
||||
, mHSTSIncludeSubdomains(false)
|
||||
{
|
||||
uint32_t hstsState = 0;
|
||||
uint32_t hstsIncludeSubdomains = 0; // PR_sscanf doesn't handle bools.
|
||||
int32_t matches = PR_sscanf(aStateString.get(), "%lld,%lu,%lu",
|
||||
&mHSTSExpireTime, &hstsState,
|
||||
&hstsIncludeSubdomains);
|
||||
bool valid = (matches == 3 &&
|
||||
(hstsIncludeSubdomains == 0 || hstsIncludeSubdomains == 1) &&
|
||||
((SecurityPropertyState)hstsState == SecurityPropertyUnset ||
|
||||
(SecurityPropertyState)hstsState == SecurityPropertySet ||
|
||||
(SecurityPropertyState)hstsState == SecurityPropertyKnockout ||
|
||||
(SecurityPropertyState)hstsState == SecurityPropertyNegative));
|
||||
if (valid) {
|
||||
mHSTSState = (SecurityPropertyState)hstsState;
|
||||
mHSTSIncludeSubdomains = (hstsIncludeSubdomains == 1);
|
||||
} else {
|
||||
bool valid = ParseHSTSState(aStateString, mHSTSExpireTime, mHSTSState,
|
||||
mHSTSIncludeSubdomains);
|
||||
if (!valid) {
|
||||
SSSLOG(("%s is not a valid SiteHSTSState", aStateString.get()));
|
||||
mHSTSExpireTime = 0;
|
||||
mHSTSState = SecurityPropertyUnset;
|
||||
|
@ -158,19 +271,66 @@ SiteHSTSState::GetOriginAttributes(JSContext* aCx,
|
|||
|
||||
NS_IMPL_ISUPPORTS(SiteHPKPState, nsISiteSecurityState, nsISiteHPKPState)
|
||||
|
||||
static bool
|
||||
stringIsBase64EncodingOf256bitValue(nsCString& encodedString) {
|
||||
nsAutoCString binaryValue;
|
||||
nsresult rv = mozilla::Base64Decode(encodedString, binaryValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
namespace {
|
||||
|
||||
// Parses a state string like
|
||||
// "1494603034103,1,1,AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" into its
|
||||
// constituent parts.
|
||||
bool
|
||||
ParseHPKPState(const nsCString& stateString,
|
||||
/*out*/ PRTime& expireTime,
|
||||
/*out*/ SecurityPropertyState& state,
|
||||
/*out*/ bool& includeSubdomains,
|
||||
/*out*/ nsTArray<nsCString>& sha256keys)
|
||||
{
|
||||
SSSTokenizer tokenizer(stateString);
|
||||
|
||||
if (!tokenizer.ReadInteger(&expireTime)) {
|
||||
return false;
|
||||
}
|
||||
if (binaryValue.Length() != SHA256_LENGTH) {
|
||||
|
||||
if (!tokenizer.CheckChar(',')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
if (!tokenizer.ReadState(state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SecurityPropertyNegative isn't a valid state for HPKP.
|
||||
switch (state) {
|
||||
case SecurityPropertyKnockout:
|
||||
case SecurityPropertySet:
|
||||
case SecurityPropertyUnset:
|
||||
break;
|
||||
case SecurityPropertyNegative:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.CheckChar(',')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.ReadBool(includeSubdomains)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tokenizer.CheckChar(',')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state == SecurityPropertySet) {
|
||||
// This reads to the end of input, so there's no need to explicitly check
|
||||
// for EOF.
|
||||
return tokenizer.ReadUntilEOFAsSHA256Keys(sha256keys);
|
||||
}
|
||||
|
||||
return tokenizer.CheckEOF();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SiteHPKPState::SiteHPKPState()
|
||||
: mExpireTime(0)
|
||||
, mState(SecurityPropertyUnset)
|
||||
|
@ -187,52 +347,9 @@ SiteHPKPState::SiteHPKPState(const nsCString& aHost,
|
|||
, mState(SecurityPropertyUnset)
|
||||
, mIncludeSubdomains(false)
|
||||
{
|
||||
uint32_t hpkpState = 0;
|
||||
uint32_t hpkpIncludeSubdomains = 0; // PR_sscanf doesn't handle bools.
|
||||
const uint32_t MaxMergedHPKPPinSize = 1024;
|
||||
char mergedHPKPins[MaxMergedHPKPPinSize];
|
||||
memset(mergedHPKPins, 0, MaxMergedHPKPPinSize);
|
||||
|
||||
if (aStateString.Length() >= MaxMergedHPKPPinSize) {
|
||||
SSSLOG(("SSS: Cannot parse PKPState string, too large\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t matches = PR_sscanf(aStateString.get(), "%lld,%lu,%lu,%s",
|
||||
&mExpireTime, &hpkpState,
|
||||
&hpkpIncludeSubdomains, mergedHPKPins);
|
||||
bool valid = (matches == 4 &&
|
||||
(hpkpIncludeSubdomains == 0 || hpkpIncludeSubdomains == 1) &&
|
||||
((SecurityPropertyState)hpkpState == SecurityPropertyUnset ||
|
||||
(SecurityPropertyState)hpkpState == SecurityPropertySet ||
|
||||
(SecurityPropertyState)hpkpState == SecurityPropertyKnockout));
|
||||
|
||||
SSSLOG(("SSS: loading SiteHPKPState matches=%d\n", matches));
|
||||
const uint32_t SHA256Base64Len = 44;
|
||||
|
||||
if (valid && (SecurityPropertyState)hpkpState == SecurityPropertySet) {
|
||||
// try to expand the merged PKPins
|
||||
const char* cur = mergedHPKPins;
|
||||
nsAutoCString pin;
|
||||
uint32_t collectedLen = 0;
|
||||
mergedHPKPins[MaxMergedHPKPPinSize - 1] = 0;
|
||||
size_t totalLen = strlen(mergedHPKPins);
|
||||
while (collectedLen + SHA256Base64Len <= totalLen) {
|
||||
pin.Assign(cur, SHA256Base64Len);
|
||||
if (stringIsBase64EncodingOf256bitValue(pin)) {
|
||||
mSHA256keys.AppendElement(pin);
|
||||
}
|
||||
cur += SHA256Base64Len;
|
||||
collectedLen += SHA256Base64Len;
|
||||
}
|
||||
if (mSHA256keys.IsEmpty()) {
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
mState = (SecurityPropertyState)hpkpState;
|
||||
mIncludeSubdomains = (hpkpIncludeSubdomains == 1);
|
||||
} else {
|
||||
bool valid = ParseHPKPState(aStateString, mExpireTime, mState,
|
||||
mIncludeSubdomains, mSHA256keys);
|
||||
if (!valid) {
|
||||
SSSLOG(("%s is not a valid SiteHPKPState", aStateString.get()));
|
||||
mExpireTime = 0;
|
||||
mState = SecurityPropertyUnset;
|
||||
|
@ -827,17 +944,14 @@ ParseSSSHeaders(uint32_t aType,
|
|||
SSSLOG(("SSS: found max-age directive"));
|
||||
foundMaxAge = true;
|
||||
|
||||
size_t len = directive->mValue.Length();
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
char chr = directive->mValue.CharAt(i);
|
||||
if (chr < '0' || chr > '9') {
|
||||
SSSLOG(("SSS: invalid value for max-age directive"));
|
||||
return nsISiteSecurityService::ERROR_INVALID_MAX_AGE;
|
||||
}
|
||||
Tokenizer tokenizer(directive->mValue);
|
||||
if (!tokenizer.ReadInteger(&maxAge)) {
|
||||
SSSLOG(("SSS: could not parse delta-seconds"));
|
||||
return nsISiteSecurityService::ERROR_INVALID_MAX_AGE;
|
||||
}
|
||||
|
||||
if (PR_sscanf(directive->mValue.get(), "%llu", &maxAge) != 1) {
|
||||
SSSLOG(("SSS: could not parse delta-seconds"));
|
||||
if (!tokenizer.CheckEOF()) {
|
||||
SSSLOG(("SSS: invalid value for max-age directive"));
|
||||
return nsISiteSecurityService::ERROR_INVALID_MAX_AGE;
|
||||
}
|
||||
|
||||
|
|
|
@ -867,3 +867,17 @@ function hexify(data) {
|
|||
// prepending a "0" solves the problem.
|
||||
return Array.from(data, (c, i) => ("0" + data.charCodeAt(i).toString(16)).slice(-2)).join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String[]} lines
|
||||
* Lines to write. Each line automatically has "\n" appended to it when
|
||||
* being written.
|
||||
* @param {nsIFileOutputStream} outputStream
|
||||
*/
|
||||
function writeLinesAndClose(lines, outputStream) {
|
||||
for (let line of lines) {
|
||||
line += "\n";
|
||||
outputStream.write(line, line.length);
|
||||
}
|
||||
outputStream.close();
|
||||
}
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
// The purpose of this test is to create a site security service state file
|
||||
// and see that the site security service reads it properly.
|
||||
|
||||
function writeLine(aLine, aOutputStream) {
|
||||
aOutputStream.write(aLine, aLine.length);
|
||||
}
|
||||
|
||||
var gSSService = null;
|
||||
var gSSSStateSeen = false;
|
||||
var gPreloadStateSeen = false;
|
||||
|
@ -50,11 +46,12 @@ function run_test() {
|
|||
ok(!stateFile.exists(),
|
||||
"State file should not exist when working with a clean slate");
|
||||
let outputStream = FileUtils.openFileOutputStream(stateFile);
|
||||
let now = (new Date()).getTime();
|
||||
writeLine(`a.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,0,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
|
||||
writeLine(`b.pinning2.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
|
||||
|
||||
outputStream.close();
|
||||
let expiryTime = Date.now() + 100000;
|
||||
let lines = [
|
||||
`a.pinning2.example.com:HPKP\t0\t0\t${expiryTime},1,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`b.pinning2.example.com:HPKP\t0\t0\t${expiryTime},1,1,${PINNING_ROOT_KEY_HASH}`,
|
||||
];
|
||||
writeLinesAndClose(lines, outputStream);
|
||||
|
||||
let preloadFile = profileDir.clone();
|
||||
preloadFile.append(PRELOAD_STATE_FILE_NAME);
|
||||
|
@ -62,8 +59,10 @@ function run_test() {
|
|||
"Preload file should not exist when working with a clean slate");
|
||||
|
||||
outputStream = FileUtils.openFileOutputStream(preloadFile);
|
||||
writeLine(`a.preload.example.com:HPKP\t0\t0\t${now + 100000},1,1,${PINNING_ROOT_KEY_HASH}\n`, outputStream);
|
||||
outputStream.close();
|
||||
lines = [
|
||||
`a.preload.example.com:HPKP\t0\t0\t${expiryTime},1,1,${PINNING_ROOT_KEY_HASH}`,
|
||||
];
|
||||
writeLinesAndClose(lines, outputStream);
|
||||
|
||||
Services.obs.addObserver(checkStateRead, "data-storage-ready");
|
||||
do_test_pending();
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
// The purpose of this test is to create a site security service state file
|
||||
// and see that the site security service reads it properly.
|
||||
|
||||
function writeLine(aLine, aOutputStream) {
|
||||
aOutputStream.write(aLine, aLine.length);
|
||||
}
|
||||
|
||||
var gSSService = null;
|
||||
|
||||
function checkStateRead(aSubject, aTopic, aData) {
|
||||
|
@ -79,15 +75,17 @@ function run_test() {
|
|||
// until we create it.
|
||||
ok(!stateFile.exists());
|
||||
let outputStream = FileUtils.openFileOutputStream(stateFile);
|
||||
let now = (new Date()).getTime();
|
||||
writeLine("expired.example.com:HSTS\t0\t0\t" + (now - 100000) + ",1,0\n", outputStream);
|
||||
writeLine("notexpired.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
|
||||
// This overrides an entry on the preload list.
|
||||
writeLine("includesubdomains.preloaded.test:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
|
||||
writeLine("incsubdomain.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,1\n", outputStream);
|
||||
// This overrides an entry on the preload list.
|
||||
writeLine("includesubdomains2.preloaded.test:HSTS\t0\t0\t0,2,0\n", outputStream);
|
||||
outputStream.close();
|
||||
let now = Date.now();
|
||||
let lines = [
|
||||
`expired.example.com:HSTS\t0\t0\t${now - 100000},1,0`,
|
||||
`notexpired.example.com:HSTS\t0\t0\t${now + 100000},1,0`,
|
||||
// This overrides an entry on the preload list.
|
||||
`includesubdomains.preloaded.test:HSTS\t0\t0\t${now + 100000},1,0`,
|
||||
`incsubdomain.example.com:HSTS\t0\t0\t${now + 100000},1,1`,
|
||||
// This overrides an entry on the preload list.
|
||||
"includesubdomains2.preloaded.test:HSTS\t0\t0\t0,2,0",
|
||||
];
|
||||
writeLinesAndClose(lines, outputStream);
|
||||
Services.obs.addObserver(checkStateRead, "data-storage-ready");
|
||||
do_test_pending();
|
||||
gSSService = Cc["@mozilla.org/ssservice;1"]
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
// and see that the site security service reads it properly. We also verify
|
||||
// that state changes are reflected in the child process.
|
||||
|
||||
function writeLine(aLine, aOutputStream) {
|
||||
aOutputStream.write(aLine, aLine.length);
|
||||
}
|
||||
|
||||
function start_test_in_child() {
|
||||
run_test_in_child("sss_readstate_child_worker.js");
|
||||
do_test_finished();
|
||||
|
@ -24,15 +20,17 @@ function run_test() {
|
|||
// until we create it.
|
||||
ok(!stateFile.exists());
|
||||
let outputStream = FileUtils.openFileOutputStream(stateFile);
|
||||
let now = (new Date()).getTime();
|
||||
writeLine("expired.example.com:HSTS\t0\t0\t" + (now - 100000) + ",1,0\n", outputStream);
|
||||
writeLine("notexpired.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
|
||||
// This overrides an entry on the preload list.
|
||||
writeLine("includesubdomains.preloaded.test:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
|
||||
writeLine("incsubdomain.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,1\n", outputStream);
|
||||
// This overrides an entry on the preload list.
|
||||
writeLine("includesubdomains2.preloaded.test:HSTS\t0\t0\t0,2,0\n", outputStream);
|
||||
outputStream.close();
|
||||
let now = Date.now();
|
||||
let lines = [
|
||||
`expired.example.com:HSTS\t0\t0\t${now - 100000},1,0`,
|
||||
`notexpired.example.com:HSTS\t0\t0\t${now + 100000},1,0`,
|
||||
// This overrides an entry on the preload list.
|
||||
`includesubdomains.preloaded.test:HSTS\t0\t0\t${now + 100000},1,0`,
|
||||
`incsubdomain.example.com:HSTS\t0\t0\t${now + 100000},1,1`,
|
||||
// This overrides an entry on the preload list.
|
||||
"includesubdomains2.preloaded.test:HSTS\t0\t0\t0,2,0",
|
||||
];
|
||||
writeLinesAndClose(lines, outputStream);
|
||||
Services.obs.addObserver(start_test_in_child, "data-storage-ready");
|
||||
do_test_pending();
|
||||
let SSService = Cc["@mozilla.org/ssservice;1"]
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
// The purpose of this test is to create a mostly bogus site security service
|
||||
// state file and see that the site security service handles it properly.
|
||||
|
||||
function writeLine(aLine, aOutputStream) {
|
||||
aOutputStream.write(aLine, aLine.length);
|
||||
}
|
||||
|
||||
var gSSService = null;
|
||||
|
||||
function checkStateRead(aSubject, aTopic, aData) {
|
||||
|
@ -19,20 +15,79 @@ function checkStateRead(aSubject, aTopic, aData) {
|
|||
|
||||
equal(aData, SSS_STATE_FILE_NAME);
|
||||
|
||||
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://example1.example.com"),
|
||||
0));
|
||||
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://example2.example.com"),
|
||||
0));
|
||||
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://example.com"), 0));
|
||||
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI("https://example3.example.com"),
|
||||
0));
|
||||
const HSTS_HOSTS = [
|
||||
"https://example1.example.com",
|
||||
"https://example2.example.com",
|
||||
];
|
||||
for (let host of HSTS_HOSTS) {
|
||||
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI(host),
|
||||
0),
|
||||
`${host} should be HSTS enabled`);
|
||||
}
|
||||
|
||||
const HPKP_HOSTS = [
|
||||
"https://keys.with.securitypropertyset.example.com",
|
||||
"https://starts.with.number.key.example.com",
|
||||
"https://starts.with.symbol.key.example.com",
|
||||
"https://multiple.keys.example.com",
|
||||
];
|
||||
for (let host of HPKP_HOSTS) {
|
||||
ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
Services.io.newURI(host),
|
||||
0),
|
||||
`${host} should be HPKP enabled`);
|
||||
}
|
||||
|
||||
const NOT_HSTS_OR_HPKP_HOSTS = [
|
||||
"https://example.com",
|
||||
"https://example3.example.com",
|
||||
"https://extra.comma.example.com",
|
||||
"https://empty.statestring.example.com",
|
||||
"https://rubbish.statestring.example.com",
|
||||
"https://spaces.statestring.example.com",
|
||||
"https://invalid.expirytime.example.com",
|
||||
"https://text.securitypropertystate.example.com",
|
||||
"https://invalid.securitypropertystate.example.com",
|
||||
"https://text.includesubdomains.example.com",
|
||||
"https://invalid.includesubdomains.example.com",
|
||||
];
|
||||
for (let host of NOT_HSTS_OR_HPKP_HOSTS) {
|
||||
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS,
|
||||
Services.io.newURI(host),
|
||||
0),
|
||||
`${host} should not be HSTS enabled`);
|
||||
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
Services.io.newURI(host),
|
||||
0),
|
||||
`${host} should not be HPKP enabled`);
|
||||
}
|
||||
|
||||
const NOT_HPKP_HOSTS = [
|
||||
"https://empty.keys.example.com",
|
||||
"https://rubbish.after.keys.example.com",
|
||||
"https://keys.with.securitypropertyunset.example.com",
|
||||
"https://keys.with.securitypropertyknockout.example.com",
|
||||
"https://securitypropertynegative.example.com",
|
||||
"https://not.sha256.key.example.com",
|
||||
];
|
||||
for (let host of NOT_HPKP_HOSTS) {
|
||||
ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HPKP,
|
||||
Services.io.newURI(host),
|
||||
0),
|
||||
`${host} should not be HPKP enabled`);
|
||||
}
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
const PINNING_ROOT_KEY_HASH = "VCIlmPM9NkgFQtrs4Oa5TeFcDu6MWRTKSNdePEhOgD8=";
|
||||
const BASE64_BUT_NOT_SHA256 = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
const STARTS_WITH_NUMBER = "1ABC23defG/hiJKlmNoP+QRStuVwxYZ9a+bcD/+/EFg=";
|
||||
const STARTS_WITH_SYMBOL = "+ABC23defG/hiJKlmNoP+QRStuVwxYZ9a+bcD/+/EFg=";
|
||||
const MULTIPLE_KEYS = PINNING_ROOT_KEY_HASH + STARTS_WITH_NUMBER +
|
||||
STARTS_WITH_SYMBOL;
|
||||
|
||||
function run_test() {
|
||||
let profileDir = do_get_profile();
|
||||
let stateFile = profileDir.clone();
|
||||
|
@ -41,19 +96,59 @@ function run_test() {
|
|||
// until we create it.
|
||||
ok(!stateFile.exists());
|
||||
let outputStream = FileUtils.openFileOutputStream(stateFile);
|
||||
let now = (new Date()).getTime();
|
||||
writeLine("example1.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
|
||||
writeLine("I'm a lumberjack and I'm okay; I work all night and I sleep all day!\n", outputStream);
|
||||
writeLine("This is a totally bogus entry\t\n", outputStream);
|
||||
writeLine("0\t0\t0\t0\t\n", outputStream);
|
||||
writeLine("\t\t\t\t\t\t\t\n", outputStream);
|
||||
writeLine("example.com:HSTS\t\t\t\t\t\t\t\n", outputStream);
|
||||
writeLine("example3.example.com:HSTS\t0\t\t\t\t\t\t\n", outputStream);
|
||||
writeLine("example2.example.com:HSTS\t0\t0\t" + (now + 100000) + ",1,0\n", outputStream);
|
||||
outputStream.close();
|
||||
let expiryTime = Date.now() + 100000;
|
||||
let lines = [
|
||||
// General state file entry tests.
|
||||
`example1.example.com:HSTS\t0\t0\t${expiryTime},1,0`,
|
||||
"I'm a lumberjack and I'm okay; I work all night and I sleep all day!",
|
||||
"This is a totally bogus entry\t",
|
||||
"0\t0\t0\t0\t",
|
||||
"\t\t\t\t\t\t\t",
|
||||
"example.com:HSTS\t\t\t\t\t\t\t",
|
||||
"example.com:HPKP\t\t\t\t\t\t\t",
|
||||
"example3.example.com:HSTS\t0\t\t\t\t\t\t",
|
||||
"example3.example.com:HPKP\t0\t\t\t\t\t\t",
|
||||
`example2.example.com:HSTS\t0\t0\t${expiryTime},1,0`,
|
||||
// HSTS and HPKP state string parsing tests
|
||||
`extra.comma.example.com:HSTS\t0\t0\t${expiryTime},,1,0`,
|
||||
`extra.comma.example.com:HPKP\t0\t0\t${expiryTime},,1,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
"empty.statestring.example.com:HSTS\t0\t0\t",
|
||||
"empty.statestring.example.com:HPKP\t0\t0\t",
|
||||
"rubbish.statestring.example.com:HSTS\t0\t0\tfoobar",
|
||||
"rubbish.statestring.example.com:HPKP\t0\t0\tfoobar",
|
||||
`spaces.statestring.example.com:HSTS\t0\t0\t${expiryTime}, 1,0 `,
|
||||
`spaces.statestring.example.com:HPKP\t0\t0\t${expiryTime}, 1,0, ${PINNING_ROOT_KEY_HASH}`,
|
||||
`invalid.expirytime.example.com:HSTS\t0\t0\t${expiryTime}foo123,1,0`,
|
||||
`invalid.expirytime.example.com:HPKP\t0\t0\t${expiryTime}foo123,1,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`text.securitypropertystate.example.com:HSTS\t0\t0\t${expiryTime},1foo,0`,
|
||||
`text.securitypropertystate.example.com:HPKP\t0\t0\t${expiryTime},1foo,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`invalid.securitypropertystate.example.com:HSTS\t0\t0\t${expiryTime},999,0`,
|
||||
`invalid.securitypropertystate.example.com:HPKP\t0\t0\t${expiryTime},999,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`text.includesubdomains.example.com:HSTS\t0\t0\t${expiryTime},1,1foo`,
|
||||
`text.includesubdomains.example.com:HPKP\t0\t0\t${expiryTime},1,1foo,${PINNING_ROOT_KEY_HASH}`,
|
||||
`invalid.includesubdomains.example.com:HSTS\t0\t0\t${expiryTime},1,0foo`,
|
||||
`invalid.includesubdomains.example.com:HPKP\t0\t0\t${expiryTime},1,0foo,${PINNING_ROOT_KEY_HASH}`,
|
||||
// HPKP specific state string parsing tests
|
||||
`empty.keys.example.com:HPKP\t0\t0\t${expiryTime},1,0,`,
|
||||
`rubbish.after.keys.example.com:HPKP\t0\t0\t${expiryTime},1,0,${PINNING_ROOT_KEY_HASH}foo`,
|
||||
`keys.with.securitypropertyunset.example.com:HPKP\t0\t0\t${expiryTime},0,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`keys.with.securitypropertyset.example.com:HPKP\t0\t0\t${expiryTime},1,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`keys.with.securitypropertyknockout.example.com:HPKP\t0\t0\t${expiryTime},2,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`securitypropertynegative.example.com:HPKP\t0\t0\t${expiryTime},3,0,${PINNING_ROOT_KEY_HASH}`,
|
||||
`not.sha256.key.example.com:HPKP\t0\t0\t${expiryTime},1,0,${BASE64_BUT_NOT_SHA256}`,
|
||||
`starts.with.number.key.example.com:HPKP\t0\t0\t${expiryTime},1,0,${STARTS_WITH_NUMBER}`,
|
||||
`starts.with.symbol.key.example.com:HPKP\t0\t0\t${expiryTime},1,0,${STARTS_WITH_SYMBOL}`,
|
||||
`multiple.keys.example.com:HPKP\t0\t0\t${expiryTime},1,0,${MULTIPLE_KEYS}`,
|
||||
];
|
||||
writeLinesAndClose(lines, outputStream);
|
||||
Services.obs.addObserver(checkStateRead, "data-storage-ready");
|
||||
do_test_pending();
|
||||
gSSService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
notEqual(gSSService, null);
|
||||
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
do_register_cleanup(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,10 +7,6 @@
|
|||
// that is too large and see that the site security service reads it properly
|
||||
// (this means discarding all entries after the 1024th).
|
||||
|
||||
function writeLine(aLine, aOutputStream) {
|
||||
aOutputStream.write(aLine, aLine.length);
|
||||
}
|
||||
|
||||
var gSSService = null;
|
||||
|
||||
function checkStateRead(aSubject, aTopic, aData) {
|
||||
|
@ -52,13 +48,17 @@ function run_test() {
|
|||
// until we create it.
|
||||
ok(!stateFile.exists());
|
||||
let outputStream = FileUtils.openFileOutputStream(stateFile);
|
||||
let now = (new Date()).getTime();
|
||||
let expiryTime = Date.now() + 100000;
|
||||
let lines = [];
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
// The 0s will all get squashed down into one 0 when they are read.
|
||||
// This is just to make the file size large (>2MB).
|
||||
writeLine("example" + i + ".example.com:HSTS\t0000000000000000000000000000000000000000000000000\t00000000000000000000000000000000000000\t" + (now + 100000) + ",1,0000000000000000000000000000000000000000000000000000000000000000000000000\n", outputStream);
|
||||
lines.push(`example${i}.example.com:HSTS\t` +
|
||||
"0000000000000000000000000000000000000000000000000\t" +
|
||||
"00000000000000000000000000000000000000\t" +
|
||||
`${expiryTime},1,0000000000000000000000000000000000000000000000000000000000000000000000000`);
|
||||
}
|
||||
outputStream.close();
|
||||
writeLinesAndClose(lines, outputStream);
|
||||
Services.obs.addObserver(checkStateRead, "data-storage-ready");
|
||||
do_test_pending();
|
||||
gSSService = Cc["@mozilla.org/ssservice;1"]
|
||||
|
|
|
@ -164,17 +164,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.25.0"
|
||||
version = "0.25.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aster 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clang-sys 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clang-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quasi_codegen 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -362,7 +363,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "0.17.0"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -605,7 +606,7 @@ name = "deny_public_fields"
|
|||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1146,7 +1147,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1346,7 +1347,7 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2028,6 +2029,11 @@ name = "pdqsort"
|
|||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "phf"
|
||||
version = "0.7.21"
|
||||
|
@ -2826,7 +2832,7 @@ dependencies = [
|
|||
"app_units 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"arrayvec 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bindgen 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bindgen 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2860,6 +2866,7 @@ dependencies = [
|
|||
"servo_config 0.0.1",
|
||||
"servo_url 0.0.1",
|
||||
"smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"style_derive 0.0.1",
|
||||
"style_traits 0.0.1",
|
||||
"time 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2867,6 +2874,15 @@ dependencies = [
|
|||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "style_derive"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "style_tests"
|
||||
version = "0.0.1"
|
||||
|
@ -2946,7 +2962,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -3444,7 +3460,7 @@ dependencies = [
|
|||
"checksum base64 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "979d348dc50dfcd050a87df408ec61f01a0a27ee9b4ebdc6085baba8275b2c7f"
|
||||
"checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff"
|
||||
"checksum bincode 1.0.0-alpha6 (registry+https://github.com/rust-lang/crates.io-index)" = "fb0cdeac1c5d567fdb487ae5853c024e4acf1ea85ba6a6552fe084e0805fea5d"
|
||||
"checksum bindgen 0.25.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ccaf8958532d7e570e905266ee2dc1094c3e5c3c3cfc2c299368747a30a5e654"
|
||||
"checksum bindgen 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "708a688675f9d2e7c73018e17f5997beacc9a5ca87a0cb60c13093915facda32"
|
||||
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
|
||||
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
|
||||
"checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23"
|
||||
|
@ -3464,7 +3480,7 @@ dependencies = [
|
|||
"checksum cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "393a5f0088efbe41f9d1fcd062f24e83c278608420e62109feb2c8abee07de7d"
|
||||
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
|
||||
"checksum cgl 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86765cb42c2a2c497e142af72517c1b4d7ae5bb2f25dfa77a5c69642f2342d89"
|
||||
"checksum clang-sys 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "33d47b0ea88a529a570490efbb79403e416e89864ce8a96bf23e2a0f23d7e9eb"
|
||||
"checksum clang-sys 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff7c2d1502c65748c7221f43ce670b3ba5c697acebfeb85a580827daca6975fc"
|
||||
"checksum clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7db281b0520e97fbd15cd615dcd8f8bcad0c26f5f7d5effe705f090f39e9a758"
|
||||
"checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac"
|
||||
"checksum cocoa 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a5d0bcb4d345adf9b4ada6c5bb3e2b87c8150b79c46f3f26446de5f4d48de4b"
|
||||
|
@ -3595,6 +3611,7 @@ dependencies = [
|
|||
"checksum parking_lot_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56a19dcbb5d1e32b6cccb8a9aa1fc2a38418c8699652e735e2bf391a3dc0aa16"
|
||||
"checksum parse-hosts 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7626e29ef8f479f10d9a753f1fca914506663ecc9ec2dedb8cffc610a3d1f705"
|
||||
"checksum pdqsort 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ceca1642c89148ca05611cc775a0c383abef355fc4907c4e95f49f7b09d6287c"
|
||||
"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc"
|
||||
"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f"
|
||||
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
|
||||
|
@ -3651,7 +3668,7 @@ dependencies = [
|
|||
"checksum swapper 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca610b32bb8bfc5e7f705480c3a1edfeb70b6582495d343872c8bee0dcf758c"
|
||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
"checksum synstructure 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ccc9780bf1aa601943988c2876ab22413c01ad1739689aa6af18d0aa0b3f38b"
|
||||
"checksum synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf318c34a2f8381a4f3d4db2c91b45bca2b1cd8cbe56caced900647be164800c"
|
||||
"checksum syntex 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a8f5e3aaa79319573d19938ea38d068056b826db9883a5d47f86c1cecc688f0e"
|
||||
"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c"
|
||||
"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047"
|
||||
|
|
|
@ -160,7 +160,9 @@ pub fn recalc_style_for_animations(context: &LayoutContext,
|
|||
animation,
|
||||
&mut fragment.style,
|
||||
&ServoMetricsProvider);
|
||||
damage |= RestyleDamage::compute(&old_style, &fragment.style);
|
||||
let difference =
|
||||
RestyleDamage::compute_style_difference(&old_style, &fragment.style);
|
||||
damage |= difference.damage;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1100,7 +1100,7 @@ impl LayoutThread {
|
|||
let el = node.as_element().unwrap();
|
||||
if let Some(mut d) = element.mutate_data() {
|
||||
if d.has_styles() {
|
||||
d.ensure_restyle().hint.insert(&StoredRestyleHint::subtree());
|
||||
d.ensure_restyle().hint.insert(StoredRestyleHint::subtree());
|
||||
}
|
||||
}
|
||||
if let Some(p) = el.parent_element() {
|
||||
|
@ -1136,7 +1136,7 @@ impl LayoutThread {
|
|||
if needs_dirtying {
|
||||
if let Some(mut d) = element.mutate_data() {
|
||||
if d.has_styles() {
|
||||
d.ensure_restyle().hint.insert(&StoredRestyleHint::subtree());
|
||||
d.ensure_restyle().hint.insert(StoredRestyleHint::subtree());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1184,7 +1184,7 @@ impl LayoutThread {
|
|||
let mut restyle_data = style_data.ensure_restyle();
|
||||
|
||||
// Stash the data on the element for processing by the style system.
|
||||
restyle_data.hint.insert(&restyle.hint.into());
|
||||
restyle_data.hint.insert(restyle.hint.into());
|
||||
restyle_data.damage = restyle.damage;
|
||||
debug!("Noting restyle for {:?}: {:?}", el, restyle_data);
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ use std::rc::Rc;
|
|||
use std::time::{Duration, Instant};
|
||||
use style::attr::AttrValue;
|
||||
use style::context::{QuirksMode, ReflowGoal};
|
||||
use style::restyle_hints::{RestyleHint, RESTYLE_SELF, RESTYLE_STYLE_ATTRIBUTE};
|
||||
use style::restyle_hints::{RestyleHint, RestyleReplacements, RESTYLE_STYLE_ATTRIBUTE};
|
||||
use style::selector_parser::{RestyleDamage, Snapshot};
|
||||
use style::shared_lock::SharedRwLock as StyleSharedRwLock;
|
||||
use style::str::{HTML_SPACE_CHARACTERS, split_html_space_chars, str_join};
|
||||
|
@ -2361,14 +2361,14 @@ impl Document {
|
|||
entry.snapshot = Some(Snapshot::new(el.html_element_in_html_document()));
|
||||
}
|
||||
if attr.local_name() == &local_name!("style") {
|
||||
entry.hint |= RESTYLE_STYLE_ATTRIBUTE;
|
||||
entry.hint.insert(RestyleHint::for_replacements(RESTYLE_STYLE_ATTRIBUTE));
|
||||
}
|
||||
|
||||
// FIXME(emilio): This should become something like
|
||||
// element.is_attribute_mapped(attr.local_name()).
|
||||
if attr.local_name() == &local_name!("width") ||
|
||||
attr.local_name() == &local_name!("height") {
|
||||
entry.hint |= RESTYLE_SELF;
|
||||
entry.hint.insert(RestyleHint::for_self());
|
||||
}
|
||||
|
||||
let mut snapshot = entry.snapshot.as_mut().unwrap();
|
||||
|
|
|
@ -102,7 +102,7 @@ use style::context::{QuirksMode, ReflowGoal};
|
|||
use style::element_state::*;
|
||||
use style::properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock, parse_style_attribute};
|
||||
use style::properties::longhands::{self, background_image, border_spacing, font_family, font_size, overflow_x};
|
||||
use style::restyle_hints::RESTYLE_SELF;
|
||||
use style::restyle_hints::RestyleHint;
|
||||
use style::rule_tree::CascadeLevel;
|
||||
use style::selector_parser::{NonTSPseudoClass, PseudoElement, RestyleDamage, SelectorImpl, SelectorParser};
|
||||
use style::shared_lock::{SharedRwLock, Locked};
|
||||
|
@ -245,7 +245,7 @@ impl Element {
|
|||
|
||||
// FIXME(bholley): I think we should probably only do this for
|
||||
// NodeStyleDamaged, but I'm preserving existing behavior.
|
||||
restyle.hint |= RESTYLE_SELF;
|
||||
restyle.hint.insert(RestyleHint::for_self());
|
||||
|
||||
if damage == NodeDamage::OtherNodeDamage {
|
||||
restyle.damage = RestyleDamage::rebuild_and_reflow();
|
||||
|
|
|
@ -29,9 +29,10 @@ pub struct MutationObserver {
|
|||
record_queue: DOMRefCell<Vec<Root<MutationRecord>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Mutation {
|
||||
Attribute { name: LocalName, namespace: Namespace, old_value: DOMString }
|
||||
pub enum Mutation<'a> {
|
||||
Attribute { name: LocalName, namespace: Namespace, old_value: DOMString },
|
||||
ChildList { added: Option<&'a [&'a Node]>, removed: Option<&'a [&'a Node]>,
|
||||
prev: Option<&'a Node>, next: Option<&'a Node> },
|
||||
}
|
||||
|
||||
#[derive(HeapSizeOf, JSTraceable)]
|
||||
|
@ -143,6 +144,12 @@ impl MutationObserver {
|
|||
interestedObservers.push((Root::from_ref(&*registered.observer),
|
||||
paired_string));
|
||||
}
|
||||
},
|
||||
Mutation::ChildList { .. } => {
|
||||
if !registered.options.child_list {
|
||||
continue;
|
||||
}
|
||||
interestedObservers.push((Root::from_ref(&*registered.observer), None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -159,6 +166,9 @@ impl MutationObserver {
|
|||
None
|
||||
};
|
||||
MutationRecord::attribute_mutated(target, name, namespace, paired_string.clone())
|
||||
},
|
||||
Mutation::ChildList { ref added, ref removed, ref next, ref prev } => {
|
||||
MutationRecord::child_list_mutated(target, *added, *removed, *next, *prev)
|
||||
}
|
||||
};
|
||||
// Step 4.8
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding;
|
||||
use dom::bindings::codegen::Bindings::MutationRecordBinding::MutationRecordBinding::MutationRecordMethods;
|
||||
use dom::bindings::js::{JS, Root};
|
||||
use dom::bindings::js::{JS, MutNullableJS, Root};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::str::DOMString;
|
||||
use dom::node::{Node, window_from_node};
|
||||
|
@ -20,6 +20,10 @@ pub struct MutationRecord {
|
|||
attribute_name: Option<DOMString>,
|
||||
attribute_namespace: Option<DOMString>,
|
||||
old_value: Option<DOMString>,
|
||||
added_nodes: MutNullableJS<NodeList>,
|
||||
removed_nodes: MutNullableJS<NodeList>,
|
||||
next_sibling: Option<JS<Node>>,
|
||||
prev_sibling: Option<JS<Node>>,
|
||||
}
|
||||
|
||||
impl MutationRecord {
|
||||
|
@ -32,15 +36,40 @@ impl MutationRecord {
|
|||
target,
|
||||
Some(DOMString::from(&**attribute_name)),
|
||||
attribute_namespace.map(|n| DOMString::from(&**n)),
|
||||
old_value);
|
||||
old_value,
|
||||
None, None, None, None);
|
||||
reflect_dom_object(record, &*window_from_node(target), MutationRecordBinding::Wrap)
|
||||
}
|
||||
|
||||
pub fn child_list_mutated(target: &Node,
|
||||
added_nodes: Option<&[&Node]>,
|
||||
removed_nodes: Option<&[&Node]>,
|
||||
next_sibling: Option<&Node>,
|
||||
prev_sibling: Option<&Node>) -> Root<MutationRecord> {
|
||||
let window = window_from_node(target);
|
||||
let added_nodes = added_nodes.map(|list| NodeList::new_simple_list_slice(&window, list));
|
||||
let removed_nodes = removed_nodes.map(|list| NodeList::new_simple_list_slice(&window, list));
|
||||
|
||||
reflect_dom_object(box MutationRecord::new_inherited("childList",
|
||||
target,
|
||||
None, None, None,
|
||||
added_nodes.as_ref().map(|list| &**list),
|
||||
removed_nodes.as_ref().map(|list| &**list),
|
||||
next_sibling,
|
||||
prev_sibling),
|
||||
&*window,
|
||||
MutationRecordBinding::Wrap)
|
||||
}
|
||||
|
||||
fn new_inherited(record_type: &str,
|
||||
target: &Node,
|
||||
attribute_name: Option<DOMString>,
|
||||
attribute_namespace: Option<DOMString>,
|
||||
old_value: Option<DOMString>) -> MutationRecord {
|
||||
old_value: Option<DOMString>,
|
||||
added_nodes: Option<&NodeList>,
|
||||
removed_nodes: Option<&NodeList>,
|
||||
next_sibling: Option<&Node>,
|
||||
prev_sibling: Option<&Node>) -> MutationRecord {
|
||||
MutationRecord {
|
||||
reflector_: Reflector::new(),
|
||||
record_type: DOMString::from(record_type),
|
||||
|
@ -48,6 +77,10 @@ impl MutationRecord {
|
|||
attribute_name: attribute_name,
|
||||
attribute_namespace: attribute_namespace,
|
||||
old_value: old_value,
|
||||
added_nodes: MutNullableJS::new(added_nodes),
|
||||
removed_nodes: MutNullableJS::new(removed_nodes),
|
||||
next_sibling: next_sibling.map(JS::from_ref),
|
||||
prev_sibling: prev_sibling.map(JS::from_ref),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -80,24 +113,28 @@ impl MutationRecordMethods for MutationRecord {
|
|||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-addednodes
|
||||
fn AddedNodes(&self) -> Root<NodeList> {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
self.added_nodes.or_init(|| {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
})
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-removednodes
|
||||
fn RemovedNodes(&self) -> Root<NodeList> {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
self.removed_nodes.or_init(|| {
|
||||
let window = window_from_node(&*self.target);
|
||||
NodeList::empty(&window)
|
||||
})
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
|
||||
fn GetPreviousSibling(&self) -> Option<Root<Node>> {
|
||||
None
|
||||
self.prev_sibling.as_ref().map(|node| Root::from_ref(&**node))
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-mutationrecord-previoussibling
|
||||
fn GetNextSibling(&self) -> Option<Root<Node>> {
|
||||
None
|
||||
self.next_sibling.as_ref().map(|node| Root::from_ref(&**node))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ use dom::htmllinkelement::HTMLLinkElement;
|
|||
use dom::htmlmetaelement::HTMLMetaElement;
|
||||
use dom::htmlstyleelement::HTMLStyleElement;
|
||||
use dom::htmltextareaelement::{HTMLTextAreaElement, LayoutHTMLTextAreaElementHelpers};
|
||||
use dom::mutationobserver::RegisteredObserver;
|
||||
use dom::mutationobserver::{Mutation, MutationObserver, RegisteredObserver};
|
||||
use dom::nodelist::NodeList;
|
||||
use dom::processinginstruction::ProcessingInstruction;
|
||||
use dom::range::WeakRangeVec;
|
||||
|
@ -1616,18 +1616,27 @@ impl Node {
|
|||
let new_nodes = if let NodeTypeId::DocumentFragment = node.type_id() {
|
||||
// Step 3.
|
||||
new_nodes.extend(node.children().map(|kid| JS::from_ref(&*kid)));
|
||||
// Step 4: mutation observers.
|
||||
// Step 5.
|
||||
// Step 4.
|
||||
for kid in new_nodes.r() {
|
||||
Node::remove(*kid, node, SuppressObserver::Suppressed);
|
||||
}
|
||||
// Step 5.
|
||||
vtable_for(&node).children_changed(&ChildrenMutation::replace_all(new_nodes.r(), &[]));
|
||||
|
||||
let mutation = Mutation::ChildList {
|
||||
added: None,
|
||||
removed: Some(new_nodes.r()),
|
||||
prev: None,
|
||||
next: None,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&node, mutation);
|
||||
|
||||
new_nodes.r()
|
||||
} else {
|
||||
// Step 3.
|
||||
ref_slice(&node)
|
||||
};
|
||||
// Step 6: mutation observers.
|
||||
// Step 6.
|
||||
let previous_sibling = match suppress_observers {
|
||||
SuppressObserver::Unsuppressed => {
|
||||
match child {
|
||||
|
@ -1646,6 +1655,14 @@ impl Node {
|
|||
if let SuppressObserver::Unsuppressed = suppress_observers {
|
||||
vtable_for(&parent).children_changed(
|
||||
&ChildrenMutation::insert(previous_sibling.r(), new_nodes, child));
|
||||
|
||||
let mutation = Mutation::ChildList {
|
||||
added: Some(new_nodes),
|
||||
removed: None,
|
||||
prev: previous_sibling.r(),
|
||||
next: child,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&parent, mutation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1677,9 +1694,19 @@ impl Node {
|
|||
if let Some(node) = node {
|
||||
Node::insert(node, parent, None, SuppressObserver::Suppressed);
|
||||
}
|
||||
// Step 6: mutation observers.
|
||||
// Step 6.
|
||||
vtable_for(&parent).children_changed(
|
||||
&ChildrenMutation::replace_all(removed_nodes.r(), added_nodes));
|
||||
|
||||
if !removed_nodes.is_empty() || !added_nodes.is_empty() {
|
||||
let mutation = Mutation::ChildList {
|
||||
added: Some(added_nodes),
|
||||
removed: Some(removed_nodes.r()),
|
||||
prev: None,
|
||||
next: None,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&parent, mutation);
|
||||
}
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-node-pre-remove
|
||||
|
@ -1730,6 +1757,15 @@ impl Node {
|
|||
&ChildrenMutation::replace(old_previous_sibling.r(),
|
||||
&Some(&node), &[],
|
||||
old_next_sibling.r()));
|
||||
|
||||
let removed = [node];
|
||||
let mutation = Mutation::ChildList {
|
||||
added: None,
|
||||
removed: Some(&removed),
|
||||
prev: old_previous_sibling.r(),
|
||||
next: old_next_sibling.r(),
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&parent, mutation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2182,6 +2218,14 @@ impl NodeMethods for Node {
|
|||
&ChildrenMutation::replace(previous_sibling.r(),
|
||||
&removed_child, nodes,
|
||||
reference_child));
|
||||
let removed = removed_child.map(|r| [r]);
|
||||
let mutation = Mutation::ChildList {
|
||||
added: Some(nodes),
|
||||
removed: removed.as_ref().map(|r| &r[..]),
|
||||
prev: previous_sibling.r(),
|
||||
next: reference_child,
|
||||
};
|
||||
MutationObserver::queue_a_mutation_record(&self, mutation);
|
||||
|
||||
// Step 15.
|
||||
Ok(Root::from_ref(child))
|
||||
|
|
|
@ -47,6 +47,10 @@ impl NodeList {
|
|||
NodeList::new(window, NodeListType::Simple(iter.map(|r| JS::from_ref(&*r)).collect()))
|
||||
}
|
||||
|
||||
pub fn new_simple_list_slice(window: &Window, slice: &[&Node]) -> Root<NodeList> {
|
||||
NodeList::new(window, NodeListType::Simple(slice.iter().map(|r| JS::from_ref(*r)).collect()))
|
||||
}
|
||||
|
||||
pub fn new_child_list(window: &Window, node: &Node) -> Root<NodeList> {
|
||||
NodeList::new(window, NodeListType::Children(ChildrenList::new(node)))
|
||||
}
|
||||
|
|
|
@ -486,7 +486,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
|||
}
|
||||
|
||||
fn has_animations(&self) -> bool {
|
||||
unreachable!("this should be only called on gecko");
|
||||
// We use this function not only for Gecko but also for Servo to know if this element has
|
||||
// animations, so we maybe try to get the important rules of this element. This is used for
|
||||
// off-main thread animations, but we don't support it on Servo, so return false directly.
|
||||
false
|
||||
}
|
||||
|
||||
fn has_css_animations(&self) -> bool {
|
||||
|
|
|
@ -63,6 +63,7 @@ serde_derive = {version = "0.9", optional = true}
|
|||
servo_atoms = {path = "../atoms", optional = true}
|
||||
servo_config = {path = "../config", optional = true}
|
||||
smallvec = "0.3.3"
|
||||
style_derive = {path = "../style_derive"}
|
||||
style_traits = {path = "../style_traits"}
|
||||
servo_url = {path = "../url", optional = true}
|
||||
time = "0.1"
|
||||
|
@ -74,7 +75,7 @@ kernel32-sys = "0.2"
|
|||
[build-dependencies]
|
||||
lazy_static = "0.2"
|
||||
log = "0.3"
|
||||
bindgen = { version = "0.25", optional = true }
|
||||
bindgen = { version = "0.25.1", optional = true }
|
||||
regex = {version = "0.2", optional = true}
|
||||
walkdir = "1.0"
|
||||
toml = {version = "0.2.1", optional = true, default-features = false}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#![deny(missing_docs)]
|
||||
|
||||
use dom::{SendElement, TElement};
|
||||
use matching::MatchMethods;
|
||||
use selectors::bloom::BloomFilter;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// A struct that allows us to fast-reject deep descendant selectors avoiding
|
||||
/// selector-matching.
|
||||
|
@ -50,6 +50,26 @@ pub struct StyleBloom<E: TElement> {
|
|||
elements: Vec<SendElement<E>>,
|
||||
}
|
||||
|
||||
fn each_relevant_element_hash<E, F>(element: E, mut f: F)
|
||||
where E: TElement,
|
||||
F: FnMut(u32),
|
||||
{
|
||||
f(element.get_local_name().get_hash());
|
||||
f(element.get_namespace().get_hash());
|
||||
|
||||
if let Some(id) = element.get_id() {
|
||||
f(id.get_hash());
|
||||
}
|
||||
|
||||
// TODO: case-sensitivity depends on the document type and quirks mode.
|
||||
//
|
||||
// TODO(emilio): It's not clear whether that's relevant here though?
|
||||
// Classes and ids should be normalized already I think.
|
||||
element.each_class(|class| {
|
||||
f(class.get_hash())
|
||||
});
|
||||
}
|
||||
|
||||
impl<E: TElement> StyleBloom<E> {
|
||||
/// Create an empty `StyleBloom`.
|
||||
pub fn new() -> Self {
|
||||
|
@ -72,15 +92,26 @@ impl<E: TElement> StyleBloom<E> {
|
|||
assert!(element.parent_element().is_none());
|
||||
}
|
||||
}
|
||||
element.insert_into_bloom_filter(&mut *self.filter);
|
||||
self.push_internal(element);
|
||||
}
|
||||
|
||||
/// Same as `push`, but without asserting, in order to use it from
|
||||
/// `rebuild`.
|
||||
fn push_internal(&mut self, element: E) {
|
||||
each_relevant_element_hash(element, |hash| {
|
||||
self.filter.insert_hash(hash);
|
||||
});
|
||||
self.elements.push(unsafe { SendElement::new(element) });
|
||||
}
|
||||
|
||||
/// Pop the last element in the bloom filter and return it.
|
||||
fn pop(&mut self) -> Option<E> {
|
||||
let popped = self.elements.pop().map(|el| *el);
|
||||
|
||||
if let Some(popped) = popped {
|
||||
popped.remove_from_bloom_filter(&mut self.filter);
|
||||
each_relevant_element_hash(popped, |hash| {
|
||||
self.filter.remove_hash(hash);
|
||||
})
|
||||
}
|
||||
|
||||
popped
|
||||
|
@ -103,8 +134,7 @@ impl<E: TElement> StyleBloom<E> {
|
|||
self.clear();
|
||||
|
||||
while let Some(parent) = element.parent_element() {
|
||||
parent.insert_into_bloom_filter(&mut *self.filter);
|
||||
self.elements.push(unsafe { SendElement::new(parent) });
|
||||
self.push_internal(parent);
|
||||
element = parent;
|
||||
}
|
||||
|
||||
|
@ -194,7 +224,7 @@ impl<E: TElement> StyleBloom<E> {
|
|||
|
||||
// Let's collect the parents we are going to need to insert once we've
|
||||
// found the common one.
|
||||
let mut parents_to_insert = vec![];
|
||||
let mut parents_to_insert = SmallVec::<[E; 8]>::new();
|
||||
|
||||
// If the bloom filter still doesn't have enough elements, the common
|
||||
// parent is up in the dom.
|
||||
|
@ -216,10 +246,12 @@ impl<E: TElement> StyleBloom<E> {
|
|||
// Not-so-happy case: Parent's don't match, so we need to keep going up
|
||||
// until we find a common ancestor.
|
||||
//
|
||||
// Gecko currently models native anonymous content that conceptually hangs
|
||||
// off the document (such as scrollbars) as a separate subtree from the
|
||||
// document root. Thus it's possible with Gecko that we do not find any
|
||||
// common ancestor.
|
||||
// Gecko currently models native anonymous content that conceptually
|
||||
// hangs off the document (such as scrollbars) as a separate subtree
|
||||
// from the document root.
|
||||
//
|
||||
// Thus it's possible with Gecko that we do not find any common
|
||||
// ancestor.
|
||||
while **self.elements.last().unwrap() != common_parent {
|
||||
parents_to_insert.push(common_parent);
|
||||
self.pop().unwrap();
|
||||
|
|
|
@ -17,13 +17,13 @@ use euclid::Size2D;
|
|||
use fnv::FnvHashMap;
|
||||
use font_metrics::FontMetricsProvider;
|
||||
#[cfg(feature = "gecko")] use gecko_bindings::structs;
|
||||
use matching::StyleSharingCandidateCache;
|
||||
#[cfg(feature = "servo")] use parking_lot::RwLock;
|
||||
#[cfg(feature = "gecko")] use properties::ComputedValues;
|
||||
use selector_parser::SnapshotMap;
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
#[cfg(feature = "servo")] use servo_config::opts;
|
||||
use shared_lock::StylesheetGuards;
|
||||
use sharing::StyleSharingCandidateCache;
|
||||
#[cfg(feature = "servo")] use std::collections::HashMap;
|
||||
#[cfg(feature = "gecko")] use std::env;
|
||||
use std::fmt;
|
||||
|
|
|
@ -4,15 +4,14 @@
|
|||
|
||||
//! Per-node data used in style calculation.
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use context::SharedStyleContext;
|
||||
use dom::TElement;
|
||||
use properties::ComputedValues;
|
||||
use properties::longhands::display::computed_value as display;
|
||||
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use restyle_hints::{HintComputationContext, RestyleReplacements, RestyleHint};
|
||||
use rule_tree::StrongRuleNode;
|
||||
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage};
|
||||
use shared_lock::StylesheetGuards;
|
||||
#[cfg(feature = "servo")] use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "servo")] use std::hash::BuildHasherDefault;
|
||||
|
@ -197,21 +196,18 @@ impl StoredRestyleHint {
|
|||
// In the middle of an animation only restyle, we don't need to
|
||||
// propagate any restyle hints, and we need to remove ourselves.
|
||||
if traversal_flags.for_animation_only() {
|
||||
self.0.remove(RestyleHint::for_animations());
|
||||
self.0.remove_animation_hints();
|
||||
return Self::empty();
|
||||
}
|
||||
|
||||
debug_assert!(!self.0.intersects(RestyleHint::for_animations()),
|
||||
debug_assert!(!self.0.has_animation_hint(),
|
||||
"There should not be any animation restyle hints \
|
||||
during normal traversal");
|
||||
|
||||
// Else we should clear ourselves, and return the propagated hint.
|
||||
let hint = mem::replace(&mut self.0, RestyleHint::empty());
|
||||
StoredRestyleHint(if hint.contains(RESTYLE_DESCENDANTS) {
|
||||
RESTYLE_SELF | RESTYLE_DESCENDANTS
|
||||
} else {
|
||||
RestyleHint::empty()
|
||||
})
|
||||
let new_hint = mem::replace(&mut self.0, RestyleHint::empty())
|
||||
.propagate_for_non_animation_restyle();
|
||||
StoredRestyleHint(new_hint)
|
||||
}
|
||||
|
||||
/// Creates an empty `StoredRestyleHint`.
|
||||
|
@ -222,25 +218,25 @@ impl StoredRestyleHint {
|
|||
/// Creates a restyle hint that forces the whole subtree to be restyled,
|
||||
/// including the element.
|
||||
pub fn subtree() -> Self {
|
||||
StoredRestyleHint(RESTYLE_SELF | RESTYLE_DESCENDANTS)
|
||||
StoredRestyleHint(RestyleHint::subtree())
|
||||
}
|
||||
|
||||
/// Creates a restyle hint that forces the element and all its later
|
||||
/// siblings to have their whole subtrees restyled, including the elements
|
||||
/// themselves.
|
||||
pub fn subtree_and_later_siblings() -> Self {
|
||||
StoredRestyleHint(RESTYLE_SELF | RESTYLE_DESCENDANTS | RESTYLE_LATER_SIBLINGS)
|
||||
StoredRestyleHint(RestyleHint::subtree_and_later_siblings())
|
||||
}
|
||||
|
||||
/// Returns true if the hint indicates that our style may be invalidated.
|
||||
pub fn has_self_invalidations(&self) -> bool {
|
||||
self.0.intersects(RestyleHint::for_self())
|
||||
self.0.affects_self()
|
||||
}
|
||||
|
||||
/// Returns true if the hint indicates that our sibling's style may be
|
||||
/// invalidated.
|
||||
pub fn has_sibling_invalidations(&self) -> bool {
|
||||
self.0.intersects(RESTYLE_LATER_SIBLINGS)
|
||||
self.0.affects_later_siblings()
|
||||
}
|
||||
|
||||
/// Whether the restyle hint is empty (nothing requires to be restyled).
|
||||
|
@ -249,13 +245,18 @@ impl StoredRestyleHint {
|
|||
}
|
||||
|
||||
/// Insert another restyle hint, effectively resulting in the union of both.
|
||||
pub fn insert(&mut self, other: &Self) {
|
||||
self.0 |= other.0
|
||||
pub fn insert(&mut self, other: Self) {
|
||||
self.0.insert(other.0)
|
||||
}
|
||||
|
||||
/// Insert another restyle hint, effectively resulting in the union of both.
|
||||
pub fn insert_from(&mut self, other: &Self) {
|
||||
self.0.insert_from(&other.0)
|
||||
}
|
||||
|
||||
/// Returns true if the hint has animation-only restyle.
|
||||
pub fn has_animation_hint(&self) -> bool {
|
||||
self.0.intersects(RestyleHint::for_animations())
|
||||
self.0.has_animation_hint()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +356,7 @@ pub enum RestyleKind {
|
|||
MatchAndCascade,
|
||||
/// We need to recascade with some replacement rule, such as the style
|
||||
/// attribute, or animation rules.
|
||||
CascadeWithReplacements(RestyleHint),
|
||||
CascadeWithReplacements(RestyleReplacements),
|
||||
/// We only need to recascade, for example, because only inherited
|
||||
/// properties in the parent changed.
|
||||
CascadeOnly,
|
||||
|
@ -369,18 +370,19 @@ impl ElementData {
|
|||
/// explicit sibling restyle hints from the stored restyle hint.
|
||||
///
|
||||
/// Returns true if later siblings must be restyled.
|
||||
pub fn compute_final_hint<E: TElement>(
|
||||
pub fn compute_final_hint<'a, E: TElement>(
|
||||
&mut self,
|
||||
element: E,
|
||||
context: &SharedStyleContext)
|
||||
shared_context: &SharedStyleContext,
|
||||
hint_context: HintComputationContext<'a, E>)
|
||||
-> bool
|
||||
{
|
||||
debug!("compute_final_hint: {:?}, {:?}",
|
||||
element,
|
||||
context.traversal_flags);
|
||||
shared_context.traversal_flags);
|
||||
|
||||
let mut hint = match self.get_restyle() {
|
||||
Some(r) => r.hint.0,
|
||||
Some(r) => r.hint.0.clone(),
|
||||
None => RestyleHint::empty(),
|
||||
};
|
||||
|
||||
|
@ -392,7 +394,11 @@ impl ElementData {
|
|||
element.implemented_pseudo_element());
|
||||
|
||||
if element.has_snapshot() && !element.handled_snapshot() {
|
||||
hint |= context.stylist.compute_restyle_hint(&element, context.snapshot_map);
|
||||
let snapshot_hint =
|
||||
shared_context.stylist.compute_restyle_hint(&element,
|
||||
shared_context,
|
||||
hint_context);
|
||||
hint.insert(snapshot_hint);
|
||||
unsafe { element.set_handled_snapshot() }
|
||||
debug_assert!(element.handled_snapshot());
|
||||
}
|
||||
|
@ -401,8 +407,7 @@ impl ElementData {
|
|||
|
||||
// If the hint includes a directive for later siblings, strip it out and
|
||||
// notify the caller to modify the base hint for future siblings.
|
||||
let later_siblings = hint.contains(RESTYLE_LATER_SIBLINGS);
|
||||
hint.remove(RESTYLE_LATER_SIBLINGS);
|
||||
let later_siblings = hint.remove_later_siblings_hint();
|
||||
|
||||
// Insert the hint, overriding the previous hint. This effectively takes
|
||||
// care of removing the later siblings restyle hint.
|
||||
|
@ -444,13 +449,13 @@ impl ElementData {
|
|||
debug_assert!(self.restyle.is_some());
|
||||
let restyle_data = self.restyle.as_ref().unwrap();
|
||||
|
||||
let hint = restyle_data.hint.0;
|
||||
if hint.contains(RESTYLE_SELF) {
|
||||
let hint = &restyle_data.hint.0;
|
||||
if hint.match_self() {
|
||||
return RestyleKind::MatchAndCascade;
|
||||
}
|
||||
|
||||
if !hint.is_empty() {
|
||||
return RestyleKind::CascadeWithReplacements(hint);
|
||||
return RestyleKind::CascadeWithReplacements(hint.replacements);
|
||||
}
|
||||
|
||||
debug_assert!(restyle_data.recascade,
|
||||
|
@ -506,6 +511,24 @@ impl ElementData {
|
|||
true
|
||||
}
|
||||
|
||||
/// Return true if important rules are different.
|
||||
/// We use this to make sure the cascade of off-main thread animations is correct.
|
||||
/// Note: Ignore custom properties for now because we only support opacity and transform
|
||||
/// properties for animations running on compositor. Actually, we only care about opacity
|
||||
/// and transform for now, but it's fine to compare all properties and let the user
|
||||
/// the check which properties do they want.
|
||||
/// If it costs too much, get_properties_overriding_animations() should return a set
|
||||
/// containing only opacity and transform properties.
|
||||
pub fn important_rules_are_different(&self,
|
||||
rules: &StrongRuleNode,
|
||||
guards: &StylesheetGuards) -> bool {
|
||||
debug_assert!(self.has_styles());
|
||||
let (important_rules, _custom) =
|
||||
self.styles().primary.rules.get_properties_overriding_animations(&guards);
|
||||
let (other_important_rules, _custom) = rules.get_properties_overriding_animations(&guards);
|
||||
important_rules != other_important_rules
|
||||
}
|
||||
|
||||
/// Returns true if the Element has a RestyleData.
|
||||
pub fn has_restyle(&self) -> bool {
|
||||
self.restyle.is_some()
|
||||
|
|
|
@ -2164,6 +2164,8 @@ cfg_if! {
|
|||
pub static nsGkAtoms_onreloadpage: *mut nsIAtom;
|
||||
#[link_name = "_ZN9nsGkAtoms3remE"]
|
||||
pub static nsGkAtoms_rem: *mut nsIAtom;
|
||||
#[link_name = "_ZN9nsGkAtoms6remoteE"]
|
||||
pub static nsGkAtoms_remote: *mut nsIAtom;
|
||||
#[link_name = "_ZN9nsGkAtoms13removeelementE"]
|
||||
pub static nsGkAtoms_removeelement: *mut nsIAtom;
|
||||
#[link_name = "_ZN9nsGkAtoms21renderingobserverlistE"]
|
||||
|
@ -7179,6 +7181,8 @@ cfg_if! {
|
|||
pub static nsGkAtoms_onreloadpage: *mut nsIAtom;
|
||||
#[link_name = "?rem@nsGkAtoms@@2PEAVnsIAtom@@EA"]
|
||||
pub static nsGkAtoms_rem: *mut nsIAtom;
|
||||
#[link_name = "?remote@nsGkAtoms@@2PEAVnsIAtom@@EA"]
|
||||
pub static nsGkAtoms_remote: *mut nsIAtom;
|
||||
#[link_name = "?removeelement@nsGkAtoms@@2PEAVnsIAtom@@EA"]
|
||||
pub static nsGkAtoms_removeelement: *mut nsIAtom;
|
||||
#[link_name = "?renderingobserverlist@nsGkAtoms@@2PEAVnsIAtom@@EA"]
|
||||
|
@ -12194,6 +12198,8 @@ cfg_if! {
|
|||
pub static nsGkAtoms_onreloadpage: *mut nsIAtom;
|
||||
#[link_name = "\x01?rem@nsGkAtoms@@2PAVnsIAtom@@A"]
|
||||
pub static nsGkAtoms_rem: *mut nsIAtom;
|
||||
#[link_name = "\x01?remote@nsGkAtoms@@2PAVnsIAtom@@A"]
|
||||
pub static nsGkAtoms_remote: *mut nsIAtom;
|
||||
#[link_name = "\x01?removeelement@nsGkAtoms@@2PAVnsIAtom@@A"]
|
||||
pub static nsGkAtoms_removeelement: *mut nsIAtom;
|
||||
#[link_name = "\x01?renderingobserverlist@nsGkAtoms@@2PAVnsIAtom@@A"]
|
||||
|
@ -17212,6 +17218,8 @@ macro_rules! atom {
|
|||
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_onreloadpage as *mut _) } };
|
||||
("rem") =>
|
||||
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_rem as *mut _) } };
|
||||
("remote") =>
|
||||
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_remote as *mut _) } };
|
||||
("removeelement") =>
|
||||
{ unsafe { $crate::string_cache::atom_macro::atom_from_static($crate::string_cache::atom_macro::nsGkAtoms_removeelement as *mut _) } };
|
||||
("renderingobserverlist") =>
|
||||
|
|
|
@ -10,6 +10,7 @@ use gecko_bindings::structs::mozilla::css::URLValue;
|
|||
use gecko_bindings::structs::mozilla::Side;
|
||||
use gecko_bindings::structs::RawGeckoAnimationPropertySegment;
|
||||
use gecko_bindings::structs::RawGeckoComputedTiming;
|
||||
use gecko_bindings::structs::RawGeckoCSSPropertyIDList;
|
||||
use gecko_bindings::structs::RawGeckoDocument;
|
||||
use gecko_bindings::structs::RawGeckoElement;
|
||||
use gecko_bindings::structs::RawGeckoKeyframeList;
|
||||
|
@ -48,6 +49,7 @@ use gecko_bindings::structs::nsCSSCounterStyleRule;
|
|||
use gecko_bindings::structs::nsCSSFontFaceRule;
|
||||
use gecko_bindings::structs::nsCSSKeyword;
|
||||
use gecko_bindings::structs::nsCSSPropertyID;
|
||||
use gecko_bindings::structs::nsCSSPropertyIDSet;
|
||||
use gecko_bindings::structs::nsCSSShadowArray;
|
||||
use gecko_bindings::structs::nsCSSUnit;
|
||||
use gecko_bindings::structs::nsCSSValue;
|
||||
|
@ -200,6 +202,92 @@ use gecko_bindings::structs::ParsingMode;
|
|||
use gecko_bindings::structs::InheritTarget;
|
||||
use gecko_bindings::structs::URLMatchingFunction;
|
||||
pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray<usize>;
|
||||
pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>;
|
||||
pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>;
|
||||
pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;
|
||||
pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;
|
||||
pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;
|
||||
pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;
|
||||
enum RawServoStyleSetVoid { }
|
||||
pub struct RawServoStyleSet(RawServoStyleSetVoid);
|
||||
pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned<StyleChildrenIterator>;
|
||||
pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<StyleChildrenIterator>;
|
||||
pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;
|
||||
pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;
|
||||
pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;
|
||||
pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;
|
||||
enum StyleChildrenIteratorVoid { }
|
||||
pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);
|
||||
pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned<ServoElementSnapshot>;
|
||||
pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<ServoElementSnapshot>;
|
||||
pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;
|
||||
pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;
|
||||
pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;
|
||||
pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;
|
||||
pub type RawServoAnimationValueMapOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoAnimationValueMap>;
|
||||
pub type RawServoAnimationValueMapOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoAnimationValueMap>;
|
||||
pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;
|
||||
pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;
|
||||
pub type RawServoAnimationValueMapBorrowedMut<'a> = &'a mut RawServoAnimationValueMap;
|
||||
pub type RawServoAnimationValueMapBorrowedMutOrNull<'a> = Option<&'a mut RawServoAnimationValueMap>;
|
||||
enum RawServoAnimationValueMapVoid { }
|
||||
pub struct RawServoAnimationValueMap(RawServoAnimationValueMapVoid);
|
||||
pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;
|
||||
pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;
|
||||
pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;
|
||||
pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;
|
||||
pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;
|
||||
pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;
|
||||
pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;
|
||||
pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;
|
||||
pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;
|
||||
pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;
|
||||
pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;
|
||||
pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;
|
||||
pub type nsCSSPropertyIDSetBorrowed<'a> = &'a nsCSSPropertyIDSet;
|
||||
pub type nsCSSPropertyIDSetBorrowedOrNull<'a> = Option<&'a nsCSSPropertyIDSet>;
|
||||
pub type nsCSSPropertyIDSetBorrowedMut<'a> = &'a mut nsCSSPropertyIDSet;
|
||||
pub type nsCSSPropertyIDSetBorrowedMutOrNull<'a> = Option<&'a mut nsCSSPropertyIDSet>;
|
||||
pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;
|
||||
pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;
|
||||
pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;
|
||||
pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;
|
||||
pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;
|
||||
pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;
|
||||
pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;
|
||||
pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;
|
||||
pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;
|
||||
pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;
|
||||
pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;
|
||||
pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;
|
||||
pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;
|
||||
pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;
|
||||
pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;
|
||||
pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowed<'a> = &'a RawGeckoCSSPropertyIDList;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowedOrNull<'a> = Option<&'a RawGeckoCSSPropertyIDList>;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowedMut<'a> = &'a mut RawGeckoCSSPropertyIDList;
|
||||
pub type RawGeckoCSSPropertyIDListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoCSSPropertyIDList>;
|
||||
pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;
|
||||
pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;
|
||||
pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;
|
||||
pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;
|
||||
pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;
|
||||
pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;
|
||||
pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;
|
||||
pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;
|
||||
pub type RawGeckoServoStyleRuleListBorrowed<'a> = &'a RawGeckoServoStyleRuleList;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoServoStyleRuleList>;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedMut<'a> = &'a mut RawGeckoServoStyleRuleList;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoServoStyleRuleList>;
|
||||
pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoCssRules>;
|
||||
pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;
|
||||
pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;
|
||||
|
@ -274,84 +362,6 @@ pub type RawServoRuleNodeBorrowed<'a> = &'a RawServoRuleNode;
|
|||
pub type RawServoRuleNodeBorrowedOrNull<'a> = Option<&'a RawServoRuleNode>;
|
||||
enum RawServoRuleNodeVoid { }
|
||||
pub struct RawServoRuleNode(RawServoRuleNodeVoid);
|
||||
pub type RawServoStyleSetOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoStyleSet>;
|
||||
pub type RawServoStyleSetOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoStyleSet>;
|
||||
pub type RawServoStyleSetBorrowed<'a> = &'a RawServoStyleSet;
|
||||
pub type RawServoStyleSetBorrowedOrNull<'a> = Option<&'a RawServoStyleSet>;
|
||||
pub type RawServoStyleSetBorrowedMut<'a> = &'a mut RawServoStyleSet;
|
||||
pub type RawServoStyleSetBorrowedMutOrNull<'a> = Option<&'a mut RawServoStyleSet>;
|
||||
enum RawServoStyleSetVoid { }
|
||||
pub struct RawServoStyleSet(RawServoStyleSetVoid);
|
||||
pub type StyleChildrenIteratorOwned = ::gecko_bindings::sugar::ownership::Owned<StyleChildrenIterator>;
|
||||
pub type StyleChildrenIteratorOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<StyleChildrenIterator>;
|
||||
pub type StyleChildrenIteratorBorrowed<'a> = &'a StyleChildrenIterator;
|
||||
pub type StyleChildrenIteratorBorrowedOrNull<'a> = Option<&'a StyleChildrenIterator>;
|
||||
pub type StyleChildrenIteratorBorrowedMut<'a> = &'a mut StyleChildrenIterator;
|
||||
pub type StyleChildrenIteratorBorrowedMutOrNull<'a> = Option<&'a mut StyleChildrenIterator>;
|
||||
enum StyleChildrenIteratorVoid { }
|
||||
pub struct StyleChildrenIterator(StyleChildrenIteratorVoid);
|
||||
pub type ServoElementSnapshotOwned = ::gecko_bindings::sugar::ownership::Owned<ServoElementSnapshot>;
|
||||
pub type ServoElementSnapshotOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<ServoElementSnapshot>;
|
||||
pub type ServoElementSnapshotBorrowed<'a> = &'a ServoElementSnapshot;
|
||||
pub type ServoElementSnapshotBorrowedOrNull<'a> = Option<&'a ServoElementSnapshot>;
|
||||
pub type ServoElementSnapshotBorrowedMut<'a> = &'a mut ServoElementSnapshot;
|
||||
pub type ServoElementSnapshotBorrowedMutOrNull<'a> = Option<&'a mut ServoElementSnapshot>;
|
||||
pub type RawServoAnimationValueMapOwned = ::gecko_bindings::sugar::ownership::Owned<RawServoAnimationValueMap>;
|
||||
pub type RawServoAnimationValueMapOwnedOrNull = ::gecko_bindings::sugar::ownership::OwnedOrNull<RawServoAnimationValueMap>;
|
||||
pub type RawServoAnimationValueMapBorrowed<'a> = &'a RawServoAnimationValueMap;
|
||||
pub type RawServoAnimationValueMapBorrowedOrNull<'a> = Option<&'a RawServoAnimationValueMap>;
|
||||
pub type RawServoAnimationValueMapBorrowedMut<'a> = &'a mut RawServoAnimationValueMap;
|
||||
pub type RawServoAnimationValueMapBorrowedMutOrNull<'a> = Option<&'a mut RawServoAnimationValueMap>;
|
||||
enum RawServoAnimationValueMapVoid { }
|
||||
pub struct RawServoAnimationValueMap(RawServoAnimationValueMapVoid);
|
||||
pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;
|
||||
pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;
|
||||
pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;
|
||||
pub type RawGeckoElementBorrowedOrNull<'a> = Option<&'a RawGeckoElement>;
|
||||
pub type RawGeckoDocumentBorrowed<'a> = &'a RawGeckoDocument;
|
||||
pub type RawGeckoDocumentBorrowedOrNull<'a> = Option<&'a RawGeckoDocument>;
|
||||
pub type RawServoDeclarationBlockStrongBorrowed<'a> = &'a RawServoDeclarationBlockStrong;
|
||||
pub type RawServoDeclarationBlockStrongBorrowedOrNull<'a> = Option<&'a RawServoDeclarationBlockStrong>;
|
||||
pub type RawGeckoPresContextBorrowed<'a> = &'a RawGeckoPresContext;
|
||||
pub type RawGeckoPresContextBorrowedOrNull<'a> = Option<&'a RawGeckoPresContext>;
|
||||
pub type RawGeckoStyleAnimationListBorrowed<'a> = &'a RawGeckoStyleAnimationList;
|
||||
pub type RawGeckoStyleAnimationListBorrowedOrNull<'a> = Option<&'a RawGeckoStyleAnimationList>;
|
||||
pub type nsCSSValueBorrowed<'a> = &'a nsCSSValue;
|
||||
pub type nsCSSValueBorrowedOrNull<'a> = Option<&'a nsCSSValue>;
|
||||
pub type nsCSSValueBorrowedMut<'a> = &'a mut nsCSSValue;
|
||||
pub type nsCSSValueBorrowedMutOrNull<'a> = Option<&'a mut nsCSSValue>;
|
||||
pub type nsTimingFunctionBorrowed<'a> = &'a nsTimingFunction;
|
||||
pub type nsTimingFunctionBorrowedOrNull<'a> = Option<&'a nsTimingFunction>;
|
||||
pub type nsTimingFunctionBorrowedMut<'a> = &'a mut nsTimingFunction;
|
||||
pub type nsTimingFunctionBorrowedMutOrNull<'a> = Option<&'a mut nsTimingFunction>;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowed<'a> = &'a RawGeckoAnimationPropertySegment;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationPropertySegment>;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowedMut<'a> = &'a mut RawGeckoAnimationPropertySegment;
|
||||
pub type RawGeckoAnimationPropertySegmentBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationPropertySegment>;
|
||||
pub type RawGeckoAnimationValueListBorrowed<'a> = &'a RawGeckoAnimationValueList;
|
||||
pub type RawGeckoAnimationValueListBorrowedOrNull<'a> = Option<&'a RawGeckoAnimationValueList>;
|
||||
pub type RawGeckoAnimationValueListBorrowedMut<'a> = &'a mut RawGeckoAnimationValueList;
|
||||
pub type RawGeckoAnimationValueListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoAnimationValueList>;
|
||||
pub type RawGeckoComputedTimingBorrowed<'a> = &'a RawGeckoComputedTiming;
|
||||
pub type RawGeckoComputedTimingBorrowedOrNull<'a> = Option<&'a RawGeckoComputedTiming>;
|
||||
pub type RawGeckoComputedTimingBorrowedMut<'a> = &'a mut RawGeckoComputedTiming;
|
||||
pub type RawGeckoComputedTimingBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedTiming>;
|
||||
pub type RawGeckoKeyframeListBorrowed<'a> = &'a RawGeckoKeyframeList;
|
||||
pub type RawGeckoKeyframeListBorrowedOrNull<'a> = Option<&'a RawGeckoKeyframeList>;
|
||||
pub type RawGeckoKeyframeListBorrowedMut<'a> = &'a mut RawGeckoKeyframeList;
|
||||
pub type RawGeckoKeyframeListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoKeyframeList>;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowed<'a> = &'a RawGeckoComputedKeyframeValuesList;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowedOrNull<'a> = Option<&'a RawGeckoComputedKeyframeValuesList>;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowedMut<'a> = &'a mut RawGeckoComputedKeyframeValuesList;
|
||||
pub type RawGeckoComputedKeyframeValuesListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoComputedKeyframeValuesList>;
|
||||
pub type RawGeckoFontFaceRuleListBorrowed<'a> = &'a RawGeckoFontFaceRuleList;
|
||||
pub type RawGeckoFontFaceRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoFontFaceRuleList>;
|
||||
pub type RawGeckoFontFaceRuleListBorrowedMut<'a> = &'a mut RawGeckoFontFaceRuleList;
|
||||
pub type RawGeckoFontFaceRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoFontFaceRuleList>;
|
||||
pub type RawGeckoServoStyleRuleListBorrowed<'a> = &'a RawGeckoServoStyleRuleList;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedOrNull<'a> = Option<&'a RawGeckoServoStyleRuleList>;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedMut<'a> = &'a mut RawGeckoServoStyleRuleList;
|
||||
pub type RawGeckoServoStyleRuleListBorrowedMutOrNull<'a> = Option<&'a mut RawGeckoServoStyleRuleList>;
|
||||
|
||||
extern "C" {
|
||||
pub fn Gecko_EnsureTArrayCapacity(aArray: *mut ::std::os::raw::c_void,
|
||||
|
@ -864,10 +874,6 @@ extern "C" {
|
|||
pub fn Gecko_SetLayerImageImageValue(image: *mut nsStyleImage,
|
||||
aImageValue: *mut ImageValue);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_SetUrlImageValue(image: *mut nsStyleImage,
|
||||
uri: ServoBundledURI);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_SetImageElement(image: *mut nsStyleImage,
|
||||
atom: *mut nsIAtom);
|
||||
|
@ -891,10 +897,6 @@ extern "C" {
|
|||
pub fn Gecko_SetListStyleImageImageValue(style_struct: *mut nsStyleList,
|
||||
aImageValue: *mut ImageValue);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_SetListStyleImage(style_struct: *mut nsStyleList,
|
||||
uri: ServoBundledURI);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_CopyListStyleImageFrom(dest: *mut nsStyleList,
|
||||
src: *const nsStyleList);
|
||||
|
@ -907,10 +909,6 @@ extern "C" {
|
|||
pub fn Gecko_SetCursorImageValue(aCursor: *mut nsCursorImage,
|
||||
aImageValue: *mut ImageValue);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_SetCursorImage(cursor: *mut nsCursorImage,
|
||||
uri: ServoBundledURI);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_CopyCursorArrayFrom(dest: *mut nsStyleUserInterface,
|
||||
src: *const nsStyleUserInterface);
|
||||
|
@ -919,10 +917,6 @@ extern "C" {
|
|||
pub fn Gecko_SetContentDataImageValue(aList: *mut nsStyleContentData,
|
||||
aImageValue: *mut ImageValue);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_SetContentDataImage(content_data: *mut nsStyleContentData,
|
||||
uri: ServoBundledURI);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_SetContentDataArray(content_data: *mut nsStyleContentData,
|
||||
type_: nsStyleContentType, len: u32);
|
||||
|
@ -951,7 +945,8 @@ extern "C" {
|
|||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_CalcStyleDifference(oldstyle: *mut nsStyleContext,
|
||||
newstyle: ServoComputedValuesBorrowed)
|
||||
newstyle: ServoComputedValuesBorrowed,
|
||||
any_style_changed: *mut bool)
|
||||
-> nsChangeHint;
|
||||
}
|
||||
extern "C" {
|
||||
|
@ -1177,6 +1172,9 @@ extern "C" {
|
|||
extern "C" {
|
||||
pub fn Gecko_NewCSSValueSharedList(len: u32) -> *mut nsCSSValueSharedList;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_NewNoneTransform() -> *mut nsCSSValueSharedList;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_CSSValue_GetArrayItem(css_value: nsCSSValueBorrowedMut,
|
||||
index: i32) -> nsCSSValueBorrowedMut;
|
||||
|
@ -1363,6 +1361,10 @@ extern "C" {
|
|||
ident: *const u16,
|
||||
set_slow_selector: *mut bool) -> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_AddPropertyToSet(arg1: nsCSSPropertyIDSetBorrowedMut,
|
||||
arg2: nsCSSPropertyID);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_Construct_Default_nsStyleFont(ptr: *mut nsStyleFont,
|
||||
pres_context:
|
||||
|
@ -1733,6 +1735,9 @@ extern "C" {
|
|||
pub fn Servo_StyleSet_Init(pres_context: RawGeckoPresContextOwned)
|
||||
-> RawServoStyleSetOwned;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_StyleSet_Clear(set: RawServoStyleSetBorrowed);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_StyleSet_RebuildData(set: RawServoStyleSetBorrowed);
|
||||
}
|
||||
|
@ -2076,6 +2081,14 @@ extern "C" {
|
|||
pub fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID)
|
||||
-> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_GetProperties_Overriding_Animation(arg1:
|
||||
RawGeckoElementBorrowed,
|
||||
arg2:
|
||||
RawGeckoCSSPropertyIDListBorrowed,
|
||||
arg3:
|
||||
nsCSSPropertyIDSetBorrowedMut);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Servo_AnimationValues_Interpolate(from:
|
||||
RawServoAnimationValueBorrowed,
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,6 +8,7 @@ use gecko_bindings::bindings;
|
|||
use gecko_bindings::structs;
|
||||
use gecko_bindings::structs::{nsChangeHint, nsStyleContext};
|
||||
use gecko_bindings::sugar::ownership::FFIArcHelpers;
|
||||
use matching::{StyleChange, StyleDifference};
|
||||
use properties::ComputedValues;
|
||||
use std::ops::{BitAnd, BitOr, BitOrAssign, Not};
|
||||
use stylearc::Arc;
|
||||
|
@ -38,22 +39,27 @@ impl GeckoRestyleDamage {
|
|||
self.0 == nsChangeHint(0)
|
||||
}
|
||||
|
||||
/// Computes a change hint given an old style (in the form of a
|
||||
/// `nsStyleContext`, and a new style (in the form of `ComputedValues`).
|
||||
/// Computes the `StyleDifference` (including the appropriate change hint)
|
||||
/// given an old style (in the form of a `nsStyleContext`, and a new style
|
||||
/// (in the form of `ComputedValues`).
|
||||
///
|
||||
/// Note that we could in theory just get two `ComputedValues` here and diff
|
||||
/// them, but Gecko has an interesting optimization when they mark accessed
|
||||
/// structs, so they effectively only diff structs that have ever been
|
||||
/// accessed from layout.
|
||||
pub fn compute(source: &nsStyleContext,
|
||||
new_style: &Arc<ComputedValues>) -> Self {
|
||||
pub fn compute_style_difference(source: &nsStyleContext,
|
||||
new_style: &Arc<ComputedValues>)
|
||||
-> StyleDifference {
|
||||
// TODO(emilio): Const-ify this?
|
||||
let context = source as *const nsStyleContext as *mut nsStyleContext;
|
||||
let mut any_style_changed: bool = false;
|
||||
let hint = unsafe {
|
||||
bindings::Gecko_CalcStyleDifference(context,
|
||||
new_style.as_borrowed_opt().unwrap())
|
||||
new_style.as_borrowed_opt().unwrap(),
|
||||
&mut any_style_changed)
|
||||
};
|
||||
GeckoRestyleDamage(hint)
|
||||
let change = if any_style_changed { StyleChange::Changed } else { StyleChange::Unchanged };
|
||||
StyleDifference::new(GeckoRestyleDamage(hint), change)
|
||||
}
|
||||
|
||||
/// Returns true if this restyle damage contains all the damage of |other|.
|
||||
|
|
|
@ -79,6 +79,8 @@ extern crate selectors;
|
|||
#[cfg(feature = "servo")] extern crate servo_url;
|
||||
extern crate smallvec;
|
||||
#[macro_use]
|
||||
extern crate style_derive;
|
||||
#[macro_use]
|
||||
extern crate style_traits;
|
||||
extern crate time;
|
||||
#[allow(unused_extern_crates)]
|
||||
|
@ -119,6 +121,7 @@ pub mod rule_tree;
|
|||
pub mod scoped_tls;
|
||||
pub mod selector_parser;
|
||||
pub mod shared_lock;
|
||||
pub mod sharing;
|
||||
pub mod stylist;
|
||||
#[cfg(feature = "servo")] #[allow(unsafe_code)] pub mod servo;
|
||||
pub mod sequential;
|
||||
|
|
|
@ -38,19 +38,6 @@ macro_rules! define_numbered_css_keyword_enum {
|
|||
}
|
||||
}
|
||||
|
||||
/// A macro used to implement HasViewportPercentage trait
|
||||
/// for a given type that may never contain viewport units.
|
||||
macro_rules! no_viewport_percentage {
|
||||
($name: ident) => {
|
||||
impl $crate::values::HasViewportPercentage for $name {
|
||||
#[inline]
|
||||
fn has_viewport_percentage(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// A macro for implementing `ComputedValueAsSpecified`, `Parse`
|
||||
/// and `HasViewportPercentage` traits for the enums defined
|
||||
/// using `define_css_keyword_enum` macro.
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -127,6 +127,15 @@ class Keyword(object):
|
|||
def maybe_cast(self, type_str):
|
||||
return "as " + type_str if self.needs_cast() else ""
|
||||
|
||||
def casted_constant_name(self, value, cast_type):
|
||||
if cast_type is None:
|
||||
raise TypeError("We should specify the cast_type.")
|
||||
|
||||
if self.gecko_enum_prefix is None:
|
||||
return cast_type.upper() + "_" + self.gecko_constant(value)
|
||||
else:
|
||||
return cast_type.upper() + "_" + self.gecko_constant(value).upper().replace("::", "_")
|
||||
|
||||
|
||||
def arg_to_bool(arg):
|
||||
if isinstance(arg, bool):
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче