merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2015-02-24 12:54:34 +01:00
Родитель 490a9c6e61 052ba27385
Коммит 6eece0b459
103 изменённых файлов: 1931 добавлений и 2245 удалений

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

@ -67,6 +67,7 @@ included_inclnames_to_ignore = set([
'js-config.h', # generated in $OBJDIR
'pratom.h', # NSPR
'prcvar.h', # NSPR
'prerror.h', # NSPR
'prinit.h', # NSPR
'prlink.h', # NSPR
'prlock.h', # NSPR

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

@ -9130,6 +9130,9 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
# Force disable DSS support in jemalloc.
ac_configure_args="$ac_configure_args ac_cv_func_sbrk=false"
# Make Linux builds munmap freed chunks instead of recycling them.
ac_configure_args="$ac_configure_args --enable-munmap"
if ! test -e memory/jemalloc; then
mkdir -p memory/jemalloc
fi

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

@ -31,7 +31,7 @@ public:
// As required
nsIGlobalObject* GetParentObject() const;
virtual JSObject* WrapObject(JSContext* aCx);
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// setter and getter
void Register(RTCIdentityProvider& aIdp);

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

@ -110,8 +110,8 @@ MediaSourceReader::RequestAudioData()
{
nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__);
MSE_DEBUGV("");
if (!GetAudioReader()) {
MSE_DEBUG("called with no audio reader");
if (!mAudioTrack) {
MSE_DEBUG("called with no audio track");
mAudioPromise.Reject(DECODE_ERROR, __func__);
return p;
}
@ -130,12 +130,13 @@ MediaSourceReader::RequestAudioData()
&MediaSourceReader::CompleteAudioSeekAndDoRequest,
&MediaSourceReader::CompleteAudioSeekAndRejectPromise));
break;
case SOURCE_ERROR:
case SOURCE_NONE:
if (mLastAudioTime) {
CheckForWaitOrEndOfStream(MediaData::AUDIO_DATA, mLastAudioTime);
break;
}
// Fallback to using current reader
// Fallback to using first reader
mAudioSourceDecoder = mAudioTrack->Decoders()[0];
default:
DoAudioRequest();
break;
@ -253,8 +254,8 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
nsRefPtr<VideoDataPromise> p = mVideoPromise.Ensure(__func__);
MSE_DEBUGV("RequestVideoData(%d, %lld)",
aSkipToNextKeyframe, aTimeThreshold);
if (!GetVideoReader()) {
MSE_DEBUG("called with no video reader");
if (!mVideoTrack) {
MSE_DEBUG("called with no video track");
mVideoPromise.Reject(DECODE_ERROR, __func__);
return p;
}
@ -278,12 +279,13 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres
&MediaSourceReader::CompleteVideoSeekAndDoRequest,
&MediaSourceReader::CompleteVideoSeekAndRejectPromise));
break;
case SOURCE_ERROR:
case SOURCE_NONE:
if (mLastVideoTime) {
CheckForWaitOrEndOfStream(MediaData::VIDEO_DATA, mLastVideoTime);
break;
}
// Fallback to using current reader.
// Fallback to using first reader.
mVideoSourceDecoder = mVideoTrack->Decoders()[0];
default:
DoVideoRequest();
break;
@ -482,7 +484,7 @@ MediaSourceReader::SwitchAudioSource(int64_t* aTarget)
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
// XXX: Can't handle adding an audio track after ReadMetadata.
if (!mAudioTrack) {
return SOURCE_ERROR;
return SOURCE_NONE;
}
// We first search without the tolerance and then search with it, so that, in
@ -495,8 +497,16 @@ MediaSourceReader::SwitchAudioSource(int64_t* aTarget)
newDecoder = SelectDecoder(*aTarget, EOS_FUZZ_US, mAudioTrack->Decoders());
usedFuzz = true;
}
if (newDecoder && newDecoder != mAudioSourceDecoder) {
if (GetAudioReader() && mAudioSourceDecoder != newDecoder) {
GetAudioReader()->SetIdle();
}
if (!newDecoder) {
mAudioSourceDecoder = nullptr;
return SOURCE_NONE;
}
if (newDecoder == mAudioSourceDecoder) {
return SOURCE_EXISTING;
}
mAudioSourceDecoder = newDecoder;
if (usedFuzz) {
// A decoder buffered range is continuous. We would have failed the exact
@ -513,8 +523,6 @@ MediaSourceReader::SwitchAudioSource(int64_t* aTarget)
mAudioSourceDecoder.get(), usedFuzz);
return SOURCE_NEW;
}
return newDecoder ? SOURCE_EXISTING : SOURCE_ERROR;
}
MediaSourceReader::SwitchSourceResult
MediaSourceReader::SwitchVideoSource(int64_t* aTarget)
@ -522,7 +530,7 @@ MediaSourceReader::SwitchVideoSource(int64_t* aTarget)
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
// XXX: Can't handle adding a video track after ReadMetadata.
if (!mVideoTrack) {
return SOURCE_ERROR;
return SOURCE_NONE;
}
// We first search without the tolerance and then search with it, so that, in
@ -535,8 +543,16 @@ MediaSourceReader::SwitchVideoSource(int64_t* aTarget)
newDecoder = SelectDecoder(*aTarget, EOS_FUZZ_US, mVideoTrack->Decoders());
usedFuzz = true;
}
if (newDecoder && newDecoder != mVideoSourceDecoder) {
if (GetVideoReader() && mVideoSourceDecoder != newDecoder) {
GetVideoReader()->SetIdle();
}
if (!newDecoder) {
mVideoSourceDecoder = nullptr;
return SOURCE_NONE;
}
if (newDecoder == mVideoSourceDecoder) {
return SOURCE_EXISTING;
}
mVideoSourceDecoder = newDecoder;
if (usedFuzz) {
// A decoder buffered range is continuous. We would have failed the exact
@ -553,8 +569,6 @@ MediaSourceReader::SwitchVideoSource(int64_t* aTarget)
mVideoSourceDecoder.get(), usedFuzz);
return SOURCE_NEW;
}
return newDecoder ? SOURCE_EXISTING : SOURCE_ERROR;
}
bool
MediaSourceReader::IsDormantNeeded()
@ -796,7 +810,12 @@ MediaSourceReader::OnVideoSeekFailed(nsresult aResult)
void
MediaSourceReader::DoAudioSeek()
{
SwitchAudioSource(&mPendingSeekTime);
if (SwitchAudioSource(&mPendingSeekTime) == SOURCE_NONE) {
// Data we need got evicted since the last time we checked for data
// availability. Abort current seek attempt.
mWaitingForSeekData = true;
return;
}
mAudioSeekRequest.Begin(GetAudioReader()->Seek(GetReaderAudioTime(mPendingSeekTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::OnAudioSeekCompleted,
@ -829,7 +848,12 @@ MediaSourceReader::AttemptSeek()
// Seek methods since it can deadlock.
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (!mWaitingForSeekData || !TrackBuffersContainTime(mPendingSeekTime)) {
if (!mWaitingForSeekData) {
return;
}
if (!TrackBuffersContainTime(mPendingSeekTime)) {
mVideoSourceDecoder = nullptr;
mAudioSourceDecoder = nullptr;
return;
}
mWaitingForSeekData = false;
@ -856,7 +880,12 @@ MediaSourceReader::AttemptSeek()
void
MediaSourceReader::DoVideoSeek()
{
SwitchVideoSource(&mPendingSeekTime);
if (SwitchVideoSource(&mPendingSeekTime) == SOURCE_NONE) {
// Data we need got evicted since the last time we checked for data
// availability. Abort current seek attempt.
mWaitingForSeekData = true;
return;
}
mVideoSeekRequest.Begin(GetVideoReader()->Seek(GetReaderVideoTime(mPendingSeekTime), 0)
->RefableThen(GetTaskQueue(), __func__, this,
&MediaSourceReader::OnVideoSeekCompleted,
@ -1085,7 +1114,7 @@ bool
MediaSourceReader::IsActiveReader(MediaDecoderReader* aReader)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
return aReader == GetVideoReader() || aReader == GetAudioReader();
return aReader && (aReader == GetVideoReader() || aReader == GetAudioReader());
}
MediaDecoderReader*

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

@ -160,7 +160,7 @@ private:
// Search can be made using a fuzz factor. Should an approximated value be
// found instead, aTarget will be updated to the actual target found.
enum SwitchSourceResult {
SOURCE_ERROR = -1,
SOURCE_NONE = -1,
SOURCE_EXISTING = 0,
SOURCE_NEW = 1,
};

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

@ -323,7 +323,7 @@ TrackBuffer::EvictData(double aPlaybackTime,
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
decoders[i]->GetBuffered(buffered);
MSE_DEBUG("decoder=%u/%u threshold=%u toEvict=%lld",
MSE_DEBUG("Step1. decoder=%u/%u threshold=%u toEvict=%lld",
i, decoders.Length(), aThreshold, toEvict);
// To ensure we don't evict data past the current playback position
@ -331,6 +331,17 @@ TrackBuffer::EvictData(double aPlaybackTime,
// that point.
if (aPlaybackTime > MSE_EVICT_THRESHOLD_TIME) {
double time = aPlaybackTime - MSE_EVICT_THRESHOLD_TIME;
bool isActive = decoders[i] == mCurrentDecoder ||
mParentDecoder->IsActiveReader(decoders[i]->GetReader());
if (!isActive && buffered->GetEndTime() < time) {
// The entire decoder is contained before our current playback time.
// It can be fully evicted.
MSE_DEBUG("evicting all bufferedEnd=%f "
"aPlaybackTime=%f time=%f, size=%lld",
buffered->GetEndTime(), aPlaybackTime, time,
decoders[i]->GetResource()->GetSize());
toEvict -= decoders[i]->GetResource()->EvictAll();
} else {
int64_t playbackOffset = decoders[i]->ConvertToByteOffset(time);
MSE_DEBUG("evicting some bufferedEnd=%f "
"aPlaybackTime=%f time=%f, playbackOffset=%lld size=%lld",
@ -342,9 +353,12 @@ TrackBuffer::EvictData(double aPlaybackTime,
}
}
}
}
// Evict all data from decoders we've likely already read from.
for (uint32_t i = 0; i < decoders.Length() && toEvict > 0; ++i) {
MSE_DEBUG("Step2. decoder=%u/%u threshold=%u toEvict=%lld",
i, decoders.Length(), aThreshold, toEvict);
if (mParentDecoder->IsActiveReader(decoders[i]->GetReader())) {
break;
}
@ -393,6 +407,8 @@ TrackBuffer::EvictData(double aPlaybackTime,
decoders.Sort(DecoderSorter());
for (int32_t i = int32_t(decoders.Length()) - 1; i >= 0 && toEvict > 0; --i) {
MSE_DEBUG("Step3. decoder=%u/%u threshold=%u toEvict=%lld",
i, decoders.Length(), aThreshold, toEvict);
if (decoders[i] == playingDecoder || decoders[i] == nextPlayingDecoder ||
decoders[i] == mCurrentDecoder) {
continue;
@ -464,6 +480,9 @@ TrackBuffer::HasOnlyIncompleteMedia()
}
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
mCurrentDecoder->GetBuffered(buffered);
MSE_DEBUG("mCurrentDecoder.size=%lld, start=%f end=%f",
mCurrentDecoder->GetResource()->GetSize(),
buffered->GetStartTime(), buffered->GetEndTime());
return mCurrentDecoder->GetResource()->GetSize() && !buffered->Length();
}
@ -614,6 +633,10 @@ TrackBuffer::InitializeDecoder(SourceBufferDecoder* aDecoder)
MSE_DEBUG("was shut down while reading metadata. Aborting initialization.");
return;
}
if (mCurrentDecoder != aDecoder) {
MSE_DEBUG("append was cancelled. Aborting initialization.");
return;
}
if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) {
mWaitingDecoders.AppendElement(aDecoder);
@ -963,31 +986,52 @@ TrackBuffer::RangeRemoval(int64_t aStart, int64_t aEnd)
// Nothing to remove.
return false;
}
if (aEnd < bufferedEnd) {
// TODO. We only handle trimming.
if (aStart > bufferedStart && aEnd < bufferedEnd) {
// TODO. We only handle trimming and removal from the start.
NS_WARNING("RangeRemoval unsupported arguments. "
"Can only handle trimming");
"Can only handle trimming (trim left or trim right");
return false;
}
nsTArray<SourceBufferDecoder*> decoders;
decoders.AppendElements(mInitializedDecoders);
if (aStart <= bufferedStart && aEnd < bufferedEnd) {
// Evict data from beginning.
for (size_t i = 0; i < decoders.Length(); ++i) {
nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
decoders[i]->GetBuffered(buffered);
if (buffered->GetEndTime() < aEnd) {
// Can be fully removed.
MSE_DEBUG("remove all bufferedEnd=%f time=%f, size=%lld",
buffered->GetEndTime(), time,
decoders[i]->GetResource()->GetSize());
decoders[i]->GetResource()->EvictAll();
} else {
int64_t offset = decoders[i]->ConvertToByteOffset(aEnd);
MSE_DEBUG("removing some bufferedEnd=%f offset=%lld size=%lld",
buffered->GetEndTime(), offset,
decoders[i]->GetResource()->GetSize());
if (offset > 0) {
decoders[i]->GetResource()->EvictData(offset, offset);
}
}
}
} else {
// Only trimming existing buffers.
for (size_t i = 0; i < decoders.Length(); ++i) {
decoders[i]->Trim(aStart);
if (aStart <= buffered->GetStartTime()) {
// We've completely emptied it, can clear the data.
int64_t size = decoders[i]->GetResource()->GetSize();
decoders[i]->GetResource()->EvictData(size, size);
if (decoders[i] == mCurrentDecoder ||
mParentDecoder->IsActiveReader(decoders[i]->GetReader())) {
continue;
}
MSE_DEBUG("remove empty decoders=%d", i);
RemoveDecoder(decoders[i]);
// It will be entirely emptied, can clear all data.
decoders[i]->GetResource()->EvictAll();
} else {
decoders[i]->Trim(aStart);
}
}
}
RemoveEmptyDecoders(decoders);
return true;
}

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

@ -19,8 +19,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=519928
var iframe = document.getElementById("load-frame");
function enableJS() allowJS(true, iframe);
function disableJS() allowJS(false, iframe);
function enableJS() { allowJS(true, iframe); }
function disableJS() { allowJS(false, iframe); }
function allowJS(allow, frame) {
SpecialPowers.wrap(frame.contentWindow)
.QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor)
@ -28,6 +28,7 @@ function allowJS(allow, frame) {
.QueryInterface(SpecialPowers.Ci.nsIDocShell)
.allowJavascript = allow;
}
function expectJSAllowed(allowed, testCondition, callback) {
window.ICanRunMyJS = false;
var self_ = window;
@ -49,8 +50,8 @@ function expectJSAllowed(allowed, testCondition, callback) {
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var enterDesignMode = function() document.designMode = "on";
var leaveDesignMode = function() document.designMode = "off";
var enterDesignMode = function() { document.designMode = "on"; };
var leaveDesignMode = function() { document.designMode = "off"; };
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(true, enableJS, function() {
expectJSAllowed(true, enterDesignMode, function() {
@ -59,8 +60,8 @@ addLoadEvent(function() {
expectJSAllowed(false, enterDesignMode, function() {
expectJSAllowed(false, leaveDesignMode, function() {
expectJSAllowed(true, enableJS, function() {
enterDesignMode = function() iframe.contentDocument.designMode = "on";
leaveDesignMode = function() iframe.contentDocument.designMode = "off";
enterDesignMode = function() { iframe.contentDocument.designMode = "on"; };
leaveDesignMode = function() { iframe.contentDocument.designMode = "off"; };
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(true, enableJS, function() {
expectJSAllowed(true, enterDesignMode, function() {
@ -120,4 +121,3 @@ function testDocumentDisabledJS() {
</pre>
</body>
</html>

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

@ -45,7 +45,7 @@ function copyCF_HTML(cfhtml, success, failure) {
var flavors = [CF_HTML];
if (!cb.hasDataMatchingFlavors(flavors, flavors.length, cb.kGlobalClipboard)) {
setTimeout(function() copyCF_HTML_worker(success, failure), 100);
setTimeout(function() { copyCF_HTML_worker(success, failure); }, 100);
return;
}
@ -59,7 +59,7 @@ function copyCF_HTML(cfhtml, success, failure) {
trans.getTransferData(CF_HTML, data, {});
data = SpecialPowers.wrap(data).value.QueryInterface(Ci.nsISupportsCString).data;
} catch (e) {
setTimeout(function() copyCF_HTML_worker(success, failure), 100);
setTimeout(function() { copyCF_HTML_worker(success, failure); }, 100);
return;
}
success();

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

@ -119,175 +119,175 @@ var tests = [
isIFrame: true,
payload: dataPayload,
iframeCount: 0,
rootElement: function() document.getElementById("a").contentDocument.documentElement
rootElement() { return document.getElementById("a").contentDocument.documentElement; },
},
{
id: "b",
isIFrame: true,
payload: jsPayload,
iframeCount: 0,
rootElement: function() document.getElementById("b").contentDocument.documentElement
rootElement() { return document.getElementById("b").contentDocument.documentElement; },
},
{
id: "c",
isIFrame: true,
payload: httpPayload,
iframeCount: 0,
rootElement: function() document.getElementById("c").contentDocument.documentElement
rootElement() { return document.getElementById("c").contentDocument.documentElement; },
},
{
id: "g",
isIFrame: true,
payload: scriptPayload,
rootElement: function() document.getElementById("g").contentDocument.documentElement,
rootElement() { return document.getElementById("g").contentDocument.documentElement; },
iframeCount: 0
},
{
id: "h",
isIFrame: true,
payload: scriptExternalPayload,
rootElement: function() document.getElementById("h").contentDocument.documentElement,
rootElement() { return document.getElementById("h").contentDocument.documentElement; },
iframeCount: 0
},
{
id: "d",
payload: dataPayload,
iframeCount: 0,
rootElement: function() document.getElementById("d")
rootElement() { return document.getElementById("d"); },
},
{
id: "e",
payload: jsPayload,
iframeCount: 0,
rootElement: function() document.getElementById("e")
rootElement() { return document.getElementById("e"); },
},
{
id: "f",
payload: httpPayload,
iframeCount: 0,
rootElement: function() document.getElementById("f")
rootElement() { return document.getElementById("f"); },
},
{
id: "i",
payload: scriptPayload,
rootElement: function() document.getElementById("i"),
rootElement() { return document.getElementById("i"); },
iframeCount: 0
},
{
id: "j",
payload: scriptExternalPayload,
rootElement: function() document.getElementById("j"),
rootElement() { return document.getElementById("j"); },
iframeCount: 0
},
{
id: "k",
isIFrame: true,
payload: validStyle1Payload,
rootElement: function() document.getElementById("k").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("k").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "l",
payload: validStyle1Payload,
rootElement: function() document.getElementById("l"),
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("l"); },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "m",
isIFrame: true,
payload: validStyle2Payload,
rootElement: function() document.getElementById("m").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("m").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "n",
payload: validStyle2Payload,
rootElement: function() document.getElementById("n"),
checkResult: function(html) isnot(html.indexOf("style"), -1, "Should have retained style")
rootElement() { return document.getElementById("n"); },
checkResult(html) { isnot(html.indexOf("style"), -1, "Should have retained style"); },
},
{
id: "o",
isIFrame: true,
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("o").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("o").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "p",
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("p"),
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("p"); },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "q",
isIFrame: true,
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("q").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("q").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "r",
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("r"),
checkResult: function(html) is(html.indexOf("binding"), -1, "Should not have retained the binding style")
rootElement() { return document.getElementById("r"); },
checkResult(html) { is(html.indexOf("binding"), -1, "Should not have retained the binding style"); },
},
{
id: "s",
isIFrame: true,
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("s").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("s").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "t",
payload: invalidStyle1Payload,
rootElement: function() document.getElementById("t"),
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("t"); },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "u",
isIFrame: true,
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("u").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("u").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "v",
payload: invalidStyle2Payload,
rootElement: function() document.getElementById("v"),
checkResult: function(html) is(html.indexOf("xxx"), -1, "Should not have retained the import style")
rootElement() { return document.getElementById("v"); },
checkResult(html) { is(html.indexOf("xxx"), -1, "Should not have retained the import style"); },
},
{
id: "w",
isIFrame: true,
payload: validStyle3Payload,
rootElement: function() document.getElementById("w").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style")
rootElement() { return document.getElementById("w").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style"); },
},
{
id: "x",
payload: validStyle3Payload,
rootElement: function() document.getElementById("x"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style")
rootElement() { return document.getElementById("x"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the font-face style"); },
},
{
id: "y",
isIFrame: true,
payload: invalidStyle5Payload,
rootElement: function() document.getElementById("y").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style")
rootElement() { return document.getElementById("y").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style"); },
},
{
id: "z",
payload: invalidStyle5Payload,
rootElement: function() document.getElementById("z"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style")
rootElement() { return document.getElementById("z"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the font-face style"); },
},
{
id: "aa",
isIFrame: true,
payload: nestedStylePayload,
rootElement: function() document.getElementById("aa").contentDocument.documentElement,
rootElement() { return document.getElementById("aa").contentDocument.documentElement; },
checkResult: function(html, text) {
is(html.indexOf("binding-1"), -1, "Should not have retained the binding-1 style");
isnot(text.indexOf("#bar2"), -1, "Should have retained binding-2 as text content");
@ -297,7 +297,7 @@ var tests = [
{
id: "bb",
payload: nestedStylePayload,
rootElement: function() document.getElementById("bb"),
rootElement() { return document.getElementById("bb"); },
checkResult: function(html, text) {
is(html.indexOf("binding-1"), -1, "Should not have retained the binding-1 style");
isnot(text.indexOf("#bar2"), -1, "Should have retained binding-2 as text content");
@ -308,73 +308,73 @@ var tests = [
id: "cc",
isIFrame: true,
payload: validStyle4Payload,
rootElement: function() document.getElementById("cc").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style")
rootElement() { return document.getElementById("cc").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style"); },
},
{
id: "dd",
payload: validStyle4Payload,
rootElement: function() document.getElementById("dd"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style")
rootElement() { return document.getElementById("dd"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should have retained the namespace style"); },
},
{
id: "ee",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ee").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style")
rootElement() { return document.getElementById("ee").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style"); },
},
{
id: "ff",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ff"),
checkResult: function(html) isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style")
rootElement() { return document.getElementById("ff"); },
checkResult(html) { isnot(html.indexOf("xxx"), -1, "Should not have retained the namespace style"); },
},
{
id: "gg",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("gg").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("gg").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "hh",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("hh"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("hh"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "ii",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ii").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("ii").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "jj",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("jj"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("jj"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "kk",
isIFrame: true,
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("kk").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("kk").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "ll",
payload: invalidStyle6Payload,
rootElement: function() document.getElementById("ll"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image")
rootElement() { return document.getElementById("ll"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the src attribute for the image"); },
},
{
id: "mm",
isIFrame: true,
indirectPaste: true,
payload: invalidStyle7Payload,
rootElement: function() document.getElementById("mm").contentDocument.documentElement,
rootElement() { return document.getElementById("mm").contentDocument.documentElement; },
checkResult: function(html) {
is(html.indexOf("xxx"), -1, "Should not have retained the title text");
isnot(html.indexOf("foo"), -1, "Should have retained the body text");
@ -384,7 +384,7 @@ var tests = [
id: "nn",
indirectPaste: true,
payload: invalidStyle7Payload,
rootElement: function() document.getElementById("nn"),
rootElement() { return document.getElementById("nn"); },
checkResult: function(html) {
is(html.indexOf("xxx"), -1, "Should not have retained the title text");
isnot(html.indexOf("foo"), -1, "Should have retained the body text");
@ -394,143 +394,143 @@ var tests = [
id: "oo",
isIFrame: true,
payload: validDataFooPayload,
rootElement: function() document.getElementById("oo").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute")
rootElement() { return document.getElementById("oo").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute"); },
},
{
id: "pp",
payload: validDataFooPayload,
rootElement: function() document.getElementById("pp"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute")
rootElement() { return document.getElementById("pp"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the data-bar attribute"); },
},
{
id: "qq",
isIFrame: true,
payload: validDataFoo2Payload,
rootElement: function() document.getElementById("qq").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute")
rootElement() { return document.getElementById("qq").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute"); },
},
{
id: "rr",
payload: validDataFoo2Payload,
rootElement: function() document.getElementById("rr"),
checkResult: function(html) isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute")
rootElement() { return document.getElementById("rr"); },
checkResult(html) { isnot(html.indexOf("bar"), -1, "Should have retained the _bar attribute"); },
},
{
id: "ss",
isIFrame: true,
payload: invalidStyle8Payload,
rootElement: function() document.getElementById("ss").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule")
rootElement() { return document.getElementById("ss").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule"); },
},
{
id: "tt",
payload: invalidStyle8Payload,
rootElement: function() document.getElementById("tt"),
checkResult: function(html) is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule")
rootElement() { return document.getElementById("tt"); },
checkResult(html) { is(html.indexOf("@-moz-document"), -1, "Should not have retained the @-moz-document rule"); },
},
{
id: "uu",
isIFrame: true,
payload: invalidStyle9Payload,
rootElement: function() document.getElementById("uu").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule")
rootElement() { return document.getElementById("uu").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule"); },
},
{
id: "vv",
payload: invalidStyle9Payload,
rootElement: function() document.getElementById("vv"),
checkResult: function(html) is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule")
rootElement() { return document.getElementById("vv"); },
checkResult(html) { is(html.indexOf("@-moz-keyframes"), -1, "Should not have retained the @-moz-keyframes rule"); },
},
{
id: "sss",
payload: svgPayload,
rootElement: function() document.getElementById("sss"),
checkResult: function(html) isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title")
rootElement() { return document.getElementById("sss"); },
checkResult(html) { isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title"); },
},
{
id: "ssss",
isIFrame: true,
payload: svgPayload,
rootElement: function() document.getElementById("ssss").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title")
rootElement() { return document.getElementById("ssss").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("svgtitle"), -1, "Should have retained SVG title"); },
},
{
id: "ttt",
payload: svg2Payload,
rootElement: function() document.getElementById("ttt"),
checkResult: function(html) is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element")
rootElement() { return document.getElementById("ttt"); },
checkResult(html) { is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element"); },
},
{
id: "tttt",
isIFrame: true,
payload: svg2Payload,
rootElement: function() document.getElementById("tttt").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element")
rootElement() { return document.getElementById("tttt").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("bogussvg"), -1, "Should have dropped bogussvg element"); },
},
{
id: "uuu",
payload: mathPayload,
rootElement: function() document.getElementById("uuu"),
checkResult: function(html) is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element")
rootElement() { return document.getElementById("uuu"); },
checkResult(html) { is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element"); },
},
{
id: "uuuu",
isIFrame: true,
payload: mathPayload,
rootElement: function() document.getElementById("uuuu").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element")
rootElement() { return document.getElementById("uuuu").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("bogusmath"), -1, "Should have dropped bogusmath element"); },
},
{
id: "vvv",
payload: math2Payload,
rootElement: function() document.getElementById("vvv"),
checkResult: function(html) is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element")
rootElement() { return document.getElementById("vvv"); },
checkResult(html) { is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element"); },
},
{
id: "vvvv",
isIFrame: true,
payload: math2Payload,
rootElement: function() document.getElementById("vvvv").contentDocument.documentElement,
checkResult: function(html) is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element")
rootElement() { return document.getElementById("vvvv").contentDocument.documentElement; },
checkResult(html) { is(html.indexOf("yyy.css"), -1, "Should have dropped MathML style element"); },
},
{
id: "www",
payload: math3Payload,
rootElement: function() document.getElementById("www"),
checkResult: function(html) isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element")
rootElement() { return document.getElementById("www"); },
checkResult(html) { isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element"); },
},
{
id: "wwww",
isIFrame: true,
payload: math3Payload,
rootElement: function() document.getElementById("wwww").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element")
rootElement() { return document.getElementById("wwww").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("<mi"), -1, "Should not have dropped MathML mi element"); },
},
{
id: "xxx",
payload: videoPayload,
rootElement: function() document.getElementById("xxx"),
checkResult: function(html) isnot(html.indexOf("controls="), -1, "Should have added the controls attribute")
rootElement() { return document.getElementById("xxx"); },
checkResult(html) { isnot(html.indexOf("controls="), -1, "Should have added the controls attribute"); },
},
{
id: "xxxx",
isIFrame: true,
payload: videoPayload,
rootElement: function() document.getElementById("xxxx").contentDocument.documentElement,
checkResult: function(html) isnot(html.indexOf("controls="), -1, "Should have added the controls attribute")
rootElement() { return document.getElementById("xxxx").contentDocument.documentElement; },
checkResult(html) { isnot(html.indexOf("controls="), -1, "Should have added the controls attribute"); },
},
{
id: "yyy",
payload: microdataPayload,
rootElement: function() document.getElementById("yyy"),
rootElement() { return document.getElementById("yyy"); },
checkResult: function(html) { is(html.indexOf("name"), -1, "Should have dropped name."); is(html.indexOf("rel"), -1, "Should have dropped rel."); isnot(html.indexOf("itemprop"), -1, "Should not have dropped itemprop."); }
},
{
id: "yyyy",
isIFrame: true,
payload: microdataPayload,
rootElement: function() document.getElementById("yyyy").contentDocument.documentElement,
rootElement() { return document.getElementById("yyyy").contentDocument.documentElement; },
checkResult: function(html) { is(html.indexOf("name"), -1, "Should have dropped name."); is(html.indexOf("rel"), -1, "Should have dropped rel."); isnot(html.indexOf("itemprop"), -1, "Should not have dropped itemprop."); }
}
];

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

@ -34,7 +34,7 @@ function testTab(prefix, callback) {
function() {
dst.focus();
var inputReceived = false;
dst.addEventListener("input", function() inputReceived = true, false);
dst.addEventListener("input", function() { inputReceived = true; }, false);
synthesizeKey("v", {accelKey: true});
ok(inputReceived, "An input event should be raised");
is(dst.value, prefix + src.value, "The value should be pasted verbatim");

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

@ -23,7 +23,7 @@ SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var i = document.querySelector("input");
var inputCount = 0;
i.addEventListener("input", function() inputCount++, false);
i.addEventListener("input", function() { inputCount++; }, false);
// test cut
i.focus();

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

@ -11,6 +11,7 @@
#include "Rect.h"
#include "ScaledFontMac.h"
#include "Tools.h"
#include "PathHelpers.h"
#include <vector>
#include <algorithm>
#include "MacIOSurface.h"
@ -990,13 +991,162 @@ DrawTargetCG::FillRect(const Rect &aRect,
CGContextRestoreGState(mCg);
}
void
DrawTargetCG::StrokeLine(const Point &p1, const Point &p2, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions)
static Float
DashPeriodLength(const StrokeOptions& aStrokeOptions)
{
if (!std::isfinite(p1.x) ||
!std::isfinite(p1.y) ||
!std::isfinite(p2.x) ||
!std::isfinite(p2.y)) {
Float length = 0;
for (size_t i = 0; i < aStrokeOptions.mDashLength; i++) {
length += aStrokeOptions.mDashPattern[i];
}
if (aStrokeOptions.mDashLength & 1) {
// "If an odd number of values is provided, then the list of values is
// repeated to yield an even number of values."
// Double the length.
length += length;
}
return length;
}
inline Float
RoundDownToMultiple(Float aValue, Float aFactor)
{
return floorf(aValue / aFactor) * aFactor;
}
static Rect
UserSpaceStrokeClip(const Rect &aDeviceClip,
const Matrix &aTransform,
const StrokeOptions &aStrokeOptions)
{
Matrix inverse = aTransform;
if (!inverse.Invert()) {
return Rect();
}
Rect deviceClip = aDeviceClip;
deviceClip.Inflate(MaxStrokeExtents(aStrokeOptions, aTransform));
return inverse.TransformBounds(deviceClip);
}
static Rect
ShrinkClippedStrokedRect(const Rect &aStrokedRect, const Rect &aDeviceClip,
const Matrix &aTransform,
const StrokeOptions &aStrokeOptions)
{
Rect userSpaceStrokeClip =
UserSpaceStrokeClip(aDeviceClip, aTransform, aStrokeOptions);
Rect intersection = aStrokedRect.Intersect(userSpaceStrokeClip);
Float dashPeriodLength = DashPeriodLength(aStrokeOptions);
if (intersection.IsEmpty() || dashPeriodLength == 0.0f) {
return intersection;
}
// Reduce the rectangle side lengths in multiples of the dash period length
// so that the visible dashes stay in the same place.
Margin insetBy = aStrokedRect - intersection;
insetBy.top = RoundDownToMultiple(insetBy.top, dashPeriodLength);
insetBy.right = RoundDownToMultiple(insetBy.right, dashPeriodLength);
insetBy.bottom = RoundDownToMultiple(insetBy.bottom, dashPeriodLength);
insetBy.left = RoundDownToMultiple(insetBy.left, dashPeriodLength);
Rect shrunkRect = aStrokedRect;
shrunkRect.Deflate(insetBy);
return shrunkRect;
}
// Liang-Barsky
// This algorithm was chosen for its code brevity, with the hope that its
// performance is good enough.
// Sets aStart and aEnd to floats between 0 and the line length, or returns
// false if the line is completely outside the rect.
static bool
IntersectLineWithRect(const Point& aP1, const Point& aP2, const Rect& aClip,
Float* aStart, Float* aEnd)
{
Float t0 = 0.0f;
Float t1 = 1.0f;
Point vector = aP2 - aP1;
for (uint32_t edge = 0; edge < 4; edge++) {
Float p, q;
switch (edge) {
case 0: p = -vector.x; q = aP1.x - aClip.x; break;
case 1: p = vector.x; q = aClip.XMost() - aP1.x; break;
case 2: p = -vector.y; q = aP1.y - aClip.y; break;
case 3: p = vector.y; q = aClip.YMost() - aP1.y; break;
}
if (p == 0.0f) {
// Line is parallel to the edge.
if (q < 0.0f) {
return false;
}
continue;
}
Float r = q / p;
if (p < 0) {
t0 = std::max(t0, r);
} else {
t1 = std::min(t1, r);
}
if (t0 > t1) {
return false;
}
}
Float length = vector.Length();
*aStart = t0 * length;
*aEnd = t1 * length;
return true;
}
// Adjusts aP1 and aP2 to a shrunk line, or returns false if the line is
// completely outside the clip.
static bool
ShrinkClippedStrokedLine(Point &aP1, Point& aP2, const Rect &aDeviceClip,
const Matrix &aTransform,
const StrokeOptions &aStrokeOptions)
{
Rect userSpaceStrokeClip =
UserSpaceStrokeClip(aDeviceClip, aTransform, aStrokeOptions);
Point vector = aP2 - aP1;
Float length = vector.Length();
if (length == 0.0f) {
return true;
}
Float start = 0;
Float end = length;
if (!IntersectLineWithRect(aP1, aP2, userSpaceStrokeClip, &start, &end)) {
return false;
}
Float dashPeriodLength = DashPeriodLength(aStrokeOptions);
if (dashPeriodLength > 0.0f) {
// Shift the line points by multiples of dashPeriodLength so that the
// dashes stay in the same place.
start = RoundDownToMultiple(start, dashPeriodLength);
end = length - RoundDownToMultiple(length - end, dashPeriodLength);
}
Point startPoint = aP1;
aP1 = Point(startPoint.x + start * vector.x / length,
startPoint.y + start * vector.y / length);
aP2 = Point(startPoint.x + end * vector.x / length,
startPoint.y + end * vector.y / length);
return true;
}
void
DrawTargetCG::StrokeLine(const Point &aP1, const Point &aP2, const Pattern &aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions &aDrawOptions)
{
if (!std::isfinite(aP1.x) ||
!std::isfinite(aP1.y) ||
!std::isfinite(aP2.x) ||
!std::isfinite(aP2.y)) {
return;
}
@ -1004,6 +1154,14 @@ DrawTargetCG::StrokeLine(const Point &p1, const Point &p2, const Pattern &aPatte
return;
}
Point p1 = aP1;
Point p2 = aP2;
Rect deviceClip(0, 0, mSize.width, mSize.height);
if (!ShrinkClippedStrokedLine(p1, p2, deviceClip, mTransform, aStrokeOptions)) {
return;
}
MarkChanged();
CGContextSaveGState(mCg);
@ -1078,6 +1236,20 @@ DrawTargetCG::StrokeRect(const Rect &aRect,
if (MOZ2D_ERROR_IF(!cg)) {
return;
}
// Stroking large rectangles with dashes is expensive with CG (fixed
// overhead based on the number of dashes, regardless of whether the dashes
// are visible), so we try to reduce the size of the stroked rectangle as
// much as possible before passing it on to CG.
Rect rect = aRect;
if (!rect.IsEmpty()) {
Rect deviceClip(0, 0, mSize.width, mSize.height);
rect = ShrinkClippedStrokedRect(rect, deviceClip, mTransform, aStrokeOptions);
if (rect.IsEmpty()) {
return;
}
}
CGContextSetAlpha(mCg, aDrawOptions.mAlpha);
CGContextSetBlendMode(mCg, ToBlendMode(aDrawOptions.mCompositionOp));

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

@ -3,11 +3,9 @@
* 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/. */
#define _USE_MATH_DEFINES
#include <cmath>
#include "DrawTargetTiled.h"
#include "Logging.h"
#include "PathHelpers.h"
using namespace std;
@ -107,8 +105,6 @@ TILED_COMMAND(Flush)
TILED_COMMAND4(DrawFilter, FilterNode*, const Rect&, const Point&, const DrawOptions&)
TILED_COMMAND1(ClearRect, const Rect&)
TILED_COMMAND4(MaskSurface, const Pattern&, SourceSurface*, Point, const DrawOptions&)
TILED_COMMAND4(StrokeRect, const Rect&, const Pattern&, const StrokeOptions&, const DrawOptions&)
TILED_COMMAND5(StrokeLine, const Point&, const Point&, const Pattern&, const StrokeOptions&, const DrawOptions&)
TILED_COMMAND5(FillGlyphs, ScaledFont*, const GlyphBuffer&, const Pattern&, const DrawOptions&, const GlyphRenderingOptions*)
TILED_COMMAND3(Mask, const Pattern&, const Pattern&, const DrawOptions&)
@ -232,40 +228,12 @@ DrawTargetTiled::FillRect(const Rect& aRect, const Pattern& aPattern, const Draw
}
}
// The logic for this comes from _cairo_stroke_style_max_distance_from_path
static Rect
PathExtentsToMaxStrokeExtents(const StrokeOptions &aStrokeOptions,
const Rect &aRect,
const Matrix &aTransform)
{
double styleExpansionFactor = 0.5f;
if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
styleExpansionFactor = M_SQRT1_2;
}
if (aStrokeOptions.mLineJoin == JoinStyle::MITER &&
styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) {
styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit;
}
styleExpansionFactor *= aStrokeOptions.mLineWidth;
double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);
Rect result = aRect;
result.Inflate(dx, dy);
return result;
}
void
DrawTargetTiled::Stroke(const Path* aPath, const Pattern& aPattern, const StrokeOptions& aStrokeOptions, const DrawOptions& aDrawOptions)
{
// Approximate the stroke extents, since Path::GetStrokeExtents can be slow
Rect deviceRect = PathExtentsToMaxStrokeExtents(aStrokeOptions,
aPath->GetBounds(mTransform),
mTransform);
Rect deviceRect = aPath->GetBounds(mTransform);
deviceRect.Inflate(MaxStrokeExtents(aStrokeOptions, mTransform));
for (size_t i = 0; i < mTiles.size(); i++) {
if (!mTiles[i].mClippedOut &&
deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
@ -277,6 +245,51 @@ DrawTargetTiled::Stroke(const Path* aPath, const Pattern& aPattern, const Stroke
}
}
void
DrawTargetTiled::StrokeRect(const Rect& aRect, const Pattern& aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions& aDrawOptions)
{
Rect deviceRect = mTransform.TransformBounds(aRect);
Margin strokeMargin = MaxStrokeExtents(aStrokeOptions, mTransform);
Rect outerRect = deviceRect;
outerRect.Inflate(strokeMargin);
Rect innerRect;
if (mTransform.IsRectilinear()) {
// If rects are mapped to rects, we can compute the inner rect
// of the stroked rect.
innerRect = deviceRect;
innerRect.Deflate(strokeMargin);
}
for (size_t i = 0; i < mTiles.size(); i++) {
if (mTiles[i].mClippedOut) {
continue;
}
Rect tileRect(mTiles[i].mTileOrigin.x,
mTiles[i].mTileOrigin.y,
mTiles[i].mDrawTarget->GetSize().width,
mTiles[i].mDrawTarget->GetSize().height);
if (outerRect.Intersects(tileRect) && !innerRect.Contains(tileRect)) {
mTiles[i].mDrawTarget->StrokeRect(aRect, aPattern, aStrokeOptions, aDrawOptions);
}
}
}
void
DrawTargetTiled::StrokeLine(const Point& aStart, const Point& aEnd, const Pattern& aPattern, const StrokeOptions &aStrokeOptions, const DrawOptions& aDrawOptions)
{
Rect lineBounds = Rect(aStart, Size()).UnionEdges(Rect(aEnd, Size()));
Rect deviceRect = mTransform.TransformBounds(lineBounds);
deviceRect.Inflate(MaxStrokeExtents(aStrokeOptions, mTransform));
for (size_t i = 0; i < mTiles.size(); i++) {
if (!mTiles[i].mClippedOut &&
deviceRect.Intersects(Rect(mTiles[i].mTileOrigin.x,
mTiles[i].mTileOrigin.y,
mTiles[i].mDrawTarget->GetSize().width,
mTiles[i].mDrawTarget->GetSize().height))) {
mTiles[i].mDrawTarget->StrokeLine(aStart, aEnd, aPattern, aStrokeOptions, aDrawOptions);
}
}
}
void
DrawTargetTiled::Fill(const Path* aPath, const Pattern& aPattern, const DrawOptions& aDrawOptions)
{

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

@ -3,6 +3,9 @@
* 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/. */
#define _USE_MATH_DEFINES
#include <cmath>
#include "PathHelpers.h"
namespace mozilla {
@ -238,6 +241,29 @@ StrokeSnappedEdgesOfRect(const Rect& aRect, DrawTarget& aDrawTarget,
aDrawTarget.StrokeLine(p1, p2, aColor, aStrokeOptions);
}
// The logic for this comes from _cairo_stroke_style_max_distance_from_path
Margin
MaxStrokeExtents(const StrokeOptions& aStrokeOptions,
const Matrix& aTransform)
{
double styleExpansionFactor = 0.5f;
if (aStrokeOptions.mLineCap == CapStyle::SQUARE) {
styleExpansionFactor = M_SQRT1_2;
}
if (aStrokeOptions.mLineJoin == JoinStyle::MITER &&
styleExpansionFactor < M_SQRT2 * aStrokeOptions.mMiterLimit) {
styleExpansionFactor = M_SQRT2 * aStrokeOptions.mMiterLimit;
}
styleExpansionFactor *= aStrokeOptions.mLineWidth;
double dx = styleExpansionFactor * hypot(aTransform._11, aTransform._21);
double dy = styleExpansionFactor * hypot(aTransform._22, aTransform._12);
return Margin(dy, dx, dy, dx);
}
} // namespace gfx
} // namespace mozilla

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

@ -283,6 +283,16 @@ GFX2D_API void StrokeSnappedEdgesOfRect(const Rect& aRect,
const ColorPattern& aColor,
const StrokeOptions& aStrokeOptions);
/**
* Return the margin, in device space, by which a stroke can extend beyond the
* rendered shape.
* @param aStrokeOptions The stroke options that the stroke is drawn with.
* @param aTransform The user space to device space transform.
* @return The stroke margin.
*/
GFX2D_API Margin MaxStrokeExtents(const StrokeOptions& aStrokeOptions,
const Matrix& aTransform);
extern UserDataKey sDisablePixelSnapping;
/**

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

@ -109,6 +109,7 @@ UNIFIED_SOURCES += [
'DrawTargetCapture.cpp',
'DrawTargetDual.cpp',
'DrawTargetRecording.cpp',
'DrawTargetTiled.cpp',
'Factory.cpp',
'FilterNodeSoftware.cpp',
'FilterProcessing.cpp',
@ -117,7 +118,6 @@ UNIFIED_SOURCES += [
'Matrix.cpp',
'Path.cpp',
'PathCairo.cpp',
'PathHelpers.cpp',
'PathRecording.cpp',
'RecordedEvent.cpp',
'Scale.cpp',
@ -128,7 +128,7 @@ UNIFIED_SOURCES += [
]
SOURCES += [
'DrawTargetTiled.cpp',
'PathHelpers.cpp', # Uses _USE_MATH_DEFINES
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':

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

@ -117,9 +117,6 @@ DEFINES['GL_APICALL'] = ""
DEFINES['GL_GLEXT_PROTOTYPES'] = ""
DEFINES['EGLAPI'] = ""
# ANGLE uses the STL, so we can't use our derpy STL wrappers.
DISABLE_STL_WRAPPING = True
# Only build libEGL/libGLESv2 on Windows
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':

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

@ -277,21 +277,6 @@ struct ParamTraits<mozilla::layers::TextureFlags>
mozilla::layers::TextureFlags::ALL_BITS>
{};
template <>
struct ParamTraits<mozilla::layers::TextureIdentifier>
: public ContiguousEnumSerializer<
mozilla::layers::TextureIdentifier,
mozilla::layers::TextureIdentifier::Front,
mozilla::layers::TextureIdentifier::HighBound>
{};
template <>
struct ParamTraits<mozilla::layers::DeprecatedTextureHostFlags>
: public BitFlagsEnumSerializer<
mozilla::layers::DeprecatedTextureHostFlags,
mozilla::layers::DeprecatedTextureHostFlags::ALL_BITS>
{};
template <>
struct ParamTraits<mozilla::layers::DiagnosticTypes>
: public BitFlagsEnumSerializer<
@ -834,14 +819,12 @@ struct ParamTraits<mozilla::layers::TextureInfo>
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, aParam.mCompositableType);
WriteParam(aMsg, aParam.mDeprecatedTextureHostFlags);
WriteParam(aMsg, aParam.mTextureFlags);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, &aResult->mCompositableType) &&
ReadParam(aMsg, aIter, &aResult->mDeprecatedTextureHostFlags) &&
ReadParam(aMsg, aIter, &aResult->mTextureFlags);
}
};

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

@ -133,8 +133,6 @@ enum class EffectTypes : uint8_t {
*/
enum class CompositableType : uint8_t {
UNKNOWN,
CONTENT_INC, // painted layer interface, only sends incremental
// updates to a texture on the compositor side.
CONTENT_TILED, // tiled painted layer
IMAGE, // image with single buffering
IMAGE_OVERLAY, // image without buffer
@ -144,19 +142,6 @@ enum class CompositableType : uint8_t {
COUNT
};
/**
* How the texture host is used for composition,
* XXX - Only used by ContentClientIncremental
*/
enum class DeprecatedTextureHostFlags : uint8_t {
DEFAULT = 0, // The default texture host for the given SurfaceDescriptor
TILED = 1 << 0, // A texture host that supports tiling
COPY_PREVIOUS = 1 << 1, // Texture contents should be initialized
// from the previous texture.
ALL_BITS = (1 << 2) - 1
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(DeprecatedTextureHostFlags)
#ifdef XP_WIN
typedef void* SyncHandle;
#else
@ -194,20 +179,6 @@ struct TextureFactoryIdentifier
{}
};
/**
* Identify a texture to a compositable. Many textures can have the same id, but
* the id is unique for any texture owned by a particular compositable.
* XXX - We don't really need this, it will be removed along with the incremental
* ContentClient/Host.
*/
enum class TextureIdentifier : uint8_t {
Front = 1,
Back = 2,
OnWhiteFront = 3,
OnWhiteBack = 4,
HighBound
};
/**
* Information required by the compositor from the content-side for creating or
* using compositables and textures.
@ -218,27 +189,22 @@ enum class TextureIdentifier : uint8_t {
struct TextureInfo
{
CompositableType mCompositableType;
// XXX - only used by ContentClientIncremental
DeprecatedTextureHostFlags mDeprecatedTextureHostFlags;
TextureFlags mTextureFlags;
TextureInfo()
: mCompositableType(CompositableType::UNKNOWN)
, mDeprecatedTextureHostFlags(DeprecatedTextureHostFlags::DEFAULT)
, mTextureFlags(TextureFlags::NO_FLAGS)
{}
explicit TextureInfo(CompositableType aType,
TextureFlags aTextureFlags = TextureFlags::DEFAULT)
: mCompositableType(aType)
, mDeprecatedTextureHostFlags(DeprecatedTextureHostFlags::DEFAULT)
, mTextureFlags(aTextureFlags)
{}
bool operator==(const TextureInfo& aOther) const
{
return mCompositableType == aOther.mCompositableType &&
mDeprecatedTextureHostFlags == aOther.mDeprecatedTextureHostFlags &&
mTextureFlags == aOther.mTextureFlags;
}
};

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

@ -272,7 +272,6 @@ public:
struct DrawIterator {
friend class RotatedContentBuffer;
friend class ContentClientIncremental;
DrawIterator()
: mCount(0)
{}

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

@ -48,8 +48,6 @@ public:
nsIntRegion* aDestRegion = nullptr,
gfx::IntPoint* aSrcOffset = nullptr) MOZ_OVERRIDE
{
// XXX - For this to work with IncrementalContentHost we will need to support
// the aDestRegion and aSrcOffset parameters properly;
mSurface = aSurface;
return true;
}

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

@ -587,17 +587,6 @@ ClientLayerManager::ForwardTransaction(bool aScheduleComposite)
break;
}
case EditReply::TOpTextureSwap: {
MOZ_LAYERS_LOG(("[LayersForwarder] TextureSwap"));
const OpTextureSwap& ots = reply.get_OpTextureSwap();
CompositableClient* compositable =
CompositableClient::FromIPDLActor(ots.compositableChild());
MOZ_ASSERT(compositable);
compositable->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReturnReleaseFence: {
const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
FenceHandle fence = rep.fence();

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

@ -143,12 +143,6 @@ public:
TextureFlags aTextureFlags,
TextureAllocationFlags aAllocFlags = ALLOC_DEFAULT);
virtual void SetDescriptorFromReply(TextureIdentifier aTextureId,
const SurfaceDescriptor& aDescriptor)
{
MOZ_CRASH("If you want to call this, you should have implemented it");
}
/**
* Establishes the connection with compositor side through IPDL
*/

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

@ -93,11 +93,6 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder)
if (useDoubleBuffering || PR_GetEnv("MOZ_FORCE_DOUBLE_BUFFERING")) {
return new ContentClientDoubleBuffered(aForwarder);
}
#ifdef XP_MACOSX
if (backend == LayersBackend::LAYERS_OPENGL) {
return new ContentClientIncremental(aForwarder);
}
#endif
return new ContentClientSingleBuffered(aForwarder);
}
@ -673,362 +668,5 @@ ContentClientSingleBuffered::FinalizeFrame(const nsIntRegion& aRegionToDraw)
}
}
static void
WrapRotationAxis(int32_t* aRotationPoint, int32_t aSize)
{
if (*aRotationPoint < 0) {
*aRotationPoint += aSize;
} else if (*aRotationPoint >= aSize) {
*aRotationPoint -= aSize;
}
}
static void
FillSurface(DrawTarget* aDT, const nsIntRegion& aRegion,
const nsIntPoint& aOffset, const gfxRGBA& aColor)
{
nsIntRegionRectIterator iter(aRegion);
const nsIntRect* r;
while ((r = iter.Next()) != nullptr) {
aDT->FillRect(Rect(r->x - aOffset.x, r->y - aOffset.y,
r->width, r->height),
ColorPattern(ToColor(aColor)));
}
}
void
ContentClientIncremental::NotifyBufferCreated(ContentType aType, TextureFlags aFlags)
{
mTextureInfo.mTextureFlags = aFlags;
mContentType = aType;
mForwarder->CreatedIncrementalBuffer(this,
mTextureInfo,
mBufferRect);
}
RotatedContentBuffer::PaintState
ContentClientIncremental::BeginPaintBuffer(PaintedLayer* aLayer,
uint32_t aFlags)
{
mTextureInfo.mDeprecatedTextureHostFlags = DeprecatedTextureHostFlags::DEFAULT;
PaintState result;
// We need to disable rotation if we're going to be resampled when
// drawing, because we might sample across the rotation boundary.
bool canHaveRotation = !(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE);
nsIntRegion validRegion = aLayer->GetValidRegion();
bool canUseOpaqueSurface = aLayer->CanUseOpaqueSurface();
ContentType contentType =
canUseOpaqueSurface ? gfxContentType::COLOR :
gfxContentType::COLOR_ALPHA;
SurfaceMode mode;
nsIntRegion neededRegion;
bool canReuseBuffer;
nsIntRect destBufferRect;
while (true) {
mode = aLayer->GetSurfaceMode();
neededRegion = aLayer->GetVisibleRegion();
// If we're going to resample, we need a buffer that's in clamp mode.
canReuseBuffer = neededRegion.GetBounds().Size() <= mBufferRect.Size() &&
mHasBuffer && !(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE);
if (canReuseBuffer) {
if (mBufferRect.Contains(neededRegion.GetBounds())) {
// We don't need to adjust mBufferRect.
destBufferRect = mBufferRect;
} else {
// The buffer's big enough but doesn't contain everything that's
// going to be visible. We'll move it.
destBufferRect = nsIntRect(neededRegion.GetBounds().TopLeft(), mBufferRect.Size());
}
} else {
destBufferRect = neededRegion.GetBounds();
}
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
if (!gfxPrefs::ComponentAlphaEnabled() ||
!aLayer->GetParent() ||
!aLayer->GetParent()->SupportsComponentAlphaChildren()) {
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
} else {
contentType = gfxContentType::COLOR;
}
}
if ((aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) &&
(!neededRegion.GetBounds().IsEqualInterior(destBufferRect) ||
neededRegion.GetNumRects() > 1)) {
// The area we add to neededRegion might not be painted opaquely
if (mode == SurfaceMode::SURFACE_OPAQUE) {
contentType = gfxContentType::COLOR_ALPHA;
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
}
// For component alpha layers, we leave contentType as gfxContentType::COLOR.
// We need to validate the entire buffer, to make sure that only valid
// pixels are sampled
neededRegion = destBufferRect;
}
if (mHasBuffer &&
(mContentType != contentType ||
(mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mHasBufferOnWhite)) {
#ifdef MOZ_DUMP_PAINTING
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
if (mContentType != contentType) {
printf_stderr("Layer's content type has changed\n");
}
if ((mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) != mHasBufferOnWhite) {
printf_stderr("Layer's component alpha status has changed\n");
}
printf_stderr("Invalidating entire layer %p: no buffer, or content type or component alpha changed\n", aLayer);
}
#endif
// We're effectively clearing the valid region, so we need to draw
// the entire needed region now.
result.mRegionToInvalidate = aLayer->GetValidRegion();
validRegion.SetEmpty();
mHasBuffer = false;
mHasBufferOnWhite = false;
mBufferRect.SetRect(0, 0, 0, 0);
mBufferRotation.MoveTo(0, 0);
// Restart decision process with the cleared buffer. We can only go
// around the loop one more iteration, since mTexImage is null now.
continue;
}
break;
}
result.mRegionToDraw.Sub(neededRegion, validRegion);
if (result.mRegionToDraw.IsEmpty())
return result;
if (destBufferRect.width > mForwarder->GetMaxTextureSize() ||
destBufferRect.height > mForwarder->GetMaxTextureSize()) {
return result;
}
// BlitTextureImage depends on the FBO texture target being
// TEXTURE_2D. This isn't the case on some older X1600-era Radeons.
if (!mForwarder->SupportsTextureBlitting() ||
!mForwarder->SupportsPartialUploads()) {
result.mRegionToDraw = neededRegion;
validRegion.SetEmpty();
mHasBuffer = false;
mHasBufferOnWhite = false;
mBufferRect.SetRect(0, 0, 0, 0);
mBufferRotation.MoveTo(0, 0);
canReuseBuffer = false;
}
nsIntRect drawBounds = result.mRegionToDraw.GetBounds();
bool createdBuffer = false;
TextureFlags bufferFlags = TextureFlags::NO_FLAGS;
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
bufferFlags |= TextureFlags::COMPONENT_ALPHA;
}
if (canReuseBuffer) {
nsIntRect keepArea;
if (keepArea.IntersectRect(destBufferRect, mBufferRect)) {
// Set mBufferRotation so that the pixels currently in mBuffer
// will still be rendered in the right place when mBufferRect
// changes to destBufferRect.
nsIntPoint newRotation = mBufferRotation +
(destBufferRect.TopLeft() - mBufferRect.TopLeft());
WrapRotationAxis(&newRotation.x, mBufferRect.width);
WrapRotationAxis(&newRotation.y, mBufferRect.height);
NS_ASSERTION(nsIntRect(nsIntPoint(0,0), mBufferRect.Size()).Contains(newRotation),
"newRotation out of bounds");
int32_t xBoundary = destBufferRect.XMost() - newRotation.x;
int32_t yBoundary = destBufferRect.YMost() - newRotation.y;
if ((drawBounds.x < xBoundary && xBoundary < drawBounds.XMost()) ||
(drawBounds.y < yBoundary && yBoundary < drawBounds.YMost()) ||
(newRotation != nsIntPoint(0,0) && !canHaveRotation)) {
// The stuff we need to redraw will wrap around an edge of the
// buffer, so we will need to do a self-copy
// If mBufferRotation == nsIntPoint(0,0) we could do a real
// self-copy but we're not going to do that in GL yet.
// We can't do a real self-copy because the buffer is rotated.
// So allocate a new buffer for the destination.
destBufferRect = neededRegion.GetBounds();
createdBuffer = true;
} else {
mBufferRect = destBufferRect;
mBufferRotation = newRotation;
}
} else {
// No pixels are going to be kept. The whole visible region
// will be redrawn, so we don't need to copy anything, so we don't
// set destBuffer.
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
}
} else {
// The buffer's not big enough, so allocate a new one
createdBuffer = true;
}
NS_ASSERTION(!(aFlags & RotatedContentBuffer::PAINT_WILL_RESAMPLE) ||
destBufferRect == neededRegion.GetBounds(),
"If we're resampling, we need to validate the entire buffer");
if (!createdBuffer && !mHasBuffer) {
return result;
}
if (createdBuffer) {
if (mHasBuffer &&
(mode != SurfaceMode::SURFACE_COMPONENT_ALPHA || mHasBufferOnWhite)) {
mTextureInfo.mDeprecatedTextureHostFlags = DeprecatedTextureHostFlags::COPY_PREVIOUS;
}
mHasBuffer = true;
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
mHasBufferOnWhite = true;
}
mBufferRect = destBufferRect;
mBufferRotation = nsIntPoint(0,0);
NotifyBufferCreated(contentType, bufferFlags);
}
NS_ASSERTION(canHaveRotation || mBufferRotation == nsIntPoint(0,0),
"Rotation disabled, but we have nonzero rotation?");
nsIntRegion invalidate;
invalidate.Sub(aLayer->GetValidRegion(), destBufferRect);
result.mRegionToInvalidate.Or(result.mRegionToInvalidate, invalidate);
// If we do partial updates, we have to clip drawing to the regionToDraw.
// If we don't clip, background images will be fillrect'd to the region correctly,
// while text or lines will paint outside of the regionToDraw. This becomes apparent
// with concave regions. Right now the scrollbars invalidate a narrow strip of the bar
// although they never cover it. This leads to two draw rects, the narow strip and the actually
// newly exposed area. It would be wise to fix this glitch in any way to have simpler
// clip and draw regions.
result.mClip = DrawRegionClip::DRAW;
result.mMode = mode;
return result;
}
DrawTarget*
ContentClientIncremental::BorrowDrawTargetForPainting(PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter)
{
if (aPaintState.mMode == SurfaceMode::SURFACE_NONE) {
return nullptr;
}
if (aIter) {
if (aIter->mCount++ > 0) {
return nullptr;
}
aIter->mDrawRegion = aPaintState.mRegionToDraw;
}
DrawTarget* result = nullptr;
nsIntRect drawBounds = aPaintState.mRegionToDraw.GetBounds();
MOZ_ASSERT(!mLoanedDrawTarget);
// BeginUpdate is allowed to modify the given region,
// if it wants more to be repainted than we request.
if (aPaintState.mMode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
nsIntRegion drawRegionCopy = aPaintState.mRegionToDraw;
RefPtr<DrawTarget> onBlack = GetUpdateSurface(BUFFER_BLACK, drawRegionCopy);
RefPtr<DrawTarget> onWhite = GetUpdateSurface(BUFFER_WHITE, aPaintState.mRegionToDraw);
if (onBlack && onWhite) {
NS_ASSERTION(aPaintState.mRegionToDraw == drawRegionCopy,
"BeginUpdate should always modify the draw region in the same way!");
FillSurface(onBlack, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(0.0, 0.0, 0.0, 1.0));
FillSurface(onWhite, aPaintState.mRegionToDraw, nsIntPoint(drawBounds.x, drawBounds.y), gfxRGBA(1.0, 1.0, 1.0, 1.0));
mLoanedDrawTarget = Factory::CreateDualDrawTarget(onBlack, onWhite);
} else {
mLoanedDrawTarget = nullptr;
}
} else {
mLoanedDrawTarget = GetUpdateSurface(BUFFER_BLACK, aPaintState.mRegionToDraw);
}
if (!mLoanedDrawTarget) {
NS_WARNING("unable to get context for update");
return nullptr;
}
result = mLoanedDrawTarget;
mLoanedTransform = mLoanedDrawTarget->GetTransform();
result->SetTransform(Matrix(mLoanedTransform).
PreTranslate(-drawBounds.x, -drawBounds.y));
if (mContentType == gfxContentType::COLOR_ALPHA) {
gfxUtils::ClipToRegion(result, aPaintState.mRegionToDraw);
nsIntRect bounds = aPaintState.mRegionToDraw.GetBounds();
result->ClearRect(Rect(bounds.x, bounds.y, bounds.width, bounds.height));
}
return result;
}
void
ContentClientIncremental::Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion,
bool aDidSelfCopy)
{
if (IsSurfaceDescriptorValid(mUpdateDescriptor)) {
mForwarder->UpdateTextureIncremental(this,
TextureIdentifier::Front,
mUpdateDescriptor,
aRegionToDraw,
mBufferRect,
mBufferRotation);
mUpdateDescriptor = SurfaceDescriptor();
}
if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) {
mForwarder->UpdateTextureIncremental(this,
TextureIdentifier::OnWhiteFront,
mUpdateDescriptorOnWhite,
aRegionToDraw,
mBufferRect,
mBufferRotation);
mUpdateDescriptorOnWhite = SurfaceDescriptor();
}
}
TemporaryRef<DrawTarget>
ContentClientIncremental::GetUpdateSurface(BufferType aType,
const nsIntRegion& aUpdateRegion)
{
nsIntRect rgnSize = aUpdateRegion.GetBounds();
if (!mBufferRect.Contains(rgnSize)) {
NS_ERROR("update outside of image");
return nullptr;
}
SurfaceDescriptor desc;
if (!mForwarder->AllocSurfaceDescriptor(rgnSize.Size().ToIntSize(),
mContentType,
&desc)) {
NS_WARNING("creating SurfaceDescriptor failed!");
Clear();
return nullptr;
}
if (aType == BUFFER_BLACK) {
MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptor));
mUpdateDescriptor = desc;
} else {
MOZ_ASSERT(!IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite));
MOZ_ASSERT(aType == BUFFER_WHITE);
mUpdateDescriptorOnWhite = desc;
}
return GetDrawTargetForDescriptor(desc, gfx::BackendType::COREGRAPHICS);
}
}
}

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

@ -397,89 +397,6 @@ public:
}
};
/**
* A single buffered ContentClient that creates temporary buffers which are
* used to update the host-side texture. The ownership of the buffers is
* passed to the host side during the transaction, and we need to create
* new ones each frame.
*/
class ContentClientIncremental : public ContentClientRemote
, public BorrowDrawTarget
{
public:
explicit ContentClientIncremental(CompositableForwarder* aFwd)
: ContentClientRemote(aFwd)
, mContentType(gfxContentType::COLOR_ALPHA)
, mHasBuffer(false)
, mHasBufferOnWhite(false)
{
mTextureInfo.mCompositableType = CompositableType::CONTENT_INC;
}
typedef RotatedContentBuffer::PaintState PaintState;
typedef RotatedContentBuffer::ContentType ContentType;
virtual TextureInfo GetTextureInfo() const MOZ_OVERRIDE
{
return mTextureInfo;
}
virtual void Clear() MOZ_OVERRIDE
{
mBufferRect.SetEmpty();
mHasBuffer = false;
mHasBufferOnWhite = false;
}
virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
uint32_t aFlags) MOZ_OVERRIDE;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
RotatedContentBuffer::DrawIterator* aIter = nullptr) MOZ_OVERRIDE;
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
BorrowDrawTarget::ReturnDrawTarget(aReturned);
}
virtual void Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion,
bool aDidSelfCopy) MOZ_OVERRIDE;
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) MOZ_OVERRIDE
{
if (IsSurfaceDescriptorValid(mUpdateDescriptor)) {
mForwarder->DestroySharedSurface(&mUpdateDescriptor);
}
if (IsSurfaceDescriptorValid(mUpdateDescriptorOnWhite)) {
mForwarder->DestroySharedSurface(&mUpdateDescriptorOnWhite);
}
ContentClientRemote::EndPaint(aReadbackUpdates);
}
private:
enum BufferType{
BUFFER_BLACK,
BUFFER_WHITE
};
void NotifyBufferCreated(ContentType aType, TextureFlags aFlags);
TemporaryRef<gfx::DrawTarget> GetUpdateSurface(BufferType aType,
const nsIntRegion& aUpdateRegion);
TextureInfo mTextureInfo;
nsIntRect mBufferRect;
nsIntPoint mBufferRotation;
SurfaceDescriptor mUpdateDescriptor;
SurfaceDescriptor mUpdateDescriptorOnWhite;
ContentType mContentType;
bool mHasBuffer;
bool mHasBufferOnWhite;
};
}
}

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

@ -181,9 +181,6 @@ CompositableHost::Create(const TextureInfo& aTextureInfo)
case CompositableType::IMAGE_BRIDGE:
NS_ERROR("Cannot create an image bridge compositable this way");
break;
case CompositableType::CONTENT_INC:
result = new ContentHostIncremental(aTextureInfo);
break;
case CompositableType::CONTENT_TILED:
result = new TiledContentHost(aTextureInfo);
break;

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

@ -101,45 +101,6 @@ public:
return false;
}
/**
* Update the content host using a surface that only contains the updated
* region.
*
* Takes ownership of aSurface, and is responsible for freeing it.
*
* @param aTextureId Texture to update.
* @param aSurface Surface containing the update area. Its contents are relative
* to aUpdated.TopLeft()
* @param aUpdated Area of the content host to update.
* @param aBufferRect New area covered by the content host.
* @param aBufferRotation New buffer rotation.
*/
virtual void UpdateIncremental(TextureIdentifier aTextureId,
SurfaceDescriptor& aSurface,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
{
MOZ_ASSERT(false, "should be implemented or not used");
}
/**
* Ensure that a suitable texture host exists in this compsitable.
*
* Only used with ContentHostIncremental.
*
* No SurfaceDescriptor or TextureIdentifier is provider as we
* don't have a single surface for the texture contents, and we
* need to allocate our own one to be updated later.
*/
virtual bool CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
{
NS_ERROR("should be implemented or not used");
return false;
}
/**
* Returns the front buffer.
*/

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

@ -388,429 +388,6 @@ ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData,
return true;
}
ContentHostIncremental::ContentHostIncremental(const TextureInfo& aTextureInfo)
: ContentHostBase(aTextureInfo)
, mDeAllocator(nullptr)
, mLocked(false)
{
}
ContentHostIncremental::~ContentHostIncremental()
{
}
bool
ContentHostIncremental::CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
{
mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo,
aBufferRect));
mDeAllocator = aAllocator;
FlushUpdateQueue();
return true;
}
void
ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId,
SurfaceDescriptor& aSurface,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
{
mUpdateList.AppendElement(new TextureUpdateRequest(mDeAllocator,
aTextureId,
aSurface,
aUpdated,
aBufferRect,
aBufferRotation));
FlushUpdateQueue();
}
void
ContentHostIncremental::Composite(EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const Filter& aFilter,
const Rect& aClipRect,
const nsIntRegion* aVisibleRegion)
{
NS_ASSERTION(aVisibleRegion, "Requires a visible region");
AutoLockCompositableHost lock(this);
if (lock.Failed()) {
return;
}
if (!mSource) {
return;
}
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mSource.get(),
mSourceOnWhite.get(),
aFilter, true);
if (!effect) {
return;
}
aEffectChain.mPrimaryEffect = effect;
nsIntRegion tmpRegion;
const nsIntRegion* renderRegion;
if (PaintWillResample()) {
// If we're resampling, then the texture image will contain exactly the
// entire visible region's bounds, and we should draw it all in one quad
// to avoid unexpected aliasing.
tmpRegion = aVisibleRegion->GetBounds();
renderRegion = &tmpRegion;
} else {
renderRegion = aVisibleRegion;
}
nsIntRegion region(*renderRegion);
nsIntPoint origin = GetOriginOffset();
// translate into TexImage space, buffer origin might not be at texture (0,0)
region.MoveBy(-origin);
// Figure out the intersecting draw region
gfx::IntSize texSize = mSource->GetSize();
nsIntRect textureRect = nsIntRect(0, 0, texSize.width, texSize.height);
textureRect.MoveBy(region.GetBounds().TopLeft());
nsIntRegion subregion;
subregion.And(region, textureRect);
if (subregion.IsEmpty()) {
// Region is empty, nothing to draw
return;
}
nsIntRegion screenRects;
nsIntRegion regionRects;
// Collect texture/screen coordinates for drawing
nsIntRegionRectIterator iter(subregion);
while (const nsIntRect* iterRect = iter.Next()) {
nsIntRect regionRect = *iterRect;
nsIntRect screenRect = regionRect;
screenRect.MoveBy(origin);
screenRects.Or(screenRects, screenRect);
regionRects.Or(regionRects, regionRect);
}
BigImageIterator* bigImgIter = mSource->AsBigImageIterator();
BigImageIterator* iterOnWhite = nullptr;
if (bigImgIter) {
bigImgIter->BeginBigImageIteration();
}
if (mSourceOnWhite) {
iterOnWhite = mSourceOnWhite->AsBigImageIterator();
MOZ_ASSERT(!bigImgIter || bigImgIter->GetTileCount() == iterOnWhite->GetTileCount(),
"Tile count mismatch on component alpha texture");
if (iterOnWhite) {
iterOnWhite->BeginBigImageIteration();
}
}
bool usingTiles = (bigImgIter && bigImgIter->GetTileCount() > 1);
do {
if (iterOnWhite) {
MOZ_ASSERT(iterOnWhite->GetTileRect() == bigImgIter->GetTileRect(),
"component alpha textures should be the same size.");
}
nsIntRect texRect = bigImgIter ? bigImgIter->GetTileRect()
: nsIntRect(0, 0,
texSize.width,
texSize.height);
// Draw texture. If we're using tiles, we do repeating manually, as texture
// repeat would cause each individual tile to repeat instead of the
// compound texture as a whole. This involves drawing at most 4 sections,
// 2 for each axis that has texture repeat.
for (int y = 0; y < (usingTiles ? 2 : 1); y++) {
for (int x = 0; x < (usingTiles ? 2 : 1); x++) {
nsIntRect currentTileRect(texRect);
currentTileRect.MoveBy(x * texSize.width, y * texSize.height);
nsIntRegionRectIterator screenIter(screenRects);
nsIntRegionRectIterator regionIter(regionRects);
const nsIntRect* screenRect;
const nsIntRect* regionRect;
while ((screenRect = screenIter.Next()) &&
(regionRect = regionIter.Next())) {
nsIntRect tileScreenRect(*screenRect);
nsIntRect tileRegionRect(*regionRect);
// When we're using tiles, find the intersection between the tile
// rect and this region rect. Tiling is then handled by the
// outer for-loops and modifying the tile rect.
if (usingTiles) {
tileScreenRect.MoveBy(-origin);
tileScreenRect = tileScreenRect.Intersect(currentTileRect);
tileScreenRect.MoveBy(origin);
if (tileScreenRect.IsEmpty())
continue;
tileRegionRect = regionRect->Intersect(currentTileRect);
tileRegionRect.MoveBy(-currentTileRect.TopLeft());
}
gfx::Rect rect(tileScreenRect.x, tileScreenRect.y,
tileScreenRect.width, tileScreenRect.height);
effect->mTextureCoords = Rect(Float(tileRegionRect.x) / texRect.width,
Float(tileRegionRect.y) / texRect.height,
Float(tileRegionRect.width) / texRect.width,
Float(tileRegionRect.height) / texRect.height);
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform);
if (usingTiles) {
DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE;
if (iterOnWhite) {
diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
}
GetCompositor()->DrawDiagnostics(diagnostics, rect, aClipRect,
aTransform, mFlashCounter);
}
}
}
}
if (iterOnWhite) {
iterOnWhite->NextTile();
}
} while (usingTiles && bigImgIter->NextTile());
if (bigImgIter) {
bigImgIter->EndBigImageIteration();
}
if (iterOnWhite) {
iterOnWhite->EndBigImageIteration();
}
DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT;
if (iterOnWhite) {
diagnostics |= DiagnosticFlags::COMPONENT_ALPHA;
}
GetCompositor()->DrawDiagnostics(diagnostics, nsIntRegion(mBufferRect), aClipRect,
aTransform, mFlashCounter);
}
void
ContentHostIncremental::FlushUpdateQueue()
{
// If we're not compositing for some reason (the window being minimized
// is one example), then we never process these updates and it can consume
// huge amounts of memory. Instead we forcibly process the updates (during the
// transaction) if the list gets too long.
static const uint32_t kMaxUpdateCount = 6;
if (mUpdateList.Length() >= kMaxUpdateCount) {
ProcessTextureUpdates();
}
}
void
ContentHostIncremental::ProcessTextureUpdates()
{
for (uint32_t i = 0; i < mUpdateList.Length(); i++) {
mUpdateList[i]->Execute(this);
}
mUpdateList.Clear();
}
void
ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental* aHost)
{
Compositor* compositor = aHost->GetCompositor();
MOZ_ASSERT(compositor);
RefPtr<DataTextureSource> temp =
compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
MOZ_ASSERT(temp->AsSourceOGL() &&
temp->AsSourceOGL()->AsTextureImageTextureSource());
RefPtr<TextureImageTextureSourceOGL> newSource =
temp->AsSourceOGL()->AsTextureImageTextureSource();
RefPtr<TextureImageTextureSourceOGL> newSourceOnWhite;
if (mTextureInfo.mTextureFlags & TextureFlags::COMPONENT_ALPHA) {
temp =
compositor->CreateDataTextureSource(mTextureInfo.mTextureFlags);
MOZ_ASSERT(temp->AsSourceOGL() &&
temp->AsSourceOGL()->AsTextureImageTextureSource());
newSourceOnWhite = temp->AsSourceOGL()->AsTextureImageTextureSource();
}
if (mTextureInfo.mDeprecatedTextureHostFlags & DeprecatedTextureHostFlags::COPY_PREVIOUS) {
MOZ_ASSERT(aHost->mSource);
MOZ_ASSERT(aHost->mSource->IsValid());
nsIntRect bufferRect = aHost->mBufferRect;
nsIntPoint bufferRotation = aHost->mBufferRotation;
nsIntRect overlap;
// The buffer looks like:
// ______
// |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner.
// |___|__|
// |3 |4 |
// |___|__|
//
// This is drawn to the screen as:
// ______
// |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
// |___|__| from the top left corner - rotationPoint.
// |2 |1 |
// |___|__|
//
// The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles
// in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified.
nsIntRect srcBufferSpaceBottomRight(bufferRotation.x, bufferRotation.y, bufferRect.width - bufferRotation.x, bufferRect.height - bufferRotation.y);
nsIntRect srcBufferSpaceTopRight(bufferRotation.x, 0, bufferRect.width - bufferRotation.x, bufferRotation.y);
nsIntRect srcBufferSpaceTopLeft(0, 0, bufferRotation.x, bufferRotation.y);
nsIntRect srcBufferSpaceBottomLeft(0, bufferRotation.y, bufferRotation.x, bufferRect.height - bufferRotation.y);
overlap.IntersectRect(bufferRect, mBufferRect);
nsIntRect srcRect(overlap), dstRect(overlap);
srcRect.MoveBy(- bufferRect.TopLeft() + bufferRotation);
nsIntRect srcRectDrawTopRight(srcRect);
nsIntRect srcRectDrawTopLeft(srcRect);
nsIntRect srcRectDrawBottomLeft(srcRect);
// transform into the different quadrants
srcRectDrawTopRight .MoveBy(-nsIntPoint(0, bufferRect.height));
srcRectDrawTopLeft .MoveBy(-nsIntPoint(bufferRect.width, bufferRect.height));
srcRectDrawBottomLeft.MoveBy(-nsIntPoint(bufferRect.width, 0));
// Intersect with the quadrant
srcRect = srcRect .Intersect(srcBufferSpaceBottomRight);
srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight);
srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft);
srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft);
dstRect = srcRect;
nsIntRect dstRectDrawTopRight(srcRectDrawTopRight);
nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft);
nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft);
// transform back to src buffer space
dstRect .MoveBy(-bufferRotation);
dstRectDrawTopRight .MoveBy(-bufferRotation + nsIntPoint(0, bufferRect.height));
dstRectDrawTopLeft .MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, bufferRect.height));
dstRectDrawBottomLeft.MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, 0));
// transform back to draw coordinates
dstRect .MoveBy(bufferRect.TopLeft());
dstRectDrawTopRight .MoveBy(bufferRect.TopLeft());
dstRectDrawTopLeft .MoveBy(bufferRect.TopLeft());
dstRectDrawBottomLeft.MoveBy(bufferRect.TopLeft());
// transform to destBuffer space
dstRect .MoveBy(-mBufferRect.TopLeft());
dstRectDrawTopRight .MoveBy(-mBufferRect.TopLeft());
dstRectDrawTopLeft .MoveBy(-mBufferRect.TopLeft());
dstRectDrawBottomLeft.MoveBy(-mBufferRect.TopLeft());
newSource->EnsureBuffer(mBufferRect.Size(),
ContentForFormat(aHost->mSource->GetFormat()));
aHost->mSource->CopyTo(srcRect, newSource, dstRect);
if (bufferRotation != nsIntPoint(0, 0)) {
// Draw the remaining quadrants. We call BlitTextureImage 3 extra
// times instead of doing a single draw call because supporting that
// with a tiled source is quite tricky.
if (!srcRectDrawTopRight.IsEmpty())
aHost->mSource->CopyTo(srcRectDrawTopRight,
newSource, dstRectDrawTopRight);
if (!srcRectDrawTopLeft.IsEmpty())
aHost->mSource->CopyTo(srcRectDrawTopLeft,
newSource, dstRectDrawTopLeft);
if (!srcRectDrawBottomLeft.IsEmpty())
aHost->mSource->CopyTo(srcRectDrawBottomLeft,
newSource, dstRectDrawBottomLeft);
}
if (newSourceOnWhite) {
newSourceOnWhite->EnsureBuffer(mBufferRect.Size(),
ContentForFormat(aHost->mSourceOnWhite->GetFormat()));
aHost->mSourceOnWhite->CopyTo(srcRect, newSourceOnWhite, dstRect);
if (bufferRotation != nsIntPoint(0, 0)) {
// draw the remaining quadrants
if (!srcRectDrawTopRight.IsEmpty())
aHost->mSourceOnWhite->CopyTo(srcRectDrawTopRight,
newSourceOnWhite, dstRectDrawTopRight);
if (!srcRectDrawTopLeft.IsEmpty())
aHost->mSourceOnWhite->CopyTo(srcRectDrawTopLeft,
newSourceOnWhite, dstRectDrawTopLeft);
if (!srcRectDrawBottomLeft.IsEmpty())
aHost->mSourceOnWhite->CopyTo(srcRectDrawBottomLeft,
newSourceOnWhite, dstRectDrawBottomLeft);
}
}
}
aHost->mSource = newSource;
aHost->mSourceOnWhite = newSourceOnWhite;
aHost->mBufferRect = mBufferRect;
aHost->mBufferRotation = nsIntPoint();
}
nsIntRect
ContentHostIncremental::TextureUpdateRequest::GetQuadrantRectangle(XSide aXSide,
YSide aYSide) const
{
// quadrantTranslation is the amount we translate the top-left
// of the quadrant by to get coordinates relative to the layer
nsIntPoint quadrantTranslation = -mBufferRotation;
quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0;
quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0;
return mBufferRect + quadrantTranslation;
}
void
ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aHost)
{
nsIntRect drawBounds = mUpdated.GetBounds();
aHost->mBufferRect = mBufferRect;
aHost->mBufferRotation = mBufferRotation;
// Figure out which quadrant to draw in
int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT;
YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP;
nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants");
mUpdated.MoveBy(-nsIntPoint(quadrantRect.x, quadrantRect.y));
IntPoint offset = ToIntPoint(-mUpdated.GetBounds().TopLeft());
RefPtr<DataSourceSurface> surf = GetSurfaceForDescriptor(mDescriptor);
if (mTextureId == TextureIdentifier::Front) {
aHost->mSource->Update(surf, &mUpdated, &offset);
} else {
aHost->mSourceOnWhite->Update(surf, &mUpdated, &offset);
}
}
void
ContentHostIncremental::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{
aStream << aPrefix;
aStream << nsPrintfCString("ContentHostIncremental (0x%p)", this).get();
if (PaintWillResample()) {
aStream << " [paint-will-resample]";
}
}
void
ContentHostTexture::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{
@ -869,15 +446,6 @@ ContentHostTexture::GenEffect(const gfx::Filter& aFilter)
aFilter, true);
}
TemporaryRef<TexturedEffect>
ContentHostIncremental::GenEffect(const gfx::Filter& aFilter)
{
if (!mSource) {
return nullptr;
}
return CreateTexturedEffect(mSource, mSourceOnWhite, aFilter, true);
}
TemporaryRef<gfx::DataSourceSurface>
ContentHostTexture::GetAsSurface()
{

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

@ -223,160 +223,6 @@ public:
nsIntRegion* aUpdatedRegionBack);
};
/**
* Maintains a host-side only texture, and gets provided with
* surfaces that only cover the changed pixels during an update.
*
* Takes ownership of the passed in update surfaces, and must
* free them once texture upload is complete.
*
* Delays texture uploads until the next composite to
* avoid blocking the main thread.
*/
class ContentHostIncremental : public ContentHostBase
{
public:
explicit ContentHostIncremental(const TextureInfo& aTextureInfo);
~ContentHostIncremental();
virtual CompositableType GetType() MOZ_OVERRIDE { return CompositableType::CONTENT_INC; }
virtual LayerRenderState GetRenderState() MOZ_OVERRIDE { return LayerRenderState(); }
virtual bool CreatedIncrementalTexture(ISurfaceAllocator* aAllocator,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) MOZ_OVERRIDE;
virtual void UpdateIncremental(TextureIdentifier aTextureId,
SurfaceDescriptor& aSurface,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) MOZ_OVERRIDE;
virtual bool UpdateThebes(const ThebesBufferData& aData,
const nsIntRegion& aUpdated,
const nsIntRegion& aOldValidRegionBack,
nsIntRegion* aUpdatedRegionBack) MOZ_OVERRIDE
{
NS_ERROR("Shouldn't call this");
return false;
}
virtual void Composite(EffectChain& aEffectChain,
float aOpacity,
const gfx::Matrix4x4& aTransform,
const gfx::Filter& aFilter,
const gfx::Rect& aClipRect,
const nsIntRegion* aVisibleRegion = nullptr) MOZ_OVERRIDE;
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
virtual bool Lock() MOZ_OVERRIDE {
MOZ_ASSERT(!mLocked);
ProcessTextureUpdates();
mLocked = true;
return true;
}
virtual void Unlock() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked);
mLocked = false;
}
virtual TemporaryRef<TexturedEffect>
GenEffect(const gfx::Filter& aFilter) MOZ_OVERRIDE;
private:
void FlushUpdateQueue();
void ProcessTextureUpdates();
class Request
{
public:
Request()
{
MOZ_COUNT_CTOR(ContentHostIncremental::Request);
}
virtual ~Request()
{
MOZ_COUNT_DTOR(ContentHostIncremental::Request);
}
virtual void Execute(ContentHostIncremental *aHost) = 0;
};
class TextureCreationRequest : public Request
{
public:
TextureCreationRequest(const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
: mTextureInfo(aTextureInfo)
, mBufferRect(aBufferRect)
{}
virtual void Execute(ContentHostIncremental *aHost);
private:
TextureInfo mTextureInfo;
nsIntRect mBufferRect;
};
class TextureUpdateRequest : public Request
{
public:
TextureUpdateRequest(ISurfaceAllocator* aDeAllocator,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdated,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
: mDeAllocator(aDeAllocator)
, mTextureId(aTextureId)
, mDescriptor(aDescriptor)
, mUpdated(aUpdated)
, mBufferRect(aBufferRect)
, mBufferRotation(aBufferRotation)
{}
~TextureUpdateRequest()
{
//TODO: Recycle these?
mDeAllocator->DestroySharedSurface(&mDescriptor);
}
virtual void Execute(ContentHostIncremental *aHost);
private:
enum XSide {
LEFT, RIGHT
};
enum YSide {
TOP, BOTTOM
};
nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
RefPtr<ISurfaceAllocator> mDeAllocator;
TextureIdentifier mTextureId;
SurfaceDescriptor mDescriptor;
nsIntRegion mUpdated;
nsIntRect mBufferRect;
nsIntPoint mBufferRotation;
};
nsTArray<UniquePtr<Request> > mUpdateList;
// Specific to OGL to avoid exposing methods on TextureSource that only
// have one implementation.
RefPtr<TextureImageTextureSourceOGL> mSource;
RefPtr<TextureImageTextureSourceOGL> mSourceOnWhite;
RefPtr<ISurfaceAllocator> mDeAllocator;
bool mLocked;
};
}
}

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

@ -53,7 +53,6 @@ bool
PaintedLayerComposite::SetCompositableHost(CompositableHost* aHost)
{
switch (aHost->GetType()) {
case CompositableType::CONTENT_INC:
case CompositableType::CONTENT_TILED:
case CompositableType::CONTENT_SINGLE:
case CompositableType::CONTENT_DOUBLE:

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

@ -55,14 +55,6 @@ public:
*/
virtual void Connect(CompositableClient* aCompositable) = 0;
/**
* Notify the CompositableHost that it should create host-side-only
* texture(s), that we will update incrementally using UpdateTextureIncremental.
*/
virtual void CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) = 0;
/**
* Tell the CompositableHost on the compositor side what TiledLayerBuffer to
* use for the next composition.
@ -83,23 +75,6 @@ public:
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) = 0;
/**
* Notify the compositor to update aTextureId using aDescriptor, and take
* ownership of aDescriptor.
*
* aDescriptor only contains the pixels for aUpdatedRegion, and is relative
* to aUpdatedRegion.TopLeft().
*
* aBufferRect/aBufferRotation define the new valid region contained
* within the texture after the update has been applied.
*/
virtual void UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) = 0;
/**
* Communicate the picture rect of a YUV image in aLayer to the compositor
*/

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

@ -73,20 +73,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
EditReplyVector& replyv)
{
switch (aEdit.type()) {
case CompositableOperation::TOpCreatedIncrementalTexture: {
MOZ_LAYERS_LOG(("[ParentSide] Created texture"));
const OpCreatedIncrementalTexture& op = aEdit.get_OpCreatedIncrementalTexture();
CompositableHost* compositable = AsCompositable(op);
bool success =
compositable->CreatedIncrementalTexture(this,
op.textureInfo(),
op.bufferRect());
if (!success) {
return false;
}
break;
}
case CompositableOperation::TOpPaintTextureRegion: {
MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer"));
@ -116,22 +102,6 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
RenderTraceInvalidateEnd(thebes, "FF00FF");
break;
}
case CompositableOperation::TOpPaintTextureIncremental: {
MOZ_LAYERS_LOG(("[ParentSide] Paint PaintedLayer"));
const OpPaintTextureIncremental& op = aEdit.get_OpPaintTextureIncremental();
CompositableHost* compositable = AsCompositable(op);
SurfaceDescriptor desc = op.image();
compositable->UpdateIncremental(op.textureId(),
desc,
op.updatedRegion(),
op.bufferRect(),
op.bufferRotation());
break;
}
case CompositableOperation::TOpUpdatePictureRect: {
const OpUpdatePictureRect& op = aEdit.get_OpUpdatePictureRect();
CompositableHost* compositable = AsCompositable(op);

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

@ -541,17 +541,6 @@ ImageBridgeChild::EndTransaction()
for (nsTArray<EditReply>::size_type i = 0; i < replies.Length(); ++i) {
const EditReply& reply = replies[i];
switch (reply.type()) {
case EditReply::TOpTextureSwap: {
const OpTextureSwap& ots = reply.get_OpTextureSwap();
CompositableClient* compositable =
CompositableClient::FromIPDLActor(ots.compositableChild());
MOZ_ASSERT(compositable);
compositable->SetDescriptorFromReply(ots.textureId(), ots.image());
break;
}
case EditReply::TReturnReleaseFence: {
const ReturnReleaseFence& rep = reply.get_ReturnReleaseFence();
FenceHandle fence = rep.fence();

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

@ -13,7 +13,7 @@
#include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc
#include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/CompositorTypes.h" // for TextureIdentifier, etc
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/PImageBridgeChild.h"
#include "nsDebug.h" // for NS_RUNTIMEABORT
#include "nsRegion.h" // for nsIntRegion
@ -248,16 +248,6 @@ public:
NS_RUNTIMEABORT("should not be called");
}
virtual void UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) MOZ_OVERRIDE
{
NS_RUNTIMEABORT("should not be called");
}
/**
* Communicate the picture rect of a YUV image in aLayer to the compositor
*/
@ -265,12 +255,6 @@ public:
const nsIntRect& aRect) MOZ_OVERRIDE;
virtual void CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) MOZ_OVERRIDE
{
NS_RUNTIMEABORT("should not be called");
}
virtual void UpdateTextureRegion(CompositableClient* aCompositable,
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) MOZ_OVERRIDE {

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

@ -41,7 +41,6 @@ using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
using struct mozilla::layers::FenceHandle from "mozilla/layers/FenceUtils.h";
using struct mozilla::layers::FenceHandleFromChild from "mozilla/layers/FenceUtils.h";
using mozilla::layers::TextureIdentifier from "mozilla/layers/CompositorTypes.h";
using std::string from "string";
namespace mozilla {
@ -339,27 +338,12 @@ struct OpUseOverlaySource {
OverlaySource overlay;
};
struct OpCreatedIncrementalTexture {
PCompositable compositable;
TextureInfo textureInfo;
nsIntRect bufferRect;
};
struct OpPaintTextureRegion {
PCompositable compositable;
ThebesBufferData bufferData;
nsIntRegion updatedRegion;
};
struct OpPaintTextureIncremental {
PCompositable compositable;
TextureIdentifier textureId;
SurfaceDescriptor image;
nsIntRegion updatedRegion;
nsIntRect bufferRect;
nsIntPoint bufferRotation;
};
struct OpUpdatePictureRect {
PCompositable compositable;
nsIntRect picture;
@ -438,10 +422,7 @@ struct OpReplyDeliverFence {
union CompositableOperation {
OpUpdatePictureRect;
OpCreatedIncrementalTexture;
OpPaintTextureRegion;
OpPaintTextureIncremental;
OpUseTiledLayerBuffer;
@ -487,12 +468,6 @@ struct OpContentBufferSwap {
nsIntRegion frontUpdatedRegion;
};
struct OpTextureSwap {
PCompositable compositable;
TextureIdentifier textureId;
SurfaceDescriptor image;
};
struct ReturnReleaseFence {
PCompositable compositable;
PTexture texture;
@ -503,7 +478,6 @@ struct ReturnReleaseFence {
// only to be used for buffer swapping.
union EditReply {
OpContentBufferSwap;
OpTextureSwap;
ReturnReleaseFence;
};

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

@ -352,26 +352,6 @@ ShadowLayerForwarder::UpdateTextureRegion(CompositableClient* aCompositable,
aUpdatedRegion));
}
void
ShadowLayerForwarder::UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation)
{
CheckSurfaceDescriptor(&aDescriptor);
MOZ_ASSERT(aCompositable);
MOZ_ASSERT(aCompositable->GetIPDLActor());
mTxn->AddNoSwapPaint(OpPaintTextureIncremental(nullptr, aCompositable->GetIPDLActor(),
aTextureId,
aDescriptor,
aUpdatedRegion,
aBufferRect,
aBufferRotation));
}
void
ShadowLayerForwarder::UpdatePictureRect(CompositableClient* aCompositable,
const nsIntRect& aRect)
@ -815,16 +795,6 @@ ShadowLayerForwarder::Connect(CompositableClient* aCompositable)
aCompositable->InitIPDLActor(actor);
}
void
ShadowLayerForwarder::CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect)
{
MOZ_ASSERT(aCompositable);
mTxn->AddNoSwapPaint(OpCreatedIncrementalTexture(nullptr, aCompositable->GetIPDLActor(),
aTextureInfo, aBufferRect));
}
void ShadowLayerForwarder::Attach(CompositableClient* aCompositable,
ShadowableLayer* aLayer)
{

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

@ -133,7 +133,6 @@ class Transaction;
class ShadowLayerForwarder : public CompositableForwarder
{
friend class ContentClientIncremental;
friend class ClientLayerManager;
public:
@ -148,10 +147,6 @@ public:
virtual PTextureChild* CreateTexture(const SurfaceDescriptor& aSharedData,
TextureFlags aFlags) MOZ_OVERRIDE;
virtual void CreatedIncrementalBuffer(CompositableClient* aCompositable,
const TextureInfo& aTextureInfo,
const nsIntRect& aBufferRect) MOZ_OVERRIDE;
/**
* Adds an edit in the layers transaction in order to attach
* the corresponding compositable and layer on the compositor side.
@ -259,13 +254,6 @@ public:
const ThebesBufferData& aThebesBufferData,
const nsIntRegion& aUpdatedRegion) MOZ_OVERRIDE;
virtual void UpdateTextureIncremental(CompositableClient* aCompositable,
TextureIdentifier aTextureId,
SurfaceDescriptor& aDescriptor,
const nsIntRegion& aUpdatedRegion,
const nsIntRect& aBufferRect,
const nsIntPoint& aBufferRotation) MOZ_OVERRIDE;
/**
* Communicate the picture rect of an image to the compositor
*/

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

@ -279,7 +279,8 @@ struct ForEachTrackedOptimizationAttemptOp
JS_PUBLIC_API(void)
ForEachTrackedOptimizationAttempt(JSRuntime *rt, void *addr,
ForEachTrackedOptimizationAttemptOp &op);
ForEachTrackedOptimizationAttemptOp &op,
JSScript **scriptOut, jsbytecode **pcOut);
struct ForEachTrackedOptimizationTypeInfoOp
{
@ -293,15 +294,28 @@ struct ForEachTrackedOptimizationTypeInfoOp
// function.
// - "alloc site" for object types tied to an allocation site.
// - "prototype" for object types tied neither to a constructor nor
// to an allocation site.
// to an allocation site, but to a prototype.
// - "singleton" for object types which only has a single value.
// - "function" for object types referring to scripted functions.
// - "native" for object types referring to native functions.
//
// The name parameter is the string representation of the type. If the
// type is keyed by "constructor", or if the type itself refers to a
// scripted function, the name is the function's displayAtom.
// scripted function, the name is the function's displayAtom. If the type
// is keyed by "native", this is nullptr.
//
// If the type is keyed by "constructor", "alloc site", or if the type
// itself refers to a scripted function, the location and lineno
// parameters will be respectively non-nullptr and non-0.
// The location parameter is the filename if the type is keyed by
// "constructor", "alloc site", or if the type itself refers to a scripted
// function. If the type is keyed by "native", it is the offset of the
// native function, suitable for use with addr2line on Linux or atos on OS
// X. Otherwise it is nullptr.
//
// The lineno parameter is the line number if the type is keyed by
// "constructor", "alloc site", or if the type itself refers to a scripted
// function. Otherwise it is UINT32_MAX.
//
// The location parameter is the only one that may need escaping if being
// quoted.
virtual void readType(const char *keyedBy, const char *name,
const char *location, unsigned lineno) = 0;

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

@ -6,6 +6,7 @@
#include "ctypes/Library.h"
#include "prerror.h"
#include "prlink.h"
#include "ctypes/CTypes.h"
@ -146,12 +147,17 @@ Library::Create(JSContext* cx, jsval path_, const JSCTypesCallbacks* callbacks)
PRLibrary* library = PR_LoadLibraryWithFlags(libSpec, 0);
if (!library) {
char *error = (char*) JS_malloc(cx, PR_GetErrorTextLength() + 1);
if (error)
PR_GetErrorText(error);
#ifdef XP_WIN
JS_ReportError(cx, "couldn't open library %hs", pathChars);
JS_ReportError(cx, "couldn't open library %hs: %s", pathChars, error);
#else
JS_ReportError(cx, "couldn't open library %s", pathBytes);
JS_ReportError(cx, "couldn't open library %s: %s", pathBytes, error);
JS_free(cx, pathBytes);
#endif
JS_free(cx, error);
return nullptr;
}

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

@ -81,6 +81,8 @@ var ignoreCallees = {
"PLDHashTableOps.hashKey" : true,
"z_stream_s.zfree" : true,
"GrGLInterface.fCallback" : true,
"std::strstreambuf._M_alloc_fun" : true,
"std::strstreambuf._M_free_fun" : true,
};
function fieldCallCannotGC(csu, fullfield)
@ -137,6 +139,10 @@ var ignoreFunctions = {
"JSObject* js::GetWeakmapKeyDelegate(JSObject*)" : true, // FIXME: mark with AutoSuppressGCAnalysis instead
"uint8 NS_IsMainThread()" : true,
// Has an indirect call under it by the name "__f", which seemed too
// generic to ignore by itself.
"void* std::_Locale_impl::~_Locale_impl(int32)" : true,
// FIXME!
"NS_LogInit": true,
"NS_LogTerm": true,

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

@ -921,7 +921,7 @@ class GCRuntime
void protectRelocatedArenas(ArenaHeader *relocatedList);
void unprotectRelocatedArenas(ArenaHeader *relocatedList);
#endif
void finishCollection();
void finishCollection(JS::gcreason::Reason reason);
void computeNonIncrementalMarkingForValidation();
void validateIncrementalMarking();

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

@ -20,19 +20,28 @@
namespace js {
namespace jit {
static inline JitcodeRegionEntry
RegionAtAddr(const JitcodeGlobalEntry::IonEntry &entry, void *ptr,
uint32_t *ptrOffset)
{
MOZ_ASSERT(entry.containsPointer(ptr));
*ptrOffset = reinterpret_cast<uint8_t *>(ptr) -
reinterpret_cast<uint8_t *>(entry.nativeStartAddr());
uint32_t regionIdx = entry.regionTable()->findRegionEntry(*ptrOffset);
MOZ_ASSERT(regionIdx < entry.regionTable()->numRegions());
return entry.regionTable()->regionEntry(regionIdx);
}
bool
JitcodeGlobalEntry::IonEntry::callStackAtAddr(JSRuntime *rt, void *ptr,
BytecodeLocationVector &results,
uint32_t *depth) const
{
MOZ_ASSERT(containsPointer(ptr));
uint32_t ptrOffset = reinterpret_cast<uint8_t *>(ptr) -
reinterpret_cast<uint8_t *>(nativeStartAddr());
uint32_t regionIdx = regionTable()->findRegionEntry(ptrOffset);
MOZ_ASSERT(regionIdx < regionTable()->numRegions());
JitcodeRegionEntry region = regionTable()->regionEntry(regionIdx);
uint32_t ptrOffset;
JitcodeRegionEntry region = RegionAtAddr(*this, ptr, &ptrOffset);
*depth = region.scriptDepth();
JitcodeRegionEntry::ScriptPcIterator locationIter = region.scriptPcIterator();
@ -61,15 +70,10 @@ JitcodeGlobalEntry::IonEntry::callStackAtAddr(JSRuntime *rt, void *ptr,
const char **results,
uint32_t maxResults) const
{
MOZ_ASSERT(containsPointer(ptr));
MOZ_ASSERT(maxResults >= 1);
uint32_t ptrOffset = reinterpret_cast<uint8_t *>(ptr) -
reinterpret_cast<uint8_t *>(nativeStartAddr());
uint32_t regionIdx = regionTable()->findRegionEntry(ptrOffset);
MOZ_ASSERT(regionIdx < regionTable()->numRegions());
JitcodeRegionEntry region = regionTable()->regionEntry(regionIdx);
uint32_t ptrOffset;
JitcodeRegionEntry region = RegionAtAddr(*this, ptr, &ptrOffset);
JitcodeRegionEntry::ScriptPcIterator locationIter = region.scriptPcIterator();
MOZ_ASSERT(locationIter.hasMore());
@ -88,6 +92,23 @@ JitcodeGlobalEntry::IonEntry::callStackAtAddr(JSRuntime *rt, void *ptr,
return count;
}
void
JitcodeGlobalEntry::IonEntry::youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script, jsbytecode **pc) const
{
uint32_t ptrOffset;
JitcodeRegionEntry region = RegionAtAddr(*this, ptr, &ptrOffset);
JitcodeRegionEntry::ScriptPcIterator locationIter = region.scriptPcIterator();
MOZ_ASSERT(locationIter.hasMore());
uint32_t scriptIdx, pcOffset;
locationIter.readNext(&scriptIdx, &pcOffset);
pcOffset = region.findPcOffset(ptrOffset, pcOffset);
*script = getScript(scriptIdx);
*pc = (*script)->offsetToPC(pcOffset);
}
void
JitcodeGlobalEntry::IonEntry::destroy()
{
@ -155,6 +176,16 @@ JitcodeGlobalEntry::BaselineEntry::callStackAtAddr(JSRuntime *rt, void *ptr,
return 1;
}
void
JitcodeGlobalEntry::BaselineEntry::youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script,
jsbytecode **pc) const
{
uint8_t *addr = reinterpret_cast<uint8_t*>(ptr);
*script = script_;
*pc = script_->baselineScript()->approximatePcForNativeAddress(script_, addr);
}
void
JitcodeGlobalEntry::BaselineEntry::destroy()
{
@ -164,19 +195,25 @@ JitcodeGlobalEntry::BaselineEntry::destroy()
str_ = nullptr;
}
static inline void
RejoinEntry(JSRuntime *rt, const JitcodeGlobalEntry::IonCacheEntry &cache,
void *ptr, JitcodeGlobalEntry *entry)
{
MOZ_ASSERT(cache.containsPointer(ptr));
// There must exist an entry for the rejoin addr if this entry exists.
JitRuntime *jitrt = rt->jitRuntime();
jitrt->getJitcodeGlobalTable()->lookupInfallible(cache.rejoinAddr(), entry, rt);
MOZ_ASSERT(entry->isIon());
}
bool
JitcodeGlobalEntry::IonCacheEntry::callStackAtAddr(JSRuntime *rt, void *ptr,
BytecodeLocationVector &results,
uint32_t *depth) const
{
MOZ_ASSERT(containsPointer(ptr));
// There must exist an entry for the rejoin addr if this entry exists.
JitRuntime *jitrt = rt->jitRuntime();
JitcodeGlobalEntry entry;
jitrt->getJitcodeGlobalTable()->lookupInfallible(rejoinAddr(), &entry, rt);
MOZ_ASSERT(entry.isIon());
RejoinEntry(rt, *this, ptr, &entry);
return entry.callStackAtAddr(rt, rejoinAddr(), results, depth);
}
@ -185,17 +222,21 @@ JitcodeGlobalEntry::IonCacheEntry::callStackAtAddr(JSRuntime *rt, void *ptr,
const char **results,
uint32_t maxResults) const
{
MOZ_ASSERT(containsPointer(ptr));
// There must exist an entry for the rejoin addr if this entry exists.
JitRuntime *jitrt = rt->jitRuntime();
JitcodeGlobalEntry entry;
jitrt->getJitcodeGlobalTable()->lookupInfallible(rejoinAddr(), &entry, rt);
MOZ_ASSERT(entry.isIon());
RejoinEntry(rt, *this, ptr, &entry);
return entry.callStackAtAddr(rt, rejoinAddr(), results, maxResults);
}
void
JitcodeGlobalEntry::IonCacheEntry::youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script,
jsbytecode **pc) const
{
JitcodeGlobalEntry entry;
RejoinEntry(rt, *this, ptr, &entry);
return entry.youngestFrameLocationAtAddr(rt, ptr, script, pc);
}
static int ComparePointers(const void *a, const void *b) {
const uint8_t *a_ptr = reinterpret_cast<const uint8_t *>(a);

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

@ -210,10 +210,23 @@ class JitcodeGlobalEntry
uint32_t callStackAtAddr(JSRuntime *rt, void *ptr, const char **results,
uint32_t maxResults) const;
void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script, jsbytecode **pc) const;
bool hasTrackedOptimizations() const {
return !!optsRegionTable_;
}
const IonTrackedOptimizationsRegionTable *trackedOptimizationsRegionTable() const {
MOZ_ASSERT(hasTrackedOptimizations());
return optsRegionTable_;
}
uint8_t numOptimizationAttempts() const {
MOZ_ASSERT(hasTrackedOptimizations());
return optsAttemptsTable_->numEntries();
}
IonTrackedOptimizationsAttempts trackedOptimizationAttempts(uint8_t index) {
MOZ_ASSERT(hasTrackedOptimizations());
return optsAttemptsTable_->entry(index);
@ -278,6 +291,9 @@ class JitcodeGlobalEntry
uint32_t callStackAtAddr(JSRuntime *rt, void *ptr, const char **results,
uint32_t maxResults) const;
void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script, jsbytecode **pc) const;
};
struct IonCacheEntry : public BaseEntry
@ -302,6 +318,9 @@ class JitcodeGlobalEntry
uint32_t callStackAtAddr(JSRuntime *rt, void *ptr, const char **results,
uint32_t maxResults) const;
void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script, jsbytecode **pc) const;
};
// Dummy entries are created for jitcode generated when profiling is not turned on,
@ -326,6 +345,13 @@ class JitcodeGlobalEntry
{
return 0;
}
void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script, jsbytecode **pc) const
{
*script = nullptr;
*pc = nullptr;
}
};
// QueryEntry is never stored in the table, just used for queries
@ -551,6 +577,23 @@ class JitcodeGlobalEntry
return false;
}
void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
JSScript **script, jsbytecode **pc) const
{
switch (kind()) {
case Ion:
return ionEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
case Baseline:
return baselineEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
case IonCache:
return ionCacheEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
case Dummy:
return dummyEntry().youngestFrameLocationAtAddr(rt, ptr, script, pc);
default:
MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
}
}
// Figure out the number of the (JSScript *, jsbytecode *) pairs that are active
// at this location.
uint32_t lookupInlineCallDepth(void *ptr);

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

@ -1123,11 +1123,13 @@ IonBuilder::trackInlineSuccessUnchecked(InliningStatus status)
JS_PUBLIC_API(void)
JS::ForEachTrackedOptimizationAttempt(JSRuntime *rt, void *addr,
ForEachTrackedOptimizationAttemptOp &op)
ForEachTrackedOptimizationAttemptOp &op,
JSScript **scriptOut, jsbytecode **pcOut)
{
JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable();
JitcodeGlobalEntry entry;
table->lookupInfallible(addr, &entry, rt);
entry.youngestFrameLocationAtAddr(rt, addr, scriptOut, pcOut);
Maybe<uint8_t> index = entry.trackedOptimizationIndexAtAddr(addr);
entry.trackedOptimizationAttempts(index.value()).forEach(op);
}
@ -1143,11 +1145,11 @@ InterpretedFunctionFilenameAndLineNumber(JSFunction *fun, const char **filename,
source = fun->lazyScript()->maybeForwardedScriptSource();
*lineno = fun->lazyScript()->lineno();
}
*filename = source->introducerFilename();
*filename = source->filename();
}
static JSFunction *
InterpretedFunctionFromTrackedType(const IonTrackedTypeWithAddendum &tracked)
FunctionFromTrackedType(const IonTrackedTypeWithAddendum &tracked)
{
if (tracked.hasConstructor())
return tracked.constructor;
@ -1162,18 +1164,9 @@ InterpretedFunctionFromTrackedType(const IonTrackedTypeWithAddendum &tracked)
return ty.group()->maybeInterpretedFunction();
}
// This adapter is needed as the internal API can deal with engine-internal
// data structures directly, while the public API cannot.
class ForEachTypeInfoAdapter : public IonTrackedOptimizationsTypeInfo::ForEachOp
void
IonTrackedOptimizationsTypeInfo::ForEachOpAdapter::readType(const IonTrackedTypeWithAddendum &tracked)
{
ForEachTrackedOptimizationTypeInfoOp &op_;
public:
explicit ForEachTypeInfoAdapter(ForEachTrackedOptimizationTypeInfoOp &op)
: op_(op)
{ }
void readType(const IonTrackedTypeWithAddendum &tracked) MOZ_OVERRIDE {
TypeSet::Type ty = tracked.type;
if (ty.isPrimitive() || ty.isUnknown() || ty.isAnyObject()) {
@ -1184,7 +1177,32 @@ class ForEachTypeInfoAdapter : public IonTrackedOptimizationsTypeInfo::ForEachOp
char buf[512];
const uint32_t bufsize = mozilla::ArrayLength(buf);
if (JSFunction *fun = InterpretedFunctionFromTrackedType(tracked)) {
if (JSFunction *fun = FunctionFromTrackedType(tracked)) {
if (fun->isNative()) {
//
// Print out the absolute address of the function pointer.
//
// Note that this address is not usable without knowing the
// starting address at which our shared library is loaded. Shared
// library information is exposed by the profiler. If this address
// needs to be symbolicated manually (e.g., when it is gotten via
// debug spewing of all optimization information), it needs to be
// converted to an offset from the beginning of the shared library
// for use with utilities like `addr2line` on Linux and `atos` on
// OS X. Converting to an offset may be done via dladdr():
//
// void *addr = JS_FUNC_TO_DATA_PTR(void *, fun->native());
// uintptr_t offset;
// Dl_info info;
// if (dladdr(addr, &info) != 0)
// offset = uintptr_t(addr) - uintptr_t(info.dli_fbase);
//
uintptr_t addr = JS_FUNC_TO_DATA_PTR(uintptr_t, fun->native());
JS_snprintf(buf, bufsize, "%llx", addr);
op_.readType("native", nullptr, buf, UINT32_MAX);
return;
}
PutEscapedString(buf, bufsize, fun->displayAtom(), 0);
const char *filename;
unsigned lineno;
@ -1199,18 +1217,25 @@ class ForEachTypeInfoAdapter : public IonTrackedOptimizationsTypeInfo::ForEachOp
if (tracked.hasAllocationSite()) {
JSScript *script = tracked.script;
op_.readType("alloc site", buf,
script->maybeForwardedScriptSource()->introducerFilename(),
script->maybeForwardedScriptSource()->filename(),
PCToLineNumber(script, script->offsetToPC(tracked.offset)));
return;
}
op_.readType("prototype", buf, nullptr, 0);
if (ty.isGroup()) {
op_.readType("prototype", buf, nullptr, UINT32_MAX);
return;
}
void operator()(JS::TrackedTypeSite site, MIRType mirType) MOZ_OVERRIDE {
op_.readType("singleton", buf, nullptr, UINT32_MAX);
}
void
IonTrackedOptimizationsTypeInfo::ForEachOpAdapter::operator()(JS::TrackedTypeSite site,
MIRType mirType)
{
op_(site, StringFromMIRType(mirType));
}
};
JS_PUBLIC_API(void)
JS::ForEachTrackedOptimizationTypeInfo(JSRuntime *rt, void *addr,
@ -1219,7 +1244,7 @@ JS::ForEachTrackedOptimizationTypeInfo(JSRuntime *rt, void *addr,
JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable();
JitcodeGlobalEntry entry;
table->lookupInfallible(addr, &entry, rt);
ForEachTypeInfoAdapter adapter(op);
IonTrackedOptimizationsTypeInfo::ForEachOpAdapter adapter(op);
Maybe<uint8_t> index = entry.trackedOptimizationIndexAtAddr(addr);
entry.trackedOptimizationTypeInfo(index.value()).forEach(adapter, entry.allTrackedTypes());
}

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

@ -484,12 +484,27 @@ class IonTrackedOptimizationsTypeInfo
// JS::ForEachTrackedOptimizaitonTypeInfoOp cannot be used directly. The
// internal API needs to deal with engine-internal data structures (e.g.,
// TypeSet::Type) directly.
//
// An adapter is provided below.
struct ForEachOp
{
virtual void readType(const IonTrackedTypeWithAddendum &tracked) = 0;
virtual void operator()(JS::TrackedTypeSite site, MIRType mirType) = 0;
};
class ForEachOpAdapter : public ForEachOp
{
JS::ForEachTrackedOptimizationTypeInfoOp &op_;
public:
explicit ForEachOpAdapter(JS::ForEachTrackedOptimizationTypeInfoOp &op)
: op_(op)
{ }
void readType(const IonTrackedTypeWithAddendum &tracked) MOZ_OVERRIDE;
void operator()(JS::TrackedTypeSite site, MIRType mirType) MOZ_OVERRIDE;
};
void forEach(ForEachOp &op, const IonTrackedTypeVector *allTypes);
};

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

@ -5546,7 +5546,7 @@ GCRuntime::compactPhase(bool lastGC, JS::gcreason::Reason reason)
}
void
GCRuntime::finishCollection()
GCRuntime::finishCollection(JS::gcreason::Reason reason)
{
MOZ_ASSERT(marker.isDrained());
marker.stop();
@ -5566,6 +5566,13 @@ GCRuntime::finishCollection()
}
lastGCTime = currentTime;
// If this is an OOM GC reason, wait on the background sweeping thread
// before returning to ensure that we free as much as possible.
if (reason == JS::gcreason::LAST_DITCH || reason == JS::gcreason::MEM_PRESSURE) {
gcstats::AutoPhase ap(stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD);
rt->gc.waitBackgroundSweepOrAllocEnd();
}
}
/* Start a new heap session. */
@ -5933,7 +5940,7 @@ GCRuntime::incrementalCollectSlice(SliceBudget &budget, JS::gcreason::Reason rea
if (isCompacting && compactPhase(lastGC, reason) == NotFinished)
break;
finishCollection();
finishCollection(reason);
incrementalState = NO_INCREMENTAL;
break;

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

@ -60,9 +60,12 @@
#include "frontend/Parser.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/Ion.h"
#include "jit/JitcodeMap.h"
#include "jit/OptimizationTracking.h"
#include "js/Debug.h"
#include "js/GCAPI.h"
#include "js/StructuredClone.h"
#include "js/TrackedOptimizationInfo.h"
#include "perf/jsperf.h"
#include "shell/jsheaptools.h"
#include "shell/jsoptparse.h"
@ -4340,6 +4343,173 @@ SetSharedArrayBuffer(JSContext *cx, unsigned argc, Value *vp)
return true;
}
class SprintOptimizationTypeInfoOp : public ForEachTrackedOptimizationTypeInfoOp
{
Sprinter *sp;
bool startedTypes_;
public:
explicit SprintOptimizationTypeInfoOp(Sprinter *sp)
: sp(sp),
startedTypes_(false)
{ }
void readType(const char *keyedBy, const char *name,
const char *location, unsigned lineno) MOZ_OVERRIDE
{
if (!startedTypes_) {
startedTypes_ = true;
Sprint(sp, "{\"typeset\": [");
}
Sprint(sp, "{\"keyedBy\":\"%s\"", keyedBy);
if (name)
Sprint(sp, ",\"name\":\"%s\"", name);
if (location) {
char buf[512];
PutEscapedString(buf, mozilla::ArrayLength(buf), location, strlen(location), '"');
Sprint(sp, ",\"location\":%s", buf);
}
if (lineno != UINT32_MAX)
Sprint(sp, ",\"line\":%u", lineno);
Sprint(sp, "},");
}
void operator()(TrackedTypeSite site, const char *mirType) MOZ_OVERRIDE {
if (startedTypes_) {
// Clear trailing ,
if ((*sp)[sp->getOffset() - 1] == ',')
(*sp)[sp->getOffset() - 1] = ' ';
Sprint(sp, "],");
startedTypes_ = false;
} else {
Sprint(sp, "{");
}
Sprint(sp, "\"site\":\"%s\",\"mirType\":\"%s\"},",
TrackedTypeSiteString(site), mirType);
}
};
class SprintOptimizationAttemptsOp : public ForEachTrackedOptimizationAttemptOp
{
Sprinter *sp;
public:
explicit SprintOptimizationAttemptsOp(Sprinter *sp)
: sp(sp)
{ }
void operator()(TrackedStrategy strategy, TrackedOutcome outcome) MOZ_OVERRIDE {
Sprint(sp, "{\"strategy\":\"%s\",\"outcome\":\"%s\"},",
TrackedStrategyString(strategy), TrackedOutcomeString(outcome));
}
};
static bool
ReflectTrackedOptimizations(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedObject callee(cx, &args.callee());
JSRuntime *rt = cx->runtime();
if (!rt->hasJitRuntime() || !rt->jitRuntime()->isOptimizationTrackingEnabled(rt)) {
JS_ReportError(cx, "Optimization tracking is off.");
return false;
}
if (args.length() != 1) {
ReportUsageError(cx, callee, "Wrong number of arguments");
return false;
}
if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
ReportUsageError(cx, callee, "Argument must be a function");
return false;
}
RootedFunction fun(cx, &args[0].toObject().as<JSFunction>());
if (!fun->hasScript() || !fun->nonLazyScript()->hasIonScript()) {
args.rval().setNull();
return true;
}
jit::JitcodeGlobalTable *table = rt->jitRuntime()->getJitcodeGlobalTable();
jit::JitcodeGlobalEntry entry;
jit::IonScript *ion = fun->nonLazyScript()->ionScript();
table->lookupInfallible(ion->method()->raw(), &entry, rt);
if (!entry.hasTrackedOptimizations()) {
JSObject *obj = JS_NewPlainObject(cx);
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
Sprinter sp(cx);
if (!sp.init())
return false;
const jit::IonTrackedOptimizationsRegionTable *regions =
entry.ionEntry().trackedOptimizationsRegionTable();
Sprint(&sp, "{\"regions\": [");
for (uint32_t i = 0; i < regions->numEntries(); i++) {
jit::IonTrackedOptimizationsRegion region = regions->entry(i);
jit::IonTrackedOptimizationsRegion::RangeIterator iter = region.ranges();
while (iter.more()) {
uint32_t startOffset, endOffset;
uint8_t index;
iter.readNext(&startOffset, &endOffset, &index);
JSScript *script;
jsbytecode *pc;
// Use endOffset, as startOffset may be associated with a
// previous, adjacent region ending exactly at startOffset. That
// is, suppose we have two regions [0, startOffset], [startOffset,
// endOffset]. Since we are not querying a return address, we want
// the second region and not the first.
uint8_t *addr = ion->method()->raw() + endOffset;
entry.youngestFrameLocationAtAddr(rt, addr, &script, &pc);
Sprint(&sp, "{\"location\":\"%s:%u\",\"offset\":%u,\"index\":%u}%s",
script->filename(), script->lineno(), script->pcToOffset(pc), index,
iter.more() ? "," : "");
}
}
Sprint(&sp, "],");
Sprint(&sp, "\"opts\": [");
for (uint8_t i = 0; i < entry.ionEntry().numOptimizationAttempts(); i++) {
Sprint(&sp, "%s{\"typeinfo\":[", i == 0 ? "" : ",");
SprintOptimizationTypeInfoOp top(&sp);
jit::IonTrackedOptimizationsTypeInfo::ForEachOpAdapter adapter(top);
entry.trackedOptimizationTypeInfo(i).forEach(adapter, entry.allTrackedTypes());
// Clear the trailing ,
if (sp[sp.getOffset() - 1] == ',')
sp[sp.getOffset() - 1] = ' ';
Sprint(&sp, "],\"attempts\":[");
SprintOptimizationAttemptsOp aop(&sp);
entry.trackedOptimizationAttempts(i).forEach(aop);
// Clear the trailing ,
if (sp[sp.getOffset() - 1] == ',')
sp[sp.getOffset() - 1] = ' ';
Sprint(&sp, "]}");
}
Sprint(&sp, "]}");
if (sp.hadOutOfMemory())
return false;
RootedString str(cx, JS_NewStringCopyZ(cx, sp.string()));
if (!str)
return false;
RootedValue jsonVal(cx);
if (!JS_ParseJSON(cx, str, &jsonVal))
return false;
args.rval().set(jsonVal);
return true;
}
static const JSFunctionSpecWithHelp shell_functions[] = {
JS_FN_HELP("version", Version, 0, 0,
"version([number])",
@ -4784,6 +4954,12 @@ static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
" Note: This is not fuzzing safe because it can be used to construct\n"
" deeply nested wrapper chains that cannot exist in the wild."),
JS_FN_HELP("trackedOpts", ReflectTrackedOptimizations, 1, 0,
"trackedOpts(fun)",
" Returns an object describing the tracked optimizations of |fun|, if\n"
" any. If |fun| is not a scripted function or has not been compiled by\n"
" Ion, null is returned."),
JS_FS_HELP_END
};

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

@ -67,8 +67,14 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::I
return obj;
}
// Trigger an identical allocation to the one that notified us of OOM
// so that we trigger the right kind of GC automatically.
// Trigger an identical allocation to the one that notified us of OOM so
// that we trigger the right kind of GC automatically; note that even
// though we are passing CanGC to AllocateObjectForCacheHit it will never
// allow GC during the allocation itself. The reason is that this would
// clobber our cache and make us unable to initialize from it. Instead we
// do an independent non-allocation GC, then return nullptr so that we'll
// take the slow allocation path. The callee is responsible for ensuring
// that the index it uses to fill the cache is still correct after this GC.
mozilla::DebugOnly<JSObject *> obj2 =
js::gc::AllocateObjectForCacheHit<CanGC>(cx, entry->kind, heap, group->clasp());
MOZ_ASSERT(!obj2);

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

@ -5864,6 +5864,20 @@ ComputeSnappedImageDrawingParameters(gfxContext* aCtx,
gfxRect anchoredDestRect(anchorPoint, scaledDest);
gfxRect anchoredImageRect(imageSpaceAnchorPoint, imageSize);
// Calculate anchoredDestRect with snapped fill rect when the devPixelFill rect
// corresponds to just a single tile in that direction
if (fill.Width() != devPixelFill.Width() &&
devPixelDest.x == devPixelFill.x &&
devPixelDest.XMost() == devPixelFill.XMost()) {
anchoredDestRect.width = fill.width;
}
if (fill.Height() != devPixelFill.Height() &&
devPixelDest.y == devPixelFill.y &&
devPixelDest.YMost() == devPixelFill.YMost()) {
anchoredDestRect.height = fill.height;
}
transform = TransformBetweenRects(anchoredImageRect, anchoredDestRect);
invTransform = TransformBetweenRects(anchoredDestRect, anchoredImageRect);
}

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

@ -0,0 +1,2 @@
x
<ruby><x>

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

@ -570,3 +570,4 @@ load 1039454-1.html
load 1042489.html
load 1054010-1.html
load 1058954-1.html
load 1134667.html

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

@ -1019,8 +1019,6 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
} else {
if (nsGkAtoms::letterFrame==frameType) {
pfd->mIsLetterFrame = true;
} else if (nsGkAtoms::rubyFrame == frameType) {
SyncAnnotationBounds(pfd);
}
if (pfd->mSpan) {
isEmpty = !pfd->mSpan->mHasNonemptyContent && pfd->mFrame->IsSelfEmpty();
@ -1127,6 +1125,7 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
}
if (nsGkAtoms::rubyFrame == frameType) {
mHasRuby = true;
SyncAnnotationBounds(pfd);
}
}
@ -2797,17 +2796,15 @@ nsLineLayout::AdvanceAnnotationInlineBounds(PerFrameData* aPFD,
/**
* This function applies the changes of icoord and isize caused by
* justification to annotations of the given frame.
* aPFD must be one of the frames in aContainingSpan.
*/
void
nsLineLayout::ApplyLineJustificationToAnnotations(PerFrameData* aPFD,
PerSpanData* aContainingSpan,
nscoord aDeltaICoord,
nscoord aDeltaISize)
{
PerFrameData* pfd = aPFD->mNextAnnotation;
nscoord containerWidth = ContainerWidthForSpan(aContainingSpan);
while (pfd) {
nscoord containerWidth = pfd->mFrame->GetParent()->GetRect().Width();
AdvanceAnnotationInlineBounds(pfd, containerWidth,
aDeltaICoord, aDeltaISize);
@ -2876,8 +2873,7 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD,
// The gaps added to the end of the frame should also be
// excluded from the isize added to the annotation.
ApplyLineJustificationToAnnotations(pfd, aPSD,
deltaICoord, dw - gapsAtEnd);
ApplyLineJustificationToAnnotations(pfd, deltaICoord, dw - gapsAtEnd);
deltaICoord += dw;
pfd->mFrame->SetRect(lineWM, pfd->mBounds, ContainerWidthForSpan(aPSD));
}

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

@ -686,7 +686,6 @@ protected:
nscoord aDeltaISize);
void ApplyLineJustificationToAnnotations(PerFrameData* aPFD,
PerSpanData* aContainingSpan,
nscoord aDeltaICoord,
nscoord aDeltaISize);

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

@ -161,7 +161,7 @@ nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
LogicalPoint pos = child->GetLogicalPosition(lineWM, containerWidth);
pos.B(lineWM) += deltaBCoord;
// Relative positioning hasn't happened yet.
// So MovePositionBy should be used here.
// So MovePositionBy should not be used here.
child->SetPosition(lineWM, pos, containerWidth);
nsContainerFrame::PlaceFrameView(child);
}

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

@ -1,7 +1,7 @@
# For more pagination tests, see layout/reftests/w3c-css/submitted/css21/pagination/
# and layout/reftests/w3c-css/submitted/multicol3/
# Pagination tests
asserts(3) == abspos-breaking-000.xhtml abspos-breaking-000.ref.xhtml # bug 1067755
# asserts(3) == abspos-breaking-000.xhtml abspos-breaking-000.ref.xhtml # bug 1067755, 1135556
== abspos-breaking-001.xhtml abspos-breaking-000.ref.xhtml
== abspos-breaking-002.xhtml abspos-breaking-000.ref.xhtml
== abspos-breaking-003.html abspos-breaking-003-ref.html

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

@ -32,4 +32,4 @@ skip-if(B2G) fuzzy-if(cocoaWidget,1,5000) == 745025-1.html 745025-1-ref.html # r
random-if(B2G&&browserIsRemote) == 960822.html 960822-ref.html # reftest-print doesn't work on B2G (scrollbar difference only)
== 966419-1.html 966419-1-ref.html
== 966419-2.html 966419-2-ref.html
skip-if(B2G) asserts(3) HTTP(..) == 1108104.html 1108104-ref.html # bug 1067755
# skip-if(B2G) asserts(3) HTTP(..) == 1108104.html 1108104-ref.html # bug 1067755, 1135556

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

@ -17,7 +17,7 @@ pref(gfx.font_rendering.opentype_svg.enabled,true) fuzzy-if(gtk2Widget,1,2268
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-paintnone.svg svg-glyph-paintnone-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-cachedopacity.svg svg-glyph-cachedopacity-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) fuzzy-if(cocoaWidget,255,100) == svg-glyph-objectvalue.svg svg-glyph-objectvalue-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) fails == svg-glyph-mask.svg svg-glyph-mask-ref.svg # bug 872483
#pref(gfx.font_rendering.opentype_svg.enabled,true) fails == svg-glyph-mask.svg svg-glyph-mask-ref.svg # bug 872483, 1135329
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-paint-server.svg svg-glyph-paint-server-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-transform.svg svg-glyph-transform-ref.svg
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-extents.html svg-glyph-extents-ref.html

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

@ -83,7 +83,7 @@ class Context(KeyedDefaultDict):
# a list to be a problem.
self._all_paths = []
self.config = config
self.executed_time = 0
self.execution_time = 0
KeyedDefaultDict.__init__(self, self._factory)
def push_source(self, path):

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

@ -719,10 +719,9 @@ class BuildReader(object):
each sandbox evaluation. Its return value is ignored.
"""
def __init__(self, config, sandbox_post_eval_cb=None):
def __init__(self, config):
self.config = config
self._sandbox_post_eval_cb = sandbox_post_eval_cb
self._log = logging.getLogger(__name__)
self._read_files = set()
self._execution_stack = []
@ -967,9 +966,6 @@ class BuildReader(object):
sandbox.exec_file(path)
context.execution_time = time.time() - time_start
if self._sandbox_post_eval_cb:
self._sandbox_post_eval_cb(context)
# We first collect directories populated in variables.
dir_vars = ['DIRS']
@ -981,7 +977,7 @@ class BuildReader(object):
curdir = mozpath.dirname(path)
gyp_contexts = []
for target_dir in context['GYP_DIRS']:
for target_dir in context.get('GYP_DIRS', []):
gyp_dir = context['GYP_DIRS'][target_dir]
for v in ('input', 'variables'):
if not getattr(gyp_dir, v):
@ -1011,9 +1007,6 @@ class BuildReader(object):
gyp_contexts.append(gyp_context)
for gyp_context in gyp_contexts:
if self._sandbox_post_eval_cb:
self._sandbox_post_eval_cb(gyp_context)
context['DIRS'].append(mozpath.relpath(gyp_context.objdir, context.objdir))
yield context

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

@ -237,21 +237,6 @@ class TestBuildReader(unittest.TestCase):
self.assertEqual([context['XPIDL_MODULE'] for context in contexts],
['foobar', 'foobar', 'baz', 'foobar'])
def test_process_eval_callback(self):
def strip_dirs(context):
context['DIRS'][:] = []
count[0] += 1
reader = self.reader('traversal-simple',
sandbox_post_eval_cb=strip_dirs)
count = [0]
contexts = list(reader.read_topsrcdir())
self.assertEqual(len(contexts), 1)
self.assertEqual(len(count), 1)
if __name__ == '__main__':
main()

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

@ -243,6 +243,13 @@ AppTrustDomain::IsChainValid(const DERArray& certChain, Time time)
return Success;
}
Result
AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm)
{
// TODO: We should restrict signatures to SHA-256 or better.
return Success;
}
Result
AppTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)
@ -257,6 +264,7 @@ Result
AppTrustDomain::VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo)
{
// TODO: We should restrict signatures to SHA-256 or better.
return VerifyRSAPKCS1SignedDigestNSS(signedDigest, subjectPublicKeyInfo,
mPinArg);
}

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

@ -38,6 +38,8 @@ public:
/*optional*/ const mozilla::pkix::Input* aiaExtension) MOZ_OVERRIDE;
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
mozilla::pkix::Time time) MOZ_OVERRIDE;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg) MOZ_OVERRIDE;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits) MOZ_OVERRIDE;

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

@ -712,6 +712,12 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
return Success;
}
Result
NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm)
{
return Success;
}
Result
NSSCertDBTrustDomain::CheckRSAPublicKeyModulusSizeInBits(
EndEntityOrCA /*endEntityOrCA*/, unsigned int modulusSizeInBits)

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

@ -70,6 +70,9 @@ public:
/*out*/ mozilla::pkix::TrustLevel& trustLevel)
MOZ_OVERRIDE;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg) MOZ_OVERRIDE;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits) MOZ_OVERRIDE;

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

@ -317,3 +317,4 @@ MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE=The server presented a certificate with a
MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA=An X.509 version 1 certificate that is not a trust anchor was used to issue the server's certificate. X.509 version 1 certificates are deprecated and should not be used to sign other certificates.
MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE=The server presented a certificate that is not yet valid.
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE=A certificate that is not yet valid was used to issue the server's certificate.
MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH=The signature algorithm in the signature field of the certificate does not match the algorithm in its signatureAlgorithm field.

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

@ -179,6 +179,8 @@ static const unsigned int FATAL_ERROR_FLAG = 0x800;
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE) \
MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_EC_POINT_FORM, 47, \
SEC_ERROR_UNSUPPORTED_EC_POINT_FORM) \
MOZILLA_PKIX_MAP(ERROR_SIGNATURE_ALGORITHM_MISMATCH, 48, \
MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH) \
MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \
SEC_ERROR_INVALID_ARGS) \
MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \

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

@ -81,6 +81,7 @@ enum ErrorCode
MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH = ERROR_BASE + 4,
MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = ERROR_BASE + 5,
MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = ERROR_BASE + 6,
MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH = ERROR_BASE + 7,
};
void RegisterErrorTable();

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

@ -271,6 +271,13 @@ public:
/*optional*/ const Input* stapledOCSPresponse,
/*optional*/ const Input* aiaExtension) = 0;
// Check that the given digest algorithm is acceptable for use in signatures.
//
// Return Success if the algorithm is acceptable,
// Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED if the algorithm is not
// acceptable, or another error code if another error occurred.
virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg) = 0;
// Check that the RSA public key size is acceptable.
//
// Return Success if the key size is acceptable,

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

@ -79,9 +79,6 @@ BackCert::Init()
if (rv != Success) {
return rv;
}
// XXX: Ignored. What are we supposed to check? This seems totally redundant
// with Certificate.signatureAlgorithm. Is it important to check that they
// are consistent with each other? It doesn't seem to matter!
rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, signature);
if (rv != Success) {
return rv;

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

@ -29,6 +29,99 @@
namespace mozilla { namespace pkix {
// 4.1.1.2 signatureAlgorithm
// 4.1.2.3 signature
Result
CheckSignatureAlgorithm(TrustDomain& trustDomain,
EndEntityOrCA endEntityOrCA,
const der::SignedDataWithSignature& signedData,
Input signatureValue)
{
// 4.1.1.2. signatureAlgorithm
der::PublicKeyAlgorithm publicKeyAlg;
DigestAlgorithm digestAlg;
Reader signatureAlgorithmReader(signedData.algorithm);
Result rv = der::SignatureAlgorithmIdentifierValue(signatureAlgorithmReader,
publicKeyAlg, digestAlg);
if (rv != Success) {
return rv;
}
rv = der::End(signatureAlgorithmReader);
if (rv != Success) {
return rv;
}
// 4.1.2.3. Signature
der::PublicKeyAlgorithm signedPublicKeyAlg;
DigestAlgorithm signedDigestAlg;
Reader signedSignatureAlgorithmReader(signatureValue);
rv = der::SignatureAlgorithmIdentifierValue(signedSignatureAlgorithmReader,
signedPublicKeyAlg,
signedDigestAlg);
if (rv != Success) {
return rv;
}
rv = der::End(signedSignatureAlgorithmReader);
if (rv != Success) {
return rv;
}
// "This field MUST contain the same algorithm identifier as the
// signatureAlgorithm field in the sequence Certificate." However, it may
// be encoded differently. In particular, one of the fields may have a NULL
// parameter while the other one may omit the parameter field altogether, and
// these are considered equivalent. Some certificates generation software
// actually generates certificates like that, so we compare the parsed values
// instead of comparing the encoded values byte-for-byte.
//
// Along the same lines, we accept two different OIDs for RSA-with-SHA1, and
// we consider those OIDs to be equivalent here.
if (publicKeyAlg != signedPublicKeyAlg || digestAlg != signedDigestAlg) {
return Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH;
}
// During the time of the deprecation of SHA-1 and the deprecation of RSA
// keys of less than 2048 bits, we will encounter many certs signed using
// SHA-1 and/or too-small RSA keys. With this in mind, we ask the trust
// domain early on if it knows it will reject the signature purely based on
// the digest algorithm and/or the RSA key size (if an RSA signature). This
// is a good optimization because it completely avoids calling
// trustDomain.FindIssuers (which may be slow) for such rejected certs, and
// more generally it short-circuits any path building with them (which, of
// course, is even slower).
rv = trustDomain.CheckSignatureDigestAlgorithm(digestAlg);
if (rv != Success) {
return rv;
}
switch (publicKeyAlg) {
case der::PublicKeyAlgorithm::RSA_PKCS1:
{
// The RSA computation may give a result that requires fewer bytes to
// encode than the public key (since it is modular arithmetic). However,
// the last step of generating a PKCS#1.5 signature is the I2OSP
// procedure, which pads any such shorter result with zeros so that it
// is exactly the same length as the public key.
unsigned int signatureSizeInBits = signedData.signature.GetLength() * 8u;
return trustDomain.CheckRSAPublicKeyModulusSizeInBits(
endEntityOrCA, signatureSizeInBits);
}
case der::PublicKeyAlgorithm::ECDSA:
// In theory, we could implement a similar early-pruning optimization for
// ECDSA curves. However, since there has been no similar deprecation for
// for any curve that we support, the chances of us encountering a curve
// during path building is too low to be worth bothering with.
break;
MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
}
return Success;
}
// 4.1.2.5 Validity
Result
@ -735,21 +828,46 @@ CheckIssuerIndependentProperties(TrustDomain& trustDomain,
const EndEntityOrCA endEntityOrCA = cert.endEntityOrCA;
// Check the cert's trust first, because we want to minimize the amount of
// processing we do on a distrusted cert, in case it is trying to exploit
// some bug in our processing.
rv = trustDomain.GetCertTrust(endEntityOrCA, requiredPolicy, cert.GetDER(),
trustLevel);
if (rv != Success) {
return rv;
}
if (trustLevel == TrustLevel::ActivelyDistrusted) {
return Result::ERROR_UNTRUSTED_CERT;
}
if (trustLevel != TrustLevel::TrustAnchor &&
trustLevel != TrustLevel::InheritsTrust) {
// The TrustDomain returned a trust level that we weren't expecting.
return Result::FATAL_ERROR_INVALID_STATE;
if (trustLevel == TrustLevel::TrustAnchor &&
endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
requiredEKUIfPresent == KeyPurposeId::id_kp_OCSPSigning) {
// OCSP signer certificates can never be trust anchors, especially
// since we don't support designated OCSP responders. All of the checks
// below that are dependent on trustLevel rely on this overriding of the
// trust level for OCSP signers.
trustLevel = TrustLevel::InheritsTrust;
}
// Check the SPKI first, because it is one of the most selective properties
switch (trustLevel) {
case TrustLevel::InheritsTrust:
rv = CheckSignatureAlgorithm(trustDomain, endEntityOrCA,
cert.GetSignedData(), cert.GetSignature());
if (rv != Success) {
return rv;
}
break;
case TrustLevel::TrustAnchor:
// We don't even bother checking signatureAlgorithm or signature for
// syntactic validity for trust anchors, because we don't use those
// fields for anything, and because the trust anchor might be signed
// with a signature algorithm we don't actually support.
break;
case TrustLevel::ActivelyDistrusted:
return Result::ERROR_UNTRUSTED_CERT;
}
// Check the SPKI early, because it is one of the most selective properties
// of the certificate due to SHA-1 deprecation and the deprecation of
// certificates with keys weaker than RSA 2048.
Reader spki(cert.GetSubjectPublicKeyInfo());

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

@ -111,6 +111,13 @@ SignatureAlgorithmIdentifierValue(Reader& input,
/*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
/*out*/ DigestAlgorithm& digestAlgorithm)
{
// RFC 5758 Section 3.2 (ECDSA with SHA-2), and RFC 3279 Section 2.2.3
// (ECDSA with SHA-1) say that parameters must be omitted.
//
// RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
// RSA must be encoded as NULL; we relax that requirement by allowing the
// NULL to be omitted, to match all the other signature algorithms we support
// and for compatibility.
Reader algorithmID;
Result rv = AlgorithmIdentifierValue(input, algorithmID);
if (rv != Success) {
@ -166,15 +173,6 @@ SignatureAlgorithmIdentifierValue(Reader& input,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01
};
// RFC 5758 Section 3.1 (DSA with SHA-2), RFC 3279 Section 2.2.2 (DSA with
// SHA-1), RFC 5758 Section 3.2 (ECDSA with SHA-2), and RFC 3279
// Section 2.2.3 (ECDSA with SHA-1) all say that parameters must be omitted.
//
// RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
// RSA must be encoded as NULL; we relax that requirement by allowing the
// NULL to be omitted, to match all the other signature algorithms we support
// and for compatibility.
// Matching is attempted based on a rough estimate of the commonality of the
// algorithm, to minimize the number of MatchRest calls.
if (algorithmID.MatchRest(sha256WithRSAEncryption)) {

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

@ -194,6 +194,9 @@ RegisterErrorTable()
{ "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE",
"A certificate that is not yet valid was used to issue the server's "
"certificate." },
{ "MOZILLA_PKIX_ERROR_SIGNATURE_ALGORITHM_MISMATCH",
"The signature algorithm in the signature field of the certificate does "
"not match the algorithm in its signatureAlgorithm field." },
};
// Note that these error strings are not localizable.
// When these strings change, update the localization information too.

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

@ -53,16 +53,18 @@ public:
Result Init();
const Input GetDER() const { return der; }
der::Version GetVersion() const { return version; }
const der::SignedDataWithSignature& GetSignedData() const {
return signedData;
}
der::Version GetVersion() const { return version; }
const Input GetSerialNumber() const { return serialNumber; }
const Input GetSignature() const { return signature; }
const Input GetIssuer() const { return issuer; }
// XXX: "validity" is a horrible name for the structure that holds
// notBefore & notAfter, but that is the name used in RFC 5280 and we use the
// RFC 5280 names for everything.
const Input GetValidity() const { return validity; }
const Input GetSerialNumber() const { return serialNumber; }
const Input GetSubject() const { return subject; }
const Input GetSubjectPublicKeyInfo() const
{

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

@ -9,6 +9,7 @@ SOURCES += [
'pkixcert_extension_tests.cpp',
'pkixcert_signature_algorithm_tests.cpp',
'pkixcheck_CheckKeyUsage_tests.cpp',
'pkixcheck_CheckSignatureAlgorithm_tests.cpp',
'pkixcheck_CheckValidity_tests.cpp',
# The naming conventions are described in ./README.txt.

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

@ -36,9 +36,7 @@
#pragma warning(pop)
#endif
#include "pkix/pkix.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@ -80,7 +78,7 @@ CreateCert(const char* issuerCN, // null means "empty name"
return certDER;
}
class TestTrustDomain final : public TrustDomain
class TestTrustDomain final : public DefaultCryptoTrustDomain
{
public:
// The "cert chain tail" is a longish chain of certificates that is used by
@ -153,36 +151,6 @@ private:
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
std::map<ByteString, ByteString> subjectDERToCertDER;
ByteString leafCACertDER;
ByteString rootCACertDER;
@ -276,7 +244,7 @@ TEST_F(pkixbuild, BeyondMaxAcceptableCertChainLength)
// is treated as a trust anchor and is assumed to have issued all certificates
// (i.e. FindIssuer always attempts to build the next step in the chain with
// it).
class ExpiredCertTrustDomain final : public TrustDomain
class ExpiredCertTrustDomain final : public DefaultCryptoTrustDomain
{
public:
explicit ExpiredCertTrustDomain(ByteString rootDER)
@ -315,48 +283,11 @@ public:
return checker.Check(rootCert, nullptr, keepGoing);
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
private:
ByteString rootDER;
};
@ -394,7 +325,7 @@ TEST_F(pkixbuild, NoRevocationCheckingForExpiredCert)
nullptr));
}
class DSSTrustDomain final : public TrustDomain
class DSSTrustDomain final : public EverythingFailsByDefaultTrustDomain
{
public:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
@ -403,56 +334,6 @@ public:
trustLevel = TrustLevel::TrustAnchor;
return Success;
}
Result FindIssuer(Input, IssuerChecker&, Time) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
Result DigestBuf(Input, DigestAlgorithm, /*out*/uint8_t*, size_t) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyECDSASignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
};
class pkixbuild_DSS : public ::testing::Test { };
@ -492,7 +373,7 @@ TEST_F(pkixbuild_DSS, DSSEndEntityKeyNotAccepted)
nullptr/*stapledOCSPResponse*/));
}
class IssuerNameCheckTrustDomain final : public TrustDomain
class IssuerNameCheckTrustDomain final : public DefaultCryptoTrustDomain
{
public:
IssuerNameCheckTrustDomain(const ByteString& issuer, bool expectedKeepGoing)
@ -534,35 +415,6 @@ public:
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
private:
const ByteString issuer;
const bool expectedKeepGoing;

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

@ -22,10 +22,8 @@
* limitations under the License.
*/
#include "pkix/pkix.h"
#include "pkixder.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@ -60,7 +58,7 @@ CreateCertWithOneExtension(const char* subjectStr, const ByteString& extension)
return CreateCertWithExtensions(subjectStr, extensions);
}
class TrustEverythingTrustDomain final : public TrustDomain
class TrustEverythingTrustDomain final : public DefaultCryptoTrustDomain
{
private:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
@ -70,13 +68,6 @@ private:
return Success;
}
Result FindIssuer(Input /*encodedIssuerName*/, IssuerChecker& /*checker*/,
Time /*time*/) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*, /*optional*/ const Input*)
override
@ -88,36 +79,6 @@ private:
{
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
};
// python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3

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

@ -3,9 +3,7 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
#include "pkix/pkix.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
@ -45,7 +43,7 @@ CreateCert(const char* issuerCN,
return certDER;
}
class AlgorithmTestsTrustDomain final : public TrustDomain
class AlgorithmTestsTrustDomain final : public DefaultCryptoTrustDomain
{
public:
AlgorithmTestsTrustDomain(const ByteString& rootDER,
@ -103,35 +101,6 @@ private:
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
ByteString rootDER;
ByteString rootSubjectDER;
ByteString intDER;

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

@ -23,8 +23,6 @@
*/
#include "pkixgtest.h"
#include "pkix/pkixtypes.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;

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

@ -0,0 +1,358 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This code is made available to you under your choice of the following sets
* of licensing terms:
*/
/* 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/.
*/
/* Copyright 2015 Mozilla Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pkixder.h"
#include "pkixgtest.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
namespace mozilla { namespace pkix {
extern Result CheckSignatureAlgorithm(
TrustDomain& trustDomain, EndEntityOrCA endEntityOrCA,
const der::SignedDataWithSignature& signedData,
Input signatureValue);
} } // namespace mozilla::pkix
struct CheckSignatureAlgorithmTestParams
{
ByteString signatureAlgorithmValue;
ByteString signatureValue;
unsigned int signatureLengthInBytes;
Result expectedResult;
};
#define BS(s) ByteString(s, MOZILLA_PKIX_ARRAY_LENGTH(s))
// python DottedOIDToCode.py --tlv sha256WithRSAEncryption 1.2.840.113549.1.1.11
static const uint8_t tlv_sha256WithRSAEncryption[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
};
// Same as tlv_sha256WithRSAEncryption, except one without the "0x0b" and with
// the DER length decreased accordingly.
static const uint8_t tlv_sha256WithRSAEncryption_truncated[] = {
0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01
};
// python DottedOIDToCode.py --tlv sha-1WithRSAEncryption 1.2.840.113549.1.1.5
static const uint8_t tlv_sha_1WithRSAEncryption[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05
};
// python DottedOIDToCode.py --tlv sha1WithRSASignature 1.3.14.3.2.29
static const uint8_t tlv_sha1WithRSASignature[] = {
0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d
};
// python DottedOIDToCode.py --tlv md5WithRSAEncryption 1.2.840.113549.1.1.4
static const uint8_t tlv_md5WithRSAEncryption[] = {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04
};
static const CheckSignatureAlgorithmTestParams
CHECKSIGNATUREALGORITHM_TEST_PARAMS[] =
{
{ // Both algorithm IDs are empty
ByteString(),
ByteString(),
2048 / 8,
Result::ERROR_BAD_DER,
},
{ // signatureAlgorithm is empty, signature is supported.
ByteString(),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_BAD_DER,
},
{ // signatureAlgorithm is supported, signature is empty.
BS(tlv_sha256WithRSAEncryption),
ByteString(),
2048 / 8,
Result::ERROR_BAD_DER,
},
{ // Algorithms match, both are supported.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Success
},
{ // Algorithms do not match because signatureAlgorithm is truncated.
BS(tlv_sha256WithRSAEncryption_truncated),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // Algorithms do not match because signature is truncated.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption_truncated),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // Algorithms do not match, both are supported.
BS(tlv_sha_1WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH,
},
{ // Algorithms do not match, both are supported.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha_1WithRSAEncryption),
2048 / 8,
Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH,
},
{ // Algorithms match, both are unsupported.
BS(tlv_md5WithRSAEncryption),
BS(tlv_md5WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // signatureAlgorithm is unsupported, signature is supported.
BS(tlv_md5WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // signatureAlgorithm is supported, signature is unsupported.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_md5WithRSAEncryption),
2048 / 8,
Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
},
{ // Both have the optional NULL parameter.
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
2048 / 8,
Success
},
{ // signatureAlgorithm has the optional NULL parameter, signature doesn't.
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
BS(tlv_sha256WithRSAEncryption),
2048 / 8,
Success
},
{ // signatureAlgorithm does not have the optional NULL parameter, signature
// does.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption) + TLV(der::NULLTag, ByteString()),
2048 / 8,
Success
},
{ // The different OIDs for RSA-with-SHA1 we support are semantically
// equivalent.
BS(tlv_sha1WithRSASignature),
BS(tlv_sha_1WithRSAEncryption),
2048 / 8,
Success,
},
{ // The different OIDs for RSA-with-SHA1 we support are semantically
// equivalent (opposite order).
BS(tlv_sha_1WithRSAEncryption),
BS(tlv_sha1WithRSASignature),
2048 / 8,
Success,
},
{ // Algorithms match, both are supported, key size is not a multile of 128
// bits. This test verifies that we're not wrongly rounding up the
// signature size like we did in the original patch for bug 1131767.
BS(tlv_sha256WithRSAEncryption),
BS(tlv_sha256WithRSAEncryption),
(2048 / 8) - 1,
Success
},
};
class pkixcheck_CheckSignatureAlgorithm
: public ::testing::Test
, public ::testing::WithParamInterface<CheckSignatureAlgorithmTestParams>
{
};
class pkixcheck_CheckSignatureAlgorithm_TrustDomain final
: public EverythingFailsByDefaultTrustDomain
{
public:
explicit pkixcheck_CheckSignatureAlgorithm_TrustDomain(
unsigned int publicKeySizeInBits)
: publicKeySizeInBits(publicKeySizeInBits)
, checkedDigestAlgorithm(false)
, checkedModulusSizeInBits(false)
{
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
{
checkedDigestAlgorithm = true;
return Success;
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits)
override
{
EXPECT_EQ(EndEntityOrCA::MustBeEndEntity, endEntityOrCA);
EXPECT_EQ(publicKeySizeInBits, modulusSizeInBits);
checkedModulusSizeInBits = true;
return Success;
}
const unsigned int publicKeySizeInBits;
bool checkedDigestAlgorithm;
bool checkedModulusSizeInBits;
};
TEST_P(pkixcheck_CheckSignatureAlgorithm, CheckSignatureAlgorithm)
{
const CheckSignatureAlgorithmTestParams& params(GetParam());
Input signatureValueInput;
ASSERT_EQ(Success,
signatureValueInput.Init(params.signatureValue.data(),
params.signatureValue.length()));
pkixcheck_CheckSignatureAlgorithm_TrustDomain
trustDomain(params.signatureLengthInBytes * 8);
der::SignedDataWithSignature signedData;
ASSERT_EQ(Success,
signedData.algorithm.Init(params.signatureAlgorithmValue.data(),
params.signatureAlgorithmValue.length()));
ByteString dummySignature(params.signatureLengthInBytes, 0xDE);
ASSERT_EQ(Success,
signedData.signature.Init(dummySignature.data(),
dummySignature.length()));
ASSERT_EQ(params.expectedResult,
CheckSignatureAlgorithm(trustDomain, EndEntityOrCA::MustBeEndEntity,
signedData, signatureValueInput));
ASSERT_EQ(params.expectedResult == Success,
trustDomain.checkedDigestAlgorithm);
ASSERT_EQ(params.expectedResult == Success,
trustDomain.checkedModulusSizeInBits);
}
INSTANTIATE_TEST_CASE_P(
pkixcheck_CheckSignatureAlgorithm, pkixcheck_CheckSignatureAlgorithm,
testing::ValuesIn(CHECKSIGNATUREALGORITHM_TEST_PARAMS));
class pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain
: public DefaultCryptoTrustDomain
{
public:
explicit pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain(
const ByteString& issuer)
: issuer(issuer)
{
}
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
Input cert, /*out*/ TrustLevel& trustLevel) override
{
trustLevel = InputEqualsByteString(cert, issuer)
? TrustLevel::TrustAnchor
: TrustLevel::InheritsTrust;
return Success;
}
Result FindIssuer(Input, IssuerChecker& checker, Time) override
{
EXPECT_FALSE(ENCODING_FAILED(issuer));
Input issuerInput;
EXPECT_EQ(Success, issuerInput.Init(issuer.data(), issuer.length()));
bool keepGoing;
EXPECT_EQ(Success, checker.Check(issuerInput, nullptr, keepGoing));
EXPECT_FALSE(keepGoing);
return Success;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
return Success;
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
ByteString issuer;
};
// Test that CheckSignatureAlgorithm actually gets called at some point when
// BuildCertChain is called.
TEST_F(pkixcheck_CheckSignatureAlgorithm, BuildCertChain)
{
ScopedTestKeyPair keyPair(CloneReusedKeyPair());
ASSERT_TRUE(keyPair);
ByteString issuerExtensions[2];
issuerExtensions[0] = CreateEncodedBasicConstraints(true, nullptr,
Critical::No);
ASSERT_FALSE(ENCODING_FAILED(issuerExtensions[0]));
ByteString issuer(CreateEncodedCertificate(3,
sha256WithRSAEncryption,
CreateEncodedSerialNumber(1),
CNToDERName("issuer"),
oneDayBeforeNow, oneDayAfterNow,
CNToDERName("issuer"),
*keyPair,
issuerExtensions,
*keyPair,
sha256WithRSAEncryption));
ASSERT_FALSE(ENCODING_FAILED(issuer));
ByteString subject(CreateEncodedCertificate(3,
TLV(der::SEQUENCE,
BS(tlv_sha_1WithRSAEncryption)),
CreateEncodedSerialNumber(2),
CNToDERName("issuer"),
oneDayBeforeNow, oneDayAfterNow,
CNToDERName("subject"),
*keyPair,
nullptr,
*keyPair,
sha256WithRSAEncryption));
ASSERT_FALSE(ENCODING_FAILED(subject));
Input subjectInput;
ASSERT_EQ(Success, subjectInput.Init(subject.data(), subject.length()));
pkixcheck_CheckSignatureAlgorithm_BuildCertChain_TrustDomain
trustDomain(issuer);
Result rv = BuildCertChain(trustDomain, subjectInput, Now(),
EndEntityOrCA::MustBeEndEntity,
KeyUsage::noParticularKeyUsageRequired,
KeyPurposeId::anyExtendedKeyUsage,
CertPolicyId::anyPolicy,
nullptr);
ASSERT_EQ(Result::ERROR_SIGNATURE_ALGORITHM_MISMATCH, rv);
}

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

@ -23,8 +23,6 @@
*/
#include "pkixgtest.h"
#include "pkix/pkixtypes.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;

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

@ -23,12 +23,11 @@
*/
#include <limits>
#include <stdint.h>
#include <vector>
#include "pkixgtest.h"
#include "pkixder.h"
#include "pkixtestutil.h"
#include "stdint.h"
#include "pkixgtest.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::der;

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

@ -56,7 +56,8 @@
#pragma warning(pop)
#endif
#include "pkix/Result.h"
#include "pkix/pkix.h"
#include "pkixtestutil.h"
// PrintTo must be in the same namespace as the type we're overloading it for.
namespace mozilla { namespace pkix {
@ -82,6 +83,122 @@ extern const std::time_t now;
extern const std::time_t oneDayBeforeNow;
extern const std::time_t oneDayAfterNow;
class EverythingFailsByDefaultTrustDomain : public TrustDomain
{
public:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
Input, /*out*/ TrustLevel&) override
{
ADD_FAILURE();
return NotReached("GetCertTrust should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result FindIssuer(Input, IssuerChecker&, Time) override
{
ADD_FAILURE();
return NotReached("FindIssuer should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*,
/*optional*/ const Input*) override
{
ADD_FAILURE();
return NotReached("CheckRevocation should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result IsChainValid(const DERArray&, Time) override
{
ADD_FAILURE();
return NotReached("IsChainValid should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result DigestBuf(Input, DigestAlgorithm, /*out*/ uint8_t*, size_t) override
{
ADD_FAILURE();
return NotReached("DigestBuf should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
{
ADD_FAILURE();
return NotReached("CheckSignatureDigestAlgorithm should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
ADD_FAILURE();
return NotReached("CheckECDSACurveIsAcceptable should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result VerifyECDSASignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return NotReached("VerifyECDSASignedDigest should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
ADD_FAILURE();
return NotReached("CheckRSAPublicKeyModulusSizeInBits should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return NotReached("VerifyRSAPKCS1SignedDigest should not be called",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
};
class DefaultCryptoTrustDomain : public EverythingFailsByDefaultTrustDomain
{
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestBufLen) override
{
return TestDigestBuf(item, digestAlg, digestBuf, digestBufLen);
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
{
return Success;
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
};
} } } // namespace mozilla::pkix::test
#endif // mozilla_pkix_pkixgtest_h

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

@ -21,11 +21,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "pkix/pkix.h"
#include "pkixcheck.h"
#include "pkixder.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
#include "pkixutil.h"
namespace mozilla { namespace pkix {

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

@ -23,42 +23,15 @@
*/
#include "pkixgtest.h"
#include "pkix/pkix.h"
#include "pkixder.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
class CreateEncodedOCSPRequestTrustDomain final : public TrustDomain
class CreateEncodedOCSPRequestTrustDomain final
: public EverythingFailsByDefaultTrustDomain
{
private:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
/*out*/ TrustLevel&) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result FindIssuer(Input, IssuerChecker&, Time) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, const Input*,
const Input*) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
/*out*/ uint8_t *digestBuf, size_t digestBufLen)
override
@ -67,28 +40,9 @@ private:
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
final override
override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) final override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result VerifyECDSASignedDigest(const SignedDigest&, Input) override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
return Success;
}
};

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

@ -22,21 +22,18 @@
* limitations under the License.
*/
#include "pkix/pkix.h"
#include "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
const uint16_t END_ENTITY_MAX_LIFETIME_IN_DAYS = 10;
class OCSPTestTrustDomain : public TrustDomain
// Note that CheckRevocation is never called for OCSP signing certificates.
class OCSPTestTrustDomain : public DefaultCryptoTrustDomain
{
public:
OCSPTestTrustDomain()
{
}
OCSPTestTrustDomain() { }
Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&,
Input, /*out*/ TrustLevel& trustLevel)
@ -46,62 +43,6 @@ public:
trustLevel = TrustLevel::InheritsTrust;
return Success;
}
Result FindIssuer(Input, IssuerChecker&, Time) final override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
/*optional*/ const Input*, /*optional*/ const Input*)
final override
{
// TODO: I guess mozilla::pkix should support revocation of designated
// OCSP responder eventually, but we don't now, so this function should
// never get called.
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result IsChainValid(const DERArray&, Time) final override
{
ADD_FAILURE();
return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
Result DigestBuf(Input item, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestBufLen)
final override
{
return TestDigestBuf(item, digestAlg, digestBuf, digestBufLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
final override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) final override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
OCSPTestTrustDomain(const OCSPTestTrustDomain&) = delete;
void operator=(const OCSPTestTrustDomain&) = delete;
};
namespace {

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

@ -28,6 +28,7 @@ catch (e) {
// under the "accessibility.*" branch.
const PREFS_WHITELIST = [
"accessibility.",
"apz.",
"browser.cache.",
"browser.display.",
"browser.download.folderList",

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

@ -1446,8 +1446,9 @@ function readStringFromInputStream(inputStream) {
sis.init(inputStream);
var text = sis.read(sis.available());
sis.close();
if (text[text.length - 1] == "\n")
if (text && text[text.length - 1] == "\n") {
text = text.slice(0, -1);
}
return text;
}

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

@ -77,9 +77,8 @@ function runTest() {
removeDirRecursive(addonPrepDir);
}
catch (e) {
dump("Unable to remove directory\n" +
"path: " + addonPrepDir.path + "\n" +
"Exception: " + e + "\n");
logTestInfo("Unable to remove directory. Path: " + addonPrepDir.path +
", Exception: " + e);
}
resetAddons(finishTest);

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

@ -167,6 +167,8 @@ const TEST_ADDONS = [ "appdisabled_1", "appdisabled_2",
"updateversion_1", "updateversion_2",
"userdisabled_1", "userdisabled_2", "hotfix" ];
const LOG_FUNCTION = info;
var gURLData = URL_HOST + "/" + REL_PATH_DATA + "/";
var gTestTimeout = 240000; // 4 minutes
@ -660,10 +662,11 @@ function waitForRemoteContentLoaded(aEvent) {
// expected or isn't the event's originalTarget.
if (gRemoteContentState != gTest.expectedRemoteContentState ||
aEvent.originalTarget != gRemoteContent) {
debugDump("returning early\n" +
"gRemoteContentState: " + gRemoteContentState + "\n" +
debugDump("returning early. " +
"gRemoteContentState: " +
gRemoteContentState + ", " +
"expectedRemoteContentState: " +
gTest.expectedRemoteContentState + "\n" +
gTest.expectedRemoteContentState + ", " +
"aEvent.originalTarget.nodeName: " +
aEvent.originalTarget.nodeName);
return true;
@ -955,9 +958,8 @@ function resetFiles() {
removeDirRecursive(updatedDir);
}
catch (e) {
dump("Unable to remove directory\n" +
"path: " + updatedDir.path + "\n" +
"Exception: " + e + "\n");
logTestInfo("Unable to remove directory. Path: " + updatedDir.path +
", Exception: " + e);
}
}
}

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

@ -430,8 +430,8 @@ function removeUpdateDirsAndFiles() {
if (file.exists())
file.remove(false);
} catch (e) {
dump("Unable to remove file\nPath: " + file.path +
"\nException: " + e + "\n");
logTestInfo("Unable to remove file. Path: " + file.path +
", Exception: " + e);
}
file = getUpdatesXMLFile(false);
@ -439,8 +439,8 @@ function removeUpdateDirsAndFiles() {
if (file.exists())
file.remove(false);
} catch (e) {
dump("Unable to remove file\nPath: " + file.path +
"\nException: " + e + "\n");
logTestInfo("Unable to remove file. Path: " + file.path +
", Exception: " + e);
}
// This fails sporadically on Mac OS X so wrap it in a try catch
@ -448,8 +448,8 @@ function removeUpdateDirsAndFiles() {
try {
cleanUpdatesDir(updatesDir);
} catch (e) {
dump("Unable to remove files / directories from directory\nPath: " +
updatesDir.path + "\nException: " + e + "\n");
logTestInfo("Unable to remove files / directories from directory. Path: " +
updatesDir.path + ", Exception: " + e);
}
}
@ -483,8 +483,8 @@ function cleanUpdatesDir(aDir) {
try {
entry.remove(true);
} catch (e) {
dump("cleanUpdatesDir: unable to remove directory\nPath: " +
entry.path + "\nException: " + e + "\n");
logTestInfo("cleanUpdatesDir: unable to remove directory. Path: " +
entry.path + ", Exception: " + e);
throw(e);
}
}
@ -493,8 +493,8 @@ function cleanUpdatesDir(aDir) {
try {
entry.remove(false);
} catch (e) {
dump("cleanUpdatesDir: unable to remove file\nPath: " + entry.path +
"\nException: " + e + "\n");
logTestInfo("cleanUpdatesDir: unable to remove file. Path: " +
entry.path + ", Exception: " + e);
throw(e);
}
}
@ -614,8 +614,9 @@ function logTestInfo(aText, aCaller) {
(mm < 10 ? "0" + mm : mm) + ":" +
(ss < 10 ? "0" + ss : ss) + ":" +
(ms < 10 ? "00" + ms : ms < 100 ? "0" + ms : ms);
dump(time + " | TEST-INFO | " + caller.filename + " | [" + caller.name +
" : " + caller.lineNumber + "] " + aText + "\n");
let msg = time + " | TEST-INFO | " + caller.filename + " | [" + caller.name +
" : " + caller.lineNumber + "] " + aText;
LOG_FUNCTION(msg);
}
/**

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

@ -61,13 +61,16 @@ function run_test() {
doTestFinish();
}
if (IS_WIN) {
/**
* Determines a unique mutex name for the installation.
*
* @return Global mutex path.
*/
function getPerInstallationMutexName() {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
let hasher = AUS_Cc["@mozilla.org/security/hash;1"].
createInstance(AUS_Ci.nsICryptoHash);
hasher.init(hasher.SHA1);
@ -90,6 +93,10 @@ if (IS_WIN) {
* The handle to close.
*/
function closeHandle(aHandle) {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
let lib = ctypes.open("kernel32.dll");
let CloseHandle = lib.declare("CloseHandle",
ctypes.winapi_abi,
@ -107,6 +114,10 @@ if (IS_WIN) {
* @return The Win32 handle to the mutex.
*/
function createMutex(aName) {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
const INITIAL_OWN = 1;
const ERROR_ALREADY_EXISTS = 0xB7;
let lib = ctypes.open("kernel32.dll");
@ -131,4 +142,3 @@ if (IS_WIN) {
return handle;
}
}

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

@ -36,7 +36,7 @@ function run_test() {
do_check_eq(gUpdateManager.activeUpdate, null);
// Verify that the active-update.xml file has had the update from the old
// channel removed.
file = getUpdatesXMLFile(true);
let file = getUpdatesXMLFile(true);
logTestInfo("verifying contents of " + FILE_UPDATE_ACTIVE);
do_check_eq(readFile(file), getLocalUpdatesXMLString(""));

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

@ -5,7 +5,10 @@
const KEY_UPDATE_ARCHIVE_DIR = "UpdArchD"
let gActiveUpdate = null;
let gActiveUpdate;
let gDirService;
let gDirProvider;
let gOldProviders;
function FakeDirProvider() {}
FakeDirProvider.prototype = {

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

@ -152,7 +152,7 @@ IncrementalDownload.prototype = {
tm.mainThread.dispatch(function() {
this._observer = observer.QueryInterface(AUS_Ci.nsIRequestObserver);
this._ctxt = ctxt;
this._observer.onStartRequest(this, this.ctxt);
this._observer.onStartRequest(this, this._ctxt);
let mar = getTestDirFile(FILE_SIMPLE_MAR);
mar.copyTo(this._destination.parent, this._destination.leafName);
var status = AUS_Cr.NS_OK

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

@ -2,6 +2,8 @@
* 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/. */
'use strict';
const INSTALL_LOCALE = "@AB_CD@";
const MOZ_APP_NAME = "@MOZ_APP_NAME@";
const BIN_SUFFIX = "@BIN_SUFFIX@";
@ -140,6 +142,8 @@ const PIPE_TO_NULL = ">nul";
const PIPE_TO_NULL = "> /dev/null 2>&1";
#endif
const LOG_FUNCTION = do_print;
// This default value will be overridden when using the http server.
var gURLData = URL_HOST + "/";
@ -1417,7 +1421,6 @@ function getMockUpdRootD() {
}
#endif
if (IS_WIN) {
const kLockFileName = "updated.update_in_progress.lock";
/**
* Helper function for locking a directory on Windows.
@ -1426,7 +1429,11 @@ if (IS_WIN) {
* The nsIFile for the directory to lock.
*/
function lockDirectory(aDir) {
var file = aDir.clone();
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
let file = aDir.clone();
file.append(kLockFileName);
file.create(file.NORMAL_FILE_TYPE, 0o444);
file.QueryInterface(AUS_Ci.nsILocalFileWin);
@ -1443,7 +1450,10 @@ if (IS_WIN) {
* The nsIFile for the directory to unlock.
*/
function unlockDirectory(aDir) {
var file = aDir.clone();
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
let file = aDir.clone();
file.append(kLockFileName);
file.QueryInterface(AUS_Ci.nsILocalFileWin);
file.fileAttributesWin |= file.WFA_READWRITE;
@ -1452,7 +1462,6 @@ if (IS_WIN) {
file.remove(false);
do_check_false(file.exists());
}
}
/**
* Helper function for updater tests for launching the updater binary to apply
@ -3229,7 +3238,7 @@ function start_httpserver() {
if (!dir.isDirectory()) {
do_throw("A file instead of a directory was specified for HttpServer " +
"registerDirectory! Path: " + dir.path + "\n");
"registerDirectory! Path: " + dir.path);
}
AUS_Cu.import("resource://testing-common/httpd.js");
@ -3639,7 +3648,7 @@ function setEnvironment() {
env.set("XPCOM_DEBUG_BREAK", "warn");
if (gStageUpdate) {
logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1\n");
logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1");
env.set("MOZ_UPDATE_STAGING", "1");
}
@ -3705,7 +3714,7 @@ function resetEnvironment() {
}
if (gStageUpdate) {
logTestInfo("removing the MOZ_UPDATE_STAGING environment variable\n");
logTestInfo("removing the MOZ_UPDATE_STAGING environment variable");
env.set("MOZ_UPDATE_STAGING", "");
}

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

@ -14,8 +14,6 @@ function run_test() {
// The mock XMLHttpRequest is MUCH faster
overrideXHR(callHandleEvent);
standardInit();
// The HTTP server is only used for the mar file downloads which is slow
start_httpserver();
let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"),

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

@ -5,6 +5,8 @@
/* General Update Timer Manager Tests */
'use strict';
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cm = Components.manager;
@ -103,8 +105,8 @@ const TESTS = [ {
lastUpdateTime : 0
} ];
var gUTM;
var gNextFunc;
let gUTM;
let gNextFunc;
XPCOMUtils.defineLazyServiceGetter(this, "gPref",
"@mozilla.org/preferences-service;1",
@ -127,7 +129,7 @@ function run_test() {
gPref.setBoolPref(PREF_APP_UPDATE_LOG_ALL, true);
// Remove existing update timers to prevent them from being notified
var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
let entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
while (entries.hasMoreElements()) {
let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false);
@ -165,7 +167,7 @@ function run_test1thru7() {
TESTS[1].defaultInterval].join(","), false, true);
// has a last update time of now - 43200 which is half of its interval
var lastUpdateTime = Math.round(Date.now() / 1000) - 43200;
let lastUpdateTime = Math.round(Date.now() / 1000) - 43200;
gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[2].timerID, lastUpdateTime);
gCompReg.registerFactory(TESTS[2].classID, TESTS[2].desc,
TESTS[2].contractID, gTest3Factory);
@ -201,7 +203,7 @@ function run_test1thru7() {
TESTS[5].defaultInterval].join(","), false, true);
// has a next update time 24 hours from now
var nextUpdateTime = Math.round(Date.now() / 1000) + 86400;
let nextUpdateTime = Math.round(Date.now() / 1000) + 86400;
gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[6].timerID, nextUpdateTime);
gCompReg.registerFactory(TESTS[6].classID, TESTS[6].desc,
TESTS[6].contractID, gTest7Factory);
@ -212,40 +214,41 @@ function run_test1thru7() {
}
function finished_test1thru7() {
if (TESTS[4].notified && TESTS[5].notified && TESTS[6].notified)
if (TESTS[4].notified && TESTS[5].notified && TESTS[6].notified) {
do_timeout(0, gNextFunc);
}
}
function check_test1thru7() {
dump("Testing: a category registered timer didn't fire due to an invalid " +
"default interval\n");
do_print("Testing: a category registered timer didn't fire due to an " +
"invalid default interval");
do_check_false(TESTS[0].notified);
dump("Testing: a category registered timer didn't fire due to not " +
"implementing nsITimerCallback\n");
do_print("Testing: a category registered timer didn't fire due to not " +
"implementing nsITimerCallback");
do_check_false(TESTS[1].notified);
dump("Testing: a category registered timer didn't fire due to the next " +
"update time being in the future\n");
do_print("Testing: a category registered timer didn't fire due to the next " +
"update time being in the future");
do_check_false(TESTS[2].notified);
dump("Testing: a category registered timer didn't fire due to not " +
"having a notify method\n");
do_print("Testing: a category registered timer didn't fire due to not " +
"having a notify method");
do_check_false(TESTS[3].notified);
dump("Testing: a category registered timer has fired\n");
do_print("Testing: a category registered timer has fired");
do_check_true(TESTS[4].notified);
dump("Testing: a category registered timer fired that has an interval " +
"preference that overrides a default that wouldn't have fired yet\n");
do_print("Testing: a category registered timer fired that has an interval " +
"preference that overrides a default that wouldn't have fired yet");
do_check_true(TESTS[5].notified);
dump("Testing: a category registered timer has fired due to the next " +
"update time being reset due to a future last update time\n");
do_print("Testing: a category registered timer has fired due to the next " +
"update time being reset due to a future last update time");
do_check_true(TESTS[6].notified);
dump("Testing: two category registered timers last update time has " +
"user values\n");
do_print("Testing: two category registered timers last update time has " +
"user values");
do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME +
TESTS[4].timerID));
do_check_true(gPref.prefHasUserValue(PREF_BRANCH_LAST_UPDATE_TIME +
@ -256,23 +259,22 @@ function check_test1thru7() {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[1].desc, true);
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[2].desc, true);
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[3].desc, true);
var count = 0;
var entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
let count = 0;
let entries = gCatMan.enumerateCategory(CATEGORY_UPDATE_TIMER);
while (entries.hasMoreElements()) {
let entry = entries.getNext().QueryInterface(Ci.nsISupportsCString).data;
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, entry, false);
count++;
}
dump("Testing: no " + CATEGORY_UPDATE_TIMER + " categories are still " +
"registered\n");
do_print("Testing: no " + CATEGORY_UPDATE_TIMER + " categories are still " +
"registered");
do_check_eq(count, 0);
do_timeout(0, run_test8);
}
function run_test8() {
gNextFunc = check_test8;
for (var i = 0; i < 2; i++) {
for (let i = 0; i < 2; i++) {
gPref.setIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID, 1);
gCompReg.registerFactory(TESTS[7 + i].classID, TESTS[7 + i].desc,
TESTS[7 + i].contractID, eval("gTest" + (8 + i) + "Factory"));
@ -281,15 +283,16 @@ function run_test8() {
}
}
function check_test8() {
var self = arguments.callee;
self.timesCalled = (self.timesCalled || 0) + 1;
if (self.timesCalled < 2)
function check_test8(aTestTimerCallback) {
aTestTimerCallback.timesCalled = (aTestTimerCallback.timesCalled || 0) + 1;
if (aTestTimerCallback.timesCalled < 2) {
return;
}
dump("Testing: two registerTimer registered timers have fired\n");
for (var i = 0; i < 2; i++)
do_print("Testing: two registerTimer registered timers have fired");
for (let i = 0; i < 2; i++) {
do_check_true(TESTS[7 + i].notified);
}
// Check that 'staggering' has happened: even though the two events wanted to fire at
// the same time, we waited a full MAIN_TIMER_INTERVAL between them.
@ -297,71 +300,76 @@ function check_test8() {
do_check_true(Math.abs(TESTS[7].notifyTime - TESTS[8].notifyTime) >=
MAIN_TIMER_INTERVAL * 0.5);
dump("Testing: two registerTimer registered timers last update time have " +
"been updated\n");
for (var i = 0; i < 2; i++)
do_print("Testing: two registerTimer registered timers last update time have " +
"been updated");
for (let i = 0; i < 2; i++) {
do_check_neq(gPref.getIntPref(PREF_BRANCH_LAST_UPDATE_TIME + TESTS[7 + i].timerID), 1);
}
end_test();
}
var gTest1TimerCallback = {
const gTest1TimerCallback = {
notify: function T1CB_notify(aTimer) {
do_throw("gTest1TimerCallback notify method should not have been called");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest1Factory = {
const gTest1Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest1TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest2TimerCallback = {
const gTest2TimerCallback = {
notify: function T2CB_notify(aTimer) {
do_throw("gTest2TimerCallback notify method should not have been called");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimer])
};
var gTest2Factory = {
const gTest2Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest2TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest3TimerCallback = {
const gTest3TimerCallback = {
notify: function T3CB_notify(aTimer) {
do_throw("gTest3TimerCallback notify method should not have been called");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest3Factory = {
const gTest3Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest3TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest4TimerCallback = {
const gTest4TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest4Factory = {
const gTest4Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest4TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest5TimerCallback = {
const gTest5TimerCallback = {
notify: function T5CB_notify(aTimer) {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[4].desc, true);
TESTS[4].notified = true;
@ -370,15 +378,16 @@ var gTest5TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest5Factory = {
const gTest5Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest5TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest6TimerCallback = {
const gTest6TimerCallback = {
notify: function T6CB_notify(aTimer) {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[5].desc, true);
TESTS[5].notified = true;
@ -387,15 +396,16 @@ var gTest6TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest6Factory = {
const gTest6Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest6TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest7TimerCallback = {
const gTest7TimerCallback = {
notify: function T7CB_notify(aTimer) {
gCatMan.deleteCategoryEntry(CATEGORY_UPDATE_TIMER, TESTS[6].desc, true);
TESTS[6].notified = true;
@ -404,44 +414,51 @@ var gTest7TimerCallback = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest7Factory = {
const gTest7Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest7TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest8TimerCallback = {
const gTest8TimerCallback = {
notify: function T8CB_notify(aTimer) {
TESTS[7].notified = true;
TESTS[7].notifyTime = Date.now();
do_timeout(0, check_test8);
do_timeout(0, function() {
check_test8(gTest8TimerCallback);
});
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest8Factory = {
const gTest8Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest8TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};
var gTest9TimerCallback = {
const gTest9TimerCallback = {
notify: function T9CB_notify(aTimer) {
TESTS[8].notified = true;
TESTS[8].notifyTime = Date.now();
do_timeout(0, check_test8);
do_timeout(0, function() {
check_test8(gTest9TimerCallback);
});
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback])
};
var gTest9Factory = {
const gTest9Factory = {
createInstance: function (outer, iid) {
if (outer == null)
if (outer == null) {
return gTest9TimerCallback.QueryInterface(iid);
}
throw Cr.NS_ERROR_NO_AGGREGATION;
}
};

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

@ -82,7 +82,8 @@ let runTest = Task.async(function*() {
let request = navigator.mozApps.installPackage(app.manifestURL);
let (deferred = Promise.defer()) {
{
let deferred = Promise.defer();
request.onerror = function() {
deferred.reject(this.error.name);
};
@ -93,13 +94,14 @@ let runTest = Task.async(function*() {
let appObject = request.result;
ok(appObject, "app is non-null");
let (deferred = Promise.defer()) {
{
let deferred = Promise.defer();
appObject.ondownloaderror = function() {
deferred.reject(appObject.downloadError.name);
};
appObject.ondownloadapplied = deferred.resolve;
yield deferred.promise;
};
}
while (!WebappOSUtils.isLaunchable(app)) {
yield wait(1000);

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

@ -80,8 +80,10 @@ let runTest = Task.async(function*() {
confirmNextPopup();
let (request = navigator.mozApps.installPackage(app.manifestURL)) {
let (deferred = Promise.defer()) {
{
let request = navigator.mozApps.installPackage(app.manifestURL);
{
let deferred = Promise.defer();
request.onerror = function() {
deferred.reject(this.error.name);
};
@ -92,14 +94,15 @@ let runTest = Task.async(function*() {
let appObject = request.result;
ok(appObject, "app is non-null");
let (deferred = Promise.defer()) {
{
let deferred = Promise.defer();
appObject.ondownloaderror = function() {
deferred.reject(appObject.downloadError.name);
};
appObject.ondownloadapplied = deferred.resolve;
yield deferred.promise;
};
};
}
}
while (!WebappOSUtils.isLaunchable(app)) {
yield wait(1000);
@ -112,8 +115,10 @@ let runTest = Task.async(function*() {
confirmNextPopup();
let (request = navigator.mozApps.installPackage(app.manifestURL)) {
let (deferred = Promise.defer()) {
{
let request = navigator.mozApps.installPackage(app.manifestURL);
{
let deferred = Promise.defer();
request.onerror = function() {
deferred.reject(this.error.name);
};
@ -124,14 +129,15 @@ let runTest = Task.async(function*() {
let appObject = request.result;
ok(appObject, "app is non-null");
let (deferred = Promise.defer()) {
{
let deferred = Promise.defer();
appObject.ondownloaderror = function() {
deferred.reject(appObject.downloadError.name);
};
appObject.ondownloadapplied = deferred.resolve;
yield deferred.promise;
};
};
}
}
while (!WebappOSUtils.isLaunchable(app)) {
yield wait(1000);

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

@ -62,7 +62,8 @@ let runTest = Task.async(function*() {
let request = navigator.mozApps.install(app.manifestURL);
let (deferred = Promise.defer()) {
{
let deferred = Promise.defer();
request.onerror = function() {
deferred.reject(this.error.name);
};

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