зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
7a55af51fb
|
@ -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/cert8.db
Двоичный файл не отображается.
Двоичные данные
build/pgo/certs/key3.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­b</div>
|
||||
|
||||
<div id="hyphen2" style="width:100px">c­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&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&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&url=%s"
|
||||
NC:prettyName="30 Boxes"
|
||||
NC:uriTemplate="https://30boxes.com/external/widget?refer=ff&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&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&url=%s"
|
||||
NC:prettyName="Gmail"
|
||||
NC:uriTemplate="https://mail.google.com/mail/?extsrc=mailto&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&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',
|
||||
|
|
|
@ -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
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче