Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-07-04 14:17:27 +02:00
commit 8ba211d938
88 changed files with 2047 additions and 1294 deletions

View File

@ -9,6 +9,7 @@ support-files =
doc_media-node-creation.html doc_media-node-creation.html
doc_destroy-nodes.html doc_destroy-nodes.html
doc_connect-toggle.html doc_connect-toggle.html
doc_connect-param.html
440hz_sine.ogg 440hz_sine.ogg
head.js head.js
@ -20,6 +21,7 @@ support-files =
[browser_audionode-actor-is-source.js] [browser_audionode-actor-is-source.js]
[browser_webaudio-actor-simple.js] [browser_webaudio-actor-simple.js]
[browser_webaudio-actor-destroy-node.js] [browser_webaudio-actor-destroy-node.js]
[browser_webaudio-actor-connect-param.js]
[browser_wa_destroy-node-01.js] [browser_wa_destroy-node-01.js]

View File

@ -0,0 +1,26 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test the `connect-param` event on the web audio actor.
*/
function spawnTest () {
let [target, debuggee, front] = yield initBackend(CONNECT_PARAM_URL);
let [_, _, [destNode, carrierNode, modNode, gainNode], _, connectParam] = yield Promise.all([
front.setup({ reload: true }),
once(front, "start-context"),
getN(front, "create-node", 4),
get2(front, "connect-node"),
once(front, "connect-param")
]);
info(connectParam);
is(connectParam.source.actorID, modNode.actorID, "`connect-param` has correct actor for `source`");
is(connectParam.dest.actorID, gainNode.actorID, "`connect-param` has correct actor for `dest`");
is(connectParam.param, "gain", "`connect-param` has correct parameter name for `param`");
yield removeTab(target.tab);
finish();
}

View File

@ -0,0 +1,28 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Web Audio Editor test page</title>
</head>
<body>
<script type="text/javascript;version=1.8">
"use strict";
let ctx = new AudioContext();
let carrier = ctx.createOscillator();
let modulator = ctx.createOscillator();
let gain = ctx.createGain();
carrier.connect(gain);
gain.connect(ctx.destination);
modulator.connect(gain.gain);
modulator.start(0);
carrier.start(0);
</script>
</body>
</html>

View File

@ -28,6 +28,7 @@ const MEDIA_NODES_URL = EXAMPLE_URL + "doc_media-node-creation.html";
const BUFFER_AND_ARRAY_URL = EXAMPLE_URL + "doc_buffer-and-array.html"; const BUFFER_AND_ARRAY_URL = EXAMPLE_URL + "doc_buffer-and-array.html";
const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html"; const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html";
const CONNECT_TOGGLE_URL = EXAMPLE_URL + "doc_connect-toggle.html"; const CONNECT_TOGGLE_URL = EXAMPLE_URL + "doc_connect-toggle.html";
const CONNECT_PARAM_URL = EXAMPLE_URL + "doc_connect-param.html";
// All tests are asynchronous. // All tests are asynchronous.
waitForExplicitFinish(); waitForExplicitFinish();

View File

@ -86,7 +86,7 @@ class RemoteAutomation(Automation):
topActivity = self._devicemanager.getTopActivity() topActivity = self._devicemanager.getTopActivity()
if topActivity == proc.procName: if topActivity == proc.procName:
proc.kill() proc.kill(True)
if status == 1: if status == 1:
if maxTime: if maxTime:
print "TEST-UNEXPECTED-FAIL | %s | application ran for longer than " \ print "TEST-UNEXPECTED-FAIL | %s | application ran for longer than " \
@ -287,5 +287,26 @@ class RemoteAutomation(Automation):
return status return status
def kill(self): def kill(self, stagedShutdown = False):
self.dm.killProcess(self.procName) if stagedShutdown:
# Trigger an ANR report with "kill -3" (SIGQUIT)
self.dm.killProcess(self.procName, 3)
time.sleep(3)
# Trigger a breakpad dump with "kill -6" (SIGABRT)
self.dm.killProcess(self.procName, 6)
# Wait for process to end
retries = 0
while retries < 3:
pid = self.dm.processExist(self.procName)
if pid and pid > 0:
print "%s still alive after SIGABRT: waiting..." % self.procName
time.sleep(5)
else:
return
retries += 1
self.dm.killProcess(self.procName, 9)
pid = self.dm.processExist(self.procName)
if pid and pid > 0:
self.dm.killProcess(self.procName)
else:
self.dm.killProcess(self.procName)

View File

@ -228,7 +228,12 @@ HTMLTrackElement::LoadResource()
return; return;
} }
CreateTextTrack(); // We may already have a TextTrack at this point if GetTrack() has already
// been called. This happens, for instance, if script tries to get the
// TextTrack before its mTrackElement has been bound to the DOM tree.
if (!mTrack) {
CreateTextTrack();
}
// Check for a Content Security Policy to pass down to the channel // Check for a Content Security Policy to pass down to the channel
// created to load the media content. // created to load the media content.

View File

@ -321,6 +321,7 @@ skip-if = os == 'win' # bug 894922
[test_bug895305.html] [test_bug895305.html]
[test_bug919265.html] [test_bug919265.html]
[test_bug957847.html] [test_bug957847.html]
[test_bug1018933.html]
[test_can_play_type.html] [test_can_play_type.html]
[test_can_play_type_mpeg.html] [test_can_play_type_mpeg.html]
skip-if = buildapp == 'b2g' # bug 1021675 skip-if = buildapp == 'b2g' # bug 1021675

View File

@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1018933
-->
<head>
<meta charset='utf-8'>
<title>Regression test for bug 1018933 - HTMLTrackElement should create only one TextTrack</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
function() {
var video = document.createElement("video");
video.src = "seek.webm";
video.preload = "auto";
var trackElement = document.createElement("track");
trackElement.src = "basic.vtt";
trackElement.kind = "subtitles";
document.getElementById("content").appendChild(video);
video.appendChild(trackElement);
// Accessing the track now would have caused the bug as the track element
// shouldn't have had time to bind to the tree yet.
trackElement.track.mode = 'showing';
video.addEventListener("loadedmetadata", function run_tests() {
// Re-que run_tests() at the end of the event loop until the track
// element has loaded its data.
if (trackElement.readyState == 1) {
setTimeout(run_tests, 0);
return;
}
is(video.textTracks.length, 1, "Video should have one TextTrack.");
SimpleTest.finish();
});
}
);
</script>
</pre>
</body>
</html>

View File

@ -12,7 +12,6 @@
#include "StreamNotifyChild.h" #include "StreamNotifyChild.h"
#include "PluginProcessChild.h" #include "PluginProcessChild.h"
#include "gfxASurface.h" #include "gfxASurface.h"
#include "gfxContext.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"
#include "gfx2DGlue.h" #include "gfx2DGlue.h"
#include "nsNPAPIPluginInstance.h" #include "nsNPAPIPluginInstance.h"
@ -2787,12 +2786,6 @@ PluginInstanceChild::DoAsyncSetWindow(const gfxSurfaceType& aSurfaceType,
} }
} }
static inline gfxRect
GfxFromNsRect(const nsIntRect& aRect)
{
return gfxRect(aRect.x, aRect.y, aRect.width, aRect.height);
}
bool bool
PluginInstanceChild::CreateOptSurface(void) PluginInstanceChild::CreateOptSurface(void)
{ {
@ -3454,12 +3447,14 @@ PluginInstanceChild::ShowPluginFrame()
PLUGIN_LOG_DEBUG((" (on background)")); PLUGIN_LOG_DEBUG((" (on background)"));
// Source the background pixels ... // Source the background pixels ...
{ {
nsRefPtr<gfxContext> ctx = nsRefPtr<gfxASurface> surface =
new gfxContext(mHelperSurface ? mHelperSurface : mCurrentSurface); mHelperSurface ? mHelperSurface : mCurrentSurface;
ctx->SetSource(mBackground); RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(surface);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE); RefPtr<SourceSurface> backgroundSurface =
ctx->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height)); gfxPlatform::GetSourceSurfaceForSurface(dt, mBackground);
ctx->Fill(); dt->CopySurface(backgroundSurface,
ToIntRect(rect),
ToIntPoint(rect.TopLeft()));
} }
// ... and hand off to the plugin // ... and hand off to the plugin
// BEWARE: mBackground may die during this call // BEWARE: mBackground may die during this call
@ -3583,18 +3578,17 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height)); mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height));
// Read back previous content // Read back previous content
nsRefPtr<gfxContext> ctx = new gfxContext(mCurrentSurface); RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(mCurrentSurface);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE); RefPtr<SourceSurface> source =
ctx->SetSource(mBackSurface); gfxPlatform::GetSourceSurfaceForSurface(dt, mBackSurface);
// Subtract from mSurfaceDifferenceRect area which is overlapping with rect // Subtract from mSurfaceDifferenceRect area which is overlapping with rect
nsIntRegion result; nsIntRegion result;
result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect)); result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect));
nsIntRegionRectIterator iter(result); nsIntRegionRectIterator iter(result);
const nsIntRect* r; const nsIntRect* r;
while ((r = iter.Next()) != nullptr) { while ((r = iter.Next()) != nullptr) {
ctx->Rectangle(GfxFromNsRect(*r)); dt->CopySurface(source, ToIntRect(*r), ToIntPoint(r->TopLeft()));
} }
ctx->Fill();
return true; return true;
} }

View File

@ -3309,13 +3309,13 @@ WifiWorker.prototype = {
return; return;
} }
let certDB2 = Cc["@mozilla.org/security/x509certdb;1"] let certDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2); .getService(Ci.nsIX509CertDB);
if (!certDB2) { if (!certDB) {
self._sendMessage(message, false, "Failed to query NSS DB service", msg); self._sendMessage(message, false, "Failed to query NSS DB service", msg);
} }
let certList = certDB2.getCerts(); let certList = certDB.getCerts();
if (!certList) { if (!certList) {
self._sendMessage(message, false, "Failed to get certificate List", msg); self._sendMessage(message, false, "Failed to get certificate List", msg);
} }
@ -3332,7 +3332,7 @@ WifiWorker.prototype = {
}; };
while (certListEnum.hasMoreElements()) { while (certListEnum.hasMoreElements()) {
let certInfo = certListEnum.getNext().QueryInterface(Ci.nsIX509Cert3); let certInfo = certListEnum.getNext().QueryInterface(Ci.nsIX509Cert);
let certNicknameInfo = /WIFI\_([A-Z]*)\_(.*)/.exec(certInfo.nickname); let certNicknameInfo = /WIFI\_([A-Z]*)\_(.*)/.exec(certInfo.nickname);
if (!certNicknameInfo) { if (!certNicknameInfo) {
continue; continue;

View File

@ -21,7 +21,6 @@
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
#include <algorithm> #include <algorithm>
#include "BackgroundChild.h"
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#include "js/OldDebugAPI.h" #include "js/OldDebugAPI.h"
#include "jsfriendapi.h" #include "jsfriendapi.h"
@ -41,7 +40,6 @@
#include "nsContentUtils.h" #include "nsContentUtils.h"
#include "nsCycleCollector.h" #include "nsCycleCollector.h"
#include "nsDOMJSUtils.h" #include "nsDOMJSUtils.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include "nsLayoutStatics.h" #include "nsLayoutStatics.h"
#include "nsNetUtil.h" #include "nsNetUtil.h"
@ -66,12 +64,6 @@
#include "WorkerPrivate.h" #include "WorkerPrivate.h"
#include "WorkerRunnable.h" #include "WorkerRunnable.h"
#ifdef ENABLE_TESTS
#include "BackgroundChildImpl.h"
#include "mozilla/ipc/PBackgroundChild.h"
#include "prrng.h"
#endif
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
@ -169,10 +161,6 @@ RuntimeService* gRuntimeService = nullptr;
// Only non-null during the call to Init. // Only non-null during the call to Init.
RuntimeService* gRuntimeServiceDuringInit = nullptr; RuntimeService* gRuntimeServiceDuringInit = nullptr;
#ifdef ENABLE_TESTS
bool gTestPBackground = false;
#endif // ENABLE_TESTS
enum { enum {
ID_Worker = 0, ID_Worker = 0,
ID_ChromeWorker, ID_ChromeWorker,
@ -911,37 +899,6 @@ private:
WorkerPrivate* mWorkerPrivate; WorkerPrivate* mWorkerPrivate;
}; };
class WorkerBackgroundChildCallback MOZ_FINAL :
public nsIIPCBackgroundChildCreateCallback
{
bool* mDone;
public:
WorkerBackgroundChildCallback(bool* aDone)
: mDone(aDone)
{
MOZ_ASSERT(mDone);
}
NS_DECL_ISUPPORTS
private:
~WorkerBackgroundChildCallback()
{ }
virtual void
ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
{
*mDone = true;
}
virtual void
ActorFailed() MOZ_OVERRIDE
{
*mDone = true;
}
};
class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
{ {
WorkerPrivate* mWorkerPrivate; WorkerPrivate* mWorkerPrivate;
@ -984,9 +941,6 @@ private:
~WorkerThreadPrimaryRunnable() ~WorkerThreadPrimaryRunnable()
{ } { }
nsresult
SynchronouslyCreatePBackground();
NS_DECL_NSIRUNNABLE NS_DECL_NSIRUNNABLE
}; };
@ -1086,28 +1040,6 @@ public:
} }
#endif #endif
#ifdef ENABLE_TESTS
void
TestPBackground()
{
using namespace mozilla::ipc;
if (gTestPBackground) {
// Randomize value to validate workers are not cross-posting messages.
uint32_t testValue;
PRSize randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue));
MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue));
nsCString testStr;
testStr.AppendInt(testValue);
testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread()));
PBackgroundChild* existingBackgroundChild =
BackgroundChild::GetForCurrentThread();
MOZ_RELEASE_ASSERT(existingBackgroundChild);
bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr);
MOZ_RELEASE_ASSERT(ok);
}
}
#endif // #ENABLE_TESTS
private: private:
WorkerThread() WorkerThread()
: nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE), : nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
@ -1311,10 +1243,6 @@ RuntimeService::GetOrCreateService()
return nullptr; return nullptr;
} }
#ifdef ENABLE_TESTS
gTestPBackground = mozilla::Preferences::GetBool("pbackground.testing", false);
#endif // ENABLE_TESTS
// The observer service now owns us until shutdown. // The observer service now owns us until shutdown.
gRuntimeService = service; gRuntimeService = service;
} }
@ -1604,6 +1532,10 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
return false; return false;
} }
#ifdef DEBUG
thread->SetAcceptingNonWorkerRunnables(false);
#endif
return true; return true;
} }
@ -2592,20 +2524,8 @@ RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
bool aMayWait, bool aMayWait,
uint32_t aRecursionDepth) uint32_t aRecursionDepth)
{ {
using mozilla::ipc::BackgroundChild;
mWorkerPrivate->AssertIsOnWorkerThread(); mWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(!aMayWait);
// If the PBackground child is not created yet, then we must permit
// blocking event processing to support SynchronouslyCreatePBackground().
// If this occurs then we are spinning on the event queue at the start of
// PrimaryWorkerRunnable::Run() and don't want to process the event in
// mWorkerPrivate yet.
if (aMayWait) {
MOZ_ASSERT(aRecursionDepth == 2);
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
return NS_OK;
}
mWorkerPrivate->OnProcessNextEvent(aRecursionDepth); mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
return NS_OK; return NS_OK;
@ -2649,15 +2569,11 @@ LogViolationDetailsRunnable::Run()
return NS_OK; return NS_OK;
} }
NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable) NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable)
NS_IMETHODIMP NS_IMETHODIMP
WorkerThreadPrimaryRunnable::Run() WorkerThreadPrimaryRunnable::Run()
{ {
using mozilla::ipc::BackgroundChild;
#ifdef MOZ_NUWA_PROCESS #ifdef MOZ_NUWA_PROCESS
if (IsNuwaProcess()) { if (IsNuwaProcess()) {
NS_ASSERTION(NuwaMarkCurrentThread != nullptr, NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
@ -2676,19 +2592,6 @@ WorkerThreadPrimaryRunnable::Run()
profiler_register_thread(threadName.get(), &stackBaseGuess); profiler_register_thread(threadName.get(), &stackBaseGuess);
// Note: SynchronouslyCreatePBackground() must be called prior to
// mThread->SetWorker() in order to avoid accidentally consuming
// worker messages here.
nsresult rv = SynchronouslyCreatePBackground();
if (NS_WARN_IF(NS_FAILED(rv))) {
// XXX need to fire an error at parent.
return rv;
}
#ifdef ENABLE_TESTS
mThread->TestPBackground();
#endif
mThread->SetWorker(mWorkerPrivate); mThread->SetWorker(mWorkerPrivate);
mWorkerPrivate->AssertIsOnWorkerThread(); mWorkerPrivate->AssertIsOnWorkerThread();
@ -2722,12 +2625,6 @@ WorkerThreadPrimaryRunnable::Run()
JS_ReportPendingException(cx); JS_ReportPendingException(cx);
} }
#ifdef ENABLE_TESTS
mThread->TestPBackground();
#endif
BackgroundChild::CloseForCurrentThread();
#ifdef MOZ_ENABLE_PROFILER_SPS #ifdef MOZ_ENABLE_PROFILER_SPS
if (stack) { if (stack) {
stack->sampleRuntime(nullptr); stack->sampleRuntime(nullptr);
@ -2766,38 +2663,6 @@ WorkerThreadPrimaryRunnable::Run()
return NS_OK; return NS_OK;
} }
nsresult
WorkerThreadPrimaryRunnable::SynchronouslyCreatePBackground()
{
using mozilla::ipc::BackgroundChild;
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
bool done = false;
nsCOMPtr<nsIIPCBackgroundChildCreateCallback> callback =
new WorkerBackgroundChildCallback(&done);
if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(callback))) {
return NS_ERROR_FAILURE;
}
while (!done) {
if (NS_WARN_IF(!NS_ProcessNextEvent(mThread, true /* aMayWay */))) {
return NS_ERROR_FAILURE;
}
}
if (NS_WARN_IF(!BackgroundChild::GetForCurrentThread())) {
return NS_ERROR_FAILURE;
}
#ifdef DEBUG
mThread->SetAcceptingNonWorkerRunnables(false);
#endif
return NS_OK;
}
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable, NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable::FinishedRunnable,
nsRunnable) nsRunnable)

View File

@ -12,6 +12,8 @@
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/Endian.h" #include "mozilla/Endian.h"
#include "TexturePoolOGL.h" #include "TexturePoolOGL.h"
#include "mozilla/layers/CompositorOGL.h"
#include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/TextureHostOGL.h" #include "mozilla/layers/TextureHostOGL.h"
#include "gfxColor.h" #include "gfxColor.h"
@ -317,6 +319,7 @@ public:
} }
void AppendDebugData(DebugGLData *aDebugData); void AppendDebugData(DebugGLData *aDebugData);
void CleanDebugData();
void DispatchDebugData(); void DispatchDebugData();
private: private:
nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers; nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers;
@ -325,7 +328,37 @@ private:
nsCOMPtr<nsIServerSocket> mServerSocket; nsCOMPtr<nsIServerSocket> mServerSocket;
}; };
static StaticAutoPtr<LayerScopeWebSocketManager> gLayerScopeWebSocketManager; // Static class to create and destory LayerScopeWebSocketManager object
class WebSocketHelper
{
public:
static void CreateServerSocket()
{
// Create Web Server Socket (which has to be on the main thread)
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (!sWebSocketManager) {
sWebSocketManager = new LayerScopeWebSocketManager();
}
}
static void DestroyServerSocket()
{
// Destroy Web Server Socket
if (sWebSocketManager) {
sWebSocketManager->RemoveAllConnections();
}
}
static LayerScopeWebSocketManager* GetSocketManager()
{
return sWebSocketManager.get();
}
private:
static StaticAutoPtr<LayerScopeWebSocketManager> sWebSocketManager;
};
StaticAutoPtr<LayerScopeWebSocketManager> WebSocketHelper::sWebSocketManager;
class DebugGLData : public LinkedListElement<DebugGLData> { class DebugGLData : public LinkedListElement<DebugGLData> {
public: public:
@ -378,9 +411,9 @@ public:
} }
static bool WriteToStream(void *ptr, uint32_t size) { static bool WriteToStream(void *ptr, uint32_t size) {
if (!gLayerScopeWebSocketManager) if (!WebSocketHelper::GetSocketManager())
return true; return true;
return gLayerScopeWebSocketManager->WriteAll(ptr, size); return WebSocketHelper::GetSocketManager()->WriteAll(ptr, size);
} }
protected: protected:
@ -428,83 +461,97 @@ public:
class DebugGLTextureData : public DebugGLData { class DebugGLTextureData : public DebugGLData {
public: public:
DebugGLTextureData(GLContext* cx, void* layerRef, GLuint target, GLenum name, DataSourceSurface* img) DebugGLTextureData(GLContext* cx,
void* layerRef,
GLenum target,
GLuint name,
DataSourceSurface* img)
: DebugGLData(DebugGLData::TextureData, cx), : DebugGLData(DebugGLData::TextureData, cx),
mLayerRef(layerRef), mLayerRef(layerRef),
mTarget(target), mTarget(target),
mName(name), mName(name),
mImage(img) mDatasize(0)
{ } {
// pre-packing
// DataSourceSurface may have locked buffer,
// so we should compress now, and then it could
// be unlocked outside.
pack(img);
}
void *GetLayerRef() const { return mLayerRef; } void *GetLayerRef() const { return mLayerRef; }
GLuint GetName() const { return mName; } GLuint GetName() const { return mName; }
DataSourceSurface* GetImage() const { return mImage; }
GLenum GetTextureTarget() const { return mTarget; } GLenum GetTextureTarget() const { return mTarget; }
virtual bool Write() { virtual bool Write() {
DebugGLData::TexturePacket packet;
char* dataptr = nullptr;
uint32_t datasize = 0;
std::auto_ptr<char> compresseddata;
packet.type = mDataType;
packet.ptr = static_cast<uint64_t>(mContextAddress);
packet.layerref = reinterpret_cast<uint64_t>(mLayerRef);
packet.name = mName;
packet.format = 0;
packet.target = mTarget;
packet.dataFormat = LOCAL_GL_RGBA;
if (mImage) {
packet.width = mImage->GetSize().width;
packet.height = mImage->GetSize().height;
packet.stride = mImage->Stride();
packet.dataSize = mImage->GetSize().height * mImage->Stride();
dataptr = (char*) mImage->GetData();
datasize = packet.dataSize;
compresseddata = std::auto_ptr<char>((char*) moz_malloc(LZ4::maxCompressedSize(datasize)));
if (compresseddata.get()) {
int ndatasize = LZ4::compress(dataptr, datasize, compresseddata.get());
if (ndatasize > 0) {
datasize = ndatasize;
dataptr = compresseddata.get();
packet.dataFormat = (1 << 16) | packet.dataFormat;
packet.dataSize = datasize;
}
}
} else {
packet.width = 0;
packet.height = 0;
packet.stride = 0;
packet.dataSize = 0;
}
// write the packet header data // write the packet header data
if (!WriteToStream(&packet, sizeof(packet))) if (!WriteToStream(&mPacket, sizeof(mPacket)))
return false; return false;
// then the image data // then the image data
if (!WriteToStream(dataptr, datasize)) if (mCompresseddata.get() && !WriteToStream(mCompresseddata.get(), mDatasize))
return false; return false;
// then pad out to 4 bytes // then pad out to 4 bytes
if (datasize % 4 != 0) { if (mDatasize % 4 != 0) {
static char buf[] = { 0, 0, 0, 0 }; static char buf[] = { 0, 0, 0, 0 };
if (!WriteToStream(buf, 4 - (datasize % 4))) if (!WriteToStream(buf, 4 - (mDatasize % 4)))
return false; return false;
} }
return true; return true;
} }
private:
void pack(DataSourceSurface* aImage) {
mPacket.type = mDataType;
mPacket.ptr = static_cast<uint64_t>(mContextAddress);
mPacket.layerref = reinterpret_cast<uint64_t>(mLayerRef);
mPacket.name = mName;
mPacket.format = 0;
mPacket.target = mTarget;
mPacket.dataFormat = LOCAL_GL_RGBA;
if (aImage) {
mPacket.width = aImage->GetSize().width;
mPacket.height = aImage->GetSize().height;
mPacket.stride = aImage->Stride();
mPacket.dataSize = aImage->GetSize().height * aImage->Stride();
mCompresseddata = std::auto_ptr<char>(
(char*)moz_malloc(LZ4::maxCompressedSize(mPacket.dataSize)));
if (mCompresseddata.get()) {
int ndatasize = LZ4::compress((char*)aImage->GetData(),
mPacket.dataSize,
mCompresseddata.get());
if (ndatasize > 0) {
mDatasize = ndatasize;
mPacket.dataFormat = (1 << 16) | mPacket.dataFormat;
mPacket.dataSize = mDatasize;
} else {
NS_WARNING("Compress data failed");
}
} else {
NS_WARNING("Couldn't moz_malloc for compressed data.");
}
} else {
mPacket.width = 0;
mPacket.height = 0;
mPacket.stride = 0;
mPacket.dataSize = 0;
}
}
protected: protected:
void* mLayerRef; void* mLayerRef;
GLenum mTarget; GLenum mTarget;
GLuint mName; GLuint mName;
RefPtr<DataSourceSurface> mImage;
// Packet data
DebugGLData::TexturePacket mPacket;
std::auto_ptr<char> mCompresseddata;
uint32_t mDatasize;
}; };
class DebugGLColorData : public DebugGLData { class DebugGLColorData : public DebugGLData {
@ -539,18 +586,6 @@ protected:
nsIntSize mSize; nsIntSize mSize;
}; };
static bool
CheckSender()
{
if (!gLayerScopeWebSocketManager)
return false;
if (!gLayerScopeWebSocketManager->IsConnected())
return false;
return true;
}
class DebugListener : public nsIServerSocketListener class DebugListener : public nsIServerSocketListener
{ {
virtual ~DebugListener() { } virtual ~DebugListener() { }
@ -566,11 +601,11 @@ public:
NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ, NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
nsISocketTransport *aTransport) nsISocketTransport *aTransport)
{ {
if (!gLayerScopeWebSocketManager) if (!WebSocketHelper::GetSocketManager())
return NS_OK; return NS_OK;
printf_stderr("*** LayerScope: Accepted connection\n"); printf_stderr("*** LayerScope: Accepted connection\n");
gLayerScopeWebSocketManager->AddConnection(aTransport); WebSocketHelper::GetSocketManager()->AddConnection(aTransport);
return NS_OK; return NS_OK;
} }
@ -594,24 +629,19 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
DebugDataSender() { DebugDataSender() { }
mList = new LinkedList<DebugGLData>();
}
void Append(DebugGLData *d) { void Append(DebugGLData *d) {
mList->insertBack(d); mList.insertBack(d);
} }
void Cleanup() { void Cleanup() {
if (!mList) if (mList.isEmpty())
return; return;
DebugGLData *d; DebugGLData *d;
while ((d = mList->popFirst()) != nullptr) while ((d = mList.popFirst()) != nullptr)
delete d; delete d;
delete mList;
mList = nullptr;
} }
/* nsIRunnable impl; send the data */ /* nsIRunnable impl; send the data */
@ -620,7 +650,7 @@ public:
DebugGLData *d; DebugGLData *d;
nsresult rv = NS_OK; nsresult rv = NS_OK;
while ((d = mList->popFirst()) != nullptr) { while ((d = mList.popFirst()) != nullptr) {
std::auto_ptr<DebugGLData> cleaner(d); std::auto_ptr<DebugGLData> cleaner(d);
if (!d->Write()) { if (!d->Write()) {
rv = NS_ERROR_FAILURE; rv = NS_ERROR_FAILURE;
@ -631,84 +661,124 @@ public:
Cleanup(); Cleanup();
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
LayerScope::DestroyServerSocket(); WebSocketHelper::DestroyServerSocket();
} }
return NS_OK; return NS_OK;
} }
protected: protected:
LinkedList<DebugGLData> *mList; LinkedList<DebugGLData> mList;
}; };
NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable); NS_IMPL_ISUPPORTS(DebugDataSender, nsIRunnable);
void /*
LayerScope::CreateServerSocket() * LayerScope SendXXX Structure
* 1. SendLayer
* 2. SendEffectChain
* 1. SendTexturedEffect
* -> SendTextureSource
* 2. SendYCbCrEffect
* -> SendTextureSource
* 3. SendColor
*/
class SenderHelper
{ {
if (!gfxPrefs::LayerScopeEnabled()) { // Sender public APIs
public:
static void SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight);
static void SendEffectChain(gl::GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth = 0,
int aHeight = 0);
// Sender private functions
private:
static void SendColor(void* aLayerRef,
const gfxRGBA& aColor,
int aWidth,
int aHeight);
static void SendTextureSource(GLContext* aGLContext,
void* aLayerRef,
TextureSourceOGL* aSource,
bool aFlipY);
static void SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef,
const TexturedEffect* aEffect);
static void SendYCbCrEffect(GLContext* aGLContext,
void* aLayerRef,
const EffectYCbCr* aEffect);
};
// ----------------------------------------------
// SenderHelper implementation
// ----------------------------------------------
void
SenderHelper::SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight)
{
MOZ_ASSERT(aLayer && aLayer->GetLayer());
if (!aLayer || !aLayer->GetLayer()) {
return; return;
} }
if (!gLayerScopeWebSocketManager) { switch (aLayer->GetLayer()->GetType()) {
gLayerScopeWebSocketManager = new LayerScopeWebSocketManager(); case Layer::TYPE_COLOR: {
EffectChain effect;
aLayer->GenEffectChain(effect);
SenderHelper::SendEffectChain(nullptr, effect, aWidth, aHeight);
break;
}
case Layer::TYPE_IMAGE:
case Layer::TYPE_CANVAS:
case Layer::TYPE_THEBES: {
// Get CompositableHost and Compositor
CompositableHost* compHost = aLayer->GetCompositableHost();
Compositor* comp = compHost->GetCompositor();
// Send EffectChain only for CompositorOGL
if (LayersBackend::LAYERS_OPENGL == comp->GetBackendType()) {
CompositorOGL* compOGL = static_cast<CompositorOGL*>(comp);
EffectChain effect;
// Generate primary effect (lock and gen)
AutoLockCompositableHost lock(compHost);
aLayer->GenEffectChain(effect);
SenderHelper::SendEffectChain(compOGL->gl(), effect);
}
break;
}
case Layer::TYPE_CONTAINER:
default:
break;
} }
} }
void void
LayerScope::DestroyServerSocket() SenderHelper::SendColor(void* aLayerRef,
const gfxRGBA& aColor,
int aWidth,
int aHeight)
{ {
if (gLayerScopeWebSocketManager) { WebSocketHelper::GetSocketManager()->AppendDebugData(
gLayerScopeWebSocketManager->RemoveAllConnections();
}
}
void
LayerScope::BeginFrame(GLContext* aGLContext, int64_t aFrameStamp)
{
if (!gLayerScopeWebSocketManager)
return;
if (!gLayerScopeWebSocketManager->IsConnected())
return;
#if 0
// if we're sending data in between frames, flush the list down the socket,
// and start a new one
if (gCurrentSender) {
gDebugSenderThread->Dispatch(gCurrentSender, NS_DISPATCH_NORMAL);
}
#endif
gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameStart, aGLContext, aFrameStamp));
}
void
LayerScope::EndFrame(GLContext* aGLContext)
{
if (!CheckSender())
return;
gLayerScopeWebSocketManager->AppendDebugData(new DebugGLData(DebugGLData::FrameEnd, aGLContext));
gLayerScopeWebSocketManager->DispatchDebugData();
}
static void
SendColor(void* aLayerRef, const gfxRGBA& aColor, int aWidth, int aHeight)
{
if (!CheckSender())
return;
gLayerScopeWebSocketManager->AppendDebugData(
new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight)); new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
} }
static void void
SendTextureSource(GLContext* aGLContext, SenderHelper::SendTextureSource(GLContext* aGLContext,
void* aLayerRef, void* aLayerRef,
TextureSourceOGL* aSource, TextureSourceOGL* aSource,
bool aFlipY) bool aFlipY)
{ {
MOZ_ASSERT(aGLContext);
if (!aGLContext) {
return;
}
GLenum textureTarget = aSource->GetTextureTarget(); GLenum textureTarget = aSource->GetTextureTarget();
ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget, ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget,
aSource->GetFormat()); aSource->GetFormat());
@ -736,15 +806,15 @@ SendTextureSource(GLContext* aGLContext,
size, size,
shaderConfig, aFlipY); shaderConfig, aFlipY);
gLayerScopeWebSocketManager->AppendDebugData( WebSocketHelper::GetSocketManager()->AppendDebugData(
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget, new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
textureId, img)); textureId, img));
} }
static void void
SendTexturedEffect(GLContext* aGLContext, SenderHelper::SendTexturedEffect(GLContext* aGLContext,
void* aLayerRef, void* aLayerRef,
const TexturedEffect* aEffect) const TexturedEffect* aEffect)
{ {
TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL(); TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
if (!source) if (!source)
@ -754,10 +824,10 @@ SendTexturedEffect(GLContext* aGLContext,
SendTextureSource(aGLContext, aLayerRef, source, flipY); SendTextureSource(aGLContext, aLayerRef, source, flipY);
} }
static void void
SendYCbCrEffect(GLContext* aGLContext, SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
void* aLayerRef, void* aLayerRef,
const EffectYCbCr* aEffect) const EffectYCbCr* aEffect)
{ {
TextureSource* sourceYCbCr = aEffect->mTexture; TextureSource* sourceYCbCr = aEffect->mTexture;
if (!sourceYCbCr) if (!sourceYCbCr)
@ -775,49 +845,48 @@ SendYCbCrEffect(GLContext* aGLContext,
} }
void void
LayerScope::SendEffectChain(GLContext* aGLContext, SenderHelper::SendEffectChain(GLContext* aGLContext,
const EffectChain& aEffectChain, const EffectChain& aEffectChain,
int aWidth, int aHeight) int aWidth,
int aHeight)
{ {
if (!CheckSender())
return;
const Effect* primaryEffect = aEffectChain.mPrimaryEffect; const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
switch (primaryEffect->mType) { switch (primaryEffect->mType) {
case EffectTypes::RGB: case EffectTypes::RGB: {
{ const TexturedEffect* texturedEffect =
const TexturedEffect* texturedEffect = static_cast<const TexturedEffect*>(primaryEffect);
static_cast<const TexturedEffect*>(primaryEffect); SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect); break;
} }
break; case EffectTypes::YCBCR: {
case EffectTypes::YCBCR: const EffectYCbCr* yCbCrEffect =
{ static_cast<const EffectYCbCr*>(primaryEffect);
const EffectYCbCr* yCbCrEffect = SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
static_cast<const EffectYCbCr*>(primaryEffect); break;
SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect); }
} case EffectTypes::SOLID_COLOR: {
case EffectTypes::SOLID_COLOR: const EffectSolidColor* solidColorEffect =
{ static_cast<const EffectSolidColor*>(primaryEffect);
const EffectSolidColor* solidColorEffect = gfxRGBA color(solidColorEffect->mColor.r,
static_cast<const EffectSolidColor*>(primaryEffect); solidColorEffect->mColor.g,
gfxRGBA color(solidColorEffect->mColor.r, solidColorEffect->mColor.b,
solidColorEffect->mColor.g, solidColorEffect->mColor.a);
solidColorEffect->mColor.b, SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight);
solidColorEffect->mColor.a); break;
SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight); }
} case EffectTypes::COMPONENT_ALPHA:
break; case EffectTypes::RENDER_TARGET:
case EffectTypes::COMPONENT_ALPHA: default:
case EffectTypes::RENDER_TARGET: break;
default:
break;
} }
//const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK]; //const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
// TODO: // TODO:
} }
// ----------------------------------------------
// LayerScopeWebSocketManager implementation
// ----------------------------------------------
LayerScopeWebSocketManager::LayerScopeWebSocketManager() LayerScopeWebSocketManager::LayerScopeWebSocketManager()
{ {
NS_NewThread(getter_AddRefs(mDebugSenderThread)); NS_NewThread(getter_AddRefs(mDebugSenderThread));
@ -832,7 +901,8 @@ LayerScopeWebSocketManager::~LayerScopeWebSocketManager()
{ {
} }
void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData) void
LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
{ {
if (!mCurrentSender) { if (!mCurrentSender) {
mCurrentSender = new DebugDataSender(); mCurrentSender = new DebugDataSender();
@ -841,11 +911,125 @@ void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
mCurrentSender->Append(aDebugData); mCurrentSender->Append(aDebugData);
} }
void LayerScopeWebSocketManager::DispatchDebugData() void
LayerScopeWebSocketManager::CleanDebugData()
{
if (mCurrentSender) {
mCurrentSender->Cleanup();
}
}
void
LayerScopeWebSocketManager::DispatchDebugData()
{ {
mDebugSenderThread->Dispatch(mCurrentSender, NS_DISPATCH_NORMAL); mDebugSenderThread->Dispatch(mCurrentSender, NS_DISPATCH_NORMAL);
mCurrentSender = nullptr; mCurrentSender = nullptr;
} }
// ----------------------------------------------
// LayerScope implementation
// ----------------------------------------------
void
LayerScope::Init()
{
if (!gfxPrefs::LayerScopeEnabled()) {
return;
}
// Note: The server socket has to be created on the main thread
WebSocketHelper::CreateServerSocket();
}
void
LayerScope::DeInit()
{
// Destroy Web Server Socket
WebSocketHelper::DestroyServerSocket();
}
void
LayerScope::SendEffectChain(gl::GLContext* aGLContext,
const EffectChain& aEffectChain,
int aWidth,
int aHeight)
{
// Protect this public function
if (!CheckSendable()) {
return;
}
SenderHelper::SendEffectChain(aGLContext, aEffectChain, aWidth, aHeight);
}
void
LayerScope::SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight)
{
// Protect this public function
if (!CheckSendable()) {
return;
}
SenderHelper::SendLayer(aLayer, aWidth, aHeight);
}
bool
LayerScope::CheckSendable()
{
if (!WebSocketHelper::GetSocketManager()) {
return false;
}
if (!WebSocketHelper::GetSocketManager()->IsConnected()) {
return false;
}
return true;
}
void
LayerScope::CleanLayer()
{
if (CheckSendable()) {
WebSocketHelper::GetSocketManager()->CleanDebugData();
}
}
// ----------------------------------------------
// LayerScopeAutoFrame implementation
// ----------------------------------------------
LayerScopeAutoFrame::LayerScopeAutoFrame(int64_t aFrameStamp)
{
// Do Begin Frame
BeginFrame(aFrameStamp);
}
LayerScopeAutoFrame::~LayerScopeAutoFrame()
{
// Do End Frame
EndFrame();
}
void
LayerScopeAutoFrame::BeginFrame(int64_t aFrameStamp)
{
if (!LayerScope::CheckSendable()) {
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
new DebugGLData(DebugGLData::FrameStart, nullptr, aFrameStamp));
}
void
LayerScopeAutoFrame::EndFrame()
{
if (!LayerScope::CheckSendable()) {
return;
}
WebSocketHelper::GetSocketManager()->AppendDebugData(
new DebugGLData(DebugGLData::FrameEnd, nullptr));
WebSocketHelper::GetSocketManager()->DispatchDebugData();
}
} /* layers */ } /* layers */
} /* mozilla */ } /* mozilla */

View File

@ -17,16 +17,32 @@ namespace gl { class GLContext; }
namespace layers { namespace layers {
struct EffectChain; struct EffectChain;
class LayerComposite;
class LayerScope { class LayerScope {
public: public:
static void CreateServerSocket(); static void Init();
static void DestroyServerSocket(); static void DeInit();
static void BeginFrame(gl::GLContext* aGLContext, int64_t aFrameStamp);
static void EndFrame(gl::GLContext* aGLContext);
static void SendEffectChain(gl::GLContext* aGLContext, static void SendEffectChain(gl::GLContext* aGLContext,
const EffectChain& aEffectChain, const EffectChain& aEffectChain,
int aWidth, int aHeight); int aWidth,
int aHeight);
static void SendLayer(LayerComposite* aLayer,
int aWidth,
int aHeight);
static bool CheckSendable();
static void CleanLayer();
};
// Perform BeginFrame and EndFrame automatically
class LayerScopeAutoFrame {
public:
LayerScopeAutoFrame(int64_t aFrameStamp);
~LayerScopeAutoFrame();
private:
static void BeginFrame(int64_t aFrameStamp);
static void EndFrame();
}; };
} /* layers */ } /* layers */

View File

@ -87,18 +87,6 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
} }
#endif #endif
GraphicsFilter filter = mFilter;
#ifdef ANDROID
// Bug 691354
// Using the LINEAR filter we get unexplained artifacts.
// Use NEAREST when no scaling is required.
Matrix matrix;
bool is2D = GetEffectiveTransform().Is2D(&matrix);
if (is2D && !ThebesMatrix(matrix).HasNonTranslationOrFlip()) {
filter = GraphicsFilter::FILTER_NEAREST;
}
#endif
EffectChain effectChain(this); EffectChain effectChain(this);
AddBlendModeEffect(effectChain); AddBlendModeEffect(effectChain);
@ -108,7 +96,7 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
mImageHost->Composite(effectChain, mImageHost->Composite(effectChain,
GetEffectiveOpacity(), GetEffectiveOpacity(),
GetEffectiveTransform(), GetEffectiveTransform(),
gfx::ToFilter(filter), GetEffectFilter(),
clipRect); clipRect);
mImageHost->BumpFlashCounter(); mImageHost->BumpFlashCounter();
} }
@ -132,6 +120,30 @@ CanvasLayerComposite::CleanupResources()
mImageHost = nullptr; mImageHost = nullptr;
} }
gfx::Filter
CanvasLayerComposite::GetEffectFilter()
{
GraphicsFilter filter = mFilter;
#ifdef ANDROID
// Bug 691354
// Using the LINEAR filter we get unexplained artifacts.
// Use NEAREST when no scaling is required.
Matrix matrix;
bool is2D = GetEffectiveTransform().Is2D(&matrix);
if (is2D && !ThebesMatrix(matrix).HasNonTranslationOrFlip()) {
filter = GraphicsFilter::FILTER_NEAREST;
}
#endif
return gfx::ToFilter(filter);
}
void
CanvasLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
aEffect.mPrimaryEffect = mImageHost->GenEffect(GetEffectFilter());
}
void void
CanvasLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix) CanvasLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{ {

View File

@ -52,6 +52,8 @@ public:
virtual void CleanupResources() MOZ_OVERRIDE; virtual void CleanupResources() MOZ_OVERRIDE;
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
CompositableHost* GetCompositableHost() MOZ_OVERRIDE; CompositableHost* GetCompositableHost() MOZ_OVERRIDE;
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; } virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
@ -63,6 +65,9 @@ public:
protected: protected:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE; virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
private:
gfx::Filter GetEffectFilter();
private: private:
RefPtr<CompositableHost> mImageHost; RefPtr<CompositableHost> mImageHost;
}; };

View File

@ -24,11 +24,9 @@ void
ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect) ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect)
{ {
EffectChain effects(this); EffectChain effects(this);
gfxRGBA color(GetColor());
effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r, GenEffectChain(effects);
color.g,
color.b,
color.a));
nsIntRect boundRect = GetBounds(); nsIntRect boundRect = GetBounds();
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(GetMaskLayer(), LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(GetMaskLayer(),
@ -50,5 +48,16 @@ ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect)
transform); transform);
} }
void
ColorLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
gfxRGBA color(GetColor());
aEffect.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r,
color.g,
color.b,
color.a));
}
} /* layers */ } /* layers */
} /* mozilla */ } /* mozilla */

View File

@ -44,6 +44,8 @@ public:
virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE; virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE;
virtual void CleanupResources() MOZ_OVERRIDE {}; virtual void CleanupResources() MOZ_OVERRIDE {};
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
CompositableHost* GetCompositableHost() MOZ_OVERRIDE { return nullptr; } CompositableHost* GetCompositableHost() MOZ_OVERRIDE { return nullptr; }
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; } virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }

View File

@ -17,6 +17,7 @@
#include "mozilla/gfx/Types.h" // for Filter #include "mozilla/gfx/Types.h" // for Filter
#include "mozilla/ipc/ProtocolUtils.h" #include "mozilla/ipc/ProtocolUtils.h"
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc #include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
#include "mozilla/layers/Effects.h" // for Texture Effect
#include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc #include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
#include "mozilla/layers/TextureHost.h" // for TextureHost #include "mozilla/layers/TextureHost.h" // for TextureHost
#include "mozilla/mozalloc.h" // for operator delete #include "mozilla/mozalloc.h" // for operator delete
@ -289,6 +290,14 @@ public:
void SetAsyncID(uint64_t aID) { mAsyncID = aID; } void SetAsyncID(uint64_t aID) { mAsyncID = aID; }
virtual bool Lock() { return false; }
virtual void Unlock() { }
virtual TemporaryRef<TexturedEffect> GenEffect(const gfx::Filter& aFilter) {
return nullptr;
}
protected: protected:
TextureInfo mTextureInfo; TextureInfo mTextureInfo;
uint64_t mAsyncID; uint64_t mAsyncID;
@ -301,6 +310,29 @@ protected:
bool mKeepAttached; bool mKeepAttached;
}; };
class AutoLockCompositableHost MOZ_FINAL
{
public:
AutoLockCompositableHost(CompositableHost* aHost)
: mHost(aHost)
{
mSucceeded = mHost->Lock();
}
~AutoLockCompositableHost()
{
if (mSucceeded) {
mHost->Unlock();
}
}
bool Failed() const { return !mSucceeded; }
private:
RefPtr<CompositableHost> mHost;
bool mSucceeded;
};
/** /**
* Global CompositableMap, to use in the compositor thread only. * Global CompositableMap, to use in the compositor thread only.
* *

View File

@ -35,27 +35,6 @@ ContentHostBase::~ContentHostBase()
{ {
} }
struct AutoLockContentHost
{
AutoLockContentHost(ContentHostBase* aHost)
: mHost(aHost)
{
mSucceeded = mHost->Lock();
}
~AutoLockContentHost()
{
if (mSucceeded) {
mHost->Unlock();
}
}
bool Failed() { return !mSucceeded; }
ContentHostBase* mHost;
bool mSucceeded;
};
void void
ContentHostBase::Composite(EffectChain& aEffectChain, ContentHostBase::Composite(EffectChain& aEffectChain,
float aOpacity, float aOpacity,
@ -67,7 +46,7 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
{ {
NS_ASSERTION(aVisibleRegion, "Requires a visible region"); NS_ASSERTION(aVisibleRegion, "Requires a visible region");
AutoLockContentHost lock(this); AutoLockCompositableHost lock(this);
if (lock.Failed()) { if (lock.Failed()) {
return; return;
} }
@ -78,9 +57,8 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
if (!source) { if (!source) {
return; return;
} }
RefPtr<TexturedEffect> effect =
CreateTexturedEffect(source, sourceOnWhite, aFilter, true);
RefPtr<TexturedEffect> effect = GenEffect(aFilter);
if (!effect) { if (!effect) {
return; return;
} }
@ -229,6 +207,16 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
aTransform, mFlashCounter); aTransform, mFlashCounter);
} }
TemporaryRef<TexturedEffect>
ContentHostBase::GenEffect(const gfx::Filter& aFilter)
{
RefPtr<NewTextureSource> source = GetTextureSource();
RefPtr<NewTextureSource> sourceOnWhite = GetTextureSourceOnWhite();
if (!source) {
return nullptr;
}
return CreateTexturedEffect(source, sourceOnWhite, aFilter, true);
}
void void
ContentHostTexture::UseTextureHost(TextureHost* aTexture) ContentHostTexture::UseTextureHost(TextureHost* aTexture)

View File

@ -102,12 +102,11 @@ public:
virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; } virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; }
virtual bool Lock() = 0;
virtual void Unlock() = 0;
virtual NewTextureSource* GetTextureSource() = 0; virtual NewTextureSource* GetTextureSource() = 0;
virtual NewTextureSource* GetTextureSourceOnWhite() = 0; virtual NewTextureSource* GetTextureSourceOnWhite() = 0;
virtual TemporaryRef<TexturedEffect> GenEffect(const gfx::Filter& aFilter) MOZ_OVERRIDE;
protected: protected:
virtual nsIntPoint GetOriginOffset() virtual nsIntPoint GetOriginOffset()
{ {
@ -150,7 +149,7 @@ public:
virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack, virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
TextureHost* aTextureOnWhite) MOZ_OVERRIDE; TextureHost* aTextureOnWhite) MOZ_OVERRIDE;
virtual bool Lock() { virtual bool Lock() MOZ_OVERRIDE {
MOZ_ASSERT(!mLocked); MOZ_ASSERT(!mLocked);
if (!mTextureHost) { if (!mTextureHost) {
return false; return false;
@ -166,7 +165,7 @@ public:
mLocked = true; mLocked = true;
return true; return true;
} }
virtual void Unlock() { virtual void Unlock() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked); MOZ_ASSERT(mLocked);
mTextureHost->Unlock(); mTextureHost->Unlock();
if (mTextureHostOnWhite) { if (mTextureHostOnWhite) {
@ -175,11 +174,11 @@ public:
mLocked = false; mLocked = false;
} }
virtual NewTextureSource* GetTextureSource() { virtual NewTextureSource* GetTextureSource() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked); MOZ_ASSERT(mLocked);
return mTextureHost->GetTextureSources(); return mTextureHost->GetTextureSources();
} }
virtual NewTextureSource* GetTextureSourceOnWhite() { virtual NewTextureSource* GetTextureSourceOnWhite() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked); MOZ_ASSERT(mLocked);
if (mTextureHostOnWhite) { if (mTextureHostOnWhite) {
return mTextureHostOnWhite->GetTextureSources(); return mTextureHostOnWhite->GetTextureSources();
@ -281,20 +280,20 @@ public:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE; virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
virtual bool Lock() { virtual bool Lock() MOZ_OVERRIDE {
MOZ_ASSERT(!mLocked); MOZ_ASSERT(!mLocked);
ProcessTextureUpdates(); ProcessTextureUpdates();
mLocked = true; mLocked = true;
return true; return true;
} }
virtual void Unlock() { virtual void Unlock() MOZ_OVERRIDE {
MOZ_ASSERT(mLocked); MOZ_ASSERT(mLocked);
mLocked = false; mLocked = false;
} }
virtual NewTextureSource* GetTextureSource(); virtual NewTextureSource* GetTextureSource() MOZ_OVERRIDE;
virtual NewTextureSource* GetTextureSourceOnWhite(); virtual NewTextureSource* GetTextureSourceOnWhite() MOZ_OVERRIDE;
private: private:

View File

@ -31,6 +31,7 @@ ImageHost::ImageHost(const TextureInfo& aTextureInfo)
: CompositableHost(aTextureInfo) : CompositableHost(aTextureInfo)
, mFrontBuffer(nullptr) , mFrontBuffer(nullptr)
, mHasPictureRect(false) , mHasPictureRect(false)
, mLocked(false)
{} {}
ImageHost::~ImageHost() {} ImageHost::~ImageHost() {}
@ -81,24 +82,17 @@ ImageHost::Composite(EffectChain& aEffectChain,
mFrontBuffer->SetCompositor(GetCompositor()); mFrontBuffer->SetCompositor(GetCompositor());
mFrontBuffer->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData()); mFrontBuffer->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
AutoLockTextureHost autoLock(mFrontBuffer); AutoLockCompositableHost autoLock(this);
if (autoLock.Failed()) { if (autoLock.Failed()) {
NS_WARNING("failed to lock front buffer"); NS_WARNING("failed to lock front buffer");
return; return;
} }
RefPtr<NewTextureSource> source = mFrontBuffer->GetTextureSources(); RefPtr<NewTextureSource> source = GetTextureSource();
if (!source) { if (!source) {
return; return;
} }
bool isAlphaPremultiplied = true; RefPtr<TexturedEffect> effect = GenEffect(aFilter);
if (mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED)
isAlphaPremultiplied = false;
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mFrontBuffer->GetFormat(),
source,
aFilter,
isAlphaPremultiplied);
if (!effect) { if (!effect) {
return; return;
} }
@ -243,5 +237,48 @@ ImageHost::GetAsSurface()
} }
#endif #endif
bool
ImageHost::Lock()
{
MOZ_ASSERT(!mLocked);
if (!mFrontBuffer->Lock()) {
return false;
}
mLocked = true;
return true;
}
void
ImageHost::Unlock()
{
MOZ_ASSERT(mLocked);
mFrontBuffer->Unlock();
mLocked = false;
}
TemporaryRef<NewTextureSource>
ImageHost::GetTextureSource()
{
MOZ_ASSERT(mLocked);
return mFrontBuffer->GetTextureSources();
}
TemporaryRef<TexturedEffect>
ImageHost::GenEffect(const gfx::Filter& aFilter)
{
RefPtr<NewTextureSource> source = GetTextureSource();
if (!source) {
return nullptr;
}
bool isAlphaPremultiplied = true;
if (mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED)
isAlphaPremultiplied = false;
return CreateTexturedEffect(mFrontBuffer->GetFormat(),
source,
aFilter,
isAlphaPremultiplied);
}
} }
} }

View File

@ -79,11 +79,20 @@ public:
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE; virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
#endif #endif
virtual bool Lock() MOZ_OVERRIDE;
virtual void Unlock() MOZ_OVERRIDE;
virtual TemporaryRef<NewTextureSource> GetTextureSource();
virtual TemporaryRef<TexturedEffect> GenEffect(const gfx::Filter& aFilter) MOZ_OVERRIDE;
protected: protected:
RefPtr<TextureHost> mFrontBuffer; RefPtr<TextureHost> mFrontBuffer;
nsIntRect mPictureRect; nsIntRect mPictureRect;
bool mHasPictureRect; bool mHasPictureRect;
bool mLocked;
}; };
} }

View File

@ -107,7 +107,7 @@ ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
mImageHost->Composite(effectChain, mImageHost->Composite(effectChain,
GetEffectiveOpacity(), GetEffectiveOpacity(),
GetEffectiveTransform(), GetEffectiveTransform(),
gfx::ToFilter(mFilter), GetEffectFilter(),
clipRect); clipRect);
mImageHost->BumpFlashCounter(); mImageHost->BumpFlashCounter();
} }
@ -161,6 +161,19 @@ ImageLayerComposite::CleanupResources()
mImageHost = nullptr; mImageHost = nullptr;
} }
gfx::Filter
ImageLayerComposite::GetEffectFilter()
{
return gfx::ToFilter(mFilter);
}
void
ImageLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
aEffect.mPrimaryEffect = mImageHost->GenEffect(GetEffectFilter());
}
void void
ImageLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix) ImageLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix)
{ {

View File

@ -51,6 +51,8 @@ public:
CompositableHost* GetCompositableHost() MOZ_OVERRIDE; CompositableHost* GetCompositableHost() MOZ_OVERRIDE;
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; } virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
virtual const char* Name() const { return "ImageLayerComposite"; } virtual const char* Name() const { return "ImageLayerComposite"; }
@ -58,6 +60,9 @@ public:
protected: protected:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE; virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
private:
gfx::Filter GetEffectFilter();
private: private:
RefPtr<CompositableHost> mImageHost; RefPtr<CompositableHost> mImageHost;
}; };

View File

@ -16,6 +16,7 @@
#include "GeckoProfiler.h" // for profiler_set_frame_number, etc #include "GeckoProfiler.h" // for profiler_set_frame_number, etc
#include "ImageLayerComposite.h" // for ImageLayerComposite #include "ImageLayerComposite.h" // for ImageLayerComposite
#include "Layers.h" // for Layer, ContainerLayer, etc #include "Layers.h" // for Layer, ContainerLayer, etc
#include "LayerScope.h" // for LayerScope Tool
#include "ThebesLayerComposite.h" // for ThebesLayerComposite #include "ThebesLayerComposite.h" // for ThebesLayerComposite
#include "TiledLayerBuffer.h" // for TiledLayerComposer #include "TiledLayerBuffer.h" // for TiledLayerComposer
#include "Units.h" // for ScreenIntRect #include "Units.h" // for ScreenIntRect
@ -417,6 +418,9 @@ LayerManagerComposite::Render()
/** Our more efficient but less powerful alter ego, if one is available. */ /** Our more efficient but less powerful alter ego, if one is available. */
nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D(); nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
// Set LayerScope begin/end frame
LayerScopeAutoFrame frame(PR_Now());
if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) { if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) {
if (mFPS) { if (mFPS) {
double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now()); double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());

View File

@ -74,7 +74,7 @@ class LayerManagerComposite : public LayerManager
public: public:
LayerManagerComposite(Compositor* aCompositor); LayerManagerComposite(Compositor* aCompositor);
~LayerManagerComposite(); ~LayerManagerComposite();
virtual void Destroy() MOZ_OVERRIDE; virtual void Destroy() MOZ_OVERRIDE;
/** /**
@ -267,7 +267,7 @@ private:
RefPtr<Compositor> mCompositor; RefPtr<Compositor> mCompositor;
nsAutoPtr<LayerProperties> mClonedLayerTreeProperties; nsAutoPtr<LayerProperties> mClonedLayerTreeProperties;
/** /**
* Context target, nullptr when drawing directly to our swap chain. * Context target, nullptr when drawing directly to our swap chain.
*/ */
RefPtr<gfx::DrawTarget> mTarget; RefPtr<gfx::DrawTarget> mTarget;
@ -336,11 +336,12 @@ public:
virtual TiledLayerComposer* GetTiledLayerComposer() { return nullptr; } virtual TiledLayerComposer* GetTiledLayerComposer() { return nullptr; }
virtual void DestroyFrontBuffer() { } virtual void DestroyFrontBuffer() { }
void AddBlendModeEffect(EffectChain& aEffectChain); void AddBlendModeEffect(EffectChain& aEffectChain);
virtual void GenEffectChain(EffectChain& aEffect) { }
/** /**
* The following methods are * The following methods are
* *

View File

@ -147,7 +147,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
mBuffer->Composite(effectChain, mBuffer->Composite(effectChain,
GetEffectiveOpacity(), GetEffectiveOpacity(),
GetEffectiveTransform(), GetEffectiveTransform(),
gfx::Filter::LINEAR, GetEffectFilter(),
clipRect, clipRect,
&visibleRegion, &visibleRegion,
mRequiresTiledProperties ? &tiledLayerProps mRequiresTiledProperties ? &tiledLayerProps
@ -180,6 +180,13 @@ ThebesLayerComposite::CleanupResources()
mBuffer = nullptr; mBuffer = nullptr;
} }
void
ThebesLayerComposite::GenEffectChain(EffectChain& aEffect)
{
aEffect.mLayerRef = this;
aEffect.mPrimaryEffect = mBuffer->GenEffect(GetEffectFilter());
}
CSSToScreenScale CSSToScreenScale
ThebesLayerComposite::GetEffectiveResolution() ThebesLayerComposite::GetEffectiveResolution()
{ {

View File

@ -56,6 +56,8 @@ public:
virtual void CleanupResources() MOZ_OVERRIDE; virtual void CleanupResources() MOZ_OVERRIDE;
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
virtual bool SetCompositableHost(CompositableHost* aHost) MOZ_OVERRIDE; virtual bool SetCompositableHost(CompositableHost* aHost) MOZ_OVERRIDE;
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; } virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
@ -81,8 +83,11 @@ protected:
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE; virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
private: private:
gfx::Filter GetEffectFilter() { return gfx::Filter::LINEAR; }
CSSToScreenScale GetEffectiveResolution(); CSSToScreenScale GetEffectiveResolution();
private:
RefPtr<ContentHost> mBuffer; RefPtr<ContentHost> mBuffer;
bool mRequiresTiledProperties; bool mRequiresTiledProperties;
}; };

View File

@ -706,8 +706,6 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame"); MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
LayerScope::BeginFrame(mGLContext, PR_Now());
mFrameInProgress = true; mFrameInProgress = true;
gfx::Rect rect; gfx::Rect rect;
if (mUseExternalSurfaceSize) { if (mUseExternalSurfaceSize) {
@ -1313,8 +1311,6 @@ CompositorOGL::EndFrame()
mFrameInProgress = false; mFrameInProgress = false;
LayerScope::EndFrame(mGLContext);
if (mTarget) { if (mTarget) {
CopyToTarget(mTarget, mTargetBounds.TopLeft(), mCurrentRenderTarget->GetTransform()); CopyToTarget(mTarget, mTargetBounds.TopLeft(), mCurrentRenderTarget->GetTransform());
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);

View File

@ -37,11 +37,6 @@ class PBackgroundChild;
// (assuming success) GetForCurrentThread() will return the same actor every // (assuming success) GetForCurrentThread() will return the same actor every
// time. // time.
// //
// CloseForCurrentThread() will close the current PBackground actor. Subsequent
// calls to GetForCurrentThread will return null. CloseForCurrentThread() may
// only be called exactly once per thread. Currently it is illegal to call this
// before the PBackground actor has been created.
//
// The PBackgroundChild actor and all its sub-protocol actors will be // The PBackgroundChild actor and all its sub-protocol actors will be
// automatically destroyed when its designated thread completes. // automatically destroyed when its designated thread completes.
class BackgroundChild MOZ_FINAL class BackgroundChild MOZ_FINAL
@ -61,10 +56,6 @@ public:
static bool static bool
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback); GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
// See above.
static void
CloseForCurrentThread();
private: private:
// Only called by ContentChild or ContentParent. // Only called by ContentChild or ContentParent.
static void static void

View File

@ -350,8 +350,6 @@ class ChildImpl MOZ_FINAL : public BackgroundChildImpl
nsIThread* mBoundThread; nsIThread* mBoundThread;
#endif #endif
DebugOnly<bool> mActorDestroyed;
public: public:
static bool static bool
OpenProtocolOnMainThread(nsIEventTarget* aEventTarget); OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
@ -374,15 +372,8 @@ public:
THREADSAFETY_ASSERT(current); THREADSAFETY_ASSERT(current);
} }
void
AssertActorDestroyed()
{
MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
}
ChildImpl() ChildImpl()
: mBoundThread(nullptr) : mBoundThread(nullptr)
, mActorDestroyed(false)
{ {
AssertIsOnMainThread(); AssertIsOnMainThread();
} }
@ -406,10 +397,6 @@ private:
static bool static bool
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback); GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
// Forwarded from BackgroundChild.
static void
CloseForCurrentThread();
// Forwarded from BackgroundChildImpl. // Forwarded from BackgroundChildImpl.
static BackgroundChildImpl::ThreadLocal* static BackgroundChildImpl::ThreadLocal*
GetThreadLocalForCurrentThread(); GetThreadLocalForCurrentThread();
@ -422,17 +409,6 @@ private:
if (threadLocalInfo) { if (threadLocalInfo) {
if (threadLocalInfo->mActor) { if (threadLocalInfo->mActor) {
threadLocalInfo->mActor->Close(); threadLocalInfo->mActor->Close();
threadLocalInfo->mActor->AssertActorDestroyed();
// Since the actor is created on the main thread it must only
// be released on the main thread as well.
if (!NS_IsMainThread()) {
ChildImpl* actor;
threadLocalInfo->mActor.forget(&actor);
nsCOMPtr<nsIRunnable> releaser =
NS_NewNonOwningRunnableMethod(actor, &ChildImpl::Release);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(releaser)));
}
} }
delete threadLocalInfo; delete threadLocalInfo;
} }
@ -443,9 +419,7 @@ private:
// This class is reference counted. // This class is reference counted.
~ChildImpl() ~ChildImpl()
{ { }
AssertActorDestroyed();
}
void void
SetBoundThread() SetBoundThread()
@ -861,13 +835,6 @@ BackgroundChild::GetOrCreateForCurrentThread(
return ChildImpl::GetOrCreateForCurrentThread(aCallback); return ChildImpl::GetOrCreateForCurrentThread(aCallback);
} }
// static
void
BackgroundChild::CloseForCurrentThread()
{
ChildImpl::CloseForCurrentThread();
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// BackgroundChildImpl Public Methods // BackgroundChildImpl Public Methods
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -1611,11 +1578,7 @@ ChildImpl::GetForCurrentThread()
auto threadLocalInfo = auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex)); static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
if (!threadLocalInfo) { return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
return nullptr;
}
return threadLocalInfo->mActor;
} }
// static // static
@ -1679,31 +1642,6 @@ ChildImpl::GetOrCreateForCurrentThread(
return true; return true;
} }
// static
void
ChildImpl::CloseForCurrentThread()
{
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex,
"BackgroundChild::Startup() was never called!");
auto threadLocalInfo =
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
// If we don't have a thread local we are in one of these conditions:
// 1) Startup has not completed and we are racing
// 2) We were called again after a previous close or shutdown
// For now, these should not happen, so crash. We can add extra complexity
// in the future if it turns out we need to support these cases.
if (!threadLocalInfo) {
MOZ_CRASH("Attempting to close a non-existent PBackground actor!");
}
if (threadLocalInfo->mActor) {
threadLocalInfo->mActor->FlushPendingInterruptQueue();
}
DebugOnly<PRStatus> status = PR_SetThreadPrivate(sThreadLocalIndex, nullptr);
MOZ_ASSERT(status == PR_SUCCESS);
}
// static // static
BackgroundChildImpl::ThreadLocal* BackgroundChildImpl::ThreadLocal*
ChildImpl::GetThreadLocalForCurrentThread() ChildImpl::GetThreadLocalForCurrentThread()
@ -2008,7 +1946,6 @@ ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
{ {
AssertIsOnBoundThread(); AssertIsOnBoundThread();
mActorDestroyed = true;
BackgroundChildImpl::ActorDestroy(aWhy); BackgroundChildImpl::ActorDestroy(aWhy);
} }

View File

@ -7,13 +7,11 @@
#include "nsIRunnable.h" #include "nsIRunnable.h"
#include "nsIThread.h" #include "nsIThread.h"
#include "nsITimer.h" #include "nsITimer.h"
#include "nsICancelableRunnable.h"
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/scoped_nsautorelease_pool.h" #include "base/scoped_nsautorelease_pool.h"
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/DebugOnly.h" #include "mozilla/DebugOnly.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "nsDebug.h" #include "nsDebug.h"
@ -42,14 +40,12 @@ static mozilla::DebugOnly<MessagePump::Delegate*> gFirstDelegate;
namespace mozilla { namespace mozilla {
namespace ipc { namespace ipc {
class DoWorkRunnable MOZ_FINAL : public nsICancelableRunnable, class DoWorkRunnable MOZ_FINAL : public nsIRunnable,
public nsITimerCallback public nsITimerCallback
{ {
public: public:
DoWorkRunnable(MessagePump* aPump) DoWorkRunnable(MessagePump* aPump)
: mPump(aPump) : mPump(aPump)
, mCanceled(false)
, mCallingRunWhileCanceled(false)
{ {
MOZ_ASSERT(aPump); MOZ_ASSERT(aPump);
} }
@ -57,15 +53,12 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE NS_DECL_NSIRUNNABLE
NS_DECL_NSITIMERCALLBACK NS_DECL_NSITIMERCALLBACK
NS_DECL_NSICANCELABLERUNNABLE
private: private:
~DoWorkRunnable() ~DoWorkRunnable()
{ } { }
MessagePump* mPump; MessagePump* mPump;
bool mCanceled;
bool mCallingRunWhileCanceled;
}; };
} /* namespace ipc */ } /* namespace ipc */
@ -218,17 +211,11 @@ MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate)
} }
} }
NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback, NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback)
nsICancelableRunnable)
NS_IMETHODIMP NS_IMETHODIMP
DoWorkRunnable::Run() DoWorkRunnable::Run()
{ {
MOZ_ASSERT(!mCanceled || mCallingRunWhileCanceled);
if (mCanceled && !mCallingRunWhileCanceled) {
return NS_OK;
}
MessageLoop* loop = MessageLoop::current(); MessageLoop* loop = MessageLoop::current();
MOZ_ASSERT(loop); MOZ_ASSERT(loop);
@ -255,23 +242,6 @@ DoWorkRunnable::Notify(nsITimer* aTimer)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
DoWorkRunnable::Cancel()
{
MOZ_ASSERT(!mCanceled);
MOZ_ASSERT(!mCallingRunWhileCanceled);
// Workers require cancelable runnables, but we can't really cancel cleanly
// here. If we don't process all of these then we will leave something
// unprocessed in the chromium queue. Therefore, eagerly complete our work
// instead by immediately calling Run().
mCanceled = true;
mozilla::AutoRestore<bool> guard(mCallingRunWhileCanceled);
mCallingRunWhileCanceled = true;
Run();
return NS_OK;
}
void void
MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate) MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate)
{ {

View File

@ -31,7 +31,6 @@
#include "nsStyleUtil.h" #include "nsStyleUtil.h"
#include "mozilla/css/Declaration.h" #include "mozilla/css/Declaration.h"
#include "nsCSSParser.h" #include "nsCSSParser.h"
#include "nsPrintfCString.h"
#include "nsDOMClassInfoID.h" #include "nsDOMClassInfoID.h"
#include "mozilla/dom/CSSStyleDeclarationBinding.h" #include "mozilla/dom/CSSStyleDeclarationBinding.h"
#include "StyleRule.h" #include "StyleRule.h"
@ -1408,52 +1407,6 @@ AppendSerializedFontSrc(const nsCSSValue& src, nsAString & aResult)
aResult.Truncate(aResult.Length() - 2); // remove the last comma-space aResult.Truncate(aResult.Length() - 2); // remove the last comma-space
} }
// print all characters with at least four hex digits
static void
AppendSerializedUnicodePoint(uint32_t aCode, nsACString &aBuf)
{
aBuf.Append(nsPrintfCString("%04X", aCode));
}
// A unicode-range: descriptor is represented as an array of integers,
// to be interpreted as a sequence of pairs: min max min max ...
// It is in source order. (Possibly it should be sorted and overlaps
// consolidated, but right now we don't do that.)
static void
AppendSerializedUnicodeRange(nsCSSValue const & aValue,
nsAString & aResult)
{
NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Null ||
aValue.GetUnit() == eCSSUnit_Array,
"improper value unit for unicode-range:");
aResult.Truncate();
if (aValue.GetUnit() != eCSSUnit_Array)
return;
nsCSSValue::Array const & sources = *aValue.GetArrayValue();
nsAutoCString buf;
NS_ABORT_IF_FALSE(sources.Count() % 2 == 0,
"odd number of entries in a unicode-range: array");
for (uint32_t i = 0; i < sources.Count(); i += 2) {
uint32_t min = sources[i].GetIntValue();
uint32_t max = sources[i+1].GetIntValue();
// We don't try to replicate the U+XX?? notation.
buf.AppendLiteral("U+");
AppendSerializedUnicodePoint(min, buf);
if (min != max) {
buf.Append('-');
AppendSerializedUnicodePoint(max, buf);
}
buf.AppendLiteral(", ");
}
buf.Truncate(buf.Length() - 2); // remove the last comma-space
CopyASCIItoUTF16(buf, aResult);
}
// Mapping from nsCSSFontDesc codes to nsCSSFontFaceStyleDecl fields. // Mapping from nsCSSFontDesc codes to nsCSSFontFaceStyleDecl fields.
nsCSSValue nsCSSFontFaceStyleDecl::* const nsCSSValue nsCSSFontFaceStyleDecl::* const
nsCSSFontFaceStyleDecl::Fields[] = { nsCSSFontFaceStyleDecl::Fields[] = {
@ -1539,7 +1492,7 @@ nsCSSFontFaceStyleDecl::GetPropertyValue(nsCSSFontDesc aFontDescID,
return NS_OK; return NS_OK;
case eCSSFontDesc_UnicodeRange: case eCSSFontDesc_UnicodeRange:
AppendSerializedUnicodeRange(val, aResult); nsStyleUtil::AppendUnicodeRange(val, aResult);
return NS_OK; return NS_OK;
case eCSSFontDesc_UNKNOWN: case eCSSFontDesc_UNKNOWN:

View File

@ -13,6 +13,7 @@
#include "nsIContentPolicy.h" #include "nsIContentPolicy.h"
#include "nsIContentSecurityPolicy.h" #include "nsIContentSecurityPolicy.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsPrintfCString.h"
using namespace mozilla; using namespace mozilla;
@ -461,6 +462,51 @@ nsStyleUtil::ComputeFunctionalAlternates(const nsCSSValueList* aList,
} }
} }
// print all characters with at least four hex digits
static void
AppendSerializedUnicodePoint(uint32_t aCode, nsACString& aBuf)
{
aBuf.Append(nsPrintfCString("%04X", aCode));
}
// A unicode-range: descriptor is represented as an array of integers,
// to be interpreted as a sequence of pairs: min max min max ...
// It is in source order. (Possibly it should be sorted and overlaps
// consolidated, but right now we don't do that.)
/* static */ void
nsStyleUtil::AppendUnicodeRange(const nsCSSValue& aValue, nsAString& aResult)
{
NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Null ||
aValue.GetUnit() == eCSSUnit_Array,
"improper value unit for unicode-range:");
aResult.Truncate();
if (aValue.GetUnit() != eCSSUnit_Array)
return;
nsCSSValue::Array const & sources = *aValue.GetArrayValue();
nsAutoCString buf;
NS_ABORT_IF_FALSE(sources.Count() % 2 == 0,
"odd number of entries in a unicode-range: array");
for (uint32_t i = 0; i < sources.Count(); i += 2) {
uint32_t min = sources[i].GetIntValue();
uint32_t max = sources[i+1].GetIntValue();
// We don't try to replicate the U+XX?? notation.
buf.AppendLiteral("U+");
AppendSerializedUnicodePoint(min, buf);
if (min != max) {
buf.Append('-');
AppendSerializedUnicodePoint(max, buf);
}
buf.AppendLiteral(", ");
}
buf.Truncate(buf.Length() - 2); // remove the last comma-space
CopyASCIItoUTF16(buf, aResult);
}
/* static */ float /* static */ float
nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha) nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha)
{ {

View File

@ -64,6 +64,8 @@ public:
static void AppendFontFeatureSettings(const nsCSSValue& src, static void AppendFontFeatureSettings(const nsCSSValue& src,
nsAString& aResult); nsAString& aResult);
static void AppendUnicodeRange(const nsCSSValue& aValue, nsAString& aResult);
static void AppendCSSNumber(float aNumber, nsAString& aResult) static void AppendCSSNumber(float aNumber, nsAString& aResult)
{ {
aResult.AppendFloat(aNumber); aResult.AppendFloat(aNumber);

View File

@ -290,7 +290,9 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver android:name="org.mozilla.gecko.ReferrerReceiver" android:exported="true"> <!-- Catch install referrer so we can do post-install work. -->
<receiver android:name="org.mozilla.gecko.distribution.ReferrerReceiver"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" /> <action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter> </intent-filter>

View File

@ -200,6 +200,13 @@ public final class GeckoProfile {
getGuestDir(context).mkdir(); getGuestDir(context).mkdir();
GeckoProfile profile = getGuestProfile(context); GeckoProfile profile = getGuestProfile(context);
profile.lock(); profile.lock();
/*
* Now do the things that createProfileDirectory normally does --
* right now that's kicking off DB init.
*/
profile.enqueueInitialization();
return profile; return profile;
} catch (Exception ex) { } catch (Exception ex) {
Log.e(LOGTAG, "Error creating guest profile", ex); Log.e(LOGTAG, "Error creating guest profile", ex);

View File

@ -1,62 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import java.net.URLDecoder;
import java.util.HashMap;
public class ReferrerReceiver
extends BroadcastReceiver
{
private static final String LOGTAG = "GeckoReferrerReceiver";
public static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
public static final String UTM_SOURCE = "mozilla";
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_INSTALL_REFERRER.equals(intent.getAction())) {
String referrer = intent.getStringExtra("referrer");
if (referrer == null)
return;
HashMap<String, String> values = new HashMap<String, String>();
try {
String referrers[] = referrer.split("&");
for (String referrerValue : referrers) {
String keyValue[] = referrerValue.split("=");
values.put(URLDecoder.decode(keyValue[0]), URLDecoder.decode(keyValue[1]));
}
} catch (Exception e) {
}
String source = values.get("utm_source");
String campaign = values.get("utm_campaign");
if (source != null && UTM_SOURCE.equals(source) && campaign != null) {
try {
JSONObject data = new JSONObject();
data.put("id", "playstore");
data.put("version", campaign);
// Try to make sure the prefs are written as a group
GeckoEvent event = GeckoEvent.createBroadcastEvent("Campaign:Set", data.toString());
GeckoAppShell.sendEventToGecko(event);
} catch (JSONException e) {
Log.e(LOGTAG, "Error setting distribution", e);
}
}
}
}
}

View File

@ -5,12 +5,19 @@
package org.mozilla.gecko.distribution; package org.mozilla.gecko.distribution;
import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
@ -19,34 +26,95 @@ import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import javax.net.ssl.SSLException;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent; import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoSharedPrefs; import org.mozilla.gecko.GeckoSharedPrefs;
import org.mozilla.gecko.Telemetry;
import org.mozilla.gecko.mozglue.RobocopTarget; import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.SystemClock;
import android.util.Log; import android.util.Log;
/** /**
* Handles distribution file loading and fetching, * Handles distribution file loading and fetching,
* and the corresponding hand-offs to Gecko. * and the corresponding hand-offs to Gecko.
*/ */
public final class Distribution { @RobocopTarget
public class Distribution {
private static final String LOGTAG = "GeckoDistribution"; private static final String LOGTAG = "GeckoDistribution";
private static final int STATE_UNKNOWN = 0; private static final int STATE_UNKNOWN = 0;
private static final int STATE_NONE = 1; private static final int STATE_NONE = 1;
private static final int STATE_SET = 2; private static final int STATE_SET = 2;
private static final String FETCH_PROTOCOL = "https";
private static final String FETCH_HOSTNAME = "distro-download.cdn.mozilla.net";
private static final String FETCH_PATH = "/android/1/";
private static final String FETCH_EXTENSION = ".jar";
private static final String EXPECTED_CONTENT_TYPE = "application/java-archive";
private static final String DISTRIBUTION_PATH = "distribution/";
/**
* Telemetry constants.
*/
private static final String HISTOGRAM_REFERRER_INVALID = "FENNEC_DISTRIBUTION_REFERRER_INVALID";
private static final String HISTOGRAM_DOWNLOAD_TIME_MS = "FENNEC_DISTRIBUTION_DOWNLOAD_TIME_MS";
private static final String HISTOGRAM_CODE_CATEGORY = "FENNEC_DISTRIBUTION_CODE_CATEGORY";
/**
* Success/failure codes. Don't exceed the maximum listed in Histograms.json.
*/
private static final int CODE_CATEGORY_STATUS_OUT_OF_RANGE = 0;
// HTTP status 'codes' run from 1 to 5.
private static final int CODE_CATEGORY_OFFLINE = 6;
private static final int CODE_CATEGORY_FETCH_EXCEPTION = 7;
// It's a post-fetch exception if we were able to download, but not
// able to extract.
private static final int CODE_CATEGORY_POST_FETCH_EXCEPTION = 8;
private static final int CODE_CATEGORY_POST_FETCH_SECURITY_EXCEPTION = 9;
// It's a malformed distribution if we could extract, but couldn't
// process the contents.
private static final int CODE_CATEGORY_MALFORMED_DISTRIBUTION = 10;
// Specific fetch errors.
private static final int CODE_CATEGORY_FETCH_SOCKET_ERROR = 11;
private static final int CODE_CATEGORY_FETCH_SSL_ERROR = 12;
private static final int CODE_CATEGORY_FETCH_NON_SUCCESS_RESPONSE = 13;
private static final int CODE_CATEGORY_FETCH_INVALID_CONTENT_TYPE = 14;
// Corresponds to the high value in Histograms.json.
private static final long MAX_DOWNLOAD_TIME_MSEC = 40000; // 40 seconds.
/**
* Used as a drop-off point for ReferrerReceiver. Checked when we process
* first-run distribution.
*
* This is `protected` so that test code can clear it between runs.
*/
@RobocopTarget
protected static volatile ReferrerDescriptor referrer;
private static Distribution instance; private static Distribution instance;
private final Context context; private final Context context;
@ -70,6 +138,7 @@ public final class Distribution {
return instance; return instance;
} }
@RobocopTarget
public static class DistributionDescriptor { public static class DistributionDescriptor {
public final boolean valid; public final boolean valid;
public final String id; public final String id;
@ -140,6 +209,7 @@ public final class Distribution {
* Use <code>Context.getPackageResourcePath</code> to find an implicit * Use <code>Context.getPackageResourcePath</code> to find an implicit
* package path. Reuses the existing Distribution if one exists. * package path. Reuses the existing Distribution if one exists.
*/ */
@RobocopTarget
public static void init(final Context context) { public static void init(final Context context) {
Distribution.init(Distribution.getInstance(context)); Distribution.init(Distribution.getInstance(context));
} }
@ -166,6 +236,17 @@ public final class Distribution {
this(context, context.getPackageResourcePath(), null); this(context, context.getPackageResourcePath(), null);
} }
/**
* This method is called by ReferrerReceiver when we receive a post-install
* notification from Google Play.
*
* @param ref a parsed referrer value from the store-supplied intent.
*/
public static void onReceivedReferrer(ReferrerDescriptor ref) {
// Track the referrer object for distribution handling.
referrer = ref;
}
/** /**
* Helper to grab a file in the distribution directory. * Helper to grab a file in the distribution directory.
* *
@ -214,9 +295,11 @@ public final class Distribution {
} catch (IOException e) { } catch (IOException e) {
Log.e(LOGTAG, "Error getting distribution descriptor file.", e); Log.e(LOGTAG, "Error getting distribution descriptor file.", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null; return null;
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOGTAG, "Error parsing preferences.json", e); Log.e(LOGTAG, "Error parsing preferences.json", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null; return null;
} }
} }
@ -232,11 +315,13 @@ public final class Distribution {
return new JSONArray(getFileContents(bookmarks)); return new JSONArray(getFileContents(bookmarks));
} catch (IOException e) { } catch (IOException e) {
Log.e(LOGTAG, "Error getting bookmarks", e); Log.e(LOGTAG, "Error getting bookmarks", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null;
} catch (JSONException e) { } catch (JSONException e) {
Log.e(LOGTAG, "Error parsing bookmarks.json", e); Log.e(LOGTAG, "Error parsing bookmarks.json", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
return null;
} }
return null;
} }
/** /**
@ -245,9 +330,12 @@ public final class Distribution {
* Postcondition: if this returns true, distributionDir will have been * Postcondition: if this returns true, distributionDir will have been
* set and populated. * set and populated.
* *
* This method is *only* protected for use from testDistribution.
*
* @return true if we've set a distribution. * @return true if we've set a distribution.
*/ */
private boolean doInit() { @RobocopTarget
protected boolean doInit() {
ThreadUtils.assertNotOnUiThread(); ThreadUtils.assertNotOnUiThread();
// Bail if we've already tried to initialize the distribution, and // Bail if we've already tried to initialize the distribution, and
@ -274,8 +362,9 @@ public final class Distribution {
return true; return true;
} }
// We try the APK, then the system directory. // We try the install intent, then the APK, then the system directory.
final boolean distributionSet = final boolean distributionSet =
checkIntentDistribution() ||
checkAPKDistribution() || checkAPKDistribution() ||
checkSystemDistribution(); checkSystemDistribution();
@ -286,6 +375,153 @@ public final class Distribution {
return distributionSet; return distributionSet;
} }
/**
* If applicable, download and select the distribution specified in
* the referrer intent.
*
* @return true if a referrer-supplied distribution was selected.
*/
private boolean checkIntentDistribution() {
if (referrer == null) {
return false;
}
URI uri = getReferredDistribution(referrer);
if (uri == null) {
return false;
}
long start = SystemClock.uptimeMillis();
Log.v(LOGTAG, "Downloading referred distribution: " + uri);
try {
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
connection.setRequestProperty(HTTP.USER_AGENT, GeckoAppShell.getGeckoInterface().getDefaultUAString());
connection.setRequestProperty("Accept", EXPECTED_CONTENT_TYPE);
try {
final JarInputStream distro;
try {
distro = fetchDistribution(uri, connection);
} catch (Exception e) {
Log.e(LOGTAG, "Error fetching distribution from network.", e);
recordFetchTelemetry(e);
return false;
}
long end = SystemClock.uptimeMillis();
final long duration = end - start;
Log.d(LOGTAG, "Distro fetch took " + duration + "ms; result? " + (distro != null));
Telemetry.HistogramAdd(HISTOGRAM_DOWNLOAD_TIME_MS, clamp(MAX_DOWNLOAD_TIME_MSEC, duration));
if (distro == null) {
// Nothing to do.
return false;
}
// Try to copy distribution files from the fetched stream.
try {
Log.d(LOGTAG, "Copying files from fetched zip.");
if (copyFilesFromStream(distro)) {
// We always copy to the data dir, and we only copy files from
// a 'distribution' subdirectory. Track our dist dir now that
// we know it.
this.distributionDir = new File(getDataDir(), DISTRIBUTION_PATH);
return true;
}
} catch (SecurityException e) {
Log.e(LOGTAG, "Security exception copying files. Corrupt or malicious?", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_POST_FETCH_SECURITY_EXCEPTION);
} catch (Exception e) {
Log.e(LOGTAG, "Error copying files from distribution.", e);
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_POST_FETCH_EXCEPTION);
} finally {
distro.close();
}
} finally {
connection.disconnect();
}
} catch (IOException e) {
Log.e(LOGTAG, "Error copying distribution files from network.", e);
recordFetchTelemetry(e);
}
return false;
}
private static final int clamp(long v, long c) {
return (int) Math.min(c, v);
}
/**
* Fetch the provided URI, returning a {@link JarInputStream} if the response body
* is appropriate.
*
* Protected to allow for mocking.
*
* @return the entity body as a stream, or null on failure.
*/
@SuppressWarnings("static-method")
@RobocopTarget
protected JarInputStream fetchDistribution(URI uri, HttpURLConnection connection) throws IOException {
final int status = connection.getResponseCode();
Log.d(LOGTAG, "Distribution fetch: " + status);
// We record HTTP statuses as 2xx, 3xx, 4xx, 5xx => 2, 3, 4, 5.
final int value;
if (status > 599 || status < 100) {
Log.wtf(LOGTAG, "Unexpected HTTP status code: " + status);
value = CODE_CATEGORY_STATUS_OUT_OF_RANGE;
} else {
value = status / 100;
}
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, value);
if (status != 200) {
Log.w(LOGTAG, "Got status " + status + " fetching distribution.");
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_NON_SUCCESS_RESPONSE);
return null;
}
final String contentType = connection.getContentType();
if (contentType == null || !contentType.startsWith(EXPECTED_CONTENT_TYPE)) {
Log.w(LOGTAG, "Malformed response: invalid Content-Type.");
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_INVALID_CONTENT_TYPE);
return null;
}
return new JarInputStream(new BufferedInputStream(connection.getInputStream()), true);
}
private static void recordFetchTelemetry(final Exception exception) {
if (exception == null) {
// Should never happen.
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_EXCEPTION);
return;
}
if (exception instanceof UnknownHostException) {
// Unknown host => we're offline.
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_OFFLINE);
return;
}
if (exception instanceof SSLException) {
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_SSL_ERROR);
return;
}
if (exception instanceof ProtocolException ||
exception instanceof SocketException) {
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_SOCKET_ERROR);
return;
}
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_FETCH_EXCEPTION);
}
/** /**
* Execute tasks that wanted to run when we were done loading * Execute tasks that wanted to run when we were done loading
* the distribution. These tasks are expected to call {@link #exists()} * the distribution. These tasks are expected to call {@link #exists()}
@ -308,7 +544,7 @@ public final class Distribution {
// We always copy to the data dir, and we only copy files from // We always copy to the data dir, and we only copy files from
// a 'distribution' subdirectory. Track our dist dir now that // a 'distribution' subdirectory. Track our dist dir now that
// we know it. // we know it.
this.distributionDir = new File(getDataDir(), "distribution/"); this.distributionDir = new File(getDataDir(), DISTRIBUTION_PATH);
return true; return true;
} }
} catch (IOException e) { } catch (IOException e) {
@ -330,6 +566,41 @@ public final class Distribution {
return false; return false;
} }
/**
* Unpack distribution files from a downloaded jar stream.
*
* The caller is responsible for closing the provided stream.
*/
private boolean copyFilesFromStream(JarInputStream jar) throws FileNotFoundException, IOException {
final byte[] buffer = new byte[1024];
boolean distributionSet = false;
JarEntry entry;
while ((entry = jar.getNextJarEntry()) != null) {
final String name = entry.getName();
if (entry.isDirectory()) {
// We'll let getDataFile deal with creating the directory hierarchy.
// Yes, we can do better, but it can wait.
continue;
}
if (!name.startsWith(DISTRIBUTION_PATH)) {
continue;
}
File outFile = getDataFile(name);
if (outFile == null) {
continue;
}
distributionSet = true;
writeStream(jar, outFile, entry.getTime(), buffer);
}
return distributionSet;
}
/** /**
* Copies the /distribution folder out of the APK and into the app's data directory. * Copies the /distribution folder out of the APK and into the app's data directory.
* Returns true if distribution files were found and copied. * Returns true if distribution files were found and copied.
@ -352,7 +623,7 @@ public final class Distribution {
continue; continue;
} }
if (!name.startsWith("distribution/")) { if (!name.startsWith(DISTRIBUTION_PATH)) {
continue; continue;
} }
@ -413,6 +684,29 @@ public final class Distribution {
return outFile; return outFile;
} }
private URI getReferredDistribution(ReferrerDescriptor descriptor) {
final String content = descriptor.content;
if (content == null) {
return null;
}
// We restrict here to avoid injection attacks. After all,
// we're downloading a distribution payload based on intent input.
if (!content.matches("^[a-zA-Z0-9]+$")) {
Log.e(LOGTAG, "Invalid referrer content: " + content);
Telemetry.HistogramAdd(HISTOGRAM_REFERRER_INVALID, 1);
return null;
}
try {
return new URI(FETCH_PROTOCOL, FETCH_HOSTNAME, FETCH_PATH + content + FETCH_EXTENSION, null);
} catch (URISyntaxException e) {
// This should never occur.
Log.wtf(LOGTAG, "Invalid URI with content " + content + "!");
return null;
}
}
/** /**
* After calling this method, either <code>distributionDir</code> * After calling this method, either <code>distributionDir</code>
* will be set, or there is no distribution in use. * will be set, or there is no distribution in use.
@ -432,7 +726,7 @@ public final class Distribution {
// the APK, or it exists in /system/. // the APK, or it exists in /system/.
// Look in each location in turn. // Look in each location in turn.
// (This could be optimized by caching the path in shared prefs.) // (This could be optimized by caching the path in shared prefs.)
File copied = new File(getDataDir(), "distribution/"); File copied = new File(getDataDir(), DISTRIBUTION_PATH);
if (copied.exists()) { if (copied.exists()) {
return this.distributionDir = copied; return this.distributionDir = copied;
} }

View File

@ -0,0 +1,55 @@
/* 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/. */
package org.mozilla.gecko.distribution;
import org.mozilla.gecko.mozglue.RobocopTarget;
import android.net.Uri;
/**
* Encapsulates access to values encoded in the "referrer" extra of an install intent.
*
* This object is immutable.
*
* Example input:
*
* "utm_source=campsource&utm_medium=campmed&utm_term=term%2Bhere&utm_content=content&utm_campaign=name"
*/
@RobocopTarget
public class ReferrerDescriptor {
public final String source;
public final String medium;
public final String term;
public final String content;
public final String campaign;
public ReferrerDescriptor(final String referrer) {
if (referrer == null) {
source = null;
medium = null;
term = null;
content = null;
campaign = null;
return;
}
final Uri u = new Uri.Builder()
.scheme("http")
.authority("local")
.path("/")
.encodedQuery(referrer).build();
source = u.getQueryParameter("utm_source");
medium = u.getQueryParameter("utm_medium");
term = u.getQueryParameter("utm_term");
content = u.getQueryParameter("utm_content");
campaign = u.getQueryParameter("utm_campaign");
}
@Override
public String toString() {
return "{s: " + source + ", m: " + medium + ", t: " + term + ", c: " + content + ", c: " + campaign + "}";
}
}

View File

@ -0,0 +1,76 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* 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/. */
package org.mozilla.gecko.distribution;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import android.util.Log;
public class ReferrerReceiver extends BroadcastReceiver {
private static final String LOGTAG = "GeckoReferrerReceiver";
private static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
/**
* If the install intent has this source, we'll track the campaign ID.
*/
private static final String MOZILLA_UTM_SOURCE = "mozilla";
/**
* If the install intent has this campaign, we'll load the specified distribution.
*/
private static final String DISTRIBUTION_UTM_CAMPAIGN = "distribution";
@Override
public void onReceive(Context context, Intent intent) {
Log.v(LOGTAG, "Received intent " + intent);
if (!ACTION_INSTALL_REFERRER.equals(intent.getAction())) {
// This should never happen.
return;
}
ReferrerDescriptor referrer = new ReferrerDescriptor(intent.getStringExtra("referrer"));
// Track the referrer object for distribution handling.
if (TextUtils.equals(referrer.campaign, DISTRIBUTION_UTM_CAMPAIGN)) {
Distribution.onReceivedReferrer(referrer);
} else {
Log.d(LOGTAG, "Not downloading distribution: non-matching campaign.");
}
// If this is a Mozilla campaign, pass the campaign along to Gecko.
if (TextUtils.equals(referrer.source, MOZILLA_UTM_SOURCE)) {
propagateMozillaCampaign(referrer);
}
}
private void propagateMozillaCampaign(ReferrerDescriptor referrer) {
if (referrer.campaign == null) {
return;
}
try {
final JSONObject data = new JSONObject();
data.put("id", "playstore");
data.put("version", referrer.campaign);
String payload = data.toString();
// Try to make sure the prefs are written as a group.
final GeckoEvent event = GeckoEvent.createBroadcastEvent("Campaign:Set", payload);
GeckoAppShell.sendEventToGecko(event);
} catch (JSONException e) {
Log.e(LOGTAG, "Error propagating campaign identifier.", e);
}
}
}

View File

@ -156,6 +156,8 @@ gbjar.sources += [
'db/TabsProvider.java', 'db/TabsProvider.java',
'db/TopSitesCursorWrapper.java', 'db/TopSitesCursorWrapper.java',
'distribution/Distribution.java', 'distribution/Distribution.java',
'distribution/ReferrerDescriptor.java',
'distribution/ReferrerReceiver.java',
'DoorHangerPopup.java', 'DoorHangerPopup.java',
'DynamicToolbar.java', 'DynamicToolbar.java',
'EditBookmarkDialog.java', 'EditBookmarkDialog.java',
@ -354,7 +356,6 @@ gbjar.sources += [
'prompts/PromptService.java', 'prompts/PromptService.java',
'prompts/TabInput.java', 'prompts/TabInput.java',
'ReaderModeUtils.java', 'ReaderModeUtils.java',
'ReferrerReceiver.java',
'Restarter.java', 'Restarter.java',
'ScrollAnimator.java', 'ScrollAnimator.java',
'ServiceNotificationClient.java', 'ServiceNotificationClient.java',

View File

@ -2,19 +2,29 @@ package org.mozilla.gecko.tests;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.util.jar.JarInputStream;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.mozilla.gecko.Actions; import org.mozilla.gecko.Actions;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.db.BrowserContract; import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.distribution.Distribution; import org.mozilla.gecko.distribution.Distribution;
import org.mozilla.gecko.distribution.ReferrerDescriptor;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Log;
/** /**
* Tests distribution customization. * Tests distribution customization.
@ -28,6 +38,38 @@ import android.content.SharedPreferences;
* engine.xml * engine.xml
*/ */
public class testDistribution extends ContentProviderTest { public class testDistribution extends ContentProviderTest {
private static final String CLASS_REFERRER_RECEIVER = "org.mozilla.gecko.distribution.ReferrerReceiver";
private static final String ACTION_INSTALL_REFERRER = "com.android.vending.INSTALL_REFERRER";
private static final int WAIT_TIMEOUT_MSEC = 10000;
public static final String LOGTAG = "GeckoTestDistribution";
public static class TestableDistribution extends Distribution {
@Override
protected JarInputStream fetchDistribution(URI uri,
HttpURLConnection connection) throws IOException {
Log.i(LOGTAG, "Not downloading: this is a test.");
return null;
}
public TestableDistribution(Context context) {
super(context);
}
public void go() {
doInit();
}
@RobocopTarget
public static void clearReferrerDescriptorForTesting() {
referrer = null;
}
@RobocopTarget
public static ReferrerDescriptor getReferrerDescriptorForTesting() {
return referrer;
}
}
private static final String MOCK_PACKAGE = "mock-package.zip"; private static final String MOCK_PACKAGE = "mock-package.zip";
private static final int PREF_REQUEST_ID = 0x7357; private static final int PREF_REQUEST_ID = 0x7357;
@ -65,7 +107,7 @@ public class testDistribution extends ContentProviderTest {
mAsserter.dumpLog("Background task completed. Proceeding."); mAsserter.dumpLog("Background task completed. Proceeding.");
} }
public void testDistribution() { public void testDistribution() throws Exception {
mActivity = getActivity(); mActivity = getActivity();
String mockPackagePath = getMockPackagePath(); String mockPackagePath = getMockPackagePath();
@ -87,6 +129,90 @@ public class testDistribution extends ContentProviderTest {
setTestLocale("es-MX"); setTestLocale("es-MX");
initDistribution(mockPackagePath); initDistribution(mockPackagePath);
checkLocalizedPreferences("es-MX"); checkLocalizedPreferences("es-MX");
// Test the (stubbed) download interaction.
setTestLocale("en-US");
clearDistributionPref();
doTestValidReferrerIntent();
clearDistributionPref();
doTestInvalidReferrerIntent();
}
public void doTestValidReferrerIntent() throws Exception {
// Send the faux-download intent.
// Equivalent to
// am broadcast -a com.android.vending.INSTALL_REFERRER \
// -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
// --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution"
final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=distribution";
final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
intent.putExtra("referrer", ref);
mActivity.sendBroadcast(intent);
// Wait for the intent to be processed.
final TestableDistribution distribution = new TestableDistribution(mActivity);
final Object wait = new Object();
distribution.addOnDistributionReadyCallback(new Runnable() {
@Override
public void run() {
mAsserter.ok(!distribution.exists(), "Not processed.", "No download because we're offline.");
ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
mAsserter.dumpLog("Referrer was " + referrerValue);
mAsserter.is(referrerValue.content, "testcontent", "Referrer content");
mAsserter.is(referrerValue.medium, "testmedium", "Referrer medium");
mAsserter.is(referrerValue.campaign, "distribution", "Referrer campaign");
synchronized (wait) {
wait.notifyAll();
}
}
});
distribution.go();
synchronized (wait) {
wait.wait(WAIT_TIMEOUT_MSEC);
}
}
/**
* Test processing if the campaign isn't "distribution". The intent shouldn't
* result in a download, and won't be saved as the temporary referrer,
* even if we *do* include it in a Campaign:Set message.
*/
public void doTestInvalidReferrerIntent() throws Exception {
// Send the faux-download intent.
// Equivalent to
// am broadcast -a com.android.vending.INSTALL_REFERRER \
// -n org.mozilla.fennec/org.mozilla.gecko.distribution.ReferrerReceiver \
// --es "referrer" "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname"
final String ref = "utm_source=mozilla&utm_medium=testmedium&utm_term=testterm&utm_content=testcontent&utm_campaign=testname";
final Intent intent = new Intent(ACTION_INSTALL_REFERRER);
intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, CLASS_REFERRER_RECEIVER);
intent.putExtra("referrer", ref);
mActivity.sendBroadcast(intent);
// Wait for the intent to be processed.
final TestableDistribution distribution = new TestableDistribution(mActivity);
final Object wait = new Object();
distribution.addOnDistributionReadyCallback(new Runnable() {
@Override
public void run() {
mAsserter.ok(!distribution.exists(), "Not processed.", "No download because campaign was wrong.");
ReferrerDescriptor referrerValue = TestableDistribution.getReferrerDescriptorForTesting();
mAsserter.is(referrerValue, null, "No referrer.");
synchronized (wait) {
wait.notifyAll();
}
}
});
distribution.go();
synchronized (wait) {
wait.wait(WAIT_TIMEOUT_MSEC);
}
} }
// Initialize the distribution from the mock package. // Initialize the distribution from the mock package.
@ -288,12 +414,16 @@ public class testDistribution extends ContentProviderTest {
return mockPackagePath; return mockPackagePath;
} }
// Clears the distribution pref to return distribution state to STATE_UNKNOWN /**
* Clears the distribution pref to return distribution state to STATE_UNKNOWN,
* and wipes the in-memory referrer pigeonhole.
*/
private void clearDistributionPref() { private void clearDistributionPref() {
mAsserter.dumpLog("Clearing distribution pref."); mAsserter.dumpLog("Clearing distribution pref.");
SharedPreferences settings = mActivity.getSharedPreferences("GeckoApp", Activity.MODE_PRIVATE); SharedPreferences settings = mActivity.getSharedPreferences("GeckoApp", Activity.MODE_PRIVATE);
String keyName = mActivity.getPackageName() + ".distribution_state"; String keyName = mActivity.getPackageName() + ".distribution_state";
settings.edit().remove(keyName).commit(); settings.edit().remove(keyName).commit();
TestableDistribution.clearReferrerDescriptorForTesting();
} }
@Override @Override

View File

@ -11,6 +11,7 @@ jar.sources += [
'src/harness/BrowserInstrumentationTestRunner.java', 'src/harness/BrowserInstrumentationTestRunner.java',
'src/harness/BrowserTestListener.java', 'src/harness/BrowserTestListener.java',
'src/tests/BrowserTestCase.java', 'src/tests/BrowserTestCase.java',
'src/tests/TestDistribution.java',
'src/tests/TestGeckoSharedPrefs.java', 'src/tests/TestGeckoSharedPrefs.java',
'src/tests/TestJarReader.java', 'src/tests/TestJarReader.java',
'src/tests/TestRawResource.java', 'src/tests/TestRawResource.java',

View File

@ -0,0 +1,36 @@
/* 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/. */
package org.mozilla.gecko.browser.tests;
import org.mozilla.gecko.distribution.ReferrerDescriptor;
public class TestDistribution extends BrowserTestCase {
private static final String TEST_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2Bhere&utm_content=content&utm_campaign=name";
private static final String TEST_MALFORMED_REFERRER_STRING = "utm_source=campsource&utm_medium=campmed&utm_term=term%2";
public void testReferrerParsing() {
ReferrerDescriptor good = new ReferrerDescriptor(TEST_REFERRER_STRING);
assertEquals("campsource", good.source);
assertEquals("campmed", good.medium);
assertEquals("term+here", good.term);
assertEquals("content", good.content);
assertEquals("name", good.campaign);
// Uri.Builder is permissive.
ReferrerDescriptor bad = new ReferrerDescriptor(TEST_MALFORMED_REFERRER_STRING);
assertEquals("campsource", bad.source);
assertEquals("campmed", bad.medium);
assertFalse("term+here".equals(bad.term));
assertNull(bad.content);
assertNull(bad.campaign);
ReferrerDescriptor ugly = new ReferrerDescriptor(null);
assertNull(ugly.source);
assertNull(ugly.medium);
assertNull(ugly.term);
assertNull(ugly.content);
assertNull(ugly.campaign);
}
}

View File

@ -569,7 +569,7 @@ VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
NS_IMETHODIMP NS_IMETHODIMP
OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile, OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
/*out, optional */ nsIZipReader** aZipReader, /*out, optional */ nsIZipReader** aZipReader,
/*out, optional */ nsIX509Cert3** aSignerCert) /*out, optional */ nsIX509Cert** aSignerCert)
{ {
NS_ENSURE_ARG_POINTER(aJarFile); NS_ENSURE_ARG_POINTER(aJarFile);
@ -728,7 +728,7 @@ OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
// but we can't do that until we switch to libpkix. // but we can't do that until we switch to libpkix.
if (aSignerCert) { if (aSignerCert) {
MOZ_ASSERT(CERT_LIST_HEAD(builtChain)); MOZ_ASSERT(CERT_LIST_HEAD(builtChain));
nsCOMPtr<nsIX509Cert3> signerCert = nsCOMPtr<nsIX509Cert> signerCert =
nsNSSCertificate::Create(CERT_LIST_HEAD(builtChain)->cert); nsNSSCertificate::Create(CERT_LIST_HEAD(builtChain)->cert);
NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
signerCert.forget(aSignerCert); signerCert.forget(aSignerCert);
@ -769,7 +769,7 @@ private:
const nsCOMPtr<nsIFile> mJarFile; const nsCOMPtr<nsIFile> mJarFile;
nsMainThreadPtrHandle<nsIOpenSignedAppFileCallback> mCallback; nsMainThreadPtrHandle<nsIOpenSignedAppFileCallback> mCallback;
nsCOMPtr<nsIZipReader> mZipReader; // out nsCOMPtr<nsIZipReader> mZipReader; // out
nsCOMPtr<nsIX509Cert3> mSignerCert; // out nsCOMPtr<nsIX509Cert> mSignerCert; // out
}; };
} // unnamed namespace } // unnamed namespace

View File

@ -43,7 +43,6 @@ function getDERString(cert)
function getPKCS7String(cert, chainMode) function getPKCS7String(cert, chainMode)
{ {
var length = {}; var length = {};
cert.QueryInterface(Components.interfaces.nsIX509Cert3);
var pkcs7Array = cert.exportAsCMS(chainMode, length); var pkcs7Array = cert.exportAsCMS(chainMode, length);
var pkcs7String = ''; var pkcs7String = '';
for (var i = 0; i < pkcs7Array.length; i++) { for (var i = 0; i < pkcs7Array.length; i++) {
@ -110,10 +109,10 @@ function exportToFile(parent, cert)
content = getDERString(cert); content = getDERString(cert);
break; break;
case 3: case 3:
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert3.CMS_CHAIN_MODE_CertOnly); content = getPKCS7String(cert, Components.interfaces.nsIX509Cert.CMS_CHAIN_MODE_CertOnly);
break; break;
case 4: case 4:
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert3.CMS_CHAIN_MODE_CertChainWithRoot); content = getPKCS7String(cert, Components.interfaces.nsIX509Cert.CMS_CHAIN_MODE_CertChainWithRoot);
break; break;
case 0: case 0:
default: default:

View File

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const nsIX509Cert = Components.interfaces.nsIX509Cert; const nsIX509Cert = Components.interfaces.nsIX509Cert;
const nsIX509Cert3 = Components.interfaces.nsIX509Cert3;
const nsX509CertDB = "@mozilla.org/security/x509certdb;1"; const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
const nsIX509CertDB = Components.interfaces.nsIX509CertDB; const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1"; const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
@ -94,14 +93,9 @@ function setWindowName()
AddCertChain("treesetDump", chain, "dump_"); AddCertChain("treesetDump", chain, "dump_");
DisplayGeneralDataFromCert(cert); DisplayGeneralDataFromCert(cert);
BuildPrettyPrint(cert); BuildPrettyPrint(cert);
cert.requestUsagesArrayAsync(new listener());
if (cert instanceof nsIX509Cert3)
{
cert.requestUsagesArrayAsync(new listener());
}
} }
function addChildrenToTree(parentTree,label,value,addTwistie) function addChildrenToTree(parentTree,label,value,addTwistie)
{ {
var treeChild1 = document.createElement("treechildren"); var treeChild1 = document.createElement("treechildren");
@ -249,7 +243,7 @@ function DisplayGeneralDataFromCert(cert)
addAttributeFromCert('validitystart', cert.validity.notBeforeLocalDay); addAttributeFromCert('validitystart', cert.validity.notBeforeLocalDay);
// Validity end // Validity end
addAttributeFromCert('validityend', cert.validity.notAfterLocalDay); addAttributeFromCert('validityend', cert.validity.notAfterLocalDay);
//Now to populate the fields that correspond to the issuer. //Now to populate the fields that correspond to the issuer.
var issuerCommonname, issuerOrg, issuerOrgUnit; var issuerCommonname, issuerOrg, issuerOrgUnit;
issuerCommonname = cert.issuerCommonName; issuerCommonname = cert.issuerCommonName;
@ -287,7 +281,7 @@ function getCurrentCert()
&& document.getElementById('prettyprint_tab').selected) { && document.getElementById('prettyprint_tab').selected) {
/* if the user manually selected a cert on the Details tab, /* if the user manually selected a cert on the Details tab,
then take that one */ then take that one */
realIndex = tree.currentIndex; realIndex = tree.currentIndex;
} else { } else {
/* otherwise, take the one at the bottom of the chain /* otherwise, take the one at the bottom of the chain
(i.e. the one of the end-entity, unless we're displaying (i.e. the one of the end-entity, unless we're displaying

View File

@ -39,10 +39,7 @@ XPIDL_SOURCES += [
'nsITokenPasswordDialogs.idl', 'nsITokenPasswordDialogs.idl',
'nsIUserCertPicker.idl', 'nsIUserCertPicker.idl',
'nsIX509Cert.idl', 'nsIX509Cert.idl',
'nsIX509Cert2.idl',
'nsIX509Cert3.idl',
'nsIX509CertDB.idl', 'nsIX509CertDB.idl',
'nsIX509CertDB2.idl',
'nsIX509CertList.idl', 'nsIX509CertList.idl',
'nsIX509CertValidity.idl', 'nsIX509CertValidity.idl',
] ]

View File

@ -23,7 +23,7 @@ interface nsISSLStatus : nsISupports {
* "unstrusted because missing or untrusted issuer" * "unstrusted because missing or untrusted issuer"
* and * and
* "untrusted because self signed" * "untrusted because self signed"
* query nsIX509Cert3::isSelfSigned * query nsIX509Cert::isSelfSigned
*/ */
readonly attribute boolean isUntrusted; readonly attribute boolean isUntrusted;

View File

@ -9,11 +9,18 @@
interface nsIArray; interface nsIArray;
interface nsIX509CertValidity; interface nsIX509CertValidity;
interface nsIASN1Object; interface nsIASN1Object;
interface nsICertVerificationListener;
%{ C++
/* forward declaration */
typedef struct CERTCertificateStr CERTCertificate;
%}
[ptr] native CERTCertificatePtr(CERTCertificate);
/** /**
* This represents a X.509 certificate. * This represents a X.509 certificate.
*/ */
[scriptable, uuid(891d2009-b9ba-4a0d-bebe-6b3a30e33191)] [scriptable, uuid(f8ed8364-ced9-4c6e-86ba-48af53c393e6)]
interface nsIX509Cert : nsISupports { interface nsIX509Cert : nsISupports {
/** /**
@ -33,7 +40,7 @@ interface nsIX509Cert : nsISupports {
* @param length The number of strings in the returned array. * @param length The number of strings in the returned array.
* @return An array of email addresses. * @return An array of email addresses.
*/ */
void getEmailAddresses(out unsigned long length, void getEmailAddresses(out unsigned long length,
[retval, array, size_is(length)] out wstring addresses); [retval, array, size_is(length)] out wstring addresses);
/** /**
@ -42,7 +49,7 @@ interface nsIX509Cert : nsISupports {
* The behaviour for non ASCII characters is undefined. * The behaviour for non ASCII characters is undefined.
* *
* @param aEmailAddress The address to search for. * @param aEmailAddress The address to search for.
* *
* @return True if the address is contained in the certificate. * @return True if the address is contained in the certificate.
*/ */
boolean containsEmailAddress(in AString aEmailAddress); boolean containsEmailAddress(in AString aEmailAddress);
@ -138,6 +145,18 @@ interface nsIX509Cert : nsISupports {
const unsigned long USER_CERT = 1 << 1; const unsigned long USER_CERT = 1 << 1;
const unsigned long EMAIL_CERT = 1 << 2; const unsigned long EMAIL_CERT = 1 << 2;
const unsigned long SERVER_CERT = 1 << 3; const unsigned long SERVER_CERT = 1 << 3;
const unsigned long ANY_CERT = 0xffff;
/**
* Type of this certificate
*/
readonly attribute unsigned long certType;
/**
* True if the certificate is self-signed. CA issued
* certificates are always self-signed.
*/
readonly attribute boolean isSelfSigned;
/** /**
* Constants for certificate verification results. * Constants for certificate verification results.
@ -152,7 +171,7 @@ interface nsIX509Cert : nsISupports {
const unsigned long INVALID_CA = 1 << 6; const unsigned long INVALID_CA = 1 << 6;
const unsigned long USAGE_NOT_ALLOWED = 1 << 7; const unsigned long USAGE_NOT_ALLOWED = 1 << 7;
const unsigned long SIGNATURE_ALGORITHM_DISABLED = 1 << 8; const unsigned long SIGNATURE_ALGORITHM_DISABLED = 1 << 8;
/** /**
* Constants that describe the certified usages of a certificate. * Constants that describe the certified usages of a certificate.
* *
@ -172,7 +191,14 @@ interface nsIX509Cert : nsISupports {
const unsigned long CERT_USAGE_AnyCA = 11; const unsigned long CERT_USAGE_AnyCA = 11;
/** /**
* Obtain a list of certificates that contains this certificate * Constants for specifying the chain mode when exporting a certificate
*/
const unsigned long CMS_CHAIN_MODE_CertOnly = 1;
const unsigned long CMS_CHAIN_MODE_CertChain = 2;
const unsigned long CMS_CHAIN_MODE_CertChainWithRoot = 3;
/**
* Obtain a list of certificates that contains this certificate
* and the issuing certificates of all involved issuers, * and the issuing certificates of all involved issuers,
* up to the root issuer. * up to the root issuer.
* *
@ -192,9 +218,17 @@ interface nsIX509Cert : nsISupports {
*/ */
void getUsagesArray(in boolean localOnly, void getUsagesArray(in boolean localOnly,
out uint32_t verified, out uint32_t verified,
out uint32_t count, out uint32_t count,
[array, size_is(count)] out wstring usages); [array, size_is(count)] out wstring usages);
/**
* Async version of nsIX509Cert::getUsagesArray()
*
* Will not block, will request results asynchronously,
* availability of results will be notified on the main thread.
*/
void requestUsagesArrayAsync(in nsICertVerificationListener cvl);
/** /**
* Obtain a single comma separated human readable string describing * Obtain a single comma separated human readable string describing
* the certificate's certified usages. * the certificate's certified usages.
@ -224,7 +258,7 @@ interface nsIX509Cert : nsISupports {
[retval, array, size_is(length)] out octet data); [retval, array, size_is(length)] out octet data);
/** /**
* Test whether two certificate instances represent the * Test whether two certificate instances represent the
* same certificate. * same certificate.
* *
* @return Whether the certificates are equal * @return Whether the certificates are equal
@ -236,4 +270,81 @@ interface nsIX509Cert : nsISupports {
* digest. * digest.
*/ */
readonly attribute ACString sha256SubjectPublicKeyInfoDigest; readonly attribute ACString sha256SubjectPublicKeyInfoDigest;
/**
* Obtain the certificate wrapped in a PKCS#7 SignedData structure,
* with or without the certificate chain
*
* @param chainMode Whether to include the chain (with or without the root),
see CMS_CHAIN_MODE constants.
* @param length The number of bytes of the PKCS#7 data.
* @param data The bytes representing the PKCS#7 wrapped certificate.
*/
void exportAsCMS(in unsigned long chainMode,
out unsigned long length,
[retval, array, size_is(length)] out octet data);
/**
* Retrieves the NSS certificate object wrapped by this interface
*/
[notxpcom, noscript] CERTCertificatePtr getCert();
/**
* Human readable names identifying all hardware or
* software tokens the certificate is stored on.
*
* @param length On success, the number of entries in the returned array.
* @return On success, an array containing the names of all tokens
* the certificate is stored on (may be empty).
* On failure the function throws/returns an error.
*/
void getAllTokenNames(out unsigned long length,
[retval, array, size_is(length)] out wstring
tokenNames);
/**
* Either delete the certificate from all cert databases,
* or mark it as untrusted.
*/
void markForPermDeletion();
};
[scriptable, uuid(2fd0a785-9f2d-4327-8871-8c3e0783891d)]
interface nsICertVerificationResult : nsISupports {
/**
* This interface reflects a container of
* verification results. Call will not block.
*
* Obtain an array of human readable strings describing
* the certificate's certified usages.
*
* Mirrors the results produced by
* nsIX509Cert::getUsagesArray()
*
* As of today, this function is a one-shot object,
* only the first call will succeed.
* This allows an optimization in the implementation,
* ownership of result data will be transfered to caller.
*
* @param cert The certificate that was verified.
* @param verified The certificate verification result,
* see constants in nsIX509Cert.
* @param count The number of human readable usages returned.
* @param usages The array of human readable usages.
*/
void getUsagesArrayResult(out uint32_t verified,
out uint32_t count,
[array, size_is(count)] out wstring usages);
};
[scriptable, uuid(6684bce9-50db-48e1-81b7-98102bf81357)]
interface nsICertVerificationListener : nsISupports {
/**
* Notify that results are ready, that have been requested
* using nsIX509Cert::requestUsagesArrayAsync()
*/
void notify(in nsIX509Cert verifiedCert,
in nsICertVerificationResult result);
}; };

View File

@ -1,30 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIX509Cert.idl"
interface nsIArray;
interface nsIASN1Object;
%{ C++
/* forward declaration */
typedef struct CERTCertificateStr CERTCertificate;
%}
[ptr] native CERTCertificatePtr(CERTCertificate);
/**
* This represents additional interfaces to X.509 certificates
*/
[scriptable, uuid(5b62c61c-f898-4dab-8ace-51109bb459b4)]
interface nsIX509Cert2 : nsIX509Cert {
/**
* Additional constants to classify the type of a certificate.
*/
const unsigned long ANY_CERT = 0xffff;
readonly attribute unsigned long certType;
void markForPermDeletion();
[notxpcom, noscript] CERTCertificatePtr getCert();
};

View File

@ -1,98 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsIX509Cert2.idl"
interface nsICertVerificationListener;
/**
* Extending nsIX509Cert
*/
[scriptable, uuid(399004d8-b8c7-4eb9-8362-d99f4c0161fd)]
interface nsIX509Cert3 : nsIX509Cert2 {
/**
* Constants for specifying the chain mode when exporting a certificate
*/
const unsigned long CMS_CHAIN_MODE_CertOnly = 1;
const unsigned long CMS_CHAIN_MODE_CertChain = 2;
const unsigned long CMS_CHAIN_MODE_CertChainWithRoot = 3;
/**
* Async version of nsIX509Cert::getUsagesArray()
*
* Will not block, will request results asynchronously,
* availability of results will be notified on the main thread.
*/
void requestUsagesArrayAsync(in nsICertVerificationListener cvl);
/**
* Obtain the certificate wrapped in a PKCS#7 SignedData structure,
* with or without the certificate chain
*
* @param chainMode Whether to include the chain (with or without the root),
see CMS_CHAIN_MODE constants.
* @param length The number of bytes of the PKCS#7 data.
* @param data The bytes representing the PKCS#7 wrapped certificate.
*/
void exportAsCMS(in unsigned long chainMode,
out unsigned long length,
[retval, array, size_is(length)] out octet data);
readonly attribute boolean isSelfSigned;
/**
* Human readable names identifying all hardware or
* software tokens the certificate is stored on.
*
* @param length On success, the number of entries in the returned array.
* @return On success, an array containing the names of all tokens
* the certificate is stored on (may be empty).
* On failure the function throws/returns an error.
*/
void getAllTokenNames(out unsigned long length,
[retval, array, size_is(length)] out wstring
tokenNames);
};
[scriptable, uuid(2fd0a785-9f2d-4327-8871-8c3e0783891d)]
interface nsICertVerificationResult : nsISupports {
/**
* This interface reflects a container of
* verification results. Call will not block.
*
* Obtain an array of human readable strings describing
* the certificate's certified usages.
*
* Mirrors the results produced by
* nsIX509Cert::getUsagesArray()
*
* As of today, this function is a one-shot object,
* only the first call will succeed.
* This allows an optimization in the implementation,
* ownership of result data will be transfered to caller.
*
* @param cert The certificate that was verified.
* @param verified The certificate verification result,
* see constants in nsIX509Cert.
* @param count The number of human readable usages returned.
* @param usages The array of human readable usages.
*/
void getUsagesArrayResult(out uint32_t verified,
out uint32_t count,
[array, size_is(count)] out wstring usages);
};
[scriptable, uuid(6684bce9-50db-48e1-81b7-98102bf81357)]
interface nsICertVerificationListener : nsISupports {
/**
* Notify that results are ready, that have been requested
* using nsIX509Cert3::requestUsagesArrayAsync()
*/
void notify(in nsIX509Cert3 verifiedCert,
in nsICertVerificationResult result);
};

View File

@ -8,7 +8,6 @@
interface nsIArray; interface nsIArray;
interface nsIX509Cert; interface nsIX509Cert;
interface nsIX509Cert3;
interface nsIFile; interface nsIFile;
interface nsIInterfaceRequestor; interface nsIInterfaceRequestor;
interface nsIZipReader; interface nsIZipReader;
@ -21,16 +20,16 @@ interface nsIX509CertList;
typedef uint32_t AppTrustedRoot; typedef uint32_t AppTrustedRoot;
[scriptable, function, uuid(0927baea-622d-4e41-a76d-255af426e7fb)] [scriptable, function, uuid(5984db62-d0e5-4671-a082-799cf7271e24)]
interface nsIOpenSignedAppFileCallback : nsISupports interface nsIOpenSignedAppFileCallback : nsISupports
{ {
void openSignedAppFileFinished(in nsresult rv, void openSignedAppFileFinished(in nsresult rv,
in nsIZipReader aZipReader, in nsIZipReader aZipReader,
in nsIX509Cert3 aSignerCert); in nsIX509Cert aSignerCert);
}; };
/** /**
* This represents a service to access and manipulate * This represents a service to access and manipulate
* X.509 certificates stored in a database. * X.509 certificates stored in a database.
*/ */
[scriptable, uuid(7446a5b1-84ca-491f-a2fe-0bc60a71ffa5)] [scriptable, uuid(7446a5b1-84ca-491f-a2fe-0bc60a71ffa5)]
@ -49,12 +48,12 @@ interface nsIX509CertDB : nsISupports {
* Given a nickname and optionally a token, * Given a nickname and optionally a token,
* locate the matching certificate. * locate the matching certificate.
* *
* @param aToken Optionally limits the scope of * @param aToken Optionally limits the scope of
* this function to a token device. * this function to a token device.
* Can be null to mean any token. * Can be null to mean any token.
* @param aNickname The nickname to be used as the key * @param aNickname The nickname to be used as the key
* to find a certificate. * to find a certificate.
* *
* @return The matching certificate if found. * @return The matching certificate if found.
*/ */
nsIX509Cert findCertByNickname(in nsISupports aToken, nsIX509Cert findCertByNickname(in nsISupports aToken,
@ -67,7 +66,7 @@ interface nsIX509CertDB : nsISupports {
* *
* @param aDBkey Database internal key, as obtained using * @param aDBkey Database internal key, as obtained using
* attribute dbkey in nsIX509Cert. * attribute dbkey in nsIX509Cert.
* @param aToken Optionally limits the scope of * @param aToken Optionally limits the scope of
* this function to a token device. * this function to a token device.
* Can be null to mean any token. * Can be null to mean any token.
*/ */
@ -79,7 +78,7 @@ interface nsIX509CertDB : nsISupports {
* user, ca, or server cert - the nickname * user, ca, or server cert - the nickname
* email cert - the email address * email cert - the email address
* *
* @param aToken Optionally limits the scope of * @param aToken Optionally limits the scope of
* this function to a token device. * this function to a token device.
* Can be null to mean any token. * Can be null to mean any token.
* @param aType Type of certificate to obtain * @param aType Type of certificate to obtain
@ -87,7 +86,7 @@ interface nsIX509CertDB : nsISupports {
* @param count The number of nicknames in the returned array * @param count The number of nicknames in the returned array
* @param certNameList The returned array of certificate nicknames. * @param certNameList The returned array of certificate nicknames.
*/ */
void findCertNicknames(in nsISupports aToken, void findCertNicknames(in nsISupports aToken,
in unsigned long aType, in unsigned long aType,
out unsigned long count, out unsigned long count,
[array, size_is(count)] out wstring certNameList); [array, size_is(count)] out wstring certNameList);
@ -97,7 +96,7 @@ interface nsIX509CertDB : nsISupports {
* *
* @param aNickname The nickname to be used as the key * @param aNickname The nickname to be used as the key
* to find the certificate. * to find the certificate.
* *
* @return The matching certificate if found. * @return The matching certificate if found.
*/ */
nsIX509Cert findEmailEncryptionCert(in AString aNickname); nsIX509Cert findEmailEncryptionCert(in AString aNickname);
@ -107,7 +106,7 @@ interface nsIX509CertDB : nsISupports {
* *
* @param aNickname The nickname to be used as the key * @param aNickname The nickname to be used as the key
* to find the certificate. * to find the certificate.
* *
* @return The matching certificate if found. * @return The matching certificate if found.
*/ */
nsIX509Cert findEmailSigningCert(in AString aNickname); nsIX509Cert findEmailSigningCert(in AString aNickname);
@ -115,12 +114,12 @@ interface nsIX509CertDB : nsISupports {
/** /**
* Find a certificate by email address. * Find a certificate by email address.
* *
* @param aToken Optionally limits the scope of * @param aToken Optionally limits the scope of
* this function to a token device. * this function to a token device.
* Can be null to mean any token. * Can be null to mean any token.
* @param aEmailAddress The email address to be used as the key * @param aEmailAddress The email address to be used as the key
* to find the certificate. * to find the certificate.
* *
* @return The matching certificate if found. * @return The matching certificate if found.
*/ */
nsIX509Cert findCertByEmailAddress(in nsISupports aToken, nsIX509Cert findCertByEmailAddress(in nsISupports aToken,
@ -164,7 +163,7 @@ interface nsIX509CertDB : nsISupports {
in nsIInterfaceRequestor ctx); in nsIInterfaceRequestor ctx);
/** /**
* Import a personal certificate into the database, assuming * Import a personal certificate into the database, assuming
* the database already contains the private key for this certificate. * the database already contains the private key for this certificate.
* *
* @param data The raw data to be imported * @param data The raw data to be imported
@ -184,7 +183,7 @@ interface nsIX509CertDB : nsISupports {
/** /**
* Modify the trust that is stored and associated to a certificate within * Modify the trust that is stored and associated to a certificate within
* a database. Separate trust is stored for * a database. Separate trust is stored for
* One call manipulates the trust for one trust type only. * One call manipulates the trust for one trust type only.
* See the trust type constants defined within this interface. * See the trust type constants defined within this interface.
* *
@ -203,14 +202,14 @@ interface nsIX509CertDB : nsISupports {
* characters, indicating SSL, Email, and Obj signing * characters, indicating SSL, Email, and Obj signing
* trust. * trust.
*/ */
void setCertTrustFromString(in nsIX509Cert3 cert, in string trustString); void setCertTrustFromString(in nsIX509Cert cert, in string trustString);
/** /**
* Query whether a certificate is trusted for a particular use. * Query whether a certificate is trusted for a particular use.
* *
* @param cert Obtain the stored trust of this certificate. * @param cert Obtain the stored trust of this certificate.
* @param certType The type of the certificate. See nsIX509Cert. * @param certType The type of the certificate. See nsIX509Cert.
* @param trustType A single bit from the usages constants defined * @param trustType A single bit from the usages constants defined
* within this interface. * within this interface.
* *
* @return Returns true if the certificate is trusted for the given use. * @return Returns true if the certificate is trusted for the given use.
@ -222,7 +221,7 @@ interface nsIX509CertDB : nsISupports {
/** /**
* Import certificate(s) from file * Import certificate(s) from file
* *
* @param aToken Optionally limits the scope of * @param aToken Optionally limits the scope of
* this function to a token device. * this function to a token device.
* Can be null to mean any token. * Can be null to mean any token.
* @param aFile Identifies a file that contains the certificate * @param aFile Identifies a file that contains the certificate
@ -237,7 +236,7 @@ interface nsIX509CertDB : nsISupports {
/** /**
* Import a PKCS#12 file containing cert(s) and key(s) into the database. * Import a PKCS#12 file containing cert(s) and key(s) into the database.
* *
* @param aToken Optionally limits the scope of * @param aToken Optionally limits the scope of
* this function to a token device. * this function to a token device.
* Can be null to mean any token. * Can be null to mean any token.
* @param aFile Identifies a file that contains the data * @param aFile Identifies a file that contains the data
@ -249,7 +248,7 @@ interface nsIX509CertDB : nsISupports {
/** /**
* Export a set of certs and keys from the database to a PKCS#12 file. * Export a set of certs and keys from the database to a PKCS#12 file.
* *
* @param aToken Optionally limits the scope of * @param aToken Optionally limits the scope of
* this function to a token device. * this function to a token device.
* Can be null to mean any token. * Can be null to mean any token.
* @param aFile Identifies a file that will be filled with the data * @param aFile Identifies a file that will be filled with the data
@ -316,7 +315,7 @@ interface nsIX509CertDB : nsISupports {
in nsIFile aJarFile, in nsIFile aJarFile,
in nsIOpenSignedAppFileCallback callback); in nsIOpenSignedAppFileCallback callback);
/* /*
* Add a cert to a cert DB from a binary string. * Add a cert to a cert DB from a binary string.
* *
* @param certDER The raw DER encoding of a certificate. * @param certDER The raw DER encoding of a certificate.
@ -361,4 +360,20 @@ interface nsIX509CertDB : nsISupports {
// Clears the OCSP cache for the current certificate verification // Clears the OCSP cache for the current certificate verification
// implementation. // implementation.
void clearOCSPCache(); void clearOCSPCache();
/*
* Add a cert to a cert DB from a base64 encoded string.
*
* @param base64 The raw representation of a certificate,
* encoded as Base 64.
* @param aTrust decoded by CERT_DecodeTrustString. 3 comma separated characters,
* indicating SSL, Email, and Obj signing trust
* @param aName name of the cert for display purposes.
*/
void addCertFromBase64(in string base64, in string aTrust, in string aName);
/*
* Get all the known certs in the database
*/
nsIX509CertList getCerts();
}; };

View File

@ -1,36 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIX509CertList;
/**
* This represents a service to access and manipulate
* X.509 certificates stored in a database through methods
* not in nsIX509CertDB, which is frozen
*
*/
[scriptable, uuid(e0df4784-6560-45bf-b1b7-86076a0e8381)]
interface nsIX509CertDB2 : nsISupports {
/*
* Add a cert to a cert DB from a base64 encoded string.
*
* @param base64 The raw representation of a certificate,
* encoded as Base 64.
* @param aTrust decoded by CERT_DecodeTrustString. 3 comma separated characters,
* indicating SSL, Email, and Obj signing trust
* @param aName name of the cert for display purposes.
*/
void addCertFromBase64(in string base64, in string aTrust, in string aName);
/*
* Get all the known certs in the database
*/
nsIX509CertList getCerts();
};

View File

@ -689,7 +689,6 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
// Get the existing cert. If there isn't one, then there is // Get the existing cert. If there isn't one, then there is
// no cert change to worry about. // no cert change to worry about.
nsCOMPtr<nsIX509Cert> cert; nsCOMPtr<nsIX509Cert> cert;
nsCOMPtr<nsIX509Cert2> cert2;
RefPtr<nsSSLStatus> status(infoObject->SSLStatus()); RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
if (!status) { if (!status) {
@ -700,10 +699,9 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
} }
status->GetServerCert(getter_AddRefs(cert)); status->GetServerCert(getter_AddRefs(cert));
cert2 = do_QueryInterface(cert); if (!cert) {
if (!cert2) {
NS_NOTREACHED("every nsSSLStatus must have a cert" NS_NOTREACHED("every nsSSLStatus must have a cert"
"that implements nsIX509Cert2"); "that implements nsIX509Cert");
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
return SECFailure; return SECFailure;
} }
@ -715,9 +713,9 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
"GetNegotiatedNPN() failed during renegotiation"); "GetNegotiatedNPN() failed during renegotiation");
if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN, if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN,
NS_LITERAL_CSTRING("spdy/"))) NS_LITERAL_CSTRING("spdy/"))) {
return SECSuccess; return SECSuccess;
}
// If GetNegotiatedNPN() failed we will assume spdy for safety's safe // If GetNegotiatedNPN() failed we will assume spdy for safety's safe
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
@ -726,11 +724,12 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
} }
// Check to see if the cert has actually changed // Check to see if the cert has actually changed
ScopedCERTCertificate c(cert2->GetCert()); ScopedCERTCertificate c(cert->GetCert());
NS_ASSERTION(c, "very bad and hopefully impossible state"); NS_ASSERTION(c, "very bad and hopefully impossible state");
bool sameCert = CERT_CompareCerts(c, serverCert); bool sameCert = CERT_CompareCerts(c, serverCert);
if (sameCert) if (sameCert) {
return SECSuccess; return SECSuccess;
}
// Report an error - changed cert is confirmed // Report an error - changed cert is confirmed
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,

View File

@ -535,13 +535,9 @@ AppendErrorTextUntrusted(PRErrorCode errTrust,
nsString &returnedMessage) nsString &returnedMessage)
{ {
const char *errorID = nullptr; const char *errorID = nullptr;
nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509); bool isSelfSigned;
if (cert3) { if (NS_SUCCEEDED(ix509->GetIsSelfSigned(&isSelfSigned)) && isSelfSigned) {
bool isSelfSigned; errorID = "certErrorTrust_SelfSigned";
if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
&& isSelfSigned) {
errorID = "certErrorTrust_SelfSigned";
}
} }
if (!errorID) { if (!errorID) {
@ -690,11 +686,7 @@ AppendErrorTextMismatch(const nsString &host,
const char16_t *params[1]; const char16_t *params[1];
nsresult rv; nsresult rv;
mozilla::pkix::ScopedCERTCertificate nssCert; mozilla::pkix::ScopedCERTCertificate nssCert(ix509->GetCert());
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
if (cert2)
nssCert = cert2->GetCert();
if (!nssCert) { if (!nssCert) {
// We are unable to extract the valid names, say "not valid for name". // We are unable to extract the valid names, say "not valid for name".

View File

@ -390,14 +390,11 @@ GetCertFingerprintByOidTag(nsIX509Cert *aCert,
SECOidTag aOidTag, SECOidTag aOidTag,
nsCString &fp) nsCString &fp)
{ {
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
if (!cert2)
return NS_ERROR_FAILURE;
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert()); mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
if (!nsscert) if (!nsscert) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
}
return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp); return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
} }
@ -425,24 +422,23 @@ GetCertFingerprintByDottedOidString(CERTCertificate* nsscert,
static nsresult static nsresult
GetCertFingerprintByDottedOidString(nsIX509Cert *aCert, GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
const nsCString &dottedOid, const nsCString &dottedOid,
nsCString &fp) nsCString &fp)
{ {
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
if (!cert2)
return NS_ERROR_FAILURE;
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert()); mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
if (!nsscert) if (!nsscert) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
}
return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp); return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
} }
NS_IMETHODIMP NS_IMETHODIMP
nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, int32_t aPort, nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
nsIX509Cert *aCert, int32_t aPort,
uint32_t aOverrideBits, nsIX509Cert* aCert,
uint32_t aOverrideBits,
bool aTemporary) bool aTemporary)
{ {
NS_ENSURE_ARG_POINTER(aCert); NS_ENSURE_ARG_POINTER(aCert);
@ -451,13 +447,10 @@ nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, in
if (aPort < -1) if (aPort < -1)
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert); mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
if (!cert2) if (!nsscert) {
return NS_ERROR_FAILURE;
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
if (!nsscert)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
}
char* nickname = DefaultServerNicknameForCert(nsscert.get()); char* nickname = DefaultServerNicknameForCert(nsscert.get());
if (!aTemporary && nickname && *nickname) if (!aTemporary && nickname && *nickname)

View File

@ -330,7 +330,7 @@ nsCertTree::nsCertCompareFunc
nsCertTree::GetCompareFuncFromCertType(uint32_t aType) nsCertTree::GetCompareFuncFromCertType(uint32_t aType)
{ {
switch (aType) { switch (aType) {
case nsIX509Cert2::ANY_CERT: case nsIX509Cert::ANY_CERT:
case nsIX509Cert::USER_CERT: case nsIX509Cert::USER_CERT:
return CmpUserCert; return CmpUserCert;
case nsIX509Cert::CA_CERT: case nsIX509Cert::CA_CERT:
@ -477,7 +477,7 @@ nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
!CERT_LIST_END(node, aCertList); !CERT_LIST_END(node, aCertList);
node = CERT_LIST_NEXT(node)) { node = CERT_LIST_NEXT(node)) {
bool wantThisCert = (aWantedType == nsIX509Cert2::ANY_CERT); bool wantThisCert = (aWantedType == nsIX509Cert::ANY_CERT);
bool wantThisCertIfNoOverrides = false; bool wantThisCertIfNoOverrides = false;
bool wantThisCertIfHaveOverrides = false; bool wantThisCertIfHaveOverrides = false;
bool addOverrides = false; bool addOverrides = false;
@ -809,12 +809,7 @@ nsCertTree::DeleteEntryObject(uint32_t index)
// although there are still overrides stored, // although there are still overrides stored,
// so, we keep the cert, but remove the trust // so, we keep the cert, but remove the trust
mozilla::pkix::ScopedCERTCertificate nsscert; mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(cert);
if (cert2) {
nsscert = cert2->GetCert();
}
if (nsscert) { if (nsscert) {
CERTCertTrust trust; CERTCertTrust trust;
@ -1235,12 +1230,8 @@ nsCertTree::GetCellText(int32_t row, nsITreeColumn* col,
(certdi->mIsTemporary) ? "CertExceptionTemporary" : "CertExceptionPermanent"; (certdi->mIsTemporary) ? "CertExceptionTemporary" : "CertExceptionPermanent";
rv = mNSSComponent->GetPIPNSSBundleString(stringID, _retval); rv = mNSSComponent->GetPIPNSSBundleString(stringID, _retval);
} else if (NS_LITERAL_STRING("typecol").Equals(colID) && cert) { } else if (NS_LITERAL_STRING("typecol").Equals(colID) && cert) {
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
uint32_t type = nsIX509Cert::UNKNOWN_CERT; uint32_t type = nsIX509Cert::UNKNOWN_CERT;
rv = cert->GetCertType(&type);
if (pipCert) {
rv = pipCert->GetCertType(&type);
}
switch (type) { switch (type) {
case nsIX509Cert::USER_CERT: case nsIX509Cert::USER_CERT:

View File

@ -17,7 +17,7 @@ class DispatchCertVerificationResult : public nsRunnable
{ {
public: public:
DispatchCertVerificationResult(const nsMainThreadPtrHandle<nsICertVerificationListener>& aListener, DispatchCertVerificationResult(const nsMainThreadPtrHandle<nsICertVerificationListener>& aListener,
nsIX509Cert3* aCert, nsIX509Cert* aCert,
nsICertVerificationResult* aResult) nsICertVerificationResult* aResult)
: mListener(aListener) : mListener(aListener)
, mCert(aCert) , mCert(aCert)
@ -31,7 +31,7 @@ public:
private: private:
nsMainThreadPtrHandle<nsICertVerificationListener> mListener; nsMainThreadPtrHandle<nsICertVerificationListener> mListener;
nsCOMPtr<nsIX509Cert3> mCert; nsCOMPtr<nsIX509Cert> mCert;
nsCOMPtr<nsICertVerificationResult> mResult; nsCOMPtr<nsICertVerificationResult> mResult;
}; };
} // anonymous namespace } // anonymous namespace
@ -63,9 +63,8 @@ void nsCertVerificationJob::Run()
ires = vres; ires = vres;
} }
nsCOMPtr<nsIX509Cert3> c3 = do_QueryInterface(mCert); nsCOMPtr<nsIRunnable> r = new DispatchCertVerificationResult(mListener, mCert, ires);
nsCOMPtr<nsIRunnable> r = new DispatchCertVerificationResult(mListener, c3, ires);
NS_DispatchToMainThread(r); NS_DispatchToMainThread(r);
} }

View File

@ -19,7 +19,6 @@
#include "nsPKCS12Blob.h" #include "nsPKCS12Blob.h"
#include "nsPK11TokenDB.h" #include "nsPK11TokenDB.h"
#include "nsIX509Cert.h" #include "nsIX509Cert.h"
#include "nsIX509Cert3.h"
#include "nsNSSASN1Object.h" #include "nsNSSASN1Object.h"
#include "nsString.h" #include "nsString.h"
#include "nsXPIDLString.h" #include "nsXPIDLString.h"
@ -68,8 +67,6 @@ NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
NS_IMPL_ISUPPORTS(nsNSSCertificate, NS_IMPL_ISUPPORTS(nsNSSCertificate,
nsIX509Cert, nsIX509Cert,
nsIX509Cert2,
nsIX509Cert3,
nsIIdentityInfo, nsIIdentityInfo,
nsISerializable, nsISerializable,
nsIClassInfo) nsIClassInfo)
@ -1141,9 +1138,9 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
switch (chainMode) { switch (chainMode) {
case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly: case nsIX509Cert::CMS_CHAIN_MODE_CertOnly:
case nsIX509Cert3::CMS_CHAIN_MODE_CertChain: case nsIX509Cert::CMS_CHAIN_MODE_CertChain:
case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot: case nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot:
break; break;
default: default:
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
@ -1178,15 +1175,15 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
// Since CERT_CertChainFromCert() also includes the certificate itself, // Since CERT_CertChainFromCert() also includes the certificate itself,
// we have to start at the issuing cert (to avoid duplicate certs // we have to start at the issuing cert (to avoid duplicate certs
// in the SignedData). // in the SignedData).
if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain || if (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChain ||
chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) { chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot) {
ScopedCERTCertificate issuerCert( ScopedCERTCertificate issuerCert(
CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA)); CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
// the issuerCert of a self signed root is the cert itself, // the issuerCert of a self signed root is the cert itself,
// so make sure we're not adding duplicates, again // so make sure we're not adding duplicates, again
if (issuerCert && issuerCert != mCert.get()) { if (issuerCert && issuerCert != mCert.get()) {
bool includeRoot = bool includeRoot =
(chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot); (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot);
ScopedCERTCertificateList certChain( ScopedCERTCertificateList certChain(
CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot)); CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot));
if (certChain) { if (certChain) {
@ -1377,11 +1374,7 @@ nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
NS_ENSURE_ARG(other); NS_ENSURE_ARG(other);
NS_ENSURE_ARG(result); NS_ENSURE_ARG(result);
nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other); ScopedCERTCertificate cert(other->GetCert());
if (!other2)
return NS_ERROR_FAILURE;
ScopedCERTCertificate cert(other2->GetCert());
*result = (mCert.get() == cert.get()); *result = (mCert.get() == cert.get());
return NS_OK; return NS_OK;
} }
@ -1552,10 +1545,7 @@ nsNSSCertList::AddCert(nsIX509Cert* aCert)
if (isAlreadyShutDown()) { if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert); CERTCertificate* cert = aCert->GetCert();
CERTCertificate* cert;
cert = nssCert->GetCert();
if (!cert) { if (!cert) {
NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate."); NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -1577,8 +1567,7 @@ nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
if (isAlreadyShutDown()) { if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert); CERTCertificate* cert = aCert->GetCert();
CERTCertificate* cert = nssCert->GetCert();
CERTCertListNode* node; CERTCertListNode* node;
if (!cert) { if (!cert) {
@ -1605,8 +1594,9 @@ CERTCertList*
nsNSSCertList::DupCertList(CERTCertList* aCertList, nsNSSCertList::DupCertList(CERTCertList* aCertList,
const nsNSSShutDownPreventionLock& /*proofOfLock*/) const nsNSSShutDownPreventionLock& /*proofOfLock*/)
{ {
if (!aCertList) if (!aCertList) {
return nullptr; return nullptr;
}
CERTCertList* newList = CERT_NewCertList(); CERTCertList* newList = CERT_NewCertList();

View File

@ -7,8 +7,6 @@
#define _NS_NSSCERTIFICATE_H_ #define _NS_NSSCERTIFICATE_H_
#include "nsIX509Cert.h" #include "nsIX509Cert.h"
#include "nsIX509Cert2.h"
#include "nsIX509Cert3.h"
#include "nsIX509CertDB.h" #include "nsIX509CertDB.h"
#include "nsIX509CertList.h" #include "nsIX509CertList.h"
#include "nsIASN1Object.h" #include "nsIASN1Object.h"
@ -25,7 +23,7 @@ class nsAutoString;
class nsINSSComponent; class nsINSSComponent;
class nsIASN1Sequence; class nsIASN1Sequence;
class nsNSSCertificate : public nsIX509Cert3, class nsNSSCertificate : public nsIX509Cert,
public nsIIdentityInfo, public nsIIdentityInfo,
public nsISerializable, public nsISerializable,
public nsIClassInfo, public nsIClassInfo,
@ -34,8 +32,6 @@ class nsNSSCertificate : public nsIX509Cert3,
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIX509CERT NS_DECL_NSIX509CERT
NS_DECL_NSIX509CERT2
NS_DECL_NSIX509CERT3
NS_DECL_NSIIDENTITYINFO NS_DECL_NSIIDENTITYINFO
NS_DECL_NSISERIALIZABLE NS_DECL_NSISERIALIZABLE
NS_DECL_NSICLASSINFO NS_DECL_NSICLASSINFO

View File

@ -82,7 +82,7 @@ attemptToLogInWithDefaultPassword()
return NS_OK; return NS_OK;
} }
NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2) NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB)
nsNSSCertificateDB::nsNSSCertificateDB() nsNSSCertificateDB::nsNSSCertificateDB()
: mBadCertsLock("nsNSSCertificateDB::mBadCertsLock") : mBadCertsLock("nsNSSCertificateDB::mBadCertsLock")
@ -954,14 +954,15 @@ nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
if (isAlreadyShutDown()) { if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert); mozilla::pkix::ScopedCERTCertificate cert(aCert->GetCert());
mozilla::pkix::ScopedCERTCertificate cert(nssCert->GetCert()); if (!cert) {
if (!cert) return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
}
SECStatus srv = SECSuccess; SECStatus srv = SECSuccess;
uint32_t certType; uint32_t certType;
nssCert->GetCertType(&certType); aCert->GetCertType(&certType);
if (NS_FAILED(nssCert->MarkForPermDeletion())) if (NS_FAILED(aCert->MarkForPermDeletion()))
{ {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -998,11 +999,7 @@ nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
} }
nsNSSCertTrust trust; nsNSSCertTrust trust;
nsresult rv; nsresult rv;
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert, &rv); mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
if (!pipCert) {
return rv;
}
mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
rv = attemptToLogInWithDefaultPassword(); rv = attemptToLogInWithDefaultPassword();
if (NS_WARN_IF(rv != NS_OK)) { if (NS_WARN_IF(rv != NS_OK)) {
@ -1054,8 +1051,7 @@ nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_AVAILABLE;
} }
SECStatus srv; SECStatus srv;
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert); mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
CERTCertTrust nsstrust; CERTCertTrust nsstrust;
srv = CERT_GetCertTrust(nsscert.get(), &nsstrust); srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
if (srv != SECSuccess) if (srv != SECSuccess)
@ -1284,7 +1280,8 @@ finish:
/* nsIX509Cert getDefaultEmailEncryptionCert (); */ /* nsIX509Cert getDefaultEmailEncryptionCert (); */
NS_IMETHODIMP NS_IMETHODIMP
nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval) nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString& aNickname,
nsIX509Cert** _retval)
{ {
NS_ENSURE_ARG_POINTER(_retval); NS_ENSURE_ARG_POINTER(_retval);
*_retval = nullptr; *_retval = nullptr;
@ -1320,7 +1317,8 @@ nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509C
/* nsIX509Cert getDefaultEmailSigningCert (); */ /* nsIX509Cert getDefaultEmailSigningCert (); */
NS_IMETHODIMP NS_IMETHODIMP
nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval) nsNSSCertificateDB::FindEmailSigningCert(const nsAString& aNickname,
nsIX509Cert** _retval)
{ {
NS_ENSURE_ARG_POINTER(_retval); NS_ENSURE_ARG_POINTER(_retval);
*_retval = nullptr; *_retval = nullptr;
@ -1590,14 +1588,16 @@ nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
} }
} }
} }
if (!dummycert) if (!dummycert) {
break; break;
}
count++; count++;
} }
} }
NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char *aBase64, const char *aTrust, const char *aName) NS_IMETHODIMP nsNSSCertificateDB::AddCertFromBase64(const char* aBase64,
const char* aTrust,
const char* aName)
{ {
NS_ENSURE_ARG_POINTER(aBase64); NS_ENSURE_ARG_POINTER(aBase64);
nsCOMPtr <nsIX509Cert> newCert; nsCOMPtr <nsIX509Cert> newCert;
@ -1668,7 +1668,7 @@ nsNSSCertificateDB::AddCert(const nsACString & aCertDER, const char *aTrust,
} }
NS_IMETHODIMP NS_IMETHODIMP
nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert3* cert, nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert,
const char* trustString) const char* trustString)
{ {
CERTCertTrust trust; CERTCertTrust trust;
@ -1761,11 +1761,10 @@ nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
EnsureIdentityInfoLoaded(); EnsureIdentityInfoLoaded();
#endif #endif
nsCOMPtr<nsIX509Cert2> x509Cert = do_QueryInterface(aCert); ScopedCERTCertificate nssCert(aCert->GetCert());
if (!x509Cert) { if (!nssCert) {
return NS_ERROR_INVALID_ARG; return NS_ERROR_INVALID_ARG;
} }
ScopedCERTCertificate nssCert(x509Cert->GetCert());
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);

View File

@ -6,7 +6,6 @@
#define __NSNSSCERTIFICATEDB_H__ #define __NSNSSCERTIFICATEDB_H__
#include "nsIX509CertDB.h" #include "nsIX509CertDB.h"
#include "nsIX509CertDB2.h"
#include "nsNSSShutDown.h" #include "nsNSSShutDown.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/Mutex.h" #include "mozilla/Mutex.h"
@ -17,14 +16,12 @@ class nsIArray;
class nsRecentBadCerts; class nsRecentBadCerts;
class nsNSSCertificateDB : public nsIX509CertDB class nsNSSCertificateDB : public nsIX509CertDB
, public nsIX509CertDB2
, public nsNSSShutDownObject , public nsNSSShutDownObject
{ {
public: public:
NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIX509CERTDB NS_DECL_NSIX509CERTDB
NS_DECL_NSIX509CERTDB2
nsNSSCertificateDB(); nsNSSCertificateDB();

View File

@ -12,7 +12,6 @@
#include "nsISupportsPrimitives.h" #include "nsISupportsPrimitives.h"
#include "nsIX509Cert.h" #include "nsIX509Cert.h"
#include "nsNSSCertificate.h" #include "nsNSSCertificate.h"
#include "nsNSSCertificate.h"
#include "nsString.h" #include "nsString.h"
#include "nsXPIDLString.h" #include "nsXPIDLString.h"
@ -357,3 +356,55 @@ nsNSSCertificateFakeTransport::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
*aClassIDNoAlloc = kNSSCertificateCID; *aClassIDNoAlloc = kNSSCertificateCID;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetCertType(unsigned int*)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetIsSelfSigned(bool*)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::RequestUsagesArrayAsync(nsICertVerificationListener*)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::GetAllTokenNames(unsigned int*,
char16_t***)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
CERTCertificate*
nsNSSCertificateFakeTransport::GetCert()
{
NS_NOTREACHED("Unimplemented on content process");
return nullptr;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::ExportAsCMS(unsigned int,
unsigned int*,
unsigned char**)
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsNSSCertificateFakeTransport::MarkForPermDeletion()
{
NS_NOTREACHED("Unimplemented on content process");
return NS_ERROR_NOT_IMPLEMENTED;
}

View File

@ -387,16 +387,19 @@ nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
ScopedCERTCertificate nssCert; ScopedCERTCertificate nssCert;
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert); nsCOMPtr<nsIX509Cert> cert(SSLStatus()->mServerCert);
if (cert2) if (cert) {
nssCert = cert2->GetCert(); nssCert = cert->GetCert();
}
if (!nssCert) if (!nssCert) {
return NS_OK; return NS_OK;
}
if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) != if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
SECSuccess) SECSuccess) {
return NS_OK; return NS_OK;
}
// All tests pass - this is joinable // All tests pass - this is joinable
mJoined = true; mJoined = true;

View File

@ -10,7 +10,6 @@
#include "nspr.h" #include "nspr.h"
#include "nsIX509Cert.h" #include "nsIX509Cert.h"
#include "nsIX509Cert3.h"
#include "nsProxyRelease.h" #include "nsProxyRelease.h"
class nsBaseVerificationJob class nsBaseVerificationJob

View File

@ -8,9 +8,6 @@
do_get_profile(); // must be called before getting nsIX509CertDB do_get_profile(); // must be called before getting nsIX509CertDB
const certdb = Cc["@mozilla.org/security/x509certdb;1"] const certdb = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB); .getService(Ci.nsIX509CertDB);
const certdb2 = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2);
// This is the list of certificates needed for the test // This is the list of certificates needed for the test
// The certificates prefixed by 'int-' are intermediates // The certificates prefixed by 'int-' are intermediates
let certList = [ let certList = [
@ -29,7 +26,7 @@ function load_cert(cert_name, trust_string) {
// the ones that I am interested in. // the ones that I am interested in.
function get_ca_array() { function get_ca_array() {
let ret_array = new Array(); let ret_array = new Array();
let allCerts = certdb2.getCerts(); let allCerts = certdb.getCerts();
let enumerator = allCerts.getEnumerator(); let enumerator = allCerts.getEnumerator();
while (enumerator.hasMoreElements()) { while (enumerator.hasMoreElements()) {
let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert); let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);

View File

@ -25,7 +25,7 @@ let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
let gCertDB = Cc["@mozilla.org/security/x509certdb;1"] let gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
.getService(Ci.nsIX509CertDB2); .getService(Ci.nsIX509CertDB);
gCertDB.QueryInterface(Ci.nsIX509CertDB); gCertDB.QueryInterface(Ci.nsIX509CertDB);
const BUILT_IN_NICK_PREFIX = "Builtin Object Token:"; const BUILT_IN_NICK_PREFIX = "Builtin Object Token:";
@ -108,8 +108,7 @@ function isBuiltinToken(tokenName) {
} }
function isCertBuiltIn(cert) { function isCertBuiltIn(cert) {
let cert3 = cert.QueryInterface(Ci.nsIX509Cert3); let tokenNames = cert.getAllTokenNames({});
let tokenNames = cert3.getAllTokenNames({});
if (!tokenNames) { if (!tokenNames) {
return false; return false;
} }

View File

@ -12,6 +12,7 @@ SOURCES += [
'pkix_cert_extension_tests.cpp', 'pkix_cert_extension_tests.cpp',
'pkix_ocsp_request_tests.cpp', 'pkix_ocsp_request_tests.cpp',
'pkixcheck_CheckKeyUsage_tests.cpp', 'pkixcheck_CheckKeyUsage_tests.cpp',
'pkixcheck_CheckTimes_tests.cpp',
'pkixder_input_tests.cpp', 'pkixder_input_tests.cpp',
'pkixder_pki_types_tests.cpp', 'pkixder_pki_types_tests.cpp',
'pkixder_universal_types_tests.cpp', 'pkixder_universal_types_tests.cpp',

View File

@ -0,0 +1,174 @@
/* -*- 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 2014 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 "pkixgtest.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
namespace mozilla { namespace pkix {
extern Result CheckTimes(const CERTValidity& validity, PRTime time);
} } // namespace mozilla::pkix
static const SECItem empty_null = { siBuffer, nullptr, 0 };
static const PRTime PAST_TIME(YMDHMS(1998, 12, 31, 12, 23, 56));
static const uint8_t OLDER_GENERALIZEDTIME_DATA[] = {
'1', '9', '9', '9', '0', '1', '0', '1', // 1999-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem OLDER_GENERALIZEDTIME = {
siGeneralizedTime,
const_cast<uint8_t*>(OLDER_GENERALIZEDTIME_DATA),
sizeof(OLDER_GENERALIZEDTIME_DATA)
};
static const uint8_t OLDER_UTCTIME_DATA[] = {
'9', '9', '0', '1', '0', '1', // (19)99-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem OLDER_UTCTIME = {
siUTCTime,
const_cast<uint8_t*>(OLDER_UTCTIME_DATA),
sizeof(OLDER_UTCTIME_DATA)
};
static const PRTime NOW(YMDHMS(2016, 12, 31, 12, 23, 56));
static const uint8_t NEWER_GENERALIZEDTIME_DATA[] = {
'2', '0', '2', '1', '0', '1', '0', '1', // 2021-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem NEWER_GENERALIZEDTIME = {
siGeneralizedTime,
const_cast<uint8_t*>(NEWER_GENERALIZEDTIME_DATA),
sizeof(NEWER_GENERALIZEDTIME_DATA)
};
static const uint8_t NEWER_UTCTIME_DATA[] = {
'2', '1', '0', '1', '0', '1', // 2021-01-01
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
};
static const SECItem NEWER_UTCTIME = {
siUTCTime,
const_cast<uint8_t*>(NEWER_UTCTIME_DATA),
sizeof(NEWER_UTCTIME_DATA)
};
static const PRTime FUTURE_TIME(YMDHMS(2025, 12, 31, 12, 23, 56));
class pkixcheck_CheckTimes : public ::testing::Test
{
public:
virtual void SetUp()
{
PR_SetError(0, 0);
}
};
TEST_F(pkixcheck_CheckTimes, BothEmptyNull)
{
static const CERTValidity validity = { nullptr, empty_null, empty_null };
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, NotBeforeEmptyNull)
{
static const CERTValidity validity = { nullptr, empty_null, NEWER_UTCTIME };
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, NotAfterEmptyNull)
{
static const CERTValidity validity = { nullptr, OLDER_UTCTIME, empty_null };
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_UTCTIME_UTCTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_GENERALIZEDTIME_GENERALIZEDTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_GENERALIZEDTIME, NEWER_GENERALIZEDTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_GENERALIZEDTIME_UTCTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_GENERALIZEDTIME, NEWER_UTCTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, Valid_UTCTIME_GENERALIZEDTIME)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_GENERALIZEDTIME
};
ASSERT_Success(CheckTimes(validity, NOW));
}
TEST_F(pkixcheck_CheckTimes, InvalidBeforeNotBefore)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
};
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, PAST_TIME));
}
TEST_F(pkixcheck_CheckTimes, InvalidAfterNotAfter)
{
static const CERTValidity validity = {
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
};
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, FUTURE_TIME));
}
TEST_F(pkixcheck_CheckTimes, InvalidNotAfterBeforeNotBefore)
{
static const CERTValidity validity = {
nullptr, NEWER_UTCTIME, OLDER_UTCTIME
};
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
CheckTimes(validity, NOW));
}

View File

@ -28,9 +28,11 @@
#include "pkix/bind.h" #include "pkix/bind.h"
#include "pkixder.h" #include "pkixder.h"
#include "pkixtestutil.h"
#include "stdint.h" #include "stdint.h"
using namespace mozilla::pkix::der; using namespace mozilla::pkix::der;
using namespace mozilla::pkix::test;
using namespace std; using namespace std;
namespace { namespace {
@ -305,23 +307,6 @@ TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError()); ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
} }
static PRTime
YMDHMS(int16_t year, int16_t month, int16_t day,
int16_t hour, int16_t minutes, int16_t seconds)
{
PRExplodedTime tm;
tm.tm_usec = 0;
tm.tm_sec = seconds;
tm.tm_min = minutes;
tm.tm_hour = hour;
tm.tm_mday = day;
tm.tm_month = month - 1; // tm_month is zero-based
tm.tm_year = year;
tm.tm_params.tp_gmt_offset = 0;
tm.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&tm);
}
//////////////////////////////////////// ////////////////////////////////////////
// GeneralizedTime and TimeChoice // GeneralizedTime and TimeChoice
// //

View File

@ -428,6 +428,23 @@ PRTimeToTimeChoice(PLArenaPool* arena, PRTime time)
: GeneralizedTime); : GeneralizedTime);
} }
PRTime
YMDHMS(int16_t year, int16_t month, int16_t day,
int16_t hour, int16_t minutes, int16_t seconds)
{
PRExplodedTime tm;
tm.tm_usec = 0;
tm.tm_sec = seconds;
tm.tm_min = minutes;
tm.tm_hour = hour;
tm.tm_mday = day;
tm.tm_month = month - 1; // tm_month is zero-based
tm.tm_year = year;
tm.tm_params.tp_gmt_offset = 0;
tm.tm_params.tp_dst_offset = 0;
return PR_ImplodeTime(&tm);
}
static SECItem* static SECItem*
SignedData(PLArenaPool* arena, const SECItem* tbsData, SignedData(PLArenaPool* arena, const SECItem* tbsData,
SECKEYPrivateKey* privKey, SECOidTag hashAlg, SECKEYPrivateKey* privKey, SECOidTag hashAlg,

View File

@ -62,6 +62,10 @@ FILE* OpenFile(const char* dir, const char* filename, const char* mode);
extern const PRTime ONE_DAY; extern const PRTime ONE_DAY;
// e.g. YMDHMS(2016, 12, 31, 1, 23, 45) => 2016-12-31:01:23:45 (GMT)
PRTime YMDHMS(int16_t year, int16_t month, int16_t day,
int16_t hour, int16_t minutes, int16_t seconds);
SECStatus GenerateKeyPair(/*out*/ ScopedSECKEYPublicKey& publicKey, SECStatus GenerateKeyPair(/*out*/ ScopedSECKEYPublicKey& publicKey,
/*out*/ ScopedSECKEYPrivateKey& privateKey); /*out*/ ScopedSECKEYPrivateKey& privateKey);

View File

@ -4,7 +4,6 @@
"robocop": "TIMED_OUT", "robocop": "TIMED_OUT",
"content/canvas/test/webgl-conformance": "bug 865443 - separate suite -- mochitest-gl", "content/canvas/test/webgl-conformance": "bug 865443 - separate suite -- mochitest-gl",
"content/canvas/test/webgl-mochitest/test_no_arr_points.html": "Android 2.3 aws only; bug 1030942", "content/canvas/test/webgl-mochitest/test_no_arr_points.html": "Android 2.3 aws only; bug 1030942",
"content/html/content/test/test_bug659743.xml": "Android 2.3 aws only; bug 1031103",
"docshell/test/navigation/test_reserved.html": "too slow on Android 2.3 aws only; bug 1030403", "docshell/test/navigation/test_reserved.html": "too slow on Android 2.3 aws only; bug 1030403",
"dom/media/tests/mochitest": "Android 2.3 only; bug 981881", "dom/media/tests/mochitest": "Android 2.3 only; bug 981881",
"layout/style/test/test_media_queries.html": "Android 2.3 aws only; bug 1030419", "layout/style/test/test_media_queries.html": "Android 2.3 aws only; bug 1030419",

View File

@ -537,20 +537,33 @@ class DeviceManagerSUT(DeviceManager):
def killProcess(self, appname, sig=None): def killProcess(self, appname, sig=None):
if sig: if sig:
self._logger.warn("killProcess(): sig parameter unsupported on SUT") pid = self.processExist(appname)
retries = 0 if pid and pid > 0:
while retries < self.retryLimit: try:
try: self.shellCheckOutput(['kill', '-%d' % sig, str(pid)],
if self.processExist(appname): root=True)
self._runCmds([{ 'cmd': 'kill ' + appname }]) except DMError, err:
return self._logger.warn("unable to kill -%d %s (pid %s)" %
except DMError, err: (sig, appname, str(pid)))
retries +=1 self._logger.debug(err)
self._logger.warn("try %d of %d failed to kill %s" %
(retries, self.retryLimit, appname))
self._logger.debug(err)
if retries >= self.retryLimit:
raise err raise err
else:
self._logger.warn("unable to kill -%d %s -- not running?" %
(sig, appname))
else:
retries = 0
while retries < self.retryLimit:
try:
if self.processExist(appname):
self._runCmds([{ 'cmd': 'kill ' + appname }])
return
except DMError, err:
retries += 1
self._logger.warn("try %d of %d failed to kill %s" %
(retries, self.retryLimit, appname))
self._logger.debug(err)
if retries >= self.retryLimit:
raise err
def getTempDir(self): def getTempDir(self):
return self._runCmds([{ 'cmd': 'tmpd' }]).strip() return self._runCmds([{ 'cmd': 'tmpd' }]).strip()

View File

@ -2959,6 +2959,28 @@
"extended_statistics_ok": true, "extended_statistics_ok": true,
"description": "PLACES: Time to calculate the md5 hash for a backup" "description": "PLACES: Time to calculate the md5 hash for a backup"
}, },
"FENNEC_DISTRIBUTION_REFERRER_INVALID": {
"expires_in_version": "never",
"kind": "flag",
"description": "Whether the referrer intent specified an invalid distribution name",
"cpp_guard": "ANDROID"
},
"FENNEC_DISTRIBUTION_CODE_CATEGORY": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 20,
"description": "First digit of HTTP result code, or error category, during distribution download",
"cpp_guard": "ANDROID"
},
"FENNEC_DISTRIBUTION_DOWNLOAD_TIME_MS": {
"expires_in_version": "never",
"kind": "exponential",
"low": 100,
"high": "40000",
"n_buckets": 30,
"description": "Time taken to download a specified distribution file (msec)",
"cpp_guard": "ANDROID"
},
"FENNEC_FAVICONS_COUNT": { "FENNEC_FAVICONS_COUNT": {
"expires_in_version": "never", "expires_in_version": "never",
"kind": "exponential", "kind": "exponential",

View File

@ -39,10 +39,9 @@ const UDPSocket = CC("@mozilla.org/network/udp-socket;1",
"nsIUDPSocket", "nsIUDPSocket",
"init"); "init");
// TODO Bug 1027456: May need to reserve these with IANA
const SCAN_PORT = 50624; const SCAN_PORT = 50624;
const UPDATE_PORT = 50625; const UPDATE_PORT = 50625;
const ADDRESS = "224.0.0.200"; const ADDRESS = "224.0.0.115";
const REPLY_TIMEOUT = 5000; const REPLY_TIMEOUT = 5000;
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {}); const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
@ -158,6 +157,8 @@ function Discovery() {
this._onRemoteUpdate = this._onRemoteUpdate.bind(this); this._onRemoteUpdate = this._onRemoteUpdate.bind(this);
this._purgeMissingDevices = this._purgeMissingDevices.bind(this); this._purgeMissingDevices = this._purgeMissingDevices.bind(this);
Services.obs.addObserver(this, "network-active-changed", false);
this._getSystemInfo(); this._getSystemInfo();
} }
@ -295,6 +296,35 @@ Discovery.prototype = {
this._transports.update = null; this._transports.update = null;
}, },
observe: function(subject, topic, data) {
if (topic !== "network-active-changed") {
return;
}
let activeNetwork = subject;
if (!activeNetwork) {
log("No active network");
return;
}
activeNetwork = activeNetwork.QueryInterface(Ci.nsINetworkInterface);
log("Active network changed to: " + activeNetwork.type);
// UDP sockets go down when the device goes offline, so we'll restart them
// when the active network goes back to WiFi.
if (activeNetwork.type === Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
this._restartListening();
}
},
_restartListening: function() {
if (this._transports.scan) {
this._stopListeningForScan();
this._startListeningForScan();
}
if (this._transports.update) {
this._stopListeningForUpdate();
this._startListeningForUpdate();
}
},
/** /**
* When sending message, we can use either transport, so just pick the first * When sending message, we can use either transport, so just pick the first
* one currently alive. * one currently alive.

View File

@ -363,7 +363,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
let { caller, args, window, name } = functionCall.details; let { caller, args, window, name } = functionCall.details;
let source = caller; let source = caller;
let dest = args[0]; let dest = args[0];
let isAudioParam = dest instanceof window.AudioParam; let isAudioParam = dest ? getConstructorName(dest) === "AudioParam" : false;
// audionode.connect(param) // audionode.connect(param)
if (name === "connect" && isAudioParam) { if (name === "connect" && isAudioParam) {
@ -433,8 +433,9 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
}, },
"connect-param": { "connect-param": {
type: "connectParam", type: "connectParam",
source: Arg(0, "audionode"), source: Option(0, "audionode"),
param: Arg(1, "string") dest: Option(0, "audionode"),
param: Option(0, "string")
}, },
"change-param": { "change-param": {
type: "changeParam", type: "changeParam",
@ -461,12 +462,30 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
// Ensure AudioNode is wrapped. // Ensure AudioNode is wrapped.
node = new XPCNativeWrapper(node); node = new XPCNativeWrapper(node);
this._instrumentParams(node);
let actor = new AudioNodeActor(this.conn, node); let actor = new AudioNodeActor(this.conn, node);
this.manage(actor); this.manage(actor);
this._nativeToActorID.set(node.id, actor.actorID); this._nativeToActorID.set(node.id, actor.actorID);
return actor; return actor;
}, },
/**
* Takes an XrayWrapper node, and attaches the node's `nativeID`
* to the AudioParams as `_parentID`, as well as the the type of param
* as a string on `_paramName`.
*/
_instrumentParams: function (node) {
let type = getConstructorName(node);
Object.keys(NODE_PROPERTIES[type])
.filter(isAudioParam.bind(null, node))
.forEach(paramName => {
let param = node[paramName];
param._parentID = node.id;
param._paramName = paramName;
});
},
/** /**
* Takes an AudioNode and returns the stored actor for it. * Takes an AudioNode and returns the stored actor for it.
* In some cases, we won't have an actor stored (for example, * In some cases, we won't have an actor stored (for example,
@ -505,10 +524,15 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
/** /**
* Called when an audio node is connected to an audio param. * Called when an audio node is connected to an audio param.
* Implement in bug 986705
*/ */
_onConnectParam: function (source, dest) { _onConnectParam: function (source, param) {
// TODO bug 986705 let sourceActor = this._getActorByNativeID(source.id);
let destActor = this._getActorByNativeID(param._parentID);
emit(this, "connect-param", {
source: sourceActor,
dest: destActor,
param: param._paramName
});
}, },
/** /**

View File

@ -167,7 +167,6 @@ this.checkCert =
if (!issuerCert) if (!issuerCert)
throw new Ce(certNotBuiltInErr, Cr.NS_ERROR_ABORT); throw new Ce(certNotBuiltInErr, Cr.NS_ERROR_ABORT);
issuerCert = issuerCert.QueryInterface(Ci.nsIX509Cert3);
var tokenNames = issuerCert.getAllTokenNames({}); var tokenNames = issuerCert.getAllTokenNames({});
if (!tokenNames || !tokenNames.some(isBuiltinToken)) if (!tokenNames || !tokenNames.some(isBuiltinToken))

View File

@ -83,6 +83,7 @@ const PREFS_WHITELIST = [
const PREFS_BLACKLIST = [ const PREFS_BLACKLIST = [
/^network[.]proxy[.]/, /^network[.]proxy[.]/,
/[.]print_to_filename$/, /[.]print_to_filename$/,
/^print[.]macosx[.]pagesetup/,
]; ];
this.Troubleshoot = { this.Troubleshoot = {

View File

@ -15,120 +15,27 @@
* limitations under the License. * limitations under the License.
*/ */
#include <fcntl.h> #include "Framebuffer.h"
#include <linux/fb.h>
#include <linux/kd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <vector>
#include "android/log.h" #include "android/log.h"
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/ioctl.h>
#include "Framebuffer.h" #include "nsSize.h"
#include "gfxContext.h"
#include "gfxImageSurface.h"
#include "gfxUtils.h"
#include "mozilla/FileUtils.h" #include "mozilla/FileUtils.h"
#include "nsTArray.h"
#include "nsRegion.h"
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
using namespace std; using namespace std;
namespace mozilla { namespace mozilla {
namespace Framebuffer { namespace Framebuffer {
static int sFd = -1;
static size_t sMappedSize; static size_t sMappedSize;
static struct fb_var_screeninfo sVi; static struct fb_var_screeninfo sVi;
static size_t sActiveBuffer;
typedef vector<nsRefPtr<gfxImageSurface> > BufferVector;
BufferVector* sBuffers;
static gfxIntSize *sScreenSize = nullptr; static gfxIntSize *sScreenSize = nullptr;
BufferVector& Buffers() { return *sBuffers; }
bool
SetGraphicsMode()
{
ScopedClose fd(open("/dev/tty0", O_RDWR | O_SYNC));
if (0 > fd.get()) {
// This is non-fatal; post-Cupcake kernels don't have tty0.
LOG("No /dev/tty0?");
} else if (ioctl(fd.get(), KDSETMODE, (void*) KD_GRAPHICS)) {
LOG("Error setting graphics mode on /dev/tty0");
return false;
}
return true;
}
bool
Open()
{
if (0 <= sFd)
return true;
if (!SetGraphicsMode())
return false;
ScopedClose fd(open("/dev/graphics/fb0", O_RDWR));
if (0 > fd.get()) {
LOG("Error opening framebuffer device");
return false;
}
struct fb_fix_screeninfo fi;
if (0 > ioctl(fd.get(), FBIOGET_FSCREENINFO, &fi)) {
LOG("Error getting fixed screeninfo");
return false;
}
if (0 > ioctl(fd.get(), FBIOGET_VSCREENINFO, &sVi)) {
LOG("Error getting variable screeninfo");
return false;
}
sMappedSize = fi.smem_len;
void* mem = mmap(0, sMappedSize, PROT_READ | PROT_WRITE, MAP_SHARED,
fd.rwget(), 0);
if (MAP_FAILED == mem) {
LOG("Error mmap'ing framebuffer");
return false;
}
sFd = fd.get();
fd.forget();
// The android porting doc requires a /dev/graphics/fb0 device
// that's double buffered with r5g6b5 format. Hence the
// hard-coded numbers here.
gfxImageFormat format = gfxImageFormat::RGB16_565;
if (!sScreenSize) {
sScreenSize = new gfxIntSize(sVi.xres, sVi.yres);
}
long stride = fi.line_length;
size_t numFrameBytes = stride * sScreenSize->height;
sBuffers = new BufferVector(2);
unsigned char* data = static_cast<unsigned char*>(mem);
for (size_t i = 0; i < 2; ++i, data += numFrameBytes) {
memset(data, 0, numFrameBytes);
Buffers()[i] = new gfxImageSurface(data, *sScreenSize, stride, format);
}
// Clear the framebuffer to a known state.
Present(nsIntRect());
return true;
}
bool bool
GetSize(nsIntSize *aScreenSize) { GetSize(nsIntSize *aScreenSize) {
// If the framebuffer has been opened, we should always have the size. // If the framebuffer has been opened, we should always have the size.
@ -153,54 +60,5 @@ GetSize(nsIntSize *aScreenSize) {
return true; return true;
} }
void
Close()
{
if (0 > sFd)
return;
munmap(Buffers()[0]->Data(), sMappedSize);
delete sBuffers;
sBuffers = nullptr;
delete sScreenSize;
sScreenSize = nullptr;
close(sFd);
sFd = -1;
}
gfxASurface*
BackBuffer()
{
return Buffers()[!sActiveBuffer];
}
static gfxASurface*
FrontBuffer()
{
return Buffers()[sActiveBuffer];
}
void
Present(const nsIntRegion& aUpdated)
{
sActiveBuffer = !sActiveBuffer;
sVi.yres_virtual = sVi.yres * 2;
sVi.yoffset = sActiveBuffer * sVi.yres;
sVi.bits_per_pixel = 16;
if (ioctl(sFd, FBIOPUT_VSCREENINFO, &sVi) < 0) {
LOG("Error presenting front buffer");
}
nsRefPtr<gfxContext> ctx = new gfxContext(BackBuffer());
gfxUtils::PathFromRegion(ctx, aUpdated);
ctx->Clip();
ctx->SetSource(FrontBuffer());
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Paint(1.0);
}
} // namespace Framebuffer } // namespace Framebuffer
} // namespace mozilla } // namespace mozilla

View File

@ -15,48 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
class gfxASurface;
class nsIntRegion;
class nsIntSize; class nsIntSize;
namespace mozilla { namespace mozilla {
namespace Framebuffer { namespace Framebuffer {
//
// The general usage of Framebuffer is
//
// -- in initialization code --
// Open();
//
// -- ready to paint next frame --
// nsRefPtr<gfxASurface> backBuffer = BackBuffer();
// // ...
// Paint(backBuffer);
// // ...
// Present();
//
// Return true if the fbdev was successfully opened. If this fails,
// the result of all further calls is undefined. Open() is idempotent.
bool Open();
// After Close(), the result of all further calls is undefined.
// Close() is idempotent, and Open() can be called again after
// Close().
void Close();
// Return true if the fbdev was successfully opened or the size was // Return true if the fbdev was successfully opened or the size was
// already cached. // already cached.
bool GetSize(nsIntSize *aScreenSize); bool GetSize(nsIntSize *aScreenSize);
// Return the buffer to be drawn into, that will be the next frame.
gfxASurface* BackBuffer();
// Swap the front buffer for the back buffer. |aUpdated| is the
// region of the back buffer that was repainted.
void Present(const nsIntRegion& aUpdated);
} // namespace Framebuffer } // namespace Framebuffer
} // namespace mozilla } // namespace mozilla

View File

@ -19,9 +19,9 @@
#include "libdisplay/GonkDisplay.h" #include "libdisplay/GonkDisplay.h"
#include "Framebuffer.h" #include "Framebuffer.h"
#include "GLContext.h" // for GLContext
#include "HwcUtils.h" #include "HwcUtils.h"
#include "HwcComposer2D.h" #include "HwcComposer2D.h"
#include "LayerScope.h"
#include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/LayerManagerComposite.h"
#include "mozilla/layers/PLayerTransaction.h" #include "mozilla/layers/PLayerTransaction.h"
#include "mozilla/layers/ShadowLayerUtilsGralloc.h" #include "mozilla/layers/ShadowLayerUtilsGralloc.h"
@ -807,8 +807,12 @@ HwcComposer2D::TryRender(Layer* aRoot,
return false; return false;
} }
// Send data to LayerScope for debugging
SendtoLayerScope();
if (!TryHwComposition()) { if (!TryHwComposition()) {
LOGD("H/W Composition failed"); LOGD("H/W Composition failed");
LayerScope::CleanLayer();
return false; return false;
} }
@ -816,4 +820,19 @@ HwcComposer2D::TryRender(Layer* aRoot,
return true; return true;
} }
void
HwcComposer2D::SendtoLayerScope()
{
if (!LayerScope::CheckSendable()) {
return;
}
const int len = mList->numHwLayers;
for (int i = 0; i < len; ++i) {
LayerComposite* layer = mHwcLayerMap[i];
const hwc_rect_t r = mList->hwLayers[i].displayFrame;
LayerScope::SendLayer(layer, r.right - r.left, r.bottom - r.top);
}
}
} // namespace mozilla } // namespace mozilla

View File

@ -97,6 +97,7 @@ private:
const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform); const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform);
void setCrop(HwcLayer* layer, hwc_rect_t srcCrop); void setCrop(HwcLayer* layer, hwc_rect_t srcCrop);
void setHwcGeometry(bool aGeometryChanged); void setHwcGeometry(bool aGeometryChanged);
void SendtoLayerScope();
HwcDevice* mHwc; HwcDevice* mHwc;
HwcList* mList; HwcList* mList;

View File

@ -68,14 +68,10 @@ static uint32_t sScreenRotation;
static uint32_t sPhysicalScreenRotation; static uint32_t sPhysicalScreenRotation;
static nsIntRect sVirtualBounds; static nsIntRect sVirtualBounds;
static nsRefPtr<GLContext> sGLContext;
static nsTArray<nsWindow *> sTopWindows; static nsTArray<nsWindow *> sTopWindows;
static nsWindow *gFocusedWindow = nullptr; static nsWindow *gFocusedWindow = nullptr;
static bool sFramebufferOpen;
static bool sUsingOMTC;
static bool sUsingHwc; static bool sUsingHwc;
static bool sScreenInitialized; static bool sScreenInitialized;
static nsRefPtr<gfxASurface> sOMTCSurface;
namespace { namespace {
@ -160,15 +156,11 @@ nsWindow::nsWindow()
// to know the color depth, which asks our native window. // to know the color depth, which asks our native window.
// This has to happen after other init has finished. // This has to happen after other init has finished.
gfxPlatform::GetPlatform(); gfxPlatform::GetPlatform();
sUsingOMTC = ShouldUseOffMainThreadCompositing(); if (!ShouldUseOffMainThreadCompositing()) {
MOZ_CRASH("How can we render apps, then?");
}
//Update sUsingHwc whenever layers.composer2d.enabled changes //Update sUsingHwc whenever layers.composer2d.enabled changes
Preferences::AddBoolVarCache(&sUsingHwc, "layers.composer2d.enabled"); Preferences::AddBoolVarCache(&sUsingHwc, "layers.composer2d.enabled");
if (sUsingOMTC) {
sOMTCSurface = new gfxImageSurface(gfxIntSize(1, 1),
gfxImageFormat::RGB24);
}
} }
} }
@ -201,35 +193,6 @@ nsWindow::DoDraw(void)
LayerManager* lm = targetWindow->GetLayerManager(); LayerManager* lm = targetWindow->GetLayerManager();
if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) { if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) {
// No need to do anything, the compositor will handle drawing // No need to do anything, the compositor will handle drawing
} else if (mozilla::layers::LayersBackend::LAYERS_BASIC == lm->GetBackendType()) {
MOZ_ASSERT(sFramebufferOpen || sUsingOMTC);
nsRefPtr<gfxASurface> targetSurface;
if(sUsingOMTC)
targetSurface = sOMTCSurface;
else
targetSurface = Framebuffer::BackBuffer();
{
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
gfxUtils::PathFromRegion(ctx, sVirtualBounds);
ctx->Clip();
// No double-buffering needed.
AutoLayerManagerSetup setupLayerManager(
targetWindow, ctx, mozilla::layers::BufferMode::BUFFER_NONE,
ScreenRotation(EffectiveScreenRotation()));
listener = targetWindow->GetWidgetListener();
if (listener) {
listener->PaintWindow(targetWindow, sVirtualBounds);
}
}
if (!sUsingOMTC) {
targetSurface->Flush();
Framebuffer::Present(sVirtualBounds);
}
} else { } else {
NS_RUNTIMEABORT("Unexpected layer manager type"); NS_RUNTIMEABORT("Unexpected layer manager type");
} }
@ -537,12 +500,7 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
if (mLayerManager) { if (mLayerManager) {
// This layer manager might be used for painting outside of DoDraw(), so we need // This layer manager might be used for painting outside of DoDraw(), so we need
// to set the correct rotation on it. // to set the correct rotation on it.
if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) { if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
BasicLayerManager* manager =
static_cast<BasicLayerManager*>(mLayerManager.get());
manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
ScreenRotation(EffectiveScreenRotation()));
} else if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
ClientLayerManager* manager = ClientLayerManager* manager =
static_cast<ClientLayerManager*>(mLayerManager.get()); static_cast<ClientLayerManager*>(mLayerManager.get());
manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
@ -561,38 +519,13 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
return nullptr; return nullptr;
} }
if (sUsingOMTC) { CreateCompositor();
CreateCompositor(); if (mCompositorParent) {
if (mCompositorParent) { uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId(); CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController()); CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
}
if (mLayerManager)
return mLayerManager;
} }
MOZ_ASSERT(mLayerManager);
if (mUseLayersAcceleration) {
DebugOnly<nsIntRect> fbBounds = gScreenBounds;
if (!sGLContext) {
sGLContext = GLContextProvider::CreateForWindow(this);
}
MOZ_ASSERT(fbBounds.value == gScreenBounds);
}
// Fall back to software rendering.
sFramebufferOpen = Framebuffer::Open();
if (sFramebufferOpen) {
LOG("Falling back to framebuffer software rendering");
} else {
LOGE("Failed to mmap fb(?!?), aborting ...");
NS_RUNTIMEABORT("Can't open GL context and can't fall back on /dev/graphics/fb0 ...");
}
mLayerManager = new ClientLayerManager(this);
mUseLayersAcceleration = false;
return mLayerManager; return mLayerManager;
} }

View File

@ -172,7 +172,7 @@ static void DeferredDestroyCompositor(CompositorParent* aCompositorParent,
void nsBaseWidget::DestroyCompositor() void nsBaseWidget::DestroyCompositor()
{ {
LayerScope::DestroyServerSocket(); LayerScope::DeInit();
if (mCompositorChild) { if (mCompositorChild) {
mCompositorChild->SendWillStop(); mCompositorChild->SendWillStop();
@ -900,8 +900,8 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
return; return;
} }
// The server socket has to be created on the main thread. // Initialize LayerScope on the main thread.
LayerScope::CreateServerSocket(); LayerScope::Init();
mCompositorParent = NewCompositorParent(aWidth, aHeight); mCompositorParent = NewCompositorParent(aWidth, aHeight);
MessageChannel *parentChannel = mCompositorParent->GetIPCChannel(); MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();

View File

@ -33,8 +33,7 @@ else:
'xptcinvoke.cpp', 'xptcinvoke.cpp',
'xptcstubs.cpp', 'xptcstubs.cpp',
] ]
if CONFIG['TARGET_CPU'] == 'x86_64' or CONFIG['GNU_CXX']: SOURCES['xptcinvoke.cpp'].no_pgo = True
SOURCES['xptcinvoke.cpp'].no_pgo = True
FINAL_LIBRARY = 'xpcom_core' FINAL_LIBRARY = 'xpcom_core'
@ -42,8 +41,3 @@ LOCAL_INCLUDES += [
'../..', '../..',
'/xpcom/reflect/xptinfo', '/xpcom/reflect/xptinfo',
] ]
if CONFIG['TARGET_CPU'] != 'x86_64':
if not CONFIG['GNU_CXX']:
# FIXME: bug 413019
NO_PGO = True