зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1581240 - Return collected frames as a promise to JS r=bzbarsky,mstange,nika
The `setCompositionRecording` API on nsIDOMWindowUtils has been broken up into two new APIs: * `startCompositionRecording()`, which starts the composition recorder; and * `stopCompositionRecording(bool writeToDisk)` which stops the composition recorder and either returns a Promise that resolves to the collected frames or returns a Promise that resolves when the frames have been written to disk. The collected frames are serialized over IPC as part of a Shmem as to not approach the IPC data transfer limit. Differential Revision: https://phabricator.services.mozilla.com/D47818 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
e62c6d736d
Коммит
3e24c77cf6
|
@ -20,14 +20,16 @@
|
|||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/BlobBinding.h"
|
||||
#include "mozilla/dom/DocumentInlines.h"
|
||||
#include "mozilla/dom/DOMCollectedFramesBinding.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/Touch.h"
|
||||
#include "mozilla/dom/UserActivation.h"
|
||||
#include "mozilla/PendingAnimationTracker.h"
|
||||
#include "nsIObjectLoadingContent.h"
|
||||
#include "nsFrame.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
#include "mozilla/layers/PCompositorBridgeTypes.h"
|
||||
#include "mozilla/layers/ShadowLayers.h"
|
||||
#include "ClientLayerManager.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "CubebDeviceEnumerator.h"
|
||||
|
@ -43,9 +45,11 @@
|
|||
#include "nsJSUtils.h"
|
||||
|
||||
#include "mozilla/ChaosMode.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/MiscEvents.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/TextEventDispatcher.h"
|
||||
|
@ -4031,6 +4035,56 @@ nsDOMWindowUtils::WrCapture() {
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) {
|
||||
return aValue ? StartCompositionRecording(aOutPromise)
|
||||
: StopCompositionRecording(true, aOutPromise);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::StartCompositionRecording(Promise** aOutPromise) {
|
||||
NS_ENSURE_ARG(aOutPromise);
|
||||
*aOutPromise = nullptr;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow);
|
||||
NS_ENSURE_STATE(outer);
|
||||
nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow();
|
||||
NS_ENSURE_STATE(inner);
|
||||
|
||||
ErrorResult err;
|
||||
RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err);
|
||||
if (NS_WARN_IF(err.Failed())) {
|
||||
return err.StealNSResult();
|
||||
}
|
||||
|
||||
CompositorBridgeChild* cbc = GetCompositorBridge();
|
||||
if (NS_WARN_IF(!cbc)) {
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
} else {
|
||||
cbc->SendBeginRecording(TimeStamp::Now())
|
||||
->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[promise](const bool& aSuccess) {
|
||||
if (aSuccess) {
|
||||
promise->MaybeResolve(true);
|
||||
} else {
|
||||
promise->MaybeRejectWithDOMException(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"The composition recorder is already running.");
|
||||
}
|
||||
},
|
||||
[promise](const mozilla::ipc::ResponseRejectReason&) {
|
||||
promise->MaybeRejectWithDOMException(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"Could not start the composition recorder.");
|
||||
});
|
||||
}
|
||||
|
||||
promise.forget(aOutPromise);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::StopCompositionRecording(bool aWriteToDisk,
|
||||
Promise** aOutPromise) {
|
||||
NS_ENSURE_ARG_POINTER(aOutPromise);
|
||||
*aOutPromise = nullptr;
|
||||
|
||||
|
@ -4048,30 +4102,8 @@ nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) {
|
|||
CompositorBridgeChild* cbc = GetCompositorBridge();
|
||||
if (NS_WARN_IF(!cbc)) {
|
||||
promise->MaybeReject(NS_ERROR_UNEXPECTED);
|
||||
promise.forget(aOutPromise);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (aValue) {
|
||||
cbc->SendBeginRecording(TimeStamp::Now())
|
||||
->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[promise](const bool& aSuccess) {
|
||||
if (aSuccess) {
|
||||
promise->MaybeResolveWithUndefined();
|
||||
} else {
|
||||
promise->MaybeRejectWithDOMException(
|
||||
NS_ERROR_DOM_INVALID_STATE_ERR,
|
||||
"The composition recorder is already running.");
|
||||
}
|
||||
},
|
||||
[promise](const mozilla::ipc::ResponseRejectReason&) {
|
||||
promise->MaybeRejectWithDOMException(
|
||||
NS_ERROR_DOM_UNKNOWN_ERR,
|
||||
"Could not start the composition recorder.");
|
||||
});
|
||||
} else {
|
||||
cbc->SendEndRecording()->Then(
|
||||
} else if (aWriteToDisk) {
|
||||
cbc->SendEndRecordingToDisk()->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[promise](const bool& aSuccess) {
|
||||
if (aSuccess) {
|
||||
|
@ -4087,6 +4119,67 @@ nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) {
|
|||
NS_ERROR_DOM_UNKNOWN_ERR,
|
||||
"Could not stop the composition recorder.");
|
||||
});
|
||||
} else {
|
||||
cbc->SendEndRecordingToMemory()->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[promise](Maybe<CollectedFramesParams>&& aFrames) {
|
||||
if (!aFrames) {
|
||||
promise->MaybeRejectWithDOMException(
|
||||
NS_ERROR_DOM_UNKNOWN_ERR,
|
||||
"Could not stop the composition recorder.");
|
||||
return;
|
||||
}
|
||||
|
||||
DOMCollectedFrames domFrames;
|
||||
if (!domFrames.mFrames.SetCapacity(aFrames->frames().Length(),
|
||||
fallible)) {
|
||||
promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
domFrames.mRecordingStart = aFrames->recordingStart();
|
||||
|
||||
CheckedInt<size_t> totalSize(0);
|
||||
for (const CollectedFrameParams& frame : aFrames->frames()) {
|
||||
totalSize += frame.length();
|
||||
}
|
||||
|
||||
if (totalSize.isValid() &&
|
||||
totalSize.value() > aFrames->buffer().Size<char>()) {
|
||||
promise->MaybeRejectWithDOMException(
|
||||
NS_ERROR_DOM_UNKNOWN_ERR,
|
||||
"Could not interpret returned frames.");
|
||||
return;
|
||||
}
|
||||
|
||||
Span<const char> buffer(aFrames->buffer().get<char>(),
|
||||
aFrames->buffer().Size<char>());
|
||||
|
||||
for (const CollectedFrameParams& frame : aFrames->frames()) {
|
||||
size_t length = frame.length();
|
||||
|
||||
Span<const char> dataUri = buffer.First(length);
|
||||
|
||||
// We have to do a fallible AppendElement() because WebIDL
|
||||
// dictionaries use FallibleTArray. However, this cannot fail due to
|
||||
// the pre-allocation earlier.
|
||||
DOMCollectedFrame* domFrame =
|
||||
domFrames.mFrames.AppendElement(fallible);
|
||||
MOZ_ASSERT(domFrame);
|
||||
|
||||
domFrame->mTimeOffset = frame.timeOffset();
|
||||
domFrame->mDataUri = nsCString(dataUri);
|
||||
|
||||
buffer = buffer.Subspan(length);
|
||||
}
|
||||
|
||||
promise->MaybeResolve(domFrames);
|
||||
},
|
||||
[promise](const mozilla::ipc::ResponseRejectReason&) {
|
||||
promise->MaybeRejectWithDOMException(
|
||||
NS_ERROR_DOM_UNKNOWN_ERR,
|
||||
"Could not stop the composition recorder.");
|
||||
});
|
||||
}
|
||||
|
||||
promise.forget(aOutPromise);
|
||||
|
@ -4101,7 +4194,6 @@ nsDOMWindowUtils::SetTransactionLogging(bool aValue) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SetSystemFont(const nsACString& aFontName) {
|
||||
nsIWidget* widget = GetWidget();
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A single frame collected by the |CompositionRecorder|.
|
||||
*/
|
||||
[GenerateConversionToJS]
|
||||
dictionary DOMCollectedFrame {
|
||||
/**
|
||||
* The offset of the frame past the start point of the recording (in
|
||||
* milliseconds).
|
||||
*/
|
||||
required double timeOffset;
|
||||
/** A data: URI containing the PNG image data of the frame. */
|
||||
required ByteString dataUri;
|
||||
};
|
||||
|
||||
/**
|
||||
* Information about frames collected by the |CompositionRecorder|.
|
||||
*/
|
||||
[GenerateConversionToJS]
|
||||
dictionary DOMCollectedFrames {
|
||||
/** The collected frames. */
|
||||
required sequence<DOMCollectedFrame> frames;
|
||||
/** The start point of the recording (in milliseconds). */
|
||||
required double recordingStart;
|
||||
};
|
|
@ -39,6 +39,7 @@ WEBIDL_FILES = [
|
|||
'DebuggerNotificationObserver.webidl',
|
||||
'DebuggerUtils.webidl',
|
||||
'DocumentL10n.webidl',
|
||||
'DOMCollectedFrames.webidl',
|
||||
'DominatorTree.webidl',
|
||||
'DOMLocalization.webidl',
|
||||
'Flex.webidl',
|
||||
|
@ -79,4 +80,3 @@ if CONFIG['MOZ_PLACES']:
|
|||
WEBIDL_FILES += [
|
||||
'PrioEncoder.webidl',
|
||||
]
|
||||
|
||||
|
|
|
@ -1914,9 +1914,32 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
|
||||
/**
|
||||
* Toggle recording of composition on and off.
|
||||
*
|
||||
* This is equivalent to calling |startCompositionRecorder()| or
|
||||
* |stopCompositionRecorder(true)|.
|
||||
*/
|
||||
Promise setCompositionRecording(in boolean aValue);
|
||||
|
||||
/**
|
||||
* Start the composition recorder.
|
||||
*
|
||||
* @return A promise that is resolved to true if the composion recorder was
|
||||
* started successfully.
|
||||
*/
|
||||
Promise startCompositionRecording();
|
||||
|
||||
/**
|
||||
* Stop the composition recorder.
|
||||
*
|
||||
* @param aWriteToDisk Whether or not the frames should be written to disk.
|
||||
* If false, they will be returned in the promise.
|
||||
* @return A promise that resolves when the frames have been collected.
|
||||
* When |aWriteToDisk| is true, the promise will resolve to |undefined|.
|
||||
* Otherwise, the promise will resolve to a |DOMCollectedFrames| dictionary,
|
||||
* which contains the timestamps and contents of the captured frames.
|
||||
*/
|
||||
Promise stopCompositionRecording(in boolean aWriteToDisk);
|
||||
|
||||
/**
|
||||
* Toggle transaction logging on and off.
|
||||
*/
|
||||
|
|
|
@ -137,6 +137,17 @@ void HostLayerManager::WriteCollectedFrames() {
|
|||
}
|
||||
}
|
||||
|
||||
Maybe<CollectedFrames> HostLayerManager::GetCollectedFrames() {
|
||||
Maybe<CollectedFrames> maybeFrames;
|
||||
|
||||
if (mCompositionRecorder) {
|
||||
maybeFrames.emplace(mCompositionRecorder->GetCollectedFrames());
|
||||
mCompositionRecorder = nullptr;
|
||||
}
|
||||
|
||||
return maybeFrames;
|
||||
}
|
||||
|
||||
/**
|
||||
* LayerManagerComposite
|
||||
*/
|
||||
|
|
|
@ -211,6 +211,8 @@ class HostLayerManager : public LayerManager {
|
|||
*/
|
||||
void WriteCollectedFrames();
|
||||
|
||||
Maybe<CollectedFrames> GetCollectedFrames();
|
||||
|
||||
protected:
|
||||
bool mDebugOverlayWantsNextFrame;
|
||||
nsTArray<ImageCompositeNotificationInfo> mImageCompositeNotifications;
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "mozilla/media/MediaSystemResourceService.h" // for MediaSystemResourceService
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
#include "mozilla/PerfStats.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
# include "basic/X11BasicCompositor.h" // for X11BasicCompositor
|
||||
|
@ -2743,8 +2744,8 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvBeginRecording(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecording(
|
||||
EndRecordingResolver&& aResolve) {
|
||||
mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToDisk(
|
||||
EndRecordingToDiskResolver&& aResolve) {
|
||||
if (!mHaveCompositionRecorder) {
|
||||
aResolve(false);
|
||||
return IPC_OK();
|
||||
|
@ -2767,5 +2768,63 @@ mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecording(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult CompositorBridgeParent::RecvEndRecordingToMemory(
|
||||
EndRecordingToMemoryResolver&& aResolve) {
|
||||
if (!mHaveCompositionRecorder) {
|
||||
aResolve(Nothing());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (mLayerManager) {
|
||||
Maybe<CollectedFrames> frames = mLayerManager->GetCollectedFrames();
|
||||
if (frames) {
|
||||
aResolve(WrapCollectedFrames(std::move(*frames)));
|
||||
} else {
|
||||
aResolve(Nothing());
|
||||
}
|
||||
} else if (mWrBridge) {
|
||||
RefPtr<CompositorBridgeParent> self = this;
|
||||
mWrBridge->GetCollectedFrames()->Then(
|
||||
MessageLoop::current()->SerialEventTarget(), __func__,
|
||||
[self, resolve{aResolve}](CollectedFrames&& frames) {
|
||||
resolve(self->WrapCollectedFrames(std::move(frames)));
|
||||
},
|
||||
[resolve{aResolve}]() { resolve(Nothing()); });
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
Maybe<CollectedFramesParams> CompositorBridgeParent::WrapCollectedFrames(
|
||||
CollectedFrames&& aFrames) {
|
||||
CollectedFramesParams ipcFrames;
|
||||
ipcFrames.recordingStart() = aFrames.mRecordingStart;
|
||||
|
||||
size_t totalLength = 0;
|
||||
for (const CollectedFrame& frame : aFrames.mFrames) {
|
||||
totalLength += frame.mDataUri.Length();
|
||||
}
|
||||
|
||||
Shmem shmem;
|
||||
if (!AllocShmem(totalLength, SharedMemory::TYPE_BASIC, &shmem)) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
{
|
||||
char* raw = shmem.get<char>();
|
||||
for (CollectedFrame& frame : aFrames.mFrames) {
|
||||
size_t length = frame.mDataUri.Length();
|
||||
|
||||
PodCopy(raw, frame.mDataUri.get(), length);
|
||||
raw += length;
|
||||
|
||||
ipcFrames.frames().EmplaceBack(frame.mTimeOffset, length);
|
||||
}
|
||||
}
|
||||
ipcFrames.buffer() = std::move(shmem);
|
||||
|
||||
return Some(std::move(ipcFrames));
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator
|
||||
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
|
||||
#include "mozilla/layers/MetricsSharingController.h"
|
||||
#include "mozilla/layers/PCompositorBridgeTypes.h"
|
||||
#include "mozilla/layers/PCompositorBridgeParent.h"
|
||||
#include "mozilla/layers/APZTestData.h"
|
||||
#include "mozilla/webrender/WebRenderTypes.h"
|
||||
|
@ -246,8 +247,10 @@ class CompositorBridgeParentBase : public PCompositorBridgeParent,
|
|||
virtual mozilla::ipc::IPCResult RecvAllPluginsCaptured() = 0;
|
||||
virtual mozilla::ipc::IPCResult RecvBeginRecording(
|
||||
const TimeStamp& aRecordingStart, BeginRecordingResolver&& aResolve) = 0;
|
||||
virtual mozilla::ipc::IPCResult RecvEndRecording(
|
||||
EndRecordingResolver&& aResolve) = 0;
|
||||
virtual mozilla::ipc::IPCResult RecvEndRecordingToDisk(
|
||||
EndRecordingToDiskResolver&& aResolve) = 0;
|
||||
virtual mozilla::ipc::IPCResult RecvEndRecordingToMemory(
|
||||
EndRecordingToMemoryResolver&& aResolve) = 0;
|
||||
virtual mozilla::ipc::IPCResult RecvInitialize(
|
||||
const LayersId& rootLayerTreeId) = 0;
|
||||
virtual mozilla::ipc::IPCResult RecvGetFrameUniformity(
|
||||
|
@ -363,8 +366,10 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
|
|||
mozilla::ipc::IPCResult RecvBeginRecording(
|
||||
const TimeStamp& aRecordingStart,
|
||||
BeginRecordingResolver&& aResolve) override;
|
||||
mozilla::ipc::IPCResult RecvEndRecording(
|
||||
EndRecordingResolver&& aResolve) override;
|
||||
mozilla::ipc::IPCResult RecvEndRecordingToDisk(
|
||||
EndRecordingToDiskResolver&& aResolve) override;
|
||||
mozilla::ipc::IPCResult RecvEndRecordingToMemory(
|
||||
EndRecordingToMemoryResolver&& aResolve) override;
|
||||
|
||||
void NotifyMemoryPressure() override;
|
||||
void AccumulateMemoryReport(wr::MemoryReport*) override;
|
||||
|
@ -676,6 +681,11 @@ class CompositorBridgeParent final : public CompositorBridgeParentBase,
|
|||
*/
|
||||
static void DeallocateLayerTreeId(LayersId aId);
|
||||
|
||||
/**
|
||||
* Wrap the data structure to be sent over IPC.
|
||||
*/
|
||||
Maybe<CollectedFramesParams> WrapCollectedFrames(CollectedFrames&& aFrames);
|
||||
|
||||
protected:
|
||||
// Protected destructor, to discourage deletion outside of Release():
|
||||
virtual ~CompositorBridgeParent();
|
||||
|
|
|
@ -96,12 +96,18 @@ class ContentCompositorBridgeParent final : public CompositorBridgeParentBase {
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvEndRecording(
|
||||
EndRecordingResolver&& aResolve) override {
|
||||
mozilla::ipc::IPCResult RecvEndRecordingToDisk(
|
||||
EndRecordingToDiskResolver&& aResolve) override {
|
||||
aResolve(false);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvEndRecordingToMemory(
|
||||
EndRecordingToMemoryResolver&& aResolve) override {
|
||||
aResolve(Nothing());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult RecvGetFrameUniformity(
|
||||
FrameUniformityData* aOutData) override {
|
||||
// Don't support calculating frame uniformity on the child process and
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
include LayersSurfaces;
|
||||
include LayersMessages;
|
||||
include PlatformWidgetTypes;
|
||||
include PCompositorBridgeTypes;
|
||||
include protocol PAPZ;
|
||||
include protocol PAPZCTreeManager;
|
||||
include protocol PBrowser;
|
||||
|
@ -64,7 +65,6 @@ struct FrameStats {
|
|||
nsCString url;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The PCompositorBridge protocol is a top-level protocol for the compositor.
|
||||
* There is an instance of the protocol for each compositor, plus one for each
|
||||
|
@ -271,9 +271,12 @@ parent:
|
|||
async BeginRecording(TimeStamp aRecordingStart)
|
||||
returns (bool success);
|
||||
|
||||
async EndRecording()
|
||||
async EndRecordingToDisk()
|
||||
returns (bool success);
|
||||
|
||||
async EndRecordingToMemory()
|
||||
returns (CollectedFramesParams? frames);
|
||||
|
||||
// To set up sharing the composited output to Firefox Reality on Desktop
|
||||
async RequestFxrOutput();
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
struct CollectedFrameParams {
|
||||
double timeOffset;
|
||||
uint32_t length;
|
||||
};
|
||||
|
||||
struct CollectedFramesParams {
|
||||
double recordingStart;
|
||||
CollectedFrameParams[] frames;
|
||||
Shmem buffer;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
|
@ -568,6 +568,7 @@ IPDL_SOURCES += [
|
|||
'ipc/PAPZInputBridge.ipdl',
|
||||
'ipc/PCanvas.ipdl',
|
||||
'ipc/PCompositorBridge.ipdl',
|
||||
'ipc/PCompositorBridgeTypes.ipdlh',
|
||||
'ipc/PCompositorManager.ipdl',
|
||||
'ipc/PImageBridge.ipdl',
|
||||
'ipc/PLayerTransaction.ipdl',
|
||||
|
|
Загрузка…
Ссылка в новой задаче