Merge last green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-01-20 01:24:13 +00:00
commit e671bf9cd2
87 changed files with 3081 additions and 510 deletions

View File

@ -74,7 +74,7 @@ static const NSString* AXRoles [] = {
NSAccessibilityGroupRole, // ROLE_CELL
@"AXLink", // ROLE_LINK. 10.4+ the attr first define in SDK 10.4, so we define it here too. ROLE_LINK
@"AXHelpTag", // ROLE_HELPBALLOON
NSAccessibilityUnknownRole, // ROLE_CHARACTER. unusued on OS X
NSAccessibilityUnknownRole, // ROLE_CHARACTER. unused on OS X
NSAccessibilityListRole, // ROLE_LIST
NSAccessibilityRowRole, // ROLE_LISTITEM
NSAccessibilityOutlineRole, // ROLE_OUTLINE

View File

@ -932,6 +932,8 @@ xpicleanup@BIN_SUFFIX@
#endif
components/txEXSLTRegExFunctions.js
components/Weave.js
components/Webapps.js
components/Webapps.manifest
components/WebContentConverter.js
defaults/autoconfig/platform.js
defaults/autoconfig/prefcalls.js
@ -1057,6 +1059,7 @@ xpicleanup@BIN_SUFFIX@
modules/tabview/AllTabs.jsm
modules/tabview/groups.jsm
modules/tabview/utils.jsm
modules/Webapps.jsm
modules/WindowDraggingUtils.jsm
#ifdef XP_WIN
modules/WindowsJumpLists.jsm
@ -1147,6 +1150,7 @@ xpicleanup@BIN_SUFFIX@
components/directory.xpt
components/docshell.xpt
components/dom.xpt
components/dom_apps.xpt
components/dom_base.xpt
#ifdef MOZ_B2G_RIL
components/dom_telephony.xpt

View File

@ -1999,6 +1999,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
if (!decoder->Init(this)) {
LOG(PR_LOG_DEBUG, ("%p Failed to init cloned decoder %p", this, decoder.get()));
return NS_ERROR_FAILURE;
}
@ -2010,6 +2011,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
nsMediaStream* stream = originalStream->CloneData(decoder);
if (!stream) {
LOG(PR_LOG_DEBUG, ("%p Failed to cloned stream for decoder %p", this, decoder.get()));
return NS_ERROR_FAILURE;
}
@ -2017,6 +2019,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
nsresult rv = decoder->Load(stream, nsnull, aOriginal);
if (NS_FAILED(rv)) {
LOG(PR_LOG_DEBUG, ("%p Failed to load decoder/stream for decoder %p", this, decoder.get()));
return rv;
}

View File

@ -193,6 +193,7 @@ nsresult nsBuiltinDecoder::Load(nsMediaStream* aStream,
nsresult rv = aStream->Open(aStreamListener);
if (NS_FAILED(rv)) {
LOG(PR_LOG_DEBUG, ("%p Failed to open stream!", this));
delete aStream;
return rv;
}
@ -245,6 +246,7 @@ nsresult nsBuiltinDecoder::ScheduleStateMachineThread()
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
NS_ASSERTION(mDecoderStateMachine,
"Must have state machine to start state machine thread");
NS_ENSURE_STATE(mDecoderStateMachine);
if (mShuttingDown)
return NS_OK;
@ -258,6 +260,7 @@ nsresult nsBuiltinDecoder::Play()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
NS_ASSERTION(mDecoderStateMachine != nsnull, "Should have state machine.");
nsresult res = ScheduleStateMachineThread();
NS_ENSURE_SUCCESS(res,res);
if (mPlayState == PLAY_STATE_SEEKING) {
@ -832,29 +835,19 @@ void nsBuiltinDecoder::ChangeState(PlayState aState)
}
mPlayState = aState;
switch (aState) {
case PLAY_STATE_PAUSED:
/* No action needed */
break;
case PLAY_STATE_PLAYING:
mDecoderStateMachine->Play();
break;
case PLAY_STATE_SEEKING:
mDecoderStateMachine->Seek(mRequestedSeekTime);
mRequestedSeekTime = -1.0;
break;
case PLAY_STATE_LOADING:
/* No action needed */
break;
case PLAY_STATE_START:
/* No action needed */
break;
case PLAY_STATE_ENDED:
/* No action needed */
break;
case PLAY_STATE_SHUTDOWN:
/* No action needed */
break;
if (mDecoderStateMachine) {
switch (aState) {
case PLAY_STATE_PLAYING:
mDecoderStateMachine->Play();
break;
case PLAY_STATE_SEEKING:
mDecoderStateMachine->Seek(mRequestedSeekTime);
mRequestedSeekTime = -1.0;
break;
default:
/* No action needed */
break;
}
}
mReentrantMonitor.NotifyAll();
}
@ -973,7 +966,9 @@ void nsBuiltinDecoder::Resume(bool aForceBuffering)
}
if (aForceBuffering) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
mDecoderStateMachine->StartBuffering();
if (mDecoderStateMachine) {
mDecoderStateMachine->StartBuffering();
}
}
}

View File

@ -45,6 +45,7 @@
#include "mozilla/mozalloc.h"
#include "VideoUtils.h"
#include "nsTimeRanges.h"
#include "nsDeque.h"
#include "mozilla/Preferences.h"
#include "mozilla/StdInt.h"
@ -229,6 +230,17 @@ public:
return mStateMachineThread;
}
// Requests that a decode thread be created for aStateMachine. The thread
// may be created immediately, or after some delay, once a thread becomes
// available. The request can be cancelled using CancelCreateDecodeThread().
// It's the callers responsibility to not call this more than once for any
// given state machine.
nsresult RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
// Cancels a request made by RequestCreateDecodeThread to create a decode
// thread for aStateMachine.
nsresult CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine);
// Maximum number of active decode threads allowed. When more
// than this number are active the thread creation will fail.
static const PRUint32 MAX_DECODE_THREADS = 25;
@ -238,16 +250,17 @@ public:
// call with any other monitor held to avoid deadlock.
PRUint32 GetDecodeThreadCount();
// Keep track of the fact that a decode thread was created.
// Call on any thread. Holds the internal monitor so don't
// call with any other monitor held to avoid deadlock.
void NoteDecodeThreadCreated();
// Keep track of the fact that a decode thread was destroyed.
// Call on any thread. Holds the internal monitor so don't
// call with any other monitor held to avoid deadlock.
void NoteDecodeThreadDestroyed();
#ifdef DEBUG
// Returns true if aStateMachine has a pending request for a
// decode thread.
bool IsQueued(nsBuiltinDecoderStateMachine* aStateMachine);
#endif
private:
// Holds global instance of StateMachineTracker.
// Writable on main thread only.
@ -271,6 +284,10 @@ private:
// only, read from the decoder threads. Synchronized via
// the mMonitor.
nsIThread* mStateMachineThread;
// Queue of state machines waiting for decode threads. Entries at the front
// get their threads first.
nsDeque mPending;
};
StateMachineTracker* StateMachineTracker::mInstance = nsnull;
@ -296,7 +313,23 @@ void StateMachineTracker::EnsureGlobalStateMachine()
}
mStateMachineCount++;
}
#ifdef DEBUG
bool StateMachineTracker::IsQueued(nsBuiltinDecoderStateMachine* aStateMachine)
{
ReentrantMonitorAutoEnter mon(mMonitor);
PRInt32 size = mPending.GetSize();
for (int i = 0; i < size; ++i) {
nsBuiltinDecoderStateMachine* m =
static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
if (m == aStateMachine) {
return true;
}
}
return false;
}
#endif
void StateMachineTracker::CleanupGlobalStateMachine()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -305,6 +338,7 @@ void StateMachineTracker::CleanupGlobalStateMachine()
mStateMachineCount--;
if (mStateMachineCount == 0) {
LOG(PR_LOG_DEBUG, ("Destroying media state machine thread"));
NS_ASSERTION(mPending.GetSize() == 0, "Shouldn't all requests be handled by now?");
{
ReentrantMonitorAutoEnter mon(mMonitor);
nsCOMPtr<nsIRunnable> event = new ShutdownThreadEvent(mStateMachineThread);
@ -319,16 +353,22 @@ void StateMachineTracker::CleanupGlobalStateMachine()
}
}
void StateMachineTracker::NoteDecodeThreadCreated()
{
ReentrantMonitorAutoEnter mon(mMonitor);
++mDecodeThreadCount;
}
void StateMachineTracker::NoteDecodeThreadDestroyed()
{
ReentrantMonitorAutoEnter mon(mMonitor);
--mDecodeThreadCount;
while (mDecodeThreadCount < MAX_DECODE_THREADS && mPending.GetSize() > 0) {
nsBuiltinDecoderStateMachine* m =
static_cast<nsBuiltinDecoderStateMachine*>(mPending.PopFront());
nsresult rv;
{
ReentrantMonitorAutoExit exitMon(mMonitor);
rv = m->StartDecodeThread();
}
if (NS_SUCCEEDED(rv)) {
++mDecodeThreadCount;
}
}
}
PRUint32 StateMachineTracker::GetDecodeThreadCount()
@ -337,6 +377,45 @@ PRUint32 StateMachineTracker::GetDecodeThreadCount()
return mDecodeThreadCount;
}
nsresult StateMachineTracker::CancelCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine) {
ReentrantMonitorAutoEnter mon(mMonitor);
PRInt32 size = mPending.GetSize();
for (PRInt32 i = 0; i < size; ++i) {
void* m = static_cast<nsBuiltinDecoderStateMachine*>(mPending.ObjectAt(i));
if (m == aStateMachine) {
mPending.RemoveObjectAt(i);
break;
}
}
NS_ASSERTION(!IsQueued(aStateMachine), "State machine should no longer have queued request.");
return NS_OK;
}
nsresult StateMachineTracker::RequestCreateDecodeThread(nsBuiltinDecoderStateMachine* aStateMachine)
{
NS_ENSURE_STATE(aStateMachine);
ReentrantMonitorAutoEnter mon(mMonitor);
if (mPending.GetSize() > 0 || mDecodeThreadCount + 1 >= MAX_DECODE_THREADS) {
// If there's already state machines in the queue, or we've exceeded the
// limit, append the state machine to the queue of state machines waiting
// for a decode thread. This ensures state machines already waiting get
// their threads first.
mPending.Push(aStateMachine);
return NS_OK;
}
nsresult rv;
{
ReentrantMonitorAutoExit exitMon(mMonitor);
rv = aStateMachine->StartDecodeThread();
}
if (NS_SUCCEEDED(rv)) {
++mDecodeThreadCount;
}
NS_ASSERTION(mDecodeThreadCount <= MAX_DECODE_THREADS,
"Should keep to thread limit!");
return NS_OK;
}
nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder,
nsBuiltinDecoderReader* aReader,
bool aRealTime) :
@ -367,6 +446,7 @@ nsBuiltinDecoderStateMachine::nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDe
mDispatchedRunEvent(false),
mDecodeThreadWaiting(false),
mRealTime(aRealTime),
mRequestedNewDecodeThread(false),
mEventManager(aDecoder)
{
MOZ_COUNT_CTOR(nsBuiltinDecoderStateMachine);
@ -386,6 +466,10 @@ nsBuiltinDecoderStateMachine::~nsBuiltinDecoderStateMachine()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
MOZ_COUNT_DTOR(nsBuiltinDecoderStateMachine);
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
"Should not have a pending request for a new decode thread");
NS_ASSERTION(!mRequestedNewDecodeThread,
"Should not have (or flagged) a pending request for a new decode thread");
if (mTimer)
mTimer->Cancel();
mTimer = nsnull;
@ -1191,6 +1275,14 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
{
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
if (mRequestedNewDecodeThread) {
// We've requested that the decode be created, but it hasn't been yet.
// Cancel that request.
NS_ASSERTION(!mDecodeThread,
"Shouldn't have a decode thread until after request processed");
StateMachineTracker::Instance().CancelCreateDecodeThread(this);
mRequestedNewDecodeThread = false;
}
mStopDecodeThread = true;
mDecoder->GetReentrantMonitor().NotifyAll();
if (mDecodeThread) {
@ -1203,6 +1295,10 @@ void nsBuiltinDecoderStateMachine::StopDecodeThread()
mDecodeThread = nsnull;
mDecodeThreadIdle = false;
}
NS_ASSERTION(!mRequestedNewDecodeThread,
"Any pending requests for decode threads must be canceled and unflagged");
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
"Any pending requests for decode threads must be canceled");
}
void nsBuiltinDecoderStateMachine::StopAudioThread()
@ -1221,52 +1317,68 @@ void nsBuiltinDecoderStateMachine::StopAudioThread()
}
nsresult
nsBuiltinDecoderStateMachine::StartDecodeThread()
nsBuiltinDecoderStateMachine::ScheduleDecodeThread()
{
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
PRUint32 count = 0;
bool created = false;
{
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
count = StateMachineTracker::Instance().GetDecodeThreadCount();
}
mStopDecodeThread = false;
if ((mDecodeThread && !mDecodeThreadIdle) || mState >= DECODER_STATE_COMPLETED)
if (mState >= DECODER_STATE_COMPLETED) {
return NS_OK;
if (!mDecodeThread && count > StateMachineTracker::MAX_DECODE_THREADS) {
// Have to run one iteration of the state machine loop to ensure the
// shutdown state is processed.
ScheduleStateMachine();
mState = DECODER_STATE_SHUTDOWN;
return NS_ERROR_FAILURE;
}
if (!mDecodeThread) {
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
nsnull,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
// Have to run one iteration of the state machine loop to ensure the
// shutdown state is processed.
ScheduleStateMachine();
mState = DECODER_STATE_SHUTDOWN;
return rv;
if (mDecodeThread) {
NS_ASSERTION(!mRequestedNewDecodeThread,
"Shouldn't have requested new decode thread when we have a decode thread");
// We already have a decode thread...
if (mDecodeThreadIdle) {
// ... and it's not been shutdown yet, wake it up.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
mDecodeThreadIdle = false;
}
created = true;
return NS_OK;
} else if (!mRequestedNewDecodeThread) {
// We don't already have a decode thread, request a new one.
mRequestedNewDecodeThread = true;
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
StateMachineTracker::Instance().RequestCreateDecodeThread(this);
}
return NS_OK;
}
nsresult
nsBuiltinDecoderStateMachine::StartDecodeThread()
{
NS_ASSERTION(StateMachineTracker::Instance().GetDecodeThreadCount() <
StateMachineTracker::MAX_DECODE_THREADS,
"Should not have reached decode thread limit");
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
"Should not already have a pending request for a new decode thread.");
NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
NS_ASSERTION(!mDecodeThread, "Should not have decode thread yet");
NS_ASSERTION(mRequestedNewDecodeThread, "Should have requested this...");
mRequestedNewDecodeThread = false;
nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
nsnull,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
// Give up, report error to media element.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::DecodeError);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
return rv;
}
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::DecodeThreadRun);
mDecodeThread->Dispatch(event, NS_DISPATCH_NORMAL);
mDecodeThreadIdle = false;
if (created) {
ReentrantMonitorAutoExit mon(mDecoder->GetReentrantMonitor());
StateMachineTracker::Instance().NoteDecodeThreadCreated();
}
return NS_OK;
}
@ -1282,6 +1394,7 @@ nsBuiltinDecoderStateMachine::StartAudioThread()
nsnull,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get()));
mState = DECODER_STATE_SHUTDOWN;
return rv;
}
@ -1639,7 +1752,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
case DECODER_STATE_DECODING_METADATA: {
// Ensure we have a decode thread to decode metadata.
return StartDecodeThread();
return ScheduleDecodeThread();
}
case DECODER_STATE_DECODING: {
@ -1663,7 +1776,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
// We're playing and/or our decode buffers aren't full. Ensure we have
// an active decode thread.
if (NS_FAILED(StartDecodeThread())) {
if (NS_FAILED(ScheduleDecodeThread())) {
NS_WARNING("Failed to start media decode thread!");
return NS_ERROR_FAILURE;
}
@ -1728,7 +1841,7 @@ nsresult nsBuiltinDecoderStateMachine::RunStateMachine()
case DECODER_STATE_SEEKING: {
// Ensure we have a decode thread to perform the seek.
return StartDecodeThread();
return ScheduleDecodeThread();
}
case DECODER_STATE_COMPLETED: {

View File

@ -253,6 +253,12 @@ public:
// earlier, in which case the request is discarded.
nsresult ScheduleStateMachine(PRInt64 aUsecs);
// Creates and starts a new decode thread. Don't call this directly,
// request a new decode thread by calling
// StateMachineTracker::RequestCreateDecodeThread().
// The decoder monitor must not be held. Called on the state machine thread.
nsresult StartDecodeThread();
// Timer function to implement ScheduleStateMachine(aUsecs).
void TimeoutExpired();
@ -352,7 +358,8 @@ protected:
// here. Called on the audio thread.
PRUint32 PlayFromAudioQueue(PRUint64 aFrameOffset, PRUint32 aChannels);
// Stops the decode thread. The decoder monitor must be held with exactly
// Stops the decode thread, and if we have a pending request for a new
// decode thread it is canceled. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
void StopDecodeThread();
@ -360,9 +367,11 @@ protected:
// one lock count. Called on the state machine thread.
void StopAudioThread();
// Starts the decode thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
nsresult StartDecodeThread();
// Ensures the decode thread is running if it already exists, or requests
// a new decode thread be started if there currently is no decode thread.
// The decoder monitor must be held with exactly one lock count. Called on
// the state machine thread.
nsresult ScheduleDecodeThread();
// Starts the audio thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
@ -625,6 +634,10 @@ protected:
// True is we are decoding a realtime stream, like a camera stream
bool mRealTime;
// True if we've requested a new decode thread, but it has not yet been
// created. Synchronized by the decoder monitor.
bool mRequestedNewDecodeThread;
PRUint32 mBufferingWait;
PRInt64 mLowDataThresholdUsecs;

View File

@ -150,6 +150,7 @@ _TEST_FILES = \
test_source_write.html \
test_standalone.html \
test_timeupdate_small_files.html \
test_too_many_elements.html \
test_volume.html \
test_video_to_canvas.html \
use_large_cache.js \

View File

@ -8,4 +8,4 @@ load 493915-1.html
skip-if(Android) load 495794-1.html
load 492286-1.xhtml
load 576612-1.html
load 691096-1.html
skip-if(Android) load 691096-1.html # Android sound API can't handle playing large number of sounds at once.

View File

@ -5,9 +5,9 @@
// These are small test files, good for just seeing if something loads. We
// really only need one test file per backend here.
var gSmallTests = [
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.233 },
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
{ name:"seek.webm", type:"video/webm", duration:3.966 },
{ name:"bogus.duh", type:"bogus/duh" }
];
@ -299,6 +299,14 @@ function getPlayableVideo(candidates) {
return null;
}
function getPlayableAudio(candidates) {
var v = document.createElement("audio");
var resources = candidates.filter(function(x){return /^audio/.test(x.type) && v.canPlayType(x.type);});
if (resources.length > 0)
return resources[0];
return null;
}
// Number of tests to run in parallel. Warning: Each media element requires
// at least 3 threads (4 on Linux), and on Linux each thread uses 10MB of
// virtual address space. Beware!

View File

@ -0,0 +1,68 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=713381
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 713381</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=713381">Mozilla Bug 713381</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<p>Received loadeddata event for <span id="result">0</span> <span id="expected"></span>audio elements.</p>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 713381 **/
const num = 500;
var loadeddata = 0;
var result = document.getElementById("result");
document.getElementById("expected").innerHTML = " of " + num + " ";
var finish = function(testNum) {
return function() {
ok(true, "Received loadeddata event for instance " + testNum );
loadeddata++;
if (loadeddata == num) {
ok(true, "Should receive loadeddata events for all " + num + " elements.");
SimpleTest.finish();
}
}
};
var resource = getPlayableAudio(gSmallTests);
if (resource == null) {
todo(false, "No types supported");
} else {
SimpleTest.waitForExplicitFinish();
// Load the resource, and play it to ensure it's entirely downloaded.
// Once it's played through, create a large number of audio elements which
// are the same resource. These will share data with the other resource, and
// so be really cheap to create.
var res = new Audio(resource.name);
res.addEventListener("ended",
function() {
for (var i=0; i<num; ++i) {
var a = new Audio(resource.name);
a.addEventListener("loadeddata", finish(i), false);
}
}, false);
res.play();
}
setInterval(function() { result.innerHTML = loadeddata; }, 1000);
</script>
</pre>
</body>
</html>

View File

@ -66,8 +66,13 @@ DIRS = \
interfaces/notification \
interfaces/svg \
interfaces/smil \
$(NULL)
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
DIRS += \
interfaces/apps \
$(NULL)
endif
DIRS += \
base \

View File

@ -0,0 +1,98 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "SmsDatabaseService.h"
namespace mozilla {
namespace dom {
namespace sms {
NS_IMPL_ISUPPORTS1(SmsDatabaseService, nsISmsDatabaseService)
NS_IMETHODIMP
SmsDatabaseService::SaveSentMessage(const nsAString& aReceiver,
const nsAString& aBody,
PRUint64 aDate, PRInt32* aId)
{
*aId = -1;
NS_ERROR("We should not be here!");
return NS_OK;
}
NS_IMETHODIMP
SmsDatabaseService::GetMessageMoz(PRInt32 aMessageId, PRInt32 aRequestId,
PRUint64 aProcessId)
{
NS_ERROR("We should not be here!");
return NS_OK;
}
NS_IMETHODIMP
SmsDatabaseService::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId,
PRUint64 aProcessId)
{
NS_ERROR("We should not be here!");
return NS_OK;
}
NS_IMETHODIMP
SmsDatabaseService::CreateMessageList(nsIDOMMozSmsFilter* aFilter,
bool aReverse, PRInt32 aRequestId,
PRUint64 aProcessId)
{
NS_ERROR("We should not be here!");
return NS_OK;
}
NS_IMETHODIMP
SmsDatabaseService::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId,
PRUint64 aProcessId)
{
NS_ERROR("We should not be here!");
return NS_OK;
}
NS_IMETHODIMP
SmsDatabaseService::ClearMessageList(PRInt32 aListId)
{
NS_ERROR("We should not be here!");
return NS_OK;
}
} // namespace sms
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mounir Lamouri <mounir.lamouri@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_dom_sms_SmsDatabaseService_h
#define mozilla_dom_sms_SmsDatabaseService_h
#include "nsISmsDatabaseService.h"
namespace mozilla {
namespace dom {
namespace sms {
class SmsDatabaseService : public nsISmsDatabaseService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISMSDATABASESERVICE
};
} // namespace sms
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_sms_SmsDatabaseService_h

View File

@ -80,7 +80,10 @@ SmsService::GetNumberOfMessagesForText(const nsAString& aText, PRUint16* aResult
}
NS_IMETHODIMP
SmsService::Send(const nsAString& aNumber, const nsAString& aMessage)
SmsService::Send(const nsAString& aNumber,
const nsAString& aMessage,
PRInt32 aRequestId,
PRUint64 aProcessId)
{
if (!mRIL) {
return NS_OK;

View File

@ -40,7 +40,7 @@
#include "nsISmsService.h"
#include "nsCOMPtr.h"
#include "nsITelephone.h"
#include "nsIRadioInterfaceLayer.h"
namespace mozilla {
namespace dom {
@ -54,7 +54,7 @@ public:
SmsService();
protected:
nsCOMPtr<nsITelephone> mRIL;
nsCOMPtr<nsIRadioInterfaceLayer> mRIL;
};
} // namespace sms

View File

@ -79,6 +79,11 @@ LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/android \
$(NULL)
endif
ifeq ($(MOZ_WIDGET_TOOLKIT),gonk)
LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/b2g \
$(NULL)
endif
EXPORTS += nsGeoPositionIPCSerialiser.h
include $(topsrcdir)/config/config.mk

View File

@ -88,6 +88,10 @@
#include "AndroidLocationProvider.h"
#endif
#ifdef MOZ_WIDGET_GONK
#include "GonkGPSGeolocationProvider.h"
#endif
#include "nsIDOMDocument.h"
#include "nsIDocument.h"
@ -577,6 +581,13 @@ nsresult nsGeolocationService::Init()
if (provider)
mProviders.AppendObject(provider);
#endif
#ifdef MOZ_WIDGET_GONK
provider = GonkGPSGeolocationProvider::GetSingleton();
if (provider)
mProviders.AppendObject(provider);
#endif
return NS_OK;
}

View File

@ -0,0 +1,185 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <pthread.h>
#include <hardware/gps.h>
#include "mozilla/Preferences.h"
#include "nsGeoPosition.h"
#include "GonkGPSGeolocationProvider.h"
using namespace mozilla;
NS_IMPL_ISUPPORTS1(GonkGPSGeolocationProvider, nsIGeolocationProvider)
GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton;
static void
LocationCallback(GpsLocation* location)
{
nsRefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
nsCOMPtr<nsIGeolocationUpdate> callback = provider->GetLocationCallback();
if (!callback)
return;
nsRefPtr<nsGeoPosition> somewhere = new nsGeoPosition(location->latitude,
location->longitude,
location->altitude,
location->accuracy,
location->accuracy,
location->bearing,
location->speed,
location->timestamp);
callback->Update(somewhere);
}
typedef void *(*pthread_func)(void *);
/** Callback for creating a thread that can call into the JS codes.
*/
static pthread_t
CreateThreadCallback(const char* name, void (*start)(void *), void* arg)
{
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
/* Unfortunately pthread_create and the callback disagreed on what
* start function should return.
*/
pthread_create(&thread, &attr, reinterpret_cast<pthread_func>(start), arg);
return thread;
}
static GpsCallbacks gCallbacks = {
sizeof(GpsCallbacks),
LocationCallback,
NULL, /* StatusCallback */
NULL, /* SvStatusCallback */
NULL, /* NmeaCallback */
NULL, /* SetCapabilitiesCallback */
NULL, /* AcquireWakelockCallback */
NULL, /* ReleaseWakelockCallback */
CreateThreadCallback,
};
GonkGPSGeolocationProvider::GonkGPSGeolocationProvider()
: mStarted(false)
{
mGpsInterface = GetGPSInterface();
}
GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider()
{
Shutdown();
sSingleton = NULL;
}
/* static */ already_AddRefed<GonkGPSGeolocationProvider>
GonkGPSGeolocationProvider::GetSingleton()
{
if (!sSingleton)
sSingleton = new GonkGPSGeolocationProvider();
NS_ADDREF(sSingleton);
return sSingleton;
}
already_AddRefed<nsIGeolocationUpdate>
GonkGPSGeolocationProvider::GetLocationCallback()
{
nsCOMPtr<nsIGeolocationUpdate> callback = mLocationCallback;
return callback.forget();
}
const GpsInterface*
GonkGPSGeolocationProvider::GetGPSInterface()
{
hw_module_t* module;
if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module))
return NULL;
hw_device_t* device;
if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device))
return NULL;
gps_device_t* gps_device = (gps_device_t *)device;
return gps_device->get_gps_interface(gps_device);
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::Startup()
{
if (mStarted)
return NS_OK;
NS_ENSURE_TRUE(mGpsInterface, NS_ERROR_FAILURE);
PRInt32 update = Preferences::GetInt("geo.default.update", 1000);
mGpsInterface->init(&gCallbacks);
mGpsInterface->start();
mGpsInterface->set_position_mode(GPS_POSITION_MODE_STANDALONE,
GPS_POSITION_RECURRENCE_PERIODIC,
update, 0, 0);
return NS_OK;
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback)
{
mLocationCallback = aCallback;
return NS_OK;
}
NS_IMETHODIMP
GonkGPSGeolocationProvider::Shutdown()
{
if (!mStarted)
return NS_OK;
mGpsInterface->stop();
mGpsInterface->cleanup();
return NS_OK;
}

View File

@ -0,0 +1,70 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Kan-Ru Chen <kchen@mozilla.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef GonkGPSGeolocationProvider_h
#define GonkGPSGeolocationProvider_h
#include <hardware/gps.h> // for GpsInterface
#include "nsIGeolocationProvider.h"
class GonkGPSGeolocationProvider : public nsIGeolocationProvider
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIGEOLOCATIONPROVIDER
static already_AddRefed<GonkGPSGeolocationProvider> GetSingleton();
already_AddRefed<nsIGeolocationUpdate> GetLocationCallback();
private:
/* Client should use GetSingleton() to get the provider instance. */
GonkGPSGeolocationProvider();
GonkGPSGeolocationProvider(const GonkGPSGeolocationProvider &);
GonkGPSGeolocationProvider & operator = (const GonkGPSGeolocationProvider &);
~GonkGPSGeolocationProvider();
const GpsInterface* GetGPSInterface();
static GonkGPSGeolocationProvider* sSingleton;
bool mStarted;
const GpsInterface* mGpsInterface;
nsCOMPtr<nsIGeolocationUpdate> mLocationCallback;
};
#endif /* GonkGPSGeolocationProvider_h */

View File

@ -55,19 +55,34 @@ CPPSRCS = \
$(NULL)
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
CPPSRCS += AudioManager.cpp
CPPSRCS += \
AudioManager.cpp \
GonkGPSGeolocationProvider.cpp \
$(NULL)
endif
XPIDLSRCS = \
nsIAudioManager.idl \
nsIRadioInterfaceLayer.idl \
nsIWorkerHolder.idl \
$(NULL)
LOCAL_INCLUDES = \
-I$(topsrcdir)/dom/base \
-I$(topsrcdir)/dom/src/geolocation \
-I$(topsrcdir)/dom/telephony \
-I$(topsrcdir)/dom/wifi \
-I$(topsrcdir)/content/events/src \
$(NULL)
EXTRA_COMPONENTS = \
RadioInterfaceLayer.manifest \
RadioInterfaceLayer.js \
$(NULL)
EXTRA_JS_MODULES = \
ril_consts.js \
ril_worker.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -14,13 +14,14 @@
* The Original Code is Telephony.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
* Philipp von Weitershausen <philipp@weitershausen.de>
* Sinker Li <thinker@codemud.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -48,13 +49,13 @@ Cu.import("resource://gre/modules/ril_consts.js", RIL);
const DEBUG = true; // set to false to suppress debug messages
const TELEPHONYWORKER_CID =
const RADIOINTERFACELAYER_CID =
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
const DATACALLINFO_CID =
Components.ID("{ef474cd9-94f7-4c05-a31b-29b9de8a10d2}");
const nsIAudioManager = Ci.nsIAudioManager;
const nsITelephone = Ci.nsITelephone;
const nsIRadioInterfaceLayer = Ci.nsIRadioInterfaceLayer;
const kSmsReceivedObserverTopic = "sms-received";
const DOM_SMS_DELIVERY_RECEIVED = "received";
@ -66,17 +67,17 @@ XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
function convertRILCallState(state) {
switch (state) {
case RIL.CALL_STATE_ACTIVE:
return nsITelephone.CALL_STATE_CONNECTED;
return nsIRadioInterfaceLayer.CALL_STATE_CONNECTED;
case RIL.CALL_STATE_HOLDING:
return nsITelephone.CALL_STATE_HELD;
return nsIRadioInterfaceLayer.CALL_STATE_HELD;
case RIL.CALL_STATE_DIALING:
return nsITelephone.CALL_STATE_DIALING;
return nsIRadioInterfaceLayer.CALL_STATE_DIALING;
case RIL.CALL_STATE_ALERTING:
return nsITelephone.CALL_STATE_RINGING;
return nsIRadioInterfaceLayer.CALL_STATE_RINGING;
case RIL.CALL_STATE_INCOMING:
return nsITelephone.CALL_STATE_INCOMING;
return nsIRadioInterfaceLayer.CALL_STATE_INCOMING;
case RIL.CALL_STATE_WAITING:
return nsITelephone.CALL_STATE_HELD; // XXX This may not be right...
return nsIRadioInterfaceLayer.CALL_STATE_HELD; // XXX This may not be right...
default:
throw new Error("Unknown rilCallState: " + state);
}
@ -126,7 +127,7 @@ DataCallInfo.protoptype = {
};
function nsTelephonyWorker() {
function RadioInterfaceLayer() {
this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js");
this.worker.onerror = this.onerror.bind(this);
this.worker.onmessage = this.onmessage.bind(this);
@ -138,16 +139,16 @@ function nsTelephonyWorker() {
cardState: null
};
}
nsTelephonyWorker.prototype = {
RadioInterfaceLayer.prototype = {
classID: TELEPHONYWORKER_CID,
classInfo: XPCOMUtils.generateCI({classID: TELEPHONYWORKER_CID,
classDescription: "Telephone",
classID: RADIOINTERFACELAYER_CID,
classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
classDescription: "RadioInterfaceLayer",
interfaces: [Ci.nsIWorkerHolder,
Ci.nsITelephone]}),
Ci.nsIRadioInterfaceLayer]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder,
Ci.nsITelephone]),
Ci.nsIRadioInterfaceLayer]),
onerror: function onerror(event) {
debug("Got an error: " + event.filename + ":" +
@ -219,12 +220,12 @@ nsTelephonyWorker.prototype = {
return;
}
switch (this._activeCall.state) {
case nsITelephone.CALL_STATE_INCOMING:
case nsIRadioInterfaceLayer.CALL_STATE_INCOMING:
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_RINGTONE;
debug("Incoming call, put audio system into PHONE_STATE_RINGTONE.");
break;
case nsITelephone.CALL_STATE_DIALING: // Fall through...
case nsITelephone.CALL_STATE_CONNECTED:
case nsIRadioInterfaceLayer.CALL_STATE_DIALING: // Fall through...
case nsIRadioInterfaceLayer.CALL_STATE_CONNECTED:
gAudioManager.phoneState = nsIAudioManager.PHONE_STATE_IN_CALL;
gAudioManager.setForceForUse(nsIAudioManager.USE_COMMUNICATION,
nsIAudioManager.FORCE_NONE);
@ -240,7 +241,7 @@ nsTelephonyWorker.prototype = {
handleCallStateChange: function handleCallStateChange(call) {
debug("handleCallStateChange: " + JSON.stringify(call));
call.state = convertRILCallState(call.state);
if (call.state == nsITelephone.CALL_STATE_CONNECTED) {
if (call.state == nsIRadioInterfaceLayer.CALL_STATE_CONNECTED) {
// This is now the active call.
this._activeCall = call;
}
@ -259,7 +260,8 @@ nsTelephonyWorker.prototype = {
}
this.updateCallAudioState();
this._deliverCallback("callStateChanged",
[call.callIndex, nsITelephone.CALL_STATE_DISCONNECTED,
[call.callIndex,
nsIRadioInterfaceLayer.CALL_STATE_DISCONNECTED,
call.number]);
},
@ -327,7 +329,7 @@ nsTelephonyWorker.prototype = {
worker: null,
// nsITelephone
// nsIRadioInterfaceLayer
currentState: null,
@ -540,12 +542,12 @@ nsTelephonyWorker.prototype = {
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([nsTelephonyWorker]);
const NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]);
let debug;
if (DEBUG) {
debug = function (s) {
dump("-*- TelephonyWorker component: " + s + "\n");
dump("-*- RadioInterfaceLayer: " + s + "\n");
};
} else {
debug = function (s) {};

View File

@ -0,0 +1 @@
component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js

View File

@ -41,7 +41,7 @@
#include "nsIObserverService.h"
#include "nsIJSContextStack.h"
#include "nsITelephone.h"
#include "nsIRadioInterfaceLayer.h"
#include "nsIWifi.h"
#include "nsIWorkerHolder.h"
#include "nsIXPConnect.h"
@ -51,8 +51,8 @@
#include "mozilla/ipc/Ril.h"
#include "nsContentUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsTelephonyWorker.h"
#include "nsThreadUtils.h"
#include "nsRadioInterfaceLayer.h"
#include "nsWifiWorker.h"
USING_TELEPHONY_NAMESPACE
@ -61,7 +61,7 @@ using namespace mozilla::ipc;
namespace {
NS_DEFINE_CID(kTelephonyWorkerCID, NS_TELEPHONYWORKER_CID);
NS_DEFINE_CID(kRadioInterfaceLayerCID, NS_RADIOINTERFACELAYER_CID);
NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID);
// Doesn't carry a reference, we're owned by services.
@ -224,7 +224,7 @@ SystemWorkerManager::Init()
return NS_ERROR_FAILURE;
}
rv = InitTelephone(cx);
rv = InitRIL(cx);
NS_ENSURE_SUCCESS(rv, rv);
rv = InitWifi(cx);
@ -252,7 +252,7 @@ SystemWorkerManager::Shutdown()
StopRil();
mTelephoneWorker = nsnull;
mRILWorker = nsnull;
mWifiWorker = nsnull;
nsCOMPtr<nsIObserverService> obs =
@ -295,9 +295,9 @@ SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
if (aIID.Equals(NS_GET_IID(nsITelephone))) {
return CallQueryInterface(mTelephoneWorker,
reinterpret_cast<nsITelephone**>(aResult));
if (aIID.Equals(NS_GET_IID(nsIRadioInterfaceLayer))) {
return CallQueryInterface(mRILWorker,
reinterpret_cast<nsIRadioInterfaceLayer**>(aResult));
}
if (aIID.Equals(NS_GET_IID(nsIWifi))) {
@ -310,12 +310,12 @@ SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult)
}
nsresult
SystemWorkerManager::InitTelephone(JSContext *cx)
SystemWorkerManager::InitRIL(JSContext *cx)
{
// We're keeping as much of this implementation as possible in JS, so the real
// worker lives in nsTelephonyWorker.js. All we do here is hold it alive and
// worker lives in RadioInterfaceLayer.js. All we do here is hold it alive and
// hook it up to the RIL thread.
nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kTelephonyWorkerCID);
nsCOMPtr<nsIWorkerHolder> worker = do_CreateInstance(kRadioInterfaceLayerCID);
NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE);
jsval workerval;
@ -345,7 +345,7 @@ SystemWorkerManager::InitTelephone(JSContext *cx)
mozilla::RefPtr<RILReceiver> receiver = new RILReceiver(wctd);
StartRil(receiver);
mTelephoneWorker = worker;
mRILWorker = worker;
return NS_OK;
}

View File

@ -70,10 +70,10 @@ private:
SystemWorkerManager();
~SystemWorkerManager();
nsresult InitTelephone(JSContext *cx);
nsresult InitRIL(JSContext *cx);
nsresult InitWifi(JSContext *cx);
nsCOMPtr<nsIWorkerHolder> mTelephoneWorker;
nsCOMPtr<nsIWorkerHolder> mRILWorker;
nsCOMPtr<nsIWorkerHolder> mWifiWorker;
bool mShutdown;

View File

@ -19,7 +19,9 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Philipp von Weitershausen <philipp@weitershausen.de>
* Philipp von Weitershausen <philipp@weitershausen.de>
* Ben Turner <bent.mozilla@gmail.com>
* Sinker Li <thinker@codemud.net>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -37,48 +39,85 @@
#include "nsISupports.idl"
[scriptable, uuid(9b7e3a01-9c45-4af3-81bb-1bf08a842226)]
interface nsITelephoneCallback : nsISupports
[scriptable, uuid(03eafd60-d138-4f09-81b4-90cd4996b3c7)]
interface nsIRILTelephonyCallback : nsISupports
{
// 'callState' uses the CALL_STATE values from nsITelephone.
/**
* Notified when a telephony call changes state.
*
* @param callIndex
* Call identifier assigned by the RIL.
* @param callState
* One of the nsIRadioInterfaceLayer::CALL_STATE_* values.
* @param number
* Number of the other party.
*/
void callStateChanged(in unsigned long callIndex,
in unsigned short callState,
in AString number);
// 'callState' uses the CALL_STATE values from nsITelephone. Return true to
// continue enumeration or false to cancel.
/**
* Called when nsIRadioInterfaceLayer is asked to enumerate the current
* telephony call state (nsIRadioInterfaceLayer::enumerateCalls). This is
* called once per call that is currently managed by the RIL.
*
* @param callIndex
* Call identifier assigned by the RIL.
* @param callState
* One of the nsIRadioInterfaceLayer::CALL_STATE_* values.
* @param number
* Number of the other party.
* @param isActive
* Indicates whether this call is the active one.
*
* @return true to continue enumeration or false to cancel.
*/
boolean enumerateCallState(in unsigned long callIndex,
in unsigned short callState,
in AString number,
in boolean isActive);
};
[scriptable, uuid(8399fddd-471c-41ac-8f35-99f7dbb738ec)]
interface nsIDataCallInfo : nsISupports
[scriptable, uuid(66a55943-e63b-4731-aece-9c04bfc14019)]
interface nsIRILDataCallInfo : nsISupports
{
readonly attribute unsigned long callState;
readonly attribute AString cid;
readonly attribute AString apn;
};
[scriptable, uuid(36cc4b89-0338-4ff7-a3c2-d78e60f2ea98)]
interface nsIPhoneDataCallCallback : nsISupports
[scriptable, uuid(cea91bcb-3cfb-42bb-8638-dae89e8870fc)]
interface nsIRILDataCallback : nsISupports
{
/**
* This method is called when the state of a data call is changed.
* Notified when a data call changes state.
*
* @param dataState use DATACALL_STATE_* values from nsITelephone.
* @param cid
* The CID of the data call.
* @param interfaceName
* Name of the associated network interface.
* @param dataState
* One of the nsIRadioInterfaceLayer::DATACALL_STATE_* values.
*/
void dataCallStateChanged(in AString cid,
in AString interfaceName,
in unsigned short callState);
void receiveDataCallList([array,size_is(aLength)] in nsIDataCallInfo aDataCalls,
in unsigned long aLength);
/**
* Called when nsIRadioInterfaceLayer is asked to enumerate the current
* data call state.
*
* @param datacalls
* Array of nsIRILDataCallInfo objects.
* @param length
* Lenght of the aforementioned array.
*/
void receiveDataCallList([array,size_is(length)] in nsIRILDataCallInfo dataCalls,
in unsigned long length);
};
[scriptable, uuid(78ed0beb-d6ad-42f8-929a-8d003285784f)]
interface nsITelephone : nsISupports
[scriptable, uuid(9b7e3a01-9c45-4af3-81bb-1bf08a842226)]
interface nsIRadioInterfaceLayer : nsISupports
{
const unsigned short CALL_STATE_UNKNOWN = 0;
const unsigned short CALL_STATE_DIALING = 1;
@ -102,14 +141,14 @@ interface nsITelephone : nsISupports
readonly attribute jsval currentState;
void registerCallback(in nsITelephoneCallback callback);
void unregisterCallback(in nsITelephoneCallback callback);
void registerCallback(in nsIRILTelephonyCallback callback);
void unregisterCallback(in nsIRILTelephonyCallback callback);
/**
* Will continue calling callback.enumerateCallState until the callback
* returns false.
*/
void enumerateCalls(in nsITelephoneCallback callback);
void enumerateCalls(in nsIRILTelephonyCallback callback);
/**
* Functionality for making and managing phone calls.
@ -126,7 +165,9 @@ interface nsITelephone : nsISupports
attribute bool microphoneMuted;
attribute bool speakerEnabled;
// PDP APIs
/**
* PDP APIs
*/
void setupDataCall(in long radioTech,
in DOMString apn,
in DOMString user,
@ -137,8 +178,8 @@ interface nsITelephone : nsISupports
in DOMString reason);
void getDataCallList();
void registerDataCallCallback(in nsIPhoneDataCallCallback callback);
void unregisterDataCallCallback(in nsIPhoneDataCallCallback callback);
void registerDataCallCallback(in nsIRILDataCallback callback);
void unregisterDataCallCallback(in nsIRILDataCallback callback);
/**
* SMS-related functionality.

View File

@ -35,7 +35,7 @@
*
* ***** END LICENSE BLOCK ***** */
// This must always match the CID given in nsTelephonyWorker.manifest!
#define NS_TELEPHONYWORKER_CID \
// This must always match the CID given in RadioInterfaceLayer.manifest!
#define NS_RADIOINTERFACELAYER_CID \
{ 0x2d831c8d, 0x6017, 0x435b, \
{ 0xa8, 0x0c, 0xe5, 0xd4, 0x22, 0x81, 0x0c, 0xea } }

View File

@ -61,18 +61,12 @@ XPIDLSRCS = \
nsIDOMTelephony.idl \
nsIDOMTelephonyCall.idl \
nsIDOMCallEvent.idl \
nsITelephone.idl \
$(NULL)
EXTRA_COMPONENTS = \
nsTelephonyWorker.manifest \
nsTelephonyWorker.js \
$(NULL)
EXTRA_JS_MODULES = \
ril_consts.js \
ril_worker.js \
$(NULL)
#LOCAL_INCLUDES = \
# -I$(topsrcdir)/dom/base \
# -I$(topsrcdir)/dom/system/b2g \
# -I$(topsrcdir)/content/events/src \
# $(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -112,8 +112,8 @@ nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
Telephony::~Telephony()
{
if (mTelephone && mTelephoneCallback) {
mTelephone->UnregisterCallback(mTelephoneCallback);
if (mRIL && mRILTelephonyCallback) {
mRIL->UnregisterCallback(mRILTelephonyCallback);
}
if (mRooted) {
@ -123,10 +123,10 @@ Telephony::~Telephony()
// static
already_AddRefed<Telephony>
Telephony::Create(nsPIDOMWindow* aOwner, nsITelephone* aTelephone)
Telephony::Create(nsPIDOMWindow* aOwner, nsIRadioInterfaceLayer* aRIL)
{
NS_ASSERTION(aOwner, "Null owner!");
NS_ASSERTION(aTelephone, "Null telephone!");
NS_ASSERTION(aRIL, "Null RIL!");
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
NS_ENSURE_TRUE(sgo, nsnull);
@ -138,13 +138,13 @@ Telephony::Create(nsPIDOMWindow* aOwner, nsITelephone* aTelephone)
telephony->mOwner = aOwner;
telephony->mScriptContext.swap(scriptContext);
telephony->mTelephone = aTelephone;
telephony->mTelephoneCallback = new TelephoneCallback(telephony);
telephony->mRIL = aRIL;
telephony->mRILTelephonyCallback = new RILTelephonyCallback(telephony);
nsresult rv = aTelephone->EnumerateCalls(telephony->mTelephoneCallback);
nsresult rv = aRIL->EnumerateCalls(telephony->mRILTelephonyCallback);
NS_ENSURE_SUCCESS(rv, nsnull);
rv = aTelephone->RegisterCallback(telephony->mTelephoneCallback);
rv = aRIL->RegisterCallback(telephony->mRILTelephonyCallback);
NS_ENSURE_SUCCESS(rv, nsnull);
return telephony.forget();
@ -195,7 +195,7 @@ NS_IMPL_RELEASE_INHERITED(Telephony, nsDOMEventTargetWrapperCache)
DOMCI_DATA(Telephony, Telephony)
NS_IMPL_ISUPPORTS1(Telephony::TelephoneCallback, nsITelephoneCallback)
NS_IMPL_ISUPPORTS1(Telephony::RILTelephonyCallback, nsIRILTelephonyCallback)
NS_IMETHODIMP
Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult)
@ -205,7 +205,7 @@ Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult)
for (PRUint32 index = 0; index < mCalls.Length(); index++) {
const nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
if (tempCall->IsOutgoing() &&
tempCall->CallState() < nsITelephone::CALL_STATE_CONNECTED) {
tempCall->CallState() < nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) {
// One call has been dialed already and we only support one outgoing call
// at a time.
NS_WARNING("Only permitted to dial one call at a time!");
@ -213,11 +213,11 @@ Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult)
}
}
nsresult rv = mTelephone->Dial(aNumber);
nsresult rv = mRIL->Dial(aNumber);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<TelephonyCall> call =
TelephonyCall::Create(this, aNumber, nsITelephone::CALL_STATE_DIALING);
TelephonyCall::Create(this, aNumber, nsIRadioInterfaceLayer::CALL_STATE_DIALING);
NS_ASSERTION(call, "This should never fail!");
NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
@ -229,7 +229,7 @@ Telephony::Dial(const nsAString& aNumber, nsIDOMTelephonyCall** aResult)
NS_IMETHODIMP
Telephony::GetMuted(bool* aMuted)
{
nsresult rv = mTelephone->GetMicrophoneMuted(aMuted);
nsresult rv = mRIL->GetMicrophoneMuted(aMuted);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -238,7 +238,7 @@ Telephony::GetMuted(bool* aMuted)
NS_IMETHODIMP
Telephony::SetMuted(bool aMuted)
{
nsresult rv = mTelephone->SetMicrophoneMuted(aMuted);
nsresult rv = mRIL->SetMicrophoneMuted(aMuted);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -247,7 +247,7 @@ Telephony::SetMuted(bool aMuted)
NS_IMETHODIMP
Telephony::GetSpeakerEnabled(bool* aSpeakerEnabled)
{
nsresult rv = mTelephone->GetSpeakerEnabled(aSpeakerEnabled);
nsresult rv = mRIL->GetSpeakerEnabled(aSpeakerEnabled);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -256,7 +256,7 @@ Telephony::GetSpeakerEnabled(bool* aSpeakerEnabled)
NS_IMETHODIMP
Telephony::SetSpeakerEnabled(bool aSpeakerEnabled)
{
nsresult rv = mTelephone->SetSpeakerEnabled(aSpeakerEnabled);
nsresult rv = mRIL->SetSpeakerEnabled(aSpeakerEnabled);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -339,7 +339,7 @@ Telephony::StartTone(const nsAString& aDTMFChar)
return NS_ERROR_INVALID_ARG;
}
nsresult rv = mTelephone->StartTone(aDTMFChar);
nsresult rv = mRIL->StartTone(aDTMFChar);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -348,7 +348,7 @@ Telephony::StartTone(const nsAString& aDTMFChar)
NS_IMETHODIMP
Telephony::StopTone()
{
nsresult rv = mTelephone->StopTone();
nsresult rv = mRIL->StopTone();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
@ -378,7 +378,7 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
if (tempCall->CallIndex() == kOutgoingPlaceholderCallIndex) {
NS_ASSERTION(!outgoingCall, "More than one outgoing call not supported!");
NS_ASSERTION(tempCall->CallState() == nsITelephone::CALL_STATE_DIALING,
NS_ASSERTION(tempCall->CallState() == nsIRadioInterfaceLayer::CALL_STATE_DIALING,
"Something really wrong here!");
// Stash this for later, we may need it if aCallIndex doesn't match one of
// our other calls.
@ -395,7 +395,7 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
// an outgoing call then we must be seeing a status update for our outgoing
// call.
if (!modifiedCall &&
aCallState != nsITelephone::CALL_STATE_INCOMING &&
aCallState != nsIRadioInterfaceLayer::CALL_STATE_INCOMING &&
outgoingCall) {
outgoingCall->UpdateCallIndex(aCallIndex);
modifiedCall.swap(outgoingCall);
@ -406,7 +406,7 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
modifiedCall->ChangeState(aCallState);
// See if this should replace our current active call.
if (aCallState == nsITelephone::CALL_STATE_CONNECTED) {
if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_CONNECTED) {
SwitchActiveCall(modifiedCall);
}
@ -414,7 +414,7 @@ Telephony::CallStateChanged(PRUint32 aCallIndex, PRUint16 aCallState,
}
// Didn't know anything about this call before now, must be incoming.
NS_ASSERTION(aCallState == nsITelephone::CALL_STATE_INCOMING,
NS_ASSERTION(aCallState == nsIRadioInterfaceLayer::CALL_STATE_INCOMING,
"Serious logic problem here!");
nsRefPtr<TelephonyCall> call =
@ -511,10 +511,10 @@ NS_NewTelephony(nsPIDOMWindow* aWindow, nsIDOMTelephony** aTelephony)
nsIInterfaceRequestor* ireq = SystemWorkerManager::GetInterfaceRequestor();
NS_ENSURE_TRUE(ireq, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsITelephone> telephone = do_GetInterface(ireq);
NS_ENSURE_TRUE(telephone, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIRadioInterfaceLayer> ril = do_GetInterface(ireq);
NS_ENSURE_TRUE(ril, NS_ERROR_UNEXPECTED);
nsRefPtr<Telephony> telephony = Telephony::Create(innerWindow, telephone);
nsRefPtr<Telephony> telephony = Telephony::Create(innerWindow, ril);
NS_ENSURE_TRUE(telephony, NS_ERROR_UNEXPECTED);
telephony.forget(aTelephony);

View File

@ -44,7 +44,7 @@
#include "nsIDOMTelephony.h"
#include "nsIDOMTelephonyCall.h"
#include "nsITelephone.h"
#include "nsIRadioInterfaceLayer.h"
class nsIScriptContext;
class nsPIDOMWindow;
@ -54,8 +54,8 @@ BEGIN_TELEPHONY_NAMESPACE
class Telephony : public nsDOMEventTargetWrapperCache,
public nsIDOMTelephony
{
nsCOMPtr<nsITelephone> mTelephone;
nsCOMPtr<nsITelephoneCallback> mTelephoneCallback;
nsCOMPtr<nsIRadioInterfaceLayer> mRIL;
nsCOMPtr<nsIRILTelephonyCallback> mRILTelephonyCallback;
NS_DECL_EVENT_HANDLER(incoming);
@ -71,14 +71,14 @@ class Telephony : public nsDOMEventTargetWrapperCache,
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMTELEPHONY
NS_DECL_NSITELEPHONECALLBACK
NS_DECL_NSIRILTELEPHONYCALLBACK
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetWrapperCache::)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
Telephony,
nsDOMEventTargetWrapperCache)
static already_AddRefed<Telephony>
Create(nsPIDOMWindow* aOwner, nsITelephone* aTelephone);
Create(nsPIDOMWindow* aOwner, nsIRadioInterfaceLayer* aRIL);
nsIDOMEventTarget*
ToIDOMEventTarget() const
@ -109,10 +109,10 @@ public:
mCallsArray = nsnull;
}
nsITelephone*
Telephone() const
nsIRadioInterfaceLayer*
RIL() const
{
return mTelephone;
return mRIL;
}
nsPIDOMWindow*
@ -137,15 +137,15 @@ private:
void
SwitchActiveCall(TelephonyCall* aCall);
class TelephoneCallback : public nsITelephoneCallback
class RILTelephonyCallback : public nsIRILTelephonyCallback
{
Telephony* mTelephony;
public:
NS_DECL_ISUPPORTS
NS_FORWARD_NSITELEPHONECALLBACK(mTelephony->)
NS_FORWARD_NSIRILTELEPHONYCALLBACK(mTelephony->)
TelephoneCallback(Telephony* aTelephony)
RILTelephonyCallback(Telephony* aTelephony)
: mTelephony(aTelephony)
{
NS_ASSERTION(mTelephony, "Null pointer!");

View File

@ -75,37 +75,37 @@ TelephonyCall::ChangeStateInternal(PRUint16 aCallState, bool aFireEvents)
nsString stateString;
switch (aCallState) {
case nsITelephone::CALL_STATE_DIALING:
case nsIRadioInterfaceLayer::CALL_STATE_DIALING:
stateString.AssignLiteral("dialing");
break;
case nsITelephone::CALL_STATE_RINGING:
case nsIRadioInterfaceLayer::CALL_STATE_RINGING:
stateString.AssignLiteral("ringing");
break;
case nsITelephone::CALL_STATE_BUSY:
case nsIRadioInterfaceLayer::CALL_STATE_BUSY:
stateString.AssignLiteral("busy");
break;
case nsITelephone::CALL_STATE_CONNECTING:
case nsIRadioInterfaceLayer::CALL_STATE_CONNECTING:
stateString.AssignLiteral("connecting");
break;
case nsITelephone::CALL_STATE_CONNECTED:
case nsIRadioInterfaceLayer::CALL_STATE_CONNECTED:
stateString.AssignLiteral("connected");
break;
case nsITelephone::CALL_STATE_HOLDING:
case nsIRadioInterfaceLayer::CALL_STATE_HOLDING:
stateString.AssignLiteral("holding");
break;
case nsITelephone::CALL_STATE_HELD:
case nsIRadioInterfaceLayer::CALL_STATE_HELD:
stateString.AssignLiteral("held");
break;
case nsITelephone::CALL_STATE_RESUMING:
case nsIRadioInterfaceLayer::CALL_STATE_RESUMING:
stateString.AssignLiteral("resuming");
break;
case nsITelephone::CALL_STATE_DISCONNECTING:
case nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTING:
stateString.AssignLiteral("disconnecting");
break;
case nsITelephone::CALL_STATE_DISCONNECTED:
case nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED:
stateString.AssignLiteral("disconnected");
break;
case nsITelephone::CALL_STATE_INCOMING:
case nsIRadioInterfaceLayer::CALL_STATE_INCOMING:
stateString.AssignLiteral("incoming");
break;
default:
@ -115,11 +115,11 @@ TelephonyCall::ChangeStateInternal(PRUint16 aCallState, bool aFireEvents)
mState = stateString;
mCallState = aCallState;
if (aCallState == nsITelephone::CALL_STATE_DIALING) {
if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_DIALING) {
mOutgoing = true;
}
if (aCallState == nsITelephone::CALL_STATE_DISCONNECTED) {
if (aCallState == nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED) {
NS_ASSERTION(mLive, "Should be live!");
mTelephony->RemoveCall(this);
mLive = false;
@ -208,33 +208,33 @@ TelephonyCall::GetState(nsAString& aState)
NS_IMETHODIMP
TelephonyCall::Answer()
{
if (mCallState != nsITelephone::CALL_STATE_INCOMING) {
if (mCallState != nsIRadioInterfaceLayer::CALL_STATE_INCOMING) {
NS_WARNING("Answer on non-incoming call ignored!");
return NS_OK;
}
nsresult rv = mTelephony->Telephone()->AnswerCall(mCallIndex);
nsresult rv = mTelephony->RIL()->AnswerCall(mCallIndex);
NS_ENSURE_SUCCESS(rv, rv);
ChangeStateInternal(nsITelephone::CALL_STATE_CONNECTING, true);
ChangeStateInternal(nsIRadioInterfaceLayer::CALL_STATE_CONNECTING, true);
return NS_OK;
}
NS_IMETHODIMP
TelephonyCall::HangUp()
{
if (mCallState == nsITelephone::CALL_STATE_DISCONNECTING ||
mCallState == nsITelephone::CALL_STATE_DISCONNECTED) {
if (mCallState == nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTING ||
mCallState == nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTED) {
NS_WARNING("HangUp on previously disconnected call ignored!");
return NS_OK;
}
nsresult rv = mCallState == nsITelephone::CALL_STATE_INCOMING ?
mTelephony->Telephone()->RejectCall(mCallIndex) :
mTelephony->Telephone()->HangUp(mCallIndex);
nsresult rv = mCallState == nsIRadioInterfaceLayer::CALL_STATE_INCOMING ?
mTelephony->RIL()->RejectCall(mCallIndex) :
mTelephony->RIL()->HangUp(mCallIndex);
NS_ENSURE_SUCCESS(rv, rv);
ChangeStateInternal(nsITelephone::CALL_STATE_DISCONNECTING, true);
ChangeStateInternal(nsIRadioInterfaceLayer::CALL_STATE_DISCONNECTING, true);
return NS_OK;
}

View File

@ -43,7 +43,7 @@
#include "TelephonyCommon.h"
#include "nsIDOMTelephonyCall.h"
#include "nsITelephone.h"
#include "nsIRadioInterfaceLayer.h"
class nsPIDOMWindow;
@ -131,7 +131,7 @@ public:
private:
TelephonyCall()
: mCallIndex(kOutgoingPlaceholderCallIndex),
mCallState(nsITelephone::CALL_STATE_UNKNOWN), mLive(false), mOutgoing(false)
mCallState(nsIRadioInterfaceLayer::CALL_STATE_UNKNOWN), mLive(false), mOutgoing(false)
{ }
~TelephonyCall()

View File

@ -1 +0,0 @@
component {2d831c8d-6017-435b-a80c-e5d422810cea} nsTelephonyWorker.js

View File

@ -14,8 +14,8 @@ SimpleTest.waitForFocus(function () opener.framesetWindowLoaded(window));
<frame src="data:text/html,&lt;html id='f7'&gt;&lt;body id='framebody4'&gt;&lt;input id='f8'&gt;&lt;body&gt;&lt;/html&gt;">
</frameset>
<noframes>
<input id="unusued1"/>
<input id="unusued2" tabindex="1"/>
<input id="unused1"/>
<input id="unused2" tabindex="1"/>
</noframes>
</frameset>

View File

@ -113,7 +113,8 @@ public class GeckoAppShell
public static native void onLowMemory();
public static native void callObserver(String observerKey, String topic, String data);
public static native void removeObserver(String observerKey);
public static native void loadLibs(String apkName, boolean shouldExtract);
public static native void loadGeckoLibsNative(String apkName);
public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
public static native void onChangeNetworkLinkStatus(String status);
public static native void reportJavaCrash(String stack);
@ -396,7 +397,8 @@ public class GeckoAppShell
}
}
}
loadLibs(apkName, extractLibs);
loadSQLiteLibsNative(apkName, extractLibs);
loadGeckoLibsNative(apkName);
}
private static void putLocaleEnv() {

View File

@ -116,6 +116,7 @@ DrawTargetCG::~DrawTargetCG()
CGColorSpaceRelease(mColorSpace);
if (mCg)
CGContextRelease(mCg);
free(mData);
}
TemporaryRef<SourceSurface>
@ -845,7 +846,6 @@ DrawTargetCG::Init(const IntSize &aSize, SurfaceFormat &)
// XXX: currently we allocate ourselves so that we can easily return a gfxImageSurface
// we might not need to later if once we don't need to support gfxImageSurface
//XXX: currently Init implicitly clears, that can often be a waste of time
// XXX: leaked
mData = calloc(mSize.height * stride, 1);
// XXX: what should we do if this fails?
mCg = CGBitmapContextCreate (mData,

View File

@ -131,12 +131,19 @@ endif
EXPORTS_NAMESPACES = gfxipc mozilla/layers
EXPORTS_gfxipc = ShadowLayerUtils.h
EXPORTS_mozilla/layers =\
CompositorCocoaWidgetHelper.h \
CompositorChild.h \
CompositorParent.h \
ShadowLayers.h \
ShadowLayersChild.h \
ShadowLayersParent.h \
ShadowLayersManager.h \
$(NULL)
CPPSRCS += \
CompositorCocoaWidgetHelper.cpp \
CompositorChild.cpp \
CompositorParent.cpp \
ShadowLayers.cpp \
ShadowLayerChild.cpp \
ShadowLayersChild.cpp \

View File

@ -50,7 +50,11 @@ SurfaceToTexture(ID3D10Device *aDevice,
gfxASurface *aSurface,
const gfxIntSize &aSize)
{
if (aSurface && aSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
if (!aSurface) {
return NULL;
}
if (aSurface->GetType() == gfxASurface::SurfaceTypeD2D) {
void *data = aSurface->GetData(&gKeyD3D10Texture);
if (data) {
nsRefPtr<ID3D10Texture2D> texture = static_cast<ID3D10Texture2D*>(data);
@ -67,7 +71,7 @@ SurfaceToTexture(ID3D10Device *aDevice,
if (!imageSurface) {
imageSurface = new gfxImageSurface(aSize,
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
context->SetSource(aSurface);
context->SetOperator(gfxContext::OPERATOR_SOURCE);
@ -75,13 +79,13 @@ SurfaceToTexture(ID3D10Device *aDevice,
}
D3D10_SUBRESOURCE_DATA data;
CD3D10_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM,
imageSurface->GetSize().width,
imageSurface->GetSize().height,
1, 1);
desc.Usage = D3D10_USAGE_IMMUTABLE;
data.pSysMem = imageSurface->Data();
data.SysMemPitch = imageSurface->Stride();

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=2 ts=2 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Girard <bgirard@mozilla.com>
* Ali Juma <ajuma@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "CompositorChild.h"
#include "CompositorParent.h"
#include "LayerManagerOGL.h"
#include "mozilla/layers/ShadowLayersChild.h"
using mozilla::layers::ShadowLayersChild;
namespace mozilla {
namespace layers {
CompositorChild::CompositorChild(LayerManager *aLayerManager)
: mLayerManager(aLayerManager)
{
MOZ_COUNT_CTOR(CompositorChild);
}
CompositorChild::~CompositorChild()
{
MOZ_COUNT_DTOR(CompositorChild);
}
void
CompositorChild::Destroy()
{
mLayerManager = NULL;
size_t numChildren = ManagedPLayersChild().Length();
NS_ABORT_IF_FALSE(0 == numChildren || 1 == numChildren,
"compositor must only have 0 or 1 layer forwarder");
if (numChildren) {
ShadowLayersChild* layers =
static_cast<ShadowLayersChild*>(ManagedPLayersChild()[0]);
layers->Destroy();
}
SendStop();
}
PLayersChild*
CompositorChild::AllocPLayers(const LayersBackend &backend)
{
return new ShadowLayersChild();
}
bool
CompositorChild::DeallocPLayers(PLayersChild* actor)
{
delete actor;
return true;
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,73 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Girard <bgirard@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_layers_CompositorChild_h
#define mozilla_layers_CompositorChild_h
#include "mozilla/layers/PCompositorChild.h"
namespace mozilla {
namespace layers {
class LayerManager;
class CompositorParent;
class CompositorChild : public PCompositorChild
{
NS_INLINE_DECL_REFCOUNTING(CompositorChild)
public:
CompositorChild(LayerManager *aLayerManager);
virtual ~CompositorChild();
void Destroy();
protected:
virtual PLayersChild* AllocPLayers(const LayersBackend &aBackend);
virtual bool DeallocPLayers(PLayersChild *aChild);
private:
nsRefPtr<LayerManager> mLayerManager;
DISALLOW_EVIL_CONSTRUCTORS(CompositorChild);
};
} // layers
} // mozilla
#endif // mozilla_layers_CompositorChild_h

View File

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=2 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Girard <bgirard@mozilla.com>
* Ali Juma <ajuma@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "CompositorParent.h"
#include "CompositorCocoaWidgetHelper.h"
#include "nsDebug.h"
namespace mozilla {
namespace layers {
namespace compositor {
LayerManager*
GetLayerManager(CompositorParent* aParent)
{
return aParent->GetLayerManager();
}
}
}
}

View File

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Girard <bgirard@mozilla.com>
* Ali Juma <ajuma@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_layers_CompositorCocoaWidgetHelper_h
#define mozilla_layers_CompositorCocoaWidgetHelper_h
// Note we can't include IPDL-generated headers here, since this file is being
// used as a workaround for Bug 719036.
namespace mozilla {
namespace layers {
class CompositorParent;
class LayerManager;
namespace compositor {
// Needed when we cannot directly include CompositorParent.h since it includes
// an IPDL-generated header (e.g. in widget/cocoa/nsChildView.mm; see Bug 719036).
LayerManager* GetLayerManager(CompositorParent* aParent);
}
}
}
#endif // mozilla_layers_CompositorCocoaWidgetHelper_h

View File

@ -0,0 +1,159 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=2 ts=2 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Girard <bgirard@mozilla.com>
* Ali Juma <ajuma@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "CompositorParent.h"
#include "ShadowLayersParent.h"
#include "LayerManagerOGL.h"
#include "nsIWidget.h"
namespace mozilla {
namespace layers {
CompositorParent::CompositorParent(nsIWidget* aWidget)
: mStopped(false), mWidget(aWidget)
{
MOZ_COUNT_CTOR(CompositorParent);
}
CompositorParent::~CompositorParent()
{
MOZ_COUNT_DTOR(CompositorParent);
}
void
CompositorParent::Destroy()
{
NS_ABORT_IF_FALSE(ManagedPLayersParent().Length() == 0,
"CompositorParent destroyed before managed PLayersParent");
// Ensure that the layer manager is destroyed on the compositor thread.
mLayerManager = NULL;
}
bool
CompositorParent::RecvStop()
{
mStopped = true;
Destroy();
return true;
}
void
CompositorParent::ScheduleComposition()
{
CancelableTask *composeTask = NewRunnableMethod(this, &CompositorParent::Composite);
MessageLoop::current()->PostTask(FROM_HERE, composeTask);
}
void
CompositorParent::Composite()
{
if (mStopped || !mLayerManager) {
return;
}
mLayerManager->EndEmptyTransaction();
}
// Go down shadow layer tree, setting properties to match their non-shadow
// counterparts.
static void
SetShadowProperties(Layer* aLayer)
{
// FIXME: Bug 717688 -- Do these updates in ShadowLayersParent::RecvUpdate.
ShadowLayer* shadow = aLayer->AsShadowLayer();
shadow->SetShadowTransform(aLayer->GetTransform());
shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
shadow->SetShadowClipRect(aLayer->GetClipRect());
for (Layer* child = aLayer->GetFirstChild();
child; child = child->GetNextSibling()) {
SetShadowProperties(child);
}
}
void
CompositorParent::ShadowLayersUpdated()
{
const nsTArray<PLayersParent*>& shadowParents = ManagedPLayersParent();
NS_ABORT_IF_FALSE(shadowParents.Length() <= 1,
"can only support at most 1 ShadowLayersParent");
if (shadowParents.Length()) {
Layer* root = static_cast<ShadowLayersParent*>(shadowParents[0])->GetRoot();
mLayerManager->SetRoot(root);
SetShadowProperties(root);
}
ScheduleComposition();
}
PLayersParent*
CompositorParent::AllocPLayers(const LayersBackend &backendType)
{
if (backendType == LayerManager::LAYERS_OPENGL) {
nsRefPtr<LayerManagerOGL> layerManager = new LayerManagerOGL(mWidget);
mWidget = NULL;
mLayerManager = layerManager;
if (!layerManager->Initialize()) {
NS_ERROR("Failed to init OGL Layers");
return NULL;
}
ShadowLayerManager* slm = layerManager->AsShadowManager();
if (!slm) {
return NULL;
}
return new ShadowLayersParent(slm, this);
} else {
NS_ERROR("Unsupported backend selected for Async Compositor");
return NULL;
}
}
bool
CompositorParent::DeallocPLayers(PLayersParent* actor)
{
delete actor;
return true;
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Girard <bgirard@mozilla.com>
* Ali Juma <ajuma@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_layers_CompositorParent_h
#define mozilla_layers_CompositorParent_h
#include "mozilla/layers/PCompositorParent.h"
#include "mozilla/layers/PLayersParent.h"
#include "ShadowLayersManager.h"
class nsIWidget;
namespace mozilla {
namespace layers {
class LayerManager;
class CompositorParent : public PCompositorParent,
public ShadowLayersManager
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorParent)
public:
CompositorParent(nsIWidget* aWidget);
virtual ~CompositorParent();
virtual bool RecvStop() MOZ_OVERRIDE;
virtual void ShadowLayersUpdated() MOZ_OVERRIDE;
void Destroy();
LayerManager* GetLayerManager() { return mLayerManager; }
protected:
virtual PLayersParent* AllocPLayers(const LayersBackend &backendType);
virtual bool DeallocPLayers(PLayersParent* aLayers);
private:
void ScheduleComposition();
void Composite();
nsRefPtr<LayerManager> mLayerManager;
bool mStopped;
nsIWidget* mWidget;
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
};
} // layers
} // mozilla
#endif // mozilla_layers_CompositorParent_h

View File

@ -0,0 +1,71 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Code.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Benoit Girard <bgirard@mozilla.com>
* Ali Juma <ajuma@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
include protocol PLayers;
using mozilla::LayersBackend;
using mozilla::null_t;
namespace mozilla {
namespace layers {
/**
* The PCompositor protocol is used to manage communication between
* the main thread and the compositor thread context. It's primary
* purpose is to manage the PLayers sub protocol.
*/
// This should really be 'sync', but we're using 'rpc' as a workaround
// for Bug 716631.
rpc protocol PCompositor
{
// A Compositor manages a single Layer Manager (PLayers)
manages PLayers;
parent:
// Clean up in preparation for destruction.
sync Stop();
sync PLayers(LayersBackend backend);
};
} // layers
} // mozilla

View File

@ -38,7 +38,7 @@
*
* ***** END LICENSE BLOCK ***** */
//include protocol PCompositor;
include protocol PCompositor;
include protocol PLayer;
include protocol PRenderFrame;
@ -226,7 +226,7 @@ union EditReply {
sync protocol PLayers {
manager PRenderFrame /*or PCompositor or PMedia or PPlugin*/;
manager PRenderFrame or PCompositor;
manages PLayer;
parent:

View File

@ -0,0 +1,63 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=80 : */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Content App.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ali Juma <ajuma@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef mozilla_layers_ShadowLayersManager_h
#define mozilla_layers_ShadowLayersManager_h
namespace mozilla {
namespace layout {
class RenderFrameParent;
}
namespace layers {
class CompositorParent;
class ShadowLayersManager
{
public:
virtual void ShadowLayersUpdated() = 0;
};
} // layers
} // mozilla
#endif // mozilla_layers_ShadowLayersManager_h

View File

@ -47,6 +47,7 @@
#include "mozilla/unused.h"
#include "mozilla/layout/RenderFrameParent.h"
#include "CompositorParent.h"
#include "gfxSharedImageSurface.h"
@ -121,11 +122,11 @@ ShadowChild(const OpRemoveChild& op)
//--------------------------------------------------
// ShadowLayersParent
ShadowLayersParent::ShadowLayersParent(ShadowLayerManager* aManager)
: mDestroyed(false)
ShadowLayersParent::ShadowLayersParent(ShadowLayerManager* aManager,
ShadowLayersManager* aLayersManager)
: mLayerManager(aManager), mShadowLayersManager(aLayersManager), mDestroyed(false)
{
MOZ_COUNT_CTOR(ShadowLayersParent);
mLayerManager = aManager;
}
ShadowLayersParent::~ShadowLayersParent()
@ -382,7 +383,7 @@ ShadowLayersParent::RecvUpdate(const InfallibleTArray<Edit>& cset,
// other's buffer contents.
ShadowLayerManager::PlatformSyncBeforeReplyUpdate();
Frame()->ShadowLayersUpdated();
mShadowLayersManager->ShadowLayersUpdated();
return true;
}
@ -400,12 +401,6 @@ ShadowLayersParent::DeallocPLayer(PLayerParent* actor)
return true;
}
RenderFrameParent*
ShadowLayersParent::Frame()
{
return static_cast<RenderFrameParent*>(Manager());
}
void
ShadowLayersParent::DestroySharedSurface(gfxSharedImageSurface* aSurface)
{

View File

@ -43,6 +43,7 @@
#include "mozilla/layers/PLayersParent.h"
#include "ShadowLayers.h"
#include "ShadowLayersManager.h"
namespace mozilla {
@ -63,7 +64,7 @@ class ShadowLayersParent : public PLayersParent,
typedef InfallibleTArray<EditReply> EditReplyArray;
public:
ShadowLayersParent(ShadowLayerManager* aManager);
ShadowLayersParent(ShadowLayerManager* aManager, ShadowLayersManager* aLayersManager);
~ShadowLayersParent();
void Destroy();
@ -83,9 +84,8 @@ protected:
NS_OVERRIDE virtual bool DeallocPLayer(PLayerParent* actor);
private:
RenderFrameParent* Frame();
nsRefPtr<ShadowLayerManager> mLayerManager;
ShadowLayersManager* mShadowLayersManager;
// Hold the root because it might be grafted under various
// containers in the "real" layer tree
nsRefPtr<ContainerLayer> mRoot;

View File

@ -1,4 +1,5 @@
IPDLSRCS = \
PCompositor.ipdl \
PLayer.ipdl \
PLayers.ipdl \
$(NULL)

View File

@ -1410,8 +1410,6 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
continue;
}
aClip.RemoveRoundedCorners();
// Just use its layer.
nsRefPtr<Layer> ownLayer = item->BuildLayer(mBuilder, mManager, mParameters);
if (!ownLayer) {
@ -1435,10 +1433,13 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
NS_ASSERTION(!ownLayer->HasUserData(&gLayerManagerUserData),
"We shouldn't have a FrameLayerBuilder-managed layer here!");
NS_ASSERTION(aClip.mHaveClipRect ||
aClip.mRoundedClipRects.IsEmpty(),
"If we have rounded rects, we must have a clip rect");
// It has its own layer. Update that layer's clip and visible rects.
if (aClip.mHaveClipRect) {
ownLayer->IntersectClipRect(
aClip.mClipRect.ScaleToNearestPixels(
aClip.NonRoundedIntersection().ScaleToNearestPixels(
mParameters.mXScale, mParameters.mYScale, appUnitsPerDevPixel));
}
ThebesLayerData* data = GetTopThebesLayerData();
@ -2364,7 +2365,6 @@ FrameLayerBuilder::Clip::IsRectClippedByRoundedCorner(const nsRect& aRect) const
nsRect
FrameLayerBuilder::Clip::NonRoundedIntersection() const
{
NS_ASSERTION(!mRoundedClipRects.IsEmpty(), "no rounded clip rects?");
nsRect result = mClipRect;
for (PRUint32 i = 0, iEnd = mRoundedClipRects.Length();
i < iEnd; ++i) {

View File

@ -648,7 +648,7 @@ RenderFrameParent::AllocPLayers(LayerManager::LayersBackend* aBackendType)
return nsnull;
}
*aBackendType = lm->GetBackendType();
return new ShadowLayersParent(slm);
return new ShadowLayersParent(slm, this);
}
bool

View File

@ -42,6 +42,7 @@
#define mozilla_layout_RenderFrameParent_h
#include "mozilla/layout/PRenderFrameParent.h"
#include "mozilla/layers/ShadowLayersManager.h"
#include <map>
#include "nsDisplayList.h"
@ -59,7 +60,8 @@ class ShadowLayersParent;
namespace layout {
class RenderFrameParent : public PRenderFrameParent
class RenderFrameParent : public PRenderFrameParent,
public mozilla::layers::ShadowLayersManager
{
typedef mozilla::layers::FrameMetrics FrameMetrics;
typedef mozilla::layers::ContainerLayer ContainerLayer;
@ -84,7 +86,7 @@ public:
void ContentViewScaleChanged(nsContentView* aView);
void ShadowLayersUpdated();
virtual void ShadowLayersUpdated() MOZ_OVERRIDE;
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
nsSubDocumentFrame* aFrame,

View File

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title>Rounded rectangle clipping test</title>
<style>
.clipround {
left:100px;
top:100px;
position:absolute;
width:700px;
height:380px;
overflow:hidden;
border-radius:45px;
}
.greendiv {
width:300px;
height:230px;
background-color:#008000;
position:absolute;
}
#nrcDiv0 {
left:0px;
top:0px;
}
#nrcDiv1 {
left:320px;
top:0px;
}
#nrcDiv2 {
left:0px;
top:240px;
}
</style>
</head>
<body>
<div class="clipround">
<div id="nrcDiv0" class="greendiv"></div>
</div>
<div class="clipround">
<div id="nrcDiv1" class="greendiv"></div>
</div>
<div class="clipround">
<div id="nrcDiv2" class="greendiv"></div>
</div>
</body>
</html>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<title>Rounded rectangle clipping test</title>
<style>
.clipround {
left:100px;
top:100px;
position:absolute;
width:700px;
height:380px;
overflow:hidden;
border-radius:45px;
}
canvas {
position:absolute;
}
#nrcCanvas0 {
left:0px;
top:0px;
}
#nrcCanvas1 {
left:320px;
top:0px;
}
#nrcCanvas2 {
left:0px;
top:240px;
}
</style>
</head>
<body>
<div class="clipround">
<canvas id="nrcCanvas0" width="320" height="260"></canvas>
<canvas id="nrcCanvas1" width="320" height="260"></canvas>
<canvas id="nrcCanvas2" width="320" height="260"></canvas>
</div>
<script>
drawShapes('nrcCanvas0');
drawShapes('nrcCanvas1');
drawShapes('nrcCanvas2');
function drawShapes(elName) {
var ctxt = document.getElementById(elName).getContext('2d');
ctxt.fillStyle = '#008000';
ctxt.fillRect(0, 0, 300, 230);
}
</script>
</body>
</html>

View File

@ -1688,3 +1688,4 @@ needs-focus != 703186-1.html 703186-2.html
== 714519-1-q.html 714519-1-ref.html
== 714519-2-as.html 714519-2-ref.html
== 714519-2-q.html 714519-2-ref.html
fuzzy == 718521.html 718521-ref.html

View File

@ -173,7 +173,7 @@ public class AboutHomeContent extends ScrollView {
activity.stopManagingCursor(mCursor);
ContentResolver resolver = GeckoApp.mAppContext.getContentResolver();
mCursor = BrowserDB.filter(resolver, "", NUMBER_OF_TOP_SITES_PORTRAIT, "about:%");
mCursor = BrowserDB.getTopSites(resolver, NUMBER_OF_TOP_SITES_PORTRAIT);
activity.startManagingCursor(mCursor);
mTopSitesAdapter = new TopSitesCursorAdapter(activity,

View File

@ -893,7 +893,8 @@ abstract public class GeckoApp
if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
Log.i(LOGTAG, "Got a document start");
handleDocumentStart(tabId);
final boolean showProgress = message.getBoolean("showProgress");
handleDocumentStart(tabId, showProgress);
} else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
Log.i(LOGTAG, "Got a document stop");
handleDocumentStop(tabId);
@ -1181,7 +1182,7 @@ abstract public class GeckoApp
});
}
void handleDocumentStart(int tabId) {
void handleDocumentStart(int tabId, final boolean showProgress) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
@ -1193,7 +1194,8 @@ abstract public class GeckoApp
public void run() {
if (Tabs.getInstance().isSelectedTab(tab)) {
mBrowserToolbar.setSecurityMode(tab.getSecurityMode());
mBrowserToolbar.setProgressVisibility(true);
if (showProgress)
mBrowserToolbar.setProgressVisibility(true);
}
onTabsChanged(tab);
}
@ -2099,9 +2101,10 @@ abstract public class GeckoApp
File profileDir = getProfileDir();
if (profileDir != null) {
Log.i(LOGTAG, "checking profile migration in: " + profileDir.getAbsolutePath());
final GeckoApp app = GeckoApp.mAppContext;
GeckoAppShell.ensureSQLiteLibsLoaded(app.getApplication().getPackageResourcePath());
ProfileMigrator profileMigrator =
new ProfileMigrator(GeckoApp.mAppContext.getContentResolver(),
profileDir);
new ProfileMigrator(app.getContentResolver(), profileDir);
profileMigrator.launchBackground();
}
}

View File

@ -112,6 +112,7 @@ public class GeckoAppShell
static private int sFreeSpace = -1;
static File sHomeDir = null;
static private int sDensityDpi = 0;
private static Boolean sSQLiteLibsLoaded = false;
private static HashMap<String, ArrayList<GeckoEventListener>> mEventListeners;
@ -129,7 +130,8 @@ public class GeckoAppShell
public static native void onLowMemory();
public static native void callObserver(String observerKey, String topic, String data);
public static native void removeObserver(String observerKey);
public static native void loadLibs(String apkName, boolean shouldExtract);
public static native void loadGeckoLibsNative(String apkName);
public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
public static native void onChangeNetworkLinkStatus(String status);
public static native void reportJavaCrash(String stack);
public static void notifyUriVisited(String uri) {
@ -310,7 +312,7 @@ public class GeckoAppShell
}
// java-side stuff
public static void loadGeckoLibs(String apkName) {
public static boolean loadLibsSetup(String apkName) {
// The package data lib directory isn't placed in ld.so's
// search path, so we have to manually load libraries that
// libxul will depend on. Not ideal.
@ -415,7 +417,23 @@ public class GeckoAppShell
}
}
}
loadLibs(apkName, extractLibs);
return extractLibs;
}
public static void ensureSQLiteLibsLoaded(String apkName) {
if (sSQLiteLibsLoaded)
return;
synchronized(sSQLiteLibsLoaded) {
if (sSQLiteLibsLoaded)
return;
loadSQLiteLibsNative(apkName, loadLibsSetup(apkName));
sSQLiteLibsLoaded = true;
}
}
public static void loadGeckoLibs(String apkName) {
boolean extractLibs = loadLibsSetup(apkName);
loadGeckoLibsNative(apkName);
}
private static void putLocaleEnv() {

View File

@ -86,8 +86,9 @@ public class GeckoThread extends Thread {
// At some point while loading the gecko libs our default locale gets set
// so just save it to locale here and reset it as default after the join
Locale locale = Locale.getDefault();
GeckoAppShell.loadGeckoLibs(
app.getApplication().getPackageResourcePath());
String resourcePath = app.getApplication().getPackageResourcePath();
GeckoAppShell.ensureSQLiteLibsLoaded(resourcePath);
GeckoAppShell.loadGeckoLibs(resourcePath);
Locale.setDefault(locale);
Resources res = app.getBaseContext().getResources();
Configuration config = res.getConfiguration();

View File

@ -89,6 +89,9 @@ FENNEC_JAVA_FILES = \
LinkPreference.java \
ProfileMigrator.java \
PromptService.java \
sqlite/ByteBufferInputStream.java \
sqlite/SQLiteBridge.java \
sqlite/SQLiteBridgeException.java \
SurfaceLockInfo.java \
Tab.java \
Tabs.java \

View File

@ -15,7 +15,7 @@
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009-2010
* Portions created by the Initial Developer are Copyright (C) 2011-2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
@ -38,24 +38,22 @@
package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.sqlite.ByteBufferInputStream;
import org.mozilla.gecko.sqlite.SQLiteBridge;
import org.mozilla.gecko.sqlite.SQLiteBridgeException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteStatement;
import android.content.ContentResolver;
import android.database.Cursor;
import android.database.SQLException;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.provider.Browser;
import android.util.Log;
import android.webkit.WebIconDatabase;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.File;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
@ -70,7 +68,6 @@ public class ProfileMigrator {
private static final String LOGTAG = "ProfMigr";
private File mProfileDir;
private ContentResolver mCr;
private SQLiteDatabase mDb;
/*
Amount of Android history entries we will remember
@ -82,32 +79,32 @@ public class ProfileMigrator {
These queries are derived from the low-level Places schema
https://developer.mozilla.org/en/The_Places_database
*/
final String bookmarkQuery = "SELECT places.url AS a_url, "
private final String bookmarkQuery = "SELECT places.url AS a_url, "
+ "places.title AS a_title FROM "
+ "(moz_places as places JOIN moz_bookmarks as bookmarks ON "
+ "places.id = bookmarks.fk) WHERE places.hidden <> 1 "
+ "ORDER BY bookmarks.dateAdded";
// Don't ask why. Just curse along at the Android devs.
final String bookmarkUrl = "a_url";
final String bookmarkTitle = "a_title";
// Result column of relevant data
private final String bookmarkUrl = "a_url";
private final String bookmarkTitle = "a_title";
final String historyQuery =
private final String historyQuery =
"SELECT places.url AS a_url, places.title AS a_title, "
+ "history.visit_date AS a_date FROM "
+ "(moz_historyvisits AS history JOIN moz_places AS places ON "
+ "places.id = history.place_id) WHERE places.hidden <> 1 "
+ "ORDER BY history.visit_date DESC";
final String historyUrl = "a_url";
final String historyTitle = "a_title";
final String historyDate = "a_date";
private final String historyUrl = "a_url";
private final String historyTitle = "a_title";
private final String historyDate = "a_date";
final String faviconQuery =
private final String faviconQuery =
"SELECT places.url AS a_url, favicon.data AS a_data, "
+ "favicon.mime_type AS a_mime FROM (moz_places AS places JOIN "
+ "moz_favicons AS favicon ON places.favicon_id = favicon.id)";
final String faviconUrl = "a_url";
final String faviconData = "a_data";
final String faviconMime = "a_mime";
private final String faviconUrl = "a_url";
private final String faviconData = "a_data";
private final String faviconMime = "a_mime";
public ProfileMigrator(ContentResolver cr, File profileDir) {
mProfileDir = profileDir;
@ -116,12 +113,8 @@ public class ProfileMigrator {
public void launchBackground() {
// Work around http://code.google.com/p/android/issues/detail?id=11291
// The WebIconDatabase needs to be initialized within the UI thread so
// just request the instance here.
WebIconDatabase.getInstance();
PlacesTask placesTask = new PlacesTask();
new Thread(placesTask).start();
// WebIconDatabase needs to be initialized within a looper thread.
GeckoAppShell.getHandler().post(new PlacesTask());
}
private class PlacesTask implements Runnable {
@ -177,37 +170,24 @@ public class ProfileMigrator {
}
}
protected void migrateHistory(SQLiteDatabase db) {
protected void migrateHistory(SQLiteBridge db) {
Map<String, Long> androidHistory = gatherAndroidHistory();
final ArrayList<String> placesHistory = new ArrayList<String>();
Cursor cursor = null;
try {
cursor =
db.rawQuery(historyQuery, new String[] { });
final int urlCol =
cursor.getColumnIndexOrThrow(historyUrl);
final int titleCol =
cursor.getColumnIndexOrThrow(historyTitle);
final int dateCol =
cursor.getColumnIndexOrThrow(historyDate);
ArrayList<Object[]> queryResult = db.query(historyQuery);
final int urlCol = db.getColumnIndex(historyUrl);
final int titleCol = db.getColumnIndex(historyTitle);
final int dateCol = db.getColumnIndex(historyDate);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String url = cursor.getString(urlCol);
String title = cursor.getString(titleCol);
// Convert from us (Places) to ms (Java, Android)
long date = cursor.getLong(dateCol) / (long)1000;
for (Object[] resultRow: queryResult) {
String url = (String)resultRow[urlCol];
String title = (String)resultRow[titleCol];
long date = Long.parseLong((String)(resultRow[dateCol])) / (long)1000;
addHistory(androidHistory, url, title, date);
placesHistory.add(url);
cursor.moveToNext();
}
cursor.close();
} catch (SQLiteException e) {
if (cursor != null) {
cursor.close();
}
} catch (SQLiteBridgeException e) {
Log.i(LOGTAG, "Failed to get bookmarks: " + e.getMessage());
return;
}
@ -231,90 +211,55 @@ public class ProfileMigrator {
}
}
protected void migrateBookmarks(SQLiteDatabase db) {
Cursor cursor = null;
protected void migrateBookmarks(SQLiteBridge db) {
try {
cursor = db.rawQuery(bookmarkQuery,
new String[] {});
if (cursor.getCount() > 0) {
final int urlCol =
cursor.getColumnIndexOrThrow(bookmarkUrl);
final int titleCol =
cursor.getColumnIndexOrThrow(bookmarkTitle);
ArrayList<Object[]> queryResult = db.query(bookmarkQuery);
final int urlCol = db.getColumnIndex(bookmarkUrl);
final int titleCol = db.getColumnIndex(bookmarkTitle);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String url = cursor.getString(urlCol);
String title = cursor.getString(titleCol);
addBookmark(url, title);
cursor.moveToNext();
}
}
cursor.close();
} catch (SQLiteException e) {
if (cursor != null) {
cursor.close();
for (Object[] resultRow: queryResult) {
String url = (String)resultRow[urlCol];
String title = (String)resultRow[titleCol];
addBookmark(url, title);
}
} catch (SQLiteBridgeException e) {
Log.i(LOGTAG, "Failed to get bookmarks: " + e.getMessage());
return;
}
}
protected void addFavicon(String url, String mime, byte[] data) {
ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
protected void addFavicon(String url, String mime, ByteBuffer data) {
ByteBufferInputStream byteStream = new ByteBufferInputStream(data);
BitmapDrawable image = (BitmapDrawable) Drawable.createFromStream(byteStream, "src");
if (image != null) {
try {
BrowserDB.updateFaviconForUrl(mCr, url, image);
} catch (SQLiteException e) {
} catch (SQLException e) {
Log.i(LOGTAG, "Migrating favicon failed: " + mime + " URL: " + url
+ " error:" + e.getMessage());
}
}
}
protected void migrateFavicons(SQLiteDatabase db) {
Cursor cursor = null;
protected void migrateFavicons(SQLiteBridge db) {
try {
cursor = db.rawQuery(faviconQuery,
new String[] {});
if (cursor.getCount() > 0) {
final int urlCol =
cursor.getColumnIndexOrThrow(faviconUrl);
final int dataCol =
cursor.getColumnIndexOrThrow(faviconData);
final int mimeCol =
cursor.getColumnIndexOrThrow(faviconMime);
ArrayList<Object[]> queryResult = db.query(faviconQuery);
final int urlCol = db.getColumnIndex(faviconUrl);
final int mimeCol = db.getColumnIndex(faviconMime);
final int dataCol = db.getColumnIndex(faviconData);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String url = cursor.getString(urlCol);
String mime = cursor.getString(mimeCol);
byte[] data = cursor.getBlob(dataCol);
addFavicon(url, mime, data);
cursor.moveToNext();
}
}
cursor.close();
} catch (SQLiteException e) {
if (cursor != null) {
cursor.close();
for (Object[] resultRow: queryResult) {
String url = (String)resultRow[urlCol];
String mime = (String)resultRow[mimeCol];
ByteBuffer dataBuff = (ByteBuffer)resultRow[dataCol];
addFavicon(url, mime, dataBuff);
}
} catch (SQLiteBridgeException e) {
Log.i(LOGTAG, "Failed to get favicons: " + e.getMessage());
return;
}
}
SQLiteDatabase openPlaces(String dbPath) throws SQLiteException {
/* http://stackoverflow.com/questions/2528489/no-such-table-android-metadata-whats-the-problem */
SQLiteDatabase db = SQLiteDatabase.openDatabase(dbPath,
null,
SQLiteDatabase.OPEN_READONLY |
SQLiteDatabase.NO_LOCALIZED_COLLATORS);
return db;
}
protected void migratePlaces(File aFile) {
String dbPath = aFile.getPath() + "/places.sqlite";
String dbPathWal = aFile.getPath() + "/places.sqlite-wal";
@ -329,9 +274,9 @@ public class ProfileMigrator {
File dbFileWal = new File(dbPathWal);
File dbFileShm = new File(dbPathShm);
SQLiteDatabase db = null;
SQLiteBridge db = null;
try {
db = openPlaces(dbPath);
db = new SQLiteBridge(dbPath);
migrateBookmarks(db);
migrateHistory(db);
migrateFavicons(db);
@ -343,7 +288,7 @@ public class ProfileMigrator {
dbFileShm.delete();
Log.i(LOGTAG, "Profile migration finished");
} catch (SQLiteException e) {
} catch (SQLiteBridgeException e) {
if (db != null) {
db.close();
}

View File

@ -63,13 +63,9 @@ public class AndroidBrowserDB implements BrowserDB.BrowserDBIface {
private static final Uri BOOKMARKS_CONTENT_URI_POST_11 = Uri.parse("content://com.android.browser/bookmarks");
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter) {
private Cursor filterAllSites(ContentResolver cr, String[] projection, CharSequence constraint, int limit, CharSequence urlFilter) {
Cursor c = cr.query(Browser.BOOKMARKS_URI,
new String[] { URL_COLUMN_ID,
BookmarkColumns.URL,
BookmarkColumns.TITLE,
BookmarkColumns.FAVICON,
URL_COLUMN_THUMBNAIL },
projection,
// The length restriction on URL is for the same reason as in the general bookmark query
// (see comment earlier in this file).
(urlFilter != null ? "(" + Browser.BookmarkColumns.URL + " NOT LIKE ? ) AND " : "" ) +
@ -86,6 +82,28 @@ public class AndroidBrowserDB implements BrowserDB.BrowserDBIface {
return new AndroidDBCursor(c);
}
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
return filterAllSites(cr,
new String[] { URL_COLUMN_ID,
BookmarkColumns.URL,
BookmarkColumns.TITLE,
BookmarkColumns.FAVICON },
constraint,
limit,
null);
}
public Cursor getTopSites(ContentResolver cr, int limit) {
return filterAllSites(cr,
new String[] { URL_COLUMN_ID,
BookmarkColumns.URL,
BookmarkColumns.TITLE,
URL_COLUMN_THUMBNAIL },
"",
limit,
BrowserDB.ABOUT_PAGES_URL_FILTER);
}
public void updateVisitedHistory(ContentResolver cr, String uri) {
Browser.updateVisitedHistory(cr, uri, true);
}

View File

@ -42,6 +42,8 @@ import android.database.Cursor;
import android.graphics.drawable.BitmapDrawable;
public class BrowserDB {
public static String ABOUT_PAGES_URL_FILTER = "about:%";
public static interface URLColumns {
public static String URL = "url";
public static String TITLE = "title";
@ -53,7 +55,9 @@ public class BrowserDB {
private static BrowserDBIface sDb;
public interface BrowserDBIface {
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter);
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit);
public Cursor getTopSites(ContentResolver cr, int limit);
public void updateVisitedHistory(ContentResolver cr, String uri);
@ -87,12 +91,12 @@ public class BrowserDB {
sDb = new LocalBrowserDB(BrowserContract.DEFAULT_PROFILE);
}
public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter) {
return sDb.filter(cr, constraint, limit, urlFilter);
public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
return sDb.filter(cr, constraint, limit);
}
public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
return sDb.filter(cr, constraint, limit, null);
public static Cursor getTopSites(ContentResolver cr, int limit) {
return sDb.getTopSites(cr, limit);
}
public static void updateVisitedHistory(ContentResolver cr, String uri) {

View File

@ -80,13 +80,9 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
return uri.buildUpon().appendQueryParameter(BrowserContract.PARAM_PROFILE, mProfile).build();
}
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit, CharSequence urlFilter) {
private Cursor filterAllSites(ContentResolver cr, String[] projection, CharSequence constraint, int limit, CharSequence urlFilter) {
Cursor c = cr.query(appendProfileAndLimit(History.CONTENT_URI, limit),
new String[] { History._ID,
History.URL,
History.TITLE,
History.FAVICON,
History.THUMBNAIL },
projection,
(urlFilter != null ? "(" + History.URL + " NOT LIKE ? ) AND " : "" ) +
"(" + History.URL + " LIKE ? OR " + History.TITLE + " LIKE ?)",
urlFilter == null ? new String[] {"%" + constraint.toString() + "%", "%" + constraint.toString() + "%"} :
@ -100,6 +96,28 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
return new LocalDBCursor(c);
}
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
return filterAllSites(cr,
new String[] { History._ID,
History.URL,
History.TITLE,
History.FAVICON },
constraint,
limit,
null);
}
public Cursor getTopSites(ContentResolver cr, int limit) {
return filterAllSites(cr,
new String[] { History._ID,
History.URL,
History.TITLE,
History.THUMBNAIL },
"",
limit,
BrowserDB.ABOUT_PAGES_URL_FILTER);
}
private void truncateHistory(ContentResolver cr) {
Cursor cursor = null;

View File

@ -12,7 +12,7 @@
android:paddingLeft="15dip"
android:paddingRight="40dip"
android:hint="@string/awesomebar_default_text"
android:inputType="textUri"
android:inputType="textUri|textNoSuggestions"
android:imeOptions="actionSearch"
android:singleLine="true"
android:gravity="center_vertical|left">

View File

@ -0,0 +1,71 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011-2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko.sqlite;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
/*
* Helper class to make the ByteBuffers returned by SQLite BLOB
* easier to use.
*/
public class ByteBufferInputStream extends InputStream {
private ByteBuffer mByteBuffer;
public ByteBufferInputStream(ByteBuffer aByteBuffer) {
mByteBuffer = aByteBuffer;
}
@Override
public synchronized int read() throws IOException {
if (!mByteBuffer.hasRemaining()) {
return -1;
}
return mByteBuffer.get();
}
@Override
public synchronized int read(byte[] aBytes, int aOffset, int aLen)
throws IOException {
int toRead = Math.min(aLen, mByteBuffer.remaining());
mByteBuffer.get(aBytes, aOffset, toRead);
return toRead;
}
}

View File

@ -0,0 +1,101 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko.sqlite;
import org.mozilla.gecko.sqlite.SQLiteBridgeException;
import android.util.Log;
import java.lang.String;
import java.util.ArrayList;
import java.util.HashMap;
/*
* This class allows using the mozsqlite3 library included with Firefox
* to read SQLite databases, instead of the Android SQLiteDataBase API,
* which might use whatever outdated DB is present on the Android system.
*/
public class SQLiteBridge {
private static final String LOGTAG = "SQLiteBridge";
// Path to the database. We reopen it every query.
private String mDb;
// Remember column names from last query result.
private ArrayList<String> mColumns;
// JNI code in $(topdir)/mozglue/android/..
private static native void sqliteCall(String aDb, String aQuery,
String[] aParams,
ArrayList<String> aColumns,
ArrayList<Object[]> aRes)
throws SQLiteBridgeException;
// Takes the path to the database we want to access.
public SQLiteBridge(String aDb) throws SQLiteBridgeException {
mDb = aDb;
}
// Do an SQL query without parameters
public ArrayList<Object[]> query(String aQuery) throws SQLiteBridgeException {
String[] params = new String[0];
return query(aQuery, params);
}
// Do an SQL query, substituting the parameters in the query with the passed
// parameters. The parameters are subsituded in order, so named parameters
// are not supported.
// The result is returned as an ArrayList<Object[]>, with each
// row being an entry in the ArrayList, and each column being one Object
// in the Object[] array. The columns are of type null,
// direct ByteBuffer (BLOB), or String (everything else).
public ArrayList<Object[]> query(String aQuery, String[] aParams)
throws SQLiteBridgeException {
ArrayList<Object[]> result = new ArrayList<Object[]>();
mColumns = new ArrayList<String>();
sqliteCall(mDb, aQuery, aParams, mColumns, result);
return result;
}
// Gets the index in the row Object[] for the given column name.
// Returns -1 if not found.
public int getColumnIndex(String aColumnName) {
return mColumns.lastIndexOf(aColumnName);
}
public void close() {
// nop, provided for API compatibility with SQLiteDatabase.
}
}

View File

@ -0,0 +1,47 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko.sqlite;
public class SQLiteBridgeException extends Exception {
static final long serialVersionUID = 1L;
public SQLiteBridgeException() {}
public SQLiteBridgeException(String msg) {
super(msg);
}
}

View File

@ -426,6 +426,12 @@ var BrowserApp = {
let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null;
let charset = "charset" in aParams ? aParams.charset : null;
if ("showProgress" in aParams) {
let tab = this.getTabForBrowser(aBrowser);
if (tab)
tab.showProgress = aParams.showProgress;
}
try {
aBrowser.loadURIWithFlags(aURI, flags, referrerURI, charset, postData);
} catch(e) {
@ -825,6 +831,11 @@ var BrowserApp = {
};
let url = this.getSearchOrFixupURI(data);
// Don't show progress throbber for about:home
if (url == "about:home")
params.showProgress = false;
if (aTopic == "Tab:Add")
this.addTab(url, params);
else
@ -1297,6 +1308,7 @@ function Tab(aURL, aParams) {
this.browser = null;
this.vbox = null;
this.id = 0;
this.showProgress = true;
this.create(aURL, aParams);
this._viewport = { x: 0, y: 0, width: gScreenWidth, height: gScreenHeight, offsetX: 0, offsetY: 0,
pageWidth: gScreenWidth, pageHeight: gScreenHeight, zoom: 1.0 };
@ -1368,6 +1380,9 @@ Tab.prototype = {
let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null;
let charset = "charset" in aParams ? aParams.charset : null;
// This determines whether or not we show the progress throbber in the urlbar
this.showProgress = "showProgress" in aParams ? aParams.showProgress : true;
try {
this.browser.loadURIWithFlags(aURL, flags, referrerURI, charset, postData);
} catch(e) {
@ -1749,11 +1764,14 @@ Tab.prototype = {
type: "Content:StateChange",
tabID: this.id,
uri: uri,
state: aStateFlags
state: aStateFlags,
showProgress: this.showProgress
}
};
sendMessageToJava(message);
// Reset showProgress after state change
this.showProgress = true;
}
},

View File

@ -62,6 +62,8 @@
#include <sys/time.h>
#include <sys/resource.h>
#include "Zip.h"
#include "sqlite3.h"
#include "SQLiteBridge.h"
/* Android headers don't define RUSAGE_THREAD */
#ifndef RUSAGE_THREAD
@ -284,23 +286,24 @@ SHELL_WRAPPER1(onChangeNetworkLinkStatus, jstring)
SHELL_WRAPPER1(reportJavaCrash, jstring)
SHELL_WRAPPER0(executeNextRunnable)
SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray)
SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble);
SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong);
SHELL_WRAPPER0(bindWidgetTexture);
SHELL_WRAPPER3_WITH_RETURN(saveMessageInSentbox, jint, jstring, jstring, jlong);
SHELL_WRAPPER6(notifySmsSent, jint, jstring, jstring, jlong, jint, jlong);
SHELL_WRAPPER4(notifySmsDelivered, jint, jstring, jstring, jlong);
SHELL_WRAPPER3(notifySmsSendFailed, jint, jint, jlong);
SHELL_WRAPPER7(notifyGetSms, jint, jstring, jstring, jstring, jlong, jint, jlong);
SHELL_WRAPPER3(notifyGetSmsFailed, jint, jint, jlong);
SHELL_WRAPPER3(notifySmsDeleted, jboolean, jint, jlong);
SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong);
SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong);
SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong);
SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong);
SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong);
SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble)
SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong)
SHELL_WRAPPER0(bindWidgetTexture)
SHELL_WRAPPER3_WITH_RETURN(saveMessageInSentbox, jint, jstring, jstring, jlong)
SHELL_WRAPPER6(notifySmsSent, jint, jstring, jstring, jlong, jint, jlong)
SHELL_WRAPPER4(notifySmsDelivered, jint, jstring, jstring, jlong)
SHELL_WRAPPER3(notifySmsSendFailed, jint, jint, jlong)
SHELL_WRAPPER7(notifyGetSms, jint, jstring, jstring, jstring, jlong, jint, jlong)
SHELL_WRAPPER3(notifyGetSmsFailed, jint, jint, jlong)
SHELL_WRAPPER3(notifySmsDeleted, jboolean, jint, jlong)
SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong)
SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong)
SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong)
SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong)
SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong)
static void * xul_handle = NULL;
static void * sqlite_handle = NULL;
static time_t apk_mtime = 0;
#ifdef DEBUG
extern "C" int extractLibs = 1;
@ -618,12 +621,10 @@ report_mapping(char *name, void *base, uint32_t len, uint32_t offset)
extern "C" void simple_linker_init(void);
static void
loadLibs(const char *apkName)
loadGeckoLibs(const char *apkName)
{
chdir(getenv("GRE_HOME"));
simple_linker_init();
struct stat status;
if (!stat(apkName, &status))
apk_mtime = status.st_mtime;
@ -635,7 +636,6 @@ loadLibs(const char *apkName)
Zip *zip = new Zip(apkName);
lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
#ifdef MOZ_CRASHREPORTER
file_ids = (char *)extractBuf("lib.id", zip);
#endif
@ -645,7 +645,6 @@ loadLibs(const char *apkName)
MOZLOAD("nspr4");
MOZLOAD("plc4");
MOZLOAD("plds4");
MOZLOAD("mozsqlite3");
MOZLOAD("nssutil3");
MOZLOAD("nss3");
MOZLOAD("ssl3");
@ -712,20 +711,67 @@ loadLibs(const char *apkName)
StartupTimeline_Record(LIBRARIES_LOADED, &t1);
}
extern "C" NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_loadLibs(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract)
static void loadSQLiteLibs(const char *apkName)
{
if (jShouldExtract)
extractLibs = 1;
chdir(getenv("GRE_HOME"));
simple_linker_init();
struct stat status;
if (!stat(apkName, &status))
apk_mtime = status.st_mtime;
Zip *zip = new Zip(apkName);
lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
#ifdef MOZ_CRASHREPORTER
file_ids = (char *)extractBuf("lib.id", zip);
#endif
#define MOZLOAD(name) mozload("lib" name ".so", zip)
sqlite_handle = MOZLOAD("mozsqlite3");
#undef MOZLOAD
delete zip;
#ifdef MOZ_CRASHREPORTER
free(file_ids);
file_ids = NULL;
#endif
if (!sqlite_handle)
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libmozsqlite3!");
setup_sqlite_functions(sqlite_handle);
}
extern "C" NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
{
const char* str;
// XXX: java doesn't give us true UTF8, we should figure out something
// XXX: java doesn't give us true UTF8, we should figure out something
// better to do here
str = jenv->GetStringUTFChars(jApkName, NULL);
if (str == NULL)
return;
loadLibs(str);
loadGeckoLibs(str);
jenv->ReleaseStringUTFChars(jApkName, str);
}
extern "C" NS_EXPORT void JNICALL
Java_org_mozilla_gecko_GeckoAppShell_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
if (jShouldExtract)
extractLibs = 1;
const char* str;
// XXX: java doesn't give us true UTF8, we should figure out something
// better to do here
str = jenv->GetStringUTFChars(jApkName, NULL);
if (str == NULL)
return;
loadSQLiteLibs(str);
jenv->ReleaseStringUTFChars(jApkName, str);
}
@ -745,7 +791,8 @@ ChildProcessInit(int argc, char* argv[])
}
fillLibCache(argv[argc - 1]);
loadLibs(argv[i]);
loadSQLiteLibs(argv[i]);
loadGeckoLibs(argv[i]);
// don't pass the last arg - it's only recognized by the lib cache
argc--;

View File

@ -53,10 +53,12 @@ DEFINES += \
CPPSRCS = \
nsGeckoUtils.cpp \
APKOpen.cpp \
SQLiteBridge.cpp \
$(NULL)
LOCAL_INCLUDES += -I$(srcdir)/../linker
LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/startup
LOCAL_INCLUDES += -I$(topsrcdir)/db/sqlite3/src
ifdef MOZ_OLD_LINKER
LOCAL_INCLUDES += -I$(topsrcdir)/other-licenses/android
ifeq ($(CPU_ARCH),arm)

View File

@ -0,0 +1,312 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2012
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <stdlib.h>
#include <jni.h>
#include <android/log.h>
#include "dlfcn.h"
#include "APKOpen.h"
#include "SQLiteBridge.h"
#ifdef DEBUG
#define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
#else
#define LOG(x...)
#endif
#define SQLITE_WRAPPER_INT(name) name ## _t f_ ## name;
SQLITE_WRAPPER_INT(sqlite3_open)
SQLITE_WRAPPER_INT(sqlite3_errmsg)
SQLITE_WRAPPER_INT(sqlite3_prepare_v2)
SQLITE_WRAPPER_INT(sqlite3_bind_parameter_count)
SQLITE_WRAPPER_INT(sqlite3_bind_text)
SQLITE_WRAPPER_INT(sqlite3_step)
SQLITE_WRAPPER_INT(sqlite3_column_count)
SQLITE_WRAPPER_INT(sqlite3_finalize)
SQLITE_WRAPPER_INT(sqlite3_close)
SQLITE_WRAPPER_INT(sqlite3_column_name)
SQLITE_WRAPPER_INT(sqlite3_column_type)
SQLITE_WRAPPER_INT(sqlite3_column_blob)
SQLITE_WRAPPER_INT(sqlite3_column_bytes)
SQLITE_WRAPPER_INT(sqlite3_column_text)
void setup_sqlite_functions(void *sqlite_handle)
{
#define GETFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(sqlite_handle, #name)
GETFUNC(sqlite3_open);
GETFUNC(sqlite3_errmsg);
GETFUNC(sqlite3_prepare_v2);
GETFUNC(sqlite3_bind_parameter_count);
GETFUNC(sqlite3_bind_text);
GETFUNC(sqlite3_step);
GETFUNC(sqlite3_column_count);
GETFUNC(sqlite3_finalize);
GETFUNC(sqlite3_close);
GETFUNC(sqlite3_column_name);
GETFUNC(sqlite3_column_type);
GETFUNC(sqlite3_column_blob);
GETFUNC(sqlite3_column_bytes);
GETFUNC(sqlite3_column_text);
#undef GETFUNC
}
static bool initialized = false;
static jclass stringClass;
static jclass objectClass;
static jclass byteBufferClass;
static jclass arrayListClass;
static jmethodID jByteBufferAllocateDirect;
static jmethodID jArrayListAdd;
static jobject jNull;
static void
JNI_Throw(JNIEnv* jenv, const char* name, const char* msg)
{
jclass cls = jenv->FindClass(name);
if (cls == NULL) {
LOG("Couldn't find exception class (or exception pending)\n");
return;
}
int rc = jenv->ThrowNew(cls, msg);
if (rc < 0) {
LOG("Error throwing exception\n");
}
jenv->DeleteLocalRef(cls);
}
static void
JNI_Setup(JNIEnv* jenv)
{
if (initialized) return;
objectClass = jenv->FindClass("java/lang/Object");
stringClass = jenv->FindClass("java/lang/String");
byteBufferClass = jenv->FindClass("java/nio/ByteBuffer");
arrayListClass = jenv->FindClass("java/util/ArrayList");
jNull = jenv->NewGlobalRef(NULL);
if (stringClass == NULL || objectClass == NULL
|| byteBufferClass == NULL || arrayListClass == NULL) {
LOG("Error finding classes");
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException",
"FindClass error");
return;
}
// public static ByteBuffer allocateDirect(int capacity)
jByteBufferAllocateDirect =
jenv->GetStaticMethodID(byteBufferClass, "allocateDirect", "(I)Ljava/nio/ByteBuffer;");
// boolean add(Object o)
jArrayListAdd =
jenv->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
if (jByteBufferAllocateDirect == NULL || jArrayListAdd == NULL) {
LOG("Error finding methods");
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException",
"GetMethodId error");
return;
}
initialized = true;
}
extern "C" NS_EXPORT void JNICALL
Java_org_mozilla_gecko_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
jstring jDb,
jstring jQuery,
jobjectArray jParams,
jobject jColumns,
jobject jArrayList)
{
JNI_Setup(jenv);
const char* queryStr;
queryStr = jenv->GetStringUTFChars(jQuery, NULL);
const char* dbPath;
dbPath = jenv->GetStringUTFChars(jDb, NULL);
const char *pzTail;
sqlite3_stmt *ppStmt;
sqlite3 *db;
int rc;
rc = f_sqlite3_open(dbPath, &db);
jenv->ReleaseStringUTFChars(jDb, dbPath);
if (rc != SQLITE_OK) {
LOG("Can't open database: %s\n", f_sqlite3_errmsg(db));
goto error_close;
}
rc = f_sqlite3_prepare_v2(db, queryStr, -1, &ppStmt, &pzTail);
if (rc != SQLITE_OK || ppStmt == NULL) {
LOG("Can't prepare statement: %s\n", f_sqlite3_errmsg(db));
goto error_close;
}
jenv->ReleaseStringUTFChars(jQuery, queryStr);
// Check if number of parameters matches
jsize numPars;
numPars = jenv->GetArrayLength(jParams);
int sqlNumPars;
sqlNumPars = f_sqlite3_bind_parameter_count(ppStmt);
if (numPars != sqlNumPars) {
LOG("Passed parameter count (%d) doesn't match SQL parameter count (%d)\n",
numPars, sqlNumPars);
goto error_close;
}
// Bind parameters, if any
if (numPars > 0) {
for (int i = 0; i < numPars; i++) {
jobject jObjectParam = jenv->GetObjectArrayElement(jParams, i);
// IsInstanceOf or isAssignableFrom? String is final, so IsInstanceOf
// should be OK.
jboolean isString = jenv->IsInstanceOf(jObjectParam, stringClass);
if (isString != JNI_TRUE) {
LOG("Parameter is not of String type");
goto error_close;
}
jstring jStringParam = (jstring)jObjectParam;
const char* paramStr = jenv->GetStringUTFChars(jStringParam, NULL);
// SQLite parameters index from 1.
rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT);
jenv->ReleaseStringUTFChars(jStringParam, paramStr);
if (rc != SQLITE_OK) {
LOG("Error binding query parameter");
goto error_close;
}
}
}
// Execute the query and step through the results
rc = f_sqlite3_step(ppStmt);
if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
LOG("Can't step statement: (%d) %s\n", rc, f_sqlite3_errmsg(db));
goto error_close;
}
// Get the column names
int cols;
cols = f_sqlite3_column_count(ppStmt);
for (int i = 0; i < cols; i++) {
const char* colName = f_sqlite3_column_name(ppStmt, i);
jstring jStr = jenv->NewStringUTF(colName);
jenv->CallBooleanMethod(jColumns, jArrayListAdd, jStr);
jenv->DeleteLocalRef(jStr);
}
// For each row, add an Object[] to the passed ArrayList,
// with that containing either String or ByteArray objects
// containing the columns
do {
// Process row
// Construct Object[]
jobjectArray jRow = jenv->NewObjectArray(cols,
objectClass,
NULL);
if (jRow == NULL) {
LOG("Can't allocate jRow Object[]\n");
goto error_close;
}
for (int i = 0; i < cols; i++) {
int colType = f_sqlite3_column_type(ppStmt, i);
if (colType == SQLITE_BLOB) {
// Treat as blob
const void* blob = f_sqlite3_column_blob(ppStmt, i);
int colLen = f_sqlite3_column_bytes(ppStmt, i);
// Construct ByteBuffer of correct size
jobject jByteBuffer =
jenv->CallStaticObjectMethod(byteBufferClass,
jByteBufferAllocateDirect,
colLen);
if (jByteBuffer == NULL) {
goto error_close;
}
// Get its backing array
void* bufferArray = jenv->GetDirectBufferAddress(jByteBuffer);
if (bufferArray == NULL) {
LOG("Failure calling GetDirectBufferAddress\n");
goto error_close;
}
memcpy(bufferArray, blob, colLen);
jenv->SetObjectArrayElement(jRow, i, jByteBuffer);
jenv->DeleteLocalRef(jByteBuffer);
} else if (colType == SQLITE_NULL) {
jenv->SetObjectArrayElement(jRow, i, jNull);
} else {
// Treat everything else as text
const char* txt = (const char*)f_sqlite3_column_text(ppStmt, i);
jstring jStr = jenv->NewStringUTF(txt);
jenv->SetObjectArrayElement(jRow, i, jStr);
jenv->DeleteLocalRef(jStr);
}
}
// Append Object[] to ArrayList<Object[]>
// JNI doesn't know about the generic, so use Object[] as Object
jenv->CallBooleanMethod(jArrayList, jArrayListAdd, jRow);
// Clean up
jenv->DeleteLocalRef(jRow);
// Get next row
rc = f_sqlite3_step(ppStmt);
// Real error?
if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
LOG("Can't re-step statement:(%d) %s\n", rc, f_sqlite3_errmsg(db));
goto error_close;
}
} while (rc != SQLITE_DONE);
rc = f_sqlite3_finalize(ppStmt);
if (rc != SQLITE_OK) {
LOG("Can't finalize statement: %s\n", f_sqlite3_errmsg(db));
goto error_close;
}
f_sqlite3_close(db);
return;
error_close:
f_sqlite3_close(db);
JNI_Throw(jenv, "org/mozilla/gecko/sqlite/SQLiteBridgeException", "SQLite error");
return;
}

View File

@ -0,0 +1,63 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Gian-Carlo Pascutto <gpascutto@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef SQLiteBridge_h
#define SQLiteBridge_h
#include "sqlite3.h"
void setup_sqlite_functions(void *sqlite_handle);
#define SQLITE_WRAPPER(name, return_type, args...) \
typedef return_type (*name ## _t)(args); \
extern name ## _t f_ ## name;
SQLITE_WRAPPER(sqlite3_open, int, const char*, sqlite3**)
SQLITE_WRAPPER(sqlite3_errmsg, const char*, sqlite3*)
SQLITE_WRAPPER(sqlite3_prepare_v2, int, sqlite3*, const char*, int, sqlite3_stmt**, const char**)
SQLITE_WRAPPER(sqlite3_bind_parameter_count, int, sqlite3_stmt*)
SQLITE_WRAPPER(sqlite3_bind_text, int, sqlite3_stmt*, int, const char*, int, void(*)(void*))
SQLITE_WRAPPER(sqlite3_step, int, sqlite3_stmt*)
SQLITE_WRAPPER(sqlite3_column_count, int, sqlite3_stmt*)
SQLITE_WRAPPER(sqlite3_finalize, int, sqlite3_stmt*)
SQLITE_WRAPPER(sqlite3_close, int, sqlite3*)
SQLITE_WRAPPER(sqlite3_column_name, const char*, sqlite3_stmt*, int)
SQLITE_WRAPPER(sqlite3_column_type, int, sqlite3_stmt*, int)
SQLITE_WRAPPER(sqlite3_column_blob, const void*, sqlite3_stmt*, int)
SQLITE_WRAPPER(sqlite3_column_bytes, int, sqlite3_stmt*, int)
SQLITE_WRAPPER(sqlite3_column_text, const unsigned char*, sqlite3_stmt*, int)
#endif /* SQLiteBridge_h */

View File

@ -424,6 +424,7 @@ OS_LIBS += \
-lui \
-lmedia \
-lhardware_legacy \
-lhardware \
$(NULL)
endif

View File

@ -48,9 +48,13 @@ LPCTSTR UACHelper::PrivsToDisable[] = {
SE_ASSIGNPRIMARYTOKEN_NAME,
SE_AUDIT_NAME,
SE_BACKUP_NAME,
// From testing ReadDirectoryChanges still succeeds even with a low
// integrity process with the following privilege disabled.
SE_CHANGE_NOTIFY_NAME,
// CreateProcess will succeed but the app will fail to launch on some WinXP
// machines if SE_CHANGE_NOTIFY_NAME is disabled. In particular this happens
// for limited user accounts on those machines. The define is kept here as a
// reminder that it should never be re-added.
// This permission is for directory watching but also from MSDN: "This
// privilege also causes the system to skip all traversal access checks."
// SE_CHANGE_NOTIFY_NAME,
SE_CREATE_GLOBAL_NAME,
SE_CREATE_PAGEFILE_NAME,
SE_CREATE_PERMANENT_NAME,

View File

@ -248,6 +248,77 @@ NS_IMETHODIMP nsOSHelperAppService::GetFromTypeAndExtension(const nsACString& aT
return nsExternalHelperAppService::GetFromTypeAndExtension(aType, aFileExt, aMIMEInfo);
}
// Returns the MIME types an application bundle explicitly claims to handle.
// Returns NULL if aAppRef doesn't explicitly claim to handle any MIME types.
// If the return value is non-NULL, the caller is responsible for freeing it.
// This isn't necessarily the same as the MIME types the application bundle
// is registered to handle in the Launch Services database. (For example
// the Preview application is normally registered to handle the application/pdf
// MIME type, even though it doesn't explicitly claim to handle *any* MIME
// types in its Info.plist. This is probably because Preview does explicitly
// claim to handle the com.adobe.pdf UTI, and Launch Services somehow
// translates this into a claim to support the application/pdf MIME type.
// Launch Services doesn't provide any APIs (documented or undocumented) to
// query which MIME types a given application is registered to handle. So any
// app that wants this information (e.g. the Default Apps pref pane) needs to
// iterate through the entire Launch Services database -- a process which can
// take several seconds.)
static CFArrayRef GetMIMETypesHandledByApp(FSRef *aAppRef)
{
CFURLRef appURL = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aAppRef);
if (!appURL) {
return NULL;
}
CFDictionaryRef infoDict = ::CFBundleCopyInfoDictionaryForURL(appURL);
::CFRelease(appURL);
if (!infoDict) {
return NULL;
}
CFTypeRef cfObject = ::CFDictionaryGetValue(infoDict, CFSTR("CFBundleDocumentTypes"));
::CFRelease(infoDict);
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
return NULL;
}
CFArrayRef docTypes = static_cast<CFArrayRef>(cfObject);
CFIndex docTypesCount = ::CFArrayGetCount(docTypes);
if (docTypesCount == 0) {
return NULL;
}
CFMutableArrayRef mimeTypes =
::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
for (CFIndex i = 0; i < docTypesCount; ++i) {
cfObject = ::CFArrayGetValueAtIndex(docTypes, i);
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFDictionaryGetTypeID())) {
continue;
}
CFDictionaryRef typeDict = static_cast<CFDictionaryRef>(cfObject);
// When this key is present (on OS X 10.5 and later), its contents
// take precedence over CFBundleTypeMIMETypes (and CFBundleTypeExtensions
// and CFBundleTypeOSTypes).
cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("LSItemContentTypes"));
if (cfObject && (::CFGetTypeID(cfObject) == ::CFArrayGetTypeID())) {
continue;
}
cfObject = ::CFDictionaryGetValue(typeDict, CFSTR("CFBundleTypeMIMETypes"));
if (!cfObject || (::CFGetTypeID(cfObject) != ::CFArrayGetTypeID())) {
continue;
}
CFArrayRef mimeTypeHolder = static_cast<CFArrayRef>(cfObject);
CFArrayAppendArray(mimeTypes, mimeTypeHolder,
::CFRangeMake(0, ::CFArrayGetCount(mimeTypeHolder)));
}
if (!::CFArrayGetCount(mimeTypes)) {
::CFRelease(mimeTypes);
mimeTypes = NULL;
}
return mimeTypes;
}
// aMIMEType and aFileExt might not match, If they don't we set *aFound to
// false and return a minimal nsIMIMEInfo structure.
already_AddRefed<nsIMIMEInfo>
@ -281,22 +352,25 @@ nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
FSRef typeAppFSRef;
FSRef extAppFSRef;
CFStringRef cfMIMEType = NULL;
if (!aMIMEType.IsEmpty()) {
CFURLRef appURL = NULL;
// CFStringCreateWithCString() can fail even if we're not out of memory --
// for example if the 'cStr' parameter is something very wierd (like "ÿÿ~"
// aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
// specified in the 'encoding' parameter. See bug 548719.
CFStringRef CFType = ::CFStringCreateWithCString(NULL, flatType.get(), kCFStringEncodingUTF8);
if (CFType) {
err = ::LSCopyApplicationForMIMEType(CFType, kLSRolesAll, &appURL);
cfMIMEType = ::CFStringCreateWithCString(NULL, flatType.get(),
kCFStringEncodingUTF8);
if (cfMIMEType) {
err = ::LSCopyApplicationForMIMEType(cfMIMEType, kLSRolesAll, &appURL);
if ((err == noErr) && appURL && ::CFURLGetFSRef(appURL, &typeAppFSRef)) {
haveAppForType = true;
PR_LOG(mLog, PR_LOG_DEBUG, ("LSCopyApplicationForMIMEType found a default application\n"));
}
if (appURL)
if (appURL) {
::CFRelease(appURL);
::CFRelease(CFType);
}
}
}
if (!aFileExt.IsEmpty()) {
@ -304,15 +378,15 @@ nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
// for example if the 'cStr' parameter is something very wierd (like "ÿÿ~"
// aka "\xFF\xFF~"), or possibly if it can't be interpreted as using what's
// specified in the 'encoding' parameter. See bug 548719.
CFStringRef CFExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
if (CFExt) {
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFExt,
CFStringRef cfExt = ::CFStringCreateWithCString(NULL, flatExt.get(), kCFStringEncodingUTF8);
if (cfExt) {
err = ::LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, cfExt,
kLSRolesAll, &extAppFSRef, nsnull);
if (err == noErr) {
haveAppForExt = true;
PR_LOG(mLog, PR_LOG_DEBUG, ("LSGetApplicationForInfo found a default application\n"));
}
::CFRelease(CFExt);
::CFRelease(cfExt);
}
}
@ -329,13 +403,52 @@ nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
*aFound = true;
}
} else if (haveAppForExt) {
// If aMIMEType isn't empty, it doesn't match aFileExt.
// If aMIMEType isn't empty, it doesn't match aFileExt, which should mean
// that we haven't found a matching app. But make an exception for an app
// that also explicitly claims to handle aMIMEType, or which doesn't claim
// to handle any MIME types. This helps work around the following Apple
// design flaw:
//
// Launch Services is somewhat unreliable about registering Apple apps to
// handle MIME types. Probably this is because Apple has officially
// deprecated support for MIME types (in favor of UTIs). As a result,
// most of Apple's own apps don't explicitly claim to handle any MIME
// types (instead they claim to handle one or more UTIs). So Launch
// Services must contain logic to translate support for a given UTI into
// support for one or more MIME types, and it doesn't always do this
// correctly. For example DiskImageMounter isn't (by default) registered
// to handle the application/x-apple-diskimage MIME type. See bug 675356.
//
// Apple has also deprecated support for file extensions, and Apple apps
// also don't register to handle them. But for some reason Launch Services
// is (apparently) better about translating support for a given UTI into
// support for one or more file extensions. It's not at all clear why.
if (aMIMEType.IsEmpty()) {
extAppIsDefault = true;
*aFound = true;
} else {
CFArrayRef extAppMIMETypes = GetMIMETypesHandledByApp(&extAppFSRef);
if (extAppMIMETypes) {
if (cfMIMEType) {
if (::CFArrayContainsValue(extAppMIMETypes,
::CFRangeMake(0, ::CFArrayGetCount(extAppMIMETypes)),
cfMIMEType)) {
extAppIsDefault = true;
*aFound = true;
}
}
::CFRelease(extAppMIMETypes);
} else {
extAppIsDefault = true;
*aFound = true;
}
}
}
if (cfMIMEType) {
::CFRelease(cfMIMEType);
}
if (aMIMEType.IsEmpty()) {
if (haveAppForExt) {
// If aMIMEType is empty and we've found a default app for aFileExt, try
@ -382,26 +495,26 @@ nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
return nsnull;
}
CFStringRef CFAppName = NULL;
CFStringRef cfAppName = NULL;
if (typeAppIsDefault) {
app->InitWithFSRef(&typeAppFSRef);
::LSCopyItemAttribute((const FSRef *) &typeAppFSRef, kLSRolesAll,
kLSItemDisplayName, (CFTypeRef *) &CFAppName);
kLSItemDisplayName, (CFTypeRef *) &cfAppName);
} else {
app->InitWithFSRef(&extAppFSRef);
::LSCopyItemAttribute((const FSRef *) &extAppFSRef, kLSRolesAll,
kLSItemDisplayName, (CFTypeRef *) &CFAppName);
kLSItemDisplayName, (CFTypeRef *) &cfAppName);
}
if (CFAppName) {
if (cfAppName) {
nsAutoTArray<UniChar, 255> buffer;
CFIndex appNameLength = ::CFStringGetLength(CFAppName);
CFIndex appNameLength = ::CFStringGetLength(cfAppName);
buffer.SetLength(appNameLength);
::CFStringGetCharacters(CFAppName, CFRangeMake(0, appNameLength),
::CFStringGetCharacters(cfAppName, CFRangeMake(0, appNameLength),
buffer.Elements());
nsAutoString appName;
appName.Assign(buffer.Elements(), appNameLength);
mimeInfoMac->SetDefaultDescription(appName);
::CFRelease(CFAppName);
::CFRelease(cfAppName);
}
mimeInfoMac->SetDefaultApplication(app);
@ -424,21 +537,22 @@ nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType,
mimeInfoMac->AppendExtension(preferredExt);
}
CFStringRef CFType = ::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8);
CFStringRef CFTypeDesc = NULL;
if (::LSCopyKindStringForMIMEType(CFType, &CFTypeDesc) == noErr) {
CFStringRef cfType = ::CFStringCreateWithCString(NULL, mimeType.get(), kCFStringEncodingUTF8);
CFStringRef cfTypeDesc = NULL;
if (::LSCopyKindStringForMIMEType(cfType, &cfTypeDesc) == noErr) {
nsAutoTArray<UniChar, 255> buffer;
CFIndex typeDescLength = ::CFStringGetLength(CFTypeDesc);
CFIndex typeDescLength = ::CFStringGetLength(cfTypeDesc);
buffer.SetLength(typeDescLength);
::CFStringGetCharacters(CFTypeDesc, CFRangeMake(0, typeDescLength),
::CFStringGetCharacters(cfTypeDesc, CFRangeMake(0, typeDescLength),
buffer.Elements());
nsAutoString typeDesc;
typeDesc.Assign(buffer.Elements(), typeDescLength);
mimeInfoMac->SetDescription(typeDesc);
}
if (CFTypeDesc)
::CFRelease(CFTypeDesc);
::CFRelease(CFType);
if (cfTypeDesc) {
::CFRelease(cfTypeDesc);
}
::CFRelease(cfType);
}
PR_LOG(mLog, PR_LOG_DEBUG, ("OS gave us: type '%s' found '%i'\n", mimeType.get(), *aFound));

View File

@ -119,6 +119,10 @@ namespace mozilla {
namespace gl {
class TextureImage;
}
namespace layers {
class LayerManagerOGL;
}
}
#ifndef NP_NO_CARBON
@ -295,6 +299,9 @@ typedef NSInteger NSEventGestureAxis;
#ifdef __LP64__
BOOL *mSwipeAnimationCancelled;
#endif
// Whether this uses off-main-thread compositing.
BOOL mUsingOMTCompositor;
}
// class initialization
@ -327,6 +334,8 @@ typedef NSInteger NSEventGestureAxis;
// If so, we shouldn't focus or unfocus a plugin.
- (BOOL)isInFailingLeftClickThrough;
- (void)setGLContext:(NSOpenGLContext *)aGLContext;
// Simple gestures support
//
// XXX - The swipeWithEvent, beginGestureWithEvent, magnifyWithEvent,
@ -348,6 +357,8 @@ typedef NSInteger NSEventGestureAxis;
- (void)maybeTrackScrollEventAsSwipe:(NSEvent *)anEvent
scrollOverflow:(PRInt32)overflow;
#endif
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC;
@end
class ChildViewMouseTracker {
@ -433,7 +444,7 @@ public:
NS_IMETHOD SetCursor(nsCursor aCursor);
NS_IMETHOD SetCursor(imgIContainer* aCursor, PRUint32 aHotspotX, PRUint32 aHotspotY);
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener, bool aDoCapture, bool aConsumeRollupEvent);
NS_IMETHOD SetTitle(const nsAString& title);
@ -486,6 +497,7 @@ public:
already_AddRefed<nsAccessible> GetDocumentAccessible();
#endif
virtual void CreateCompositor();
virtual gfxASurface* GetThebesSurface();
virtual void DrawOver(LayerManager* aManager, nsIntRect aRect);

View File

@ -87,6 +87,7 @@
#include "Layers.h"
#include "LayerManagerOGL.h"
#include "GLContext.h"
#include "mozilla/layers/CompositorCocoaWidgetHelper.h"
#include "mozilla/Preferences.h"
@ -1772,6 +1773,22 @@ NSView<mozView>* nsChildView::GetEditorView()
#pragma mark -
void
nsChildView::CreateCompositor()
{
nsBaseWidget::CreateCompositor();
if (mCompositorChild) {
LayerManagerOGL *manager =
static_cast<LayerManagerOGL*>(compositor::GetLayerManager(mCompositorParent));
NSOpenGLContext *glContext =
(NSOpenGLContext *) manager->gl()->GetNativeData(GLContext::NativeGLContext);
[(ChildView *)mView setGLContext:glContext];
[(ChildView *)mView setUsingOMTCompositor:true];
}
}
gfxASurface*
nsChildView::GetThebesSurface()
{
@ -2096,6 +2113,16 @@ NSEvent* gLastDragMouseDownEvent = nil;
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)setGLContext:(NSOpenGLContext *)aGLContext
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
mGLContext = aGLContext;
[mGLContext retain];
NS_OBJC_END_TRY_ABORT_BLOCK;
}
- (void)dealloc
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -2546,13 +2573,18 @@ NSEvent* gLastDragMouseDownEvent = nil;
}
#endif
if (mGeckoChild->GetLayerManager(nsnull)->GetBackendType() == LayerManager::LAYERS_OPENGL) {
LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(mGeckoChild->GetLayerManager(nsnull));
manager->SetClippingRegion(paintEvent.region);
LayerManager *layerManager = mGeckoChild->GetLayerManager(nsnull);
if (layerManager->GetBackendType() == LayerManager::LAYERS_OPENGL) {
NSOpenGLContext *glContext;
LayerManagerOGL *manager = static_cast<LayerManagerOGL*>(layerManager);
manager->SetClippingRegion(paintEvent.region);
glContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
if (!mGLContext) {
mGLContext = (NSOpenGLContext *)manager->gl()->GetNativeData(mozilla::gl::GLContext::NativeGLContext);
[mGLContext retain];
[self setGLContext:glContext];
}
mGeckoChild->DispatchWindowEvent(paintEvent);
// Force OpenGL to refresh the very first time we draw. This works around a
@ -2592,6 +2624,16 @@ NSEvent* gLastDragMouseDownEvent = nil;
painted = mGeckoChild->DispatchWindowEvent(paintEvent);
}
// Force OpenGL to refresh the very first time we draw. This works around a
// Mac OS X bug that stops windows updating on OS X when we use OpenGL.
if (painted && !mDidForceRefreshOpenGL &&
layerManager->AsShadowManager() && mUsingOMTCompositor) {
if (!mDidForceRefreshOpenGL) {
[self performSelector:@selector(forceRefreshOpenGL) withObject:nil afterDelay:0];
mDidForceRefreshOpenGL = YES;
}
}
if (!painted && [self isOpaque]) {
// Gecko refused to draw, but we've claimed to be opaque, so we have to
// draw something--fill with white.
@ -3129,6 +3171,12 @@ NSEvent* gLastDragMouseDownEvent = nil;
}
#endif // #ifdef __LP64__
- (void)setUsingOMTCompositor:(BOOL)aUseOMTC
{
mUsingOMTCompositor = aUseOMTC;
}
// Returning NO from this method only disallows ordering on mousedown - in order
// to prevent it for mouseup too, we need to call [NSApp preventWindowOrdering]
// when handling the mousedown event.

View File

@ -38,6 +38,8 @@
#include "mozilla/Util.h"
#include "mozilla/layers/CompositorChild.h"
#include "mozilla/layers/CompositorParent.h"
#include "nsBaseWidget.h"
#include "nsDeviceContext.h"
#include "nsCOMPtr.h"
@ -55,6 +57,7 @@
#include "nsIXULRuntime.h"
#include "nsIGfxInfo.h"
#include "npapi.h"
#include "base/thread.h"
#ifdef DEBUG
#include "nsIObserver.h"
@ -70,6 +73,8 @@ static PRInt32 gNumWidgets;
using namespace mozilla::layers;
using namespace mozilla;
using base::Thread;
using mozilla::ipc::AsyncChannel;
nsIContent* nsBaseWidget::mLastRollup = nsnull;
@ -104,6 +109,7 @@ nsBaseWidget::nsBaseWidget()
, mEventCallback(nsnull)
, mViewCallback(nsnull)
, mContext(nsnull)
, mCompositorThread(nsnull)
, mCursor(eCursor_standard)
, mWindowType(eWindowType_child)
, mBorderStyle(eBorderStyle_none)
@ -142,6 +148,12 @@ nsBaseWidget::~nsBaseWidget()
if (mLayerManager) {
mLayerManager->Destroy();
mLayerManager = nsnull;
}
if (mCompositorChild) {
mCompositorChild->Destroy();
delete mCompositorThread;
}
#ifdef NOISY_WIDGET_LEAKS
@ -814,6 +826,38 @@ nsBaseWidget::GetShouldAccelerate()
return mUseAcceleratedRendering;
}
void nsBaseWidget::CreateCompositor()
{
mCompositorParent = new CompositorParent(this);
mCompositorThread = new Thread("CompositorThread");
if (mCompositorThread->Start()) {
LayerManager* lm = CreateBasicLayerManager();
MessageLoop *childMessageLoop = mCompositorThread->message_loop();
mCompositorChild = new CompositorChild(lm);
AsyncChannel *parentChannel = mCompositorParent->GetIPCChannel();
AsyncChannel::Side childSide = mozilla::ipc::AsyncChannel::Child;
mCompositorChild->Open(parentChannel, childMessageLoop, childSide);
PLayersChild* shadowManager =
mCompositorChild->SendPLayersConstructor(LayerManager::LAYERS_OPENGL);
if (shadowManager) {
ShadowLayerForwarder* lf = lm->AsShadowForwarder();
if (!lf) {
delete lm;
mCompositorChild = nsnull;
}
lf->SetShadowManager(shadowManager);
lf->SetParentBackendType(LayerManager::LAYERS_OPENGL);
mLayerManager = lm;
} else {
NS_WARNING("fail to construct LayersChild");
delete lm;
mCompositorChild = nsnull;
}
}
}
LayerManager* nsBaseWidget::GetLayerManager(PLayersChild* aShadowManager,
LayersBackend aBackendHint,
LayerManagerPersistence aPersistence,
@ -824,16 +868,29 @@ LayerManager* nsBaseWidget::GetLayerManager(PLayersChild* aShadowManager,
mUseAcceleratedRendering = GetShouldAccelerate();
if (mUseAcceleratedRendering) {
nsRefPtr<LayerManagerOGL> layerManager = new LayerManagerOGL(this);
/**
* XXX - On several OSes initialization is expected to fail for now.
* If we'd get a none-basic layer manager they'd crash. This is ok though
* since on those platforms it will fail. Anyone implementing new
* platforms on LayerManagerOGL should ensure their widget is able to
* deal with it though!
*/
if (layerManager->Initialize()) {
mLayerManager = layerManager;
// Try to use an async compositor first, if possible
bool useCompositor =
Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
if (useCompositor) {
// e10s uses the parameter to pass in the shadow manager from the TabChild
// so we don't expect to see it there since this doesn't support e10s.
NS_ASSERTION(aShadowManager == nsnull, "Async Compositor not supported with e10s");
CreateCompositor();
}
if (!mLayerManager) {
nsRefPtr<LayerManagerOGL> layerManager = new LayerManagerOGL(this);
/**
* XXX - On several OSes initialization is expected to fail for now.
* If we'd get a non-basic layer manager they'd crash. This is ok though
* since on those platforms it will fail. Anyone implementing new
* platforms on LayerManagerOGL should ensure their widget is able to
* deal with it though!
*/
if (layerManager->Initialize()) {
mLayerManager = layerManager;
}
}
}
if (!mLayerManager) {

View File

@ -51,6 +51,17 @@ class nsIContent;
class nsAutoRollup;
class gfxContext;
namespace mozilla {
namespace layers {
class CompositorChild;
class CompositorParent;
}
}
namespace base {
class Thread;
}
/**
* Common widget implementation used as base class for native
* or crossplatform implementations of Widgets.
@ -66,6 +77,9 @@ class nsBaseWidget : public nsIWidget
protected:
typedef mozilla::layers::BasicLayerManager BasicLayerManager;
typedef mozilla::layers::CompositorChild CompositorChild;
typedef mozilla::layers::CompositorParent CompositorParent;
typedef base::Thread Thread;
public:
nsBaseWidget();
@ -117,6 +131,7 @@ public:
LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
bool* aAllowRetaining = nsnull);
virtual void CreateCompositor();
virtual void DrawOver(LayerManager* aManager, nsIntRect aRect) {}
virtual void UpdateThemeGeometries(const nsTArray<ThemeGeometry>& aThemeGeometries) {}
virtual gfxASurface* GetThebesSurface();
@ -268,6 +283,9 @@ protected:
nsDeviceContext* mContext;
nsRefPtr<LayerManager> mLayerManager;
nsRefPtr<LayerManager> mBasicLayerManager;
nsRefPtr<CompositorChild> mCompositorChild;
nsRefPtr<CompositorParent> mCompositorParent;
Thread* mCompositorThread;
nscolor mBackground;
nscolor mForeground;
nsCursor mCursor;

View File

@ -350,6 +350,22 @@ void* nsDeque::ObjectAt(PRInt32 aIndex) const {
return result;
}
void* nsDeque::RemoveObjectAt(PRInt32 aIndex) {
if ((aIndex<0) || (aIndex>=mSize)) {
return 0;
}
void* result=mData[modulus(mOrigin + aIndex, mCapacity)];
// "Shuffle down" all elements in the array by 1, overwritting the element
// being removed.
for (PRInt32 i=aIndex; i<mSize; i++) {
mData[modulus(mOrigin + i, mCapacity)] = mData[modulus(mOrigin + i + 1, mCapacity)];
}
mSize--;
return result;
}
/**
* Create and return an iterator pointing to
* the beginning of the queue. Note that this

View File

@ -152,6 +152,14 @@ class NS_COM_GLUE nsDeque {
*/
void* ObjectAt(int aIndex) const;
/**
* Removes and returns the i'th member from the deque.
*
* @param index of desired item
* @return the element which was removed
*/
void* RemoveObjectAt(int aIndex);
/**
* Remove all items from container without destroying them.
*

View File

@ -223,6 +223,39 @@ private:
nsCOMPtr<nsISupports> mSupports;
};
/**
* hashkey wrapper using refcounted * KeyType
*
* @see nsTHashtable::EntryType for specification
*/
template<class T>
class nsRefPtrHashKey : public PLDHashEntryHdr
{
public:
typedef T* KeyType;
typedef const T* KeyTypePointer;
nsRefPtrHashKey(const T* key) :
mKey(const_cast<T*>(key)) { }
nsRefPtrHashKey(const nsRefPtrHashKey& toCopy) :
mKey(toCopy.mKey) { }
~nsRefPtrHashKey() { }
KeyType GetKey() const { return mKey; }
bool KeyEquals(KeyTypePointer aKey) const { return aKey == mKey; }
static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; }
static PLDHashNumber HashKey(KeyTypePointer aKey)
{
return NS_PTR_TO_INT32(aKey) >>2;
}
enum { ALLOW_MEMMOVE = true };
private:
nsRefPtr<T> mKey;
};
/**
* hashkey wrapper using T* KeyType
*

View File

@ -89,6 +89,7 @@ CPP_UNIT_TESTS = \
TestCOMArray.cpp \
TestCOMPtr.cpp \
TestCOMPtrEq.cpp \
TestDeque.cpp \
TestFile.cpp \
TestHashtables.cpp \
TestID.cpp \
@ -109,7 +110,6 @@ endif
#CPP_UNIT_TESTS += \
# TestArray.cpp \
# TestCRT.cpp \
# TestDeque.cpp \
# TestEncoding.cpp \
# TestExpirationTracker.cpp \
# TestPipes.cpp \

View File

@ -35,6 +35,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "TestHarness.h"
#include "nsDeque.h"
#include "nsCRT.h"
#include <stdio.h>
@ -44,13 +45,12 @@
**************************************************************/
class _TestDeque {
public:
_TestDeque() {
SelfTest();
}
int SelfTest();
nsresult OriginalTest();
nsresult OriginalFlaw();
nsresult AssignFlaw();
int Test();
private:
int OriginalTest();
int OriginalFlaw();
int AssignFlaw();
int TestRemove();
};
static _TestDeque sTestDeque;
@ -60,96 +60,214 @@ class _Dealloc: public nsDequeFunctor {
}
};
#define TEST(aCondition, aMsg) \
if (!(aCondition)) { fail("TestDeque: "#aMsg); return 1; }
/**
* conduct automated self test for this class
*
* @param
* @return
*/
int _TestDeque::SelfTest() {
int _TestDeque::Test() {
/* the old deque should have failed a bunch of these tests */
int results=0;
results+=OriginalTest();
results+=OriginalFlaw();
results+=AssignFlaw();
results+=TestRemove();
return results;
}
nsresult _TestDeque::OriginalTest() {
int ints[200];
int count=sizeof(ints)/sizeof(int);
int _TestDeque::OriginalTest() {
const int size = 200;
int ints[size];
int i=0;
int* temp;
int temp;
nsDeque theDeque(new _Dealloc); //construct a simple one...
for (i=0;i<count;i++) { //initialize'em
ints[i]=10*(1+i);
// ints = [0...199]
for (i=0;i<size;i++) { //initialize'em
ints[i]=i;
}
// queue = [0...69]
for (i=0;i<70;i++) {
theDeque.Push(&ints[i]);
temp=*(int*)theDeque.Peek();
TEST(temp == i, "Verify end after push #1");
TEST(theDeque.GetSize() == i + 1, "Verify size after push #1");
}
for (i=0;i<56;i++) {
temp=(int*)theDeque.Pop();
TEST(theDeque.GetSize() == 70, "Verify overall size after pushes #1");
// queue = [0...14]
for (i=1;i<=55;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 70-i, "Verify end after pop # 1");
TEST(theDeque.GetSize() == 70 - i, "Verify size after pop # 1");
}
TEST(theDeque.GetSize() == 15, "Verify overall size after pops");
// queue = [0...14,0...54]
for (i=0;i<55;i++) {
theDeque.Push(&ints[i]);
temp=*(int*)theDeque.Peek();
TEST(temp == i, "Verify end after push #2");
TEST(theDeque.GetSize() == i + 15 + 1, "Verify size after push # 2");
}
for (i=0;i<35;i++) {
temp=(int*)theDeque.Pop();
TEST(theDeque.GetSize() == 70, "Verify size after end of all pushes #2");
// queue = [0...14,0...19]
for (i=1;i<=35;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 55-i, "Verify end after pop # 2");
TEST(theDeque.GetSize() == 70 - i, "Verify size after pop #2");
}
TEST(theDeque.GetSize() == 35, "Verify overall size after end of all pops #2");
// queue = [0...14,0...19,0...34]
for (i=0;i<35;i++) {
theDeque.Push(&ints[i]);
temp = *(int*)theDeque.Peek();
TEST(temp == i, "Verify end after push # 3");
TEST(theDeque.GetSize() == 35 + 1 + i, "Verify size after push #3");
}
for (i=0;i<38;i++) {
temp=(int*)theDeque.Pop();
// queue = [0...14,0...19]
for (i=0;i<35;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 34 - i, "Verify end after pop # 3");
}
return NS_OK;
// queue = [0...14]
for (i=0;i<20;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 19 - i, "Verify end after pop # 4");
}
// queue = []
for (i=0;i<15;i++) {
temp=*(int*)theDeque.Pop();
TEST(temp == 14 - i, "Verify end after pop # 5");
}
TEST(theDeque.GetSize() == 0, "Deque should finish empty.");
return 0;
}
nsresult _TestDeque::OriginalFlaw() {
int _TestDeque::OriginalFlaw() {
int ints[200];
int i=0;
int* temp;
nsDeque secondDeque(new _Dealloc);
int temp;
nsDeque d(new _Dealloc);
/**
* Test 1. Origin near end, semi full, call Peek().
* you start, mCapacity is 8
*/
printf("fill array\n");
for (i=32; i; --i)
ints[i]=i*3+10;
printf("push 6 times\n");
for (i=0; i<6; i++)
secondDeque.Push(&ints[i]);
printf("popfront 4 times:\n");
for (i=4; i; --i) {
temp=(int*)secondDeque.PopFront();
printf("%d\t",*temp);
for (i=0; i<30; i++)
ints[i]=i;
for (i=0; i<6; i++) {
d.Push(&ints[i]);
temp = *(int*)d.Peek();
TEST(temp == i, "OriginalFlaw push #1");
}
printf("push 4 times\n");
for (int j=4; j; --j)
secondDeque.Push(&ints[++i]);
printf("origin should now be about 4\n");
printf("and size should be 6\n");
printf("origin+size>capacity\n");
TEST(d.GetSize() == 6, "OriginalFlaw size check #1");
/*<akk> Oh, I see ... it's a circular buffer */
printf("but the old code wasn't behaving accordingly.\n");
for (i=0; i<4; i++) {
temp=*(int*)d.PopFront();
TEST(temp == i, "PopFront test");
}
// d = [4,5]
TEST(d.GetSize() == 2, "OriginalFlaw size check #2");
/*right*/
printf("we shouldn't crash or anything interesting, ");
for (i=0; i<4; i++) {
d.Push(&ints[6 + i]);
}
// d = [4...9]
temp=(int*)secondDeque.Peek();
printf("peek: %d\n",*temp);
return NS_OK;
for (i=4; i<=9; i++) {
temp=*(int*)d.PopFront();
TEST(temp == i, "OriginalFlaw empty check");
}
return 0;
}
nsresult _TestDeque::AssignFlaw() {
int _TestDeque::AssignFlaw() {
nsDeque src(new _Dealloc),dest(new _Dealloc);
return NS_OK;
return 0;
}
static bool VerifyContents(const nsDeque& aDeque, const int* aContents, int aLength) {
for (int i=0; i<aLength; ++i) {
if (*(int*)aDeque.ObjectAt(i) != aContents[i]) {
return false;
}
}
return true;
}
int _TestDeque::TestRemove() {
nsDeque d;
const int count = 10;
int ints[count];
for (int i=0; i<count; i++) {
ints[i] = i;
}
for (int i=0; i<6; i++) {
d.Push(&ints[i]);
}
// d = [0...5]
d.PopFront();
d.PopFront();
// d = [2,5]
for (int i=2; i<=5; i++) {
int t = *(int*)d.ObjectAt(i-2);
TEST(t == i, "Verify ObjectAt()");
}
d.RemoveObjectAt(1);
// d == [2,4,5]
static const int t1[] = {2,4,5};
TEST(VerifyContents(d, t1, 3), "verify contents t1");
d.PushFront(&ints[1]);
d.PushFront(&ints[0]);
d.PushFront(&ints[7]);
d.PushFront(&ints[6]);
// d == [6,7,0,1,2,4,5] // (0==mOrigin)
static const int t2[] = {6,7,0,1,2,4,5};
TEST(VerifyContents(d, t2, 7), "verify contents t2");
d.RemoveObjectAt(1);
// d == [6,0,1,2,4,5] // (1==mOrigin)
static const int t3[] = {6,0,1,2,4,5};
TEST(VerifyContents(d, t3, 6), "verify contents t3");
d.RemoveObjectAt(5);
// d == [6,0,1,2,4] // (1==mOrigin)
static const int t4[] = {6,0,1,2,4};
TEST(VerifyContents(d, t4, 5), "verify contents t4");
d.RemoveObjectAt(0);
// d == [0,1,2,4] // (2==mOrigin)
static const int t5[] = {0,1,2,4};
TEST(VerifyContents(d, t5, 4), "verify contents t5");
return 0;
}
int main (void) {
ScopedXPCOM xpcom("TestTimers");
NS_ENSURE_FALSE(xpcom.failed(), 1);
_TestDeque test;
int result = test.Test();
TEST(result == 0, "All tests pass");
return 0;
}