This commit is contained in:
Wes Kocher 2017-04-17 13:03:40 -07:00
Родитель c944eed13a 228c755a80
Коммит b53f4d8806
93 изменённых файлов: 1649 добавлений и 867 удалений

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

@ -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");
}