Merge autoland to m-c, a=merge

MozReview-Commit-ID: JM3dPUdZm4k
This commit is contained in:
Phil Ringnalda 2017-05-21 12:59:59 -07:00
Родитель dabae514fa 120f3c37ca
Коммит 2113ba8f80
193 изменённых файлов: 19371 добавлений и 8110 удалений

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

@ -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"]

39
servo/Cargo.lock сгенерированный
Просмотреть файл

@ -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):

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше