mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
fb2781b65d
@ -9,6 +9,7 @@ support-files =
|
||||
doc_media-node-creation.html
|
||||
doc_destroy-nodes.html
|
||||
doc_connect-toggle.html
|
||||
doc_connect-param.html
|
||||
440hz_sine.ogg
|
||||
head.js
|
||||
|
||||
@ -20,6 +21,7 @@ support-files =
|
||||
[browser_audionode-actor-is-source.js]
|
||||
[browser_webaudio-actor-simple.js]
|
||||
[browser_webaudio-actor-destroy-node.js]
|
||||
[browser_webaudio-actor-connect-param.js]
|
||||
|
||||
[browser_wa_destroy-node-01.js]
|
||||
|
||||
|
@ -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();
|
||||
}
|
28
browser/devtools/webaudioeditor/test/doc_connect-param.html
Normal file
28
browser/devtools/webaudioeditor/test/doc_connect-param.html
Normal 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>
|
@ -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 DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.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.
|
||||
waitForExplicitFinish();
|
||||
|
@ -86,7 +86,7 @@ class RemoteAutomation(Automation):
|
||||
|
||||
topActivity = self._devicemanager.getTopActivity()
|
||||
if topActivity == proc.procName:
|
||||
proc.kill()
|
||||
proc.kill(True)
|
||||
if status == 1:
|
||||
if maxTime:
|
||||
print "TEST-UNEXPECTED-FAIL | %s | application ran for longer than " \
|
||||
@ -287,5 +287,26 @@ class RemoteAutomation(Automation):
|
||||
|
||||
return status
|
||||
|
||||
def kill(self):
|
||||
self.dm.killProcess(self.procName)
|
||||
def kill(self, stagedShutdown = False):
|
||||
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)
|
||||
|
@ -228,7 +228,12 @@ HTMLTrackElement::LoadResource()
|
||||
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
|
||||
// created to load the media content.
|
||||
|
@ -321,6 +321,7 @@ skip-if = os == 'win' # bug 894922
|
||||
[test_bug895305.html]
|
||||
[test_bug919265.html]
|
||||
[test_bug957847.html]
|
||||
[test_bug1018933.html]
|
||||
[test_can_play_type.html]
|
||||
[test_can_play_type_mpeg.html]
|
||||
skip-if = buildapp == 'b2g' # bug 1021675
|
||||
|
50
content/media/test/test_bug1018933.html
Normal file
50
content/media/test/test_bug1018933.html
Normal 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>
|
@ -12,7 +12,6 @@
|
||||
#include "StreamNotifyChild.h"
|
||||
#include "PluginProcessChild.h"
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfx2DGlue.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
|
||||
PluginInstanceChild::CreateOptSurface(void)
|
||||
{
|
||||
@ -3454,12 +3447,14 @@ PluginInstanceChild::ShowPluginFrame()
|
||||
PLUGIN_LOG_DEBUG((" (on background)"));
|
||||
// Source the background pixels ...
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx =
|
||||
new gfxContext(mHelperSurface ? mHelperSurface : mCurrentSurface);
|
||||
ctx->SetSource(mBackground);
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx->Rectangle(gfxRect(rect.x, rect.y, rect.width, rect.height));
|
||||
ctx->Fill();
|
||||
nsRefPtr<gfxASurface> surface =
|
||||
mHelperSurface ? mHelperSurface : mCurrentSurface;
|
||||
RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(surface);
|
||||
RefPtr<SourceSurface> backgroundSurface =
|
||||
gfxPlatform::GetSourceSurfaceForSurface(dt, mBackground);
|
||||
dt->CopySurface(backgroundSurface,
|
||||
ToIntRect(rect),
|
||||
ToIntPoint(rect.TopLeft()));
|
||||
}
|
||||
// ... and hand off to the plugin
|
||||
// BEWARE: mBackground may die during this call
|
||||
@ -3583,18 +3578,17 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
|
||||
mSurfaceDifferenceRect.width, mSurfaceDifferenceRect.height));
|
||||
|
||||
// Read back previous content
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(mCurrentSurface);
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx->SetSource(mBackSurface);
|
||||
RefPtr<DrawTarget> dt = CreateDrawTargetForSurface(mCurrentSurface);
|
||||
RefPtr<SourceSurface> source =
|
||||
gfxPlatform::GetSourceSurfaceForSurface(dt, mBackSurface);
|
||||
// Subtract from mSurfaceDifferenceRect area which is overlapping with rect
|
||||
nsIntRegion result;
|
||||
result.Sub(mSurfaceDifferenceRect, nsIntRegion(rect));
|
||||
nsIntRegionRectIterator iter(result);
|
||||
const nsIntRect* r;
|
||||
while ((r = iter.Next()) != nullptr) {
|
||||
ctx->Rectangle(GfxFromNsRect(*r));
|
||||
dt->CopySurface(source, ToIntRect(*r), ToIntPoint(r->TopLeft()));
|
||||
}
|
||||
ctx->Fill();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3309,13 +3309,13 @@ WifiWorker.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let certDB2 = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB2);
|
||||
if (!certDB2) {
|
||||
let certDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
if (!certDB) {
|
||||
self._sendMessage(message, false, "Failed to query NSS DB service", msg);
|
||||
}
|
||||
|
||||
let certList = certDB2.getCerts();
|
||||
let certList = certDB.getCerts();
|
||||
if (!certList) {
|
||||
self._sendMessage(message, false, "Failed to get certificate List", msg);
|
||||
}
|
||||
@ -3332,7 +3332,7 @@ WifiWorker.prototype = {
|
||||
};
|
||||
|
||||
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);
|
||||
if (!certNicknameInfo) {
|
||||
continue;
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "BackgroundChild.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
#include "jsfriendapi.h"
|
||||
@ -41,7 +40,6 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCycleCollector.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
#include "nsIIPCBackgroundChildCreateCallback.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsLayoutStatics.h"
|
||||
#include "nsNetUtil.h"
|
||||
@ -66,12 +64,6 @@
|
||||
#include "WorkerPrivate.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::dom;
|
||||
|
||||
@ -169,10 +161,6 @@ RuntimeService* gRuntimeService = nullptr;
|
||||
// Only non-null during the call to Init.
|
||||
RuntimeService* gRuntimeServiceDuringInit = nullptr;
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
bool gTestPBackground = false;
|
||||
#endif // ENABLE_TESTS
|
||||
|
||||
enum {
|
||||
ID_Worker = 0,
|
||||
ID_ChromeWorker,
|
||||
@ -911,37 +899,6 @@ private:
|
||||
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
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
@ -984,9 +941,6 @@ private:
|
||||
~WorkerThreadPrimaryRunnable()
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
SynchronouslyCreatePBackground();
|
||||
|
||||
NS_DECL_NSIRUNNABLE
|
||||
};
|
||||
|
||||
@ -1086,28 +1040,6 @@ public:
|
||||
}
|
||||
#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:
|
||||
WorkerThread()
|
||||
: nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
|
||||
@ -1311,10 +1243,6 @@ RuntimeService::GetOrCreateService()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
gTestPBackground = mozilla::Preferences::GetBool("pbackground.testing", false);
|
||||
#endif // ENABLE_TESTS
|
||||
|
||||
// The observer service now owns us until shutdown.
|
||||
gRuntimeService = service;
|
||||
}
|
||||
@ -1604,6 +1532,10 @@ RuntimeService::ScheduleWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
thread->SetAcceptingNonWorkerRunnables(false);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2592,20 +2524,8 @@ RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
|
||||
bool aMayWait,
|
||||
uint32_t aRecursionDepth)
|
||||
{
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// 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;
|
||||
}
|
||||
MOZ_ASSERT(!aMayWait);
|
||||
|
||||
mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
|
||||
return NS_OK;
|
||||
@ -2649,15 +2569,11 @@ LogViolationDetailsRunnable::Run()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerBackgroundChildCallback, nsIIPCBackgroundChildCreateCallback)
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadPrimaryRunnable, nsRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThreadPrimaryRunnable::Run()
|
||||
{
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
if (IsNuwaProcess()) {
|
||||
NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
|
||||
@ -2676,19 +2592,6 @@ WorkerThreadPrimaryRunnable::Run()
|
||||
|
||||
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);
|
||||
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
@ -2722,12 +2625,6 @@ WorkerThreadPrimaryRunnable::Run()
|
||||
JS_ReportPendingException(cx);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
mThread->TestPBackground();
|
||||
#endif
|
||||
|
||||
BackgroundChild::CloseForCurrentThread();
|
||||
|
||||
#ifdef MOZ_ENABLE_PROFILER_SPS
|
||||
if (stack) {
|
||||
stack->sampleRuntime(nullptr);
|
||||
@ -2766,38 +2663,6 @@ WorkerThreadPrimaryRunnable::Run()
|
||||
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,
|
||||
nsRunnable)
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Endian.h"
|
||||
#include "TexturePoolOGL.h"
|
||||
#include "mozilla/layers/CompositorOGL.h"
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
#include "mozilla/layers/TextureHostOGL.h"
|
||||
|
||||
#include "gfxColor.h"
|
||||
@ -317,6 +319,7 @@ public:
|
||||
}
|
||||
|
||||
void AppendDebugData(DebugGLData *aDebugData);
|
||||
void CleanDebugData();
|
||||
void DispatchDebugData();
|
||||
private:
|
||||
nsTArray<nsRefPtr<LayerScopeWebSocketHandler> > mHandlers;
|
||||
@ -325,7 +328,37 @@ private:
|
||||
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> {
|
||||
public:
|
||||
@ -378,9 +411,9 @@ public:
|
||||
}
|
||||
|
||||
static bool WriteToStream(void *ptr, uint32_t size) {
|
||||
if (!gLayerScopeWebSocketManager)
|
||||
if (!WebSocketHelper::GetSocketManager())
|
||||
return true;
|
||||
return gLayerScopeWebSocketManager->WriteAll(ptr, size);
|
||||
return WebSocketHelper::GetSocketManager()->WriteAll(ptr, size);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -428,83 +461,97 @@ public:
|
||||
|
||||
class DebugGLTextureData : public DebugGLData {
|
||||
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),
|
||||
mLayerRef(layerRef),
|
||||
mTarget(target),
|
||||
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; }
|
||||
GLuint GetName() const { return mName; }
|
||||
DataSourceSurface* GetImage() const { return mImage; }
|
||||
GLenum GetTextureTarget() const { return mTarget; }
|
||||
|
||||
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
|
||||
if (!WriteToStream(&packet, sizeof(packet)))
|
||||
if (!WriteToStream(&mPacket, sizeof(mPacket)))
|
||||
return false;
|
||||
|
||||
// then the image data
|
||||
if (!WriteToStream(dataptr, datasize))
|
||||
if (mCompresseddata.get() && !WriteToStream(mCompresseddata.get(), mDatasize))
|
||||
return false;
|
||||
|
||||
// then pad out to 4 bytes
|
||||
if (datasize % 4 != 0) {
|
||||
if (mDatasize % 4 != 0) {
|
||||
static char buf[] = { 0, 0, 0, 0 };
|
||||
if (!WriteToStream(buf, 4 - (datasize % 4)))
|
||||
if (!WriteToStream(buf, 4 - (mDatasize % 4)))
|
||||
return false;
|
||||
}
|
||||
|
||||
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:
|
||||
void* mLayerRef;
|
||||
GLenum mTarget;
|
||||
GLuint mName;
|
||||
RefPtr<DataSourceSurface> mImage;
|
||||
|
||||
// Packet data
|
||||
DebugGLData::TexturePacket mPacket;
|
||||
std::auto_ptr<char> mCompresseddata;
|
||||
uint32_t mDatasize;
|
||||
};
|
||||
|
||||
class DebugGLColorData : public DebugGLData {
|
||||
@ -539,18 +586,6 @@ protected:
|
||||
nsIntSize mSize;
|
||||
};
|
||||
|
||||
static bool
|
||||
CheckSender()
|
||||
{
|
||||
if (!gLayerScopeWebSocketManager)
|
||||
return false;
|
||||
|
||||
if (!gLayerScopeWebSocketManager->IsConnected())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class DebugListener : public nsIServerSocketListener
|
||||
{
|
||||
virtual ~DebugListener() { }
|
||||
@ -566,11 +601,11 @@ public:
|
||||
NS_IMETHODIMP OnSocketAccepted(nsIServerSocket *aServ,
|
||||
nsISocketTransport *aTransport)
|
||||
{
|
||||
if (!gLayerScopeWebSocketManager)
|
||||
if (!WebSocketHelper::GetSocketManager())
|
||||
return NS_OK;
|
||||
|
||||
printf_stderr("*** LayerScope: Accepted connection\n");
|
||||
gLayerScopeWebSocketManager->AddConnection(aTransport);
|
||||
WebSocketHelper::GetSocketManager()->AddConnection(aTransport);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -594,24 +629,19 @@ public:
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
DebugDataSender() {
|
||||
mList = new LinkedList<DebugGLData>();
|
||||
}
|
||||
DebugDataSender() { }
|
||||
|
||||
void Append(DebugGLData *d) {
|
||||
mList->insertBack(d);
|
||||
mList.insertBack(d);
|
||||
}
|
||||
|
||||
void Cleanup() {
|
||||
if (!mList)
|
||||
if (mList.isEmpty())
|
||||
return;
|
||||
|
||||
DebugGLData *d;
|
||||
while ((d = mList->popFirst()) != nullptr)
|
||||
while ((d = mList.popFirst()) != nullptr)
|
||||
delete d;
|
||||
delete mList;
|
||||
|
||||
mList = nullptr;
|
||||
}
|
||||
|
||||
/* nsIRunnable impl; send the data */
|
||||
@ -620,7 +650,7 @@ public:
|
||||
DebugGLData *d;
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
while ((d = mList->popFirst()) != nullptr) {
|
||||
while ((d = mList.popFirst()) != nullptr) {
|
||||
std::auto_ptr<DebugGLData> cleaner(d);
|
||||
if (!d->Write()) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
@ -631,84 +661,124 @@ public:
|
||||
Cleanup();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LayerScope::DestroyServerSocket();
|
||||
WebSocketHelper::DestroyServerSocket();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
LinkedList<DebugGLData> *mList;
|
||||
LinkedList<DebugGLData> mList;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!gLayerScopeWebSocketManager) {
|
||||
gLayerScopeWebSocketManager = new LayerScopeWebSocketManager();
|
||||
switch (aLayer->GetLayer()->GetType()) {
|
||||
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
|
||||
LayerScope::DestroyServerSocket()
|
||||
SenderHelper::SendColor(void* aLayerRef,
|
||||
const gfxRGBA& aColor,
|
||||
int aWidth,
|
||||
int aHeight)
|
||||
{
|
||||
if (gLayerScopeWebSocketManager) {
|
||||
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(
|
||||
WebSocketHelper::GetSocketManager()->AppendDebugData(
|
||||
new DebugGLColorData(aLayerRef, aColor, aWidth, aHeight));
|
||||
}
|
||||
|
||||
static void
|
||||
SendTextureSource(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
bool aFlipY)
|
||||
void
|
||||
SenderHelper::SendTextureSource(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
TextureSourceOGL* aSource,
|
||||
bool aFlipY)
|
||||
{
|
||||
MOZ_ASSERT(aGLContext);
|
||||
if (!aGLContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum textureTarget = aSource->GetTextureTarget();
|
||||
ShaderConfigOGL config = ShaderConfigFromTargetAndFormat(textureTarget,
|
||||
aSource->GetFormat());
|
||||
@ -736,15 +806,15 @@ SendTextureSource(GLContext* aGLContext,
|
||||
size,
|
||||
shaderConfig, aFlipY);
|
||||
|
||||
gLayerScopeWebSocketManager->AppendDebugData(
|
||||
WebSocketHelper::GetSocketManager()->AppendDebugData(
|
||||
new DebugGLTextureData(aGLContext, aLayerRef, textureTarget,
|
||||
textureId, img));
|
||||
}
|
||||
|
||||
static void
|
||||
SendTexturedEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const TexturedEffect* aEffect)
|
||||
void
|
||||
SenderHelper::SendTexturedEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const TexturedEffect* aEffect)
|
||||
{
|
||||
TextureSourceOGL* source = aEffect->mTexture->AsSourceOGL();
|
||||
if (!source)
|
||||
@ -754,10 +824,10 @@ SendTexturedEffect(GLContext* aGLContext,
|
||||
SendTextureSource(aGLContext, aLayerRef, source, flipY);
|
||||
}
|
||||
|
||||
static void
|
||||
SendYCbCrEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectYCbCr* aEffect)
|
||||
void
|
||||
SenderHelper::SendYCbCrEffect(GLContext* aGLContext,
|
||||
void* aLayerRef,
|
||||
const EffectYCbCr* aEffect)
|
||||
{
|
||||
TextureSource* sourceYCbCr = aEffect->mTexture;
|
||||
if (!sourceYCbCr)
|
||||
@ -775,49 +845,48 @@ SendYCbCrEffect(GLContext* aGLContext,
|
||||
}
|
||||
|
||||
void
|
||||
LayerScope::SendEffectChain(GLContext* aGLContext,
|
||||
const EffectChain& aEffectChain,
|
||||
int aWidth, int aHeight)
|
||||
SenderHelper::SendEffectChain(GLContext* aGLContext,
|
||||
const EffectChain& aEffectChain,
|
||||
int aWidth,
|
||||
int aHeight)
|
||||
{
|
||||
if (!CheckSender())
|
||||
return;
|
||||
|
||||
const Effect* primaryEffect = aEffectChain.mPrimaryEffect;
|
||||
switch (primaryEffect->mType) {
|
||||
case EffectTypes::RGB:
|
||||
{
|
||||
const TexturedEffect* texturedEffect =
|
||||
static_cast<const TexturedEffect*>(primaryEffect);
|
||||
SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
|
||||
}
|
||||
break;
|
||||
case EffectTypes::YCBCR:
|
||||
{
|
||||
const EffectYCbCr* yCbCrEffect =
|
||||
static_cast<const EffectYCbCr*>(primaryEffect);
|
||||
SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
|
||||
}
|
||||
case EffectTypes::SOLID_COLOR:
|
||||
{
|
||||
const EffectSolidColor* solidColorEffect =
|
||||
static_cast<const EffectSolidColor*>(primaryEffect);
|
||||
gfxRGBA color(solidColorEffect->mColor.r,
|
||||
solidColorEffect->mColor.g,
|
||||
solidColorEffect->mColor.b,
|
||||
solidColorEffect->mColor.a);
|
||||
SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight);
|
||||
}
|
||||
break;
|
||||
case EffectTypes::COMPONENT_ALPHA:
|
||||
case EffectTypes::RENDER_TARGET:
|
||||
default:
|
||||
break;
|
||||
case EffectTypes::RGB: {
|
||||
const TexturedEffect* texturedEffect =
|
||||
static_cast<const TexturedEffect*>(primaryEffect);
|
||||
SendTexturedEffect(aGLContext, aEffectChain.mLayerRef, texturedEffect);
|
||||
break;
|
||||
}
|
||||
case EffectTypes::YCBCR: {
|
||||
const EffectYCbCr* yCbCrEffect =
|
||||
static_cast<const EffectYCbCr*>(primaryEffect);
|
||||
SendYCbCrEffect(aGLContext, aEffectChain.mLayerRef, yCbCrEffect);
|
||||
break;
|
||||
}
|
||||
case EffectTypes::SOLID_COLOR: {
|
||||
const EffectSolidColor* solidColorEffect =
|
||||
static_cast<const EffectSolidColor*>(primaryEffect);
|
||||
gfxRGBA color(solidColorEffect->mColor.r,
|
||||
solidColorEffect->mColor.g,
|
||||
solidColorEffect->mColor.b,
|
||||
solidColorEffect->mColor.a);
|
||||
SendColor(aEffectChain.mLayerRef, color, aWidth, aHeight);
|
||||
break;
|
||||
}
|
||||
case EffectTypes::COMPONENT_ALPHA:
|
||||
case EffectTypes::RENDER_TARGET:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
//const Effect* secondaryEffect = aEffectChain.mSecondaryEffects[EffectTypes::MASK];
|
||||
// TODO:
|
||||
}
|
||||
|
||||
// ----------------------------------------------
|
||||
// LayerScopeWebSocketManager implementation
|
||||
// ----------------------------------------------
|
||||
LayerScopeWebSocketManager::LayerScopeWebSocketManager()
|
||||
{
|
||||
NS_NewThread(getter_AddRefs(mDebugSenderThread));
|
||||
@ -832,7 +901,8 @@ LayerScopeWebSocketManager::~LayerScopeWebSocketManager()
|
||||
{
|
||||
}
|
||||
|
||||
void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
|
||||
void
|
||||
LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
|
||||
{
|
||||
if (!mCurrentSender) {
|
||||
mCurrentSender = new DebugDataSender();
|
||||
@ -841,11 +911,125 @@ void LayerScopeWebSocketManager::AppendDebugData(DebugGLData *aDebugData)
|
||||
mCurrentSender->Append(aDebugData);
|
||||
}
|
||||
|
||||
void LayerScopeWebSocketManager::DispatchDebugData()
|
||||
void
|
||||
LayerScopeWebSocketManager::CleanDebugData()
|
||||
{
|
||||
if (mCurrentSender) {
|
||||
mCurrentSender->Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LayerScopeWebSocketManager::DispatchDebugData()
|
||||
{
|
||||
mDebugSenderThread->Dispatch(mCurrentSender, NS_DISPATCH_NORMAL);
|
||||
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 */
|
||||
} /* mozilla */
|
||||
|
@ -17,16 +17,32 @@ namespace gl { class GLContext; }
|
||||
namespace layers {
|
||||
|
||||
struct EffectChain;
|
||||
class LayerComposite;
|
||||
|
||||
class LayerScope {
|
||||
public:
|
||||
static void CreateServerSocket();
|
||||
static void DestroyServerSocket();
|
||||
static void BeginFrame(gl::GLContext* aGLContext, int64_t aFrameStamp);
|
||||
static void EndFrame(gl::GLContext* aGLContext);
|
||||
static void Init();
|
||||
static void DeInit();
|
||||
static void SendEffectChain(gl::GLContext* aGLContext,
|
||||
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 */
|
||||
|
@ -87,18 +87,6 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
}
|
||||
#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);
|
||||
AddBlendModeEffect(effectChain);
|
||||
|
||||
@ -108,7 +96,7 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
mImageHost->Composite(effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransform(),
|
||||
gfx::ToFilter(filter),
|
||||
GetEffectFilter(),
|
||||
clipRect);
|
||||
mImageHost->BumpFlashCounter();
|
||||
}
|
||||
@ -132,6 +120,30 @@ CanvasLayerComposite::CleanupResources()
|
||||
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
|
||||
CanvasLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
|
@ -52,6 +52,8 @@ public:
|
||||
|
||||
virtual void CleanupResources() MOZ_OVERRIDE;
|
||||
|
||||
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
|
||||
|
||||
CompositableHost* GetCompositableHost() MOZ_OVERRIDE;
|
||||
|
||||
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
|
||||
@ -63,6 +65,9 @@ public:
|
||||
protected:
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
gfx::Filter GetEffectFilter();
|
||||
|
||||
private:
|
||||
RefPtr<CompositableHost> mImageHost;
|
||||
};
|
||||
|
@ -24,11 +24,9 @@ void
|
||||
ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
{
|
||||
EffectChain effects(this);
|
||||
gfxRGBA color(GetColor());
|
||||
effects.mPrimaryEffect = new EffectSolidColor(gfx::Color(color.r,
|
||||
color.g,
|
||||
color.b,
|
||||
color.a));
|
||||
|
||||
GenEffectChain(effects);
|
||||
|
||||
nsIntRect boundRect = GetBounds();
|
||||
|
||||
LayerManagerComposite::AutoAddMaskEffect autoMaskEffect(GetMaskLayer(),
|
||||
@ -50,5 +48,16 @@ ColorLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
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 */
|
||||
} /* mozilla */
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
virtual void RenderLayer(const nsIntRect& aClipRect) MOZ_OVERRIDE;
|
||||
virtual void CleanupResources() MOZ_OVERRIDE {};
|
||||
|
||||
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
|
||||
|
||||
CompositableHost* GetCompositableHost() MOZ_OVERRIDE { return nullptr; }
|
||||
|
||||
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/gfx/Types.h" // for Filter
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#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/TextureHost.h" // for TextureHost
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
@ -289,6 +290,14 @@ public:
|
||||
|
||||
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:
|
||||
TextureInfo mTextureInfo;
|
||||
uint64_t mAsyncID;
|
||||
@ -301,6 +310,29 @@ protected:
|
||||
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.
|
||||
*
|
||||
|
@ -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
|
||||
ContentHostBase::Composite(EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
@ -67,7 +46,7 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
|
||||
{
|
||||
NS_ASSERTION(aVisibleRegion, "Requires a visible region");
|
||||
|
||||
AutoLockContentHost lock(this);
|
||||
AutoLockCompositableHost lock(this);
|
||||
if (lock.Failed()) {
|
||||
return;
|
||||
}
|
||||
@ -78,9 +57,8 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
RefPtr<TexturedEffect> effect =
|
||||
CreateTexturedEffect(source, sourceOnWhite, aFilter, true);
|
||||
|
||||
RefPtr<TexturedEffect> effect = GenEffect(aFilter);
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
@ -229,6 +207,16 @@ ContentHostBase::Composite(EffectChain& aEffectChain,
|
||||
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
|
||||
ContentHostTexture::UseTextureHost(TextureHost* aTexture)
|
||||
|
@ -102,12 +102,11 @@ public:
|
||||
|
||||
virtual void SetPaintWillResample(bool aResample) { mPaintWillResample = aResample; }
|
||||
|
||||
virtual bool Lock() = 0;
|
||||
virtual void Unlock() = 0;
|
||||
|
||||
virtual NewTextureSource* GetTextureSource() = 0;
|
||||
virtual NewTextureSource* GetTextureSourceOnWhite() = 0;
|
||||
|
||||
virtual TemporaryRef<TexturedEffect> GenEffect(const gfx::Filter& aFilter) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual nsIntPoint GetOriginOffset()
|
||||
{
|
||||
@ -150,7 +149,7 @@ public:
|
||||
virtual void UseComponentAlphaTextures(TextureHost* aTextureOnBlack,
|
||||
TextureHost* aTextureOnWhite) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool Lock() {
|
||||
virtual bool Lock() MOZ_OVERRIDE {
|
||||
MOZ_ASSERT(!mLocked);
|
||||
if (!mTextureHost) {
|
||||
return false;
|
||||
@ -166,7 +165,7 @@ public:
|
||||
mLocked = true;
|
||||
return true;
|
||||
}
|
||||
virtual void Unlock() {
|
||||
virtual void Unlock() MOZ_OVERRIDE {
|
||||
MOZ_ASSERT(mLocked);
|
||||
mTextureHost->Unlock();
|
||||
if (mTextureHostOnWhite) {
|
||||
@ -175,11 +174,11 @@ public:
|
||||
mLocked = false;
|
||||
}
|
||||
|
||||
virtual NewTextureSource* GetTextureSource() {
|
||||
virtual NewTextureSource* GetTextureSource() MOZ_OVERRIDE {
|
||||
MOZ_ASSERT(mLocked);
|
||||
return mTextureHost->GetTextureSources();
|
||||
}
|
||||
virtual NewTextureSource* GetTextureSourceOnWhite() {
|
||||
virtual NewTextureSource* GetTextureSourceOnWhite() MOZ_OVERRIDE {
|
||||
MOZ_ASSERT(mLocked);
|
||||
if (mTextureHostOnWhite) {
|
||||
return mTextureHostOnWhite->GetTextureSources();
|
||||
@ -281,20 +280,20 @@ public:
|
||||
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool Lock() {
|
||||
virtual bool Lock() MOZ_OVERRIDE {
|
||||
MOZ_ASSERT(!mLocked);
|
||||
ProcessTextureUpdates();
|
||||
mLocked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Unlock() {
|
||||
virtual void Unlock() MOZ_OVERRIDE {
|
||||
MOZ_ASSERT(mLocked);
|
||||
mLocked = false;
|
||||
}
|
||||
|
||||
virtual NewTextureSource* GetTextureSource();
|
||||
virtual NewTextureSource* GetTextureSourceOnWhite();
|
||||
virtual NewTextureSource* GetTextureSource() MOZ_OVERRIDE;
|
||||
virtual NewTextureSource* GetTextureSourceOnWhite() MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -31,6 +31,7 @@ ImageHost::ImageHost(const TextureInfo& aTextureInfo)
|
||||
: CompositableHost(aTextureInfo)
|
||||
, mFrontBuffer(nullptr)
|
||||
, mHasPictureRect(false)
|
||||
, mLocked(false)
|
||||
{}
|
||||
|
||||
ImageHost::~ImageHost() {}
|
||||
@ -81,24 +82,17 @@ ImageHost::Composite(EffectChain& aEffectChain,
|
||||
mFrontBuffer->SetCompositor(GetCompositor());
|
||||
mFrontBuffer->SetCompositableBackendSpecificData(GetCompositableBackendSpecificData());
|
||||
|
||||
AutoLockTextureHost autoLock(mFrontBuffer);
|
||||
AutoLockCompositableHost autoLock(this);
|
||||
if (autoLock.Failed()) {
|
||||
NS_WARNING("failed to lock front buffer");
|
||||
return;
|
||||
}
|
||||
RefPtr<NewTextureSource> source = mFrontBuffer->GetTextureSources();
|
||||
RefPtr<NewTextureSource> source = GetTextureSource();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool isAlphaPremultiplied = true;
|
||||
if (mFrontBuffer->GetFlags() & TextureFlags::NON_PREMULTIPLIED)
|
||||
isAlphaPremultiplied = false;
|
||||
|
||||
RefPtr<TexturedEffect> effect = CreateTexturedEffect(mFrontBuffer->GetFormat(),
|
||||
source,
|
||||
aFilter,
|
||||
isAlphaPremultiplied);
|
||||
RefPtr<TexturedEffect> effect = GenEffect(aFilter);
|
||||
if (!effect) {
|
||||
return;
|
||||
}
|
||||
@ -243,5 +237,48 @@ ImageHost::GetAsSurface()
|
||||
}
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -79,11 +79,20 @@ public:
|
||||
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE;
|
||||
#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:
|
||||
|
||||
RefPtr<TextureHost> mFrontBuffer;
|
||||
nsIntRect mPictureRect;
|
||||
bool mHasPictureRect;
|
||||
bool mLocked;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
mImageHost->Composite(effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransform(),
|
||||
gfx::ToFilter(mFilter),
|
||||
GetEffectFilter(),
|
||||
clipRect);
|
||||
mImageHost->BumpFlashCounter();
|
||||
}
|
||||
@ -161,6 +161,19 @@ ImageLayerComposite::CleanupResources()
|
||||
mImageHost = nullptr;
|
||||
}
|
||||
|
||||
gfx::Filter
|
||||
ImageLayerComposite::GetEffectFilter()
|
||||
{
|
||||
return gfx::ToFilter(mFilter);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLayerComposite::GenEffectChain(EffectChain& aEffect)
|
||||
{
|
||||
aEffect.mLayerRef = this;
|
||||
aEffect.mPrimaryEffect = mImageHost->GenEffect(GetEffectFilter());
|
||||
}
|
||||
|
||||
void
|
||||
ImageLayerComposite::PrintInfo(std::stringstream& aStream, const char* aPrefix)
|
||||
{
|
||||
|
@ -51,6 +51,8 @@ public:
|
||||
|
||||
CompositableHost* GetCompositableHost() MOZ_OVERRIDE;
|
||||
|
||||
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
|
||||
|
||||
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
|
||||
|
||||
virtual const char* Name() const { return "ImageLayerComposite"; }
|
||||
@ -58,6 +60,9 @@ public:
|
||||
protected:
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
gfx::Filter GetEffectFilter();
|
||||
|
||||
private:
|
||||
RefPtr<CompositableHost> mImageHost;
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "GeckoProfiler.h" // for profiler_set_frame_number, etc
|
||||
#include "ImageLayerComposite.h" // for ImageLayerComposite
|
||||
#include "Layers.h" // for Layer, ContainerLayer, etc
|
||||
#include "LayerScope.h" // for LayerScope Tool
|
||||
#include "ThebesLayerComposite.h" // for ThebesLayerComposite
|
||||
#include "TiledLayerBuffer.h" // for TiledLayerComposer
|
||||
#include "Units.h" // for ScreenIntRect
|
||||
@ -417,6 +418,9 @@ LayerManagerComposite::Render()
|
||||
/** Our more efficient but less powerful alter ego, if one is available. */
|
||||
nsRefPtr<Composer2D> composer2D = mCompositor->GetWidget()->GetComposer2D();
|
||||
|
||||
// Set LayerScope begin/end frame
|
||||
LayerScopeAutoFrame frame(PR_Now());
|
||||
|
||||
if (!mTarget && composer2D && composer2D->TryRender(mRoot, mWorldMatrix, mGeometryChanged)) {
|
||||
if (mFPS) {
|
||||
double fps = mFPS->mCompositionFps.AddFrameAndGetFps(TimeStamp::Now());
|
||||
|
@ -336,11 +336,12 @@ public:
|
||||
|
||||
virtual TiledLayerComposer* GetTiledLayerComposer() { return nullptr; }
|
||||
|
||||
|
||||
virtual void DestroyFrontBuffer() { }
|
||||
|
||||
void AddBlendModeEffect(EffectChain& aEffectChain);
|
||||
|
||||
virtual void GenEffectChain(EffectChain& aEffect) { }
|
||||
|
||||
/**
|
||||
* The following methods are
|
||||
*
|
||||
|
@ -147,7 +147,7 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
|
||||
mBuffer->Composite(effectChain,
|
||||
GetEffectiveOpacity(),
|
||||
GetEffectiveTransform(),
|
||||
gfx::Filter::LINEAR,
|
||||
GetEffectFilter(),
|
||||
clipRect,
|
||||
&visibleRegion,
|
||||
mRequiresTiledProperties ? &tiledLayerProps
|
||||
@ -180,6 +180,13 @@ ThebesLayerComposite::CleanupResources()
|
||||
mBuffer = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ThebesLayerComposite::GenEffectChain(EffectChain& aEffect)
|
||||
{
|
||||
aEffect.mLayerRef = this;
|
||||
aEffect.mPrimaryEffect = mBuffer->GenEffect(GetEffectFilter());
|
||||
}
|
||||
|
||||
CSSToScreenScale
|
||||
ThebesLayerComposite::GetEffectiveResolution()
|
||||
{
|
||||
|
@ -56,6 +56,8 @@ public:
|
||||
|
||||
virtual void CleanupResources() MOZ_OVERRIDE;
|
||||
|
||||
virtual void GenEffectChain(EffectChain& aEffect) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool SetCompositableHost(CompositableHost* aHost) MOZ_OVERRIDE;
|
||||
|
||||
virtual LayerComposite* AsLayerComposite() MOZ_OVERRIDE { return this; }
|
||||
@ -81,8 +83,11 @@ protected:
|
||||
virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
gfx::Filter GetEffectFilter() { return gfx::Filter::LINEAR; }
|
||||
|
||||
CSSToScreenScale GetEffectiveResolution();
|
||||
|
||||
private:
|
||||
RefPtr<ContentHost> mBuffer;
|
||||
bool mRequiresTiledProperties;
|
||||
};
|
||||
|
@ -706,8 +706,6 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||
|
||||
MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame");
|
||||
|
||||
LayerScope::BeginFrame(mGLContext, PR_Now());
|
||||
|
||||
mFrameInProgress = true;
|
||||
gfx::Rect rect;
|
||||
if (mUseExternalSurfaceSize) {
|
||||
@ -1313,8 +1311,6 @@ CompositorOGL::EndFrame()
|
||||
|
||||
mFrameInProgress = false;
|
||||
|
||||
LayerScope::EndFrame(mGLContext);
|
||||
|
||||
if (mTarget) {
|
||||
CopyToTarget(mTarget, mTargetBounds.TopLeft(), mCurrentRenderTarget->GetTransform());
|
||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||
|
@ -37,11 +37,6 @@ class PBackgroundChild;
|
||||
// (assuming success) GetForCurrentThread() will return the same actor every
|
||||
// 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
|
||||
// automatically destroyed when its designated thread completes.
|
||||
class BackgroundChild MOZ_FINAL
|
||||
@ -61,10 +56,6 @@ public:
|
||||
static bool
|
||||
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
|
||||
|
||||
// See above.
|
||||
static void
|
||||
CloseForCurrentThread();
|
||||
|
||||
private:
|
||||
// Only called by ContentChild or ContentParent.
|
||||
static void
|
||||
|
@ -350,8 +350,6 @@ class ChildImpl MOZ_FINAL : public BackgroundChildImpl
|
||||
nsIThread* mBoundThread;
|
||||
#endif
|
||||
|
||||
DebugOnly<bool> mActorDestroyed;
|
||||
|
||||
public:
|
||||
static bool
|
||||
OpenProtocolOnMainThread(nsIEventTarget* aEventTarget);
|
||||
@ -374,15 +372,8 @@ public:
|
||||
THREADSAFETY_ASSERT(current);
|
||||
}
|
||||
|
||||
void
|
||||
AssertActorDestroyed()
|
||||
{
|
||||
MOZ_ASSERT(mActorDestroyed, "ChildImpl::ActorDestroy not called in time");
|
||||
}
|
||||
|
||||
ChildImpl()
|
||||
: mBoundThread(nullptr)
|
||||
, mActorDestroyed(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
@ -406,10 +397,6 @@ private:
|
||||
static bool
|
||||
GetOrCreateForCurrentThread(nsIIPCBackgroundChildCreateCallback* aCallback);
|
||||
|
||||
// Forwarded from BackgroundChild.
|
||||
static void
|
||||
CloseForCurrentThread();
|
||||
|
||||
// Forwarded from BackgroundChildImpl.
|
||||
static BackgroundChildImpl::ThreadLocal*
|
||||
GetThreadLocalForCurrentThread();
|
||||
@ -422,17 +409,6 @@ private:
|
||||
if (threadLocalInfo) {
|
||||
if (threadLocalInfo->mActor) {
|
||||
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;
|
||||
}
|
||||
@ -443,9 +419,7 @@ private:
|
||||
|
||||
// This class is reference counted.
|
||||
~ChildImpl()
|
||||
{
|
||||
AssertActorDestroyed();
|
||||
}
|
||||
{ }
|
||||
|
||||
void
|
||||
SetBoundThread()
|
||||
@ -861,13 +835,6 @@ BackgroundChild::GetOrCreateForCurrentThread(
|
||||
return ChildImpl::GetOrCreateForCurrentThread(aCallback);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
BackgroundChild::CloseForCurrentThread()
|
||||
{
|
||||
ChildImpl::CloseForCurrentThread();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// BackgroundChildImpl Public Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -1611,11 +1578,7 @@ ChildImpl::GetForCurrentThread()
|
||||
auto threadLocalInfo =
|
||||
static_cast<ThreadLocalInfo*>(PR_GetThreadPrivate(sThreadLocalIndex));
|
||||
|
||||
if (!threadLocalInfo) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return threadLocalInfo->mActor;
|
||||
return threadLocalInfo ? threadLocalInfo->mActor : nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
@ -1679,31 +1642,6 @@ ChildImpl::GetOrCreateForCurrentThread(
|
||||
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
|
||||
BackgroundChildImpl::ThreadLocal*
|
||||
ChildImpl::GetThreadLocalForCurrentThread()
|
||||
@ -2008,7 +1946,6 @@ ChildImpl::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
AssertIsOnBoundThread();
|
||||
|
||||
mActorDestroyed = true;
|
||||
BackgroundChildImpl::ActorDestroy(aWhy);
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,11 @@
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsICancelableRunnable.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/scoped_nsautorelease_pool.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDebug.h"
|
||||
@ -42,14 +40,12 @@ static mozilla::DebugOnly<MessagePump::Delegate*> gFirstDelegate;
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class DoWorkRunnable MOZ_FINAL : public nsICancelableRunnable,
|
||||
class DoWorkRunnable MOZ_FINAL : public nsIRunnable,
|
||||
public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
DoWorkRunnable(MessagePump* aPump)
|
||||
: mPump(aPump)
|
||||
, mCanceled(false)
|
||||
, mCallingRunWhileCanceled(false)
|
||||
{
|
||||
MOZ_ASSERT(aPump);
|
||||
}
|
||||
@ -57,15 +53,12 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
NS_DECL_NSICANCELABLERUNNABLE
|
||||
|
||||
private:
|
||||
~DoWorkRunnable()
|
||||
{ }
|
||||
|
||||
MessagePump* mPump;
|
||||
bool mCanceled;
|
||||
bool mCallingRunWhileCanceled;
|
||||
};
|
||||
|
||||
} /* namespace ipc */
|
||||
@ -218,17 +211,11 @@ MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate)
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback,
|
||||
nsICancelableRunnable)
|
||||
NS_IMPL_ISUPPORTS(DoWorkRunnable, nsIRunnable, nsITimerCallback)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DoWorkRunnable::Run()
|
||||
{
|
||||
MOZ_ASSERT(!mCanceled || mCallingRunWhileCanceled);
|
||||
if (mCanceled && !mCallingRunWhileCanceled) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MessageLoop* loop = MessageLoop::current();
|
||||
MOZ_ASSERT(loop);
|
||||
|
||||
@ -255,23 +242,6 @@ DoWorkRunnable::Notify(nsITimer* aTimer)
|
||||
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
|
||||
MessagePumpForChildProcess::Run(base::MessagePump::Delegate* aDelegate)
|
||||
{
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "nsStyleUtil.h"
|
||||
#include "mozilla/css/Declaration.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
#include "mozilla/dom/CSSStyleDeclarationBinding.h"
|
||||
#include "StyleRule.h"
|
||||
@ -1408,52 +1407,6 @@ AppendSerializedFontSrc(const nsCSSValue& src, nsAString & aResult)
|
||||
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.
|
||||
nsCSSValue nsCSSFontFaceStyleDecl::* const
|
||||
nsCSSFontFaceStyleDecl::Fields[] = {
|
||||
@ -1539,7 +1492,7 @@ nsCSSFontFaceStyleDecl::GetPropertyValue(nsCSSFontDesc aFontDescID,
|
||||
return NS_OK;
|
||||
|
||||
case eCSSFontDesc_UnicodeRange:
|
||||
AppendSerializedUnicodeRange(val, aResult);
|
||||
nsStyleUtil::AppendUnicodeRange(val, aResult);
|
||||
return NS_OK;
|
||||
|
||||
case eCSSFontDesc_UNKNOWN:
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
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
|
||||
nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha)
|
||||
{
|
||||
|
@ -64,6 +64,8 @@ public:
|
||||
static void AppendFontFeatureSettings(const nsCSSValue& src,
|
||||
nsAString& aResult);
|
||||
|
||||
static void AppendUnicodeRange(const nsCSSValue& aValue, nsAString& aResult);
|
||||
|
||||
static void AppendCSSNumber(float aNumber, nsAString& aResult)
|
||||
{
|
||||
aResult.AppendFloat(aNumber);
|
||||
|
@ -290,7 +290,9 @@
|
||||
</intent-filter>
|
||||
</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>
|
||||
<action android:name="com.android.vending.INSTALL_REFERRER" />
|
||||
</intent-filter>
|
||||
|
@ -200,6 +200,13 @@ public final class GeckoProfile {
|
||||
getGuestDir(context).mkdir();
|
||||
GeckoProfile profile = getGuestProfile(context);
|
||||
profile.lock();
|
||||
|
||||
/*
|
||||
* Now do the things that createProfileDirectory normally does --
|
||||
* right now that's kicking off DB init.
|
||||
*/
|
||||
profile.enqueueInitialization();
|
||||
|
||||
return profile;
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, "Error creating guest profile", ex);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -5,12 +5,19 @@
|
||||
|
||||
package org.mozilla.gecko.distribution;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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.Enumeration;
|
||||
import java.util.HashMap;
|
||||
@ -19,34 +26,95 @@ import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import org.apache.http.protocol.HTTP;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.GeckoEvent;
|
||||
import org.mozilla.gecko.GeckoSharedPrefs;
|
||||
import org.mozilla.gecko.Telemetry;
|
||||
import org.mozilla.gecko.mozglue.RobocopTarget;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Handles distribution file loading and fetching,
|
||||
* and the corresponding hand-offs to Gecko.
|
||||
*/
|
||||
public final class Distribution {
|
||||
@RobocopTarget
|
||||
public class Distribution {
|
||||
private static final String LOGTAG = "GeckoDistribution";
|
||||
|
||||
private static final int STATE_UNKNOWN = 0;
|
||||
private static final int STATE_NONE = 1;
|
||||
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 final Context context;
|
||||
@ -70,6 +138,7 @@ public final class Distribution {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
public static class DistributionDescriptor {
|
||||
public final boolean valid;
|
||||
public final String id;
|
||||
@ -140,6 +209,7 @@ public final class Distribution {
|
||||
* Use <code>Context.getPackageResourcePath</code> to find an implicit
|
||||
* package path. Reuses the existing Distribution if one exists.
|
||||
*/
|
||||
@RobocopTarget
|
||||
public static void init(final Context context) {
|
||||
Distribution.init(Distribution.getInstance(context));
|
||||
}
|
||||
@ -166,6 +236,17 @@ public final class Distribution {
|
||||
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.
|
||||
*
|
||||
@ -214,9 +295,11 @@ public final class Distribution {
|
||||
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "Error getting distribution descriptor file.", e);
|
||||
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
|
||||
return null;
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Error parsing preferences.json", e);
|
||||
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -232,11 +315,13 @@ public final class Distribution {
|
||||
return new JSONArray(getFileContents(bookmarks));
|
||||
} catch (IOException e) {
|
||||
Log.e(LOGTAG, "Error getting bookmarks", e);
|
||||
Telemetry.HistogramAdd(HISTOGRAM_CODE_CATEGORY, CODE_CATEGORY_MALFORMED_DISTRIBUTION);
|
||||
return null;
|
||||
} catch (JSONException 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
|
||||
* set and populated.
|
||||
*
|
||||
* This method is *only* protected for use from testDistribution.
|
||||
*
|
||||
* @return true if we've set a distribution.
|
||||
*/
|
||||
private boolean doInit() {
|
||||
@RobocopTarget
|
||||
protected boolean doInit() {
|
||||
ThreadUtils.assertNotOnUiThread();
|
||||
|
||||
// Bail if we've already tried to initialize the distribution, and
|
||||
@ -274,8 +362,9 @@ public final class Distribution {
|
||||
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 =
|
||||
checkIntentDistribution() ||
|
||||
checkAPKDistribution() ||
|
||||
checkSystemDistribution();
|
||||
|
||||
@ -286,6 +375,153 @@ public final class Distribution {
|
||||
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
|
||||
* 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
|
||||
// a 'distribution' subdirectory. Track our dist dir now that
|
||||
// we know it.
|
||||
this.distributionDir = new File(getDataDir(), "distribution/");
|
||||
this.distributionDir = new File(getDataDir(), DISTRIBUTION_PATH);
|
||||
return true;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
@ -330,6 +566,41 @@ public final class Distribution {
|
||||
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.
|
||||
* Returns true if distribution files were found and copied.
|
||||
@ -352,7 +623,7 @@ public final class Distribution {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!name.startsWith("distribution/")) {
|
||||
if (!name.startsWith(DISTRIBUTION_PATH)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -413,6 +684,29 @@ public final class Distribution {
|
||||
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>
|
||||
* 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/.
|
||||
// Look in each location in turn.
|
||||
// (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()) {
|
||||
return this.distributionDir = copied;
|
||||
}
|
||||
|
55
mobile/android/base/distribution/ReferrerDescriptor.java
Normal file
55
mobile/android/base/distribution/ReferrerDescriptor.java
Normal 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 + "}";
|
||||
}
|
||||
}
|
76
mobile/android/base/distribution/ReferrerReceiver.java
Normal file
76
mobile/android/base/distribution/ReferrerReceiver.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -156,6 +156,8 @@ gbjar.sources += [
|
||||
'db/TabsProvider.java',
|
||||
'db/TopSitesCursorWrapper.java',
|
||||
'distribution/Distribution.java',
|
||||
'distribution/ReferrerDescriptor.java',
|
||||
'distribution/ReferrerReceiver.java',
|
||||
'DoorHangerPopup.java',
|
||||
'DynamicToolbar.java',
|
||||
'EditBookmarkDialog.java',
|
||||
@ -354,7 +356,6 @@ gbjar.sources += [
|
||||
'prompts/PromptService.java',
|
||||
'prompts/TabInput.java',
|
||||
'ReaderModeUtils.java',
|
||||
'ReferrerReceiver.java',
|
||||
'Restarter.java',
|
||||
'ScrollAnimator.java',
|
||||
'ServiceNotificationClient.java',
|
||||
|
@ -2,19 +2,29 @@ package org.mozilla.gecko.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.util.jar.JarInputStream;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.Actions;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
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 android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Tests distribution customization.
|
||||
@ -28,6 +38,38 @@ import android.content.SharedPreferences;
|
||||
* engine.xml
|
||||
*/
|
||||
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 int PREF_REQUEST_ID = 0x7357;
|
||||
|
||||
@ -65,7 +107,7 @@ public class testDistribution extends ContentProviderTest {
|
||||
mAsserter.dumpLog("Background task completed. Proceeding.");
|
||||
}
|
||||
|
||||
public void testDistribution() {
|
||||
public void testDistribution() throws Exception {
|
||||
mActivity = getActivity();
|
||||
|
||||
String mockPackagePath = getMockPackagePath();
|
||||
@ -87,6 +129,90 @@ public class testDistribution extends ContentProviderTest {
|
||||
setTestLocale("es-MX");
|
||||
initDistribution(mockPackagePath);
|
||||
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.
|
||||
@ -288,12 +414,16 @@ public class testDistribution extends ContentProviderTest {
|
||||
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() {
|
||||
mAsserter.dumpLog("Clearing distribution pref.");
|
||||
SharedPreferences settings = mActivity.getSharedPreferences("GeckoApp", Activity.MODE_PRIVATE);
|
||||
String keyName = mActivity.getPackageName() + ".distribution_state";
|
||||
settings.edit().remove(keyName).commit();
|
||||
TestableDistribution.clearReferrerDescriptorForTesting();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,6 +11,7 @@ jar.sources += [
|
||||
'src/harness/BrowserInstrumentationTestRunner.java',
|
||||
'src/harness/BrowserTestListener.java',
|
||||
'src/tests/BrowserTestCase.java',
|
||||
'src/tests/TestDistribution.java',
|
||||
'src/tests/TestGeckoSharedPrefs.java',
|
||||
'src/tests/TestJarReader.java',
|
||||
'src/tests/TestRawResource.java',
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -569,7 +569,7 @@ VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
|
||||
NS_IMETHODIMP
|
||||
OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile,
|
||||
/*out, optional */ nsIZipReader** aZipReader,
|
||||
/*out, optional */ nsIX509Cert3** aSignerCert)
|
||||
/*out, optional */ nsIX509Cert** aSignerCert)
|
||||
{
|
||||
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.
|
||||
if (aSignerCert) {
|
||||
MOZ_ASSERT(CERT_LIST_HEAD(builtChain));
|
||||
nsCOMPtr<nsIX509Cert3> signerCert =
|
||||
nsCOMPtr<nsIX509Cert> signerCert =
|
||||
nsNSSCertificate::Create(CERT_LIST_HEAD(builtChain)->cert);
|
||||
NS_ENSURE_TRUE(signerCert, NS_ERROR_OUT_OF_MEMORY);
|
||||
signerCert.forget(aSignerCert);
|
||||
@ -769,7 +769,7 @@ private:
|
||||
const nsCOMPtr<nsIFile> mJarFile;
|
||||
nsMainThreadPtrHandle<nsIOpenSignedAppFileCallback> mCallback;
|
||||
nsCOMPtr<nsIZipReader> mZipReader; // out
|
||||
nsCOMPtr<nsIX509Cert3> mSignerCert; // out
|
||||
nsCOMPtr<nsIX509Cert> mSignerCert; // out
|
||||
};
|
||||
|
||||
} // unnamed namespace
|
||||
|
@ -43,7 +43,6 @@ function getDERString(cert)
|
||||
function getPKCS7String(cert, chainMode)
|
||||
{
|
||||
var length = {};
|
||||
cert.QueryInterface(Components.interfaces.nsIX509Cert3);
|
||||
var pkcs7Array = cert.exportAsCMS(chainMode, length);
|
||||
var pkcs7String = '';
|
||||
for (var i = 0; i < pkcs7Array.length; i++) {
|
||||
@ -110,10 +109,10 @@ function exportToFile(parent, cert)
|
||||
content = getDERString(cert);
|
||||
break;
|
||||
case 3:
|
||||
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert3.CMS_CHAIN_MODE_CertOnly);
|
||||
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert.CMS_CHAIN_MODE_CertOnly);
|
||||
break;
|
||||
case 4:
|
||||
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert3.CMS_CHAIN_MODE_CertChainWithRoot);
|
||||
content = getPKCS7String(cert, Components.interfaces.nsIX509Cert.CMS_CHAIN_MODE_CertChainWithRoot);
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
|
@ -3,7 +3,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const nsIX509Cert = Components.interfaces.nsIX509Cert;
|
||||
const nsIX509Cert3 = Components.interfaces.nsIX509Cert3;
|
||||
const nsX509CertDB = "@mozilla.org/security/x509certdb;1";
|
||||
const nsIX509CertDB = Components.interfaces.nsIX509CertDB;
|
||||
const nsPK11TokenDB = "@mozilla.org/security/pk11tokendb;1";
|
||||
@ -94,14 +93,9 @@ function setWindowName()
|
||||
AddCertChain("treesetDump", chain, "dump_");
|
||||
DisplayGeneralDataFromCert(cert);
|
||||
BuildPrettyPrint(cert);
|
||||
|
||||
if (cert instanceof nsIX509Cert3)
|
||||
{
|
||||
cert.requestUsagesArrayAsync(new listener());
|
||||
}
|
||||
cert.requestUsagesArrayAsync(new listener());
|
||||
}
|
||||
|
||||
|
||||
function addChildrenToTree(parentTree,label,value,addTwistie)
|
||||
{
|
||||
var treeChild1 = document.createElement("treechildren");
|
||||
|
@ -39,10 +39,7 @@ XPIDL_SOURCES += [
|
||||
'nsITokenPasswordDialogs.idl',
|
||||
'nsIUserCertPicker.idl',
|
||||
'nsIX509Cert.idl',
|
||||
'nsIX509Cert2.idl',
|
||||
'nsIX509Cert3.idl',
|
||||
'nsIX509CertDB.idl',
|
||||
'nsIX509CertDB2.idl',
|
||||
'nsIX509CertList.idl',
|
||||
'nsIX509CertValidity.idl',
|
||||
]
|
||||
|
@ -23,7 +23,7 @@ interface nsISSLStatus : nsISupports {
|
||||
* "unstrusted because missing or untrusted issuer"
|
||||
* and
|
||||
* "untrusted because self signed"
|
||||
* query nsIX509Cert3::isSelfSigned
|
||||
* query nsIX509Cert::isSelfSigned
|
||||
*/
|
||||
readonly attribute boolean isUntrusted;
|
||||
|
||||
|
@ -9,11 +9,18 @@
|
||||
interface nsIArray;
|
||||
interface nsIX509CertValidity;
|
||||
interface nsIASN1Object;
|
||||
interface nsICertVerificationListener;
|
||||
|
||||
%{ C++
|
||||
/* forward declaration */
|
||||
typedef struct CERTCertificateStr CERTCertificate;
|
||||
%}
|
||||
[ptr] native CERTCertificatePtr(CERTCertificate);
|
||||
|
||||
/**
|
||||
* This represents a X.509 certificate.
|
||||
*/
|
||||
[scriptable, uuid(891d2009-b9ba-4a0d-bebe-6b3a30e33191)]
|
||||
[scriptable, uuid(f8ed8364-ced9-4c6e-86ba-48af53c393e6)]
|
||||
interface nsIX509Cert : nsISupports {
|
||||
|
||||
/**
|
||||
@ -138,6 +145,18 @@ interface nsIX509Cert : nsISupports {
|
||||
const unsigned long USER_CERT = 1 << 1;
|
||||
const unsigned long EMAIL_CERT = 1 << 2;
|
||||
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.
|
||||
@ -171,6 +190,13 @@ interface nsIX509Cert : nsISupports {
|
||||
const unsigned long CERT_USAGE_StatusResponder = 10;
|
||||
const unsigned long CERT_USAGE_AnyCA = 11;
|
||||
|
||||
/**
|
||||
* 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,
|
||||
@ -195,6 +221,14 @@ interface nsIX509Cert : nsISupports {
|
||||
out uint32_t count,
|
||||
[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
|
||||
* the certificate's certified usages.
|
||||
@ -236,4 +270,81 @@ interface nsIX509Cert : nsISupports {
|
||||
* digest.
|
||||
*/
|
||||
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);
|
||||
};
|
||||
|
@ -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();
|
||||
};
|
@ -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);
|
||||
};
|
@ -8,7 +8,6 @@
|
||||
|
||||
interface nsIArray;
|
||||
interface nsIX509Cert;
|
||||
interface nsIX509Cert3;
|
||||
interface nsIFile;
|
||||
interface nsIInterfaceRequestor;
|
||||
interface nsIZipReader;
|
||||
@ -21,12 +20,12 @@ interface nsIX509CertList;
|
||||
|
||||
typedef uint32_t AppTrustedRoot;
|
||||
|
||||
[scriptable, function, uuid(0927baea-622d-4e41-a76d-255af426e7fb)]
|
||||
[scriptable, function, uuid(5984db62-d0e5-4671-a082-799cf7271e24)]
|
||||
interface nsIOpenSignedAppFileCallback : nsISupports
|
||||
{
|
||||
void openSignedAppFileFinished(in nsresult rv,
|
||||
in nsIZipReader aZipReader,
|
||||
in nsIX509Cert3 aSignerCert);
|
||||
in nsIX509Cert aSignerCert);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -203,7 +202,7 @@ interface nsIX509CertDB : nsISupports {
|
||||
* characters, indicating SSL, Email, and Obj signing
|
||||
* 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.
|
||||
@ -361,4 +360,20 @@ interface nsIX509CertDB : nsISupports {
|
||||
// Clears the OCSP cache for the current certificate verification
|
||||
// implementation.
|
||||
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();
|
||||
};
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -689,7 +689,6 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
|
||||
// Get the existing cert. If there isn't one, then there is
|
||||
// no cert change to worry about.
|
||||
nsCOMPtr<nsIX509Cert> cert;
|
||||
nsCOMPtr<nsIX509Cert2> cert2;
|
||||
|
||||
RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
|
||||
if (!status) {
|
||||
@ -700,10 +699,9 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
|
||||
}
|
||||
|
||||
status->GetServerCert(getter_AddRefs(cert));
|
||||
cert2 = do_QueryInterface(cert);
|
||||
if (!cert2) {
|
||||
if (!cert) {
|
||||
NS_NOTREACHED("every nsSSLStatus must have a cert"
|
||||
"that implements nsIX509Cert2");
|
||||
"that implements nsIX509Cert");
|
||||
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
@ -715,9 +713,9 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
|
||||
"GetNegotiatedNPN() failed during renegotiation");
|
||||
|
||||
if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN,
|
||||
NS_LITERAL_CSTRING("spdy/")))
|
||||
NS_LITERAL_CSTRING("spdy/"))) {
|
||||
return SECSuccess;
|
||||
|
||||
}
|
||||
// If GetNegotiatedNPN() failed we will assume spdy for safety's safe
|
||||
if (NS_FAILED(rv)) {
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
@ -726,11 +724,12 @@ BlockServerCertChangeForSpdy(nsNSSSocketInfo* infoObject,
|
||||
}
|
||||
|
||||
// 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");
|
||||
bool sameCert = CERT_CompareCerts(c, serverCert);
|
||||
if (sameCert)
|
||||
if (sameCert) {
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
// Report an error - changed cert is confirmed
|
||||
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
|
||||
|
@ -535,13 +535,9 @@ AppendErrorTextUntrusted(PRErrorCode errTrust,
|
||||
nsString &returnedMessage)
|
||||
{
|
||||
const char *errorID = nullptr;
|
||||
nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
|
||||
if (cert3) {
|
||||
bool isSelfSigned;
|
||||
if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
|
||||
&& isSelfSigned) {
|
||||
errorID = "certErrorTrust_SelfSigned";
|
||||
}
|
||||
bool isSelfSigned;
|
||||
if (NS_SUCCEEDED(ix509->GetIsSelfSigned(&isSelfSigned)) && isSelfSigned) {
|
||||
errorID = "certErrorTrust_SelfSigned";
|
||||
}
|
||||
|
||||
if (!errorID) {
|
||||
@ -690,11 +686,7 @@ AppendErrorTextMismatch(const nsString &host,
|
||||
const char16_t *params[1];
|
||||
nsresult rv;
|
||||
|
||||
mozilla::pkix::ScopedCERTCertificate nssCert;
|
||||
|
||||
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
|
||||
if (cert2)
|
||||
nssCert = cert2->GetCert();
|
||||
mozilla::pkix::ScopedCERTCertificate nssCert(ix509->GetCert());
|
||||
|
||||
if (!nssCert) {
|
||||
// We are unable to extract the valid names, say "not valid for name".
|
||||
|
@ -390,14 +390,11 @@ GetCertFingerprintByOidTag(nsIX509Cert *aCert,
|
||||
SECOidTag aOidTag,
|
||||
nsCString &fp)
|
||||
{
|
||||
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
|
||||
if (!cert2)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
|
||||
if (!nsscert)
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
|
||||
if (!nsscert) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
}
|
||||
return GetCertFingerprintByOidTag(nsscert.get(), aOidTag, fp);
|
||||
}
|
||||
|
||||
@ -428,20 +425,19 @@ GetCertFingerprintByDottedOidString(nsIX509Cert *aCert,
|
||||
const nsCString &dottedOid,
|
||||
nsCString &fp)
|
||||
{
|
||||
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
|
||||
if (!cert2)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
|
||||
if (!nsscert)
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
|
||||
if (!nsscert) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return GetCertFingerprintByDottedOidString(nsscert.get(), dottedOid, fp);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, int32_t aPort,
|
||||
nsIX509Cert *aCert,
|
||||
nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName,
|
||||
int32_t aPort,
|
||||
nsIX509Cert* aCert,
|
||||
uint32_t aOverrideBits,
|
||||
bool aTemporary)
|
||||
{
|
||||
@ -451,13 +447,10 @@ nsCertOverrideService::RememberValidityOverride(const nsACString & aHostName, in
|
||||
if (aPort < -1)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(aCert);
|
||||
if (!cert2)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(cert2->GetCert());
|
||||
if (!nsscert)
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(aCert->GetCert());
|
||||
if (!nsscert) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
char* nickname = DefaultServerNicknameForCert(nsscert.get());
|
||||
if (!aTemporary && nickname && *nickname)
|
||||
|
@ -330,7 +330,7 @@ nsCertTree::nsCertCompareFunc
|
||||
nsCertTree::GetCompareFuncFromCertType(uint32_t aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case nsIX509Cert2::ANY_CERT:
|
||||
case nsIX509Cert::ANY_CERT:
|
||||
case nsIX509Cert::USER_CERT:
|
||||
return CmpUserCert;
|
||||
case nsIX509Cert::CA_CERT:
|
||||
@ -477,7 +477,7 @@ nsCertTree::GetCertsByTypeFromCertList(CERTCertList *aCertList,
|
||||
!CERT_LIST_END(node, aCertList);
|
||||
node = CERT_LIST_NEXT(node)) {
|
||||
|
||||
bool wantThisCert = (aWantedType == nsIX509Cert2::ANY_CERT);
|
||||
bool wantThisCert = (aWantedType == nsIX509Cert::ANY_CERT);
|
||||
bool wantThisCertIfNoOverrides = false;
|
||||
bool wantThisCertIfHaveOverrides = false;
|
||||
bool addOverrides = false;
|
||||
@ -809,12 +809,7 @@ nsCertTree::DeleteEntryObject(uint32_t index)
|
||||
// although there are still overrides stored,
|
||||
// so, we keep the cert, but remove the trust
|
||||
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert;
|
||||
|
||||
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(cert);
|
||||
if (cert2) {
|
||||
nsscert = cert2->GetCert();
|
||||
}
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
|
||||
|
||||
if (nsscert) {
|
||||
CERTCertTrust trust;
|
||||
@ -1235,12 +1230,8 @@ nsCertTree::GetCellText(int32_t row, nsITreeColumn* col,
|
||||
(certdi->mIsTemporary) ? "CertExceptionTemporary" : "CertExceptionPermanent";
|
||||
rv = mNSSComponent->GetPIPNSSBundleString(stringID, _retval);
|
||||
} else if (NS_LITERAL_STRING("typecol").Equals(colID) && cert) {
|
||||
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
|
||||
uint32_t type = nsIX509Cert::UNKNOWN_CERT;
|
||||
|
||||
if (pipCert) {
|
||||
rv = pipCert->GetCertType(&type);
|
||||
}
|
||||
rv = cert->GetCertType(&type);
|
||||
|
||||
switch (type) {
|
||||
case nsIX509Cert::USER_CERT:
|
||||
|
@ -17,7 +17,7 @@ class DispatchCertVerificationResult : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DispatchCertVerificationResult(const nsMainThreadPtrHandle<nsICertVerificationListener>& aListener,
|
||||
nsIX509Cert3* aCert,
|
||||
nsIX509Cert* aCert,
|
||||
nsICertVerificationResult* aResult)
|
||||
: mListener(aListener)
|
||||
, mCert(aCert)
|
||||
@ -31,7 +31,7 @@ public:
|
||||
|
||||
private:
|
||||
nsMainThreadPtrHandle<nsICertVerificationListener> mListener;
|
||||
nsCOMPtr<nsIX509Cert3> mCert;
|
||||
nsCOMPtr<nsIX509Cert> mCert;
|
||||
nsCOMPtr<nsICertVerificationResult> mResult;
|
||||
};
|
||||
} // anonymous namespace
|
||||
@ -64,8 +64,7 @@ void nsCertVerificationJob::Run()
|
||||
ires = vres;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIX509Cert3> c3 = do_QueryInterface(mCert);
|
||||
nsCOMPtr<nsIRunnable> r = new DispatchCertVerificationResult(mListener, c3, ires);
|
||||
nsCOMPtr<nsIRunnable> r = new DispatchCertVerificationResult(mListener, mCert, ires);
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "nsPKCS12Blob.h"
|
||||
#include "nsPK11TokenDB.h"
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
#include "nsNSSASN1Object.h"
|
||||
#include "nsString.h"
|
||||
#include "nsXPIDLString.h"
|
||||
@ -68,8 +67,6 @@ NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false)
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNSSCertificate,
|
||||
nsIX509Cert,
|
||||
nsIX509Cert2,
|
||||
nsIX509Cert3,
|
||||
nsIIdentityInfo,
|
||||
nsISerializable,
|
||||
nsIClassInfo)
|
||||
@ -1141,9 +1138,9 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
switch (chainMode) {
|
||||
case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly:
|
||||
case nsIX509Cert3::CMS_CHAIN_MODE_CertChain:
|
||||
case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot:
|
||||
case nsIX509Cert::CMS_CHAIN_MODE_CertOnly:
|
||||
case nsIX509Cert::CMS_CHAIN_MODE_CertChain:
|
||||
case nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot:
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
@ -1178,15 +1175,15 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
|
||||
// Since CERT_CertChainFromCert() also includes the certificate itself,
|
||||
// we have to start at the issuing cert (to avoid duplicate certs
|
||||
// in the SignedData).
|
||||
if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain ||
|
||||
chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) {
|
||||
if (chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChain ||
|
||||
chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot) {
|
||||
ScopedCERTCertificate issuerCert(
|
||||
CERT_FindCertIssuer(mCert.get(), PR_Now(), certUsageAnyCA));
|
||||
// the issuerCert of a self signed root is the cert itself,
|
||||
// so make sure we're not adding duplicates, again
|
||||
if (issuerCert && issuerCert != mCert.get()) {
|
||||
bool includeRoot =
|
||||
(chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot);
|
||||
(chainMode == nsIX509Cert::CMS_CHAIN_MODE_CertChainWithRoot);
|
||||
ScopedCERTCertificateList certChain(
|
||||
CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot));
|
||||
if (certChain) {
|
||||
@ -1377,11 +1374,7 @@ nsNSSCertificate::Equals(nsIX509Cert* other, bool* result)
|
||||
NS_ENSURE_ARG(other);
|
||||
NS_ENSURE_ARG(result);
|
||||
|
||||
nsCOMPtr<nsIX509Cert2> other2 = do_QueryInterface(other);
|
||||
if (!other2)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
ScopedCERTCertificate cert(other2->GetCert());
|
||||
ScopedCERTCertificate cert(other->GetCert());
|
||||
*result = (mCert.get() == cert.get());
|
||||
return NS_OK;
|
||||
}
|
||||
@ -1552,10 +1545,7 @@ nsNSSCertList::AddCert(nsIX509Cert* aCert)
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
|
||||
CERTCertificate* cert;
|
||||
|
||||
cert = nssCert->GetCert();
|
||||
CERTCertificate* cert = aCert->GetCert();
|
||||
if (!cert) {
|
||||
NS_ERROR("Somehow got nullptr for mCertificate in nsNSSCertificate.");
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -1577,8 +1567,7 @@ nsNSSCertList::DeleteCert(nsIX509Cert* aCert)
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
|
||||
CERTCertificate* cert = nssCert->GetCert();
|
||||
CERTCertificate* cert = aCert->GetCert();
|
||||
CERTCertListNode* node;
|
||||
|
||||
if (!cert) {
|
||||
@ -1605,8 +1594,9 @@ CERTCertList*
|
||||
nsNSSCertList::DupCertList(CERTCertList* aCertList,
|
||||
const nsNSSShutDownPreventionLock& /*proofOfLock*/)
|
||||
{
|
||||
if (!aCertList)
|
||||
if (!aCertList) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CERTCertList* newList = CERT_NewCertList();
|
||||
|
||||
|
@ -7,8 +7,6 @@
|
||||
#define _NS_NSSCERTIFICATE_H_
|
||||
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509Cert2.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
#include "nsIX509CertDB.h"
|
||||
#include "nsIX509CertList.h"
|
||||
#include "nsIASN1Object.h"
|
||||
@ -25,7 +23,7 @@ class nsAutoString;
|
||||
class nsINSSComponent;
|
||||
class nsIASN1Sequence;
|
||||
|
||||
class nsNSSCertificate : public nsIX509Cert3,
|
||||
class nsNSSCertificate : public nsIX509Cert,
|
||||
public nsIIdentityInfo,
|
||||
public nsISerializable,
|
||||
public nsIClassInfo,
|
||||
@ -34,8 +32,6 @@ class nsNSSCertificate : public nsIX509Cert3,
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIX509CERT
|
||||
NS_DECL_NSIX509CERT2
|
||||
NS_DECL_NSIX509CERT3
|
||||
NS_DECL_NSIIDENTITYINFO
|
||||
NS_DECL_NSISERIALIZABLE
|
||||
NS_DECL_NSICLASSINFO
|
||||
|
@ -82,7 +82,7 @@ attemptToLogInWithDefaultPassword()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB, nsIX509CertDB2)
|
||||
NS_IMPL_ISUPPORTS(nsNSSCertificateDB, nsIX509CertDB)
|
||||
|
||||
nsNSSCertificateDB::nsNSSCertificateDB()
|
||||
: mBadCertsLock("nsNSSCertificateDB::mBadCertsLock")
|
||||
@ -954,14 +954,15 @@ nsNSSCertificateDB::DeleteCertificate(nsIX509Cert *aCert)
|
||||
if (isAlreadyShutDown()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
nsCOMPtr<nsIX509Cert2> nssCert = do_QueryInterface(aCert);
|
||||
mozilla::pkix::ScopedCERTCertificate cert(nssCert->GetCert());
|
||||
if (!cert) return NS_ERROR_FAILURE;
|
||||
mozilla::pkix::ScopedCERTCertificate cert(aCert->GetCert());
|
||||
if (!cert) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
SECStatus srv = SECSuccess;
|
||||
|
||||
uint32_t certType;
|
||||
nssCert->GetCertType(&certType);
|
||||
if (NS_FAILED(nssCert->MarkForPermDeletion()))
|
||||
aCert->GetCertType(&certType);
|
||||
if (NS_FAILED(aCert->MarkForPermDeletion()))
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -998,11 +999,7 @@ nsNSSCertificateDB::SetCertTrust(nsIX509Cert *cert,
|
||||
}
|
||||
nsNSSCertTrust trust;
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert, &rv);
|
||||
if (!pipCert) {
|
||||
return rv;
|
||||
}
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
|
||||
|
||||
rv = attemptToLogInWithDefaultPassword();
|
||||
if (NS_WARN_IF(rv != NS_OK)) {
|
||||
@ -1054,8 +1051,7 @@ nsNSSCertificateDB::IsCertTrusted(nsIX509Cert *cert,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
SECStatus srv;
|
||||
nsCOMPtr<nsIX509Cert2> pipCert = do_QueryInterface(cert);
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(pipCert->GetCert());
|
||||
mozilla::pkix::ScopedCERTCertificate nsscert(cert->GetCert());
|
||||
CERTCertTrust nsstrust;
|
||||
srv = CERT_GetCertTrust(nsscert.get(), &nsstrust);
|
||||
if (srv != SECSuccess)
|
||||
@ -1284,7 +1280,8 @@ finish:
|
||||
|
||||
/* nsIX509Cert getDefaultEmailEncryptionCert (); */
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509Cert **_retval)
|
||||
nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString& aNickname,
|
||||
nsIX509Cert** _retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = nullptr;
|
||||
@ -1320,7 +1317,8 @@ nsNSSCertificateDB::FindEmailEncryptionCert(const nsAString &aNickname, nsIX509C
|
||||
|
||||
/* nsIX509Cert getDefaultEmailSigningCert (); */
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificateDB::FindEmailSigningCert(const nsAString &aNickname, nsIX509Cert **_retval)
|
||||
nsNSSCertificateDB::FindEmailSigningCert(const nsAString& aNickname,
|
||||
nsIX509Cert** _retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = nullptr;
|
||||
@ -1590,14 +1588,16 @@ nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dummycert)
|
||||
if (!dummycert) {
|
||||
break;
|
||||
|
||||
}
|
||||
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);
|
||||
nsCOMPtr <nsIX509Cert> newCert;
|
||||
@ -1668,7 +1668,7 @@ nsNSSCertificateDB::AddCert(const nsACString & aCertDER, const char *aTrust,
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert3* cert,
|
||||
nsNSSCertificateDB::SetCertTrustFromString(nsIX509Cert* cert,
|
||||
const char* trustString)
|
||||
{
|
||||
CERTCertTrust trust;
|
||||
@ -1761,11 +1761,10 @@ nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert,
|
||||
EnsureIdentityInfoLoaded();
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIX509Cert2> x509Cert = do_QueryInterface(aCert);
|
||||
if (!x509Cert) {
|
||||
ScopedCERTCertificate nssCert(aCert->GetCert());
|
||||
if (!nssCert) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
ScopedCERTCertificate nssCert(x509Cert->GetCert());
|
||||
|
||||
RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
|
||||
NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE);
|
||||
|
@ -6,7 +6,6 @@
|
||||
#define __NSNSSCERTIFICATEDB_H__
|
||||
|
||||
#include "nsIX509CertDB.h"
|
||||
#include "nsIX509CertDB2.h"
|
||||
#include "nsNSSShutDown.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
@ -17,14 +16,12 @@ class nsIArray;
|
||||
class nsRecentBadCerts;
|
||||
|
||||
class nsNSSCertificateDB : public nsIX509CertDB
|
||||
, public nsIX509CertDB2
|
||||
, public nsNSSShutDownObject
|
||||
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIX509CERTDB
|
||||
NS_DECL_NSIX509CERTDB2
|
||||
|
||||
nsNSSCertificateDB();
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsString.h"
|
||||
#include "nsXPIDLString.h"
|
||||
|
||||
@ -357,3 +356,55 @@ nsNSSCertificateFakeTransport::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
|
||||
*aClassIDNoAlloc = kNSSCertificateCID;
|
||||
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;
|
||||
}
|
@ -387,16 +387,19 @@ nsNSSSocketInfo::JoinConnection(const nsACString& npnProtocol,
|
||||
|
||||
ScopedCERTCertificate nssCert;
|
||||
|
||||
nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
|
||||
if (cert2)
|
||||
nssCert = cert2->GetCert();
|
||||
nsCOMPtr<nsIX509Cert> cert(SSLStatus()->mServerCert);
|
||||
if (cert) {
|
||||
nssCert = cert->GetCert();
|
||||
}
|
||||
|
||||
if (!nssCert)
|
||||
if (!nssCert) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
|
||||
SECSuccess)
|
||||
return NS_OK;
|
||||
SECSuccess) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// All tests pass - this is joinable
|
||||
mJoined = true;
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include "nspr.h"
|
||||
|
||||
#include "nsIX509Cert.h"
|
||||
#include "nsIX509Cert3.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
class nsBaseVerificationJob
|
||||
|
@ -8,9 +8,6 @@
|
||||
do_get_profile(); // must be called before getting nsIX509CertDB
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const certdb2 = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB2);
|
||||
|
||||
// This is the list of certificates needed for the test
|
||||
// The certificates prefixed by 'int-' are intermediates
|
||||
let certList = [
|
||||
@ -29,7 +26,7 @@ function load_cert(cert_name, trust_string) {
|
||||
// the ones that I am interested in.
|
||||
function get_ca_array() {
|
||||
let ret_array = new Array();
|
||||
let allCerts = certdb2.getCerts();
|
||||
let allCerts = certdb.getCerts();
|
||||
let enumerator = allCerts.getEnumerator();
|
||||
while (enumerator.hasMoreElements()) {
|
||||
let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert);
|
||||
|
@ -25,7 +25,7 @@ let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
||||
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
let gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB2);
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
gCertDB.QueryInterface(Ci.nsIX509CertDB);
|
||||
|
||||
const BUILT_IN_NICK_PREFIX = "Builtin Object Token:";
|
||||
@ -108,8 +108,7 @@ function isBuiltinToken(tokenName) {
|
||||
}
|
||||
|
||||
function isCertBuiltIn(cert) {
|
||||
let cert3 = cert.QueryInterface(Ci.nsIX509Cert3);
|
||||
let tokenNames = cert3.getAllTokenNames({});
|
||||
let tokenNames = cert.getAllTokenNames({});
|
||||
if (!tokenNames) {
|
||||
return false;
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ SOURCES += [
|
||||
'pkix_cert_extension_tests.cpp',
|
||||
'pkix_ocsp_request_tests.cpp',
|
||||
'pkixcheck_CheckKeyUsage_tests.cpp',
|
||||
'pkixcheck_CheckTimes_tests.cpp',
|
||||
'pkixder_input_tests.cpp',
|
||||
'pkixder_pki_types_tests.cpp',
|
||||
'pkixder_universal_types_tests.cpp',
|
||||
|
174
security/pkix/test/gtest/pkixcheck_CheckTimes_tests.cpp
Normal file
174
security/pkix/test/gtest/pkixcheck_CheckTimes_tests.cpp
Normal 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));
|
||||
}
|
@ -28,9 +28,11 @@
|
||||
|
||||
#include "pkix/bind.h"
|
||||
#include "pkixder.h"
|
||||
#include "pkixtestutil.h"
|
||||
#include "stdint.h"
|
||||
|
||||
using namespace mozilla::pkix::der;
|
||||
using namespace mozilla::pkix::test;
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
@ -305,23 +307,6 @@ TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
|
||||
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
|
||||
//
|
||||
|
@ -428,6 +428,23 @@ PRTimeToTimeChoice(PLArenaPool* arena, PRTime time)
|
||||
: 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*
|
||||
SignedData(PLArenaPool* arena, const SECItem* tbsData,
|
||||
SECKEYPrivateKey* privKey, SECOidTag hashAlg,
|
||||
|
@ -62,6 +62,10 @@ FILE* OpenFile(const char* dir, const char* filename, const char* mode);
|
||||
|
||||
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,
|
||||
/*out*/ ScopedSECKEYPrivateKey& privateKey);
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
"robocop": "TIMED_OUT",
|
||||
"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/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",
|
||||
"dom/media/tests/mochitest": "Android 2.3 only; bug 981881",
|
||||
"layout/style/test/test_media_queries.html": "Android 2.3 aws only; bug 1030419",
|
||||
|
@ -537,20 +537,33 @@ class DeviceManagerSUT(DeviceManager):
|
||||
|
||||
def killProcess(self, appname, sig=None):
|
||||
if sig:
|
||||
self._logger.warn("killProcess(): sig parameter unsupported on SUT")
|
||||
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:
|
||||
pid = self.processExist(appname)
|
||||
if pid and pid > 0:
|
||||
try:
|
||||
self.shellCheckOutput(['kill', '-%d' % sig, str(pid)],
|
||||
root=True)
|
||||
except DMError, err:
|
||||
self._logger.warn("unable to kill -%d %s (pid %s)" %
|
||||
(sig, appname, str(pid)))
|
||||
self._logger.debug(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):
|
||||
return self._runCmds([{ 'cmd': 'tmpd' }]).strip()
|
||||
|
@ -2959,6 +2959,28 @@
|
||||
"extended_statistics_ok": true,
|
||||
"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": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
@ -39,10 +39,9 @@ const UDPSocket = CC("@mozilla.org/network/udp-socket;1",
|
||||
"nsIUDPSocket",
|
||||
"init");
|
||||
|
||||
// TODO Bug 1027456: May need to reserve these with IANA
|
||||
const SCAN_PORT = 50624;
|
||||
const UPDATE_PORT = 50625;
|
||||
const ADDRESS = "224.0.0.200";
|
||||
const ADDRESS = "224.0.0.115";
|
||||
const REPLY_TIMEOUT = 5000;
|
||||
|
||||
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
@ -158,6 +157,8 @@ function Discovery() {
|
||||
this._onRemoteUpdate = this._onRemoteUpdate.bind(this);
|
||||
this._purgeMissingDevices = this._purgeMissingDevices.bind(this);
|
||||
|
||||
Services.obs.addObserver(this, "network-active-changed", false);
|
||||
|
||||
this._getSystemInfo();
|
||||
}
|
||||
|
||||
@ -295,6 +296,35 @@ Discovery.prototype = {
|
||||
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
|
||||
* one currently alive.
|
||||
|
@ -363,7 +363,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
|
||||
let { caller, args, window, name } = functionCall.details;
|
||||
let source = caller;
|
||||
let dest = args[0];
|
||||
let isAudioParam = dest instanceof window.AudioParam;
|
||||
let isAudioParam = dest ? getConstructorName(dest) === "AudioParam" : false;
|
||||
|
||||
// audionode.connect(param)
|
||||
if (name === "connect" && isAudioParam) {
|
||||
@ -433,8 +433,9 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
|
||||
},
|
||||
"connect-param": {
|
||||
type: "connectParam",
|
||||
source: Arg(0, "audionode"),
|
||||
param: Arg(1, "string")
|
||||
source: Option(0, "audionode"),
|
||||
dest: Option(0, "audionode"),
|
||||
param: Option(0, "string")
|
||||
},
|
||||
"change-param": {
|
||||
type: "changeParam",
|
||||
@ -461,12 +462,30 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
|
||||
// Ensure AudioNode is wrapped.
|
||||
node = new XPCNativeWrapper(node);
|
||||
|
||||
this._instrumentParams(node);
|
||||
|
||||
let actor = new AudioNodeActor(this.conn, node);
|
||||
this.manage(actor);
|
||||
this._nativeToActorID.set(node.id, actor.actorID);
|
||||
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.
|
||||
* 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.
|
||||
* Implement in bug 986705
|
||||
*/
|
||||
_onConnectParam: function (source, dest) {
|
||||
// TODO bug 986705
|
||||
_onConnectParam: function (source, param) {
|
||||
let sourceActor = this._getActorByNativeID(source.id);
|
||||
let destActor = this._getActorByNativeID(param._parentID);
|
||||
emit(this, "connect-param", {
|
||||
source: sourceActor,
|
||||
dest: destActor,
|
||||
param: param._paramName
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -167,7 +167,6 @@ this.checkCert =
|
||||
if (!issuerCert)
|
||||
throw new Ce(certNotBuiltInErr, Cr.NS_ERROR_ABORT);
|
||||
|
||||
issuerCert = issuerCert.QueryInterface(Ci.nsIX509Cert3);
|
||||
var tokenNames = issuerCert.getAllTokenNames({});
|
||||
|
||||
if (!tokenNames || !tokenNames.some(isBuiltinToken))
|
||||
|
@ -83,6 +83,7 @@ const PREFS_WHITELIST = [
|
||||
const PREFS_BLACKLIST = [
|
||||
/^network[.]proxy[.]/,
|
||||
/[.]print_to_filename$/,
|
||||
/^print[.]macosx[.]pagesetup/,
|
||||
];
|
||||
|
||||
this.Troubleshoot = {
|
||||
|
@ -15,120 +15,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <fcntl.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 "Framebuffer.h"
|
||||
|
||||
#include "android/log.h"
|
||||
#include <fcntl.h>
|
||||
#include <linux/fb.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "Framebuffer.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxImageSurface.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "nsSize.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;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace Framebuffer {
|
||||
|
||||
static int sFd = -1;
|
||||
static size_t sMappedSize;
|
||||
static struct fb_var_screeninfo sVi;
|
||||
static size_t sActiveBuffer;
|
||||
typedef vector<nsRefPtr<gfxImageSurface> > BufferVector;
|
||||
BufferVector* sBuffers;
|
||||
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
|
||||
GetSize(nsIntSize *aScreenSize) {
|
||||
// If the framebuffer has been opened, we should always have the size.
|
||||
@ -153,54 +60,5 @@ GetSize(nsIntSize *aScreenSize) {
|
||||
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 mozilla
|
||||
|
@ -15,48 +15,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class gfxASurface;
|
||||
class nsIntRegion;
|
||||
class nsIntSize;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
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
|
||||
// already cached.
|
||||
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 mozilla
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
#include "libdisplay/GonkDisplay.h"
|
||||
#include "Framebuffer.h"
|
||||
#include "GLContext.h" // for GLContext
|
||||
#include "HwcUtils.h"
|
||||
#include "HwcComposer2D.h"
|
||||
#include "LayerScope.h"
|
||||
#include "mozilla/layers/LayerManagerComposite.h"
|
||||
#include "mozilla/layers/PLayerTransaction.h"
|
||||
#include "mozilla/layers/ShadowLayerUtilsGralloc.h"
|
||||
@ -807,8 +807,12 @@ HwcComposer2D::TryRender(Layer* aRoot,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send data to LayerScope for debugging
|
||||
SendtoLayerScope();
|
||||
|
||||
if (!TryHwComposition()) {
|
||||
LOGD("H/W Composition failed");
|
||||
LayerScope::CleanLayer();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -816,4 +820,19 @@ HwcComposer2D::TryRender(Layer* aRoot,
|
||||
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
|
||||
|
@ -97,6 +97,7 @@ private:
|
||||
const gfxMatrix& aParentTransform, const gfxMatrix& aGLWorldTransform);
|
||||
void setCrop(HwcLayer* layer, hwc_rect_t srcCrop);
|
||||
void setHwcGeometry(bool aGeometryChanged);
|
||||
void SendtoLayerScope();
|
||||
|
||||
HwcDevice* mHwc;
|
||||
HwcList* mList;
|
||||
|
@ -68,14 +68,10 @@ static uint32_t sScreenRotation;
|
||||
static uint32_t sPhysicalScreenRotation;
|
||||
static nsIntRect sVirtualBounds;
|
||||
|
||||
static nsRefPtr<GLContext> sGLContext;
|
||||
static nsTArray<nsWindow *> sTopWindows;
|
||||
static nsWindow *gFocusedWindow = nullptr;
|
||||
static bool sFramebufferOpen;
|
||||
static bool sUsingOMTC;
|
||||
static bool sUsingHwc;
|
||||
static bool sScreenInitialized;
|
||||
static nsRefPtr<gfxASurface> sOMTCSurface;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -160,15 +156,11 @@ nsWindow::nsWindow()
|
||||
// to know the color depth, which asks our native window.
|
||||
// This has to happen after other init has finished.
|
||||
gfxPlatform::GetPlatform();
|
||||
sUsingOMTC = ShouldUseOffMainThreadCompositing();
|
||||
|
||||
if (!ShouldUseOffMainThreadCompositing()) {
|
||||
MOZ_CRASH("How can we render apps, then?");
|
||||
}
|
||||
//Update sUsingHwc whenever layers.composer2d.enabled changes
|
||||
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();
|
||||
if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) {
|
||||
// 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 {
|
||||
NS_RUNTIMEABORT("Unexpected layer manager type");
|
||||
}
|
||||
@ -537,12 +500,7 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
|
||||
if (mLayerManager) {
|
||||
// This layer manager might be used for painting outside of DoDraw(), so we need
|
||||
// to set the correct rotation on it.
|
||||
if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_BASIC) {
|
||||
BasicLayerManager* manager =
|
||||
static_cast<BasicLayerManager*>(mLayerManager.get());
|
||||
manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
|
||||
ScreenRotation(EffectiveScreenRotation()));
|
||||
} else if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
|
||||
if (mLayerManager->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
|
||||
ClientLayerManager* manager =
|
||||
static_cast<ClientLayerManager*>(mLayerManager.get());
|
||||
manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE,
|
||||
@ -561,38 +519,13 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (sUsingOMTC) {
|
||||
CreateCompositor();
|
||||
if (mCompositorParent) {
|
||||
uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
|
||||
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
|
||||
CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
|
||||
}
|
||||
if (mLayerManager)
|
||||
return mLayerManager;
|
||||
CreateCompositor();
|
||||
if (mCompositorParent) {
|
||||
uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
|
||||
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
|
||||
CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
MOZ_ASSERT(mLayerManager);
|
||||
return mLayerManager;
|
||||
}
|
||||
|
||||
|
@ -172,7 +172,7 @@ static void DeferredDestroyCompositor(CompositorParent* aCompositorParent,
|
||||
|
||||
void nsBaseWidget::DestroyCompositor()
|
||||
{
|
||||
LayerScope::DestroyServerSocket();
|
||||
LayerScope::DeInit();
|
||||
|
||||
if (mCompositorChild) {
|
||||
mCompositorChild->SendWillStop();
|
||||
@ -900,8 +900,8 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight)
|
||||
return;
|
||||
}
|
||||
|
||||
// The server socket has to be created on the main thread.
|
||||
LayerScope::CreateServerSocket();
|
||||
// Initialize LayerScope on the main thread.
|
||||
LayerScope::Init();
|
||||
|
||||
mCompositorParent = NewCompositorParent(aWidth, aHeight);
|
||||
MessageChannel *parentChannel = mCompositorParent->GetIPCChannel();
|
||||
|
@ -33,8 +33,7 @@ else:
|
||||
'xptcinvoke.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'
|
||||
|
||||
@ -42,8 +41,3 @@ LOCAL_INCLUDES += [
|
||||
'../..',
|
||||
'/xpcom/reflect/xptinfo',
|
||||
]
|
||||
|
||||
if CONFIG['TARGET_CPU'] != 'x86_64':
|
||||
if not CONFIG['GNU_CXX']:
|
||||
# FIXME: bug 413019
|
||||
NO_PGO = True
|
||||
|
Loading…
Reference in New Issue
Block a user