Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2017-03-15 13:17:53 +01:00
Родитель 9f8f7ef83a f807b332df
Коммит 7a55af51fb
108 изменённых файлов: 2006 добавлений и 573 удалений

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

@ -45,7 +45,7 @@ class CertificateVerificationResult {
result.chain = certListToJSArray(aVerifiedChain);
} else {
result.error = "certificate reverification";
console.log(`${this.hostname}: ${aPRErrorCode}`);
Services.console.logStringMessage(`${this.hostname}: ${aPRErrorCode}`);
}
this.resolve(result);
}
@ -193,15 +193,16 @@ function makeRequests() {
function analyzeAndReport(results) {
let payload = { version: "1.0", mismatches: [] };
Services.console.logStringMessage("deployment-checker results:");
for (let result of results) {
// Skip if the connection resulted in any kind of error.
if ("error" in result) {
console.log(`${result.hostname}: ${result.error} - skipping`);
Services.console.logStringMessage(`${result.hostname}: ${result.error} - skipping`);
continue;
}
// Skip imported roots.
if (!result.chain[result.chain.length - 1].isBuiltInRoot) {
console.log(`${result.hostname}: imported root - skipping`);
Services.console.logStringMessage(`${result.hostname}: imported root - skipping`);
continue;
}
@ -226,12 +227,10 @@ function analyzeAndReport(results) {
if (report) {
payload.mismatches.push({ hostname: result.hostname,
chain: certArrayToBase64(result.chain) });
} else {
Services.console.logStringMessage(`${result.hostname} sends expected certificate chain`);
}
}
console.log("deployment-checker results:");
console.log(results);
console.log("deployment-checker payload:");
console.log(payload);
return TelemetryController.submitExternalPing("deployment-checker", payload,
{});
}

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

@ -459,6 +459,8 @@
@RESPATH@/components/nsContentPrefService.js
@RESPATH@/components/nsContentDispatchChooser.manifest
@RESPATH@/components/nsContentDispatchChooser.js
@RESPATH@/components/nsHandlerService-json.manifest
@RESPATH@/components/nsHandlerService-json.js
@RESPATH@/components/nsHandlerService.manifest
@RESPATH@/components/nsHandlerService.js
@RESPATH@/components/nsWebHandlerApp.manifest

Двоичные данные
build/pgo/certs/cert8.db

Двоичный файл не отображается.

Двоичные данные
build/pgo/certs/key3.db

Двоичный файл не отображается.

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

@ -190,6 +190,7 @@ http://exception.flashallow.example.com:80
http://flashblock.example.com:80
http://exception.flashblock.example.com:80
http://subdocument.example.com:80
https://subdocument.example.com:443
http://exception.subdocument.example.com:80
#

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

@ -476,7 +476,7 @@ exports.defaultThemes = [
// (By default, supported target is only local tab)
exports.ToolboxButtons = [
{ id: "command-button-splitconsole",
description: l10n("toolbox.buttons.splitconsole"),
description: l10n("toolbox.buttons.splitconsole", "Esc"),
isTargetSupported: target => !target.isAddon,
onClick(event, toolbox) {
toolbox.toggleSplitConsole();

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

@ -13070,9 +13070,10 @@ ArrayContainsTable(const nsTArray<nsCString>& aTableArray,
* toolkit/components/url-classifier/flash-block-lists.rst
*/
FlashClassification
nsDocument::PrincipalFlashClassification(bool aIsTopLevel)
nsDocument::PrincipalFlashClassification()
{
nsresult rv;
bool isThirdPartyDoc = IsThirdParty();
// If flash blocking is disabled, it is equivalent to all sites being
// whitelisted.
@ -13105,7 +13106,7 @@ nsDocument::PrincipalFlashClassification(bool aIsTopLevel)
Preferences::GetCString("urlclassifier.flashExceptTable",
&denyExceptionsTables);
MaybeAddTableToTableList(denyExceptionsTables, tables);
if (!aIsTopLevel) {
if (isThirdPartyDoc) {
Preferences::GetCString("urlclassifier.flashSubDocTable",
&subDocDenyTables);
MaybeAddTableToTableList(subDocDenyTables, tables);
@ -13150,7 +13151,7 @@ nsDocument::PrincipalFlashClassification(bool aIsTopLevel)
return FlashClassification::Allowed;
}
if (!aIsTopLevel && ArrayContainsTable(results, subDocDenyTables) &&
if (isThirdPartyDoc && ArrayContainsTable(results, subDocDenyTables) &&
!ArrayContainsTable(results, subDocDenyExceptionsTables)) {
return FlashClassification::Denied;
}
@ -13173,7 +13174,7 @@ nsDocument::ComputeFlashClassification()
bool isTopLevel = !parent;
FlashClassification classification;
if (isTopLevel) {
classification = PrincipalFlashClassification(isTopLevel);
classification = PrincipalFlashClassification();
} else {
nsCOMPtr<nsIDocument> parentDocument = GetParentDocument();
if (!parentDocument) {
@ -13185,7 +13186,7 @@ nsDocument::ComputeFlashClassification()
if (parentClassification == FlashClassification::Denied) {
classification = FlashClassification::Denied;
} else {
classification = PrincipalFlashClassification(isTopLevel);
classification = PrincipalFlashClassification();
// Allow unknown children to inherit allowed status from parent, but
// do not allow denied children to do so.
@ -13219,3 +13220,83 @@ nsDocument::DocumentFlashClassification()
return mFlashClassification;
}
/**
* Initializes |mIsThirdParty| if necessary and returns its value. The value
* returned represents whether this document should be considered Third-Party.
*
* A top-level document cannot be a considered Third-Party; only subdocuments
* may. For a subdocument to be considered Third-Party, it must meet ANY ONE
* of the following requirements:
* - The document's parent is Third-Party
* - The document has a different scheme (http/https) than its parent document
* - The document's domain and subdomain do not match those of its parent
* document.
*
* If there is an error in determining whether the document is Third-Party,
* it will be assumed to be Third-Party for security reasons.
*/
bool
nsDocument::IsThirdParty()
{
if (mIsThirdParty.isSome()) {
return mIsThirdParty.value();
}
nsCOMPtr<nsIDocShellTreeItem> docshell = this->GetDocShell();
if (!docshell) {
mIsThirdParty.emplace(true);
return mIsThirdParty.value();
}
nsCOMPtr<nsIDocShellTreeItem> parent;
nsresult rv = docshell->GetSameTypeParent(getter_AddRefs(parent));
MOZ_ASSERT(NS_SUCCEEDED(rv),
"nsIDocShellTreeItem::GetSameTypeParent should never fail");
bool isTopLevel = !parent;
if (isTopLevel) {
mIsThirdParty.emplace(false);
return mIsThirdParty.value();
}
nsCOMPtr<nsIDocument> parentDocument = GetParentDocument();
if (!parentDocument) {
// Failure
mIsThirdParty.emplace(true);
return mIsThirdParty.value();
}
if (parentDocument->IsThirdParty()) {
mIsThirdParty.emplace(true);
return mIsThirdParty.value();
}
nsCOMPtr<nsIPrincipal> principal = GetPrincipal();
nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(parentDocument,
&rv);
if (NS_WARN_IF(NS_FAILED(rv) || !sop)) {
// Failure
mIsThirdParty.emplace(true);
return mIsThirdParty.value();
}
nsCOMPtr<nsIPrincipal> parentPrincipal = sop->GetPrincipal();
bool principalsMatch = false;
rv = principal->Equals(parentPrincipal, &principalsMatch);
if (NS_WARN_IF(NS_FAILED(rv))) {
// Failure
mIsThirdParty.emplace(true);
return mIsThirdParty.value();
}
if (!principalsMatch) {
mIsThirdParty.emplace(true);
return mIsThirdParty.value();
}
// Fall-through. Document is not a Third-Party Document.
mIsThirdParty.emplace(false);
return mIsThirdParty.value();
}

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

@ -70,6 +70,7 @@
#include "mozilla/LinkedList.h"
#include "CustomElementRegistry.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/Maybe.h"
#define XML_DECLARATION_BITS_DECLARATION_EXISTS (1 << 0)
#define XML_DECLARATION_BITS_ENCODING_EXISTS (1 << 1)
@ -1308,6 +1309,7 @@ protected:
void UpdateScreenOrientation();
virtual mozilla::dom::FlashClassification DocumentFlashClassification() override;
virtual bool IsThirdParty() override;
#define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_) \
NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers, nsIDocumentObserver, \
@ -1331,7 +1333,7 @@ protected:
// Retrieves the classification of the Flash plugins in the document based on
// the classification lists.
mozilla::dom::FlashClassification PrincipalFlashClassification(bool aIsTopLevel);
mozilla::dom::FlashClassification PrincipalFlashClassification();
// Attempts to determine the Flash classification of this page based on the
// the classification lists and the classification of parent documents.
@ -1383,6 +1385,9 @@ protected:
nsWeakPtr mFullscreenRoot;
mozilla::dom::FlashClassification mFlashClassification;
// Do not use this value directly. Call the |IsThirdParty()| method, which
// caches its result here.
mozilla::Maybe<bool> mIsThirdParty;
private:
static bool CustomElementConstructor(JSContext* aCx, unsigned aArgc, JS::Value* aVp);

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

@ -2903,6 +2903,7 @@ public:
// For more information on Flash classification, see
// toolkit/components/url-classifier/flash-block-lists.rst
virtual mozilla::dom::FlashClassification DocumentFlashClassification() = 0;
virtual bool IsThirdParty() = 0;
protected:
bool GetUseCounter(mozilla::UseCounter aUseCounter)

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

@ -2973,13 +2973,6 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
{
nsTextFrame* textFrame = GetTextFrameForContent(aContent, aFlushLayout);
if (textFrame) {
// If we'll need it later, collect the full content text now.
nsAutoString textContent;
if (aTextList) {
mozilla::ErrorResult err; // ignored
aContent->GetTextContent(textContent, err);
}
nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
int32_t fstart = f->GetContentOffset(), fend = f->GetContentEnd();
@ -3010,11 +3003,13 @@ static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
// Finally capture the text, if requested.
if (aTextList) {
const nsAString& textSubstring =
Substring(textContent,
textContentStart,
(textContentEnd - textContentStart));
aTextList->AppendElement(textSubstring, fallible);
nsIFrame::RenderedText renderedText = f->GetRenderedText(
textContentStart,
textContentEnd,
nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
aTextList->AppendElement(renderedText.mString, fallible);
}
}
}

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

@ -15,11 +15,17 @@ function runTests()
let attempts = [
{startNode: "one", start:0, endNode:"one", end:0, textList:[], message:"Empty rect"},
{startNode: "one", start:2, endNode:"one", end:6, textList:["l on"], message:"Single line"},
{startNode: "implicit", start:6, endNode:"implicit", end:12, textList:["it\nbre"], message:"Implicit break"},
{startNode: "implicit", start:6, endNode:"implicit", end:12, textList:["it bre"], message:"Implicit break"},
{startNode: "two.a", start:1, endNode:"two.b", end:2, textList:["wo", "", "li"], message:"Two lines"},
{startNode: "embed.a", start:7, endNode:"embed.b", end:2, textList:["th ", "simple nested", " ", "te"], message:"Simple nested"},
{startNode: "deep.a", start:2, endNode:"deep.b", end:2, textList:["ne with ", "complex, more deeply nested", " ", "te"], message:"Complex nested"},
{startNode: "image.a", start:7, endNode:"image.b", end:2, textList:["th inline ", "", " ", "im"], message:"Inline image"},
{startNode: "hyphen1", start:0, endNode:"hyphen1", end:3, textList:["a\u00AD", "b"], message:"Shy hyphen (active)"},
{startNode: "hyphen2", start:0, endNode:"hyphen2", end:3, textList:["c\u00ADd"], message:"Shy hyphen (inactive)"},
{startNode: "hyphen2", start:0, endNode:"hyphen2", end:2, textList:["c\u00AD"], message:"Shy hyphen (inactive, trailing)"},
{startNode: "hyphen2", start:1, endNode:"hyphen2", end:3, textList:["\u00ADd"], message:"Shy hyphen (inactive, leading)"},
{startNode: "uc", start:0, endNode:"uc", end:2, textList:["EF"], message:"UC transform"},
{startNode: "pre", start:0, endNode:"pre", end:3, textList:["g\n", "h"], message:"pre with break"},
];
for (let attempt of attempts) {
@ -56,5 +62,14 @@ break in one line</div>
<div id="image.a">Line with inline <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAG0lEQVR42mP8z0A%2BYKJA76jmUc2jmkc1U0EzACKcASfOgGoMAAAAAElFTkSuQmCC" width="20" height="20"/> <span id="image.b">image</span></div>
<div id="hyphen1" style="width:0">a&shy;b</div>
<div id="hyphen2" style="width:100px">c&shy;d</div>
<div id="uc" style="text-transform:uppercase">ef</div>
<pre id="pre">g
h</pre>
</body>
</html>

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

@ -433,21 +433,20 @@ VideoData::CreateAndCopyData(const VideoInfo& aInfo,
/* static */
already_AddRefed<VideoData>
VideoData::CreateFromImage(const VideoInfo& aInfo,
VideoData::CreateFromImage(const IntSize& aDisplay,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const RefPtr<Image>& aImage,
bool aKeyframe,
int64_t aTimecode,
const IntRect& aPicture)
int64_t aTimecode)
{
RefPtr<VideoData> v(new VideoData(aOffset,
aTime,
aDuration,
aKeyframe,
aTimecode,
aInfo.mDisplay,
aDisplay,
0));
v->mImage = aImage;
return v.forget();

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

@ -518,14 +518,13 @@ public:
const IntRect& aPicture);
static already_AddRefed<VideoData> CreateFromImage(
const VideoInfo& aInfo,
const IntSize& aDisplay,
int64_t aOffset,
int64_t aTime,
int64_t aDuration,
const RefPtr<Image>& aImage,
bool aKeyframe,
int64_t aTimecode,
const IntRect& aPicture);
int64_t aTimecode);
// Initialize PlanarYCbCrImage. Only When aCopyData is true,
// video data is copied to PlanarYCbCrImage.

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

@ -565,10 +565,6 @@ public:
{
return mDecoder->SupportDecoderRecycling();
}
void ConfigurationChanged(const TrackInfo& aConfig) override
{
mDecoder->ConfigurationChanged(aConfig);
}
RefPtr<ShutdownPromise> Shutdown() override
{
RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
@ -1082,6 +1078,7 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
Preferences::GetUint("media.video-max-decode-error", 2))
, mDemuxer(new DemuxerProxy(aDemuxer))
, mDemuxerInitDone(false)
, mPendingNotifyDataArrived(false)
, mLastReportedNumDecodedFrames(0)
, mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
, mInitDone(false)
@ -1991,9 +1988,6 @@ MediaFormatReader::HandleDemuxedSamples(
if (sample->mKeyframe) {
decoder.mQueuedSamples.AppendElements(Move(samples));
}
} else if (decoder.mInfo && *decoder.mInfo != *info) {
const TrackInfo* trackInfo = *info;
decoder.mDecoder->ConfigurationChanged(*trackInfo);
}
decoder.mInfo = info;
@ -2144,6 +2138,16 @@ MediaFormatReader::Update(TrackType aTrack)
return;
}
if (decoder.HasWaitingPromise() && decoder.HasCompletedDrain()) {
// This situation will occur when a change of stream ID occurred during
// internal seeking following a gap encountered in the data, a drain was
// requested and has now completed. We need to complete the draining process
// so that the new data can be processed.
// We can complete the draining operation now as we have no pending
// operation when a waiting promise is pending.
decoder.mDrainState = DrainState::None;
}
if (UpdateReceivedNewData(aTrack)) {
LOGV("Nothing more to do");
return;
@ -2230,8 +2234,7 @@ MediaFormatReader::Update(TrackType aTrack)
LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
decoder.RejectPromise(decoder.mError.ref(), __func__);
return;
} else if (decoder.mDrainState == DrainState::DrainCompleted
|| decoder.mDrainState == DrainState::DrainAborted) {
} else if (decoder.HasCompletedDrain()) {
if (decoder.mDemuxEOS) {
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
@ -2884,10 +2887,8 @@ MediaFormatReader::NotifyDataArrived()
}
if (mNotifyDataArrivedPromise.Exists()) {
// Already one in progress. Reschedule for later.
RefPtr<nsIRunnable> task(
NewRunnableMethod(this, &MediaFormatReader::NotifyDataArrived));
OwnerThread()->Dispatch(task.forget());
// Already one in progress. Set the dirty flag so we can process it later.
mPendingNotifyDataArrived = true;
return;
}
@ -2898,6 +2899,10 @@ MediaFormatReader::NotifyDataArrived()
self->mNotifyDataArrivedPromise.Complete();
self->UpdateBuffered();
self->NotifyTrackDemuxers();
if (self->mPendingNotifyDataArrived) {
self->mPendingNotifyDataArrived = false;
self->NotifyDataArrived();
}
},
[self]() { self->mNotifyDataArrivedPromise.Complete(); })
->Track(mNotifyDataArrivedPromise);

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

@ -263,6 +263,11 @@ private:
{
return mDrainState != DrainState::None;
}
bool HasCompletedDrain() const
{
return mDrainState == DrainState::DrainCompleted ||
mDrainState == DrainState::DrainAborted;
}
void RequestDrain()
{
MOZ_RELEASE_ASSERT(mDrainState == DrainState::None);
@ -450,6 +455,7 @@ private:
void OnDemuxerInitFailed(const MediaResult& aError);
MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest;
MozPromiseRequestHolder<NotifyDataArrivedPromise> mNotifyDataArrivedPromise;
bool mPendingNotifyDataArrived;
void OnDemuxFailed(TrackType aTrack, const MediaResult &aError);
void DoDemuxVideo();

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

@ -172,26 +172,13 @@ bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip,
RefPtr<VideoData> v;
if (currentImage) {
gfx::IntSize frameSize = currentImage->GetSize();
if (frameSize.width != mInitialFrame.width ||
frameSize.height != mInitialFrame.height) {
// Frame size is different from what the container reports. This is legal,
// and we will preserve the ratio of the crop rectangle as it
// was reported relative to the picture size reported by the container.
picture.x = (mPicture.x * frameSize.width) / mInitialFrame.width;
picture.y = (mPicture.y * frameSize.height) / mInitialFrame.height;
picture.width = (frameSize.width * mPicture.width) / mInitialFrame.width;
picture.height = (frameSize.height * mPicture.height) / mInitialFrame.height;
}
v = VideoData::CreateFromImage(mInfo.mVideo,
v = VideoData::CreateFromImage(mInfo.mVideo.mDisplay,
pos,
frame.mTimeUs,
1, // We don't know the duration yet.
currentImage,
frame.mKeyFrame,
-1,
picture);
-1);
} else {
// Assume YUV
VideoData::YCbCrBuffer b;

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

@ -324,7 +324,7 @@ ServeResourceEvent::Shutdown()
// To shutdown the current thread we need to first exit this event.
// The Shutdown event below is posted to the main thread to do this.
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(NS_GetCurrentThread());
NS_DispatchToMainThread(event);
SystemGroup::Dispatch("ServeResourceEvent::Shutdown", TaskCategory::Other, event.forget());
}
/*

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

@ -17,8 +17,10 @@
namespace mozilla {
GMPCDMCallbackProxy::GMPCDMCallbackProxy(CDMProxy* aProxy)
GMPCDMCallbackProxy::GMPCDMCallbackProxy(CDMProxy* aProxy,
nsIEventTarget* aMainThread)
: mProxy(aProxy)
, mMainThread(aMainThread)
{}
void
@ -27,12 +29,14 @@ GMPCDMCallbackProxy::SetDecryptorId(uint32_t aId)
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy, aId] ()
{
proxy->OnSetDecryptorId(aId);
})
);}
}),
NS_DISPATCH_NORMAL
);
}
void
GMPCDMCallbackProxy::SetSessionId(uint32_t aToken,
@ -42,13 +46,14 @@ GMPCDMCallbackProxy::SetSessionId(uint32_t aToken,
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy,
aToken,
sid] ()
{
proxy->OnSetSessionId(aToken, sid);
})
}),
NS_DISPATCH_NORMAL
);
}
@ -59,11 +64,12 @@ GMPCDMCallbackProxy::ResolveLoadSessionPromise(uint32_t aPromiseId,
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy, aPromiseId, aSuccess] ()
{
proxy->OnResolveLoadSessionPromise(aPromiseId, aSuccess);
})
}),
NS_DISPATCH_NORMAL
);
}
@ -84,14 +90,15 @@ GMPCDMCallbackProxy::RejectPromise(uint32_t aPromiseId,
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy,
aPromiseId,
aException,
aMessage] ()
{
proxy->OnRejectPromise(aPromiseId, aException, aMessage);
})
}),
NS_DISPATCH_NORMAL
);
}
@ -105,14 +112,15 @@ GMPCDMCallbackProxy::SessionMessage(const nsCString& aSessionId,
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
nsTArray<uint8_t> msg(aMessage);
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy,
sid,
aMessageType,
msg] () mutable
{
proxy->OnSessionMessage(sid, aMessageType, msg);
})
}),
NS_DISPATCH_NORMAL
);
}
@ -124,13 +132,14 @@ GMPCDMCallbackProxy::ExpirationChange(const nsCString& aSessionId,
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy,
sid,
aExpiryTime] ()
{
proxy->OnExpirationChange(sid, aExpiryTime);
})
}),
NS_DISPATCH_NORMAL
);
}
@ -147,20 +156,22 @@ GMPCDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
}
if (keyStatusesChange) {
RefPtr<CDMProxy> proxy = mProxy;
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy, sid] ()
{
proxy->OnKeyStatusesChange(sid);
})
}),
NS_DISPATCH_NORMAL
);
}
RefPtr<CDMProxy> proxy = mProxy;
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy, sid] ()
{
proxy->OnSessionClosed(sid);
})
}),
NS_DISPATCH_NORMAL
);
}
@ -175,7 +186,7 @@ GMPCDMCallbackProxy::SessionError(const nsCString& aSessionId,
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
auto msg = NS_ConvertUTF8toUTF16(aMessage);
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy,
sid,
aException,
@ -186,7 +197,8 @@ GMPCDMCallbackProxy::SessionError(const nsCString& aSessionId,
aException,
aSystemCode,
msg);
})
}),
NS_DISPATCH_NORMAL
);
}
@ -215,11 +227,12 @@ GMPCDMCallbackProxy::BatchedKeyStatusChangedInternal(const nsCString& aSessionId
if (keyStatusesChange) {
RefPtr<CDMProxy> proxy = mProxy;
auto sid = NS_ConvertUTF8toUTF16(aSessionId);
NS_DispatchToMainThread(
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy, sid] ()
{
proxy->OnKeyStatusesChange(sid);
})
}),
NS_DISPATCH_NORMAL
);
}
}
@ -240,11 +253,12 @@ GMPCDMCallbackProxy::Terminated()
MOZ_ASSERT(mProxy->IsOnOwnerThread());
RefPtr<CDMProxy> proxy = mProxy;
NS_DispatchToMainThread(
NS_NewRunnableFunction([proxy] ()
{
proxy->Terminated();
})
mMainThread->Dispatch(
NS_NewRunnableFunction([proxy] ()
{
proxy->Terminated();
}),
NS_DISPATCH_NORMAL
);
}

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

@ -59,12 +59,14 @@ public:
private:
friend class GMPCDMProxy;
explicit GMPCDMCallbackProxy(CDMProxy* aProxy);
GMPCDMCallbackProxy(CDMProxy* aProxy, nsIEventTarget* aMainThread);
void BatchedKeyStatusChangedInternal(const nsCString& aSessionId,
const nsTArray<CDMKeyInfo>& aKeyInfos);
// Warning: Weak ref.
CDMProxy* mProxy;
const nsCOMPtr<nsIEventTarget> mMainThread;
};
} // namespace mozilla

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

@ -126,7 +126,7 @@ GMPCDMProxy::gmp_InitDone(GMPDecryptorProxy* aCDM, UniquePtr<InitData>&& aData)
}
mCDM = aCDM;
mCallback.reset(new GMPCDMCallbackProxy(this));
mCallback.reset(new GMPCDMCallbackProxy(this, mMainThread));
mCDM->Init(mCallback.get(),
mDistinctiveIdentifierRequired,
mPersistentStateRequired);

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

@ -19,7 +19,9 @@ GMPCrashHelper::Destroy()
delete this;
} else {
// Don't addref, as then we'd end up releasing after the detele runs!
NS_DispatchToMainThread(mozilla::NewNonOwningRunnableMethod(this, &GMPCrashHelper::Destroy));
SystemGroup::Dispatch(
"GMPCrashHelper::Destroy", TaskCategory::Other,
NewNonOwningRunnableMethod(this, &GMPCrashHelper::Destroy));
}
}

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

@ -60,7 +60,7 @@ extern LogModule* GetGMPLog();
namespace gmp {
GMPParent::GMPParent()
GMPParent::GMPParent(AbstractThread* aMainThread)
: mState(GMPStateNotLoaded)
, mProcess(nullptr)
, mDeleteProcessOnlyOnUnload(false)
@ -70,6 +70,7 @@ GMPParent::GMPParent()
, mGMPContentChildCount(0)
, mChildPid(0)
, mHoldingSelfRef(false)
, mMainThread(aMainThread)
{
mPluginId = GeckoChildProcessHost::GetUniqueID();
LOGD("GMPParent ctor id=%u", mPluginId);
@ -302,7 +303,8 @@ GMPParent::Shutdown()
class NotifyGMPShutdownTask : public Runnable {
public:
explicit NotifyGMPShutdownTask(const nsAString& aNodeId)
: mNodeId(aNodeId)
: Runnable("NotifyGMPShutdownTask")
, mNodeId(aNodeId)
{
}
NS_IMETHOD Run() override {
@ -354,9 +356,9 @@ GMPParent::DeleteProcess()
mProcess = nullptr;
mState = GMPStateNotLoaded;
NS_DispatchToMainThread(
new NotifyGMPShutdownTask(NS_ConvertUTF8toUTF16(mNodeId)),
NS_DISPATCH_NORMAL);
nsCOMPtr<nsIRunnable> r
= new NotifyGMPShutdownTask(NS_ConvertUTF8toUTF16(mNodeId));
mMainThread->Dispatch(r.forget());
if (mHoldingSelfRef) {
Release();
@ -517,9 +519,9 @@ GMPParent::ActorDestroy(ActorDestroyReason aWhy)
}
// NotifyObservers is mainthread-only
NS_DispatchToMainThread(WrapRunnableNM(&GMPNotifyObservers,
mPluginId, mDisplayName, dumpID),
NS_DISPATCH_NORMAL);
nsCOMPtr<nsIRunnable> r = WrapRunnableNM(
&GMPNotifyObservers, mPluginId, mDisplayName, dumpID);
mMainThread->Dispatch(r.forget());
}
#endif
// warn us off trying to close again
@ -728,8 +730,7 @@ GMPParent::ReadChromiumManifestFile(nsIFile* aFile)
// DOM JSON parsing needs to run on the main thread.
return InvokeAsync<nsString&&>(
// Non DocGroup-version of AbstractThread::MainThread for the task in parent.
AbstractThread::MainThread(), this, __func__,
mMainThread, this, __func__,
&GMPParent::ParseChromiumManifest, NS_ConvertUTF8toUTF16(json));
}

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

@ -73,7 +73,7 @@ class GMPParent final : public PGMPParent
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPParent)
GMPParent();
explicit GMPParent(AbstractThread* aMainThread);
RefPtr<GenericPromise> Init(GeckoMediaPluginServiceParent* aService, nsIFile* aPluginDir);
nsresult CloneFrom(const GMPParent* aOther);
@ -228,6 +228,8 @@ private:
#ifdef MOZ_CRASHREPORTER
UniquePtr<ipc::CrashReporterHost> mCrashReporter;
#endif
const RefPtr<AbstractThread> mMainThread;
};
} // namespace gmp

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

@ -79,12 +79,11 @@ public:
if (NS_IsMainThread()) {
service = GetOrCreateOnMainThread();
} else {
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
RefPtr<GMPServiceCreateHelper> createHelper = new GMPServiceCreateHelper();
mozilla::SyncRunnable::DispatchToThread(mainThread, createHelper, true);
mozilla::SyncRunnable::DispatchToThread(
SystemGroup::EventTargetFor(mozilla::TaskCategory::Other),
createHelper, true);
service = createHelper->mService.forget();
}
@ -94,6 +93,7 @@ public:
private:
GMPServiceCreateHelper()
: Runnable("GMPServiceCreateHelper")
{
}

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

@ -305,8 +305,9 @@ GeckoMediaPluginServiceChild::GetServiceChild()
MozPromiseHolder<GetServiceChildPromise>* holder = mGetServiceChildPromises.AppendElement();
RefPtr<GetServiceChildPromise> promise = holder->Ensure(__func__);
if (mGetServiceChildPromises.Length() == 1) {
NS_DispatchToMainThread(WrapRunnable(contentChild,
&dom::ContentChild::SendCreateGMPService));
nsCOMPtr<nsIRunnable> r = WrapRunnable(
contentChild, &dom::ContentChild::SendCreateGMPService);
SystemGroup::Dispatch("SendCreateGMPService", TaskCategory::Other, r.forget());
}
return promise;
}
@ -358,9 +359,6 @@ GMPServiceChild::GetBridgedGMPContentParent(ProcessId aOtherPid,
MOZ_ASSERT(aOtherPid == endpoint.OtherPid());
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
MOZ_ASSERT(mainThread);
parent = new GMPContentParent();
DebugOnly<bool> ok = endpoint.Bind(parent);

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

@ -94,6 +94,7 @@ GeckoMediaPluginServiceParent::GeckoMediaPluginServiceParent()
, mInitPromiseMonitor("GeckoMediaPluginServiceParent::mInitPromiseMonitor")
, mLoadPluginsFromDiskComplete(false)
, mServiceUserCount(0)
, mMainThread(SystemGroup::AbstractMainThreadFor(TaskCategory::Other))
{
MOZ_ASSERT(NS_IsMainThread());
mInitPromise.SetMonitor(&mInitPromiseMonitor);
@ -462,9 +463,10 @@ GeckoMediaPluginServiceParent::UnloadPlugins()
plugin->CloseActive(true);
}
nsCOMPtr<nsIRunnable> task(NewRunnableMethod(
this, &GeckoMediaPluginServiceParent::NotifySyncShutdownComplete));
NS_DispatchToMainThread(task);
nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
"GeckoMediaPluginServiceParent::NotifySyncShutdownComplete",
this, &GeckoMediaPluginServiceParent::NotifySyncShutdownComplete);
mMainThread->Dispatch(task.forget());
}
void
@ -520,7 +522,8 @@ GeckoMediaPluginServiceParent::LoadFromEnvironment()
class NotifyObserversTask final : public mozilla::Runnable {
public:
explicit NotifyObserversTask(const char* aTopic, nsString aData = EmptyString())
: mTopic(aTopic)
: Runnable(aTopic)
, mTopic(aTopic)
, mData(aData)
{}
NS_IMETHOD Run() override {
@ -553,9 +556,10 @@ void
GeckoMediaPluginServiceParent::UpdateContentProcessGMPCapabilities()
{
if (!NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> task =
NewRunnableMethod(this, &GeckoMediaPluginServiceParent::UpdateContentProcessGMPCapabilities);
NS_DispatchToMainThread(task);
nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
"GeckoMediaPluginServiceParent::UpdateContentProcessGMPCapabilities",
this, &GeckoMediaPluginServiceParent::UpdateContentProcessGMPCapabilities);
mMainThread->Dispatch(task.forget());
return;
}
@ -617,7 +621,7 @@ GeckoMediaPluginServiceParent::AsyncAddPluginDirectory(const nsAString& aDirecto
thread, this, __func__,
&GeckoMediaPluginServiceParent::AddOnGMPThread, dir)
->Then(
AbstractThread::MainThread(), // Non DocGroup-version for the task in parent.
mMainThread,
__func__,
[dir, self]() -> void {
LOGD(("GeckoMediaPluginServiceParent::AsyncAddPluginDirectory %s succeeded",
@ -779,7 +783,7 @@ GeckoMediaPluginServiceParent::SelectPluginForAPI(const nsACString& aNodeId,
}
RefPtr<GMPParent>
CreateGMPParent()
CreateGMPParent(AbstractThread* aMainThread)
{
#if defined(XP_LINUX) && defined(MOZ_GMP_SANDBOX)
if (!SandboxInfo::Get().CanSandboxMedia()) {
@ -790,7 +794,7 @@ CreateGMPParent()
NS_WARNING("Loading media plugin despite lack of sandboxing.");
}
#endif
return new GMPParent();
return new GMPParent(aMainThread);
}
already_AddRefed<GMPParent>
@ -798,7 +802,7 @@ GeckoMediaPluginServiceParent::ClonePlugin(const GMPParent* aOriginal)
{
MOZ_ASSERT(aOriginal);
RefPtr<GMPParent> gmp = CreateGMPParent();
RefPtr<GMPParent> gmp = CreateGMPParent(mMainThread);
nsresult rv = gmp ? gmp->CloneFrom(aOriginal) : NS_ERROR_NOT_AVAILABLE;
if (NS_FAILED(rv)) {
@ -837,7 +841,7 @@ GeckoMediaPluginServiceParent::AddOnGMPThread(nsString aDirectory)
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
RefPtr<GMPParent> gmp = CreateGMPParent();
RefPtr<GMPParent> gmp = CreateGMPParent(mMainThread);
if (!gmp) {
NS_WARNING("Can't Create GMPParent");
return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
@ -920,9 +924,9 @@ GeckoMediaPluginServiceParent::RemoveOnGMPThread(const nsAString& aDirectory,
}
if (NS_SUCCEEDED(directory->Remove(true))) {
mPluginsWaitingForDeletion.RemoveElement(aDirectory);
NS_DispatchToMainThread(new NotifyObserversTask("gmp-directory-deleted",
nsString(aDirectory)),
NS_DISPATCH_NORMAL);
nsCOMPtr<nsIRunnable> task = new NotifyObserversTask(
"gmp-directory-deleted", nsString(aDirectory));
mMainThread->Dispatch(task.forget());
}
}
}
@ -1537,7 +1541,9 @@ GeckoMediaPluginServiceParent::ClearRecentHistoryOnGMPThread(PRTime aSince)
ClearNodeIdAndPlugin(filter);
NS_DispatchToMainThread(new NotifyObserversTask("gmp-clear-storage-complete"), NS_DISPATCH_NORMAL);
nsCOMPtr<nsIRunnable> task
= new NotifyObserversTask("gmp-clear-storage-complete");
mMainThread->Dispatch(task.forget());
}
NS_IMETHODIMP
@ -1647,7 +1653,9 @@ GeckoMediaPluginServiceParent::ClearStorage()
// Clear private-browsing storage.
mTempGMPStorage.Clear();
NS_DispatchToMainThread(new NotifyObserversTask("gmp-clear-storage-complete"), NS_DISPATCH_NORMAL);
nsCOMPtr<nsIRunnable> task
= new NotifyObserversTask("gmp-clear-storage-complete");
mMainThread->Dispatch(task.forget());
}
already_AddRefed<GMPParent>
@ -1664,9 +1672,10 @@ GeckoMediaPluginServiceParent::GetById(uint32_t aPluginId)
GMPServiceParent::~GMPServiceParent()
{
NS_DispatchToMainThread(
NewRunnableMethod(mService.get(),
&GeckoMediaPluginServiceParent::ServiceUserDestroyed));
nsCOMPtr<nsIRunnable> task = NewRunnableMethod(
"GeckoMediaPluginServiceParent::ServiceUserDestroyed",
mService.get(), &GeckoMediaPluginServiceParent::ServiceUserDestroyed);
mService->MainThread()->Dispatch(task.forget());
}
mozilla::ipc::IPCResult

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

@ -65,6 +65,8 @@ public:
void UpdateContentProcessGMPCapabilities();
AbstractThread* MainThread() const { return mMainThread; }
private:
friend class GMPServiceParent;
@ -202,6 +204,8 @@ private:
// Tracks how many users are running (on the GMP thread). Only when this count
// drops to 0 can we safely shut down the thread.
MainThreadOnly<int32_t> mServiceUserCount;
const RefPtr<AbstractThread> mMainThread;
};
nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData);

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

@ -39,21 +39,19 @@ mozilla::ipc::IPCResult
VideoDecoderChild::RecvOutput(const VideoDataIPDL& aData)
{
AssertOnManagerThread();
VideoInfo info(aData.display().width, aData.display().height);
// The Image here creates a TextureData object that takes ownership
// of the SurfaceDescriptor, and is responsible for making sure that
// it gets deallocated.
RefPtr<Image> image = new GPUVideoImage(GetManager(), aData.sd(), aData.frameSize());
RefPtr<VideoData> video = VideoData::CreateFromImage(info,
RefPtr<VideoData> video = VideoData::CreateFromImage(aData.display(),
aData.base().offset(),
aData.base().time(),
aData.base().duration(),
image,
aData.base().keyframe(),
aData.base().timecode(),
IntRect());
aData.base().timecode());
mDecodedData.AppendElement(Move(video));
return IPC_OK();
}

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

@ -309,7 +309,10 @@ DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
public:
R(PlaybackInfoInit&& aInit, Promise&& aPromise,
OutputStreamManager* aManager, AbstractThread* aMainThread)
: mInit(Move(aInit)), mOutputStreamManager(aManager), mAbstractMainThread(aMainThread)
: Runnable("CreateDecodedStreamData")
, mInit(Move(aInit))
, mOutputStreamManager(aManager)
, mAbstractMainThread(aMainThread)
{
mPromise = Move(aPromise);
}
@ -346,8 +349,8 @@ DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
};
nsCOMPtr<nsIRunnable> r =
new R(Move(init), Move(promise), mOutputStreamManager, mAbstractMainThread);
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
SyncRunnable::DispatchToThread(mainThread, r);
SyncRunnable::DispatchToThread(
SystemGroup::EventTargetFor(mozilla::TaskCategory::Other), r);
mData = static_cast<R*>(r.get())->ReleaseData();
if (mData) {

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

@ -56,6 +56,8 @@ skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not
skip-if = toolkit == 'android' #timeout android bug 1199531
[test_BufferingWait_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
[test_ChangeWhileWaitingOnMissingData_mp4.html]
skip-if = ((os == "win" && (os_version == "5.1" || os_version == "6.2")) || (toolkit == 'android')) # Not supported on xp and android 2.3, win8 see bug 1347101
[test_DrainOnMissingData_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
[test_DurationChange.html]
@ -114,7 +116,7 @@ skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not
[test_SeekToEnd_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
[test_SeekToLastFrame_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
skip-if = ((os == "win" && (os_version == "5.1" || os_version == "6.2")) || (toolkit == 'android')) # Not supported on xp and android 2.3, win8 see bug 1347101
[test_SeekTwice_mp4.html]
skip-if = ((os == "win" && os_version == "5.1") || (toolkit == 'android')) # Not supported on xp and android 2.3
[test_Sequence_mp4.html]

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

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
<title>MSE: resume from waiting even after format change occurred</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="mediasource.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test"><script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
runWithMSE(function(ms, el) {
el.controls = true;
once(ms, 'sourceopen').then(function() {
ok(true, "Receive a sourceopen event");
var sb = ms.addSourceBuffer("video/mp4");
fetchAndLoad(sb, 'bipbop/bipbop_480_624kbps-video', ['init'], '.mp4')
.then(fetchAndLoad.bind(null, sb, 'bipbop/bipbop_480_624kbps-video', range(1, 3), '.m4s'))
.then(function() {
el.play();
// let seek to the last audio frame.
// The seek will complete and then playback will stall.
el.currentTime = 1.532517;
return Promise.all([once(el, 'seeked'), once(el, 'stalled')]);
})
.then(function() {
info("seek completed");
return fetchAndLoad(sb, 'bipbop/bipbop', ['init'], '.mp4');
})
.then(fetchAndLoad.bind(null, sb, 'bipbop/bipbop', range(1, 4), '.m4s'))
.then(function() {
ms.endOfStream();
return once(el, 'ended');
}).then(function() {
SimpleTest.finish();
});
});
});
</script>
</pre>
</body>
</html>

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

@ -297,20 +297,6 @@ public:
// Currently, only Android video decoder will return true.
virtual bool SupportDecoderRecycling() const { return false; }
// ConfigurationChanged will be called to inform the video or audio decoder
// that the format of the next input sample is about to change.
// If video decoder, aConfig will be a VideoInfo object.
// If audio decoder, aConfig will be a AudioInfo object.
// It is not safe to store a reference to this object and the decoder must
// make a copy.
// Care should be taken as ConfigurationChanged is called on the reader's
// taskqueue.
virtual void ConfigurationChanged(const TrackInfo& aConfig)
{
MOZ_ASSERT(SupportDecoderRecycling(),
"Can only work with a decoder supporting recycling.");
}
enum class ConversionRequired
{
kNeedNone = 0,

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

@ -2,37 +2,38 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_DurationMap_h
#define mozilla_DurationMap_h
#ifndef mozilla_SimpleMap_h
#define mozilla_SimpleMap_h
#include "mozilla/Pair.h"
#include "nsTArray.h"
namespace mozilla {
class DurationMap
template<typename T>
class SimpleMap
{
public:
typedef Pair<int64_t, int64_t> DurationElement;
typedef Pair<int64_t, T> Element;
DurationMap() : mMutex("DurationMap") { }
SimpleMap() : mMutex("SimpleMap") { }
// Insert Key and Duration pair at the end of our map.
void Insert(int64_t aKey, int64_t aDuration)
// Insert Key and Value pair at the end of our map.
void Insert(int64_t aKey, const T& aValue)
{
MutexAutoLock lock(mMutex);
mMap.AppendElement(MakePair(aKey, aDuration));
mMap.AppendElement(MakePair(aKey, aValue));
}
// Sets aDuration matching aKey and remove it from the map if found.
// Sets aValue matching aKey and remove it from the map if found.
// The element returned is the first one found.
// Returns true if found, false otherwise.
bool Find(int64_t aKey, int64_t& aDuration)
bool Find(int64_t aKey, T& aValue)
{
MutexAutoLock lock(mMutex);
for (uint32_t i = 0; i < mMap.Length(); i++) {
DurationElement& element = mMap[i];
Element& element = mMap[i];
if (element.first() == aKey) {
aDuration = element.second();
aValue = element.second();
mMap.RemoveElementAt(i);
return true;
}
@ -48,9 +49,9 @@ public:
private:
Mutex mMutex; // To protect mMap.
AutoTArray<DurationElement, 16> mMap;
AutoTArray<Element, 16> mMap;
};
} // namespace mozilla
#endif // mozilla_DurationMap_h
#endif // mozilla_SimpleMap_h

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

@ -5,14 +5,14 @@
#include "AndroidBridge.h"
#include "AndroidDecoderModule.h"
#include "AndroidSurfaceTexture.h"
#include "DurationMap.h"
#include "SimpleMap.h"
#include "FennecJNINatives.h"
#include "GLImages.h"
#include "MediaData.h"
#include "MediaInfo.h"
#include "VPXDecoder.h"
#include "VideoUtils.h"
#include "mozilla/Mutex.h"
#include "VPXDecoder.h"
#include "nsIGfxInfo.h"
#include "nsPromiseFlatString.h"
#include "nsThreadUtils.h"
@ -136,6 +136,24 @@ public:
java::Sample::GlobalRef mSample;
};
class InputInfo
{
public:
InputInfo() { }
InputInfo(const int64_t aDurationUs, const gfx::IntSize& aImageSize, const gfx::IntSize& aDisplaySize)
: mDurationUs(aDurationUs)
, mImageSize(aImageSize)
, mDisplaySize(aDisplaySize)
{
}
int64_t mDurationUs;
gfx::IntSize mImageSize;
gfx::IntSize mDisplaySize;
};
class CallbacksSupport final : public JavaCallbacksSupport
{
public:
@ -172,25 +190,21 @@ public:
}
bool isEOS = !!(flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM);
int64_t durationUs = 0;
if (!mDecoder->mInputDurations.Find(presentationTimeUs, durationUs)
InputInfo inputInfo;
if (!mDecoder->mInputInfos.Find(presentationTimeUs, inputInfo)
&& !isEOS) {
return;
}
if (size > 0) {
MutexAutoLock lock(mDecoder->mMutex);
RefPtr<layers::Image> img = new SurfaceTextureImage(
mDecoder->mSurfaceTexture.get(), mDecoder->mConfig.mDisplay,
mDecoder->mSurfaceTexture.get(), inputInfo.mImageSize,
gl::OriginPos::BottomLeft);
RefPtr<VideoData> v = VideoData::CreateFromImage(
mDecoder->mConfig, offset, presentationTimeUs, durationUs,
inputInfo.mDisplaySize, offset, presentationTimeUs, inputInfo.mDurationUs,
img, !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME),
presentationTimeUs,
gfx::IntRect(0, 0, mDecoder->mConfig.mDisplay.width,
mDecoder->mConfig.mDisplay.height));
presentationTimeUs);
v->SetListener(Move(releaseSample));
@ -220,7 +234,6 @@ public:
: RemoteDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mMimeType,
aFormat, aDrmStubId, aTaskQueue)
, mImageContainer(aImageContainer)
, mMutex("RemoteVideoDecoder Mutex")
, mConfig(aConfig)
{
}
@ -263,13 +276,19 @@ public:
RefPtr<MediaDataDecoder::FlushPromise> Flush() override
{
mInputDurations.Clear();
mInputInfos.Clear();
return RemoteDataDecoder::Flush();
}
RefPtr<MediaDataDecoder::DecodePromise> Decode(MediaRawData* aSample) override
{
mInputDurations.Insert(aSample->mTime, aSample->mDuration);
const VideoInfo* config = aSample->mTrackInfo
? aSample->mTrackInfo->GetAsVideoInfo()
: &mConfig;
MOZ_ASSERT(config);
InputInfo info(aSample->mDuration, config->mImage, config->mDisplay);
mInputInfos.Insert(aSample->mTime, info);
return RemoteDataDecoder::Decode(aSample);
}
@ -277,20 +296,13 @@ public:
{
return mIsCodecSupportAdaptivePlayback;
}
void ConfigurationChanged(const TrackInfo& aConfig) override
{
MOZ_ASSERT(aConfig.GetAsVideoInfo());
MutexAutoLock lock(mMutex);
mConfig = *aConfig.GetAsVideoInfo();
}
private:
layers::ImageContainer* mImageContainer;
const VideoInfo mConfig;
RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
DurationMap mInputDurations;
SimpleMap<InputInfo> mInputInfos;
bool mIsCodecSupportAdaptivePlayback = false;
Mutex mMutex; // Protects mConfig
VideoInfo mConfig;
};
class RemoteAudioDecoder : public RemoteDataDecoder

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

@ -352,10 +352,6 @@ AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage,
// Bounds.
VideoInfo info;
info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight);
gfx::IntRect visible = gfx::IntRect(0,
0,
mPictureWidth,
mPictureHeight);
if (useNullSample) {
data = new NullData(aFrameRef.byte_offset,
@ -405,6 +401,11 @@ AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage,
buffer.mPlanes[2].mOffset = 1;
buffer.mPlanes[2].mSkip = 1;
gfx::IntRect visible = gfx::IntRect(0,
0,
mPictureWidth,
mPictureHeight);
// Copy the image data into our own format.
data =
VideoData::CreateAndCopyData(info,
@ -428,14 +429,13 @@ AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage,
RefPtr<layers::Image> image = new MacIOSurfaceImage(macSurface);
data =
VideoData::CreateFromImage(info,
VideoData::CreateFromImage(info.mDisplay,
aFrameRef.byte_offset,
aFrameRef.composition_timestamp.ToMicroseconds(),
aFrameRef.duration.ToMicroseconds(),
image.forget(),
aFrameRef.is_sync_point,
aFrameRef.decode_timestamp.ToMicroseconds(),
visible);
aFrameRef.decode_timestamp.ToMicroseconds());
#else
MOZ_ASSERT_UNREACHABLE("No MacIOSurface on iOS");
#endif

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

@ -9,7 +9,7 @@
#include "FFmpegLibWrapper.h"
#include "FFmpegDataDecoder.h"
#include "DurationMap.h"
#include "SimpleMap.h"
namespace mozilla
{
@ -24,6 +24,7 @@ class FFmpegVideoDecoder<LIBAV_VER> : public FFmpegDataDecoder<LIBAV_VER>
{
typedef mozilla::layers::Image Image;
typedef mozilla::layers::ImageContainer ImageContainer;
typedef SimpleMap<int64_t> DurationMap;
public:
FFmpegVideoDecoder(FFmpegLibWrapper* aLib, TaskQueue* aTaskQueue,

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

@ -11,10 +11,10 @@ EXPORTS += [
'agnostic/TheoraDecoder.h',
'agnostic/VorbisDecoder.h',
'agnostic/VPXDecoder.h',
'DurationMap.h',
'MediaTelemetryConstants.h',
'PDMFactory.h',
'PlatformDecoderModule.h',
'SimpleMap.h',
'wrappers/H264Converter.h',
'wrappers/MediaDataDecoderProxy.h'

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

@ -900,14 +900,13 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
false);
RefPtr<VideoData> v =
VideoData::CreateFromImage(mVideoInfo,
VideoData::CreateFromImage(mVideoInfo.mDisplay,
aStreamOffset,
pts.ToMicroseconds(),
duration.ToMicroseconds(),
image.forget(),
false,
-1,
pictureRegion);
-1);
v.forget(aOutVideoData);
return S_OK;
@ -939,14 +938,13 @@ WMFVideoMFTManager::CreateD3DVideoFrame(IMFSample* aSample,
NS_ENSURE_TRUE(pts.IsValid(), E_FAIL);
media::TimeUnit duration = GetSampleDuration(aSample);
NS_ENSURE_TRUE(duration.IsValid(), E_FAIL);
RefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo,
RefPtr<VideoData> v = VideoData::CreateFromImage(mVideoInfo.mDisplay,
aStreamOffset,
pts.ToMicroseconds(),
duration.ToMicroseconds(),
image.forget(),
false,
-1,
pictureRegion);
-1);
NS_ENSURE_TRUE(v, E_FAIL);
v.forget(aOutVideoData);

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

@ -302,9 +302,6 @@ H264Converter::DecodeFirstSample(MediaRawData* aSample)
mNeedKeyframe = false;
if (CanRecycleDecoder()) {
mDecoder->ConfigurationChanged(mCurrentConfig);
}
RefPtr<H264Converter> self = this;
mDecoder->Decode(aSample)
->Then(AbstractThread::GetCurrent()->AsTaskQueue(), __func__,
@ -342,6 +339,9 @@ H264Converter::CheckForSPSChange(MediaRawData* aSample)
// be used with MSE. And with MSE, the MediaFormatReader would have drained
// the decoder already.
RefPtr<H264Converter> self = this;
if (!sample->mTrackInfo) {
sample->mTrackInfo = new TrackInfoSharedPtr(mCurrentConfig, 0);
}
mDecoder->Flush()
->Then(AbstractThread::GetCurrent()->AsTaskQueue(),
__func__,

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

@ -50,12 +50,7 @@ public:
}
return false;
}
void ConfigurationChanged(const TrackInfo& aConfig) override
{
if (mDecoder && mDecoder->SupportDecoderRecycling()) {
mDecoder->ConfigurationChanged(aConfig);
}
}
ConversionRequired NeedsConversion() const override
{
if (mDecoder) {

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

@ -118,23 +118,6 @@ MediaDataDecoderProxy::SupportDecoderRecycling() const
return mProxyDecoder->SupportDecoderRecycling();
}
void
MediaDataDecoderProxy::ConfigurationChanged(const TrackInfo& aConfig)
{
MOZ_ASSERT(!mIsShutdown);
if (!mProxyThread) {
mProxyDecoder->ConfigurationChanged(aConfig);
return;
}
RefPtr<MediaDataDecoderProxy> self = this;
RefPtr<TrackInfoSharedPtr> config = new TrackInfoSharedPtr(aConfig, 0);
mProxyThread->Dispatch(NS_NewRunnableFunction([self, config] {
const TrackInfo* trackInfo = *config;
self->mProxyDecoder->ConfigurationChanged(*trackInfo);
}));
}
MediaDataDecoder::ConversionRequired
MediaDataDecoderProxy::NeedsConversion() const
{

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

@ -50,7 +50,6 @@ public:
bool IsHardwareAccelerated(nsACString& aFailureReason) const override;
void SetSeekThreshold(const media::TimeUnit& aTime) override;
bool SupportDecoderRecycling() const override;
void ConfigurationChanged(const TrackInfo& aConfig) override;
ConversionRequired NeedsConversion() const override;
private:

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

@ -32,6 +32,7 @@
#include "nsIScrollableFrame.h"
#include "nsIScrollbarMediator.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/widget/nsAutoRollup.h"
#define APZES_LOG(...)
// #define APZES_LOG(...) printf_stderr("APZES: " __VA_ARGS__)
@ -129,19 +130,22 @@ public:
LayoutDevicePoint& aPoint,
Modifiers aModifiers,
int32_t aClickCount,
nsITimer* aTimer)
nsITimer* aTimer,
RefPtr<nsIContent>& aTouchRollup)
: mWidget(aWidget)
, mPoint(aPoint)
, mModifiers(aModifiers)
, mClickCount(aClickCount)
// Hold the reference count until we are called back.
, mTimer(aTimer)
, mTouchRollup(aTouchRollup)
{
}
NS_IMETHOD Notify(nsITimer*) override
{
if (nsCOMPtr<nsIWidget> widget = do_QueryReferent(mWidget)) {
widget::nsAutoRollup rollup(mTouchRollup.get());
APZCCallbackHelper::FireSingleTapEvent(mPoint, mModifiers, mClickCount, widget);
}
mTimer = nullptr;
@ -162,6 +166,7 @@ private:
Modifiers mModifiers;
int32_t mClickCount;
nsCOMPtr<nsITimer> mTimer;
RefPtr<nsIContent> mTouchRollup;
};
NS_IMPL_ISUPPORTS(DelayedFireSingleTapEvent, nsITimerCallback)
@ -176,6 +181,9 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
APZES_LOG("Handling single tap at %s on %s with %d\n",
Stringify(aPoint).c_str(), Stringify(aGuid).c_str(), mTouchEndCancelled);
RefPtr<nsIContent> touchRollup = GetTouchRollup();
mTouchRollup = nullptr;
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return;
@ -190,6 +198,7 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
// If the active element isn't visually affected by the :active style, we
// have no need to wait the extra sActiveDurationMs to make the activation
// visually obvious to the user.
widget::nsAutoRollup rollup(touchRollup.get());
APZCCallbackHelper::FireSingleTapEvent(ldPoint, aModifiers, aClickCount, widget);
return;
}
@ -197,7 +206,8 @@ APZEventState::ProcessSingleTap(const CSSPoint& aPoint,
APZES_LOG("Active element uses style, scheduling timer for click event\n");
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
RefPtr<DelayedFireSingleTapEvent> callback =
new DelayedFireSingleTapEvent(mWidget, ldPoint, aModifiers, aClickCount, timer);
new DelayedFireSingleTapEvent(mWidget, ldPoint, aModifiers, aClickCount,
timer, touchRollup);
nsresult rv = timer->InitWithCallback(callback,
sActiveDurationMs,
nsITimer::TYPE_ONE_SHOT);
@ -322,6 +332,8 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
switch (aEvent.mMessage) {
case eTouchStart: {
mTouchEndCancelled = false;
mTouchRollup = do_GetWeakReference(widget::nsAutoRollup::GetLastRollup());
sentContentResponse = SendPendingTouchPreventedResponse(false);
// sentContentResponse can be true here if we get two TOUCH_STARTs in a row
// and just responded to the first one.
@ -509,5 +521,12 @@ APZEventState::GetWidget() const
return result.forget();
}
already_AddRefed<nsIContent>
APZEventState::GetTouchRollup() const
{
nsCOMPtr<nsIContent> result = do_QueryReferent(mTouchRollup);
return result.forget();
}
} // namespace layers
} // namespace mozilla

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

@ -20,6 +20,7 @@
#include <functional>
template <class> class nsCOMPtr;
class nsIContent;
class nsIDocument;
class nsIPresShell;
class nsIWidget;
@ -86,6 +87,7 @@ private:
Modifiers aModifiers,
const nsCOMPtr<nsIWidget>& aWidget);
already_AddRefed<nsIWidget> GetWidget() const;
already_AddRefed<nsIContent> GetTouchRollup() const;
private:
nsWeakPtr mWidget;
RefPtr<ActiveElementManager> mActiveElementManager;
@ -96,6 +98,22 @@ private:
bool mEndTouchIsClick;
bool mTouchEndCancelled;
int32_t mLastTouchIdentifier;
// Because touch-triggered mouse events (e.g. mouse events from a tap
// gesture) happen asynchronously from the touch events themselves, we
// need to stash and replicate some of the state from the touch events
// to the mouse events. One piece of state is the rollup content, which
// is the content for which a popup window was recently closed. If we
// don't replicate this state properly during the mouse events, the
// synthetic click might reopen a popup window that was just closed by
// the touch event, which is undesirable. See also documentation in
// nsAutoRollup.h
// Note that in cases where we get multiple touch blocks interleaved with
// their single-tap event notifications, mTouchRollup may hold an incorrect
// value. This is kind of an edge case, and falls in the same category of
// problems as bug 1227241. I intend that fixing that bug will also take
// care of this potential problem.
nsWeakPtr mTouchRollup;
};
} // namespace layers

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

@ -21,7 +21,6 @@ VRLayerChild::VRLayerChild(uint32_t aVRDisplayID, VRManagerChild* aVRManagerChil
, mShSurfClient(nullptr)
, mFront(nullptr)
{
MOZ_COUNT_CTOR(VRLayerChild);
}
VRLayerChild::~VRLayerChild()

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

@ -29,7 +29,7 @@ class SurfaceFactory;
namespace gfx {
class VRLayerChild : public PVRLayerChild {
NS_INLINE_DECL_REFCOUNTING(VRLayerChild)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRLayerChild)
public:
VRLayerChild(uint32_t aVRDisplayID, VRManagerChild* aVRManagerChild);

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

@ -16,7 +16,6 @@ VRLayerParent::VRLayerParent(uint32_t aVRDisplayID, const Rect& aLeftEyeRect, co
, mLeftEyeRect(aLeftEyeRect)
, mRightEyeRect(aRightEyeRect)
{
MOZ_COUNT_CTOR(VRLayerParent);
}
VRLayerParent::~VRLayerParent()

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

@ -16,7 +16,7 @@ namespace mozilla {
namespace gfx {
class VRLayerParent : public PVRLayerParent {
NS_INLINE_DECL_REFCOUNTING(VRLayerParent)
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRLayerParent)
public:
VRLayerParent(uint32_t aVRDisplayID, const Rect& aLeftEyeRect, const Rect& aRightEyeRect);

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

@ -249,6 +249,12 @@ public:
aContext->SetState(aContext->PostScrollState());
}
virtual void OnScrollPositionChanged(
AccessibleCaretEventHub* aContext) override
{
aContext->mManager->OnScrollPositionChanged();
}
virtual void OnBlur(AccessibleCaretEventHub* aContext,
bool aIsLeavingDocument) override
{

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

@ -63,6 +63,7 @@ std::ostream& operator<<(std::ostream& aStream,
switch (aHint) {
AC_PROCESS_ENUM_TO_STREAM(UpdateCaretsHint::Default);
AC_PROCESS_ENUM_TO_STREAM(UpdateCaretsHint::RespectOldAppearance);
AC_PROCESS_ENUM_TO_STREAM(UpdateCaretsHint::DispatchNoEvent);
}
return aStream;
}
@ -223,7 +224,7 @@ AccessibleCaretManager::HideCarets()
}
void
AccessibleCaretManager::UpdateCarets(UpdateCaretsHint aHint)
AccessibleCaretManager::UpdateCarets(UpdateCaretsHintSet aHint)
{
FlushLayout();
if (IsTerminated()) {
@ -284,7 +285,7 @@ AccessibleCaretManager::HasNonEmptyTextContent(nsINode* aNode) const
}
void
AccessibleCaretManager::UpdateCaretsForCursorMode(UpdateCaretsHint aHint)
AccessibleCaretManager::UpdateCaretsForCursorMode(UpdateCaretsHintSet aHints)
{
AC_LOG("%s, selection: %p", __FUNCTION__, GetSelection());
@ -295,44 +296,36 @@ AccessibleCaretManager::UpdateCaretsForCursorMode(UpdateCaretsHint aHint)
return;
}
bool oldSecondCaretVisible = mSecondCaret->IsLogicallyVisible();
PositionChangedResult result = mFirstCaret->SetPosition(frame, offset);
switch (result) {
case PositionChangedResult::NotChanged:
// Do nothing
break;
case PositionChangedResult::Changed:
switch (aHint) {
case UpdateCaretsHint::Default:
if (HasNonEmptyTextContent(GetEditingHostForFrame(frame))) {
if (aHints == UpdateCaretsHint::Default) {
if (HasNonEmptyTextContent(GetEditingHostForFrame(frame))) {
mFirstCaret->SetAppearance(Appearance::Normal);
} else if (sCaretShownWhenLongTappingOnEmptyContent) {
if (mFirstCaret->IsLogicallyVisible()) {
// Possible cases are: 1) SelectWordOrShortcut() sets the
// appearance to Normal. 2) When the caret is out of viewport and
// now scrolling into viewport, it has appearance NormalNotShown.
mFirstCaret->SetAppearance(Appearance::Normal);
} else if (sCaretShownWhenLongTappingOnEmptyContent) {
if (mFirstCaret->IsLogicallyVisible()) {
// Possible cases are: 1) SelectWordOrShortcut() sets the
// appearance to Normal. 2) When the caret is out of viewport and
// now scrolling into viewport, it has appearance NormalNotShown.
mFirstCaret->SetAppearance(Appearance::Normal);
} else {
// Possible cases are: a) Single tap on current empty content;
// OnSelectionChanged() sets the appearance to None due to
// MOUSEDOWN_REASON. b) Single tap on other empty content;
// OnBlur() sets the appearance to None.
//
// Do nothing to make the appearance remains None so that it can
// be distinguished from case 2). Also do not set the appearance
// to NormalNotShown here like the default update behavior.
}
} else {
mFirstCaret->SetAppearance(Appearance::NormalNotShown);
// Possible cases are: a) Single tap on current empty content;
// OnSelectionChanged() sets the appearance to None due to
// MOUSEDOWN_REASON. b) Single tap on other empty content;
// OnBlur() sets the appearance to None.
//
// Do nothing to make the appearance remains None so that it can
// be distinguished from case 2). Also do not set the appearance
// to NormalNotShown here like the default update behavior.
}
break;
case UpdateCaretsHint::RespectOldAppearance:
// Do nothing to preserve the appearance of the caret set by the
// caller.
break;
} else {
mFirstCaret->SetAppearance(Appearance::NormalNotShown);
}
} else if (aHints.contains(UpdateCaretsHint::RespectOldAppearance)) {
// Do nothing to preserve the appearance of the caret set by the
// caller.
}
break;
@ -346,14 +339,14 @@ AccessibleCaretManager::UpdateCaretsForCursorMode(UpdateCaretsHint aHint)
LaunchCaretTimeoutTimer();
if ((result != PositionChangedResult::NotChanged || oldSecondCaretVisible) &&
if (!aHints.contains(UpdateCaretsHint::DispatchNoEvent) &&
!mActiveCaret) {
DispatchCaretStateChangedEvent(CaretChangedReason::Updateposition);
}
}
void
AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHint aHint)
AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHintSet aHints)
{
AC_LOG("%s: selection: %p", __FUNCTION__, GetSelection());
@ -371,27 +364,20 @@ AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHint aHint)
return;
}
auto updateSingleCaret = [aHint](AccessibleCaret* aCaret, nsIFrame* aFrame,
int32_t aOffset) -> PositionChangedResult
auto updateSingleCaret = [aHints](AccessibleCaret* aCaret, nsIFrame* aFrame,
int32_t aOffset) -> PositionChangedResult
{
PositionChangedResult result = aCaret->SetPosition(aFrame, aOffset);
aCaret->SetSelectionBarEnabled(sSelectionBarEnabled);
switch (result) {
case PositionChangedResult::NotChanged:
// Do nothing
break;
case PositionChangedResult::Changed:
switch (aHint) {
case UpdateCaretsHint::Default:
aCaret->SetAppearance(Appearance::Normal);
break;
case UpdateCaretsHint::RespectOldAppearance:
// Do nothing to preserve the appearance of the caret set by the
// caller.
break;
if (aHints == UpdateCaretsHint::Default) {
aCaret->SetAppearance(Appearance::Normal);
} else if (aHints.contains(UpdateCaretsHint::RespectOldAppearance)) {
// Do nothing to preserve the appearance of the caret set by the
// caller.
}
break;
@ -416,7 +402,7 @@ AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHint aHint)
}
}
if (aHint == UpdateCaretsHint::Default) {
if (aHints == UpdateCaretsHint::Default) {
// Only check for tilt carets with default update hint. Otherwise we might
// override the appearance set by the caller.
if (sCaretsAlwaysTilt) {
@ -426,7 +412,8 @@ AccessibleCaretManager::UpdateCaretsForSelectionMode(UpdateCaretsHint aHint)
}
}
if (!mActiveCaret) {
if (!aHints.contains(UpdateCaretsHint::DispatchNoEvent) &&
!mActiveCaret) {
DispatchCaretStateChangedEvent(CaretChangedReason::Updateposition);
}
}
@ -666,6 +653,8 @@ AccessibleCaretManager::OnScrollStart()
{
AC_LOG("%s", __FUNCTION__);
mIsScrollStarted = true;
if (!sCaretsAlwaysShowWhenScrolling) {
// Backup the appearance so that we can restore them after the scrolling
// ends.
@ -689,6 +678,8 @@ AccessibleCaretManager::OnScrollEnd()
return;
}
mIsScrollStarted = false;
if (!sCaretsAlwaysShowWhenScrolling) {
// Restore the appearance which is saved before the scrolling is started.
mFirstCaret->SetAppearance(mFirstCaretAppearanceOnScrollStart);
@ -723,8 +714,17 @@ AccessibleCaretManager::OnScrollPositionChanged()
}
if (mFirstCaret->IsLogicallyVisible() || mSecondCaret->IsLogicallyVisible()) {
AC_LOG("%s: UpdateCarets(RespectOldAppearance)", __FUNCTION__);
UpdateCarets(UpdateCaretsHint::RespectOldAppearance);
if (mIsScrollStarted) {
// We don't want extra CaretStateChangedEvents dispatched when user is
// scrolling the page.
AC_LOG("%s: UpdateCarets(RespectOldAppearance | DispatchNoEvent)",
__FUNCTION__);
UpdateCarets({ UpdateCaretsHint::RespectOldAppearance,
UpdateCaretsHint::DispatchNoEvent });
} else {
AC_LOG("%s: UpdateCarets(RespectOldAppearance)", __FUNCTION__);
UpdateCarets(UpdateCaretsHint::RespectOldAppearance);
}
}
}

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

@ -8,17 +8,17 @@
#define AccessibleCaretManager_h
#include "AccessibleCaret.h"
#include "mozilla/dom/CaretStateChangedEvent.h"
#include "mozilla/EnumSet.h"
#include "mozilla/EventForwards.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsCoord.h"
#include "nsIDOMMouseEvent.h"
#include "nsIFrame.h"
#include "nsISelectionListener.h"
#include "mozilla/RefPtr.h"
#include "nsWeakReference.h"
#include "mozilla/dom/CaretStateChangedEvent.h"
#include "mozilla/EventForwards.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
class nsFrameSelection;
class nsIContent;
@ -130,22 +130,28 @@ protected:
// Update everything while respecting the old appearance. For example, if
// the caret in cursor mode is hidden due to timeout, do not change its
// appearance to Normal.
RespectOldAppearance
RespectOldAppearance,
// No CaretStateChangedEvent will be dispatched in the end of
// UpdateCarets().
DispatchNoEvent,
};
using UpdateCaretsHintSet = mozilla::EnumSet<UpdateCaretsHint>;
friend std::ostream& operator<<(std::ostream& aStream,
const UpdateCaretsHint& aResult);
// Update carets based on current selection status. This function will flush
// layout, so caller must ensure the PresShell is still valid after calling
// this method.
void UpdateCarets(UpdateCaretsHint aHint = UpdateCaretsHint::Default);
void UpdateCarets(UpdateCaretsHintSet aHints = UpdateCaretsHint::Default);
// Force hiding all carets regardless of the current selection status.
void HideCarets();
void UpdateCaretsForCursorMode(UpdateCaretsHint aHint);
void UpdateCaretsForSelectionMode(UpdateCaretsHint aHint);
void UpdateCaretsForCursorMode(UpdateCaretsHintSet aHints);
void UpdateCaretsForSelectionMode(UpdateCaretsHintSet aHints);
// Provide haptic / touch feedback, primarily for select on longpress.
void ProvideHapticFeedback();
@ -294,6 +300,9 @@ protected:
// input types such as touch.
uint16_t mLastInputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
// Set to true in OnScrollStart() and set to false in OnScrollEnd().
bool mIsScrollStarted = false;
static const int32_t kAutoScrollTimerDelay = 30;
// Clicking on the boundary of input or textarea will move the caret to the

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

@ -738,7 +738,7 @@ AccessibleCaretEventHubTester::TestEventDrivenAsyncPanZoomScroll(
EXPECT_EQ(mHub->GetState(), MockAccessibleCaretEventHub::NoActionState());
}
TEST_F(AccessibleCaretEventHubTester, TestNoEventAsyncPanZoomScroll)
TEST_F(AccessibleCaretEventHubTester, TestAsyncPanZoomScroll)
{
MockFunction<void(::std::string aCheckPointName)> check;
{
@ -748,7 +748,7 @@ TEST_F(AccessibleCaretEventHubTester, TestNoEventAsyncPanZoomScroll)
EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnScrollStart());
EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(),
OnScrollPositionChanged()).Times(0);
OnScrollPositionChanged()).Times(2);
EXPECT_CALL(check, Call("2"));
EXPECT_CALL(*mHub->GetMockAccessibleCaretManager(), OnScrollEnd());

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

@ -453,6 +453,9 @@ TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionModeWithAlwaysTiltPref
CaretChangedReason::Scroll));
EXPECT_CALL(check, Call("scrollstart1"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
EXPECT_CALL(check, Call("scrollPositionChanged1"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition));
EXPECT_CALL(check, Call("reflow1"));
@ -470,6 +473,9 @@ TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionModeWithAlwaysTiltPref
CaretChangedReason::Scroll));
EXPECT_CALL(check, Call("scrollstart2"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(_)).Times(0);
EXPECT_CALL(check, Call("scrollPositionChanged2"));
EXPECT_CALL(mManager, DispatchCaretStateChangedEvent(
CaretChangedReason::Updateposition));
EXPECT_CALL(check, Call("reflow2"));
@ -490,6 +496,11 @@ TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionModeWithAlwaysTiltPref
EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
check.Call("scrollstart1");
mManager.OnScrollPositionChanged();
EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
check.Call("scrollPositionChanged1");
mManager.OnReflow();
EXPECT_EQ(FirstCaretAppearance(), Appearance::NormalNotShown);
EXPECT_EQ(SecondCaretAppearance(), Appearance::Right);
@ -505,6 +516,11 @@ TEST_F(AccessibleCaretManagerTester, TestScrollInSelectionModeWithAlwaysTiltPref
EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
check.Call("scrollstart2");
mManager.OnScrollPositionChanged();
EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
check.Call("scrollPositionChanged2");
mManager.OnReflow();
EXPECT_EQ(FirstCaretAppearance(), Appearance::Left);
EXPECT_EQ(SecondCaretAppearance(), Appearance::NormalNotShown);
@ -795,6 +811,7 @@ TEST_F(AccessibleCaretManagerTester,
// Scroll the caret into the viewport.
mManager.OnScrollStart();
check.Call("longtap scrollstart2");
mManager.OnScrollPositionChanged();
mManager.OnScrollEnd();
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
check.Call("longtap scrollend2");
@ -802,6 +819,7 @@ TEST_F(AccessibleCaretManagerTester,
// Scroll the caret within the viewport.
mManager.OnScrollStart();
check.Call("longtap scrollstart3");
mManager.OnScrollPositionChanged();
mManager.OnScrollEnd();
EXPECT_EQ(FirstCaretAppearance(), Appearance::Normal);
check.Call("longtap scrollend3");

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

@ -4018,16 +4018,13 @@ struct MOZ_RAII BoxToRectAndText : public BoxToRect {
if (aFrame->GetType() == nsGkAtoms::textFrame) {
nsTextFrame* textFrame = static_cast<nsTextFrame*>(aFrame);
nsIContent* content = textFrame->GetContent();
nsAutoString textContent;
mozilla::ErrorResult err; // ignored
content->GetTextContent(textContent, err);
nsIFrame::RenderedText renderedText = textFrame->GetRenderedText(
textFrame->GetContentOffset(),
textFrame->GetContentOffset() + textFrame->GetContentLength(),
nsIFrame::TextOffsetType::OFFSETS_IN_CONTENT_TEXT,
nsIFrame::TrailingWhitespace::DONT_TRIM_TRAILING_WHITESPACE);
const nsAString& textSubstring =
Substring(textContent,
textFrame->GetContentOffset(),
textFrame->GetContentLength());
aResult.Append(textSubstring);
aResult.Append(renderedText.mString);
}
for (nsIFrame* child = aFrame->PrincipalChildList().FirstChild();

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

@ -48,6 +48,7 @@
#include "mozilla/MouseEvents.h"
#include "mozilla/Unused.h"
#include "gfx2DGlue.h"
#include "mozilla/widget/nsAutoRollup.h"
#ifdef XP_WIN
#define COMBOBOX_ROLLUP_CONSUME_EVENT 0
@ -1149,8 +1150,7 @@ nsComboboxControlFrame::HandleEvent(nsPresContext* aPresContext,
#if COMBOBOX_ROLLUP_CONSUME_EVENT == 0
if (aEvent->mMessage == eMouseDown) {
nsIWidget* widget = GetNearestWidget();
if (widget && GetContent() == widget->GetLastRollup()) {
if (GetContent() == mozilla::widget::nsAutoRollup::GetLastRollup()) {
// This event did a Rollup on this control - prevent it from opening
// the dropdown again!
*aEventStatus = nsEventStatus_eConsumeNoDefault;

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

@ -9838,7 +9838,13 @@ nsTextFrame::GetRenderedText(uint32_t aStartOffset,
TextOffsetType aOffsetType,
TrailingWhitespace aTrimTrailingWhitespace)
{
NS_ASSERTION(!GetPrevContinuation(), "Must be called on first-in-flow");
MOZ_ASSERT(aStartOffset <= aEndOffset, "bogus offsets");
MOZ_ASSERT(!GetPrevContinuation() ||
(aOffsetType == TextOffsetType::OFFSETS_IN_CONTENT_TEXT &&
aStartOffset >= (uint32_t)GetContentOffset() &&
aEndOffset <= (uint32_t)GetContentEnd()),
"Must be called on first-in-flow, or content offsets must be "
"given and be within this frame.");
// The handling of offsets could be more efficient...
RenderedText result;

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

@ -1,58 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "inSearchLoop.h"
#include "nsITimer.h"
#include "nsIServiceManager.h"
///////////////////////////////////////////////////////////////////////////////
inSearchLoop::inSearchLoop(inISearchProcess* aSearchProcess)
{
mSearchProcess = aSearchProcess;
nsresult rv;
mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
}
inSearchLoop::~inSearchLoop()
{
}
///////////////////////////////////////////////////////////////////////////////
// inSearchLoop
nsresult
inSearchLoop::Start()
{
mTimer->InitWithFuncCallback(inSearchLoop::TimerCallback, (void*)this, 0, nsITimer::TYPE_REPEATING_SLACK);
return NS_OK;
}
nsresult
inSearchLoop::Step()
{
bool done = false;
mSearchProcess->SearchStep(&done);
if (done)
Stop();
return NS_OK;
}
nsresult
inSearchLoop::Stop()
{
mTimer->Cancel();
return NS_OK;
}
void
inSearchLoop::TimerCallback(nsITimer *aTimer, void *aClosure)
{
inSearchLoop* loop = (inSearchLoop*) aClosure;
loop->Step();
}

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

@ -1,28 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef __inSearchLoop_h__
#define __inSearchLoop_h__
#include "nsCOMPtr.h"
#include "nsITimer.h"
#include "inISearchProcess.h"
class inSearchLoop
{
public:
explicit inSearchLoop(inISearchProcess* aSearchProcess);
virtual ~inSearchLoop();
nsresult Start();
nsresult Step();
nsresult Stop();
static void TimerCallback(nsITimer *aTimer, void *aClosure);
protected:
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<inISearchProcess> mSearchProcess;
};
#endif

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

@ -31,7 +31,6 @@ UNIFIED_SOURCES += [
'inDeepTreeWalker.cpp',
'inDOMUtils.cpp',
'inLayoutUtils.cpp',
'inSearchLoop.cpp',
'nsFontFace.cpp',
'nsFontFaceList.cpp',
]

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

@ -40,7 +40,7 @@ Any line which doesn't follow the format above would be ignored like comment.
* test_display_mode_reflow.html [2]
* test_all_shorthand.html: all shorthand servo/servo#15055 [*]
* Animation support:
* test_animations.html [44]
* test_animations.html [36]
* test_animations_dynamic_changes.html [1]
* test_bug716226.html [1]
* OMTA
@ -110,7 +110,7 @@ Any line which doesn't follow the format above would be ignored like comment.
* url value in style attribute bug 1310886
* test_computed_style.html `url` [11]
* test_parse_url.html [4]
* test_value_storage.html `url` [89]
* test_value_storage.html `url` [53]
* test_shorthand_property_getters.html `url` [3]
* auto value for min-{width,height} servo/servo#15045
* test_compute_data_with_start_struct.html `timing-function`: incorrectly computing keywords to bezier function servo/servo#15086 [2]
@ -132,7 +132,7 @@ Any line which doesn't follow the format above would be ignored like comment.
* test_namespace_rule.html [17]
* test_dont_use_document_colors.html: support of disabling document color [21]
* test_exposed_prop_accessors.html: mainly various unsupported properties [*]
* test_extra_inherit_initial.html: CSS-wide keywords are accepted as part of value servo/servo#15054 [986]
* test_extra_inherit_initial.html: CSS-wide keywords are accepted as part of value servo/servo#15054 [980]
* test_flexbox_flex_shorthand.html `flex-basis`: **need investigation** [12]
* test_flexbox_layout.html: **need investigation** [5]
* test_font_feature_values_parsing.html: @font-feature-values support [107]
@ -370,8 +370,6 @@ Any line which doesn't follow the format above would be ignored like comment.
* test_inherit_storage.html `for property 'border-image-` [5]
* test_initial_storage.html `for property 'border-image-` [10]
* test_value_storage.html `(for 'border-image-` [60]
* accepts rubbish for second part of value:
* test_property_syntax_errors.html `'text-overflow'`: servo/servo#15491 [8]
* -moz-alt-content parsing is wrong: servo/servo#15726
* test_property_syntax_errors.html `-moz-alt-content` [4]
* {transform,perspective}-origin fail to parse 'center left' and 'center right' servo/servo#15750

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

@ -41,6 +41,7 @@
#include "mozilla/LookAndFeel.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Services.h"
#include "mozilla/widget/nsAutoRollup.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -1732,8 +1733,7 @@ nsXULPopupManager::MayShowPopup(nsMenuPopupFrame* aPopup)
}
// if the popup was just rolled up, don't reopen it
nsCOMPtr<nsIWidget> widget = aPopup->GetWidget();
if (widget && widget->GetLastRollup() == aPopup->GetContent())
if (mozilla::widget::nsAutoRollup::GetLastRollup() == aPopup->GetContent())
return false;
nsCOMPtr<nsIDocShellTreeItem> dsti = aPopup->PresContext()->GetDocShell();

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

@ -205,10 +205,13 @@ bool WebrtcAudioConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
fractionLost,
*cumulativeLost,
*rttMs);
if (result) {
*timestamp = NTPtoDOMHighResTimeStamp(ntpHigh, ntpLow);
if (!result) {
return false;
}
return result;
// Note: timestamp is not correct per the spec... should be time the rtcp
// was received (remote) or sent (local)
*timestamp = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
return true;
}
bool WebrtcAudioConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,

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

@ -821,24 +821,42 @@ bool WebrtcVideoConduit::GetRTCPReceiverReport(DOMHighResTimeStamp* timestamp,
{
CSFLogVerbose(logTag, "%s for VideoConduit:%p", __FUNCTION__, this);
MutexAutoLock lock(mCodecMutex);
if (!mRecvStream) {
if (!mSendStream) {
return false;
}
const webrtc::VideoReceiveStream::Stats &stats = mRecvStream->GetStats();
*jitterMs = stats.rtcp_stats.jitter;
*cumulativeLost = stats.rtcp_stats.cumulative_lost;
*bytesReceived = stats.rtp_stats.MediaPayloadBytes();
*packetsReceived = stats.rtp_stats.transmitted.packets;
// Note: timestamp is not correct per the spec... should be time the rtcp
// was received (remote) or sent (local)
*timestamp = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
int64_t rtt = mRecvStream->GetRtt();
const webrtc::VideoSendStream::Stats& sendStats = mSendStream->GetStats();
if (sendStats.substreams.size() == 0
|| mSendStreamConfig.rtp.ssrcs.size() == 0) {
return false;
}
uint32_t ssrc = mSendStreamConfig.rtp.ssrcs.front();
auto ind = sendStats.substreams.find(ssrc);
if (ind == sendStats.substreams.end()) {
CSFLogError(logTag,
"%s for VideoConduit:%p ssrc not found in SendStream stats.",
__FUNCTION__, this);
return false;
}
*jitterMs = ind->second.rtcp_stats.jitter;
*cumulativeLost = ind->second.rtcp_stats.cumulative_lost;
*bytesReceived = ind->second.rtp_stats.MediaPayloadBytes();
*packetsReceived = ind->second.rtp_stats.transmitted.packets;
int64_t rtt = mSendStream->GetRtt(); // TODO: BUG 1241066, mozRtt is 0 or 1
if (rtt >= 0) {
*rttMs = rtt;
} else {
*rttMs = 0;
}
#ifdef DEBUG
if (rtt > INT32_MAX) {
CSFLogError(logTag,
"%s for VideoConduit:%p mRecvStream->GetRtt() is larger than the"
" maximum size of an RTCP RTT.", __FUNCTION__, this);
}
#endif
// Note: timestamp is not correct per the spec... should be time the rtcp
// was received (remote) or sent (local)
*timestamp = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
}
return true;
}
@ -849,22 +867,16 @@ WebrtcVideoConduit::GetRTCPSenderReport(DOMHighResTimeStamp* timestamp,
uint64_t* bytesSent)
{
CSFLogVerbose(logTag, "%s for VideoConduit:%p", __FUNCTION__, this);
MutexAutoLock lock(mCodecMutex);
if (!mSendStream) {
return false;
webrtc::RTCPSenderInfo senderInfo;
{
MutexAutoLock lock(mCodecMutex);
if (!mRecvStream || !mRecvStream->GetRemoteRTCPSenderInfo(&senderInfo)) {
return false;
}
}
const webrtc::VideoSendStream::Stats& stats = mSendStream->GetStats();
*packetsSent = 0;
for (auto entry: stats.substreams){
*packetsSent += entry.second.rtp_stats.transmitted.packets;
// NG -- per https://www.w3.org/TR/webrtc-stats/ this is only payload bytes
*bytesSent += entry.second.rtp_stats.MediaPayloadBytes();
}
// Note: timestamp is not correct per the spec... should be time the rtcp
// was received (remote) or sent (local)
*timestamp = webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds();
*packetsSent = senderInfo.sendPacketCount;
*bytesSent = senderInfo.sendOctetCount;
return true;
}

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

@ -407,5 +407,10 @@ int64_t VideoReceiveStream::GetRtt() const {
return -1;
}
bool
VideoReceiveStream::GetRemoteRTCPSenderInfo(RTCPSenderInfo* sender_info) const {
return -1 != vie_channel_->GetRemoteRTCPSenderInfo(sender_info);
}
} // namespace internal
} // namespace webrtc

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

@ -76,6 +76,7 @@ class VideoReceiveStream : public webrtc::VideoReceiveStream,
void SetSyncChannel(VoiceEngine* voice_engine, int audio_channel_id) override;
int64_t GetRtt() const override;
bool GetRemoteRTCPSenderInfo(RTCPSenderInfo* sender_info) const override;
private:
TransportAdapter transport_adapter_;
EncodedFrameCallbackAdapter encoded_frame_proxy_;

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

@ -70,7 +70,7 @@ class VideoSendStream : public webrtc::VideoSendStream,
typedef std::map<uint32_t, RtpState> RtpStateMap;
RtpStateMap GetRtpStates() const;
int64_t GetRtt() const;
int64_t GetRtt() const override;
int GetPaddingNeededBps() const;
private:

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

@ -891,21 +891,15 @@ int32_t ViEChannel::GetRemoteRTCPReceiverInfo(uint32_t& NTPHigh,
return 0;
}
//->@@NG // int32_t ViEChannel::GetRemoteRTCPSenderInfo(RTCPSenderInfo* sender_info) const {
//->@@NG // // Get the sender info from the latest received RTCP Sender Report.
//->@@NG // RTCPSenderInfo rtcp_sender_info;
//->@@NG // if (rtp_rtcp_->RemoteRTCPStat(&rtcp_sender_info) != 0) {
//->@@NG // LOG_F(LS_ERROR) << "failed to read RTCP SR sender info";
//->@@NG // return -1;
//->@@NG // }
//->@@NG //
//->@@NG // sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
//->@@NG // sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
//->@@NG // sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
//->@@NG // sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
//->@@NG // sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
//->@@NG // return 0;
//->@@NG // }
int32_t ViEChannel::GetRemoteRTCPSenderInfo(RTCPSenderInfo* sender_info) const {
// Get the sender info from the latest received RTCP Sender Report.
if (rtp_rtcp_modules_[0] &&
rtp_rtcp_modules_[0]->RemoteRTCPStat(sender_info) != 0) {
LOG_F(LS_ERROR) << "failed to read RTCP SR sender info";
return -1;
}
return 0;
}
void ViEChannel::RegisterSendChannelRtcpStatisticsCallback(
RtcpStatisticsCallback* callback) {

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

@ -179,6 +179,10 @@ class VideoReceiveStream : public ReceiveStream {
// TODO(pbos): Add info on currently-received codec to Stats.
virtual Stats GetStats() const = 0;
virtual int64_t GetRtt() const = 0;
virtual bool
GetRemoteRTCPSenderInfo(RTCPSenderInfo* sender_info) const = 0;
virtual void SetSyncChannel(VoiceEngine* voice_engine, int audio_channel_id) = 0;
};

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

@ -187,6 +187,8 @@ class VideoSendStream : public SendStream {
virtual bool ReconfigureVideoEncoder(const VideoEncoderConfig& config) = 0;
virtual Stats GetStats() = 0;
virtual int64_t GetRtt() const = 0;
};
} // namespace webrtc

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

@ -330,6 +330,8 @@
@BINPATH@/components/txEXSLTRegExFunctions.js
@BINPATH@/components/nsContentPrefService.manifest
@BINPATH@/components/nsContentPrefService.js
@BINPATH@/components/nsHandlerService-json.manifest
@BINPATH@/components/nsHandlerService-json.js
@BINPATH@/components/nsHandlerService.manifest
@BINPATH@/components/nsHandlerService.js
@BINPATH@/components/nsWebHandlerApp.manifest

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

@ -20,6 +20,8 @@ def main(args):
parser.add_argument("-C", metavar='DIR', default=".",
help="Change to given directory before considering "
"other paths")
parser.add_argument("--strip", action='store_true',
help="Strip executables")
parser.add_argument("zip", help="Path to zip file to write")
parser.add_argument("input", nargs="+",
help="Path to files to add to zip")
@ -28,7 +30,7 @@ def main(args):
jarrer = Jarrer(optimize=False)
with errors.accumulate():
finder = FileFinder(args.C)
finder = FileFinder(args.C, find_executables=args.strip)
for path in args.input:
for p, f in finder.find(path):
jarrer.add(p, f)

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

@ -506,24 +506,31 @@ impl<'le> TElement for GeckoElement<'le> {
}
fn update_animations(&self, pseudo: Option<&PseudoElement>) {
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
// 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
// all CSS animations in display:none subtree.
let computed_data = self.borrow_data();
let computed_values = computed_data.as_ref().map(|d| d.styles().primary.values());
let computed_values =
computed_data.as_ref().map(|d|
pseudo.map_or_else(|| d.styles().primary.values(),
|p| d.styles().pseudos.get(p).unwrap().values())
);
let computed_values_opt = computed_values.map(|v|
*HasArcFFI::arc_as_borrowed(v)
);
let parent_element = self.parent_element();
let parent_element = if pseudo.is_some() {
self.parent_element()
} else {
Some(*self)
};
let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
let parent_values = parent_data.as_ref().map(|d| d.styles().primary.values());
let parent_values_opt = parent_values.map(|v|
*HasArcFFI::arc_as_borrowed(v)
);
let atom_ptr = PseudoElement::ns_atom_or_null_from_opt(pseudo);
unsafe {
Gecko_UpdateAnimations(self.0, atom_ptr,
computed_values_opt,

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

@ -266,9 +266,7 @@ ${helpers.predefined_type("clip",
try!(dest.write_str(")"));
}
computed_value::Filter::Url(ref url) => {
dest.write_str("url(")?;
url.to_css(dest)?;
dest.write_str(")")?;
}
% endif
}
@ -311,9 +309,7 @@ ${helpers.predefined_type("clip",
try!(dest.write_str(")"));
}
SpecifiedFilter::Url(ref url) => {
dest.write_str("url(")?;
url.to_css(dest)?;
dest.write_str(")")?;
}
% endif
}

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

@ -51,7 +51,7 @@
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
let first = try!(Side::parse(context, input));
let second = Side::parse(context, input).ok();
let second = input.try(|input| Side::parse(context, input)).ok();
Ok(SpecifiedValue {
first: first,
second: second,

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

@ -22,3 +22,13 @@ fn test_text_overflow() {
assert_roundtrip_with_context!(text_overflow::parse, r#""x" "y""#);
}
#[test]
fn test_text_overflow_parser_exhaustion() {
use style::properties::longhands::text_overflow;
assert_parser_exhausted!(text_overflow, r#"clip rubbish"#, false);
assert_parser_exhausted!(text_overflow, r#"clip"#, true);
assert_parser_exhausted!(text_overflow, r#"ellipsis"#, true);
assert_parser_exhausted!(text_overflow, r#"clip ellipsis"#, true);
}

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

@ -122,6 +122,10 @@ external-media-tests-twitch:
treeherder-symbol: tc-VP(b-t)
unittest-try-name: media-twitch-tests
e10s: false
instance-size:
by-test-platform:
linux.*: xlarge
default: default
tier: 2
max-run-time: 5400
docker-image: {"in-tree": "desktop1604-test"}

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

@ -1,5 +1,5 @@
[flake8]
# See http://pep8.readthedocs.io/en/latest/intro.html#configuration
ignore = E121, E123, E126, E129, E133, E226, E241, E242, E704, W503, E402, E502, E128, E501, E713, E111, E222, E201, E202, W602, E127, W601
ignore = E121, E123, E126, E129, E133, E226, E241, E242, E704, W503, E402, E502, E128, E501, E713, E222, E201, E202, W602, E127, W601
max-line-length = 99
filename = *.py, +.lint

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

@ -85,7 +85,7 @@ try:
try:
whitelists = json.load(f)
for name, whitelist in whitelists.iteritems():
whitelists[name] = set(whitelist)
whitelists[name] = set(whitelist)
except ValueError, e:
raise BaseException, 'error parsing whitelist (%s)' % whitelist_path
except IOError:

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

@ -27,7 +27,8 @@ Documents with an Unknown classification will have Flash set to Click To Activat
If the document is at the top level (its address is in the URL bar), then the Deny List is checked first followed by the Allow List to determine its classification.
If the document is not at the top level, it will receive a Deny classification if the classification of the parent document is Deny or if the document is on the Deny List or the Sub-Document Deny List.
If the document is not at the top level, it will receive a Deny classification if the classification of the parent document is Deny or if the document is on the Deny List.
It will also receive a Deny classification if the sub-document is not same-origin and the document is on the Sub-Document Deny List.
If the document did not receive a Deny classification, it can receive an Allow classification if it is on the Allow List or if the parent document received an Allow classification.
If for any reason, the document has a null principal, it will receive a Deny classification.

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

@ -11,6 +11,8 @@ const WHITELIST_TABLE_PREF = "urlclassifier.trackingWhitelistTable";
Cu.import("resource://gre/modules/Services.jsm");
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.UrlClassifierTestUtils = {
addTestTrackers() {
@ -46,7 +48,25 @@ this.UrlClassifierTestUtils = {
}
];
return this.useTestDatabase(tables);
let tableIndex = 0
let doOneUpdate = () => {
if (tableIndex == tables.length) {
return;
}
return this.useTestDatabase(tables[tableIndex])
.then(() => {
tableIndex++;
return doOneUpdate();
}, aErrMsg => {
dump("Rejected: " + aErrMsg + ". Retry later.\n");
return new Promise(resolve => {
timer.initWithCallback(resolve, 100, Ci.nsITimer.TYPE_ONE_SHOT);
})
.then(doOneUpdate);
});
}
return doOneUpdate();
},
cleanupTestTrackers() {
@ -60,10 +80,8 @@ this.UrlClassifierTestUtils = {
*
* @return {Promise}
*/
useTestDatabase(tables) {
for (var table of tables) {
Services.prefs.setCharPref(table.pref, table.name);
}
useTestDatabase(table) {
Services.prefs.setCharPref(table.pref, table.name);
return new Promise((resolve, reject) => {
let dbService = Cc["@mozilla.org/url-classifier/dbservice;1"].
@ -79,19 +97,21 @@ this.UrlClassifierTestUtils = {
updateUrlRequested: url => { },
streamFinished: status => { },
updateError: errorCode => {
reject("Couldn't update classifier.");
reject('Got updateError when updating ' + table.name);
},
updateSuccess: requestedTimeout => {
resolve();
}
};
for (var table of tables) {
try {
dbService.beginUpdate(listener, table.name, "");
dbService.beginStream("", "");
dbService.updateStream(table.update);
dbService.finishStream();
dbService.finishUpdate();
} catch (e) {
reject('Failed to update with dbService: ' + table.name);
}
});
},

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

@ -184,6 +184,24 @@ var testCases = [
pluginListed: false,
expectedFlashClassification: "denied"
},
{
name: "Sub-document blocked domain in non-Third-Party context",
domains: ["http://subdocument.example.com", "http://subdocument.example.com"],
expectedPluginFallbackType: Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY,
expectedActivated: false,
expectedHasRunningPlugin: false,
pluginListed: true,
expectedFlashClassification: "unknown"
},
{
name: "Sub-document blocked domain differing only by scheme",
domains: ["http://subdocument.example.com", "https://subdocument.example.com"],
expectedPluginFallbackType: Ci.nsIObjectLoadingContent.PLUGIN_USER_DISABLED,
expectedActivated: false,
expectedHasRunningPlugin: false,
pluginListed: false,
expectedFlashClassification: "denied"
},
{
name: "Sub-document blocked subdocument of an allowed domain",
domains: ["http://flashallow.example.com", "http://subdocument.example.com"],

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

@ -46,6 +46,11 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
"resource://gre/modules/PluralForm.jsm");
this.__defineGetter__("gDecimalSymbol", function() {
delete this.gDecimalSymbol;
return this.gDecimalSymbol = Number(5.4).toLocaleString().match(/\D/);
});
var localeNumberFormatCache = new Map();
function getLocaleNumberFormat(fractionDigits) {
// Backward compatibility: don't use localized digits
@ -344,9 +349,12 @@ this.DownloadUtils = {
let today = new Date(aNow.getFullYear(), aNow.getMonth(), aNow.getDate());
// Get locale to use for date/time formatting
const locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry)
.getSelectedLocale("global", true);
// TODO: Remove Intl fallback when no longer needed (bug 1344543).
const locale = typeof Intl === "undefined"
? undefined
: Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry)
.getSelectedLocale("global", true);
// Figure out if the time is from today, yesterday, this week, etc.
let dateTimeCompact;
@ -362,10 +370,14 @@ this.DownloadUtils = {
dateTimeCompact = gBundle.GetStringFromName(gStr.yesterday);
} else if (today - aDate < (6 * 24 * 60 * 60 * 1000)) {
// After last week started, show day of week
dateTimeCompact = aDate.toLocaleDateString(locale, { weekday: "long" });
dateTimeCompact = typeof Intl === "undefined"
? aDate.toLocaleFormat("%A")
: aDate.toLocaleDateString(locale, { weekday: "long" });
} else {
// Show month/day
let month = aDate.toLocaleDateString(locale, { month: "long" });
let month = typeof Intl === "undefined"
? aDate.toLocaleFormat("%B")
: aDate.toLocaleDateString(locale, { month: "long" });
let date = aDate.getDate();
dateTimeCompact = gBundle.formatStringFromName(gStr.monthDate, [month, date], 2);
}
@ -477,8 +489,15 @@ this.DownloadUtils = {
// Don't try to format Infinity values using NumberFormat.
if (aBytes === Infinity) {
aBytes = "Infinity";
} else if (typeof Intl != "undefined") {
aBytes = getLocaleNumberFormat(fractionDigits)
.format(aBytes);
} else {
aBytes = getLocaleNumberFormat(fractionDigits).format(aBytes);
// FIXME: Fall back to the old hack, will be fixed in bug 1344543.
aBytes = aBytes.toFixed(fractionDigits);
if (gDecimalSymbol != ".") {
aBytes = aBytes.replace(".", gDecimalSymbol);
}
}
return [aBytes, gBundle.GetStringFromName(gStr.units[unitIndex])];

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

@ -78,9 +78,12 @@ function testAllGetReadableDates() {
const sixdaysago = new Date(2000, 11, 25, 11, 30, 15);
const sevendaysago = new Date(2000, 11, 24, 11, 30, 15);
const locale = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
.getService(Components.interfaces.nsIXULChromeRegistry)
.getSelectedLocale("global", true);
// TODO: Remove Intl fallback when no longer needed (bug 1344543).
const locale = typeof Intl === "undefined"
? undefined
: Components.classes["@mozilla.org/chrome/chrome-registry;1"]
.getService(Components.interfaces.nsIXULChromeRegistry)
.getSelectedLocale("global", true);
let dts = Components.classes["@mozilla.org/intl/scriptabledateformat;1"].
getService(Components.interfaces.nsIScriptableDateFormat);
@ -92,11 +95,17 @@ function testAllGetReadableDates() {
testGetReadableDates(yesterday_11_30, "Yesterday");
testGetReadableDates(yesterday_12_30, "Yesterday");
testGetReadableDates(twodaysago,
twodaysago.toLocaleDateString(locale, { weekday: "long" }));
typeof Intl === "undefined"
? twodaysago.toLocaleFormat("%A")
: twodaysago.toLocaleDateString(locale, { weekday: "long" }));
testGetReadableDates(sixdaysago,
sixdaysago.toLocaleDateString(locale, { weekday: "long" }));
typeof Intl === "undefined"
? sixdaysago.toLocaleFormat("%A")
: sixdaysago.toLocaleDateString(locale, { weekday: "long" }));
testGetReadableDates(sevendaysago,
sevendaysago.toLocaleDateString(locale, { month: "long" }) + " " +
(typeof Intl === "undefined"
? sevendaysago.toLocaleFormat("%B")
: sevendaysago.toLocaleDateString(locale, { month: "long" })) + " " +
sevendaysago.getDate().toString().padStart(2, "0"));
let [, dateTimeFull] = DownloadUtils.getReadableDates(today_11_30);

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

@ -76,7 +76,7 @@ ifdef WIN_UCRT_REDIST_DIR
JSSHELL_BINS += ucrtbase.dll
endif
MAKE_JSSHELL = $(call py_action,zip,-C $(DIST)/bin $(abspath $(PKG_JSSHELL)) $(JSSHELL_BINS))
MAKE_JSSHELL = $(call py_action,zip,-C $(DIST)/bin --strip $(abspath $(PKG_JSSHELL)) $(JSSHELL_BINS))
JARLOG_DIR = $(topobjdir)/jarlog/
JARLOG_FILE_AB_CD = $(JARLOG_DIR)/$(AB_CD).log

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

@ -3820,11 +3820,27 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
return 1;
}
if (!username) {
struct passwd *pw = getpwuid(geteuid());
if (pw && pw->pw_name) {
// Beware that another call to getpwent/getpwname/getpwuid will overwrite
// pw, but we don't have such another call between here and when username
// is used last.
username = pw->pw_name;
}
}
nsCOMPtr<nsIFile> mutexDir;
rv = GetSpecialSystemDirectory(OS_TemporaryDirectory, getter_AddRefs(mutexDir));
if (NS_SUCCEEDED(rv)) {
nsAutoCString mutexPath =
program + NS_LITERAL_CSTRING("_") + nsDependentCString(username);
nsAutoCString mutexPath = program + NS_LITERAL_CSTRING("_");
// In the unlikely even that LOGNAME is not set and getpwuid failed, just
// don't put the username in the mutex directory. It will conflict with
// other users mutex, but the worst that can happen is that they wait for
// MOZ_XREMOTE_START_TIMEOUT_SEC during startup in that case.
if (username) {
mutexPath.Append(username);
}
if (profile) {
mutexPath.Append(NS_LITERAL_CSTRING("_") + nsDependentCString(profile));
}

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

@ -31,6 +31,8 @@ protected:
}
public:
// Can only run on the main thread.
NS_IMETHOD Run() override
{
MonitorAutoLock mon(mMonitor);
@ -95,18 +97,15 @@ ThreadResponsiveness::~ThreadResponsiveness()
void
ThreadResponsiveness::Update(bool aIsMainThread, nsIThread* aThread)
{
if (!mActiveTracerEvent) {
if (aIsMainThread) {
mActiveTracerEvent = new CheckResponsivenessTask();
NS_DispatchToMainThread(mActiveTracerEvent);
} else if (aThread) {
mActiveTracerEvent = new CheckResponsivenessTask();
aThread->Dispatch(mActiveTracerEvent, NS_DISPATCH_NORMAL);
}
if (!aIsMainThread) {
return;
}
if (mActiveTracerEvent) {
mLastTracerTime = mActiveTracerEvent->GetLastTracerTime();
if (!mActiveTracerEvent) {
mActiveTracerEvent = new CheckResponsivenessTask();
NS_DispatchToMainThread(mActiveTracerEvent);
}
mLastTracerTime = mActiveTracerEvent->GetLastTracerTime();
}

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

@ -18,6 +18,7 @@ public:
~ThreadResponsiveness();
// Won't do anything on non-main threads for now.
void Update(bool aIsMainThread, nsIThread* aThread);
mozilla::TimeDuration GetUnresponsiveDuration(const mozilla::TimeStamp& now) const {

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

@ -108,6 +108,8 @@ if CONFIG['MOZ_ENABLE_CONTENTACTION']:
]
EXTRA_COMPONENTS += [
'nsHandlerService-json.js',
'nsHandlerService-json.manifest',
'nsHandlerService.js',
'nsHandlerService.manifest',
'nsWebHandlerApp.js',

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

@ -0,0 +1,385 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
"resource://gre/modules/JSONFile.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService",
"@mozilla.org/uriloader/external-protocol-service;1",
"nsIExternalProtocolService");
XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
"@mozilla.org/mime;1",
"nsIMIMEService");
function HandlerService() {
// Observe handlersvc-json-replace so we can switch to the datasource
Services.obs.addObserver(this, "handlersvc-json-replace", true);
}
HandlerService.prototype = {
classID: Components.ID("{220cc253-b60f-41f6-b9cf-fdcb325f970f}"),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsISupportsWeakReference,
Ci.nsIHandlerService,
Ci.nsIObserver
]),
__store: null,
get _store() {
if (!this.__store) {
this.__store = new JSONFile({
path: OS.Path.join(OS.Constants.Path.profileDir,
"handlers.json"),
dataPostProcessor: this._dataPostProcessor.bind(this),
});
this.__store.ensureDataReady();
this._updateDB();
}
return this.__store;
},
_dataPostProcessor(data) {
return data.schemes ? data : { version: {}, mimetypes: {}, schemes: {} };
},
_updateDB() {
try {
let locale = Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry)
.getSelectedLocale("global");
let prefsDefaultHandlersVersion = Number(Services.prefs.getComplexValue(
"gecko.handlerService.defaultHandlersVersion",
Ci.nsIPrefLocalizedString).data);
let defaultHandlersVersion = this._store.data.version[locale] || 0;
if (defaultHandlersVersion < prefsDefaultHandlersVersion ) {
this._injectNewDefaults();
this._store.data.version[locale] = prefsDefaultHandlersVersion;
}
} catch (ex) {
Cu.reportError(ex);
}
},
_injectNewDefaults() {
let schemesPrefBranch = Services.prefs.getBranch("gecko.handlerService.schemes.");
let schemePrefList = schemesPrefBranch.getChildList("");
let schemes = {};
// read all the scheme prefs into a hash
for (let schemePrefName of schemePrefList) {
let [scheme, handlerNumber, attribute] = schemePrefName.split(".");
try {
let attrData =
schemesPrefBranch.getComplexValue(schemePrefName,
Ci.nsIPrefLocalizedString).data;
if (!(scheme in schemes)) {
schemes[scheme] = {};
}
if (!(handlerNumber in schemes[scheme])) {
schemes[scheme][handlerNumber] = {};
}
schemes[scheme][handlerNumber][attribute] = attrData;
} catch (ex) {}
}
for (let scheme of Object.keys(schemes)) {
// This clause is essentially a reimplementation of
// nsIExternalProtocolHandlerService.getProtocolHandlerInfo().
// Necessary because we want to use this instance of the service,
// but nsIExternalProtocolHandlerService would call the RDF-based based version
// until we complete the conversion.
let osDefaultHandlerFound = {};
let protoInfo = gExternalProtocolService.getProtocolHandlerInfoFromOS(scheme,
osDefaultHandlerFound);
if (this.exists(protoInfo)) {
this.fillHandlerInfo(protoInfo, null);
} else {
gExternalProtocolService.setProtocolHandlerDefaults(protoInfo,
osDefaultHandlerFound.value);
}
// cache the possible handlers to avoid extra xpconnect traversals.
let possibleHandlers = protoInfo.possibleApplicationHandlers;
for (let handlerNumber of Object.keys(schemes[scheme])) {
let handlerApp = this.handlerAppFromSerializable(schemes[scheme][handlerNumber]);
if (!this._isInHandlerArray(possibleHandlers, handlerApp)) {
possibleHandlers.appendElement(handlerApp, false);
}
}
this.store(protoInfo);
}
},
_isInHandlerArray(array, handler) {
let enumerator = array.enumerate();
while (enumerator.hasMoreElements()) {
let handlerApp = enumerator.getNext().QueryInterface(Ci.nsIHandlerApp);
if (handlerApp.equals(handler)) {
return true;
}
}
return false;
},
_onDBChange() {
return Task.spawn(function* () {
if (this.__store) {
yield this.__store.finalize();
}
this.__store = null;
}.bind(this)).catch(Cu.reportError);
},
// nsIObserver
observe(subject, topic, data) {
if (topic != "handlersvc-json-replace") {
return;
}
let promise = this._onDBChange();
promise.then(() => {
Services.obs.notifyObservers(null, "handlersvc-json-replace-complete", null);
});
},
// nsIHandlerService
enumerate() {
let handlers = Cc["@mozilla.org/array;1"].
createInstance(Ci.nsIMutableArray);
for (let type of Object.keys(this._store.data.mimetypes)) {
let handler = gMIMEService.getFromTypeAndExtension(type, null);
handlers.appendElement(handler, false);
}
for (let type of Object.keys(this._store.data.schemes)) {
let handler = gExternalProtocolService.getProtocolHandlerInfo(type);
handlers.appendElement(handler, false);
}
return handlers.enumerate();
},
// nsIHandlerService
store(handlerInfo) {
let handlerObj = {
action: handlerInfo.preferredAction,
askBeforeHandling: handlerInfo.alwaysAskBeforeHandling,
};
if (handlerInfo.description) {
handlerObj.description = handlerInfo.description;
}
let preferredHandler = handlerInfo.preferredApplicationHandler;
if (preferredHandler) {
let serializable = this.handlerAppToSerializable(preferredHandler);
if (serializable) {
handlerObj.preferredHandler = serializable;
}
}
let apps = handlerInfo.possibleApplicationHandlers.enumerate();
let possibleHandlers = [];
while (apps.hasMoreElements()) {
let handler = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
let serializable = this.handlerAppToSerializable(handler);
if (serializable) {
possibleHandlers.push(serializable);
}
}
if (possibleHandlers.length) {
handlerObj.possibleHandlers = possibleHandlers;
}
if (handlerInfo instanceof Ci.nsIMIMEInfo) {
let extEnumerator = handlerInfo.getFileExtensions();
let extensions = [];
while (extEnumerator.hasMore()) {
let extension = extEnumerator.getNext();
if (!extensions.includes(extension)) {
extensions.push(extension);
}
}
if (extensions.length) {
handlerObj.fileExtensions = extensions;
}
}
this._getHandlerListByHandlerInfoType(handlerInfo)[handlerInfo.type] = handlerObj;
this._store.saveSoon();
},
// nsIHandlerService
fillHandlerInfo(handlerInfo, overrideType) {
let type = overrideType || handlerInfo.type;
let storedHandlerInfo = this._getHandlerListByHandlerInfoType(handlerInfo)[type];
if (!storedHandlerInfo) {
throw new Components.Exception("handlerSvc fillHandlerInfo: don't know this type",
Cr.NS_ERROR_NOT_AVAILABLE);
}
handlerInfo.description = storedHandlerInfo.description;
// logic from _retrievePreferredAction of nsHandlerService.js
if (storedHandlerInfo.action == Ci.nsIHandlerInfo.saveToDisk ||
storedHandlerInfo.action == Ci.nsIHandlerInfo.useSystemDefault ||
storedHandlerInfo.action == Ci.nsIHandlerInfo.handleInternally) {
handlerInfo.preferredAction = storedHandlerInfo.action;
} else {
handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
}
let preferHandler = null;
if (storedHandlerInfo.preferredHandler) {
preferHandler = this.handlerAppFromSerializable(storedHandlerInfo.preferredHandler);
}
handlerInfo.preferredApplicationHandler = preferHandler;
if (preferHandler) {
handlerInfo.possibleApplicationHandlers.appendElement(preferHandler, false);
}
if (storedHandlerInfo.possibleHandlers) {
for (let handler of storedHandlerInfo.possibleHandlers) {
let possibleHandler = this.handlerAppFromSerializable(handler);
if (possibleHandler && (!preferHandler ||
!possibleHandler.equals(preferHandler))) {
handlerInfo.possibleApplicationHandlers.appendElement(possibleHandler, false);
}
}
}
// We always store "askBeforeHandling" in the JSON file. Just use this value.
handlerInfo.alwaysAskBeforeHandling = storedHandlerInfo.askBeforeHandling;
if (handlerInfo instanceof Ci.nsIMIMEInfo) {
if (storedHandlerInfo.fileExtensions) {
for (let extension of storedHandlerInfo.fileExtensions) {
handlerInfo.appendExtension(extension);
}
}
}
},
/**
* @param handler
* A nsIHandlerApp handler app
* @returns Serializable representation of a handler app object.
*/
handlerAppToSerializable(handler) {
if (handler instanceof Ci.nsILocalHandlerApp) {
return {
name: handler.name,
path: handler.executable.path,
};
} else if (handler instanceof Ci.nsIWebHandlerApp) {
return {
name: handler.name,
uriTemplate: handler.uriTemplate,
};
} else if (handler instanceof Ci.nsIDBusHandlerApp) {
return {
name: handler.name,
service: handler.service,
method: handler.method,
objectPath: handler.objectPath,
dBusInterface: handler.dBusInterface,
};
}
// If the handler is an unknown handler type, return null.
// Android default application handler is the case.
return null;
},
/**
* @param handlerObj
* Serializable representation of a handler object.
* @returns {nsIHandlerApp} the handler app, if any; otherwise null
*/
handlerAppFromSerializable(handlerObj) {
let handlerApp;
if ("path" in handlerObj) {
try {
let file = new FileUtils.File(handlerObj.path);
if (!file.exists()) {
return null;
}
handlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"].
createInstance(Ci.nsILocalHandlerApp);
handlerApp.executable = file;
} catch (ex) {
return null;
}
} else if ("uriTemplate" in handlerObj) {
handlerApp = Cc["@mozilla.org/uriloader/web-handler-app;1"].
createInstance(Ci.nsIWebHandlerApp);
handlerApp.uriTemplate = handlerObj.uriTemplate;
} else if ("service" in handlerObj) {
handlerApp = Cc["@mozilla.org/uriloader/dbus-handler-app;1"].
createInstance(Ci.nsIDBusHandlerApp);
handlerApp.service = handlerObj.service;
handlerApp.method = handlerObj.method;
handlerApp.objectPath = handlerObj.objectPath;
handlerApp.dBusInterface = handlerObj.dBusInterface;
} else {
return null;
}
handlerApp.name = handlerObj.name;
return handlerApp;
},
/**
* The function return a reference to the "mimetypes" or "schemes" object
* based on which type of handlerInfo is provided.
*/
_getHandlerListByHandlerInfoType(handlerInfo) {
if (handlerInfo instanceof Ci.nsIMIMEInfo) {
return this._store.data.mimetypes;
}
return this._store.data.schemes;
},
// nsIHandlerService
exists(handlerInfo) {
return handlerInfo.type in this._getHandlerListByHandlerInfoType(handlerInfo);
},
// nsIHandlerService
remove(handlerInfo) {
delete this._getHandlerListByHandlerInfoType(handlerInfo)[handlerInfo.type];
this._store.saveSoon();
},
// nsIHandlerService
getTypeFromExtension(fileExtension) {
let extension = fileExtension.toLowerCase();
let mimeTypes = this._store.data.mimetypes;
for (let type of Object.keys(mimeTypes)) {
if (mimeTypes[type].fileExtensions &&
mimeTypes[type].fileExtensions.includes(extension)) {
return type;
}
}
return "";
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HandlerService]);

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

@ -0,0 +1,2 @@
component {220cc253-b60f-41f6-b9cf-fdcb325f970f} nsHandlerService-json.js
contract @mozilla.org/uriloader/handler-service-json;1 {220cc253-b60f-41f6-b9cf-fdcb325f970f} process=main

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

@ -118,9 +118,9 @@ HandlerService.prototype = {
// Observe profile-do-change so that non-default profiles get upgraded too
this._observerSvc.addObserver(this, "profile-do-change", false);
// do any necessary updating of the datastore
this._updateDB();
// Observe handlersvc-rdf-replace so we can switch to the datasource
this._observerSvc.addObserver(this, "handlersvc-rdf-replace", false);
},
_updateDB: function HS__updateDB() {
@ -160,6 +160,7 @@ HandlerService.prototype = {
this._observerSvc.removeObserver(this, "profile-before-change");
this._observerSvc.removeObserver(this, "xpcom-shutdown");
this._observerSvc.removeObserver(this, "profile-do-change");
this._observerSvc.removeObserver(this, "handlersvc-rdf-replace");
// XXX Should we also null references to all the services that get stored
// by our memoizing getters in the Convenience Getters section?
@ -289,7 +290,14 @@ HandlerService.prototype = {
break;
case "profile-do-change":
this._updateDB();
break;
break;
case "handlersvc-rdf-replace":
if (this.__ds) {
this._rdf.UnregisterDataSource(this.__ds);
this.__ds = null;
}
this._observerSvc.notifyObservers(null, "handlersvc-rdf-replace-complete", null);
break;
}
},
@ -313,7 +321,8 @@ HandlerService.prototype = {
// in the datastore by looking for its "value" property, which stores its
// type and should always be present.
if (!this._hasValue(typeID, NC_VALUE))
throw Cr.NS_ERROR_NOT_AVAILABLE;
throw new Components.Exception("handlerSvc fillHandlerInfo: don't know this type",
Cr.NS_ERROR_NOT_AVAILABLE);
// Retrieve the human-readable description of the type.
if (this._hasValue(typeID, NC_DESCRIPTION))
@ -688,6 +697,17 @@ HandlerService.prototype = {
}
},
_handlerAppIsUnknownType: function HS__handlerAppIsUnknownType(aHandlerApp) {
if (aHandlerApp instanceof Ci.nsILocalHandlerApp ||
aHandlerApp instanceof Ci.nsIWebHandlerApp ||
aHandlerApp instanceof Ci.nsIDBusHandlerApp) {
return false;
} else {
return true;
}
},
_storePreferredHandler: function HS__storePreferredHandler(aHandlerInfo) {
var infoID = this._getInfoID(this._getClass(aHandlerInfo), aHandlerInfo.type);
var handlerID =
@ -696,6 +716,11 @@ HandlerService.prototype = {
var handler = aHandlerInfo.preferredApplicationHandler;
if (handler) {
// If the handlerApp is an unknown type, ignore it.
// Android default application handler is the case.
if (this._handlerAppIsUnknownType(handler)) {
return;
}
this._storeHandlerApp(handlerID, handler);
// Make this app be the preferred app for the handler info.
@ -744,6 +769,11 @@ HandlerService.prototype = {
while (newHandlerApps.hasMoreElements()) {
let handlerApp =
newHandlerApps.getNext().QueryInterface(Ci.nsIHandlerApp);
// If the handlerApp is an unknown type, ignore it.
// Android default application handler is the case.
if (this._handlerAppIsUnknownType(handlerApp)) {
continue;
}
let handlerAppID = this._getPossibleHandlerAppID(handlerApp);
if (!this._hasResourceAssertion(infoID, NC_POSSIBLE_APP, handlerAppID)) {
this._storeHandlerApp(handlerAppID, handlerApp);
@ -912,6 +942,8 @@ HandlerService.prototype = {
QueryInterface(Ci.nsIFileProtocolHandler);
this.__ds =
this._rdf.GetDataSourceBlocking(fileHandler.getURLSpecFromFile(file));
// do any necessary updating of the datastore
this._updateDB();
}
return this.__ds;

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

@ -0,0 +1,488 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This script is loaded by "test_handlerService_json.js" and "test_handlerService_rdf.js"
* to make sure there is the same behavior when using two different implementations
* of handlerService (JSON backend and RDF backend).
*/
"use strict"
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://testing-common/TestUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gMIMEService",
"@mozilla.org/mime;1",
"nsIMIMEService");
XPCOMUtils.defineLazyServiceGetter(this, "gExternalProtocolService",
"@mozilla.org/uriloader/external-protocol-service;1",
"nsIExternalProtocolService");
const pdfHandlerInfo = gMIMEService.getFromTypeAndExtension("application/pdf", null);
const gzipHandlerInfo = gMIMEService.getFromTypeAndExtension("application/x-gzip", null);
const ircHandlerInfo = gExternalProtocolService.getProtocolHandlerInfo("irc");
let executable = HandlerServiceTest._dirSvc.get("TmpD", Ci.nsIFile);
let localHandler = {
name: "Local Handler",
executable: executable,
interfaces: [Ci.nsIHandlerApp, Ci.nsILocalHandlerApp, Ci.nsISupports],
QueryInterface: function(iid) {
if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
throw Cr.NS_ERROR_NO_INTERFACE;
return this;
}
};
let webHandler = {
name: "Web Handler",
uriTemplate: "https://www.webhandler.com/?url=%s",
interfaces: [Ci.nsIHandlerApp, Ci.nsIWebHandlerApp, Ci.nsISupports],
QueryInterface: function(iid) {
if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
throw Cr.NS_ERROR_NO_INTERFACE;
return this;
}
};
let dBusHandler = {
name: "DBus Handler",
service: "DBus Service",
method: "DBus method",
objectPath: "/tmp/PATH/DBus",
dBusInterface: "DBusInterface",
interfaces: [Ci.nsIHandlerApp, Ci.nsIDBusHandlerApp, Ci.nsISupports],
QueryInterface: function(iid) {
if (!this.interfaces.some( function(v) { return iid.equals(v) } ))
throw Cr.NS_ERROR_NO_INTERFACE;
return this;
}
};
function run_test() {
do_get_profile();
run_next_test();
}
/**
* Get a handler info for a MIME type that neither the application nor the OS
* knows about and make sure its properties are set to the proper default
* values.
*/
function getBlankHandlerInfo(type) {
let handlerInfo = gMIMEService.getFromTypeAndExtension(type, null);
do_check_true(handlerInfo.alwaysAskBeforeHandling);
if (handlerInfo.possibleApplicationHandlers.length) {
let apps = handlerInfo.possibleApplicationHandlers.enumerate();
let app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, "Android chooser");
} else {
do_check_eq(handlerInfo.preferredAction, Ci.nsIHandlerInfo.saveToDisk);
}
return handlerInfo;
}
/**
* Get a handler info for a protocol that neither the application nor the OS
* knows about and make sure its properties are set to the proper default
* values.
*/
function getBlankHandlerInfoForProtocol(type) {
let handlerInfo = gExternalProtocolService.getProtocolHandlerInfo(type);
do_check_true(handlerInfo.alwaysAskBeforeHandling);
if (handlerInfo.possibleApplicationHandlers.length) {
let apps = handlerInfo.possibleApplicationHandlers.enumerate();
let app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, "Android chooser");
} else {
do_check_eq(handlerInfo.preferredAction, Ci.nsIHandlerInfo.alwaysAsk);
}
return handlerInfo;
}
function getAllTypesByEnumerate() {
let handlerInfos = gHandlerService.enumerate();
let types = [];
while (handlerInfos.hasMoreElements()) {
let handlerInfo = handlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
types.push(handlerInfo.type);
}
return types.sort();
}
// Verify the load mechansim of hander service by
// - Start the hander service with DB
// - Do some modifications on DB first and reload it
add_task(function* testImportAndReload() {
// I. Prepare a testing ds first and do reload for handerService
yield prepareImportDB();
Assert.deepEqual(getAllTypesByEnumerate(), ["application/pdf", "irc", "ircs", "mailto", "webcal"]);
// II. do modifications first and reload the DS again
gHandlerService.store(gzipHandlerInfo);
gHandlerService.remove(pdfHandlerInfo);
yield reloadData();
Assert.deepEqual(getAllTypesByEnumerate(), ["application/x-gzip", "irc", "ircs", "mailto", "webcal"]);
});
// Verify reload without DB
add_task(function* testReloadWithoutDB() {
yield removeImportDB();
// If we have a defaultHandlersVersion pref, then assume that we're in the
// firefox tree and that we'll also have default handlers.
if (Services.prefs.getPrefType("gecko.handlerService.defaultHandlersVersion")){
Assert.deepEqual(getAllTypesByEnumerate(), ["irc", "ircs", "mailto", "webcal"]);
}
});
// Do the test for exist() with store() and remove()
add_task(function* testExists() {
yield prepareImportDB();
do_check_true(gHandlerService.exists(pdfHandlerInfo));
do_check_false(gHandlerService.exists(gzipHandlerInfo));
// Remove the handler of irc first
let handler = ircHandlerInfo;
gHandlerService.remove(handler);
do_check_false(gHandlerService.exists(handler));
gHandlerService.store(handler);
do_check_true(gHandlerService.exists(handler));
});
// Do the test for GetTypeFromExtension() with store(), remove() and exist()
add_task(function* testGetTypeFromExtension() {
yield prepareImportDB();
let type = gHandlerService.getTypeFromExtension("doc");
do_check_eq(type, "");
type = gHandlerService.getTypeFromExtension("pdf");
do_check_eq(type, "application/pdf");
gHandlerService.remove(pdfHandlerInfo);
do_check_false(gHandlerService.exists(pdfHandlerInfo));
type = gHandlerService.getTypeFromExtension("pdf");
do_check_eq(type, "");
gHandlerService.store(pdfHandlerInfo);
do_check_true(gHandlerService.exists(pdfHandlerInfo));
type = gHandlerService.getTypeFromExtension("pdf");
do_check_eq(type, "application/pdf");
});
// Test the functionality of fillHandlerInfo :
// - All the detail of handlerinfo are filled perferectly
// - The set of possible handlers included the preferred handler
add_task(function* testStoreAndFillHandlerInfo() {
yield removeImportDB();
// Get a handler info for a MIME type that neither the application nor
// the OS knows about and make sure its properties are set to the proper
// default values.
let handlerInfo = getBlankHandlerInfo("nonexistent/type");
let handlerInfo2 = getBlankHandlerInfo("nonexistent/type2");
handlerInfo2.preferredAction = Ci.nsIHandlerInfo.useSystemDefault;
handlerInfo2.preferredApplicationHandler = localHandler;
handlerInfo2.alwaysAskBeforeHandling = false;
handlerInfo2.appendExtension(".type2");
gHandlerService.store(handlerInfo2);
gHandlerService.fillHandlerInfo(handlerInfo, "nonexistent/type2");
do_check_eq(handlerInfo.preferredAction, Ci.nsIHandlerInfo.useSystemDefault);
if (Services.appinfo.widgetToolkit == "android") {
do_check_eq(handlerInfo.possibleApplicationHandlers.length, 2);
} else {
do_check_eq(handlerInfo.possibleApplicationHandlers.length, 1);
}
do_check_false(handlerInfo.alwaysAskBeforeHandling);
let extEnumerator = handlerInfo.getFileExtensions();
do_check_eq(extEnumerator.getNext(), ".type2");
do_check_false(extEnumerator.hasMore());
do_check_eq(handlerInfo.preferredApplicationHandler.name, "Local Handler");
let apps = handlerInfo.possibleApplicationHandlers.enumerate();
let app;
if (Services.appinfo.widgetToolkit == "android") {
app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, "Android chooser");
}
app = apps.getNext().QueryInterface(Ci.nsILocalHandlerApp);
do_check_eq(executable.path, app.executable.path);
do_check_eq(app.name, localHandler.name);
do_check_false(apps.hasMoreElements());
});
// Test the functionality of fillHandlerInfo :
// - Check the failure case by requesting a non-existent handler type
add_task(function* testFillHandlerInfoWithError() {
yield removeImportDB();
let handlerInfo = getBlankHandlerInfo("nonexistent/type");
Assert.throws(
() => gHandlerService.fillHandlerInfo(handlerInfo, "nonexistent/type2"),
ex => ex.result == Cr.NS_ERROR_NOT_AVAILABLE);
});
// Test the functionality of fillHandlerInfo :
// - Prefer handler is the first one of possibleHandlers and with only one instance
add_task(function* testPreferHandlerIsTheFirstOrder() {
yield removeImportDB();
let handlerInfo = getBlankHandlerInfo("nonexistent/type");
let handlerInfo2 = getBlankHandlerInfo("nonexistent/type2");
handlerInfo2.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
handlerInfo2.preferredApplicationHandler = webHandler;
handlerInfo2.possibleApplicationHandlers.appendElement(localHandler, false);
handlerInfo2.possibleApplicationHandlers.appendElement(webHandler, false);
handlerInfo2.alwaysAskBeforeHandling = false;
gHandlerService.store(handlerInfo2);
gHandlerService.fillHandlerInfo(handlerInfo, "nonexistent/type2");
let apps = handlerInfo.possibleApplicationHandlers.enumerate();
let app;
if (Services.appinfo.widgetToolkit == "android") {
app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, "Android chooser");
}
app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, webHandler.name);
app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, localHandler.name);
do_check_false(apps.hasMoreElements());
});
// Verify the handling of app handler: web handler
add_task(function* testStoreForWebHandler() {
yield removeImportDB();
let handlerInfo = getBlankHandlerInfo("nonexistent/type");
let handlerInfo2 = getBlankHandlerInfo("nonexistent/type2");
handlerInfo2.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
handlerInfo2.preferredApplicationHandler = webHandler;
handlerInfo2.alwaysAskBeforeHandling = false;
gHandlerService.store(handlerInfo2);
gHandlerService.fillHandlerInfo(handlerInfo, "nonexistent/type2");
let apps = handlerInfo.possibleApplicationHandlers.enumerate();
let app;
if (Services.appinfo.widgetToolkit == "android") {
app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, "Android chooser");
}
app = apps.getNext().QueryInterface(Ci.nsIWebHandlerApp);
do_check_eq(app.name, webHandler.name);
do_check_eq(app.uriTemplate, webHandler.uriTemplate);
});
// Verify the handling of app handler: DBus handler
add_task(function* testStoreForDBusHandler() {
if (!("@mozilla.org/uriloader/dbus-handler-app;1" in Cc)) {
do_print("Skipping test because it does not apply to this platform.");
return;
}
yield removeImportDB();
let handlerInfo = getBlankHandlerInfo("nonexistent/type");
let handlerInfo2 = getBlankHandlerInfo("nonexistent/type2");
handlerInfo2.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
handlerInfo2.preferredApplicationHandler = dBusHandler;
handlerInfo2.alwaysAskBeforeHandling = false;
gHandlerService.store(handlerInfo2);
gHandlerService.fillHandlerInfo(handlerInfo, "nonexistent/type2");
let app = handlerInfo.preferredApplicationHandler.QueryInterface(Ci.nsIDBusHandlerApp);
do_check_eq(app.name, dBusHandler.name);
do_check_eq(app.service, dBusHandler.service);
do_check_eq(app.method, dBusHandler.method);
do_check_eq(app.objectPath, dBusHandler.objectPath);
do_check_eq(app.dBusInterface, dBusHandler.dBusInterface);
});
// Test the functionality of _IsInHandlerArray() by injecting default handler again
// Since we don't have defaultHandlersVersion pref on Android, skip this test.
add_task(function* testIsInHandlerArray() {
if (Services.appinfo.widgetToolkit == "android") {
do_print("Skipping test because it does not apply to this platform.");
return;
}
yield removeImportDB();
let protoInfo = getBlankHandlerInfoForProtocol("nonexistent");
do_check_eq(protoInfo.possibleApplicationHandlers.length, 0);
gHandlerService.fillHandlerInfo(protoInfo, "ircs");
do_check_eq(protoInfo.possibleApplicationHandlers.length, 1);
// Remove the handler of irc first
let osDefaultHandlerFound = {};
let ircInfo = gExternalProtocolService.getProtocolHandlerInfoFromOS("irc",
osDefaultHandlerFound);
gHandlerService.remove(ircInfo);
do_check_false(gHandlerService.exists(ircInfo));
let origPrefs = Services.prefs.getComplexValue(
"gecko.handlerService.defaultHandlersVersion", Ci.nsIPrefLocalizedString);
// Set preference as an arbitrarily high number to force injecting
let string = Cc["@mozilla.org/pref-localizedstring;1"]
.createInstance(Ci.nsIPrefLocalizedString);
string.data = "999";
Services.prefs.setComplexValue("gecko.handlerService.defaultHandlersVersion",
Ci.nsIPrefLocalizedString, string);
// do reloading
yield reloadData();
// check "irc" exists again to make sure that injection actually happened
do_check_true(gHandlerService.exists(ircInfo));
// test "ircs" has only one handler to know the _IsInHandlerArray was invoked
protoInfo = getBlankHandlerInfoForProtocol("nonexistent");
do_check_false(gHandlerService.exists(protoInfo));
gHandlerService.fillHandlerInfo(protoInfo, "ircs");
do_check_eq(protoInfo.possibleApplicationHandlers.length, 1);
// reset the preference after the test
Services.prefs.setComplexValue("gecko.handlerService.defaultHandlersVersion",
Ci.nsIPrefLocalizedString, origPrefs);
});
// Test the basic functionality of FillHandlerInfo() for protocol
// Since Android use mimeInfo to deal with mimeTypes and protocol, skip this test.
add_task(function* testFillHandlerInfoForProtocol() {
if (Services.appinfo.widgetToolkit == "android") {
do_print("Skipping test because it does not apply to this platform.");
return;
}
yield removeImportDB();
let osDefaultHandlerFound = {};
let protoInfo = getBlankHandlerInfoForProtocol("nonexistent");
let ircInfo = gExternalProtocolService.getProtocolHandlerInfoFromOS("irc",
osDefaultHandlerFound);
do_check_true(gHandlerService.exists(ircInfo));
gHandlerService.fillHandlerInfo(protoInfo, "irc");
do_check_true(protoInfo.alwaysAskBeforeHandling);
let possibleHandlers = protoInfo.possibleApplicationHandlers;
do_check_eq(possibleHandlers.length, 1);
let app = possibleHandlers.enumerate().getNext().QueryInterface(Ci.nsIWebHandlerApp);
do_check_eq(app.name, "Mibbit");
do_check_eq(app.uriTemplate, "https://www.mibbit.com/?url=%s");
});
// Test the functionality of store() and fillHandlerInfo for protocol
add_task(function* testStoreForProtocol() {
yield removeImportDB();
let protoInfo = getBlankHandlerInfoForProtocol("nonexistent");
let protoInfo2 = getBlankHandlerInfoForProtocol("nonexistent2");
protoInfo2.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
protoInfo2.alwaysAskBeforeHandling = false;
protoInfo2.preferredApplicationHandler = webHandler;
gHandlerService.store(protoInfo2);
yield reloadData();
do_check_true(gHandlerService.exists(protoInfo2));
gHandlerService.fillHandlerInfo(protoInfo, "nonexistent2");
do_check_eq(protoInfo.preferredAction, Ci.nsIHandlerInfo.useHelperApp);
do_check_false(protoInfo.alwaysAskBeforeHandling);
do_check_eq(protoInfo.preferredApplicationHandler.name, webHandler.name);
let apps = protoInfo.possibleApplicationHandlers.enumerate();
let app;
if (Services.appinfo.widgetToolkit == "android") {
app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, "Android chooser");
}
app = apps.getNext().QueryInterface(Ci.nsIWebHandlerApp);
do_check_eq(app.name, webHandler.name);
do_check_eq(app.uriTemplate, webHandler.uriTemplate);
});
// Test the functionality of fillHandlerInfo when there is no overrideType
add_task(function* testFillHandlerInfoWithoutOverrideType() {
yield removeImportDB();
// mimeType
let mimeInfo = getBlankHandlerInfo("nonexistent/type");
let storedHandlerInfo = getBlankHandlerInfo("nonexistent/type");
storedHandlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault;
storedHandlerInfo.preferredApplicationHandler = webHandler;
storedHandlerInfo.alwaysAskBeforeHandling = false;
gHandlerService.store(storedHandlerInfo);
// protocol type
let protoInfo = getBlankHandlerInfoForProtocol("nonexistent");
let storedProtoInfo = getBlankHandlerInfoForProtocol("nonexistent");
storedProtoInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
storedProtoInfo.alwaysAskBeforeHandling = false;
storedProtoInfo.preferredApplicationHandler = webHandler;
gHandlerService.store(storedProtoInfo);
// Get handlerInfo by fillHandlerInfo without overrideType
for (let handlerInfo of [mimeInfo, protoInfo]) {
let handlerInfo2 = storedProtoInfo;
if (handlerInfo.type == "nonexistent/type") {
handlerInfo2 = storedHandlerInfo;
}
gHandlerService.fillHandlerInfo(handlerInfo, null);
do_check_eq(handlerInfo.preferredAction, handlerInfo2.preferredAction);
do_check_eq(handlerInfo.alwaysAskBeforeHandling,
handlerInfo2.alwaysAskBeforeHandling);
do_check_eq(handlerInfo.preferredApplicationHandler.name,
handlerInfo2.preferredApplicationHandler.name);
let apps = handlerInfo.possibleApplicationHandlers.enumerate();
let app;
if (Services.appinfo.widgetToolkit == "android") {
app = apps.getNext().QueryInterface(Ci.nsIHandlerApp);
do_check_eq(app.name, "Android chooser");
}
app = apps.getNext().QueryInterface(Ci.nsIWebHandlerApp);
do_check_eq(app.name, webHandler.name);
do_check_eq(app.uriTemplate, webHandler.uriTemplate);
}
});
// Test the functionality of fillHandlerInfo() :
// - Use "nsIHandlerInfo.useHelperApp" to replace "nsIHandlerInfo.alwaysAsk" for handlerInfo.preferredAction
// - Use "nsIHandlerInfo.useHelperApp" to replace unknow action for handlerInfo.preferredAction
add_task(function* testPreferredActionHandling() {
yield removeImportDB();
let protoInfo = getBlankHandlerInfoForProtocol("nonexistent");
let protoInfo2 = getBlankHandlerInfoForProtocol("nonexistent2");
for (let preferredAction of [
Ci.nsIHandlerInfo.saveToDisk,
Ci.nsIHandlerInfo.useHelperApp,
Ci.nsIHandlerInfo.handleInternally,
Ci.nsIHandlerInfo.useSystemDefault
]) {
protoInfo2.preferredAction = preferredAction;
gHandlerService.store(protoInfo2);
gHandlerService.fillHandlerInfo(protoInfo, "nonexistent2");
do_check_eq(protoInfo.preferredAction, preferredAction);
}
for (let preferredAction of [
Ci.nsIHandlerInfo.alwaysAsk,
999
]) {
protoInfo2.preferredAction = preferredAction;
gHandlerService.store(protoInfo2);
gHandlerService.fillHandlerInfo(protoInfo, "nonexistent2");
do_check_eq(protoInfo.preferredAction, Ci.nsIHandlerInfo.useHelperApp);
}
});

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

@ -0,0 +1 @@
{"version":{"en-US":999},"mimetypes":{"application/pdf":{"description":"PDF document","action":3,"askBeforeHandling":false,"fileExtensions":["pdf"]}},"schemes":{"webcal":{"action":1,"askBeforeHandling":true,"preferredHandler":{"name":"30 Boxes","uriTemplate":"http://30boxes.com/external/widget?refer=ff&amp;url=%s"},"possibleHandlers":[{"name":"30 Boxes","uriTemplate":"https://30boxes.com/external/widget?refer=ff&url=%s"}]},"ircs":{"action":1,"askBeforeHandling":true,"fileExtensions":[],"possibleHandlers":[{"name":"Mibbit","uriTemplate":"https://www.mibbit.com/?url=%s"}]},"mailto":{"action":4,"askBeforeHandling":false,"possibleHandlers":[{"name":"Yahoo! Mail","uriTemplate":"https://compose.mail.yahoo.com/?To=%s"},{"name":"Gmail","uriTemplate":"https://mail.google.com/mail/?extsrc=mailto&url=%s"}]},"irc":{"action":1,"askBeforeHandling":true,"possibleHandlers":[{"name":"Mibbit","uriTemplate":"https://www.mibbit.com/?url=%s"}]}}}

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

@ -52,6 +52,7 @@ var HandlerServiceTest = {
try {
this._dirSvc.get("UMimTyp", Ci.nsIFile);
} catch (ex) {
do_get_profile();
this._dirSvc.registerProvider(this);
this._providerRegistered = true;
}
@ -86,7 +87,7 @@ var HandlerServiceTest = {
persistent.value = true;
if (property == "UMimTyp") {
var datasourceFile = this._dirSvc.get("CurProcD", Ci.nsIFile);
var datasourceFile = this._dirSvc.get("ProfD", Ci.nsIFile);
datasourceFile.append("mimeTypes.rdf");
return datasourceFile;
}

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

@ -0,0 +1,79 @@
<?xml version="1.0"?>
<RDF:RDF xmlns:NC="http://home.netscape.com/NC-rdf#"
xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<RDF:Description RDF:about="urn:handler:web:https://compose.mail.yahoo.com/?To=%s"
NC:prettyName="Yahoo! Mail"
NC:uriTemplate="https://compose.mail.yahoo.com/?To=%s" />
<RDF:Description RDF:about="urn:mimetype:application/pdf"
NC:value="application/pdf"
NC:fileExtensions="pdf">
<NC:handlerProp RDF:resource="urn:mimetype:handler:application/pdf"/>
</RDF:Description>
<RDF:Description RDF:about="urn:scheme:handler:mailto"
NC:useSystemDefault="true"
NC:alwaysAsk="false">
<NC:possibleApplication RDF:resource="urn:handler:web:https://compose.mail.yahoo.com/?To=%s"/>
<NC:possibleApplication RDF:resource="urn:handler:web:https://mail.google.com/mail/?extsrc=mailto&amp;url=%s"/>
</RDF:Description>
<RDF:Description RDF:about="urn:root"
NC:en-US_defaultHandlersVersion="999" />
<RDF:Description RDF:about="urn:scheme:irc"
NC:value="irc">
<NC:handlerProp RDF:resource="urn:scheme:handler:irc"/>
</RDF:Description>
<RDF:Description RDF:about="urn:scheme:mailto"
NC:value="mailto">
<NC:handlerProp RDF:resource="urn:scheme:handler:mailto"/>
</RDF:Description>
<RDF:Seq RDF:about="urn:schemes:root">
<RDF:li RDF:resource="urn:scheme:webcal"/>
<RDF:li RDF:resource="urn:scheme:ircs"/>
<RDF:li RDF:resource="urn:scheme:mailto"/>
<RDF:li RDF:resource="urn:scheme:irc"/>
</RDF:Seq>
<RDF:Description RDF:about="urn:scheme:webcal"
NC:value="webcal">
<NC:handlerProp RDF:resource="urn:scheme:handler:webcal"/>
</RDF:Description>
<RDF:Seq RDF:about="urn:mimetypes:root">
<RDF:li RDF:resource="urn:mimetype:application/pdf"/>
</RDF:Seq>
<RDF:Description RDF:about="urn:handler:web:https://30boxes.com/external/widget?refer=ff&amp;url=%s"
NC:prettyName="30 Boxes"
NC:uriTemplate="https://30boxes.com/external/widget?refer=ff&amp;url=%s" />
<RDF:Description RDF:about="urn:schemes">
<NC:Protocol-Schemes RDF:resource="urn:schemes:root"/>
</RDF:Description>
<RDF:Description RDF:about="urn:handler:web:https://www.mibbit.com/?url=%s"
NC:prettyName="Mibbit"
NC:uriTemplate="https://www.mibbit.com/?url=%s" />
<RDF:Description RDF:about="urn:scheme:handler:webcal"
NC:alwaysAsk="true">
<NC:possibleApplication RDF:resource="urn:handler:web:https://30boxes.com/external/widget?refer=ff&amp;url=%s"/>
<NC:externalApplication RDF:resource="urn:scheme:externalApplication:webcal"/>
</RDF:Description>
<RDF:Description RDF:about="urn:scheme:handler:irc"
NC:alwaysAsk="true">
<NC:possibleApplication RDF:resource="urn:handler:web:https://www.mibbit.com/?url=%s"/>
</RDF:Description>
<RDF:Description RDF:about="urn:handler:web:https://mail.google.com/mail/?extsrc=mailto&amp;url=%s"
NC:prettyName="Gmail"
NC:uriTemplate="https://mail.google.com/mail/?extsrc=mailto&amp;url=%s" />
<RDF:Description RDF:about="urn:mimetype:handler:application/pdf"
NC:handleInternal="true"
NC:alwaysAsk="false" />
<RDF:Description RDF:about="urn:mimetypes">
<NC:MIME-types RDF:resource="urn:mimetypes:root"/>
</RDF:Description>
<RDF:Description RDF:about="urn:scheme:externalApplication:webcal"
NC:prettyName="30 Boxes"
NC:uriTemplate="http://30boxes.com/external/widget?refer=ff&amp;url=%s"/>
<RDF:Description RDF:about="urn:scheme:ircs"
NC:value="ircs">
<NC:handlerProp RDF:resource="urn:scheme:handler:ircs"/>
</RDF:Description>
<RDF:Description RDF:about="urn:scheme:handler:ircs"
NC:alwaysAsk="true">
<NC:possibleApplication RDF:resource="urn:handler:web:https://www.mibbit.com/?url=%s"/>
</RDF:Description>
</RDF:RDF>

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

@ -0,0 +1,46 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests the handlerService interfaces using JSON backend.
*/
"use strict"
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gHandlerService",
"@mozilla.org/uriloader/handler-service-json;1",
"nsIHandlerService");
var scriptFile = do_get_file("common_test_handlerService.js");
Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
var prepareImportDB = Task.async(function* () {
yield reloadData();
let dst = OS.Path.join(OS.Constants.Path.profileDir, "handlers.json");
yield OS.File.copy(do_get_file("handlers.json").path, dst);
Assert.ok((yield OS.File.exists(dst)), "should have a DB now");
});
var removeImportDB = Task.async(function* () {
yield reloadData();
let dst = OS.Path.join(OS.Constants.Path.profileDir, "handlers.json");
yield OS.File.remove(dst);
Assert.ok(!(yield OS.File.exists(dst)), "should not have a DB now");
});
var reloadData = Task.async(function* () {
// Force the initialization of handlerService to prevent observer is not initialized yet.
let svc = gHandlerService;
let promise = TestUtils.topicObserved("handlersvc-json-replace-complete");
Services.obs.notifyObservers(null, "handlersvc-json-replace", null);
yield promise;
});

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

@ -0,0 +1,44 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests the handlerService interfaces using RDF backend.
*/
"use strict"
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gHandlerService",
"@mozilla.org/uriloader/handler-service;1",
"nsIHandlerService");
var scriptFile = do_get_file("common_test_handlerService.js");
Services.scriptloader.loadSubScript(NetUtil.newURI(scriptFile).spec);
var prepareImportDB = Task.async(function* () {
yield reloadData();
let dst = HandlerServiceTest._dirSvc.get("UMimTyp", Ci.nsIFile);
yield OS.File.copy(do_get_file("mimeTypes.rdf").path, dst.path);
Assert.ok((yield OS.File.exists(dst.path)), "should have a DB now");
});
var removeImportDB = Task.async(function* () {
yield reloadData();
HandlerServiceTest._deleteDatasourceFile();
let dst = HandlerServiceTest._dirSvc.get("UMimTyp", Ci.nsIFile);
Assert.ok(!(yield OS.File.exists(dst.path)), "should not have a DB now");
});
var reloadData = Task.async(function* () {
// Force the initialization of handlerService to prevent observer is not initialized yet.
let svc = gHandlerService;
let promise = TestUtils.topicObserved("handlersvc-rdf-replace-complete");
Services.obs.notifyObservers(null, "handlersvc-rdf-replace", null);
yield promise;
});

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

@ -1,6 +1,8 @@
[DEFAULT]
head = head_handlerService.js
run-sequentially = Bug 912235 - Intermittent failures
firefox-appdir = browser
support-files = common_test_handlerService.js
[test_getTypeFromExtension_ext_to_type_mapping.js]
[test_getTypeFromExtension_with_empty_Content_Type.js]
@ -9,6 +11,10 @@ run-sequentially = Bug 912235 - Intermittent failures
support-files = mailcap
# Bug 676997: test consistently fails on Android
fail-if = os == "android"
[test_handlerService_json.js]
support-files = handlers.json
[test_handlerService_rdf.js]
support-files = mimeTypes.rdf
[test_punycodeURIs.js]
# Bug 676997: test consistently fails on Android
fail-if = os == "android"

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

@ -129,6 +129,7 @@ EXPORTS.mozilla.widget += [
'CompositorWidget.h',
'IMEData.h',
'InProcessCompositorWidget.h',
'nsAutoRollup.h',
'PuppetBidiKeyboard.h',
'WidgetMessageUtils.h',
'WindowSurface.h'
@ -143,6 +144,7 @@ UNIFIED_SOURCES += [
'GfxInfoWebGL.cpp',
'InProcessCompositorWidget.cpp',
'InputData.cpp',
'nsAutoRollup.cpp',
'nsBaseAppShell.cpp',
'nsBaseScreen.cpp',
'nsClipboardHelper.cpp',

55
widget/nsAutoRollup.cpp Normal file
Просмотреть файл

@ -0,0 +1,55 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/widget/nsAutoRollup.h"
namespace mozilla {
namespace widget {
/*static*/ uint32_t nsAutoRollup::sCount = 0;
/*static*/ StaticRefPtr<nsIContent> nsAutoRollup::sLastRollup;
nsAutoRollup::nsAutoRollup()
{
// remember if sLastRollup was null, and only clear it upon destruction
// if so. This prevents recursive usage of nsAutoRollup from clearing
// sLastRollup when it shouldn't.
mWasClear = !sLastRollup;
sCount++;
}
nsAutoRollup::nsAutoRollup(nsIContent* aRollup)
{
MOZ_ASSERT(!sLastRollup);
mWasClear = true;
sCount++;
SetLastRollup(aRollup);
}
nsAutoRollup::~nsAutoRollup()
{
if (sLastRollup && mWasClear) {
sLastRollup = nullptr;
}
sCount--;
}
/*static*/ void
nsAutoRollup::SetLastRollup(nsIContent* aLastRollup)
{
// There must be at least one nsAutoRollup on the stack.
MOZ_ASSERT(sCount);
sLastRollup = aLastRollup;
}
/*static*/ nsIContent*
nsAutoRollup::GetLastRollup()
{
return sLastRollup.get();
}
} // namespace widget
} // namespace mozilla

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