зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound, a=merge
This commit is contained in:
Коммит
b53f4d8806
|
@ -99,11 +99,15 @@ this.tabs = class extends ExtensionAPI {
|
|||
|
||||
let self = {
|
||||
tabs: {
|
||||
onActivated: new WindowEventManager(context, "tabs.onActivated", "TabSelect", (fire, event) => {
|
||||
let nativeTab = event.originalTarget;
|
||||
let tabId = tabTracker.getId(nativeTab);
|
||||
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
|
||||
fire.async({tabId, windowId});
|
||||
onActivated: new SingletonEventManager(context, "tabs.onActivated", fire => {
|
||||
let listener = (eventName, event) => {
|
||||
fire.async(event);
|
||||
};
|
||||
|
||||
tabTracker.on("tab-activated", listener);
|
||||
return () => {
|
||||
tabTracker.off("tab-activated", listener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
onCreated: new SingletonEventManager(context, "tabs.onCreated", fire => {
|
||||
|
@ -123,11 +127,15 @@ this.tabs = class extends ExtensionAPI {
|
|||
* the tabId in an array to match the API.
|
||||
* @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/Tabs/onHighlighted
|
||||
*/
|
||||
onHighlighted: new WindowEventManager(context, "tabs.onHighlighted", "TabSelect", (fire, event) => {
|
||||
let nativeTab = event.originalTarget;
|
||||
let tabIds = [tabTracker.getId(nativeTab)];
|
||||
let windowId = windowTracker.getId(nativeTab.ownerGlobal);
|
||||
fire.async({tabIds, windowId});
|
||||
onHighlighted: new SingletonEventManager(context, "tabs.onHighlighted", fire => {
|
||||
let listener = (eventName, event) => {
|
||||
fire.async({tabIds: [event.tabId], windowId: event.windowId});
|
||||
};
|
||||
|
||||
tabTracker.on("tab-activated", listener);
|
||||
return () => {
|
||||
tabTracker.off("tab-activated", listener);
|
||||
};
|
||||
}).api(),
|
||||
|
||||
onAttached: new SingletonEventManager(context, "tabs.onAttached", fire => {
|
||||
|
|
|
@ -155,6 +155,7 @@ class TabTracker extends TabTrackerBase {
|
|||
|
||||
windowTracker.addListener("TabClose", this);
|
||||
windowTracker.addListener("TabOpen", this);
|
||||
windowTracker.addListener("TabSelect", this);
|
||||
windowTracker.addOpenListener(this._handleWindowOpen);
|
||||
windowTracker.addCloseListener(this._handleWindowClose);
|
||||
|
||||
|
@ -262,6 +263,14 @@ class TabTracker extends TabTrackerBase {
|
|||
this.emitRemoved(nativeTab, false);
|
||||
}
|
||||
break;
|
||||
|
||||
case "TabSelect":
|
||||
// Because we are delaying calling emitCreated above, we also need to
|
||||
// delay sending this event because it shouldn't fire before onCreated.
|
||||
Promise.resolve().then(() => {
|
||||
this.emitActivated(nativeTab);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,6 +316,9 @@ class TabTracker extends TabTrackerBase {
|
|||
for (let nativeTab of window.gBrowser.tabs) {
|
||||
this.emitCreated(nativeTab);
|
||||
}
|
||||
|
||||
// emitActivated to trigger tab.onActivated/tab.onHighlighted for a newly opened window.
|
||||
this.emitActivated(window.gBrowser.tabs[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,6 +340,19 @@ class TabTracker extends TabTrackerBase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a "tab-activated" event for the given tab element.
|
||||
*
|
||||
* @param {NativeTab} nativeTab
|
||||
* The tab element which has been activated.
|
||||
* @private
|
||||
*/
|
||||
emitActivated(nativeTab) {
|
||||
this.emit("tab-activated", {
|
||||
tabId: this.getId(nativeTab),
|
||||
windowId: windowTracker.getId(nativeTab.ownerGlobal)});
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a "tab-attached" event for the given tab element.
|
||||
*
|
||||
|
|
|
@ -25,6 +25,14 @@ add_task(function* testTabEvents() {
|
|||
}
|
||||
});
|
||||
|
||||
browser.tabs.onCreated.addListener((info) => {
|
||||
if (info.id in events) {
|
||||
events[info.id].push("onCreated");
|
||||
} else {
|
||||
events[info.id] = ["onCreated"];
|
||||
}
|
||||
});
|
||||
|
||||
browser.tabs.onHighlighted.addListener((info) => {
|
||||
if (info.tabIds[0] in events) {
|
||||
events[info.tabIds[0]].push("onHighlighted");
|
||||
|
@ -43,7 +51,10 @@ add_task(function* testTabEvents() {
|
|||
async function expectEvents(tabId, expectedEvents) {
|
||||
browser.test.log(`Expecting events: ${expectedEvents.join(", ")}`);
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, 0));
|
||||
// Wait up to 5000 ms for the expected number of events.
|
||||
for (let i = 0; i < 50 && (!events[tabId] || events[tabId].length < expectedEvents.length); i++) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
|
||||
browser.test.assertEq(expectedEvents.length, events[tabId].length,
|
||||
`Got expected number of events for ${tabId}`);
|
||||
|
@ -61,23 +72,58 @@ add_task(function* testTabEvents() {
|
|||
* @param {number} windowId
|
||||
*/
|
||||
async function openTab(windowId) {
|
||||
browser.test.assertEq(0, Object.keys(events).length,
|
||||
"No events remaining before testing openTab.");
|
||||
|
||||
let tab = await browser.tabs.create({windowId});
|
||||
|
||||
tabIds.push(tab.id);
|
||||
browser.test.log(`Opened tab ${tab.id}`);
|
||||
|
||||
await expectEvents(tab.id, [
|
||||
"onCreated",
|
||||
"onActivated",
|
||||
"onHighlighted",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new window and asserts that the correct events are fired.
|
||||
*
|
||||
* @param {Array} urls A list of urls for which to open tabs in the new window.
|
||||
*/
|
||||
async function openWindow(urls) {
|
||||
browser.test.assertEq(0, Object.keys(events).length,
|
||||
"No events remaining before testing openWindow.");
|
||||
|
||||
let window = await browser.windows.create({url: urls});
|
||||
browser.test.log(`Opened new window ${window.id}`);
|
||||
|
||||
for (let [i] of urls.entries()) {
|
||||
let tab = window.tabs[i];
|
||||
tabIds.push(tab.id);
|
||||
|
||||
let expectedEvents = [
|
||||
"onCreated",
|
||||
"onActivated",
|
||||
"onHighlighted",
|
||||
];
|
||||
if (i !== 0) {
|
||||
expectedEvents.splice(1);
|
||||
}
|
||||
await expectEvents(window.tabs[i].id, expectedEvents);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights an existing tab and asserts that the correct events are fired.
|
||||
*
|
||||
* @param {number} tabId
|
||||
*/
|
||||
async function highlightTab(tabId) {
|
||||
browser.test.assertEq(0, Object.keys(events).length,
|
||||
"No events remaining before testing highlightTab.");
|
||||
|
||||
browser.test.log(`Highlighting tab ${tabId}`);
|
||||
let tab = await browser.tabs.update(tabId, {active: true});
|
||||
|
||||
|
@ -107,6 +153,15 @@ add_task(function* testTabEvents() {
|
|||
highlightTab(tabIds[2]),
|
||||
]);
|
||||
|
||||
await Promise.all([
|
||||
openWindow(["http://example.com"]),
|
||||
openWindow(["http://example.com", "http://example.org"]),
|
||||
openWindow(["http://example.com", "http://example.org", "http://example.net"]),
|
||||
]);
|
||||
|
||||
browser.test.assertEq(0, Object.keys(events).length,
|
||||
"No events remaining after tests.");
|
||||
|
||||
await Promise.all(tabIds.map(id => browser.tabs.remove(id)));
|
||||
|
||||
browser.test.notifyPass("tabs.highlight");
|
||||
|
|
|
@ -13,12 +13,6 @@ const { getAbbreviatedMimeType } = require("../utils/request-utils");
|
|||
|
||||
const { div, span } = DOM;
|
||||
|
||||
const CONTENT_MIME_TYPE_ABBREVIATIONS = {
|
||||
"ecmascript": "js",
|
||||
"javascript": "js",
|
||||
"x-javascript": "js"
|
||||
};
|
||||
|
||||
const RequestListColumnType = createClass({
|
||||
displayName: "RequestListColumnType",
|
||||
|
||||
|
@ -35,7 +29,6 @@ const RequestListColumnType = createClass({
|
|||
let abbrevType;
|
||||
if (mimeType) {
|
||||
abbrevType = getAbbreviatedMimeType(mimeType);
|
||||
abbrevType = CONTENT_MIME_TYPE_ABBREVIATIONS[abbrevType] || abbrevType;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const CONTENT_MIME_TYPE_ABBREVIATIONS = {
|
||||
"ecmascript": "js",
|
||||
"javascript": "js",
|
||||
"x-javascript": "js"
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts any urlencoded form data sections (e.g. "?foo=bar&baz=42") from a
|
||||
* POST request.
|
||||
|
@ -112,7 +118,8 @@ function getAbbreviatedMimeType(mimeType) {
|
|||
if (!mimeType) {
|
||||
return "";
|
||||
}
|
||||
return (mimeType.split(";")[0].split("/")[1] || "").split("+")[0];
|
||||
let abbrevType = (mimeType.split(";")[0].split("/")[1] || "").split("+")[0];
|
||||
return CONTENT_MIME_TYPE_ABBREVIATIONS[abbrevType] || abbrevType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -316,12 +316,12 @@ EffectCompositor::PostRestyleForAnimation(dom::Element* aElement,
|
|||
"Restyle request during restyling should be requested only on "
|
||||
"the main-thread. e.g. after the parallel traversal");
|
||||
if (ServoStyleSet::IsInServoTraversal()) {
|
||||
// FIXME: Bug 1302946: We will handle eRestyle_CSSTransitions.
|
||||
MOZ_ASSERT(hint == eRestyle_CSSAnimations);
|
||||
MOZ_ASSERT(hint == eRestyle_CSSAnimations ||
|
||||
hint == eRestyle_CSSTransitions);
|
||||
|
||||
// We can't call Servo_NoteExplicitHints here since AtomicRefCell does not
|
||||
// allow us mutate ElementData of the |aElement| in SequentialTask.
|
||||
// Instead we call Servo_NoteExplicitHints for the element in PreTraverse() right
|
||||
// Instead we call Servo_NoteExplicitHints for the element in PreTraverse()
|
||||
// which will be called right before the second traversal that we do for
|
||||
// updating CSS animations.
|
||||
// In that case PreTraverse() will return true so that we know to do the
|
||||
|
@ -982,8 +982,10 @@ EffectCompositor::PreTraverseInSubtree(Element* aRoot)
|
|||
MOZ_ASSERT(mPresContext->RestyleManager()->IsServo());
|
||||
|
||||
bool foundElementsNeedingRestyle = false;
|
||||
for (auto& elementsToRestyle : mElementsToRestyle) {
|
||||
for (auto iter = elementsToRestyle.Iter(); !iter.Done(); iter.Next()) {
|
||||
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) {
|
||||
|
@ -1003,7 +1005,10 @@ EffectCompositor::PreTraverseInSubtree(Element* aRoot)
|
|||
// We can't call PostRestyleEvent directly here since we are still in the
|
||||
// middle of the servo traversal.
|
||||
mPresContext->RestyleManager()->AsServo()->
|
||||
PostRestyleEventForAnimations(target.mElement, eRestyle_CSSAnimations);
|
||||
PostRestyleEventForAnimations(target.mElement,
|
||||
cascadeLevel == CascadeLevel::Transitions
|
||||
? eRestyle_CSSTransitions
|
||||
: eRestyle_CSSAnimations);
|
||||
|
||||
foundElementsNeedingRestyle = true;
|
||||
|
||||
|
@ -1048,14 +1053,21 @@ EffectCompositor::PreTraverse(dom::Element* aElement, nsIAtom* aPseudoTagOrNull)
|
|||
|
||||
PseudoElementHashEntry::KeyType key = { aElement, pseudoType };
|
||||
|
||||
for (auto& elementsToRestyle : mElementsToRestyle) {
|
||||
if (!elementsToRestyle.Get(key)) {
|
||||
|
||||
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.
|
||||
continue;
|
||||
}
|
||||
|
||||
mPresContext->RestyleManager()->AsServo()->
|
||||
PostRestyleEventForAnimations(aElement, eRestyle_CSSAnimations);
|
||||
PostRestyleEventForAnimations(aElement,
|
||||
cascadeLevel == CascadeLevel::Transitions
|
||||
? eRestyle_CSSTransitions
|
||||
: eRestyle_CSSAnimations);
|
||||
|
||||
EffectSet* effects = EffectSet::GetEffectSet(aElement, pseudoType);
|
||||
if (effects) {
|
||||
|
@ -1066,7 +1078,7 @@ EffectCompositor::PreTraverse(dom::Element* aElement, nsIAtom* aPseudoTagOrNull)
|
|||
}
|
||||
}
|
||||
|
||||
elementsToRestyle.Remove(key);
|
||||
elementSet.Remove(key);
|
||||
found = true;
|
||||
}
|
||||
return found;
|
||||
|
|
|
@ -1132,12 +1132,15 @@ mozilla::ipc::IPCResult
|
|||
ContentChild::RecvInitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
|
||||
Endpoint<PImageBridgeChild>&& aImageBridge,
|
||||
Endpoint<PVRManagerChild>&& aVRBridge,
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
|
||||
nsTArray<uint32_t>&& namespaces)
|
||||
{
|
||||
if (!CompositorBridgeChild::InitForContent(Move(aCompositor))) {
|
||||
MOZ_ASSERT(namespaces.Length() == 2);
|
||||
|
||||
if (!CompositorBridgeChild::InitForContent(Move(aCompositor), namespaces[0])) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
if (!ImageBridgeChild::InitForContent(Move(aImageBridge))) {
|
||||
if (!ImageBridgeChild::InitForContent(Move(aImageBridge), namespaces[1])) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
if (!gfx::VRManagerChild::InitForContent(Move(aVRBridge))) {
|
||||
|
@ -1151,8 +1154,10 @@ mozilla::ipc::IPCResult
|
|||
ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor,
|
||||
Endpoint<PImageBridgeChild>&& aImageBridge,
|
||||
Endpoint<PVRManagerChild>&& aVRBridge,
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager)
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
|
||||
nsTArray<uint32_t>&& namespaces)
|
||||
{
|
||||
MOZ_ASSERT(namespaces.Length() == 2);
|
||||
nsTArray<RefPtr<TabChild>> tabs = TabChild::GetAll();
|
||||
|
||||
// Zap all the old layer managers we have lying around.
|
||||
|
@ -1163,10 +1168,10 @@ ContentChild::RecvReinitRendering(Endpoint<PCompositorBridgeChild>&& aCompositor
|
|||
}
|
||||
|
||||
// Re-establish singleton bridges to the compositor.
|
||||
if (!CompositorBridgeChild::ReinitForContent(Move(aCompositor))) {
|
||||
if (!CompositorBridgeChild::ReinitForContent(Move(aCompositor), namespaces[0])) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
if (!ImageBridgeChild::ReinitForContent(Move(aImageBridge))) {
|
||||
if (!ImageBridgeChild::ReinitForContent(Move(aImageBridge), namespaces[1])) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
if (!gfx::VRManagerChild::ReinitForContent(Move(aVRBridge))) {
|
||||
|
|
|
@ -158,14 +158,16 @@ public:
|
|||
Endpoint<PCompositorBridgeChild>&& aCompositor,
|
||||
Endpoint<PImageBridgeChild>&& aImageBridge,
|
||||
Endpoint<PVRManagerChild>&& aVRBridge,
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
|
||||
nsTArray<uint32_t>&& namespaces) override;
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RecvReinitRendering(
|
||||
Endpoint<PCompositorBridgeChild>&& aCompositor,
|
||||
Endpoint<PImageBridgeChild>&& aImageBridge,
|
||||
Endpoint<PVRManagerChild>&& aVRBridge,
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager) override;
|
||||
Endpoint<PVideoDecoderManagerChild>&& aVideoManager,
|
||||
nsTArray<uint32_t>&& namespaces) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSetProcessSandbox(const MaybeFileDesc& aBroker) override;
|
||||
|
||||
|
|
|
@ -2301,20 +2301,23 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
|||
Endpoint<PImageBridgeChild> imageBridge;
|
||||
Endpoint<PVRManagerChild> vrBridge;
|
||||
Endpoint<PVideoDecoderManagerChild> videoManager;
|
||||
nsTArray<uint32_t> namespaces;
|
||||
|
||||
DebugOnly<bool> opened = gpm->CreateContentBridges(
|
||||
OtherPid(),
|
||||
&compositor,
|
||||
&imageBridge,
|
||||
&vrBridge,
|
||||
&videoManager);
|
||||
&videoManager,
|
||||
&namespaces);
|
||||
MOZ_ASSERT(opened);
|
||||
|
||||
Unused << SendInitRendering(
|
||||
Move(compositor),
|
||||
Move(imageBridge),
|
||||
Move(vrBridge),
|
||||
Move(videoManager));
|
||||
Move(videoManager),
|
||||
Move(namespaces));
|
||||
|
||||
gpm->AddListener(this);
|
||||
}
|
||||
|
@ -2449,20 +2452,23 @@ ContentParent::OnCompositorUnexpectedShutdown()
|
|||
Endpoint<PImageBridgeChild> imageBridge;
|
||||
Endpoint<PVRManagerChild> vrBridge;
|
||||
Endpoint<PVideoDecoderManagerChild> videoManager;
|
||||
nsTArray<uint32_t> namespaces;
|
||||
|
||||
DebugOnly<bool> opened = gpm->CreateContentBridges(
|
||||
OtherPid(),
|
||||
&compositor,
|
||||
&imageBridge,
|
||||
&vrBridge,
|
||||
&videoManager);
|
||||
&videoManager,
|
||||
&namespaces);
|
||||
MOZ_ASSERT(opened);
|
||||
|
||||
Unused << SendReinitRendering(
|
||||
Move(compositor),
|
||||
Move(imageBridge),
|
||||
Move(vrBridge),
|
||||
Move(videoManager));
|
||||
Move(videoManager),
|
||||
Move(namespaces));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -354,7 +354,8 @@ child:
|
|||
Endpoint<PCompositorBridgeChild> compositor,
|
||||
Endpoint<PImageBridgeChild> imageBridge,
|
||||
Endpoint<PVRManagerChild> vr,
|
||||
Endpoint<PVideoDecoderManagerChild> video);
|
||||
Endpoint<PVideoDecoderManagerChild> video,
|
||||
uint32_t[] namespaces);
|
||||
|
||||
// Re-create the rendering stack using the given endpoints. This is sent
|
||||
// after the compositor process has crashed. The new endpoints may be to a
|
||||
|
@ -363,7 +364,8 @@ child:
|
|||
Endpoint<PCompositorBridgeChild> compositor,
|
||||
Endpoint<PImageBridgeChild> bridge,
|
||||
Endpoint<PVRManagerChild> vr,
|
||||
Endpoint<PVideoDecoderManagerChild> video);
|
||||
Endpoint<PVideoDecoderManagerChild> video,
|
||||
uint32_t[] namespaces);
|
||||
|
||||
/**
|
||||
* Enable system-level sandboxing features, if available. Can
|
||||
|
|
|
@ -753,12 +753,12 @@ ADTSTrackDemuxer::GetNextFrame(const adts::Frame& aFrame)
|
|||
UpdateState(aFrame);
|
||||
|
||||
frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds();
|
||||
frame->mDuration = Duration(1).ToMicroseconds();
|
||||
frame->mDuration = Duration(1);
|
||||
frame->mTimecode = frame->mTime;
|
||||
frame->mKeyframe = true;
|
||||
|
||||
MOZ_ASSERT(frame->mTime >= 0);
|
||||
MOZ_ASSERT(frame->mDuration > 0);
|
||||
MOZ_ASSERT(frame->mDuration.IsPositive());
|
||||
|
||||
ADTSLOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
|
||||
" mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
|
||||
|
|
|
@ -605,12 +605,12 @@ MP3TrackDemuxer::GetNextFrame(const MediaByteRange& aRange)
|
|||
UpdateState(aRange);
|
||||
|
||||
frame->mTime = Duration(mFrameIndex - 1).ToMicroseconds();
|
||||
frame->mDuration = Duration(1).ToMicroseconds();
|
||||
frame->mDuration = Duration(1);
|
||||
frame->mTimecode = frame->mTime;
|
||||
frame->mKeyframe = true;
|
||||
|
||||
MOZ_ASSERT(frame->mTime >= 0);
|
||||
MOZ_ASSERT(frame->mDuration > 0);
|
||||
MOZ_ASSERT(frame->mDuration.IsPositive());
|
||||
|
||||
if (mNumParsedFrames == 1) {
|
||||
// First frame parsed, let's read VBR info if available.
|
||||
|
|
|
@ -22,6 +22,7 @@ using namespace mozilla::gfx;
|
|||
using layers::ImageContainer;
|
||||
using layers::PlanarYCbCrImage;
|
||||
using layers::PlanarYCbCrData;
|
||||
using media::TimeUnit;
|
||||
|
||||
const char* AudioData::sTypeName = "audio";
|
||||
const char* VideoData::sTypeName = "video";
|
||||
|
@ -173,7 +174,7 @@ VideoData::VideoData(int64_t aOffset,
|
|||
, mFrameID(aFrameID)
|
||||
, mSentToCompositor(false)
|
||||
{
|
||||
NS_ASSERTION(mDuration >= 0, "Frame must have non-negative duration.");
|
||||
MOZ_ASSERT(!mDuration.IsNegative(), "Frame must have non-negative duration.");
|
||||
mKeyframe = aKeyframe;
|
||||
mTimecode = aTimecode;
|
||||
}
|
||||
|
@ -222,10 +223,9 @@ VideoData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
|||
}
|
||||
|
||||
void
|
||||
VideoData::UpdateDuration(int64_t aDuration)
|
||||
VideoData::UpdateDuration(const TimeUnit& aDuration)
|
||||
{
|
||||
MOZ_ASSERT(aDuration >= 0);
|
||||
|
||||
MOZ_ASSERT(!aDuration.IsNegative());
|
||||
mDuration = aDuration;
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ VideoData::UpdateTimestamp(int64_t aTimestamp)
|
|||
MOZ_ASSERT(updatedDuration >= 0);
|
||||
|
||||
mTime = aTimestamp;
|
||||
mDuration = updatedDuration;
|
||||
mDuration = TimeUnit::FromMicroseconds(updatedDuration);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -286,7 +286,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
ImageContainer* aContainer,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const TimeUnit& aDuration,
|
||||
const YCbCrBuffer& aBuffer,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
|
@ -297,7 +297,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
// send to media streams if necessary.
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aDuration.ToMicroseconds(),
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
|
@ -311,7 +311,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aDuration.ToMicroseconds(),
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
|
@ -370,7 +370,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
ImageContainer* aContainer,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const TimeUnit& aDuration,
|
||||
const YCbCrBuffer& aBuffer,
|
||||
const YCbCrBuffer::Plane &aAlphaPlane,
|
||||
bool aKeyframe,
|
||||
|
@ -382,7 +382,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
// send to media streams if necessary.
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aDuration.ToMicroseconds(),
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
|
@ -396,7 +396,7 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
|
|||
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aDuration.ToMicroseconds(),
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aInfo.mDisplay,
|
||||
|
@ -436,14 +436,14 @@ already_AddRefed<VideoData>
|
|||
VideoData::CreateFromImage(const IntSize& aDisplay,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const TimeUnit& aDuration,
|
||||
const RefPtr<Image>& aImage,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode)
|
||||
{
|
||||
RefPtr<VideoData> v(new VideoData(aOffset,
|
||||
aTime,
|
||||
aDuration,
|
||||
aDuration.ToMicroseconds(),
|
||||
aKeyframe,
|
||||
aTimecode,
|
||||
aDisplay,
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "nsTArray.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "TimeUnits.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -295,7 +296,7 @@ public:
|
|||
, mOffset(aOffset)
|
||||
, mTime(aTimestamp)
|
||||
, mTimecode(aTimestamp)
|
||||
, mDuration(aDuration)
|
||||
, mDuration(media::TimeUnit::FromMicroseconds(aDuration))
|
||||
, mFrames(aFrames)
|
||||
, mKeyframe(false)
|
||||
{
|
||||
|
@ -315,14 +316,14 @@ public:
|
|||
int64_t mTimecode;
|
||||
|
||||
// Duration of sample, in microseconds.
|
||||
int64_t mDuration;
|
||||
media::TimeUnit mDuration;
|
||||
|
||||
// Amount of frames for contained data.
|
||||
const uint32_t mFrames;
|
||||
|
||||
bool mKeyframe;
|
||||
|
||||
int64_t GetEndTime() const { return mTime + mDuration; }
|
||||
int64_t GetEndTime() const { return mTime + mDuration.ToMicroseconds(); }
|
||||
|
||||
bool AdjustForStartTime(int64_t aStartTime)
|
||||
{
|
||||
|
@ -350,7 +351,6 @@ protected:
|
|||
, mOffset(0)
|
||||
, mTime(0)
|
||||
, mTimecode(0)
|
||||
, mDuration(0)
|
||||
, mFrames(aFrames)
|
||||
, mKeyframe(false)
|
||||
{
|
||||
|
@ -489,7 +489,7 @@ public:
|
|||
ImageContainer* aContainer,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const media::TimeUnit& aDuration,
|
||||
const YCbCrBuffer& aBuffer,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
|
@ -500,7 +500,7 @@ public:
|
|||
ImageContainer* aContainer,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const media::TimeUnit& aDuration,
|
||||
const YCbCrBuffer& aBuffer,
|
||||
const YCbCrBuffer::Plane& aAlphaPlane,
|
||||
bool aKeyframe,
|
||||
|
@ -511,7 +511,7 @@ public:
|
|||
const VideoInfo& aInfo,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const media::TimeUnit& aDuration,
|
||||
layers::TextureClient* aBuffer,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode,
|
||||
|
@ -521,7 +521,7 @@ public:
|
|||
const IntSize& aDisplay,
|
||||
int64_t aOffset,
|
||||
int64_t aTime,
|
||||
int64_t aDuration,
|
||||
const media::TimeUnit& aDuration,
|
||||
const RefPtr<Image>& aImage,
|
||||
bool aKeyframe,
|
||||
int64_t aTimecode);
|
||||
|
@ -558,7 +558,7 @@ public:
|
|||
void MarkSentToCompositor();
|
||||
bool IsSentToCompositor() { return mSentToCompositor; }
|
||||
|
||||
void UpdateDuration(int64_t aDuration);
|
||||
void UpdateDuration(const media::TimeUnit& aDuration);
|
||||
void UpdateTimestamp(int64_t aTimestamp);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -1724,7 +1724,8 @@ MediaFormatReader::NotifyNewOutput(
|
|||
auto& decoder = GetDecoderData(aTrack);
|
||||
for (auto& sample : aResults) {
|
||||
LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64,
|
||||
TrackTypeToStr(aTrack), sample->mTime, sample->mDuration);
|
||||
TrackTypeToStr(aTrack), sample->mTime,
|
||||
sample->mDuration.ToMicroseconds());
|
||||
decoder.mOutput.AppendElement(sample);
|
||||
decoder.mNumSamplesOutput++;
|
||||
decoder.mNumOfConsecutiveError = 0;
|
||||
|
|
|
@ -165,6 +165,10 @@ public:
|
|||
return mValue.value() > 0;
|
||||
}
|
||||
|
||||
bool IsNegative() const {
|
||||
return mValue.value() < 0;
|
||||
}
|
||||
|
||||
bool operator == (const TimeUnit& aOther) const {
|
||||
MOZ_ASSERT(IsValid() && aOther.IsValid());
|
||||
return mValue.value() == aOther.mValue.value();
|
||||
|
|
|
@ -142,7 +142,7 @@ bool AndroidMediaReader::DecodeVideoFrame(bool& aKeyframeSkip,
|
|||
int64_t durationUs;
|
||||
mPlugin->GetDuration(mPlugin, &durationUs);
|
||||
durationUs = std::max<int64_t>(durationUs - mLastVideoFrame->mTime, 0);
|
||||
mLastVideoFrame->UpdateDuration(durationUs);
|
||||
mLastVideoFrame->UpdateDuration(TimeUnit::FromMicroseconds(durationUs));
|
||||
mVideoQueue.Push(mLastVideoFrame);
|
||||
mLastVideoFrame = nullptr;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ bool AndroidMediaReader::DecodeVideoFrame(bool& aKeyframeSkip,
|
|||
v = VideoData::CreateFromImage(mInfo.mVideo.mDisplay,
|
||||
pos,
|
||||
frame.mTimeUs,
|
||||
1, // We don't know the duration yet.
|
||||
TimeUnit::FromMicroseconds(1), // We don't know the duration yet.
|
||||
currentImage,
|
||||
frame.mKeyFrame,
|
||||
-1);
|
||||
|
@ -221,7 +221,7 @@ bool AndroidMediaReader::DecodeVideoFrame(bool& aKeyframeSkip,
|
|||
mDecoder->GetImageContainer(),
|
||||
pos,
|
||||
frame.mTimeUs,
|
||||
1, // We don't know the duration yet.
|
||||
TimeUnit::FromMicroseconds(1), // We don't know the duration yet.
|
||||
b,
|
||||
frame.mKeyFrame,
|
||||
-1,
|
||||
|
@ -248,7 +248,7 @@ bool AndroidMediaReader::DecodeVideoFrame(bool& aKeyframeSkip,
|
|||
// timestamp of the previous frame. We can then return the previously
|
||||
// decoded frame, and it will have a valid timestamp.
|
||||
int64_t duration = v->mTime - mLastVideoFrame->mTime;
|
||||
mLastVideoFrame->UpdateDuration(duration);
|
||||
mLastVideoFrame->UpdateDuration(TimeUnit::FromMicroseconds(duration));
|
||||
|
||||
// We have the start time of the next frame, so we can push the previous
|
||||
// frame into the queue, except if the end time is below the threshold,
|
||||
|
|
|
@ -981,13 +981,13 @@ FlacTrackDemuxer::GetNextFrame(const flac::Frame& aFrame)
|
|||
}
|
||||
|
||||
frame->mTime = aFrame.Time().ToMicroseconds();
|
||||
frame->mDuration = aFrame.Duration().ToMicroseconds();
|
||||
frame->mDuration = aFrame.Duration();
|
||||
frame->mTimecode = frame->mTime;
|
||||
frame->mOffset = aFrame.Offset();
|
||||
frame->mKeyframe = true;
|
||||
|
||||
MOZ_ASSERT(frame->mTime >= 0);
|
||||
MOZ_ASSERT(frame->mDuration >= 0);
|
||||
MOZ_ASSERT(!frame->mDuration.IsNegative());
|
||||
|
||||
return frame.forget();
|
||||
}
|
||||
|
|
|
@ -462,7 +462,8 @@ MP4TrackDemuxer::GetNextSample()
|
|||
"@ pts:%" PRId64 " dur:%" PRId64
|
||||
" dts:%" PRId64,
|
||||
keyframe ? "" : "non-", sample->mTime,
|
||||
sample->mDuration, sample->mTimecode)
|
||||
sample->mDuration.ToMicroseconds(),
|
||||
sample->mTimecode)
|
||||
.get());
|
||||
sample->mKeyframe = keyframe;
|
||||
}
|
||||
|
@ -472,7 +473,8 @@ MP4TrackDemuxer::GetNextSample()
|
|||
NS_WARNING(
|
||||
nsPrintfCString("Invalid H264 frame @ pts:%" PRId64 " dur:%" PRId64
|
||||
" dts:%" PRId64,
|
||||
sample->mTime, sample->mDuration, sample->mTimecode)
|
||||
sample->mTime, sample->mDuration.ToMicroseconds(),
|
||||
sample->mTimecode)
|
||||
.get());
|
||||
// We could reject the sample now, however demuxer errors are fatal.
|
||||
// So we keep the invalid frame, relying on the H264 decoder to
|
||||
|
|
|
@ -191,7 +191,7 @@ ChromiumCDMParent::InitCDMInputBuffer(gmp::CDMInputBuffer& aBuffer,
|
|||
crypto.mKeyId,
|
||||
crypto.mIV,
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mDuration.ToMicroseconds(),
|
||||
crypto.mPlainSizes,
|
||||
crypto.mEncryptedSizes,
|
||||
crypto.mValid);
|
||||
|
@ -636,15 +636,16 @@ ChromiumCDMParent::RecvDecoded(const CDMVideoFrame& aFrame)
|
|||
b.mPlanes[2].mSkip = 0;
|
||||
|
||||
gfx::IntRect pictureRegion(0, 0, aFrame.mImageWidth(), aFrame.mImageHeight());
|
||||
RefPtr<VideoData> v = VideoData::CreateAndCopyData(mVideoInfo,
|
||||
mImageContainer,
|
||||
mLastStreamOffset,
|
||||
aFrame.mTimestamp(),
|
||||
aFrame.mDuration(),
|
||||
b,
|
||||
false,
|
||||
-1,
|
||||
pictureRegion);
|
||||
RefPtr<VideoData> v = VideoData::CreateAndCopyData(
|
||||
mVideoInfo,
|
||||
mImageContainer,
|
||||
mLastStreamOffset,
|
||||
aFrame.mTimestamp(),
|
||||
media::TimeUnit::FromMicroseconds(aFrame.mDuration()),
|
||||
b,
|
||||
false,
|
||||
-1,
|
||||
pictureRegion);
|
||||
|
||||
// Return the shmem to the CDM so the shmem can be reused to send us
|
||||
// another frame.
|
||||
|
|
|
@ -45,13 +45,15 @@ VideoDecoderChild::RecvOutput(const VideoDataIPDL& aData)
|
|||
// it gets deallocated.
|
||||
RefPtr<Image> image = new GPUVideoImage(GetManager(), aData.sd(), aData.frameSize());
|
||||
|
||||
RefPtr<VideoData> video = VideoData::CreateFromImage(aData.display(),
|
||||
aData.base().offset(),
|
||||
aData.base().time(),
|
||||
aData.base().duration(),
|
||||
image,
|
||||
aData.base().keyframe(),
|
||||
aData.base().timecode());
|
||||
RefPtr<VideoData> video = VideoData::CreateFromImage(
|
||||
aData.display(),
|
||||
aData.base().offset(),
|
||||
aData.base().time(),
|
||||
media::TimeUnit::FromMicroseconds(aData.base().duration()),
|
||||
image,
|
||||
aData.base().keyframe(),
|
||||
aData.base().timecode());
|
||||
|
||||
mDecodedData.AppendElement(Move(video));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
@ -230,7 +232,7 @@ VideoDecoderChild::Decode(MediaRawData* aSample)
|
|||
MediaRawDataIPDL sample(MediaDataIPDL(aSample->mOffset,
|
||||
aSample->mTime,
|
||||
aSample->mTimecode,
|
||||
aSample->mDuration,
|
||||
aSample->mDuration.ToMicroseconds(),
|
||||
aSample->mFrames,
|
||||
aSample->mKeyframe),
|
||||
buffer);
|
||||
|
|
|
@ -139,7 +139,7 @@ VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData)
|
|||
data->mOffset = aData.base().offset();
|
||||
data->mTime = aData.base().time();
|
||||
data->mTimecode = aData.base().timecode();
|
||||
data->mDuration = aData.base().duration();
|
||||
data->mDuration = media::TimeUnit::FromMicroseconds(aData.base().duration());
|
||||
data->mKeyframe = aData.base().keyframe();
|
||||
|
||||
DeallocShmem(aData.buffer());
|
||||
|
@ -187,7 +187,8 @@ VideoDecoderParent::ProcessDecodedData(
|
|||
|
||||
VideoDataIPDL output(
|
||||
MediaDataIPDL(data->mOffset, data->mTime, data->mTimecode,
|
||||
data->mDuration, data->mFrames, data->mKeyframe),
|
||||
data->mDuration.ToMicroseconds(),
|
||||
data->mFrames, data->mKeyframe),
|
||||
video->mDisplay,
|
||||
texture ? texture->GetSize() : IntSize(),
|
||||
texture ? mParent->StoreImage(video->mImage, texture)
|
||||
|
|
|
@ -1465,7 +1465,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData)
|
|||
: TimeInterval(mAppendWindow.mStart, mAppendWindow.mEnd,
|
||||
trackBuffer.mLastFrameDuration.isSome()
|
||||
? trackBuffer.mLongestFrameDuration
|
||||
: TimeUnit::FromMicroseconds(aSamples[0]->mDuration));
|
||||
: aSamples[0]->mDuration);
|
||||
|
||||
TimeIntervals samplesRange;
|
||||
uint32_t sizeNewSamples = 0;
|
||||
|
@ -1491,7 +1491,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData)
|
|||
sample->mTime,
|
||||
sample->GetEndTime(),
|
||||
sample->mTimecode,
|
||||
sample->mDuration,
|
||||
sample->mDuration.ToMicroseconds(),
|
||||
sample->mKeyframe);
|
||||
|
||||
const TimeUnit sampleEndTime =
|
||||
|
@ -1527,7 +1527,7 @@ TrackBuffersManager::ProcessFrames(TrackBuffer& aSamples, TrackData& aTrackData)
|
|||
|
||||
TimeUnit sampleTime = TimeUnit::FromMicroseconds(sample->mTime);
|
||||
TimeUnit sampleTimecode = TimeUnit::FromMicroseconds(sample->mTimecode);
|
||||
TimeUnit sampleDuration = TimeUnit::FromMicroseconds(sample->mDuration);
|
||||
TimeUnit sampleDuration = sample->mDuration;
|
||||
TimeUnit timestampOffset = mSourceBufferAttributes->GetTimestampOffset();
|
||||
|
||||
TimeInterval sampleInterval =
|
||||
|
@ -1870,7 +1870,7 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
|||
lastRemovedIndex = i;
|
||||
}
|
||||
|
||||
int64_t maxSampleDuration = 0;
|
||||
TimeUnit maxSampleDuration;
|
||||
uint32_t sizeRemoved = 0;
|
||||
TimeIntervals removedIntervals;
|
||||
for (uint32_t i = firstRemovedIndex.ref(); i <= lastRemovedIndex; i++) {
|
||||
|
@ -1931,7 +1931,7 @@ TrackBuffersManager::RemoveFrames(const TimeIntervals& aIntervals,
|
|||
|
||||
// Recalculate sanitized buffered ranges.
|
||||
aTrackData.mSanitizedBufferedRanges = aTrackData.mBufferedRanges;
|
||||
aTrackData.mSanitizedBufferedRanges.SetFuzz(TimeUnit::FromMicroseconds(maxSampleDuration/2));
|
||||
aTrackData.mSanitizedBufferedRanges.SetFuzz(maxSampleDuration/2);
|
||||
|
||||
data.RemoveElementsAt(firstRemovedIndex.ref(),
|
||||
lastRemovedIndex - firstRemovedIndex.ref() + 1);
|
||||
|
@ -2244,7 +2244,7 @@ TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack,
|
|||
break;
|
||||
}
|
||||
nextSampleTimecode =
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration;
|
||||
nextSampleTime = TimeUnit::FromMicroseconds(sample->GetEndTime());
|
||||
parsed++;
|
||||
}
|
||||
|
@ -2360,7 +2360,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack,
|
|||
trackData.mNextGetSampleIndex.ref()++;
|
||||
// Estimate decode timestamp and timestamp of the next sample.
|
||||
TimeUnit nextSampleTimecode =
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration;
|
||||
TimeUnit nextSampleTime =
|
||||
TimeUnit::FromMicroseconds(sample->GetEndTime());
|
||||
const MediaRawData* nextSample =
|
||||
|
@ -2384,8 +2384,9 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack,
|
|||
return p.forget();
|
||||
}
|
||||
|
||||
if (trackData.mNextSampleTimecode.ToMicroseconds() >
|
||||
track.LastElement()->mTimecode + track.LastElement()->mDuration) {
|
||||
if (trackData.mNextSampleTimecode >
|
||||
TimeUnit::FromMicroseconds(track.LastElement()->mTimecode)
|
||||
+ track.LastElement()->mDuration) {
|
||||
// The next element is past our last sample. We're done.
|
||||
trackData.mNextGetSampleIndex = Some(uint32_t(track.Length()));
|
||||
aResult = NS_ERROR_DOM_MEDIA_END_OF_STREAM;
|
||||
|
@ -2417,7 +2418,7 @@ TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack,
|
|||
|
||||
trackData.mNextGetSampleIndex = Some(uint32_t(pos)+1);
|
||||
trackData.mNextSampleTimecode =
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration;
|
||||
trackData.mNextSampleTime =
|
||||
TimeUnit::FromMicroseconds(sample->GetEndTime());
|
||||
aResult = NS_OK;
|
||||
|
@ -2437,7 +2438,7 @@ TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack,
|
|||
const RefPtr<MediaRawData>& sample = track[i];
|
||||
TimeInterval sampleInterval{
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode),
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration)};
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration};
|
||||
|
||||
if (sampleInterval.ContainsStrict(trackData.mNextSampleTimecode)) {
|
||||
return i;
|
||||
|
@ -2453,7 +2454,7 @@ TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack,
|
|||
const RefPtr<MediaRawData>& sample = track[i];
|
||||
TimeInterval sampleInterval{
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode),
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration),
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration,
|
||||
aFuzz};
|
||||
|
||||
if (sampleInterval.ContainsWithStrictEnd(trackData.mNextSampleTimecode)) {
|
||||
|
@ -2514,7 +2515,7 @@ TrackBuffersManager::GetNextRandomAccessPoint(TrackInfo::TrackType aTrack,
|
|||
return TimeUnit::FromMicroseconds(sample->mTime);
|
||||
}
|
||||
nextSampleTimecode =
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
|
||||
TimeUnit::FromMicroseconds(sample->mTimecode) + sample->mDuration;
|
||||
nextSampleTime = TimeUnit::FromMicroseconds(sample->GetEndTime());
|
||||
}
|
||||
return TimeUnit::FromInfinity();
|
||||
|
|
|
@ -261,7 +261,7 @@ OggCodecState::PacketOutAsMediaRawData()
|
|||
|
||||
sample->mTimecode = packet->granulepos;
|
||||
sample->mTime = end_tstamp - duration;
|
||||
sample->mDuration = duration;
|
||||
sample->mDuration = media::TimeUnit::FromMicroseconds(duration);
|
||||
sample->mKeyframe = IsKeyframe(packet.get());
|
||||
sample->mEOS = packet->e_o_s;
|
||||
|
||||
|
|
|
@ -93,7 +93,8 @@ BlankAudioDataCreator::Create(MediaRawData* aSample)
|
|||
{
|
||||
// Convert duration to frames. We add 1 to duration to account for
|
||||
// rounding errors, so we get a consistent tone.
|
||||
CheckedInt64 frames = UsecsToFrames(aSample->mDuration+1, mSampleRate);
|
||||
CheckedInt64 frames = UsecsToFrames(
|
||||
aSample->mDuration.ToMicroseconds()+1, mSampleRate);
|
||||
if (!frames.isValid()
|
||||
|| !mChannelCount
|
||||
|| !mSampleRate
|
||||
|
@ -116,7 +117,7 @@ BlankAudioDataCreator::Create(MediaRawData* aSample)
|
|||
}
|
||||
RefPtr<AudioData> data(new AudioData(aSample->mOffset,
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mDuration.ToMicroseconds(),
|
||||
uint32_t(frames.value()),
|
||||
Move(samples),
|
||||
mChannelCount,
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
// send to media streams if necessary.
|
||||
RefPtr<VideoData> v(new VideoData(aSample->mOffset,
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mDuration.ToMicroseconds(),
|
||||
aSample->mKeyframe,
|
||||
aSample->mTimecode,
|
||||
gfx::IntSize(),
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
|
||||
// How much time duration of the media would we have decrypted inside the
|
||||
// time window if we did decrypt this block?
|
||||
TimeDuration sampleDuration = TimeDuration::FromMicroseconds(aSample->mDuration);
|
||||
TimeDuration sampleDuration = aSample->mDuration.ToTimeDuration();
|
||||
TimeDuration durationDecrypted = sampleDuration;
|
||||
for (const DecryptedJob& job : mDecrypts) {
|
||||
durationDecrypted += job.mSampleDuration;
|
||||
|
|
|
@ -62,16 +62,16 @@ GMPVideoDecoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
|
|||
|
||||
gfx::IntRect pictureRegion(
|
||||
0, 0, decodedFrame->Width(), decodedFrame->Height());
|
||||
RefPtr<VideoData> v =
|
||||
VideoData::CreateAndCopyData(mConfig,
|
||||
mImageContainer,
|
||||
mLastStreamOffset,
|
||||
decodedFrame->Timestamp(),
|
||||
decodedFrame->Duration(),
|
||||
b,
|
||||
false,
|
||||
-1,
|
||||
pictureRegion);
|
||||
RefPtr<VideoData> v = VideoData::CreateAndCopyData(
|
||||
mConfig,
|
||||
mImageContainer,
|
||||
mLastStreamOffset,
|
||||
decodedFrame->Timestamp(),
|
||||
media::TimeUnit::FromMicroseconds(decodedFrame->Duration()),
|
||||
b,
|
||||
false,
|
||||
-1,
|
||||
pictureRegion);
|
||||
RefPtr<GMPVideoDecoder> self = this;
|
||||
if (v) {
|
||||
mDecodedData.AppendElement(Move(v));
|
||||
|
@ -202,7 +202,7 @@ GMPVideoDecoder::CreateFrame(MediaRawData* aSample)
|
|||
frame->SetEncodedHeight(mConfig.mDisplay.height);
|
||||
frame->SetTimeStamp(aSample->mTime);
|
||||
frame->SetCompleteFrame(true);
|
||||
frame->SetDuration(aSample->mDuration);
|
||||
frame->SetDuration(aSample->mDuration.ToMicroseconds());
|
||||
frame->SetFrameType(aSample->mKeyframe ? kGMPKeyFrame : kGMPDeltaFrame);
|
||||
|
||||
return frame;
|
||||
|
|
|
@ -138,7 +138,8 @@ public:
|
|||
gl::OriginPos::BottomLeft);
|
||||
|
||||
RefPtr<VideoData> v = VideoData::CreateFromImage(
|
||||
inputInfo.mDisplaySize, offset, presentationTimeUs, inputInfo.mDurationUs,
|
||||
inputInfo.mDisplaySize, offset, presentationTimeUs,
|
||||
TimeUnit::FromMicroseconds(inputInfo.mDurationUs),
|
||||
img, !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME),
|
||||
presentationTimeUs);
|
||||
|
||||
|
@ -223,7 +224,8 @@ public:
|
|||
: &mConfig;
|
||||
MOZ_ASSERT(config);
|
||||
|
||||
InputInfo info(aSample->mDuration, config->mImage, config->mDisplay);
|
||||
InputInfo info(
|
||||
aSample->mDuration.ToMicroseconds(), config->mImage, config->mDisplay);
|
||||
mInputInfos.Insert(aSample->mTime, info);
|
||||
return RemoteDataDecoder::Decode(aSample);
|
||||
}
|
||||
|
|
|
@ -67,7 +67,8 @@ RefPtr<MediaDataDecoder::DecodePromise>
|
|||
AppleATDecoder::Decode(MediaRawData* aSample)
|
||||
{
|
||||
LOG("mp4 input sample %p %lld us %lld pts%s %llu bytes audio", aSample,
|
||||
aSample->mDuration, aSample->mTime, aSample->mKeyframe ? " keyframe" : "",
|
||||
aSample->mDuration.ToMicroseconds(), aSample->mTime,
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
(unsigned long long)aSample->Size());
|
||||
RefPtr<AppleATDecoder> self = this;
|
||||
RefPtr<MediaRawData> sample = aSample;
|
||||
|
|
|
@ -79,7 +79,7 @@ AppleVTDecoder::Decode(MediaRawData* aSample)
|
|||
LOG("mp4 input sample %p pts %lld duration %lld us%s %" PRIuSIZE " bytes",
|
||||
aSample,
|
||||
aSample->mTime,
|
||||
aSample->mDuration,
|
||||
aSample->mDuration.ToMicroseconds(),
|
||||
aSample->mKeyframe ? " keyframe" : "",
|
||||
aSample->Size());
|
||||
|
||||
|
@ -129,7 +129,8 @@ TimingInfoFromSample(MediaRawData* aSample)
|
|||
{
|
||||
CMSampleTimingInfo timestamp;
|
||||
|
||||
timestamp.duration = CMTimeMake(aSample->mDuration, USECS_PER_S);
|
||||
timestamp.duration = CMTimeMake(
|
||||
aSample->mDuration.ToMicroseconds(), USECS_PER_S);
|
||||
timestamp.presentationTimeStamp =
|
||||
CMTimeMake(aSample->mTime, USECS_PER_S);
|
||||
timestamp.decodeTimeStamp =
|
||||
|
@ -412,7 +413,7 @@ AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage,
|
|||
mImageContainer,
|
||||
aFrameRef.byte_offset,
|
||||
aFrameRef.composition_timestamp.ToMicroseconds(),
|
||||
aFrameRef.duration.ToMicroseconds(),
|
||||
aFrameRef.duration,
|
||||
buffer,
|
||||
aFrameRef.is_sync_point,
|
||||
aFrameRef.decode_timestamp.ToMicroseconds(),
|
||||
|
@ -432,7 +433,7 @@ AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage,
|
|||
VideoData::CreateFromImage(info.mDisplay,
|
||||
aFrameRef.byte_offset,
|
||||
aFrameRef.composition_timestamp.ToMicroseconds(),
|
||||
aFrameRef.duration.ToMicroseconds(),
|
||||
aFrameRef.duration,
|
||||
image.forget(),
|
||||
aFrameRef.is_sync_point,
|
||||
aFrameRef.decode_timestamp.ToMicroseconds());
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
explicit AppleFrameRef(const MediaRawData& aSample)
|
||||
: decode_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTimecode))
|
||||
, composition_timestamp(media::TimeUnit::FromMicroseconds(aSample.mTime))
|
||||
, duration(media::TimeUnit::FromMicroseconds(aSample.mDuration))
|
||||
, duration(aSample.mDuration)
|
||||
, byte_offset(aSample.mOffset)
|
||||
, is_sync_point(aSample.mKeyframe)
|
||||
{
|
||||
|
|
|
@ -241,7 +241,7 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample,
|
|||
// As such we instead use a map using the dts as key that we will retrieve
|
||||
// later.
|
||||
// The map will have a typical size of 16 entry.
|
||||
mDurationMap.Insert(aSample->mTimecode, aSample->mDuration);
|
||||
mDurationMap.Insert(aSample->mTimecode, aSample->mDuration.ToMicroseconds());
|
||||
|
||||
if (!PrepareFrame()) {
|
||||
NS_WARNING("FFmpeg h264 decoder failed to allocate frame.");
|
||||
|
@ -282,7 +282,7 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample,
|
|||
int64_t duration;
|
||||
if (!mDurationMap.Find(mFrame->pkt_dts, duration)) {
|
||||
NS_WARNING("Unable to retrieve duration from map");
|
||||
duration = aSample->mDuration;
|
||||
duration = aSample->mDuration.ToMicroseconds();
|
||||
// dts are probably incorrectly reported ; so clear the map as we're
|
||||
// unlikely to find them in the future anyway. This also guards
|
||||
// against the map becoming extremely big.
|
||||
|
@ -340,7 +340,7 @@ FFmpegVideoDecoder<LIBAV_VER>::DoDecode(MediaRawData* aSample,
|
|||
mImageContainer,
|
||||
aSample->mOffset,
|
||||
pts,
|
||||
duration,
|
||||
media::TimeUnit::FromMicroseconds(duration),
|
||||
b,
|
||||
!!mFrame->key_frame,
|
||||
-1,
|
||||
|
|
|
@ -995,7 +995,7 @@ MediaDataHelper::CreateYUV420VideoData(BufferData* aBufferData)
|
|||
mImageContainer,
|
||||
0, // Filled later by caller.
|
||||
0, // Filled later by caller.
|
||||
1, // We don't know the duration.
|
||||
media::TimeUnit::FromMicroseconds(1), // We don't know the duration.
|
||||
b,
|
||||
0, // Filled later by caller.
|
||||
-1,
|
||||
|
|
|
@ -672,7 +672,7 @@ WMFVideoMFTManager::Input(MediaRawData* aSample)
|
|||
&inputSample);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr) && inputSample != nullptr, hr);
|
||||
|
||||
mLastDuration = aSample->mDuration;
|
||||
mLastDuration = aSample->mDuration.ToMicroseconds();
|
||||
mLastTime = aSample->mTime;
|
||||
mSamplesCount++;
|
||||
|
||||
|
@ -839,7 +839,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
|||
mImageContainer,
|
||||
aStreamOffset,
|
||||
pts.ToMicroseconds(),
|
||||
duration.ToMicroseconds(),
|
||||
duration,
|
||||
b,
|
||||
false,
|
||||
-1,
|
||||
|
@ -866,7 +866,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
|||
VideoData::CreateFromImage(mVideoInfo.mDisplay,
|
||||
aStreamOffset,
|
||||
pts.ToMicroseconds(),
|
||||
duration.ToMicroseconds(),
|
||||
duration,
|
||||
image.forget(),
|
||||
false,
|
||||
-1);
|
||||
|
@ -904,7 +904,7 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
|
|||
RefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo.mDisplay,
|
||||
aStreamOffset,
|
||||
pts.ToMicroseconds(),
|
||||
duration.ToMicroseconds(),
|
||||
duration,
|
||||
image.forget(),
|
||||
false,
|
||||
-1);
|
||||
|
@ -1033,7 +1033,7 @@ WMFVideoMFTManager::Output(int64_t aStreamOffset,
|
|||
aOutData = frame;
|
||||
// Set the potentially corrected pts and duration.
|
||||
aOutData->mTime = pts.ToMicroseconds();
|
||||
aOutData->mDuration = duration.ToMicroseconds();
|
||||
aOutData->mDuration = duration;
|
||||
|
||||
if (mNullOutputCount) {
|
||||
mGotValidOutputAfterNullOutput = true;
|
||||
|
|
|
@ -534,17 +534,17 @@ WAVTrackDemuxer::GetNextChunk(const MediaByteRange& aRange)
|
|||
datachunk->mTime = Duration(mChunkIndex - 1).ToMicroseconds();
|
||||
|
||||
if (static_cast<uint32_t>(mChunkIndex) * DATA_CHUNK_SIZE < mDataLength) {
|
||||
datachunk->mDuration = Duration(1).ToMicroseconds();
|
||||
datachunk->mDuration = Duration(1);
|
||||
} else {
|
||||
uint32_t mBytesRemaining =
|
||||
mDataLength - mChunkIndex * DATA_CHUNK_SIZE;
|
||||
datachunk->mDuration = DurationFromBytes(mBytesRemaining).ToMicroseconds();
|
||||
datachunk->mDuration = DurationFromBytes(mBytesRemaining);
|
||||
}
|
||||
datachunk->mTimecode = datachunk->mTime;
|
||||
datachunk->mKeyframe = true;
|
||||
|
||||
MOZ_ASSERT(datachunk->mTime >= 0);
|
||||
MOZ_ASSERT(datachunk->mDuration >= 0);
|
||||
MOZ_ASSERT(!datachunk->mDuration.IsNegative());
|
||||
|
||||
return datachunk.forget();
|
||||
}
|
||||
|
|
|
@ -724,7 +724,7 @@ WebMDemuxer::GetNextPacket(TrackInfo::TrackType aType,
|
|||
}
|
||||
sample->mTimecode = tstamp;
|
||||
sample->mTime = tstamp;
|
||||
sample->mDuration = next_tstamp - tstamp;
|
||||
sample->mDuration = media::TimeUnit::FromMicroseconds(next_tstamp - tstamp);
|
||||
sample->mOffset = holder->Offset();
|
||||
sample->mKeyframe = isKeyframe;
|
||||
if (discardPadding && i == count - 1) {
|
||||
|
|
|
@ -82,6 +82,7 @@ GPUProcessManager::Shutdown()
|
|||
GPUProcessManager::GPUProcessManager()
|
||||
: mTaskFactory(this),
|
||||
mNextLayerTreeId(0),
|
||||
mNextNamespace(0),
|
||||
mNextResetSequenceNo(0),
|
||||
mNumProcessAttempts(0),
|
||||
mDeviceResetCount(0),
|
||||
|
@ -204,7 +205,7 @@ GPUProcessManager::EnsureImageBridgeChild()
|
|||
}
|
||||
|
||||
if (!EnsureGPUReady()) {
|
||||
ImageBridgeChild::InitSameProcess();
|
||||
ImageBridgeChild::InitSameProcess(AllocateNamespace());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -221,7 +222,7 @@ GPUProcessManager::EnsureImageBridgeChild()
|
|||
}
|
||||
|
||||
mGPUChild->SendInitImageBridge(Move(parentPipe));
|
||||
ImageBridgeChild::InitWithGPUProcess(Move(childPipe));
|
||||
ImageBridgeChild::InitWithGPUProcess(Move(childPipe), AllocateNamespace());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -600,7 +601,8 @@ GPUProcessManager::CreateTopLevelCompositor(nsBaseWidget* aWidget,
|
|||
aScale,
|
||||
aOptions,
|
||||
aUseExternalSurfaceSize,
|
||||
aSurfaceSize);
|
||||
aSurfaceSize,
|
||||
AllocateNamespace());
|
||||
}
|
||||
|
||||
RefPtr<CompositorSession>
|
||||
|
@ -629,7 +631,8 @@ GPUProcessManager::CreateRemoteSession(nsBaseWidget* aWidget,
|
|||
RefPtr<CompositorBridgeChild> child = CompositorBridgeChild::CreateRemote(
|
||||
mProcessToken,
|
||||
aLayerManager,
|
||||
Move(childPipe));
|
||||
Move(childPipe),
|
||||
AllocateNamespace());
|
||||
if (!child) {
|
||||
gfxCriticalNote << "Failed to create CompositorBridgeChild";
|
||||
return nullptr;
|
||||
|
@ -687,7 +690,8 @@ GPUProcessManager::CreateContentBridges(base::ProcessId aOtherProcess,
|
|||
ipc::Endpoint<PCompositorBridgeChild>* aOutCompositor,
|
||||
ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
|
||||
ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
|
||||
ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager)
|
||||
ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
|
||||
nsTArray<uint32_t>* aNamespaces)
|
||||
{
|
||||
if (!CreateContentCompositorBridge(aOtherProcess, aOutCompositor) ||
|
||||
!CreateContentImageBridge(aOtherProcess, aOutImageBridge) ||
|
||||
|
@ -698,6 +702,9 @@ GPUProcessManager::CreateContentBridges(base::ProcessId aOtherProcess,
|
|||
// VideoDeocderManager is only supported in the GPU process, so we allow this to be
|
||||
// fallible.
|
||||
CreateContentVideoDecoderManager(aOtherProcess, aOutVideoManager);
|
||||
// Allocates 2 namaspaces(for CompositorBridgeChild and ImageBridgeChild)
|
||||
aNamespaces->AppendElement(AllocateNamespace());
|
||||
aNamespaces->AppendElement(AllocateNamespace());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -881,6 +888,13 @@ GPUProcessManager::AllocateLayerTreeId()
|
|||
return ++mNextLayerTreeId;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GPUProcessManager::AllocateNamespace()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return ++mNextNamespace;
|
||||
}
|
||||
|
||||
bool
|
||||
GPUProcessManager::AllocateAndConnectLayerTreeId(PCompositorBridgeChild* aCompositorBridge,
|
||||
base::ProcessId aOtherPid,
|
||||
|
|
|
@ -95,7 +95,8 @@ public:
|
|||
ipc::Endpoint<PCompositorBridgeChild>* aOutCompositor,
|
||||
ipc::Endpoint<PImageBridgeChild>* aOutImageBridge,
|
||||
ipc::Endpoint<PVRManagerChild>* aOutVRBridge,
|
||||
ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager);
|
||||
ipc::Endpoint<dom::PVideoDecoderManagerChild>* aOutVideoManager,
|
||||
nsTArray<uint32_t>* aNamespaces);
|
||||
|
||||
// This returns a reference to the APZCTreeManager to which
|
||||
// pan/zoom-related events can be sent.
|
||||
|
@ -119,6 +120,10 @@ public:
|
|||
// Must run on the browser main thread.
|
||||
uint64_t AllocateLayerTreeId();
|
||||
|
||||
// Allocate an ID that can be used as Namespace and
|
||||
// Must run on the browser main thread.
|
||||
uint32_t AllocateNamespace();
|
||||
|
||||
// Allocate a layers ID and connect it to a compositor. If the compositor is null,
|
||||
// the connect operation will not be performed, but an ID will still be allocated.
|
||||
// This must be called from the browser main thread.
|
||||
|
@ -241,6 +246,7 @@ private:
|
|||
ipc::TaskFactory<GPUProcessManager> mTaskFactory;
|
||||
RefPtr<VsyncIOThreadHolder> mVsyncIOThread;
|
||||
uint64_t mNextLayerTreeId;
|
||||
uint32_t mNextNamespace;
|
||||
uint64_t mNextResetSequenceNo;
|
||||
uint32_t mNumProcessAttempts;
|
||||
|
||||
|
|
|
@ -29,13 +29,14 @@ InProcessCompositorSession::Create(nsIWidget* aWidget,
|
|||
CSSToLayoutDeviceScale aScale,
|
||||
const CompositorOptions& aOptions,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize)
|
||||
const gfx::IntSize& aSurfaceSize,
|
||||
uint32_t aNamespace)
|
||||
{
|
||||
CompositorWidgetInitData initData;
|
||||
aWidget->GetCompositorWidgetInitData(&initData);
|
||||
|
||||
RefPtr<CompositorWidget> widget = CompositorWidget::CreateLocal(initData, aOptions, aWidget);
|
||||
RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager);
|
||||
RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager, aNamespace);
|
||||
RefPtr<CompositorBridgeParent> parent =
|
||||
child->InitSameProcess(widget, aRootLayerTreeId, aScale, aOptions, aUseExternalSurfaceSize, aSurfaceSize);
|
||||
|
||||
|
|
|
@ -27,7 +27,8 @@ public:
|
|||
CSSToLayoutDeviceScale aScale,
|
||||
const CompositorOptions& aOptions,
|
||||
bool aUseExternalSurfaceSize,
|
||||
const gfx::IntSize& aSurfaceSize);
|
||||
const gfx::IntSize& aSurfaceSize,
|
||||
uint32_t aNamespace);
|
||||
|
||||
CompositorBridgeParent* GetInProcessBridge() const override;
|
||||
void SetContentController(GeckoContentController* aController) override;
|
||||
|
|
|
@ -90,12 +90,14 @@ public:
|
|||
};
|
||||
|
||||
static bool
|
||||
WrapWithWebRenderTextureHost(LayersBackend aBackend,
|
||||
WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator,
|
||||
LayersBackend aBackend,
|
||||
TextureFlags aFlags)
|
||||
{
|
||||
if (!gfxVars::UseWebRender() ||
|
||||
(aFlags & TextureFlags::SNAPSHOT) ||
|
||||
(aBackend != LayersBackend::LAYERS_WR)) {
|
||||
(aBackend != LayersBackend::LAYERS_WR) ||
|
||||
(!aDeallocator->UsesImageBridge() && !aDeallocator->AsCompositorBridgeParentBase())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -240,7 +242,7 @@ TextureHost::Create(const SurfaceDescriptor& aDesc,
|
|||
MOZ_CRASH("GFX: Unsupported Surface type host");
|
||||
}
|
||||
|
||||
if (WrapWithWebRenderTextureHost(aBackend, aFlags)) {
|
||||
if (WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
|
||||
result = new WebRenderTextureHost(aDesc, aFlags, result);
|
||||
}
|
||||
|
||||
|
|
|
@ -76,14 +76,16 @@ static StaticRefPtr<CompositorBridgeChild> sCompositorBridge;
|
|||
|
||||
Atomic<int32_t> KnowsCompositor::sSerialCounter(0);
|
||||
|
||||
CompositorBridgeChild::CompositorBridgeChild(LayerManager *aLayerManager)
|
||||
CompositorBridgeChild::CompositorBridgeChild(LayerManager *aLayerManager, uint32_t aNamespace)
|
||||
: mLayerManager(aLayerManager)
|
||||
, mNamespace(aNamespace)
|
||||
, mCanSend(false)
|
||||
, mFwdTransactionId(0)
|
||||
, mDeviceResetSequenceNumber(0)
|
||||
, mMessageLoop(MessageLoop::current())
|
||||
, mSectionAllocator(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mNamespace);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
|
@ -208,12 +210,12 @@ CompositorBridgeChild::LookupCompositorFrameMetrics(const FrameMetrics::ViewID a
|
|||
}
|
||||
|
||||
/* static */ bool
|
||||
CompositorBridgeChild::InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint)
|
||||
CompositorBridgeChild::InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint, uint32_t aNamespace)
|
||||
{
|
||||
// There's only one compositor per child process.
|
||||
MOZ_ASSERT(!sCompositorBridge);
|
||||
|
||||
RefPtr<CompositorBridgeChild> child(new CompositorBridgeChild(nullptr));
|
||||
RefPtr<CompositorBridgeChild> child(new CompositorBridgeChild(nullptr, aNamespace));
|
||||
if (!aEndpoint.Bind(child)) {
|
||||
NS_RUNTIMEABORT("Couldn't Open() Compositor channel.");
|
||||
return false;
|
||||
|
@ -226,7 +228,7 @@ CompositorBridgeChild::InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoi
|
|||
}
|
||||
|
||||
/* static */ bool
|
||||
CompositorBridgeChild::ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint)
|
||||
CompositorBridgeChild::ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint, uint32_t aNamespace)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -238,7 +240,7 @@ CompositorBridgeChild::ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndp
|
|||
old->Destroy();
|
||||
}
|
||||
|
||||
return InitForContent(Move(aEndpoint));
|
||||
return InitForContent(Move(aEndpoint), aNamespace);
|
||||
}
|
||||
|
||||
CompositorBridgeParent*
|
||||
|
@ -268,9 +270,10 @@ CompositorBridgeChild::InitSameProcess(widget::CompositorWidget* aWidget,
|
|||
/* static */ RefPtr<CompositorBridgeChild>
|
||||
CompositorBridgeChild::CreateRemote(const uint64_t& aProcessToken,
|
||||
LayerManager* aLayerManager,
|
||||
Endpoint<PCompositorBridgeChild>&& aEndpoint)
|
||||
Endpoint<PCompositorBridgeChild>&& aEndpoint,
|
||||
uint32_t aNamespace)
|
||||
{
|
||||
RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager);
|
||||
RefPtr<CompositorBridgeChild> child = new CompositorBridgeChild(aLayerManager, aNamespace);
|
||||
if (!aEndpoint.Bind(child)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1180,6 +1183,18 @@ CompositorBridgeChild::DeallocPWebRenderBridgeChild(PWebRenderBridgeChild* aActo
|
|||
return true;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
CompositorBridgeChild::GetNextExternalImageId()
|
||||
{
|
||||
static uint32_t sNextID = 1;
|
||||
++sNextID;
|
||||
MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
|
||||
|
||||
uint64_t imageId = mNamespace;
|
||||
imageId = imageId << 32 | sNextID;
|
||||
return imageId;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ class CompositorBridgeChild final : public PCompositorBridgeChild,
|
|||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorBridgeChild, override);
|
||||
|
||||
explicit CompositorBridgeChild(LayerManager *aLayerManager);
|
||||
explicit CompositorBridgeChild(LayerManager *aLayerManager, uint32_t aNamespace);
|
||||
|
||||
void Destroy();
|
||||
|
||||
|
@ -65,13 +65,14 @@ public:
|
|||
/**
|
||||
* Initialize the singleton compositor bridge for a content process.
|
||||
*/
|
||||
static bool InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint);
|
||||
static bool ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint);
|
||||
static bool InitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint, uint32_t aNamespace);
|
||||
static bool ReinitForContent(Endpoint<PCompositorBridgeChild>&& aEndpoint, uint32_t aNamespace);
|
||||
|
||||
static RefPtr<CompositorBridgeChild> CreateRemote(
|
||||
const uint64_t& aProcessToken,
|
||||
LayerManager* aLayerManager,
|
||||
Endpoint<PCompositorBridgeChild>&& aEndpoint);
|
||||
Endpoint<PCompositorBridgeChild>&& aEndpoint,
|
||||
uint32_t aNamespace);
|
||||
|
||||
/**
|
||||
* Initialize the CompositorBridgeChild, create CompositorBridgeParent, and
|
||||
|
@ -233,6 +234,8 @@ public:
|
|||
return mDeviceResetSequenceNumber;
|
||||
}
|
||||
|
||||
uint64_t GetNextExternalImageId();
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
virtual ~CompositorBridgeChild();
|
||||
|
@ -295,6 +298,9 @@ private:
|
|||
};
|
||||
|
||||
RefPtr<LayerManager> mLayerManager;
|
||||
|
||||
uint32_t mNamespace;
|
||||
|
||||
// When not multi-process, hold a reference to the CompositorBridgeParent to keep it
|
||||
// alive. This reference should be null in multi-process.
|
||||
RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
|
||||
|
|
|
@ -117,6 +117,8 @@ public:
|
|||
|
||||
virtual ShmemAllocator* AsShmemAllocator() override { return this; }
|
||||
|
||||
virtual CompositorBridgeParentBase* AsCompositorBridgeParentBase() override { return this; }
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvSyncWithCompositor() override { return IPC_OK(); }
|
||||
|
||||
virtual void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) = 0;
|
||||
|
|
|
@ -29,6 +29,7 @@ class DataSourceSurface;
|
|||
namespace layers {
|
||||
|
||||
class CompositableForwarder;
|
||||
class CompositorBridgeParentBase;
|
||||
class TextureForwarder;
|
||||
|
||||
class ShmemAllocator;
|
||||
|
@ -89,6 +90,8 @@ public:
|
|||
virtual LegacySurfaceDescriptorAllocator*
|
||||
AsLegacySurfaceDescriptorAllocator() { return nullptr; }
|
||||
|
||||
virtual CompositorBridgeParentBase* AsCompositorBridgeParentBase() { return nullptr; }
|
||||
|
||||
// ipc info
|
||||
|
||||
virtual bool IPCOpen() const { return true; }
|
||||
|
|
|
@ -287,12 +287,14 @@ ImageBridgeChild::CreateCanvasClientSync(SynchronousTask* aTask,
|
|||
*outResult = CreateCanvasClientNow(aType, aFlags);
|
||||
}
|
||||
|
||||
ImageBridgeChild::ImageBridgeChild()
|
||||
: mCanSend(false)
|
||||
ImageBridgeChild::ImageBridgeChild(uint32_t aNamespace)
|
||||
: mNamespace(aNamespace)
|
||||
, mCanSend(false)
|
||||
, mDestroyed(false)
|
||||
, mFwdTransactionId(0)
|
||||
, mContainerMapLock("ImageBridgeChild.mContainerMapLock")
|
||||
{
|
||||
MOZ_ASSERT(mNamespace);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mTxn = new CompositableTransaction();
|
||||
|
@ -560,7 +562,7 @@ ImageBridgeChild::SendImageBridgeThreadId()
|
|||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
|
||||
ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -573,7 +575,7 @@ ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
|
||||
RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
|
||||
|
||||
RefPtr<Runnable> runnable = NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
|
||||
child,
|
||||
|
@ -591,7 +593,7 @@ ImageBridgeChild::InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
|
|||
}
|
||||
|
||||
bool
|
||||
ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
|
||||
ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -601,7 +603,7 @@ ImageBridgeChild::ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint)
|
|||
// false result and a MsgDropped processing error. This is okay.
|
||||
ShutdownSingleton();
|
||||
|
||||
return InitForContent(Move(aEndpoint));
|
||||
return InitForContent(Move(aEndpoint), aNamespace);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -687,7 +689,7 @@ ImageBridgeChild::WillShutdown()
|
|||
}
|
||||
|
||||
void
|
||||
ImageBridgeChild::InitSameProcess()
|
||||
ImageBridgeChild::InitSameProcess(uint32_t aNamespace)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
|
||||
|
@ -699,7 +701,7 @@ ImageBridgeChild::InitSameProcess()
|
|||
sImageBridgeChildThread->Start();
|
||||
}
|
||||
|
||||
RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
|
||||
RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
|
||||
RefPtr<ImageBridgeParent> parent = ImageBridgeParent::CreateSameProcess();
|
||||
|
||||
RefPtr<Runnable> runnable = WrapRunnable(
|
||||
|
@ -716,7 +718,7 @@ ImageBridgeChild::InitSameProcess()
|
|||
}
|
||||
|
||||
/* static */ void
|
||||
ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint)
|
||||
ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!sImageBridgeChildSingleton);
|
||||
|
@ -727,7 +729,7 @@ ImageBridgeChild::InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint)
|
|||
sImageBridgeChildThread->Start();
|
||||
}
|
||||
|
||||
RefPtr<ImageBridgeChild> child = new ImageBridgeChild();
|
||||
RefPtr<ImageBridgeChild> child = new ImageBridgeChild(aNamespace);
|
||||
|
||||
MessageLoop* loop = child->GetMessageLoop();
|
||||
loop->PostTask(NewRunnableMethod<Endpoint<PImageBridgeChild>&&>(
|
||||
|
@ -1154,5 +1156,17 @@ ImageBridgeChild::HandleFatalError(const char* aName, const char* aMsg) const
|
|||
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aName, aMsg, OtherPid());
|
||||
}
|
||||
|
||||
uint64_t
|
||||
ImageBridgeChild::GetNextExternalImageId()
|
||||
{
|
||||
static uint32_t sNextID = 1;
|
||||
++sNextID;
|
||||
MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
|
||||
|
||||
uint64_t imageId = mNamespace;
|
||||
imageId = imageId << 32 | sNextID;
|
||||
return imageId;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -124,11 +124,11 @@ public:
|
|||
* We may want to use a specifi thread in the future. In this case, use
|
||||
* CreateWithThread instead.
|
||||
*/
|
||||
static void InitSameProcess();
|
||||
static void InitSameProcess(uint32_t aNamespace);
|
||||
|
||||
static void InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint);
|
||||
static bool InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint);
|
||||
static bool ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint);
|
||||
static void InitWithGPUProcess(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace);
|
||||
static bool InitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace);
|
||||
static bool ReinitForContent(Endpoint<PImageBridgeChild>&& aEndpoint, uint32_t aNamespace);
|
||||
|
||||
/**
|
||||
* Destroys the image bridge by calling DestroyBridge, and destroys the
|
||||
|
@ -339,8 +339,10 @@ public:
|
|||
|
||||
virtual void HandleFatalError(const char* aName, const char* aMsg) const override;
|
||||
|
||||
uint64_t GetNextExternalImageId();
|
||||
|
||||
protected:
|
||||
ImageBridgeChild();
|
||||
explicit ImageBridgeChild(uint32_t aNamespace);
|
||||
bool DispatchAllocShmemInternal(size_t aSize,
|
||||
SharedMemory::SharedMemoryType aType,
|
||||
Shmem* aShmem,
|
||||
|
@ -365,6 +367,8 @@ protected:
|
|||
static void ShutdownSingleton();
|
||||
|
||||
private:
|
||||
uint32_t mNamespace;
|
||||
|
||||
CompositableTransaction* mTxn;
|
||||
|
||||
bool mCanSend;
|
||||
|
|
|
@ -111,16 +111,7 @@ WebRenderBridgeChild::DPEnd(wr::DisplayListBuilder &aBuilder, const gfx::IntSize
|
|||
uint64_t
|
||||
WebRenderBridgeChild::GetNextExternalImageId()
|
||||
{
|
||||
static uint32_t sNextID = 1;
|
||||
++sNextID;
|
||||
MOZ_RELEASE_ASSERT(sNextID != UINT32_MAX);
|
||||
|
||||
// XXX replace external image id allocation with webrender's id allocation.
|
||||
// Use proc id as IdNamespace for now.
|
||||
uint32_t procId = static_cast<uint32_t>(base::GetCurrentProcId());
|
||||
uint64_t imageId = procId;
|
||||
imageId = imageId << 32 | sNextID;
|
||||
return imageId;
|
||||
return GetCompositorBridgeChild()->GetNextExternalImageId();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -147,7 +138,12 @@ WebRenderBridgeChild::AllocExternalImageIdForCompositable(CompositableClient* aC
|
|||
void
|
||||
WebRenderBridgeChild::DeallocExternalImageId(uint64_t aImageId)
|
||||
{
|
||||
MOZ_ASSERT(!mDestroyed);
|
||||
if (mDestroyed) {
|
||||
// This can happen if the IPC connection was torn down, because, e.g.
|
||||
// the GPU process died.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aImageId);
|
||||
SendRemoveExternalImageId(aImageId);
|
||||
}
|
||||
|
|
|
@ -50,14 +50,15 @@ WebRenderDisplayItemLayer::RenderLayer(wr::DisplayListBuilder& aBuilder)
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
WebRenderDisplayItemLayer::SendImageContainer(ImageContainer* aContainer)
|
||||
Maybe<wr::ImageKey>
|
||||
WebRenderDisplayItemLayer::SendImageContainer(ImageContainer* aContainer,
|
||||
nsTArray<layers::WebRenderParentCommand>& aParentCommands)
|
||||
{
|
||||
if (mImageContainer != aContainer) {
|
||||
AutoLockImage autoLock(aContainer);
|
||||
Image* image = autoLock.GetImage();
|
||||
if (!image) {
|
||||
return 0;
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
if (!mImageClient) {
|
||||
|
@ -65,7 +66,7 @@ WebRenderDisplayItemLayer::SendImageContainer(ImageContainer* aContainer)
|
|||
WrBridge(),
|
||||
TextureFlags::DEFAULT);
|
||||
if (!mImageClient) {
|
||||
return 0;
|
||||
return Nothing();
|
||||
}
|
||||
mImageClient->Connect();
|
||||
}
|
||||
|
@ -76,13 +77,20 @@ WebRenderDisplayItemLayer::SendImageContainer(ImageContainer* aContainer)
|
|||
}
|
||||
MOZ_ASSERT(mExternalImageId);
|
||||
|
||||
if (mImageClient && !mImageClient->UpdateImage(aContainer, /* unused */0)) {
|
||||
return 0;
|
||||
if (!mImageClient->UpdateImage(aContainer, /* unused */0)) {
|
||||
return Nothing();
|
||||
}
|
||||
mImageContainer = aContainer;
|
||||
}
|
||||
|
||||
return mExternalImageId;
|
||||
WrImageKey key;
|
||||
key.mNamespace = WrBridge()->GetNamespace();
|
||||
key.mHandle = WrBridge()->GetNextResourceId();
|
||||
aParentCommands.AppendElement(layers::OpAddExternalImage(
|
||||
mExternalImageId,
|
||||
key));
|
||||
WrManager()->AddImageKeyForDiscard(key);
|
||||
return Some(key);
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -7,9 +7,11 @@
|
|||
#define GFX_WEBRENDERDISPLAYITEMLAYER_H
|
||||
|
||||
#include "Layers.h"
|
||||
#include "WebRenderLayerManager.h"
|
||||
#include "mozilla/layers/ImageClient.h"
|
||||
#include "mozilla/layers/PWebRenderBridgeChild.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
#include "WebRenderLayerManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
@ -24,7 +26,8 @@ public:
|
|||
MOZ_COUNT_CTOR(WebRenderDisplayItemLayer);
|
||||
}
|
||||
|
||||
uint64_t SendImageContainer(ImageContainer* aContainer);
|
||||
Maybe<wr::ImageKey> SendImageContainer(ImageContainer* aContainer,
|
||||
nsTArray<layers::WebRenderParentCommand>& aParentCommands);
|
||||
|
||||
protected:
|
||||
virtual ~WebRenderDisplayItemLayer()
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "nsIObserver.h" // for nsIObserver, etc
|
||||
#include "nsIObserverService.h" // for nsIObserverService
|
||||
#include "nsIScreen.h" // for nsIScreen
|
||||
#include "nsIScreenManager.h" // for nsIScreenManager
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
#include "nsIWidget.h" // for nsIWidget, NS_NATIVE_WINDOW
|
||||
|
@ -38,10 +37,12 @@
|
|||
#include "nsTArray.h" // for nsTArray, nsTArray_Impl
|
||||
#include "nsThreadUtils.h" // for NS_IsMainThread
|
||||
#include "mozilla/gfx/Logging.h"
|
||||
#include "mozilla/widget/ScreenManager.h" // for ScreenManager
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using mozilla::services::GetObserverService;
|
||||
using mozilla::widget::ScreenManager;
|
||||
|
||||
class nsFontCache final : public nsIObserver
|
||||
{
|
||||
|
@ -190,7 +191,7 @@ nsFontCache::Flush()
|
|||
}
|
||||
|
||||
nsDeviceContext::nsDeviceContext()
|
||||
: mWidth(0), mHeight(0), mDepth(0),
|
||||
: mWidth(0), mHeight(0),
|
||||
mAppUnitsPerDevPixel(-1), mAppUnitsPerDevPixelAtUnitFullZoom(-1),
|
||||
mAppUnitsPerPhysicalInch(-1),
|
||||
mFullZoom(1.0f), mPrintingScale(1.0f)
|
||||
|
@ -399,13 +400,15 @@ nsDeviceContext::CreateRenderingContextCommon(bool aWantReferenceContext)
|
|||
nsresult
|
||||
nsDeviceContext::GetDepth(uint32_t& aDepth)
|
||||
{
|
||||
if (mDepth == 0 && mScreenManager) {
|
||||
nsCOMPtr<nsIScreen> primaryScreen;
|
||||
mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen));
|
||||
primaryScreen->GetColorDepth(reinterpret_cast<int32_t *>(&mDepth));
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
FindScreen(getter_AddRefs(screen));
|
||||
if (!screen) {
|
||||
ScreenManager& screenManager = ScreenManager::GetSingleton();
|
||||
screenManager.GetPrimaryScreen(getter_AddRefs(screen));
|
||||
MOZ_ASSERT(screen);
|
||||
}
|
||||
screen->GetColorDepth(reinterpret_cast<int32_t *>(&aDepth));
|
||||
|
||||
aDepth = mDepth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -294,7 +294,6 @@ private:
|
|||
|
||||
nscoord mWidth;
|
||||
nscoord mHeight;
|
||||
uint32_t mDepth;
|
||||
int32_t mAppUnitsPerDevPixel;
|
||||
int32_t mAppUnitsPerDevPixelAtUnitFullZoom;
|
||||
int32_t mAppUnitsPerPhysicalInch;
|
||||
|
|
|
@ -269,7 +269,8 @@ TEST(Layers, TextureYCbCrSerialization) {
|
|||
clientData.mPicX = 0;
|
||||
clientData.mPicX = 0;
|
||||
|
||||
ImageBridgeChild::InitSameProcess();
|
||||
uint32_t namespaceId = 1;
|
||||
ImageBridgeChild::InitSameProcess(namespaceId);
|
||||
|
||||
RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
|
||||
static int retry = 5;
|
||||
|
|
|
@ -241,11 +241,11 @@ RenderThread::UnregisterExternalImage(uint64_t aExternalImageId)
|
|||
}
|
||||
|
||||
RenderTextureHost*
|
||||
RenderThread::GetRenderTexture(uint64_t aExternalImageId)
|
||||
RenderThread::GetRenderTexture(WrExternalImageId aExternalImageId)
|
||||
{
|
||||
MutexAutoLock lock(mRenderTextureMapLock);
|
||||
MOZ_ASSERT(mRenderTextures.Get(aExternalImageId).get());
|
||||
return mRenderTextures.Get(aExternalImageId).get();
|
||||
MOZ_ASSERT(mRenderTextures.Get(aExternalImageId.mHandle).get());
|
||||
return mRenderTextures.Get(aExternalImageId.mHandle).get();
|
||||
}
|
||||
|
||||
} // namespace wr
|
||||
|
|
|
@ -109,7 +109,7 @@ public:
|
|||
|
||||
void UnregisterExternalImage(uint64_t aExternalImageId);
|
||||
|
||||
RenderTextureHost* GetRenderTexture(uint64_t aExternalImageId);
|
||||
RenderTextureHost* GetRenderTexture(WrExternalImageId aExternalImageId);
|
||||
|
||||
private:
|
||||
explicit RenderThread(base::Thread* aThread);
|
||||
|
|
|
@ -174,7 +174,7 @@ RendererOGL::FlushRenderedEpochs()
|
|||
}
|
||||
|
||||
RenderTextureHost*
|
||||
RendererOGL::GetRenderTexture(uint64_t aExternalImageId)
|
||||
RendererOGL::GetRenderTexture(WrExternalImageId aExternalImageId)
|
||||
{
|
||||
return mThread->GetRenderTexture(aExternalImageId);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public:
|
|||
|
||||
WrRenderedEpochs* FlushRenderedEpochs();
|
||||
|
||||
RenderTextureHost* GetRenderTexture(uint64_t aExternalImageId);
|
||||
RenderTextureHost* GetRenderTexture(WrExternalImageId aExternalImageId);
|
||||
|
||||
WrRenderer* GetWrRenderer() { return mWrRenderer; }
|
||||
|
||||
|
|
|
@ -365,7 +365,9 @@ static inline WrComplexClipRegion ToWrComplexClipRegion(const gfx::RectTyped<T>&
|
|||
|
||||
static inline WrExternalImageId ToWrExternalImageId(uint64_t aID)
|
||||
{
|
||||
return aID;
|
||||
WrExternalImageId Id;
|
||||
Id.mHandle = aID;
|
||||
return Id;
|
||||
}
|
||||
|
||||
static inline WrExternalImage RawDataToWrExternalImage(const uint8_t* aBuff,
|
||||
|
|
|
@ -11,62 +11,60 @@ use webrender::renderer::{Renderer, RendererOptions};
|
|||
use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
|
||||
use webrender::{ApiRecordingReceiver, BinaryRecorder};
|
||||
use app_units::Au;
|
||||
use euclid::{TypedPoint2D, SideOffsets2D};
|
||||
use euclid::{TypedPoint2D, TypedSize2D, TypedRect, TypedMatrix4D, SideOffsets2D};
|
||||
|
||||
extern crate webrender_traits;
|
||||
|
||||
// Enables binary recording that can be used with `wrench replay`
|
||||
// Outputs a wr-record-*.bin file for each window that is shown
|
||||
// Note: wrench will panic if external images are used, they can
|
||||
// be disabled in WebRenderBridgeParent::ProcessWebRenderCommands
|
||||
// by commenting out the path that adds an external image ID
|
||||
static ENABLE_RECORDING: bool = false;
|
||||
|
||||
type WrAPI = RenderApi;
|
||||
type WrAuxiliaryListsDescriptor = AuxiliaryListsDescriptor;
|
||||
type WrBorderStyle = BorderStyle;
|
||||
type WrBoxShadowClipMode = BoxShadowClipMode;
|
||||
type WrBuiltDisplayListDescriptor = BuiltDisplayListDescriptor;
|
||||
type WrEpoch = Epoch;
|
||||
type WrExternalImageId = ExternalImageId;
|
||||
type WrFontKey = FontKey;
|
||||
type WrGlyphInstance = GlyphInstance;
|
||||
type WrIdNamespace = IdNamespace;
|
||||
type WrImageFormat = ImageFormat;
|
||||
type WrImageRendering = ImageRendering;
|
||||
type WrImageKey = ImageKey;
|
||||
type WrMixBlendMode = MixBlendMode;
|
||||
type WrPipelineId = PipelineId;
|
||||
type WrRenderedEpochs = Vec<(WrPipelineId, WrEpoch)>;
|
||||
type WrRenderer = Renderer;
|
||||
type WrSideOffsets2Du32 = WrSideOffsets2D<u32>;
|
||||
type WrSideOffsets2Df32 = WrSideOffsets2D<f32>;
|
||||
|
||||
static ENABLE_RECORDING: bool = false;
|
||||
/// cbindgen:field-names=[mHandle]
|
||||
/// cbindgen:struct-gen-op-lt=true
|
||||
/// cbindgen:struct-gen-op-lte=true
|
||||
type WrEpoch = Epoch;
|
||||
/// cbindgen:field-names=[mHandle]
|
||||
/// cbindgen:struct-gen-op-lt=true
|
||||
/// cbindgen:struct-gen-op-lte=true
|
||||
type WrIdNamespace = IdNamespace;
|
||||
|
||||
// This macro adds some checks to make sure we notice when the memory representation of
|
||||
// types change.
|
||||
macro_rules! check_ffi_type {
|
||||
($check_sizes_match:ident struct $TypeName:ident as ($T1:ident, $T2:ident)) => (
|
||||
fn $check_sizes_match() {
|
||||
#[repr(C)] struct TestType($T1, $T2);
|
||||
let _ = mem::transmute::<$TypeName, TestType>;
|
||||
}
|
||||
);
|
||||
($check_sizes_match:ident struct $TypeName:ident as ($T:ident)) => (
|
||||
fn $check_sizes_match() {
|
||||
#[repr(C)] struct TestType($T);
|
||||
let _ = mem::transmute::<$TypeName, TestType>;
|
||||
}
|
||||
);
|
||||
($check_sizes_match:ident enum $TypeName:ident as $T:ident) => (
|
||||
fn $check_sizes_match() { let _ = mem::transmute::<$TypeName, $T>; }
|
||||
);
|
||||
/// cbindgen:field-names=[mNamespace, mHandle]
|
||||
type WrPipelineId = PipelineId;
|
||||
/// cbindgen:field-names=[mNamespace, mHandle]
|
||||
type WrImageKey = ImageKey;
|
||||
/// cbindgen:field-names=[mNamespace, mHandle]
|
||||
type WrFontKey = FontKey;
|
||||
|
||||
/// cbindgen:field-names=[mHandle]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct WrExternalImageId(pub u64);
|
||||
|
||||
impl Into<ExternalImageId> for WrExternalImageId {
|
||||
fn into(self) -> ExternalImageId {
|
||||
ExternalImageId(self.0)
|
||||
}
|
||||
}
|
||||
impl Into<WrExternalImageId> for ExternalImageId {
|
||||
fn into(self) -> WrExternalImageId {
|
||||
WrExternalImageId(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
check_ffi_type!(_pipeline_id_repr struct WrPipelineId as (u32, u32));
|
||||
check_ffi_type!(_image_key_repr struct WrImageKey as (u32, u32));
|
||||
check_ffi_type!(_font_key_repr struct WrFontKey as (u32, u32));
|
||||
check_ffi_type!(_epoch_repr struct WrEpoch as (u32));
|
||||
check_ffi_type!(_image_format_repr enum WrImageFormat as u32);
|
||||
check_ffi_type!(_border_style_repr enum WrBorderStyle as u32);
|
||||
check_ffi_type!(_image_rendering_repr enum WrImageRendering as u32);
|
||||
check_ffi_type!(_mix_blend_mode_repr enum WrMixBlendMode as u32);
|
||||
check_ffi_type!(_box_shadow_clip_mode_repr enum WrBoxShadowClipMode as u32);
|
||||
check_ffi_type!(_namespace_id_repr struct WrIdNamespace as (u32));
|
||||
|
||||
const GL_FORMAT_BGRA_GL: gl::GLuint = gl::BGRA;
|
||||
const GL_FORMAT_BGRA_GLES: gl::GLuint = gl::BGRA_EXT;
|
||||
|
@ -155,13 +153,14 @@ impl From<ItemRange> for WrItemRange {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WrPoint {
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
impl WrPoint {
|
||||
pub fn to_point(&self) -> TypedPoint2D<f32, LayerPixel> {
|
||||
pub fn to_point<U>(&self) -> TypedPoint2D<f32, U> {
|
||||
TypedPoint2D::new(self.x, self.y)
|
||||
}
|
||||
}
|
||||
|
@ -173,8 +172,8 @@ pub struct WrSize {
|
|||
}
|
||||
|
||||
impl WrSize {
|
||||
pub fn to_size(&self) -> LayoutSize {
|
||||
LayoutSize::new(self.width, self.height)
|
||||
pub fn to_size<U>(&self) -> TypedSize2D<f32, U> {
|
||||
TypedSize2D::new(self.width, self.height)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,13 +187,13 @@ pub struct WrRect {
|
|||
}
|
||||
|
||||
impl WrRect {
|
||||
pub fn to_rect(&self) -> LayoutRect {
|
||||
LayoutRect::new(LayoutPoint::new(self.x, self.y),
|
||||
LayoutSize::new(self.width, self.height))
|
||||
pub fn to_rect<U>(&self) -> TypedRect<f32, U> {
|
||||
TypedRect::new(TypedPoint2D::new(self.x, self.y),
|
||||
TypedSize2D::new(self.width, self.height))
|
||||
}
|
||||
}
|
||||
impl From<LayoutRect> for WrRect {
|
||||
fn from(rect: LayoutRect) -> Self {
|
||||
impl<U> From<TypedRect<f32, U>> for WrRect {
|
||||
fn from(rect: TypedRect<f32, U>) -> Self {
|
||||
WrRect {
|
||||
x: rect.origin.x,
|
||||
y: rect.origin.y,
|
||||
|
@ -211,8 +210,8 @@ pub struct WrMatrix {
|
|||
}
|
||||
|
||||
impl WrMatrix {
|
||||
pub fn to_layout_transform(&self) -> LayoutTransform {
|
||||
LayoutTransform::row_major(
|
||||
pub fn to_transform<U, E>(&self) -> TypedMatrix4D<f32, U, E> {
|
||||
TypedMatrix4D::row_major(
|
||||
self.values[0], self.values[1], self.values[2], self.values[3],
|
||||
self.values[4], self.values[5], self.values[6], self.values[7],
|
||||
self.values[8], self.values[9], self.values[10], self.values[11],
|
||||
|
@ -234,6 +233,25 @@ impl WrColor {
|
|||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WrGlyphInstance {
|
||||
index: u32,
|
||||
point: WrPoint,
|
||||
}
|
||||
|
||||
impl WrGlyphInstance {
|
||||
pub fn to_glyph_instance(&self) -> GlyphInstance {
|
||||
GlyphInstance {
|
||||
index: self.index,
|
||||
point: self.point.to_point(),
|
||||
}
|
||||
}
|
||||
pub fn to_glyph_instances(glyphs: &[WrGlyphInstance]) -> Vec<GlyphInstance> {
|
||||
glyphs.iter().map(|x| x.to_glyph_instance()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct WrGradientStop {
|
||||
offset: f32,
|
||||
|
@ -496,8 +514,8 @@ pub struct WrExternalImageHandler {
|
|||
}
|
||||
|
||||
impl ExternalImageHandler for WrExternalImageHandler {
|
||||
fn lock(&mut self, id: WrExternalImageId) -> ExternalImage {
|
||||
let image = (self.lock_func)(self.external_image_obj, id);
|
||||
fn lock(&mut self, id: ExternalImageId) -> ExternalImage {
|
||||
let image = (self.lock_func)(self.external_image_obj, id.into());
|
||||
|
||||
match image.image_type {
|
||||
WrExternalImageType::NativeTexture => {
|
||||
|
@ -524,15 +542,18 @@ impl ExternalImageHandler for WrExternalImageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
fn unlock(&mut self, id: WrExternalImageId) {
|
||||
(self.unlock_func)(self.external_image_obj, id);
|
||||
fn unlock(&mut self, id: ExternalImageId) {
|
||||
(self.unlock_func)(self.external_image_obj, id.into());
|
||||
}
|
||||
|
||||
fn release(&mut self, id: WrExternalImageId) {
|
||||
(self.release_func)(self.external_image_obj, id);
|
||||
fn release(&mut self, id: ExternalImageId) {
|
||||
(self.release_func)(self.external_image_obj, id.into());
|
||||
}
|
||||
}
|
||||
|
||||
/// cbindgen:field-names=[mHandle]
|
||||
/// cbindgen:struct-gen-op-lt=true
|
||||
/// cbindgen:struct-gen-op-lte=true
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct WrWindowId(u64);
|
||||
|
@ -715,17 +736,23 @@ pub extern "C" fn wr_renderer_current_epoch(renderer: &mut WrRenderer,
|
|||
return false;
|
||||
}
|
||||
|
||||
/// wr-binding:destructor_safe // This is used by the binding generator
|
||||
/// cbindgen:function-postfix=WR_DESTRUCTOR_SAFE_FUNC
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_renderer_delete(renderer: *mut WrRenderer) {
|
||||
Box::from_raw(renderer);
|
||||
}
|
||||
|
||||
pub struct WrRenderedEpochs {
|
||||
data: Vec<(WrPipelineId, WrEpoch)>,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_renderer_flush_rendered_epochs(renderer: &mut WrRenderer)
|
||||
-> *mut WrRenderedEpochs {
|
||||
let map = renderer.flush_rendered_epochs();
|
||||
let pipeline_epochs = Box::new(map.into_iter().collect());
|
||||
let pipeline_epochs = Box::new(WrRenderedEpochs {
|
||||
data: map.into_iter().collect()
|
||||
});
|
||||
return Box::into_raw(pipeline_epochs);
|
||||
}
|
||||
|
||||
|
@ -734,7 +761,7 @@ pub unsafe extern "C" fn wr_rendered_epochs_next(pipeline_epochs: &mut WrRendere
|
|||
out_pipeline: &mut WrPipelineId,
|
||||
out_epoch: &mut WrEpoch)
|
||||
-> bool {
|
||||
if let Some((pipeline, epoch)) = pipeline_epochs.pop() {
|
||||
if let Some((pipeline, epoch)) = pipeline_epochs.data.pop() {
|
||||
*out_pipeline = pipeline;
|
||||
*out_epoch = epoch;
|
||||
return true;
|
||||
|
@ -742,7 +769,7 @@ pub unsafe extern "C" fn wr_rendered_epochs_next(pipeline_epochs: &mut WrRendere
|
|||
return false;
|
||||
}
|
||||
|
||||
/// wr-binding:destructor_safe // This is used by the binding generator
|
||||
/// cbindgen:function-postfix=WR_DESTRUCTOR_SAFE_FUNC
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wr_rendered_epochs_delete(pipeline_epochs: *mut WrRenderedEpochs) {
|
||||
Box::from_raw(pipeline_epochs);
|
||||
|
@ -958,7 +985,7 @@ pub extern "C" fn wr_api_generate_frame(api: &mut WrAPI) {
|
|||
api.generate_frame(None);
|
||||
}
|
||||
|
||||
/// wr-binding:destructor_safe // This is used by the binding generator
|
||||
/// cbindgen:function-postfix=WR_DESTRUCTOR_SAFE_FUNC
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_api_send_external_event(api: &mut WrAPI, evt: usize) {
|
||||
assert!(unsafe { !is_in_render_thread() });
|
||||
|
@ -1118,7 +1145,7 @@ pub extern "C" fn wr_dp_push_stacking_context(state: &mut WrState,
|
|||
.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
|
||||
bounds,
|
||||
state.z_index,
|
||||
Some(PropertyBinding::Value(transform.to_layout_transform())),
|
||||
Some(PropertyBinding::Value(transform.to_transform())),
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
mix_blend_mode,
|
||||
|
@ -1211,7 +1238,7 @@ pub extern "C" fn wr_dp_push_text(state: &mut WrState,
|
|||
|
||||
let glyph_slice = unsafe { slice::from_raw_parts(glyphs, glyph_count as usize) };
|
||||
let mut glyph_vector = Vec::new();
|
||||
glyph_vector.extend_from_slice(&glyph_slice);
|
||||
glyph_vector.extend_from_slice(&WrGlyphInstance::to_glyph_instances(glyph_slice));
|
||||
|
||||
let colorf = ColorF::new(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
|
|
@ -9,59 +9,9 @@
|
|||
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/gfx/Point.h"
|
||||
// ---
|
||||
#define WR_DECL_FFI_1(WrType, t1) \
|
||||
struct WrType { \
|
||||
t1 mHandle; \
|
||||
bool operator==(const WrType& rhs) const { \
|
||||
return mHandle == rhs.mHandle; \
|
||||
} \
|
||||
bool operator!=(const WrType& rhs) const { \
|
||||
return mHandle != rhs.mHandle; \
|
||||
} \
|
||||
bool operator<(const WrType& rhs) const { \
|
||||
return mHandle < rhs.mHandle; \
|
||||
} \
|
||||
bool operator<=(const WrType& rhs) const { \
|
||||
return mHandle <= rhs.mHandle; \
|
||||
} \
|
||||
}; \
|
||||
// ---
|
||||
|
||||
// ---
|
||||
#define WR_DECL_FFI_2(WrType, t1, t2) \
|
||||
struct WrType { \
|
||||
t1 mNamespace; \
|
||||
t2 mHandle; \
|
||||
bool operator==(const WrType& rhs) const { \
|
||||
return mNamespace == rhs.mNamespace \
|
||||
&& mHandle == rhs.mHandle; \
|
||||
} \
|
||||
bool operator!=(const WrType& rhs) const { \
|
||||
return mNamespace != rhs.mNamespace \
|
||||
|| mHandle != rhs.mHandle; \
|
||||
} \
|
||||
}; \
|
||||
// ---
|
||||
|
||||
|
||||
extern "C" {
|
||||
|
||||
// If you modify any of the declarations below, make sure to update the
|
||||
// serialization code in WebRenderMessageUtils.h and the rust bindings.
|
||||
|
||||
WR_DECL_FFI_1(WrEpoch, uint32_t)
|
||||
WR_DECL_FFI_1(WrIdNamespace, uint32_t)
|
||||
WR_DECL_FFI_1(WrWindowId, uint64_t)
|
||||
|
||||
WR_DECL_FFI_2(WrPipelineId, uint32_t, uint32_t)
|
||||
WR_DECL_FFI_2(WrImageKey, uint32_t, uint32_t)
|
||||
WR_DECL_FFI_2(WrFontKey, uint32_t, uint32_t)
|
||||
|
||||
#undef WR_DECL_FFI_1
|
||||
#undef WR_DECL_FFI_2
|
||||
|
||||
// ----
|
||||
// Functions invoked from Rust code
|
||||
// ----
|
||||
|
@ -73,13 +23,6 @@ bool is_glcontext_egl(void* glcontext_ptr);
|
|||
void gfx_critical_note(const char* msg);
|
||||
void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
|
||||
|
||||
// -----
|
||||
// Typedefs for struct fields and function signatures below.
|
||||
// -----
|
||||
|
||||
typedef uint64_t WrExternalImageId;
|
||||
typedef mozilla::gfx::Point Point2D; // TODO: get rid of this somehow
|
||||
|
||||
// Some useful defines to stub out webrender binding functions for when we
|
||||
// build gecko without webrender. We try to tell the compiler these functions
|
||||
// are unreachable in that case, but VC++ emits a warning if it finds any
|
||||
|
@ -97,12 +40,6 @@ typedef mozilla::gfx::Point Point2D; // TODO: get rid of this somehow
|
|||
# define WR_DESTRUCTOR_SAFE_FUNC {}
|
||||
#endif
|
||||
|
||||
// Structs defined in Rust, but opaque to C++ code.
|
||||
struct WrRenderedEpochs;
|
||||
struct WrRenderer;
|
||||
struct WrState;
|
||||
struct WrAPI;
|
||||
|
||||
#include "webrender_ffi_generated.h"
|
||||
|
||||
#undef WR_FUNC
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -61,7 +61,20 @@ HourCycle()
|
|||
key = "clock-format";
|
||||
}
|
||||
|
||||
GSettings* settings = g_settings_new(schema);
|
||||
// This is a workaround for old GTK versions.
|
||||
// Once we bump the minimum version to 2.40 we should replace
|
||||
// this with g_settings_schme_source_lookup.
|
||||
// See bug 1356718 for details.
|
||||
const char* const* schemas = g_settings_list_schemas();
|
||||
GSettings* settings = nullptr;
|
||||
|
||||
for (uint32_t i = 0; schemas[i] != nullptr; i++) {
|
||||
if (strcmp(schemas[i], schema) == 0) {
|
||||
settings = g_settings_new(schema);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (settings) {
|
||||
// We really want to use g_settings_get_user_value which will
|
||||
// only want to take it if user manually changed the value.
|
||||
|
|
|
@ -965,9 +965,7 @@ PresShell::Init(nsIDocument* aDocument,
|
|||
|
||||
// Bind the context to the presentation shell.
|
||||
mPresContext = aPresContext;
|
||||
StyleBackendType backend = aStyleSet->IsServo() ? StyleBackendType::Servo
|
||||
: StyleBackendType::Gecko;
|
||||
aPresContext->AttachShell(this, backend);
|
||||
mPresContext->AttachShell(this, aStyleSet->BackendType());
|
||||
|
||||
// Now we can initialize the style set. Make sure to set the member before
|
||||
// calling Init, since various subroutines need to find the style set off
|
||||
|
|
|
@ -456,7 +456,10 @@ BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t externalImageId = layer->SendImageContainer(container);
|
||||
Maybe<wr::ImageKey> key = layer->SendImageContainer(container, aParentCommands);
|
||||
if (key.isNothing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int32_t appUnitsPerDevPixel = aItem->Frame()->PresContext()->AppUnitsPerDevPixel();
|
||||
Rect destRect =
|
||||
|
@ -466,17 +469,10 @@ BulletRenderer::CreateWebRenderCommandsForImage(nsDisplayItem* aItem,
|
|||
|
||||
WrClipRegion clipRegion = aBuilder.BuildClipRegion(wr::ToWrRect(dest));
|
||||
|
||||
WrImageKey key;
|
||||
key.mNamespace = layer->WrBridge()->GetNamespace();
|
||||
key.mHandle = layer->WrBridge()->GetNextResourceId();
|
||||
aParentCommands.AppendElement(layers::OpAddExternalImage(
|
||||
externalImageId,
|
||||
key));
|
||||
layer->WrManager()->AddImageKeyForDiscard(key);
|
||||
aBuilder.PushImage(wr::ToWrRect(dest),
|
||||
clipRegion,
|
||||
WrImageRendering::Auto,
|
||||
key);
|
||||
key.value());
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -4780,20 +4780,15 @@ nsDisplayBorder::CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuil
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t externalImageId = aLayer->SendImageContainer(container);
|
||||
if (!externalImageId) {
|
||||
Maybe<wr::ImageKey> key = aLayer->SendImageContainer(container, aParentCommands);
|
||||
if (key.isNothing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WrImageKey key;
|
||||
key.mNamespace = aLayer->WrBridge()->GetNamespace();
|
||||
key.mHandle = aLayer->WrBridge()->GetNextResourceId();
|
||||
aParentCommands.AppendElement(OpAddExternalImage(externalImageId, key));
|
||||
aLayer->WrManager()->AddImageKeyForDiscard(key);
|
||||
aBuilder.PushBorderImage(wr::ToWrRect(dest),
|
||||
aBuilder.BuildClipRegion(wr::ToWrRect(clip)),
|
||||
wr::ToWrBorderWidths(widths[0], widths[1], widths[2], widths[3]),
|
||||
key,
|
||||
key.value(),
|
||||
wr::ToWrNinePatchDescriptor(
|
||||
(float)(mBorderImageRenderer->mImageSize.width) / appUnitsPerDevPixel,
|
||||
(float)(mBorderImageRenderer->mImageSize.height) / appUnitsPerDevPixel,
|
||||
|
|
|
@ -616,8 +616,8 @@ nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext* aPresContext,
|
|||
NS_WARNING("Failed to get image container");
|
||||
return;
|
||||
}
|
||||
uint64_t externalImageId = aLayer->SendImageContainer(container);
|
||||
if (!externalImageId) {
|
||||
Maybe<wr::ImageKey> key = aLayer->SendImageContainer(container, aParentCommands);
|
||||
if (key.isNothing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -631,14 +631,9 @@ nsImageRenderer::BuildWebRenderDisplayItems(nsPresContext* aPresContext,
|
|||
Rect clip = fill;
|
||||
Size gapSize((aRepeatSize.width - aDest.width) / appUnitsPerDevPixel,
|
||||
(aRepeatSize.height - aDest.height) / appUnitsPerDevPixel);
|
||||
WrImageKey key;
|
||||
key.mNamespace = aLayer->WrBridge()->GetNamespace();
|
||||
key.mHandle = aLayer->WrBridge()->GetNextResourceId();
|
||||
aParentCommands.AppendElement(OpAddExternalImage(externalImageId, key));
|
||||
aLayer->WrManager()->AddImageKeyForDiscard(key);
|
||||
aBuilder.PushImage(wr::ToWrRect(fill), aBuilder.BuildClipRegion(wr::ToWrRect(clip)),
|
||||
wr::ToWrSize(dest.Size()), wr::ToWrSize(gapSize),
|
||||
wr::ImageRendering::Auto, key);
|
||||
wr::ImageRendering::Auto, key.value());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# DO NOT EDIT! This is a auto-generated temporary list for Stylo testing
|
||||
fails == transitions-inline-already-wrapped-1.html transitions-inline-already-wrapped-1.html
|
||||
== transitions-inline-already-wrapped-1.html transitions-inline-already-wrapped-1.html
|
||||
== transitions-inline-already-wrapped-2.html transitions-inline-already-wrapped-2.html
|
||||
fails == transitions-inline-rewrap-1.html transitions-inline-rewrap-1.html
|
||||
== transitions-inline-rewrap-1.html transitions-inline-rewrap-1.html
|
||||
== transitions-inline-rewrap-2.html transitions-inline-rewrap-2.html
|
||||
== stacking-context-opacity-lose-to-animation.html stacking-context-opacity-lose-to-animation.html
|
||||
== stacking-context-transform-lose-to-animation.html stacking-context-transform-lose-to-animation.html
|
||||
fails == stacking-context-opacity-wins-over-important-style.html stacking-context-opacity-wins-over-important-style.html # Bug 1302946?
|
||||
fails == stacking-context-transform-wins-over-important-style.html stacking-context-transform-wins-over-important-style.html # Bug 1302946?
|
||||
skip-if(stylo) == transition-and-animation-with-different-durations.html transition-and-animation-with-different-durations.html # Bug 1302946?
|
||||
== stacking-context-opacity-wins-over-important-style.html stacking-context-opacity-wins-over-important-style.html
|
||||
== stacking-context-transform-wins-over-important-style.html stacking-context-transform-wins-over-important-style.html
|
||||
== transition-and-animation-with-different-durations.html transition-and-animation-with-different-durations.html
|
||||
|
|
|
@ -58,6 +58,25 @@ AnimationCollection<AnimationType>::GetAnimationCollection(
|
|||
GetProperty(propName));
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetAnimationCollection(
|
||||
const dom::Element *aElement,
|
||||
nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
MOZ_ASSERT(!aPseudoTagOrNull ||
|
||||
aPseudoTagOrNull == nsCSSPseudoElements::before ||
|
||||
aPseudoTagOrNull == nsCSSPseudoElements::after);
|
||||
|
||||
CSSPseudoElementType pseudoType = CSSPseudoElementType::NotPseudo;
|
||||
if (aPseudoTagOrNull) {
|
||||
pseudoType = aPseudoTagOrNull == nsCSSPseudoElements::before
|
||||
? CSSPseudoElementType::before
|
||||
: CSSPseudoElementType::after;
|
||||
}
|
||||
return GetAnimationCollection(aElement, pseudoType);
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetAnimationCollection(
|
||||
|
|
|
@ -70,6 +70,12 @@ public:
|
|||
GetAnimationCollection(const dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
// Get the collection of animations for the given |aElement| and
|
||||
// |aPseudoTagOrNull|.
|
||||
static AnimationCollection<AnimationType>*
|
||||
GetAnimationCollection(const dom::Element* aElement,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
|
||||
// Given the frame |aFrame| with possibly animated content, finds its
|
||||
// associated collection of animations. If |aFrame| is a generated content
|
||||
// frame, this function may examine the parent frame to search for such
|
||||
|
|
|
@ -513,20 +513,75 @@ bool
|
|||
Gecko_ElementHasCSSAnimations(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
MOZ_ASSERT(!aPseudoTagOrNull ||
|
||||
aPseudoTagOrNull == nsCSSPseudoElements::before ||
|
||||
aPseudoTagOrNull == nsCSSPseudoElements::after);
|
||||
|
||||
CSSPseudoElementType pseudoType =
|
||||
nsCSSPseudoElements::GetPseudoType(aPseudoTagOrNull,
|
||||
CSSEnabledState::eForAllContent);
|
||||
nsAnimationManager::CSSAnimationCollection* collection =
|
||||
nsAnimationManager::CSSAnimationCollection
|
||||
::GetAnimationCollection(aElement, pseudoType);
|
||||
::GetAnimationCollection(aElement, aPseudoTagOrNull);
|
||||
|
||||
return collection && !collection->mAnimations.IsEmpty();
|
||||
}
|
||||
|
||||
bool
|
||||
Gecko_ElementHasCSSTransitions(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
nsTransitionManager::CSSTransitionCollection* collection =
|
||||
nsTransitionManager::CSSTransitionCollection
|
||||
::GetAnimationCollection(aElement, aPseudoTagOrNull);
|
||||
|
||||
return collection && !collection->mAnimations.IsEmpty();
|
||||
}
|
||||
|
||||
size_t
|
||||
Gecko_ElementTransitions_Length(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull)
|
||||
{
|
||||
nsTransitionManager::CSSTransitionCollection* collection =
|
||||
nsTransitionManager::CSSTransitionCollection
|
||||
::GetAnimationCollection(aElement, aPseudoTagOrNull);
|
||||
|
||||
return collection ? collection->mAnimations.Length() : 0;
|
||||
}
|
||||
|
||||
static CSSTransition*
|
||||
GetCurrentTransitionAt(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull,
|
||||
size_t aIndex)
|
||||
{
|
||||
nsTransitionManager::CSSTransitionCollection* collection =
|
||||
nsTransitionManager::CSSTransitionCollection
|
||||
::GetAnimationCollection(aElement, aPseudoTagOrNull);
|
||||
if (!collection) {
|
||||
return nullptr;
|
||||
}
|
||||
nsTArray<RefPtr<CSSTransition>>& transitions = collection->mAnimations;
|
||||
return aIndex < transitions.Length()
|
||||
? transitions[aIndex].get()
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
nsCSSPropertyID
|
||||
Gecko_ElementTransitions_PropertyAt(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull,
|
||||
size_t aIndex)
|
||||
{
|
||||
CSSTransition* transition = GetCurrentTransitionAt(aElement,
|
||||
aPseudoTagOrNull,
|
||||
aIndex);
|
||||
return transition ? transition->TransitionProperty()
|
||||
: nsCSSPropertyID::eCSSProperty_UNKNOWN;
|
||||
}
|
||||
|
||||
RawServoAnimationValueBorrowedOrNull
|
||||
Gecko_ElementTransitions_EndValueAt(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull,
|
||||
size_t aIndex)
|
||||
{
|
||||
CSSTransition* transition = GetCurrentTransitionAt(aElement,
|
||||
aPseudoTagOrNull,
|
||||
aIndex);
|
||||
return transition ? transition->ToValue().mServo.get() : nullptr;
|
||||
}
|
||||
|
||||
double
|
||||
Gecko_GetProgressFromComputedTiming(RawGeckoComputedTimingBorrowed aComputedTiming)
|
||||
{
|
||||
|
|
|
@ -205,6 +205,18 @@ bool Gecko_ElementHasAnimations(RawGeckoElementBorrowed aElement,
|
|||
nsIAtom* aPseudoTagOrNull);
|
||||
bool Gecko_ElementHasCSSAnimations(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
bool Gecko_ElementHasCSSTransitions(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
size_t Gecko_ElementTransitions_Length(RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
nsCSSPropertyID Gecko_ElementTransitions_PropertyAt(
|
||||
RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull,
|
||||
size_t aIndex);
|
||||
RawServoAnimationValueBorrowedOrNull Gecko_ElementTransitions_EndValueAt(
|
||||
RawGeckoElementBorrowed aElement,
|
||||
nsIAtom* aPseudoTagOrNull,
|
||||
size_t aIndex);
|
||||
double Gecko_GetProgressFromComputedTiming(RawGeckoComputedTimingBorrowed aComputedTiming);
|
||||
double Gecko_GetPositionInSegment(
|
||||
RawGeckoAnimationPropertySegmentBorrowed aSegment,
|
||||
|
|
|
@ -291,7 +291,7 @@ ServoStyleSet::PrepareAndTraverseSubtree(RawGeckoElementBorrowed aRoot,
|
|||
auto root = const_cast<Element*>(aRoot);
|
||||
|
||||
// If there are still animation restyles needed, trigger a second traversal to
|
||||
// update CSS animations' styles.
|
||||
// update CSS animations or transitions' styles.
|
||||
EffectCompositor* compositor = mPresContext->EffectCompositor();
|
||||
if (forReconstruct ? compositor->PreTraverseInSubtree(root)
|
||||
: compositor->PreTraverse()) {
|
||||
|
|
|
@ -273,7 +273,6 @@ skip-if = toolkit == 'android' #bug 775227
|
|||
[test_transitions_and_reframes.html]
|
||||
[test_transitions_and_restyles.html]
|
||||
[test_transitions_and_zoom.html]
|
||||
skip-if = stylo # timeout bug 1328499
|
||||
[test_transitions_cancel_near_end.html]
|
||||
skip-if = stylo # timeout bug 1328499
|
||||
[test_transitions_computed_values.html]
|
||||
|
@ -283,7 +282,6 @@ skip-if = stylo # timeout bug 1328499
|
|||
[test_transitions.html]
|
||||
skip-if = (android_version == '18' && debug) # bug 1159532
|
||||
[test_transitions_bug537151.html]
|
||||
skip-if = stylo # timeout bug 1328499
|
||||
[test_transitions_dynamic_changes.html]
|
||||
[test_transitions_per_property.html]
|
||||
skip-if = (toolkit == 'android' || stylo) # bug 775227 for android, bug 1292283 for stylo
|
||||
|
|
|
@ -72,18 +72,13 @@ to mochitest command.
|
|||
* test_bug413958.html `monitorConsole` [3]
|
||||
* test_parser_diagnostics_unprintables.html [550]
|
||||
* Transition support:
|
||||
* test_bug621351.html [4]
|
||||
* test_bug621351.html: shorthand properties [4]
|
||||
* test_compute_data_with_start_struct.html `transition` [2]
|
||||
* test_transitions.html [63]
|
||||
* test_transitions_and_reframes.html [16]
|
||||
* test_transitions_and_restyles.html [3]
|
||||
* test_transitions.html: pseudo elements and shorthand properties [*]
|
||||
* test_transitions_computed_value_combinations.html [145]
|
||||
* test_transitions_dynamic_changes.html [10]
|
||||
* test_transitions_step_functions.html [24]
|
||||
* test_value_storage.html `transition` [596]
|
||||
* Events:
|
||||
* test_animations_event_handler_attribute.html [10]
|
||||
* test_animations_event_order.html [11]
|
||||
* test_animations_event_order.html [2]
|
||||
* test_computed_style.html `gradient`: -moz-prefixed radient value [9]
|
||||
* ... `mask`: mask-image isn't set properly bug 1341667 [10]
|
||||
* ... `fill`: svg paint should distinguish whether there is fallback bug 1347409 [2]
|
||||
|
|
|
@ -36,7 +36,7 @@ is(cs.textIndent, "50px", "changing delay doesn't change transitioning");
|
|||
p.style.transitionProperty = "text-indent";
|
||||
is(cs.textIndent, "50px",
|
||||
"irrelevant change to transition property doesn't change transitioning");
|
||||
p.style.transitionProperty = "font";
|
||||
p.style.transitionProperty = "letter-spacing";
|
||||
is(cs.textIndent, "0px",
|
||||
"relevant change to transition property does change transitioning");
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ already_AddRefed<MediaRawData> SampleIterator::GetNext()
|
|||
RefPtr<MediaRawData> sample = new MediaRawData();
|
||||
sample->mTimecode= s->mDecodeTime;
|
||||
sample->mTime = s->mCompositionRange.start;
|
||||
sample->mDuration = s->mCompositionRange.Length();
|
||||
sample->mDuration = TimeUnit::FromMicroseconds(s->mCompositionRange.Length());
|
||||
sample->mOffset = s->mByteRange.mStart;
|
||||
sample->mKeyframe = s->mSync;
|
||||
|
||||
|
|
|
@ -335,7 +335,7 @@ def makensis_progs(target):
|
|||
|
||||
return tuple(candidates)
|
||||
|
||||
nsis = check_prog('MAKENSISU', makensis_progs)
|
||||
nsis = check_prog('MAKENSISU', makensis_progs, allow_missing=True)
|
||||
|
||||
# Make sure the version of makensis is up to date.
|
||||
@depends_if(nsis)
|
||||
|
|
|
@ -92,6 +92,13 @@ fn convert_repeat_mode(from: RepeatKeyword) -> RepeatMode {
|
|||
}
|
||||
}
|
||||
|
||||
fn establishes_containing_block_for_absolute(positioning: position::T) -> bool {
|
||||
match positioning {
|
||||
position::T::absolute | position::T::relative | position::T::fixed => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
trait RgbColor {
|
||||
fn rgb(r: u8, g: u8, b: u8) -> Self;
|
||||
}
|
||||
|
@ -1953,6 +1960,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
// we don't want it to be clipped by its own scroll root.
|
||||
let containing_scroll_root_id = self.setup_scroll_root_for_block(state);
|
||||
|
||||
if establishes_containing_block_for_absolute(self.positioning()) {
|
||||
state.containing_block_scroll_root_id = state.current_scroll_root_id;
|
||||
}
|
||||
|
||||
match block_stacking_context_type {
|
||||
BlockStackingContextType::NonstackingContext => {
|
||||
self.base.collect_stacking_contexts_for_children(state);
|
||||
|
@ -2038,12 +2049,6 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
self.base.scroll_root_id = new_scroll_root_id;
|
||||
state.current_scroll_root_id = new_scroll_root_id;
|
||||
|
||||
match self.positioning() {
|
||||
position::T::absolute | position::T::relative | position::T::fixed =>
|
||||
state.containing_block_scroll_root_id = new_scroll_root_id,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
containing_scroll_root_id
|
||||
}
|
||||
|
||||
|
@ -2153,6 +2158,11 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
self.base.scroll_root_id = state.current_scroll_root_id;
|
||||
|
||||
for mut fragment in self.fragments.fragments.iter_mut() {
|
||||
let previous_containing_block_scroll_root_id = state.containing_block_scroll_root_id;
|
||||
if establishes_containing_block_for_absolute(fragment.style.get_box().position) {
|
||||
state.containing_block_scroll_root_id = state.current_scroll_root_id;
|
||||
}
|
||||
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut block_flow) => {
|
||||
let block_flow = FlowRef::deref_mut(&mut block_flow.flow_ref);
|
||||
|
@ -2162,6 +2172,10 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
let block_flow = FlowRef::deref_mut(&mut block_flow.flow_ref);
|
||||
block_flow.collect_stacking_contexts(state);
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsolute(ref mut block_flow) => {
|
||||
let block_flow = FlowRef::deref_mut(&mut block_flow.flow_ref);
|
||||
block_flow.collect_stacking_contexts(state);
|
||||
}
|
||||
_ if fragment.establishes_stacking_context() => {
|
||||
fragment.stacking_context_id =
|
||||
StackingContextId::new_of_type(fragment.fragment_id(),
|
||||
|
@ -2178,6 +2192,7 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
}
|
||||
_ => fragment.stacking_context_id = state.current_stacking_context_id,
|
||||
}
|
||||
state.containing_block_scroll_root_id = previous_containing_block_scroll_root_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2360,7 +2360,7 @@ impl Document {
|
|||
if attr.local_name() == &local_name!("width") ||
|
||||
attr.local_name() == &local_name!("height") {
|
||||
entry.hint |= RESTYLE_SELF;
|
||||
}
|
||||
}
|
||||
|
||||
let mut snapshot = entry.snapshot.as_mut().unwrap();
|
||||
if snapshot.attrs.is_none() {
|
||||
|
|
|
@ -468,6 +468,10 @@ impl<'le> TElement for ServoLayoutElement<'le> {
|
|||
fn has_css_animations(&self, _pseudo: Option<&PseudoElement>) -> bool {
|
||||
panic!("this should be only called on gecko");
|
||||
}
|
||||
|
||||
fn has_css_transitions(&self, _pseudo: Option<&PseudoElement>) -> bool {
|
||||
panic!("this should be only called on gecko");
|
||||
}
|
||||
}
|
||||
|
||||
impl<'le> PartialEq for ServoLayoutElement<'le> {
|
||||
|
|
|
@ -19,6 +19,7 @@ use font_metrics::FontMetricsProvider;
|
|||
#[cfg(feature = "gecko")] use gecko_bindings::structs;
|
||||
use matching::StyleSharingCandidateCache;
|
||||
use parking_lot::RwLock;
|
||||
#[cfg(feature = "gecko")] use properties::ComputedValues;
|
||||
#[cfg(feature = "gecko")] use selector_parser::PseudoElement;
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
#[cfg(feature = "servo")] use servo_config::opts;
|
||||
|
@ -285,10 +286,22 @@ bitflags! {
|
|||
pub enum SequentialTask<E: TElement> {
|
||||
/// Entry to avoid an unused type parameter error on servo.
|
||||
Unused(SendElement<E>),
|
||||
|
||||
/// Performs one of a number of possible tasks related to updating animations based on the
|
||||
/// |tasks| field. These include updating CSS animations/transitions that changed as part
|
||||
/// of the non-animation style traversal, and updating the computed effect properties.
|
||||
#[cfg(feature = "gecko")]
|
||||
/// Marks that we need to update CSS animations, update effect properties of
|
||||
/// any type of animations after the normal traversal.
|
||||
UpdateAnimations(SendElement<E>, Option<PseudoElement>, UpdateAnimationsTasks),
|
||||
UpdateAnimations {
|
||||
/// The target element.
|
||||
el: SendElement<E>,
|
||||
/// The target pseudo element.
|
||||
pseudo: Option<PseudoElement>,
|
||||
/// The before-change style for transitions. We use before-change style as the initial
|
||||
/// value of its Keyframe. Required if |tasks| includes CSSTransitions.
|
||||
before_change_style: Option<Arc<ComputedValues>>,
|
||||
/// The tasks which are performed in this SequentialTask.
|
||||
tasks: UpdateAnimationsTasks
|
||||
},
|
||||
}
|
||||
|
||||
impl<E: TElement> SequentialTask<E> {
|
||||
|
@ -299,18 +312,24 @@ impl<E: TElement> SequentialTask<E> {
|
|||
match self {
|
||||
Unused(_) => unreachable!(),
|
||||
#[cfg(feature = "gecko")]
|
||||
UpdateAnimations(el, pseudo, tasks) => {
|
||||
unsafe { el.update_animations(pseudo.as_ref(), tasks) };
|
||||
UpdateAnimations { el, pseudo, before_change_style, tasks } => {
|
||||
unsafe { el.update_animations(pseudo.as_ref(), before_change_style, tasks) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a task to update various animation-related state on
|
||||
/// a given (pseudo-)element.
|
||||
#[cfg(feature = "gecko")]
|
||||
/// Creates a task to update various animation state on a given (pseudo-)element.
|
||||
pub fn update_animations(el: E, pseudo: Option<PseudoElement>,
|
||||
pub fn update_animations(el: E,
|
||||
pseudo: Option<PseudoElement>,
|
||||
before_change_style: Option<Arc<ComputedValues>>,
|
||||
tasks: UpdateAnimationsTasks) -> Self {
|
||||
use self::SequentialTask::*;
|
||||
UpdateAnimations(unsafe { SendElement::new(el) }, pseudo, tasks)
|
||||
UpdateAnimations { el: unsafe { SendElement::new(el) },
|
||||
pseudo: pseudo,
|
||||
before_change_style: before_change_style,
|
||||
tasks: tasks }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
use dom::TElement;
|
||||
use properties::ComputedValues;
|
||||
use properties::longhands::display::computed_value as display;
|
||||
use restyle_hints::{RESTYLE_CSS_ANIMATIONS, RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use restyle_hints::{RESTYLE_DESCENDANTS, RESTYLE_LATER_SIBLINGS, RESTYLE_SELF, RestyleHint};
|
||||
use rule_tree::StrongRuleNode;
|
||||
use selector_parser::{EAGER_PSEUDO_COUNT, PseudoElement, RestyleDamage, Snapshot};
|
||||
#[cfg(feature = "servo")] use std::collections::HashMap;
|
||||
|
@ -199,13 +199,13 @@ 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() {
|
||||
if self.0.contains(RESTYLE_CSS_ANIMATIONS) {
|
||||
self.0.remove(RESTYLE_CSS_ANIMATIONS);
|
||||
if self.0.intersects(RestyleHint::for_animations()) {
|
||||
self.0.remove(RestyleHint::for_animations());
|
||||
}
|
||||
return Self::empty();
|
||||
}
|
||||
|
||||
debug_assert!(!self.0.contains(RESTYLE_CSS_ANIMATIONS),
|
||||
debug_assert!(!self.0.intersects(RestyleHint::for_animations()),
|
||||
"There should not be any animation restyle hints \
|
||||
during normal traversal");
|
||||
|
||||
|
@ -259,7 +259,7 @@ impl StoredRestyleHint {
|
|||
|
||||
/// Returns true if the hint has animation-only restyle.
|
||||
pub fn has_animation_hint(&self) -> bool {
|
||||
self.0.contains(RESTYLE_CSS_ANIMATIONS)
|
||||
self.0.intersects(RestyleHint::for_animations())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,11 +14,15 @@ use data::ElementData;
|
|||
use element_state::ElementState;
|
||||
use font_metrics::FontMetricsProvider;
|
||||
use properties::{ComputedValues, PropertyDeclarationBlock};
|
||||
#[cfg(feature = "gecko")] use properties::animated_properties::AnimationValue;
|
||||
#[cfg(feature = "gecko")] use properties::animated_properties::TransitionProperty;
|
||||
use rule_tree::CascadeLevel;
|
||||
use selector_parser::{ElementExt, PreExistingComputedValues, PseudoElement};
|
||||
use selectors::matching::ElementSelectorFlags;
|
||||
use shared_lock::Locked;
|
||||
use sink::Push;
|
||||
use std::fmt;
|
||||
#[cfg(feature = "gecko")] use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Deref;
|
||||
|
@ -320,6 +324,14 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
|||
AnimationRules(None, None)
|
||||
}
|
||||
|
||||
/// Get this element's animation rule by the cascade level.
|
||||
fn get_animation_rule_by_cascade(&self,
|
||||
_pseudo: Option<&PseudoElement>,
|
||||
_cascade_level: CascadeLevel)
|
||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get this element's animation rule.
|
||||
fn get_animation_rule(&self, _pseudo: Option<&PseudoElement>)
|
||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||
|
@ -453,6 +465,7 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
|||
/// Creates a task to update various animation state on a given (pseudo-)element.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn update_animations(&self, _pseudo: Option<&PseudoElement>,
|
||||
before_change_style: Option<Arc<ComputedValues>>,
|
||||
tasks: UpdateAnimationsTasks);
|
||||
|
||||
/// Returns true if the element has relevant animations. Relevant
|
||||
|
@ -463,6 +476,10 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
|||
/// Returns true if the element has a CSS animation.
|
||||
fn has_css_animations(&self, _pseudo: Option<&PseudoElement>) -> bool;
|
||||
|
||||
/// Returns true if the element has a CSS transition (including running transitions and
|
||||
/// completed transitions).
|
||||
fn has_css_transitions(&self, _pseudo: Option<&PseudoElement>) -> bool;
|
||||
|
||||
/// Returns true if the element has animation restyle hints.
|
||||
fn has_animation_restyle_hints(&self) -> bool {
|
||||
let data = match self.borrow_data() {
|
||||
|
@ -472,6 +489,44 @@ pub trait TElement : Eq + PartialEq + Debug + Hash + Sized + Copy + Clone +
|
|||
return data.get_restyle()
|
||||
.map_or(false, |r| r.hint.has_animation_hint());
|
||||
}
|
||||
|
||||
/// Gets the current existing CSS transitions, by |property, end value| pairs in a HashMap.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn get_css_transitions_info(&self,
|
||||
pseudo: Option<&PseudoElement>)
|
||||
-> HashMap<TransitionProperty, Arc<AnimationValue>>;
|
||||
|
||||
/// Does a rough (and cheap) check for whether or not transitions might need to be updated that
|
||||
/// will quickly return false for the common case of no transitions specified or running. If
|
||||
/// this returns false, we definitely don't need to update transitions but if it returns true
|
||||
/// we can perform the more thoroughgoing check, needs_transitions_update, to further
|
||||
/// reduce the possibility of false positives.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn might_need_transitions_update(&self,
|
||||
old_values: &Option<&Arc<ComputedValues>>,
|
||||
new_values: &Arc<ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>) -> bool;
|
||||
|
||||
/// Returns true if one of the transitions needs to be updated on this element. We check all
|
||||
/// the transition properties to make sure that updating transitions is necessary.
|
||||
/// This method should only be called if might_needs_transitions_update returns true when
|
||||
/// passed the same parameters.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn needs_transitions_update(&self,
|
||||
before_change_style: &Arc<ComputedValues>,
|
||||
after_change_style: &Arc<ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>) -> bool;
|
||||
|
||||
/// Returns true if we need to update transitions for the specified property on this element.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn needs_transitions_update_per_property(&self,
|
||||
property: TransitionProperty,
|
||||
combined_duration: f32,
|
||||
before_change_style: &Arc<ComputedValues>,
|
||||
after_change_style: &Arc<ComputedValues>,
|
||||
existing_transitions: &HashMap<TransitionProperty,
|
||||
Arc<AnimationValue>>)
|
||||
-> bool;
|
||||
}
|
||||
|
||||
/// Trait abstracting over different kinds of dirty-descendants bits.
|
||||
|
|
|
@ -34,6 +34,7 @@ use gecko_bindings::bindings::{Gecko_SetNodeFlags, Gecko_UnsetNodeFlags};
|
|||
use gecko_bindings::bindings::Gecko_ClassOrClassList;
|
||||
use gecko_bindings::bindings::Gecko_ElementHasAnimations;
|
||||
use gecko_bindings::bindings::Gecko_ElementHasCSSAnimations;
|
||||
use gecko_bindings::bindings::Gecko_ElementHasCSSTransitions;
|
||||
use gecko_bindings::bindings::Gecko_GetAnimationRule;
|
||||
use gecko_bindings::bindings::Gecko_GetExtraContentStyleDeclarations;
|
||||
use gecko_bindings::bindings::Gecko_GetHTMLPresentationAttrDeclarationBlock;
|
||||
|
@ -56,7 +57,7 @@ use media_queries::Device;
|
|||
use parking_lot::RwLock;
|
||||
use properties::{ComputedValues, parse_style_attribute};
|
||||
use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
|
||||
use properties::animated_properties::AnimationValueMap;
|
||||
use properties::animated_properties::{AnimationValue, AnimationValueMap, TransitionProperty};
|
||||
use properties::style_structs::Font;
|
||||
use rule_tree::CascadeLevel as ServoCascadeLevel;
|
||||
use selector_parser::{ElementExt, Snapshot};
|
||||
|
@ -66,6 +67,7 @@ use selectors::parser::{AttrSelector, NamespaceConstraint};
|
|||
use shared_lock::Locked;
|
||||
use sink::Push;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ptr;
|
||||
|
@ -528,6 +530,17 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
self.get_transition_rule(pseudo))
|
||||
}
|
||||
|
||||
fn get_animation_rule_by_cascade(&self,
|
||||
pseudo: Option<&PseudoElement>,
|
||||
cascade_level: ServoCascadeLevel)
|
||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||
match cascade_level {
|
||||
ServoCascadeLevel::Animations => self.get_animation_rule(pseudo),
|
||||
ServoCascadeLevel::Transitions => self.get_transition_rule(pseudo),
|
||||
_ => panic!("Unsupported cascade level for getting the animation rule")
|
||||
}
|
||||
}
|
||||
|
||||
fn get_animation_rule(&self, pseudo: Option<&PseudoElement>)
|
||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||
get_animation_rule(self, pseudo, CascadeLevel::Animations)
|
||||
|
@ -653,7 +666,9 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
(self.flags() & node_flags) == node_flags
|
||||
}
|
||||
|
||||
fn update_animations(&self, pseudo: Option<&PseudoElement>,
|
||||
fn update_animations(&self,
|
||||
pseudo: Option<&PseudoElement>,
|
||||
before_change_style: Option<Arc<ComputedValues>>,
|
||||
tasks: UpdateAnimationsTasks) {
|
||||
// We have to update animations even if the element has no computed style
|
||||
// since it means the element is in a display:none subtree, we should destroy
|
||||
|
@ -680,9 +695,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
);
|
||||
|
||||
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
|
||||
let before_change_values = before_change_style.as_ref().map(|v| *HasArcFFI::arc_as_borrowed(v));
|
||||
unsafe {
|
||||
Gecko_UpdateAnimations(self.0, atom_ptr,
|
||||
None,
|
||||
before_change_values,
|
||||
computed_values_opt,
|
||||
parent_values_opt,
|
||||
tasks.bits());
|
||||
|
@ -698,6 +714,167 @@ impl<'le> TElement for GeckoElement<'le> {
|
|||
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
|
||||
unsafe { Gecko_ElementHasCSSAnimations(self.0, atom_ptr) }
|
||||
}
|
||||
|
||||
fn has_css_transitions(&self, pseudo: Option<&PseudoElement>) -> bool {
|
||||
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
|
||||
unsafe { Gecko_ElementHasCSSTransitions(self.0, atom_ptr) }
|
||||
}
|
||||
|
||||
fn get_css_transitions_info(&self,
|
||||
pseudo: Option<&PseudoElement>)
|
||||
-> HashMap<TransitionProperty, Arc<AnimationValue>> {
|
||||
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
|
||||
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
|
||||
use gecko_bindings::bindings::Gecko_ElementTransitions_PropertyAt;
|
||||
|
||||
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
|
||||
let collection_length = unsafe { Gecko_ElementTransitions_Length(self.0, atom_ptr) };
|
||||
let mut map = HashMap::with_capacity(collection_length);
|
||||
for i in 0..collection_length {
|
||||
let (property, raw_end_value) = unsafe {
|
||||
(Gecko_ElementTransitions_PropertyAt(self.0, atom_ptr, i as usize).into(),
|
||||
Gecko_ElementTransitions_EndValueAt(self.0, atom_ptr, i as usize))
|
||||
};
|
||||
let end_value = AnimationValue::arc_from_borrowed(&raw_end_value);
|
||||
debug_assert!(end_value.is_some());
|
||||
map.insert(property, end_value.unwrap().clone());
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
fn might_need_transitions_update(&self,
|
||||
old_values: &Option<&Arc<ComputedValues>>,
|
||||
new_values: &Arc<ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>) -> bool {
|
||||
use properties::longhands::display::computed_value as display;
|
||||
|
||||
if old_values.is_none() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let ref new_box_style = new_values.get_box();
|
||||
let transition_not_running = !self.has_css_transitions(pseudo) &&
|
||||
new_box_style.transition_property_count() == 1 &&
|
||||
new_box_style.transition_combined_duration_at(0) <= 0.0f32;
|
||||
let new_display_style = new_box_style.clone_display();
|
||||
let old_display_style = old_values.map(|ref old| old.get_box().clone_display()).unwrap();
|
||||
|
||||
new_box_style.transition_property_count() > 0 &&
|
||||
!transition_not_running &&
|
||||
(new_display_style != display::T::none &&
|
||||
old_display_style != display::T::none)
|
||||
}
|
||||
|
||||
// Detect if there are any changes that require us to update transitions. This is used as a
|
||||
// more thoroughgoing check than the, cheaper might_need_transitions_update check.
|
||||
// The following logic shadows the logic used on the Gecko side
|
||||
// (nsTransitionManager::DoUpdateTransitions) where we actually perform the update.
|
||||
// https://drafts.csswg.org/css-transitions/#starting
|
||||
fn needs_transitions_update(&self,
|
||||
before_change_style: &Arc<ComputedValues>,
|
||||
after_change_style: &Arc<ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>) -> bool {
|
||||
use gecko_bindings::structs::nsCSSPropertyID;
|
||||
use properties::animated_properties;
|
||||
use std::collections::HashSet;
|
||||
|
||||
debug_assert!(self.might_need_transitions_update(&Some(before_change_style),
|
||||
after_change_style,
|
||||
pseudo),
|
||||
"We should only call needs_transitions_update if \
|
||||
might_need_transitions_update returns true");
|
||||
|
||||
let ref after_change_box_style = after_change_style.get_box();
|
||||
let transitions_count = after_change_box_style.transition_property_count();
|
||||
let existing_transitions = self.get_css_transitions_info(pseudo);
|
||||
let mut transitions_to_keep = if !existing_transitions.is_empty() &&
|
||||
(after_change_box_style.transition_nscsspropertyid_at(0) !=
|
||||
nsCSSPropertyID::eCSSPropertyExtra_all_properties) {
|
||||
Some(HashSet::<TransitionProperty>::with_capacity(transitions_count))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Check if this property is none, custom or unknown.
|
||||
let is_none_or_custom_property = |property: nsCSSPropertyID| -> bool {
|
||||
return property == nsCSSPropertyID::eCSSPropertyExtra_no_properties ||
|
||||
property == nsCSSPropertyID::eCSSPropertyExtra_variable ||
|
||||
property == nsCSSPropertyID::eCSSProperty_UNKNOWN;
|
||||
};
|
||||
|
||||
for i in 0..transitions_count {
|
||||
let property = after_change_box_style.transition_nscsspropertyid_at(i);
|
||||
let combined_duration = after_change_box_style.transition_combined_duration_at(i);
|
||||
|
||||
// We don't need to update transition for none/custom properties.
|
||||
if is_none_or_custom_property(property) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut property_check_helper = |property: TransitionProperty| -> bool {
|
||||
if self.needs_transitions_update_per_property(property,
|
||||
combined_duration,
|
||||
before_change_style,
|
||||
after_change_style,
|
||||
&existing_transitions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some(set) = transitions_to_keep.as_mut() {
|
||||
set.insert(property);
|
||||
}
|
||||
false
|
||||
};
|
||||
// FIXME: Bug 1353628: Shorthand properties are parsed failed now, so after fixing
|
||||
// that, we have to handle shorthand.
|
||||
if property == nsCSSPropertyID::eCSSPropertyExtra_all_properties {
|
||||
if TransitionProperty::any(property_check_helper) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if animated_properties::nscsspropertyid_is_animatable(property) &&
|
||||
property_check_helper(property.into()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have to cancel the running transition because this is not a matching
|
||||
// transition-property value.
|
||||
transitions_to_keep.map_or(false, |set| {
|
||||
existing_transitions.keys().any(|property| !set.contains(property))
|
||||
})
|
||||
}
|
||||
|
||||
fn needs_transitions_update_per_property(&self,
|
||||
property: TransitionProperty,
|
||||
combined_duration: f32,
|
||||
before_change_style: &Arc<ComputedValues>,
|
||||
after_change_style: &Arc<ComputedValues>,
|
||||
existing_transitions: &HashMap<TransitionProperty,
|
||||
Arc<AnimationValue>>)
|
||||
-> bool {
|
||||
use properties::animated_properties::AnimatedProperty;
|
||||
|
||||
// We don't allow transitions on properties that are not interpolable.
|
||||
if property.is_discrete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if existing_transitions.contains_key(&property) {
|
||||
// If there is an existing transition, update only if the end value differs.
|
||||
// If the end value has not changed, we should leave the currently running
|
||||
// transition as-is since we don't want to interrupt its timing function.
|
||||
let after_value =
|
||||
Arc::new(AnimationValue::from_computed_values(&property, after_change_style));
|
||||
return existing_transitions.get(&property).unwrap() != &after_value;
|
||||
}
|
||||
|
||||
combined_duration > 0.0f32 &&
|
||||
AnimatedProperty::from_transition_property(&property,
|
||||
before_change_style,
|
||||
after_change_style).does_animate()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'le> PartialEq for GeckoElement<'le> {
|
||||
|
|
|
@ -648,6 +648,30 @@ extern "C" {
|
|||
aPseudoTagOrNull: *mut nsIAtom)
|
||||
-> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_ElementHasCSSTransitions(aElement: RawGeckoElementBorrowed,
|
||||
aPseudoTagOrNull: *mut nsIAtom)
|
||||
-> bool;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_ElementTransitions_Length(aElement: RawGeckoElementBorrowed,
|
||||
aPseudoTagOrNull: *mut nsIAtom)
|
||||
-> usize;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_ElementTransitions_PropertyAt(aElement:
|
||||
RawGeckoElementBorrowed,
|
||||
aPseudoTagOrNull: *mut nsIAtom,
|
||||
aIndex: usize)
|
||||
-> nsCSSPropertyID;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_ElementTransitions_EndValueAt(aElement:
|
||||
RawGeckoElementBorrowed,
|
||||
aPseudoTagOrNull: *mut nsIAtom,
|
||||
aIndex: usize)
|
||||
-> RawServoAnimationValueBorrowedOrNull;
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_GetProgressFromComputedTiming(aComputedTiming:
|
||||
RawGeckoComputedTimingBorrowed)
|
||||
|
|
|
@ -19,7 +19,7 @@ use dom::{AnimationRules, SendElement, TElement, TNode};
|
|||
use font_metrics::FontMetricsProvider;
|
||||
use properties::{CascadeFlags, ComputedValues, SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP, cascade};
|
||||
use properties::longhands::display::computed_value as display;
|
||||
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RestyleHint};
|
||||
use restyle_hints::{RESTYLE_STYLE_ATTRIBUTE, RESTYLE_CSS_ANIMATIONS, RESTYLE_CSS_TRANSITIONS, RestyleHint};
|
||||
use rule_tree::{CascadeLevel, RuleTree, StrongRuleNode};
|
||||
use selector_parser::{PseudoElement, RestyleDamage, SelectorImpl};
|
||||
use selectors::bloom::BloomFilter;
|
||||
|
@ -477,10 +477,14 @@ trait PrivateMatchMethods: TElement {
|
|||
|
||||
// Handle animations.
|
||||
if animate && !context.shared.traversal_flags.for_animation_only() {
|
||||
let pseudo_style = pseudo_style.as_ref().map(|&(ref pseudo, ref computed_style)| {
|
||||
(*pseudo, &**computed_style)
|
||||
});
|
||||
self.process_animations(context,
|
||||
&mut old_values,
|
||||
&mut new_values,
|
||||
pseudo);
|
||||
primary_style,
|
||||
&pseudo_style);
|
||||
}
|
||||
|
||||
// Accumulate restyle damage.
|
||||
|
@ -496,32 +500,59 @@ trait PrivateMatchMethods: TElement {
|
|||
}
|
||||
}
|
||||
|
||||
/// get_after_change_style removes the transition rules from the ComputedValues.
|
||||
/// If there is no transition rule in the ComputedValues, it returns None.
|
||||
#[cfg(feature = "gecko")]
|
||||
fn get_after_change_style(&self,
|
||||
context: &mut StyleContext<Self>,
|
||||
primary_style: &ComputedStyle,
|
||||
pseudo_style: &Option<(&PseudoElement, &ComputedStyle)>)
|
||||
-> Arc<ComputedValues> {
|
||||
-> Option<Arc<ComputedValues>> {
|
||||
let style = &pseudo_style.as_ref().map_or(primary_style, |p| &*p.1);
|
||||
let rule_node = &style.rules;
|
||||
let without_transition_rules =
|
||||
context.shared.stylist.rule_tree.remove_transition_rule_if_applicable(rule_node);
|
||||
if without_transition_rules == *rule_node {
|
||||
// Note that unwrapping here is fine, because the style is
|
||||
// only incomplete during the styling process.
|
||||
return style.values.as_ref().unwrap().clone();
|
||||
// We don't have transition rule in this case, so return None to let the caller
|
||||
// use the original ComputedValues.
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut cascade_flags = CascadeFlags::empty();
|
||||
if self.skip_root_and_item_based_display_fixup() {
|
||||
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP)
|
||||
cascade_flags.insert(SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP);
|
||||
}
|
||||
self.cascade_with_rules(context.shared,
|
||||
&context.thread_local.font_metrics_provider,
|
||||
&without_transition_rules,
|
||||
primary_style,
|
||||
cascade_flags,
|
||||
pseudo_style.is_some())
|
||||
Some(self.cascade_with_rules(context.shared,
|
||||
&context.thread_local.font_metrics_provider,
|
||||
&without_transition_rules,
|
||||
primary_style,
|
||||
cascade_flags,
|
||||
pseudo_style.is_some()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
fn needs_animations_update(&self,
|
||||
old_values: &Option<Arc<ComputedValues>>,
|
||||
new_values: &Arc<ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>) -> bool {
|
||||
let ref new_box_style = new_values.get_box();
|
||||
let has_new_animation_style = new_box_style.animation_name_count() >= 1 &&
|
||||
new_box_style.animation_name_at(0).0.len() != 0;
|
||||
let has_animations = self.has_css_animations(pseudo);
|
||||
|
||||
old_values.as_ref().map_or(has_new_animation_style, |ref old| {
|
||||
let ref old_box_style = old.get_box();
|
||||
let old_display_style = old_box_style.clone_display();
|
||||
let new_display_style = new_box_style.clone_display();
|
||||
// FIXME: Bug 1344581: We still need to compare keyframe rules.
|
||||
!old_box_style.animations_equals(&new_box_style) ||
|
||||
(old_display_style == display::T::none &&
|
||||
new_display_style != display::T::none &&
|
||||
has_new_animation_style) ||
|
||||
(old_display_style != display::T::none &&
|
||||
new_display_style == display::T::none &&
|
||||
has_animations)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "gecko")]
|
||||
|
@ -529,39 +560,63 @@ trait PrivateMatchMethods: TElement {
|
|||
context: &mut StyleContext<Self>,
|
||||
old_values: &mut Option<Arc<ComputedValues>>,
|
||||
new_values: &mut Arc<ComputedValues>,
|
||||
pseudo: Option<&PseudoElement>) {
|
||||
use context::{CSS_ANIMATIONS, EFFECT_PROPERTIES};
|
||||
primary_style: &ComputedStyle,
|
||||
pseudo_style: &Option<(&PseudoElement, &ComputedStyle)>) {
|
||||
use context::{CSS_ANIMATIONS, CSS_TRANSITIONS, EFFECT_PROPERTIES};
|
||||
use context::UpdateAnimationsTasks;
|
||||
|
||||
let ref new_box_style = new_values.get_box();
|
||||
let has_new_animation_style = new_box_style.animation_name_count() >= 1 &&
|
||||
new_box_style.animation_name_at(0).0.len() != 0;
|
||||
let has_animations = self.has_css_animations(pseudo);
|
||||
|
||||
let pseudo = pseudo_style.map(|(p, _)| p);
|
||||
let mut tasks = UpdateAnimationsTasks::empty();
|
||||
let needs_update_animations =
|
||||
old_values.as_ref().map_or(has_new_animation_style, |ref old| {
|
||||
let ref old_box_style = old.get_box();
|
||||
let old_display_style = old_box_style.clone_display();
|
||||
let new_display_style = new_box_style.clone_display();
|
||||
// FIXME: Bug 1344581: We still need to compare keyframe rules.
|
||||
!old_box_style.animations_equals(&new_box_style) ||
|
||||
(old_display_style == display::T::none &&
|
||||
new_display_style != display::T::none &&
|
||||
has_new_animation_style) ||
|
||||
(old_display_style != display::T::none &&
|
||||
new_display_style == display::T::none &&
|
||||
has_animations)
|
||||
});
|
||||
if needs_update_animations {
|
||||
if self.needs_animations_update(old_values, new_values, pseudo) {
|
||||
tasks.insert(CSS_ANIMATIONS);
|
||||
}
|
||||
|
||||
let before_change_style = if self.might_need_transitions_update(&old_values.as_ref(),
|
||||
new_values,
|
||||
pseudo) {
|
||||
let after_change_style = if self.has_css_transitions(pseudo) {
|
||||
self.get_after_change_style(context, primary_style, pseudo_style)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// In order to avoid creating a SequentialTask for transitions which may not be updated,
|
||||
// we check it per property to make sure Gecko side will really update transition.
|
||||
let needs_transitions_update = {
|
||||
// We borrow new_values here, so need to add a scope to make sure we release it
|
||||
// before assigning a new value to it.
|
||||
let after_change_style_ref = match after_change_style {
|
||||
Some(ref value) => value,
|
||||
None => &new_values
|
||||
};
|
||||
self.needs_transitions_update(old_values.as_ref().unwrap(),
|
||||
after_change_style_ref,
|
||||
pseudo)
|
||||
};
|
||||
|
||||
if needs_transitions_update {
|
||||
if let Some(values_without_transitions) = after_change_style {
|
||||
*new_values = values_without_transitions;
|
||||
}
|
||||
tasks.insert(CSS_TRANSITIONS);
|
||||
|
||||
// We need to clone old_values into SequentialTask, so we can use it later.
|
||||
old_values.clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if self.has_animations(pseudo) {
|
||||
tasks.insert(EFFECT_PROPERTIES);
|
||||
}
|
||||
|
||||
if !tasks.is_empty() {
|
||||
let task = ::context::SequentialTask::update_animations(*self,
|
||||
pseudo.cloned(),
|
||||
before_change_style,
|
||||
tasks);
|
||||
context.thread_local.tasks.push(task);
|
||||
}
|
||||
|
@ -572,7 +627,8 @@ trait PrivateMatchMethods: TElement {
|
|||
context: &mut StyleContext<Self>,
|
||||
old_values: &mut Option<Arc<ComputedValues>>,
|
||||
new_values: &mut Arc<ComputedValues>,
|
||||
_pseudo: Option<&PseudoElement>) {
|
||||
_primary_style: &ComputedStyle,
|
||||
_pseudo_style: &Option<(&PseudoElement, &ComputedStyle)>) {
|
||||
let possibly_expired_animations =
|
||||
&mut context.thread_local.current_element_info.as_mut().unwrap()
|
||||
.possibly_expired_animations;
|
||||
|
@ -984,24 +1040,43 @@ pub trait MatchMethods : TElement {
|
|||
}
|
||||
};
|
||||
|
||||
// RESTYLE_CSS_ANIMATIONS is processed prior to other restyle hints
|
||||
// in the name of animation-only traversal. Rest of restyle hints
|
||||
// RESTYLE_CSS_ANIMATIONS or RESTYLE_CSS_TRANSITIONS is processed prior to other
|
||||
// restyle hints in the name of animation-only traversal. Rest of restyle hints
|
||||
// will be processed in a subsequent normal traversal.
|
||||
if hint.contains(RESTYLE_CSS_ANIMATIONS) {
|
||||
if hint.intersects(RestyleHint::for_animations()) {
|
||||
debug_assert!(context.shared.traversal_flags.for_animation_only());
|
||||
|
||||
let animation_rule = self.get_animation_rule(None);
|
||||
replace_rule_node(CascadeLevel::Animations,
|
||||
animation_rule.as_ref(),
|
||||
primary_rules);
|
||||
|
||||
let pseudos = &mut element_styles.pseudos;
|
||||
for pseudo in pseudos.keys().iter().filter(|p| p.is_before_or_after()) {
|
||||
let animation_rule = self.get_animation_rule(Some(&pseudo));
|
||||
let pseudo_rules = &mut pseudos.get_mut(&pseudo).unwrap().rules;
|
||||
replace_rule_node(CascadeLevel::Animations,
|
||||
use data::EagerPseudoStyles;
|
||||
let mut replace_rule_node_for_animation = |level: CascadeLevel,
|
||||
primary_rules: &mut StrongRuleNode,
|
||||
pseudos: &mut EagerPseudoStyles| {
|
||||
let animation_rule = self.get_animation_rule_by_cascade(None, level);
|
||||
replace_rule_node(level,
|
||||
animation_rule.as_ref(),
|
||||
pseudo_rules);
|
||||
primary_rules);
|
||||
|
||||
for pseudo in pseudos.keys().iter().filter(|p| p.is_before_or_after()) {
|
||||
let animation_rule = self.get_animation_rule_by_cascade(Some(&pseudo), level);
|
||||
let pseudo_rules = &mut pseudos.get_mut(&pseudo).unwrap().rules;
|
||||
replace_rule_node(level,
|
||||
animation_rule.as_ref(),
|
||||
pseudo_rules);
|
||||
}
|
||||
};
|
||||
|
||||
// Apply Transition rules and Animation rules if the corresponding restyle hint
|
||||
// is contained.
|
||||
let pseudos = &mut element_styles.pseudos;
|
||||
if hint.contains(RESTYLE_CSS_TRANSITIONS) {
|
||||
replace_rule_node_for_animation(CascadeLevel::Transitions,
|
||||
primary_rules,
|
||||
pseudos);
|
||||
}
|
||||
|
||||
if hint.contains(RESTYLE_CSS_ANIMATIONS) {
|
||||
replace_rule_node_for_animation(CascadeLevel::Animations,
|
||||
primary_rules,
|
||||
pseudos);
|
||||
}
|
||||
} else if hint.contains(RESTYLE_STYLE_ATTRIBUTE) {
|
||||
let style_attribute = self.style_attribute();
|
||||
|
|
|
@ -44,6 +44,7 @@ use gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
|
|||
use gecko_bindings::bindings::{Gecko_ResetFilters, Gecko_CopyFiltersFrom};
|
||||
use gecko_bindings::bindings::RawGeckoPresContextBorrowed;
|
||||
use gecko_bindings::structs::{self, StyleComplexColor};
|
||||
use gecko_bindings::structs::nsCSSPropertyID;
|
||||
use gecko_bindings::structs::nsStyleVariables;
|
||||
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordData, CoordDataMut};
|
||||
use gecko_bindings::sugar::ownership::HasArcFFI;
|
||||
|
@ -679,6 +680,7 @@ impl Debug for ${style_struct.gecko_struct_name} {
|
|||
"LengthOrPercentageOrAuto": impl_style_coord,
|
||||
"LengthOrPercentageOrNone": impl_style_coord,
|
||||
"LengthOrNone": impl_style_coord,
|
||||
"LengthOrNormal": impl_style_coord,
|
||||
"MaxLength": impl_style_coord,
|
||||
"MinLength": impl_style_coord,
|
||||
"Number": impl_simple,
|
||||
|
@ -1985,6 +1987,11 @@ fn static_assert() {
|
|||
${impl_transition_time_value('duration', 'Duration')}
|
||||
${impl_transition_timing_function()}
|
||||
|
||||
pub fn transition_combined_duration_at(&self, index: usize) -> f32 {
|
||||
// https://drafts.csswg.org/css-transitions/#transition-combined-duration
|
||||
self.gecko.mTransitions[index].mDuration.max(0.0) + self.gecko.mTransitions[index].mDelay
|
||||
}
|
||||
|
||||
pub fn set_transition_property(&mut self, v: longhands::transition_property::computed_value::T) {
|
||||
use gecko_bindings::structs::nsCSSPropertyID::eCSSPropertyExtra_no_properties;
|
||||
|
||||
|
@ -2018,6 +2025,10 @@ fn static_assert() {
|
|||
self.gecko.mTransitions[index].mProperty.into()
|
||||
}
|
||||
|
||||
pub fn transition_nscsspropertyid_at(&self, index: usize) -> nsCSSPropertyID {
|
||||
self.gecko.mTransitions[index].mProperty
|
||||
}
|
||||
|
||||
pub fn copy_transition_property_from(&mut self, other: &Self) {
|
||||
unsafe { self.gecko.mTransitions.ensure_len(other.gecko.mTransitions.len()) };
|
||||
|
||||
|
@ -3610,6 +3621,17 @@ clip-path
|
|||
|
||||
${impl_simple_copy('column_count', 'mColumnCount')}
|
||||
|
||||
pub fn clone_column_count(&self) -> longhands::column_count::computed_value::T {
|
||||
use gecko_bindings::structs::NS_STYLE_COLUMN_COUNT_AUTO;
|
||||
if self.gecko.mColumnCount != NS_STYLE_COLUMN_COUNT_AUTO {
|
||||
debug_assert!((self.gecko.mColumnCount as i32) >= 0 &&
|
||||
(self.gecko.mColumnCount as i32) < i32::max_value());
|
||||
Either::First(self.gecko.mColumnCount as i32)
|
||||
} else {
|
||||
Either::Second(Auto)
|
||||
}
|
||||
}
|
||||
|
||||
<% impl_app_units("column_rule_width", "mColumnRuleWidth", need_clone=True,
|
||||
round_to_pixels=True) %>
|
||||
</%self:impl_trait>
|
||||
|
|
|
@ -29,7 +29,7 @@ use std::fmt;
|
|||
use style_traits::ToCss;
|
||||
use super::ComputedValues;
|
||||
use values::CSSFloat;
|
||||
use values::{Auto, Either};
|
||||
use values::{Auto, Either, Normal};
|
||||
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
||||
use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone};
|
||||
use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
|
||||
|
@ -66,6 +66,19 @@ impl TransitionProperty {
|
|||
% endfor
|
||||
}
|
||||
|
||||
/// Iterates over every property that is not TransitionProperty::All, stopping and returning
|
||||
/// true when the provided callback returns true for the first time.
|
||||
pub fn any<F: FnMut(TransitionProperty) -> bool>(mut cb: F) -> bool {
|
||||
% for prop in data.longhands:
|
||||
% if prop.animatable:
|
||||
if cb(TransitionProperty::${prop.camel_case}) {
|
||||
return true;
|
||||
}
|
||||
% endif
|
||||
% endfor
|
||||
false
|
||||
}
|
||||
|
||||
/// Parse a transition-property value.
|
||||
pub fn parse(input: &mut Parser) -> Result<Self, ()> {
|
||||
match_ignore_ascii_case! { &try!(input.expect_ident()),
|
||||
|
@ -515,6 +528,13 @@ impl Interpolate for Auto {
|
|||
}
|
||||
}
|
||||
|
||||
impl Interpolate for Normal {
|
||||
#[inline]
|
||||
fn interpolate(&self, _other: &Self, _progress: f64) -> Result<Self, ()> {
|
||||
Ok(Normal)
|
||||
}
|
||||
}
|
||||
|
||||
impl <T> Interpolate for Option<T>
|
||||
where T: Interpolate,
|
||||
{
|
||||
|
|
|
@ -6,20 +6,19 @@
|
|||
|
||||
<% data.new_style_struct("Column", inherited=False) %>
|
||||
|
||||
// FIXME: This prop should be animatable.
|
||||
${helpers.predefined_type("column-width",
|
||||
"length::LengthOrAuto",
|
||||
"Either::Second(Auto)",
|
||||
initial_specified_value="Either::Second(Auto)",
|
||||
parse_method="parse_non_negative_length",
|
||||
extra_prefixes="moz",
|
||||
animation_type="none",
|
||||
animation_type="normal",
|
||||
experimental=True,
|
||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-width")}
|
||||
|
||||
|
||||
// FIXME: This prop should be animatable.
|
||||
${helpers.predefined_type("column-count", "IntegerOrAuto",
|
||||
${helpers.predefined_type("column-count",
|
||||
"IntegerOrAuto",
|
||||
"Either::Second(Auto)",
|
||||
parse_method="parse_positive",
|
||||
initial_specified_value="Either::Second(Auto)",
|
||||
|
@ -28,14 +27,13 @@ ${helpers.predefined_type("column-count", "IntegerOrAuto",
|
|||
extra_prefixes="moz",
|
||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-count")}
|
||||
|
||||
// FIXME: This prop should be animatable.
|
||||
${helpers.predefined_type("column-gap",
|
||||
"length::LengthOrNormal",
|
||||
"Either::Second(Normal)",
|
||||
parse_method='parse_non_negative_length',
|
||||
extra_prefixes="moz",
|
||||
experimental=True,
|
||||
animation_type="none",
|
||||
animation_type="normal",
|
||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-gap")}
|
||||
|
||||
${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
|
||||
|
|
|
@ -48,6 +48,11 @@ bitflags! {
|
|||
/// of their descendants.
|
||||
const RESTYLE_LATER_SIBLINGS = 0x08,
|
||||
|
||||
/// Replace the style data coming from CSS transitions without updating
|
||||
/// any other style data. This hint is only processed in animation-only
|
||||
/// traversal which is prior to normal traversal.
|
||||
const RESTYLE_CSS_TRANSITIONS = 0x10,
|
||||
|
||||
/// Replace the style data coming from CSS animations without updating
|
||||
/// any other style data. This hint is only processed in animation-only
|
||||
/// traversal which is prior to normal traversal.
|
||||
|
@ -87,6 +92,7 @@ pub fn assert_restyle_hints_match() {
|
|||
// (RESTYLE_SELF | RESTYLE_DESCENDANTS).
|
||||
nsRestyleHint_eRestyle_Subtree => RESTYLE_DESCENDANTS,
|
||||
nsRestyleHint_eRestyle_LaterSiblings => RESTYLE_LATER_SIBLINGS,
|
||||
nsRestyleHint_eRestyle_CSSTransitions => RESTYLE_CSS_TRANSITIONS,
|
||||
nsRestyleHint_eRestyle_CSSAnimations => RESTYLE_CSS_ANIMATIONS,
|
||||
nsRestyleHint_eRestyle_StyleAttribute => RESTYLE_STYLE_ATTRIBUTE,
|
||||
}
|
||||
|
@ -96,7 +102,12 @@ impl RestyleHint {
|
|||
/// The subset hints that affect the styling of a single element during the
|
||||
/// traversal.
|
||||
pub fn for_self() -> Self {
|
||||
RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE | RESTYLE_CSS_ANIMATIONS
|
||||
RESTYLE_SELF | RESTYLE_STYLE_ATTRIBUTE | RESTYLE_CSS_ANIMATIONS | RESTYLE_CSS_TRANSITIONS
|
||||
}
|
||||
|
||||
/// The subset hints that are used for animation restyle.
|
||||
pub fn for_animations() -> Self {
|
||||
RESTYLE_CSS_ANIMATIONS | RESTYLE_CSS_TRANSITIONS
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1788,12 +1788,15 @@ pub extern "C" fn Servo_NoteExplicitHints(element: RawGeckoElementBorrowed,
|
|||
debug!("Servo_NoteExplicitHints: {:?}, restyle_hint={:?}, change_hint={:?}",
|
||||
element, restyle_hint, change_hint);
|
||||
debug_assert!(restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations ||
|
||||
(restyle_hint.0 & structs::nsRestyleHint_eRestyle_CSSAnimations.0) == 0,
|
||||
"eRestyle_CSSAnimations should only appear by itself");
|
||||
restyle_hint == structs::nsRestyleHint_eRestyle_CSSTransitions ||
|
||||
(restyle_hint.0 & (structs::nsRestyleHint_eRestyle_CSSAnimations.0 |
|
||||
structs::nsRestyleHint_eRestyle_CSSTransitions.0)) == 0,
|
||||
"eRestyle_CSSAnimations or eRestyle_CSSTransitions should only appear by itself");
|
||||
|
||||
let mut maybe_data = element.mutate_data();
|
||||
let maybe_restyle_data = maybe_data.as_mut().and_then(|d| unsafe {
|
||||
maybe_restyle(d, element, restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations)
|
||||
maybe_restyle(d, element, restyle_hint == structs::nsRestyleHint_eRestyle_CSSAnimations ||
|
||||
restyle_hint == structs::nsRestyleHint_eRestyle_CSSTransitions)
|
||||
});
|
||||
if let Some(restyle_data) = maybe_restyle_data {
|
||||
let restyle_hint: RestyleHint = restyle_hint.into();
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace mozilla {
|
|||
namespace widget {
|
||||
|
||||
BOOL CALLBACK
|
||||
CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam)
|
||||
CollectMonitors(HMONITOR aMon, HDC hDCScreen, LPRECT, LPARAM ioParam)
|
||||
{
|
||||
auto screens = reinterpret_cast<nsTArray<RefPtr<Screen>>*>(ioParam);
|
||||
BOOL success = FALSE;
|
||||
|
@ -41,11 +41,7 @@ CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam)
|
|||
LayoutDeviceIntRect availRect(info.rcWork.left, info.rcWork.top,
|
||||
info.rcWork.right - info.rcWork.left,
|
||||
info.rcWork.bottom - info.rcWork.top);
|
||||
//XXX not sure how to get this info for multiple monitors, this might be ok...
|
||||
HDC hDCScreen = ::GetDC(nullptr);
|
||||
NS_ASSERTION(hDCScreen,"GetDC Failure");
|
||||
uint32_t pixelDepth = ::GetDeviceCaps(hDCScreen, BITSPIXEL);
|
||||
::ReleaseDC(nullptr, hDCScreen);
|
||||
if (pixelDepth == 32) {
|
||||
// If a device uses 32 bits per pixel, it's still only using 8 bits
|
||||
// per color component, which is what our callers want to know.
|
||||
|
@ -73,9 +69,12 @@ ScreenHelperWin::RefreshScreens()
|
|||
MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
|
||||
|
||||
AutoTArray<RefPtr<Screen>, 4> screens;
|
||||
BOOL result = ::EnumDisplayMonitors(nullptr, nullptr,
|
||||
HDC hdc = ::CreateDC(L"DISPLAY", nullptr, nullptr, nullptr);
|
||||
NS_ASSERTION(hdc,"CreateDC Failure");
|
||||
BOOL result = ::EnumDisplayMonitors(hdc, nullptr,
|
||||
(MONITORENUMPROC)CollectMonitors,
|
||||
(LPARAM)&screens);
|
||||
::DeleteDC(hdc);
|
||||
if (!result) {
|
||||
NS_WARNING("Unable to EnumDisplayMonitors");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче