This commit is contained in:
Kyle Huey 2012-08-05 08:29:15 -07:00
Родитель 7e943e244f 5be29bb8fd
Коммит 579ea680e3
35 изменённых файлов: 882 добавлений и 298 удалений

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

@ -483,3 +483,15 @@ pref("javascript.options.mem.gc_incremental_slice_ms", 30);
// Show/Hide scrollbars when active/inactive
pref("ui.showHideScrollbars", 1);
// Enable the ProcessPriorityManager, and give processes with no visible
// documents a 1s grace period before they're eligible to be marked as
// background.
pref("dom.ipc.processPriorityManager.enabled", true);
pref("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
pref("hal.processPriorityManager.gonk.masterOomAdjust", 0);
pref("hal.processPriorityManager.gonk.foregroundOomAdjust", 1);
pref("hal.processPriorityManager.gonk.backgroundOomAdjust", 2);
pref("hal.processPriorityManager.gonk.masterNice", -1);
pref("hal.processPriorityManager.gonk.foregroundNice", 0);
pref("hal.processPriorityManager.gonk.backgroundNice", 10);

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

@ -45,9 +45,11 @@ dnl Replace AC_OUTPUT to create and call a python config.status
define([AC_OUTPUT],
[dnl Top source directory in Windows format (as opposed to msys format).
WIN_TOP_SRC=
encoding=utf-8
case "$host_os" in
mingw*)
WIN_TOP_SRC=`cd $srcdir; pwd -W`
encoding=mbcs
;;
esac
AC_SUBST(WIN_TOP_SRC)
@ -74,6 +76,7 @@ echo creating $CONFIG_STATUS
cat > $CONFIG_STATUS <<EOF
#!${PYTHON}
# coding=$encoding
import os, sys
dnl topsrcdir is the top source directory in native form, as opposed to a

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

@ -320,7 +320,7 @@ endif
ifneq (,$(CONFIG_STATUS))
$(OBJDIR)/config/autoconf.mk: $(TOPSRCDIR)/config/autoconf.mk.in
$(OBJDIR)/config.status -n --file=$(OBJDIR)/config/autoconf.mk
$(PYTHON) $(OBJDIR)/config.status -n --file=$(OBJDIR)/config/autoconf.mk
endif

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

@ -1154,24 +1154,26 @@ GARBAGE_DIRS += $(_JAVA_DIR)
ifndef NO_MAKEFILE_RULE
Makefile: Makefile.in
@$(DEPTH)/config.status -n --file=Makefile
@$(PYTHON) $(DEPTH)/config.status -n --file=Makefile
@$(TOUCH) $@
endif
ifndef NO_SUBMAKEFILES_RULE
ifdef SUBMAKEFILES
# VPATH does not work on some machines in this case, so add $(srcdir)
$(SUBMAKEFILES): % : $(srcdir)/%.in
$(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file=$@
$(PYTHON) $(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file=$@
@$(TOUCH) $@
endif
endif
ifdef AUTOUPDATE_CONFIGURE
$(topsrcdir)/configure: $(topsrcdir)/configure.in
(cd $(topsrcdir) && $(AUTOCONF)) && $(DEPTH)/config.status -n --recheck)
(cd $(topsrcdir) && $(AUTOCONF)) && $(PYTHON) $(DEPTH)/config.status -n --recheck)
endif
$(DEPTH)/config/autoconf.mk: $(topsrcdir)/config/autoconf.mk.in
$(DEPTH)/config.status -n --file=$(DEPTH)/config/autoconf.mk
$(PYTHON) $(DEPTH)/config.status -n --file=$(DEPTH)/config/autoconf.mk
$(TOUCH) $@
###############################################################################

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

@ -40,6 +40,7 @@ EXPORTS_mozilla/dom = \
EXPORTS_mozilla/dom/ipc = \
Blob.h \
ProcessPriorityManager.h \
nsIRemoteBlob.h \
$(NULL)
@ -50,6 +51,7 @@ CPPSRCS = \
ContentChild.cpp \
CrashReporterParent.cpp \
CrashReporterChild.cpp \
ProcessPriorityManager.cpp \
StructuredCloneUtils.cpp \
TabParent.cpp \
TabChild.cpp \

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

@ -0,0 +1,336 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ipc/ProcessPriorityManager.h"
#include "mozilla/Hal.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/HalTypes.h"
#include "mozilla/TimeStamp.h"
#include "prlog.h"
#include "nsWeakPtr.h"
#include "nsXULAppAPI.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsITimer.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIDocument.h"
#include "nsIDOMEventListener.h"
#include "nsIDOMWindow.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMDocument.h"
#include "nsPIDOMWindow.h"
#ifdef XP_WIN
#include <process.h>
#define getpid _getpid
#else
#include <unistd.h>
#endif
using namespace mozilla::hal;
namespace mozilla {
namespace dom {
namespace ipc {
namespace {
static bool sInitialized = false;
// Some header defines a LOG macro, but we don't want it here.
#ifdef LOG
#undef LOG
#endif
// Enable logging by setting
//
// NSPR_LOG_MODULES=ProcessPriorityManager:5
//
// in your environment.
#ifdef PR_LOGGING
static PRLogModuleInfo* logModule = PR_NewLogModule("ProcessPriorityManager");
#define LOG(fmt, ...) \
PR_LOG(logModule, PR_LOG_DEBUG, \
("[%d] ProcessPriorityManager - " fmt, getpid(), ##__VA_ARGS__))
#else
#define LOG(fmt, ...)
#endif
/**
* This class listens to window creation and visibilitychange events and
* informs the hal back-end when this process transitions between having no
* visible top-level windows, and when it has at least one visible top-level
* window.
*
*
* An important heuristic here is that we don't mark a process as background
* until it's had no visible top-level windows for some amount of time.
*
* We do this because the notion of visibility is tied to inner windows
* (actually, to documents). When we navigate a page with outer window W, we
* first destroy W's inner window and document, then insert a new inner window
* and document into W. If not for our grace period, this transition could
* cause us to inform hal that this process quickly transitioned from
* foreground to background to foreground again.
*
*/
class ProcessPriorityManager MOZ_FINAL
: public nsIObserver
, public nsIDOMEventListener
{
public:
ProcessPriorityManager();
void Init();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMEVENTLISTENER
private:
void SetPriority(ProcessPriority aPriority);
void OnContentDocumentGlobalCreated(nsISupports* aOuterWindow);
void OnInnerWindowDestroyed();
void OnGracePeriodTimerFired();
void RecomputeNumVisibleWindows();
// mProcessPriority tracks the priority we've given this process in hal,
// except that, when the grace period timer is active,
// mProcessPriority == BACKGROUND even though hal still thinks we're a
// foreground process.
ProcessPriority mProcessPriority;
nsTArray<nsWeakPtr> mWindows;
nsCOMPtr<nsITimer> mGracePeriodTimer;
TimeStamp mStartupTime;
};
NS_IMPL_ISUPPORTS2(ProcessPriorityManager, nsIObserver, nsIDOMEventListener);
ProcessPriorityManager::ProcessPriorityManager()
: mProcessPriority(PROCESS_PRIORITY_FOREGROUND)
, mStartupTime(TimeStamp::Now())
{
}
void
ProcessPriorityManager::Init()
{
LOG("Starting up.");
// We can't do this in the constructor because we need to hold a strong ref
// to |this| before calling these methods.
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
os->AddObserver(this, "content-document-global-created", /* ownsWeak = */ false);
os->AddObserver(this, "inner-window-destroyed", /* ownsWeak = */ false);
SetPriority(PROCESS_PRIORITY_FOREGROUND);
}
NS_IMETHODIMP
ProcessPriorityManager::Observe(
nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
if (!strcmp(aTopic, "content-document-global-created")) {
OnContentDocumentGlobalCreated(aSubject);
} else if (!strcmp(aTopic, "inner-window-destroyed")) {
OnInnerWindowDestroyed();
} else if (!strcmp(aTopic, "timer-callback")) {
OnGracePeriodTimerFired();
} else {
MOZ_ASSERT(false);
}
return NS_OK;
}
NS_IMETHODIMP
ProcessPriorityManager::HandleEvent(
nsIDOMEvent* aEvent)
{
LOG("Got visibilitychange.");
RecomputeNumVisibleWindows();
return NS_OK;
}
void
ProcessPriorityManager::OnContentDocumentGlobalCreated(
nsISupports* aOuterWindow)
{
// Get the inner window (the topic of content-document-global-created is
// the /outer/ window!).
nsCOMPtr<nsPIDOMWindow> outerWindow = do_QueryInterface(aOuterWindow);
NS_ENSURE_TRUE(outerWindow, );
nsCOMPtr<nsPIDOMWindow> innerWindow = outerWindow->GetCurrentInnerWindow();
NS_ENSURE_TRUE(innerWindow, );
// We're only interested in top-level windows.
nsCOMPtr<nsIDOMWindow> parentOuterWindow;
innerWindow->GetScriptableParent(getter_AddRefs(parentOuterWindow));
NS_ENSURE_TRUE(parentOuterWindow, );
if (parentOuterWindow != outerWindow) {
return;
}
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(innerWindow);
NS_ENSURE_TRUE(target, );
nsWeakPtr weakWin = do_GetWeakReference(innerWindow);
NS_ENSURE_TRUE(weakWin, );
if (mWindows.Contains(weakWin)) {
return;
}
target->AddSystemEventListener(NS_LITERAL_STRING("mozvisibilitychange"),
this,
/* useCapture = */ false,
/* wantsUntrusted = */ false);
mWindows.AppendElement(weakWin);
RecomputeNumVisibleWindows();
}
void
ProcessPriorityManager::OnInnerWindowDestroyed()
{
RecomputeNumVisibleWindows();
}
void
ProcessPriorityManager::RecomputeNumVisibleWindows()
{
// We could try to be clever and count the number of visible windows, instead
// of iterating over mWindows every time one window's visibility state changes.
// But experience suggests that iterating over the windows is prone to fewer
// errors (and one mistake doesn't mess you up for the entire session).
// Moreover, mWindows should be a very short list, since it contains only
// top-level content windows.
bool allHidden = true;
for (PRUint32 i = 0; i < mWindows.Length(); i++) {
nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mWindows[i]);
if (!window) {
mWindows.RemoveElementAt(i);
i--;
continue;
}
nsCOMPtr<nsIDOMDocument> doc;
window->GetDocument(getter_AddRefs(doc));
if (!doc) {
continue;
}
bool hidden = false;
doc->GetMozHidden(&hidden);
#ifdef DEBUG
nsAutoString spec;
doc->GetDocumentURI(spec);
LOG("Document at %s has visibility %d.", NS_ConvertUTF16toUTF8(spec).get(), !hidden);
#endif
allHidden = allHidden && hidden;
// We could break out early from this loop if
// !hidden && mProcessPriority == BACKGROUND,
// but then we might not clean up all the weak refs.
}
SetPriority(allHidden ?
PROCESS_PRIORITY_BACKGROUND :
PROCESS_PRIORITY_FOREGROUND);
}
void
ProcessPriorityManager::SetPriority(ProcessPriority aPriority)
{
if (aPriority == mProcessPriority) {
return;
}
if (aPriority == PROCESS_PRIORITY_BACKGROUND) {
// If this is a foreground --> background transition, give ourselves a
// grace period before informing hal.
PRUint32 gracePeriodMS = Preferences::GetUint("dom.ipc.processPriorityManager.gracePeriodMS", 1000);
if (mGracePeriodTimer) {
LOG("Grace period timer already active.");
return;
}
LOG("Initializing grace period timer.");
mProcessPriority = aPriority;
mGracePeriodTimer = do_CreateInstance("@mozilla.org/timer;1");
mGracePeriodTimer->Init(this, gracePeriodMS, nsITimer::TYPE_ONE_SHOT);
} else if (aPriority == PROCESS_PRIORITY_FOREGROUND) {
// If this is a background --> foreground transition, do it immediately, and
// cancel the outstanding grace period timer, if there is one.
if (mGracePeriodTimer) {
mGracePeriodTimer->Cancel();
mGracePeriodTimer = nullptr;
}
LOG("Setting priority to %d.", aPriority);
mProcessPriority = aPriority;
hal::SetProcessPriority(getpid(), aPriority);
} else {
MOZ_ASSERT(false);
}
}
void
ProcessPriorityManager::OnGracePeriodTimerFired()
{
LOG("Grace period timer fired; setting priority to %d.",
PROCESS_PRIORITY_BACKGROUND);
// mProcessPriority should already be BACKGROUND: We set it in
// SetPriority(BACKGROUND), and we canceled this timer if there was an
// intervening SetPriority(FOREGROUND) call.
MOZ_ASSERT(mProcessPriority == PROCESS_PRIORITY_BACKGROUND);
mGracePeriodTimer = nullptr;
hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_BACKGROUND);
}
} // anonymous namespace
void
InitProcessPriorityManager()
{
if (sInitialized) {
return;
}
// If IPC tabs aren't enabled at startup, don't bother with any of this.
if (!Preferences::GetBool("dom.ipc.processPriorityManager.enabled") ||
Preferences::GetBool("dom.ipc.tabs.disabled")) {
return;
}
sInitialized = true;
// If we're the master process, mark ourselves as such and don't create a
// ProcessPriorityManager (we never want to mark the master process as
// backgrounded).
if (XRE_GetProcessType() == GeckoProcessType_Default) {
LOG("This is the master process.");
hal::SetProcessPriority(getpid(), PROCESS_PRIORITY_MASTER);
return;
}
// This object is held alive by the observer service.
nsRefPtr<ProcessPriorityManager> mgr = new ProcessPriorityManager();
mgr->Init();
}
} // namespace ipc
} // namespace dom
} // namespace mozilla

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

@ -0,0 +1,33 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ProcessPriorityManager_h_
#define mozilla_ProcessPriorityManager_h_
namespace mozilla {
namespace dom {
namespace ipc {
/**
* Initialize the ProcessPriorityManager.
*
* The ProcessPriorityManager informs the hal back-end whether this is the root
* Gecko process, and, if we're not the root, informs hal when this process
* transitions between having no visible top-level windows, and having at least
* one visible top-level window.
*
* Hal may adjust this process's operating system priority (e.g. niceness, on
* *nix) according to these notificaitons.
*
* This function call does nothing if the pref for OOP tabs is not set.
*/
void InitProcessPriorityManager();
} // namespace ipc
} // namespace dom
} // namespace mozilla
#endif

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

@ -5,7 +5,7 @@
# Encoding warnings and errors
EncNoDeclarationFrame=The character encoding of a framed document was not declared. The document may appear different if viewed without the document framing it.
EncNoDeclarationPlain=The character encoding of the plain text document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the file needs to be declared in the transfer protocol or file needs to use a byte order mark as an encoding signature.
EncNoDeclaration=The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must to be declared in the document or in the transfer protocol.
EncNoDeclaration=The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must be declared in the document or in the transfer protocol.
EncLateMetaFrame=The character encoding declaration of the framed HTML document was not found when prescanning the first 1024 bytes of the file. When viewed without the document framing it, the page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.
EncLateMeta=The character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. When viewed in a differently-configured browser, this page will reload automatically. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.
EncLateMetaReload=The page was reloaded, because the character encoding declaration of the HTML document was not found when prescanning the first 1024 bytes of the file. The encoding declaration needs to be moved to be within the first 1024 bytes of the file.

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

@ -97,4 +97,4 @@ skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-ref.h
== 694880-3.html 694880-ref.html
== 388980-1.html 388980-1-ref.html
needs-focus == spellcheck-superscript-1.html spellcheck-superscript-1-ref.html
needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html
fails-if(Android) needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html

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

@ -233,4 +233,4 @@ DEFINES += -DMOZ_TREE_PIXMAN
endif
cairo-features.h: $(srcdir)/cairo-features.h.in $(GLOBAL_DEPS)
$(DEPTH)/config.status -n --file=$@
$(PYTHON) $(DEPTH)/config.status -n --file=$@

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

@ -22,6 +22,11 @@
#include "WindowIdentifier.h"
#include "mozilla/dom/ScreenOrientation.h"
#ifdef XP_WIN
#include <process.h>
#define getpid _getpid
#endif
using namespace mozilla::services;
#define PROXY_IF_SANDBOXED(_call) \
@ -728,5 +733,16 @@ SetAlarm(PRInt32 aSeconds, PRInt32 aNanoseconds)
RETURN_PROXY_IF_SANDBOXED(SetAlarm(aSeconds, aNanoseconds));
}
void
SetProcessPriority(int aPid, ProcessPriority aPriority)
{
if (InSandbox()) {
hal_sandbox::SetProcessPriority(aPid, aPriority);
}
else {
hal_impl::SetProcessPriority(aPid, aPriority);
}
}
} // namespace hal
} // namespace mozilla

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

@ -402,6 +402,15 @@ void NotifyAlarmFired();
*/
bool SetAlarm(PRInt32 aSeconds, PRInt32 aNanoseconds);
/**
* Set the priority of the given process.
*
* Exactly what this does will vary between platforms. On *nix we might give
* background processes higher nice values. On other platforms, we might
* ignore this call entirely.
*/
void SetProcessPriority(int aPid, hal::ProcessPriority aPriority);
} // namespace MOZ_HAL_NAMESPACE
} // namespace mozilla

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

@ -54,11 +54,13 @@ enum SwitchState {
};
typedef Observer<SwitchEvent> SwitchObserver;
} // namespace hal
} // namespace mozilla
namespace mozilla {
namespace hal {
enum ProcessPriority {
PROCESS_PRIORITY_BACKGROUND,
PROCESS_PRIORITY_FOREGROUND,
PROCESS_PRIORITY_MASTER,
NUM_PROCESS_PRIORITY
};
/**
* Used by ModifyWakeLock
@ -69,8 +71,8 @@ enum WakeLockControl {
WAKE_LOCK_ADD_ONE = 1,
};
}
}
} // namespace hal
} // namespace mozilla
namespace IPC {
@ -134,6 +136,13 @@ struct ParamTraits<mozilla::hal::SwitchDevice>:
mozilla::hal::NUM_SWITCH_DEVICE> {
};
template <>
struct ParamTraits<mozilla::hal::ProcessPriority>:
public EnumSerializer<mozilla::hal::ProcessPriority,
mozilla::hal::PROCESS_PRIORITY_BACKGROUND,
mozilla::hal::NUM_PROCESS_PRIORITY> {
};
} // namespace IPC

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

@ -124,6 +124,7 @@ CPPSRCS += \
FallbackWakeLocks.cpp \
FallbackSwitch.cpp \
FallbackScreenPower.cpp \
FallbackProcessPriority.cpp \
$(NULL)
endif #}

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

@ -0,0 +1,19 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Hal.h"
using namespace mozilla::hal;
namespace mozilla {
namespace hal_impl {
void
SetProcessPriority(int aPid, ProcessPriority aPriority)
{
HAL_LOG(("FallbackProcessPriority - SetProcessPriority(%d, %d)\n", aPid, aPriority));
}
} // hal_impl
} // namespace mozilla

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

@ -21,6 +21,7 @@
#include <math.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/resource.h>
#include <time.h>
#include "android/log.h"
@ -39,7 +40,9 @@
#include "mozilla/FileUtils.h"
#include "mozilla/Monitor.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
#include "nsAlgorithm.h"
#include "nsPrintfCString.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIRunnable.h"
@ -56,7 +59,8 @@
#define NsecPerSec 1000000000
using mozilla::hal::WindowIdentifier;
using namespace mozilla;
using namespace mozilla::hal;
namespace mozilla {
namespace hal_impl {
@ -800,5 +804,50 @@ SetAlarm(PRInt32 aSeconds, PRInt32 aNanoseconds)
return true;
}
void
SetProcessPriority(int aPid, ProcessPriority aPriority)
{
HAL_LOG(("SetProcessPriority(pid=%d, priority=%d)", aPid, aPriority));
const char* priorityStr = NULL;
switch (aPriority) {
case PROCESS_PRIORITY_BACKGROUND:
priorityStr = "background";
break;
case PROCESS_PRIORITY_FOREGROUND:
priorityStr = "foreground";
break;
case PROCESS_PRIORITY_MASTER:
priorityStr = "master";
break;
default:
MOZ_NOT_REACHED();
}
// Notice that you can disable oom_adj and renice by deleting the prefs
// hal.processPriorityManager{foreground,background,master}{OomAdjust,Nice}.
PRInt32 oomAdj = 0;
nsresult rv = Preferences::GetInt(nsPrintfCString(
"hal.processPriorityManager.gonk.%sOomAdjust", priorityStr).get(), &oomAdj);
if (NS_SUCCEEDED(rv)) {
HAL_LOG(("Setting oom_adj for pid %d to %d", aPid, oomAdj));
WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(),
nsPrintfCString("%d", oomAdj).get());
}
PRInt32 nice = 0;
rv = Preferences::GetInt(nsPrintfCString(
"hal.processPriorityManager.gonk.%sNice", priorityStr).get(), &nice);
if (NS_SUCCEEDED(rv)) {
HAL_LOG(("Setting nice for pid %d to %d", aPid, nice));
int success = setpriority(PRIO_PROCESS, aPid, nice);
if (success != 0) {
HAL_LOG(("Failed to set nice for pid %d to %d", aPid, nice));
}
}
}
} // hal_impl
} // mozilla

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

@ -21,6 +21,7 @@ using mozilla::hal::SensorAccuracyType;
using mozilla::hal::WakeLockControl;
using mozilla::hal::SwitchState;
using mozilla::hal::SwitchDevice;
using mozilla::hal::ProcessPriority;
using nsIntRect;
using PRTime;
@ -71,7 +72,8 @@ struct ScreenConfiguration {
uint32_t colorDepth;
uint32_t pixelDepth;
};
}
} // namespace hal
namespace hal_sandbox {
@ -138,6 +140,8 @@ parent:
sync GetCurrentSwitchState(SwitchDevice aDevice)
returns (SwitchState aState);
SetProcessPriority(int aPid, ProcessPriority aPriority);
child:
NotifySensorChange(SensorData aSensorData);

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

@ -280,6 +280,12 @@ SetAlarm(PRInt32 aSeconds, PRInt32 aNanoseconds)
return false;
}
void
SetProcessPriority(int aPid, ProcessPriority aPriority)
{
Hal()->SendSetProcessPriority(aPid, aPriority);
}
class HalParent : public PHalParent
, public BatteryObserver
, public NetworkObserver
@ -568,6 +574,15 @@ public:
*aState = hal::GetCurrentSwitchState(aDevice);
return true;
}
virtual bool
RecvSetProcessPriority(const int& aPid, const ProcessPriority& aPriority)
{
// TODO As a security check, we should ensure that aPid is either the pid
// of our child, or the pid of one of the child's children.
hal::SetProcessPriority(aPid, aPriority);
return true;
}
};
class HalChild : public PHalChild {

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

@ -45,9 +45,11 @@ dnl Replace AC_OUTPUT to create and call a python config.status
define([AC_OUTPUT],
[dnl Top source directory in Windows format (as opposed to msys format).
WIN_TOP_SRC=
encoding=utf-8
case "$host_os" in
mingw*)
WIN_TOP_SRC=`cd $srcdir; pwd -W`
encoding=mbcs
;;
esac
AC_SUBST(WIN_TOP_SRC)
@ -74,6 +76,7 @@ echo creating $CONFIG_STATUS
cat > $CONFIG_STATUS <<EOF
#!${PYTHON}
# coding=$encoding
import os, sys
dnl topsrcdir is the top source directory in native form, as opposed to a

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

@ -1154,24 +1154,26 @@ GARBAGE_DIRS += $(_JAVA_DIR)
ifndef NO_MAKEFILE_RULE
Makefile: Makefile.in
@$(DEPTH)/config.status -n --file=Makefile
@$(PYTHON) $(DEPTH)/config.status -n --file=Makefile
@$(TOUCH) $@
endif
ifndef NO_SUBMAKEFILES_RULE
ifdef SUBMAKEFILES
# VPATH does not work on some machines in this case, so add $(srcdir)
$(SUBMAKEFILES): % : $(srcdir)/%.in
$(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file=$@
$(PYTHON) $(DEPTH)$(addprefix /,$(subsrcdir))/config.status -n --file=$@
@$(TOUCH) $@
endif
endif
ifdef AUTOUPDATE_CONFIGURE
$(topsrcdir)/configure: $(topsrcdir)/configure.in
(cd $(topsrcdir) && $(AUTOCONF)) && $(DEPTH)/config.status -n --recheck)
(cd $(topsrcdir) && $(AUTOCONF)) && $(PYTHON) $(DEPTH)/config.status -n --recheck)
endif
$(DEPTH)/config/autoconf.mk: $(topsrcdir)/config/autoconf.mk.in
$(DEPTH)/config.status -n --file=$(DEPTH)/config/autoconf.mk
$(PYTHON) $(DEPTH)/config.status -n --file=$(DEPTH)/config/autoconf.mk
$(TOUCH) $@
###############################################################################

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

@ -375,6 +375,17 @@ IsInlineFrame(const nsIFrame* aFrame)
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
}
/**
* True if aFrame is an instance of an SVG frame class or is an inline/block
* frame being used for SVG text.
*/
static bool
IsFrameForSVG(const nsIFrame* aFrame)
{
return aFrame->IsFrameOfType(nsIFrame::eSVG) ||
aFrame->IsSVGText();
}
/**
* Returns true iff aFrame explicitly prevents its descendants from floating
* (at least, down to the level of descendants which themselves are
@ -5233,7 +5244,7 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
// Don't create frames for non-SVG element children of SVG elements.
if (aNameSpaceID != kNameSpaceID_SVG &&
aParentFrame &&
aParentFrame->IsFrameOfType(nsIFrame::eSVG) &&
IsFrameForSVG(aParentFrame) &&
!aParentFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)
) {
SetAsUndisplayedContent(aItems, element, styleContext,
@ -5498,12 +5509,14 @@ nsCSSFrameConstructor::ConstructFramesFromItem(nsFrameConstructorState& aState,
// We don't do it for content that may have XBL anonymous siblings,
// because they make it difficult to correctly create the frame
// due to dynamic changes.
// We don't do it for text that's not a line participant (i.e. SVG text).
// We don't do it for SVG text, since we might need to position and
// measure the white space glyphs due to x/y/dx/dy attributes.
if (AtLineBoundary(aIter) &&
!styleContext->GetStyleText()->NewlineIsSignificant() &&
aIter.List()->ParentHasNoXBLChildren() &&
!(aState.mAdditionalStateBits & NS_FRAME_GENERATED_CONTENT) &&
(item.mFCData->mBits & FCDATA_IS_LINE_PARTICIPANT) &&
!(item.mFCData->mBits & FCDATA_IS_SVG_TEXT) &&
item.IsWhitespace(aState))
return NS_OK;

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

@ -1195,6 +1195,13 @@ PresShell::CreatePreferenceStyleSheet()
mPrefStyleSheet->SetURIs(uri, uri, uri);
mPrefStyleSheet->SetComplete();
PRUint32 index;
rv =
mPrefStyleSheet->InsertRuleInternal(NS_LITERAL_STRING("@namespace svg url(http://www.w3.org/2000/svg);"),
0, &index);
if (NS_FAILED(rv)) {
mPrefStyleSheet = nullptr;
return rv;
}
rv =
mPrefStyleSheet->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"),
0, &index);
@ -1207,10 +1214,10 @@ PresShell::CreatePreferenceStyleSheet()
return NS_OK;
}
// XXX We want these after the @namespace rule. Does order matter
// XXX We want these after the @namespace rules. Does order matter
// for these rules, or can we call StyleRule::StyleRuleCount()
// and just "append"?
static PRUint32 sInsertPrefSheetRulesAt = 1;
static PRUint32 sInsertPrefSheetRulesAt = 2;
nsresult
PresShell::SetPrefNoScriptRule()
@ -1345,7 +1352,7 @@ nsresult PresShell::SetPrefLinkRules(void)
// NOTE: these must go in the agent stylesheet or they cannot be
// overridden by authors
rv = mPrefStyleSheet->
InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:underline}"),
InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:not(svg|a){text-decoration:underline}"),
sInsertPrefSheetRulesAt, &index);
} else {
rv = mPrefStyleSheet->

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

@ -94,11 +94,13 @@
#include "nsHyphenationManager.h"
#include "nsEditorSpellCheck.h"
#include "nsWindowMemoryReporter.h"
#include "mozilla/dom/ipc/ProcessPriorityManager.h"
extern void NS_ShutdownChainItemPool();
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::ipc;
nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0;
@ -243,6 +245,8 @@ nsLayoutStatics::Initialize()
nsSVGUtils::Init();
InitProcessPriorityManager();
return NS_OK;
}

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

@ -23,18 +23,24 @@ class PropertyProvider;
#define TEXT_HAS_FONT_INFLATION NS_FRAME_STATE_BIT(61)
class nsTextFrame : public nsFrame {
typedef nsFrame nsTextFrameBase;
class nsTextFrame : public nsTextFrameBase {
public:
NS_DECL_QUERYFRAME_TARGET(nsTextFrame)
NS_DECL_FRAMEARENA_HELPERS
friend class nsContinuingTextFrame;
nsTextFrame(nsStyleContext* aContext)
: nsFrame(aContext)
: nsTextFrameBase(aContext)
{
NS_ASSERTION(mContentOffset == 0, "Bogus content offset");
}
// nsQueryFrame
NS_DECL_QUERYFRAME
// nsIFrame
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,

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

@ -2404,6 +2404,10 @@ BuildTextRunsScanner::AssignTextRun(gfxTextRun* aTextRun, float aInflation)
}
}
NS_QUERYFRAME_HEAD(nsTextFrame)
NS_QUERYFRAME_ENTRY(nsTextFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsTextFrameBase)
gfxSkipCharsIterator
nsTextFrame::EnsureTextRun(TextRunType aWhichTextRun,
gfxContext* aReferenceContext,

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

@ -993,10 +993,10 @@ nsComputedDOMStyle::DoGetTransform()
/* First, get the display data. We'll need it. */
const nsStyleDisplay* display = GetStyleDisplay();
/* If the "no transforms" flag is set, then we should construct a
* single-element entry and hand it back.
/* If there are no transforms, then we should construct a single-element
* entry and hand it back.
*/
if (!display->HasTransform()) {
if (!display->mSpecifiedTransform) {
nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
/* Set it to "none." */

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

@ -18,11 +18,14 @@
#include "nsStyleContext.h"
#include "prlog.h"
#include "nsStyleAnimation.h"
#include "mozilla/Util.h"
#ifdef DEBUG
// #define NOISY_DEBUG
#endif
using namespace mozilla;
//----------------------------------------------------------------------
@ -699,19 +702,38 @@ NS_NewStyleContext(nsStyleContext* aParentContext,
return context;
}
static nscolor ExtractColor(nsCSSProperty aProperty,
nsStyleContext *aStyleContext)
static inline void
ExtractAnimationValue(nsCSSProperty aProperty,
nsStyleContext* aStyleContext,
nsStyleAnimation::Value& aResult)
{
nsStyleAnimation::Value val;
#ifdef DEBUG
bool success =
#endif
nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext, val);
DebugOnly<bool> success =
nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext, aResult);
NS_ABORT_IF_FALSE(success,
"aProperty must be extractable by nsStyleAnimation");
}
static nscolor
ExtractColor(nsCSSProperty aProperty,
nsStyleContext *aStyleContext)
{
nsStyleAnimation::Value val;
ExtractAnimationValue(aProperty, aStyleContext, val);
return val.GetColorValue();
}
static nscolor
ExtractColorLenient(nsCSSProperty aProperty,
nsStyleContext *aStyleContext)
{
nsStyleAnimation::Value val;
ExtractAnimationValue(aProperty, aStyleContext, val);
if (val.GetUnit() == nsStyleAnimation::eUnit_Color) {
return val.GetColorValue();
}
return NS_RGBA(0, 0, 0, 0);
}
struct ColorIndexSet {
PRUint8 colorIndex, alphaIndex;
};
@ -734,15 +756,20 @@ nsStyleContext::GetVisitedDependentColor(nsCSSProperty aProperty)
aProperty == eCSSProperty_stroke,
"we need to add to nsStyleContext::CalcStyleDifference");
bool isPaintProperty = aProperty == eCSSProperty_fill ||
aProperty == eCSSProperty_stroke;
nscolor colors[2];
colors[0] = ExtractColor(aProperty, this);
colors[0] = isPaintProperty ? ExtractColorLenient(aProperty, this)
: ExtractColor(aProperty, this);
nsStyleContext *visitedStyle = this->GetStyleIfVisited();
if (!visitedStyle) {
return colors[0];
}
colors[1] = ExtractColor(aProperty, visitedStyle);
colors[1] = isPaintProperty ? ExtractColorLenient(aProperty, visitedStyle)
: ExtractColor(aProperty, visitedStyle);
return nsStyleContext::CombineVisitedColors(colors,
this->RelevantLinkVisited());

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

@ -185,6 +185,7 @@ MOCHITEST_FILES = test_acid3_test46.html \
visited_image_loading_frame_empty.html \
test_load_events_on_stylesheets.html \
test_bug721136.html \
test_bug732153.html \
$(NULL)
ifdef MOZ_FLEXBOX

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

@ -0,0 +1,22 @@
<!doctype html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=732153
-->
<title>Test for Bug 732153</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=732153">Mozilla Bug 732153</a>
<div></div>
<script>
var div = document.querySelector("div");
[
"",
"backface-visibility: hidden",
"transform-style: preserve-3d",
"backface-visibility: hidden; transform-style: preserve-3d",
].forEach(function(style) {
div.setAttribute("style", style);
is(getComputedStyle(div).transform, "none",
"Computed 'transform' with style=\"" + style + '"');
});
</script>

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

@ -212,9 +212,9 @@ abstract public class BrowserApp extends GeckoApp
super.finishProfileMigration();
}
// We don't want to call super.initializeChrome in here because we don't
// want to create two DoorHangerPopup instances.
@Override void initializeChrome(String uri, Boolean isExternalURL) {
super.initializeChrome(uri, isExternalURL);
mBrowserToolbar.updateBackButton(false);
mBrowserToolbar.updateForwardButton(false);
@ -244,6 +244,8 @@ abstract public class BrowserApp extends GeckoApp
}
mBrowserToolbar.setProgressVisibility(isExternalURL || (mRestoreMode != GeckoAppShell.RESTORE_NONE));
mDoorHangerPopup = new DoorHangerPopup(this, mBrowserToolbar.mFavicon);
}
void toggleChrome(final boolean aShow) {
@ -436,17 +438,6 @@ abstract public class BrowserApp extends GeckoApp
});
}
/* Doorhanger notification methods */
@Override
void updatePopups(final Tab tab) {
mDoorHangerPopup.updatePopup(mBrowserToolbar.mFavicon);
}
@Override
void addDoorHanger(String message, String value, JSONArray buttons, Tab tab, JSONObject options) {
mDoorHangerPopup.addDoorHanger(message, value, buttons, tab, options, mBrowserToolbar.mFavicon);
}
/* Favicon methods */
private void loadFavicon(final Tab tab) {
maybeCancelFaviconLoad(tab);

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

@ -5,6 +5,7 @@
package org.mozilla.gecko;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -22,51 +23,79 @@ import android.widget.LinearLayout;
import android.widget.TextView;
public class DoorHanger extends LinearLayout implements Button.OnClickListener {
private static final String LOGTAG = "DoorHanger";
private static final String LOGTAG = "GeckoDoorHanger";
private Context mContext;
private GeckoApp mActivity;
// The popup that holds this doorhanger
private DoorHangerPopup mPopup;
private LinearLayout mChoicesLayout;
private TextView mTextView;
// LayoutParams used for adding button layouts
static private LayoutParams mLayoutParams;
public Tab mTab;
// value used to identify the notification
private String mValue;
private final int mTabId;
// Value used to identify the notification
private final String mValue;
// Optional checkbox added underneath message text
private CheckBox mCheckBox;
static private LayoutInflater mInflater;
private int mPersistence = 0;
private boolean mPersistWhileVisible = false;
private long mTimeout = 0;
public DoorHanger(Context aContext, String aValue) {
super(aContext);
DoorHanger(GeckoApp aActivity, DoorHangerPopup aPopup, int aTabId, String aValue) {
super(aActivity);
mContext = aContext;
mActivity = aActivity;
mPopup = aPopup;
mTabId = aTabId;
mValue = aValue;
}
int getTabId() {
return mTabId;
}
String getValue() {
return mValue;
}
// Postpone stuff that needs to be done on the main thread
void init(String message, JSONArray buttons, JSONObject options) {
setOrientation(VERTICAL);
setBackgroundResource(R.drawable.doorhanger_shadow_bg);
if (mInflater == null)
mInflater = LayoutInflater.from(mContext);
mInflater.inflate(R.layout.doorhanger, this);
hide();
LayoutInflater.from(mActivity).inflate(R.layout.doorhanger, this);
setVisibility(View.GONE);
mTextView = (TextView) findViewById(R.id.doorhanger_title);
mTextView.setText(message);
mChoicesLayout = (LinearLayout) findViewById(R.id.doorhanger_choices);
// Set the doorhanger text and buttons
for (int i = 0; i < buttons.length(); i++) {
try {
JSONObject buttonObject = buttons.getJSONObject(i);
String label = buttonObject.getString("label");
int callBackId = buttonObject.getInt("callback");
addButton(label, callBackId);
} catch (JSONException e) {
Log.e(LOGTAG, "Error creating doorhanger button", e);
}
}
setOptions(options);
}
private void addButton(String aText, int aCallback) {
if (mLayoutParams == null)
mLayoutParams = new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT,
1.0f);
}
public void addButton(String aText, int aCallback) {
Button mButton = new Button(mContext);
Button mButton = new Button(mActivity);
mButton.setText(aText);
mButton.setTag(Integer.toString(aCallback));
mButton.setOnClickListener(this);
@ -81,48 +110,20 @@ public class DoorHanger extends LinearLayout implements Button.OnClickListener {
// If the checkbox is being used, pass its value
if (mCheckBox != null)
response.put("checked", mCheckBox.isChecked());
} catch (JSONException ex) {
Log.e(LOGTAG, "Error creating onClick response: " + ex);
} catch (JSONException e) {
Log.e(LOGTAG, "Error creating onClick response", e);
}
GeckoEvent e = GeckoEvent.createBroadcastEvent("Doorhanger:Reply", response.toString());
GeckoAppShell.sendEventToGecko(e);
mTab.removeDoorHanger(mValue);
mPopup.removeDoorHanger(this);
// This will hide the doorhanger (and hide the popup if there are no
// more doorhangers to show)
((GeckoApp)mContext).updatePopups(mTab);
mPopup.updatePopup();
}
public void show() {
setVisibility(View.VISIBLE);
}
public void hide() {
setVisibility(View.GONE);
}
public boolean isVisible() {
return getVisibility() == View.VISIBLE;
}
public String getValue() {
return mValue;
}
public void setText(String aText) {
mTextView.setText(aText);
}
public Tab getTab() {
return mTab;
}
public void setTab(Tab tab) {
mTab = tab;
}
public void setOptions(JSONObject options) {
private void setOptions(JSONObject options) {
try {
mPersistence = options.getInt("persistence");
} catch (JSONException e) { }
@ -144,7 +145,7 @@ public class DoorHanger extends LinearLayout implements Button.OnClickListener {
URLSpan linkSpan = new URLSpan(linkUrl) {
@Override
public void onClick(View view) {
GeckoApp.mAppContext.loadUrlInTab(this.getURL());
mActivity.loadUrlInTab(this.getURL());
}
};
@ -167,8 +168,8 @@ public class DoorHanger extends LinearLayout implements Button.OnClickListener {
// This method checks with persistence and timeout options to see if
// it's okay to remove a doorhanger.
public boolean shouldRemove() {
if (mPersistWhileVisible && GeckoApp.mAppContext.mDoorHangerPopup.isShowing()) {
boolean shouldRemove() {
if (mPersistWhileVisible && mPopup.isShowing()) {
// We still want to decrement mPersistence, even if the popup is showing
if (mPersistence != 0)
mPersistence--;

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

@ -21,34 +21,109 @@ import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import java.util.HashMap;
import java.util.HashSet;
public class DoorHangerPopup extends PopupWindow {
public class DoorHangerPopup extends PopupWindow
implements GeckoEventListener, Tabs.OnTabsChangedListener {
private static final String LOGTAG = "GeckoDoorHangerPopup";
private Context mContext;
private GeckoApp mActivity;
private View mAnchor;
private LinearLayout mContent;
private boolean mInflated;
private ImageView mArrow;
private int mArrowWidth;
public DoorHangerPopup(Context aContext) {
super(aContext);
mContext = aContext;
// Stores a set of all active DoorHanger notifications. A DoorHanger is
// uniquely identified by its tabId and value.
private HashSet<DoorHanger> mDoorHangers;
DoorHangerPopup(GeckoApp aActivity, View aAnchor) {
super(aActivity);
mActivity = aActivity;
mAnchor = aAnchor;
mInflated = false;
mArrowWidth = aContext.getResources().getDimensionPixelSize(R.dimen.doorhanger_arrow_width);
}
mArrowWidth = aActivity.getResources().getDimensionPixelSize(R.dimen.doorhanger_arrow_width);
mDoorHangers = new HashSet<DoorHanger>();
GeckoAppShell.registerGeckoEventListener("Doorhanger:Add", this);
GeckoAppShell.registerGeckoEventListener("Doorhanger:Remove", this);
Tabs.registerOnTabsChangedListener(this);
}
void destroy() {
GeckoAppShell.unregisterGeckoEventListener("Doorhanger:Add", this);
GeckoAppShell.unregisterGeckoEventListener("Doorhanger:Remove", this);
Tabs.unregisterOnTabsChangedListener(this);
}
public void handleMessage(String event, JSONObject geckoObject) {
try {
if (event.equals("Doorhanger:Add")) {
int tabId = geckoObject.getInt("tabID");
String value = geckoObject.getString("value");
String message = geckoObject.getString("message");
JSONArray buttons = geckoObject.getJSONArray("buttons");
JSONObject options = geckoObject.getJSONObject("options");
addDoorHanger(tabId, value, message, buttons, options);
} else if (event.equals("Doorhanger:Remove")) {
int tabId = geckoObject.getInt("tabID");
String value = geckoObject.getString("value");
DoorHanger doorHanger = getDoorHanger(tabId, value);
if (doorHanger == null)
return;
removeDoorHanger(doorHanger);
mActivity.runOnUiThread(new Runnable() {
public void run() {
updatePopup();
}
});
}
} catch (Exception e) {
Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
}
}
public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
switch(msg) {
case CLOSED:
// Remove any doorhangers for a tab when it's closed
for (DoorHanger dh : mDoorHangers) {
if (dh.getTabId() == tab.getId())
removeDoorHanger(dh);
}
break;
case LOCATION_CHANGE:
// Only remove doorhangers if the popup is hidden or if we're navigating to a new URL
if (!isShowing() || !data.equals(tab.getURL()))
removeTransientDoorHangers(tab.getId());
// Update the popup if the location change was on the current tab
if (Tabs.getInstance().isSelectedTab(tab))
updatePopup();
break;
case SELECTED:
// Always update the popup when a new tab is selected. This will cover cases
// where a different tab was closed, since we always need to select a new tab.
updatePopup();
break;
}
}
private void init() {
setBackgroundDrawable(new BitmapDrawable());
setOutsideTouchable(true);
setFocusable(true);
setWindowLayoutMode(GeckoApp.mAppContext.isTablet() ? ViewGroup.LayoutParams.WRAP_CONTENT : ViewGroup.LayoutParams.FILL_PARENT,
setWindowLayoutMode(mActivity.isTablet() ? ViewGroup.LayoutParams.WRAP_CONTENT : ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
LayoutInflater inflater = LayoutInflater.from(mContext);
LayoutInflater inflater = LayoutInflater.from(mActivity);
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.doorhangerpopup, null);
mArrow = (ImageView) layout.findViewById(R.id.doorhanger_arrow);
mContent = (LinearLayout) layout.findViewById(R.id.doorhanger_container);
@ -57,111 +132,123 @@ public class DoorHangerPopup extends PopupWindow {
mInflated = true;
}
public void addDoorHanger(String message, String value, JSONArray buttons,
Tab tab, JSONObject options, View v) {
Log.i(LOGTAG, "Adding a DoorHanger to Tab: " + tab.getId());
if (!mInflated)
init();
void addDoorHanger(final int tabId, final String value, final String message,
final JSONArray buttons, final JSONObject options) {
// Don't add a doorhanger for a tab that doesn't exist
if (Tabs.getInstance().getTab(tabId) == null)
return;
// Replace the doorhanger if it already exists
DoorHanger dh = tab.getDoorHanger(value);
if (dh != null) {
tab.removeDoorHanger(value);
}
dh = new DoorHanger(mContent.getContext(), value);
// Set the doorhanger text and buttons
dh.setText(message);
for (int i = 0; i < buttons.length(); i++) {
try {
JSONObject buttonObject = buttons.getJSONObject(i);
String label = buttonObject.getString("label");
int callBackId = buttonObject.getInt("callback");
dh.addButton(label, callBackId);
} catch (JSONException e) {
Log.i(LOGTAG, "JSON throws", e);
DoorHanger oldDoorHanger = getDoorHanger(tabId, value);
if (oldDoorHanger != null)
removeDoorHanger(oldDoorHanger);
final DoorHanger newDoorHanger = new DoorHanger(mActivity, this, tabId, value);
mDoorHangers.add(newDoorHanger);
// Update the UI bits on the main thread
mActivity.runOnUiThread(new Runnable() {
public void run() {
if (!mInflated)
init();
newDoorHanger.init(message, buttons, options);
mContent.addView(newDoorHanger);
// Only update the popup if we're adding a notifcation to the selected tab
if (tabId == Tabs.getInstance().getSelectedTab().getId())
updatePopup();
}
}
dh.setOptions(options);
dh.setTab(tab);
tab.addDoorHanger(value, dh);
mContent.addView(dh);
// Only update the popup if we're adding a notifcation to the selected tab
if (tab.equals(Tabs.getInstance().getSelectedTab()))
updatePopup(v);
});
}
// Updates popup contents to show doorhangers for the selected tab
public void updatePopup() {
updatePopup(null);
DoorHanger getDoorHanger(int tabId, String value) {
for (DoorHanger dh : mDoorHangers) {
if (dh.getTabId() == tabId && dh.getValue().equals(value))
return dh;
}
// If there's no doorhanger for the given tabId and value, return null
return null;
}
public void updatePopup(View v) {
void removeDoorHanger(final DoorHanger doorHanger) {
mDoorHangers.remove(doorHanger);
// Update the UI on the main thread
mActivity.runOnUiThread(new Runnable() {
public void run() {
mContent.removeView(doorHanger);
}
});
}
void removeTransientDoorHangers(int tabId) {
// Make a temporary set to avoid a ConcurrentModificationException
HashSet<DoorHanger> doorHangersToRemove = new HashSet<DoorHanger>();
for (DoorHanger dh : mDoorHangers) {
// Only remove transient doorhangers for the given tab
if (dh.getTabId() == tabId && dh.shouldRemove())
doorHangersToRemove.add(dh);
}
for (DoorHanger dh : doorHangersToRemove) {
removeDoorHanger(dh);
}
}
void updatePopup() {
// Bail if the selected tab is null, if there are no active doorhangers,
// or if we haven't inflated the layout yet (this can happen if updatePopup()
// is called before the runnable from addDoorHanger() runs).
Tab tab = Tabs.getInstance().getSelectedTab();
if (tab == null) {
hidePopup();
return;
}
Log.i(LOGTAG, "Showing all doorhangers for tab: " + tab.getId());
HashMap<String, DoorHanger> doorHangers = tab.getDoorHangers();
// Hide the popup if there aren't any doorhangers to show
if (doorHangers == null || doorHangers.size() == 0) {
hidePopup();
return;
}
if (!mInflated)
init();
// Hide old doorhangers
for (int i = 0; i < mContent.getChildCount(); i++) {
DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
dh.hide();
}
// Show the doorhangers for the tab
for (DoorHanger dh : doorHangers.values()) {
dh.show();
}
if (v == null)
showAtLocation(((GeckoApp)mContext).getView(), Gravity.TOP, 0, 0);
else
showPopup(v);
}
public void hidePopup() {
if (isShowing()) {
if (tab == null || mDoorHangers.size() == 0 || !mInflated) {
dismiss();
return;
}
// Show doorhangers for the selected tab
int tabId = tab.getId();
boolean shouldShowPopup = false;
for (DoorHanger dh : mDoorHangers) {
if (dh.getTabId() == tabId) {
dh.setVisibility(View.VISIBLE);
shouldShowPopup = true;
} else {
dh.setVisibility(View.GONE);
}
}
// Dismiss the popup if there are no doorhangers to show for this tab
if (!shouldShowPopup) {
dismiss();
return;
}
}
public void showPopup(View v) {
fixBackgroundForFirst();
if (isShowing()) {
update();
return;
}
// If there's no anchor, just show the popup at the top of the gecko app view.
if (mAnchor == null) {
showAtLocation(mActivity.getView(), Gravity.TOP, 0, 0);
return;
}
// On tablets, we need to position the popup so that the center of the arrow points to the
// center of the anchor view. On phones the popup stretches across the entire screen, so the
// arrow position is determined by its left margin.
int offset = GeckoApp.mAppContext.isTablet() ? v.getWidth()/2 - mArrowWidth/2 -
int offset = mActivity.isTablet() ? mAnchor.getWidth()/2 - mArrowWidth/2 -
((RelativeLayout.LayoutParams) mArrow.getLayoutParams()).leftMargin : 0;
showAsDropDown(v, offset, 0);
showAsDropDown(mAnchor, offset, 0);
}
private void fixBackgroundForFirst() {
for (int i=0; i < mContent.getChildCount(); i++) {
for (int i = 0; i < mContent.getChildCount(); i++) {
DoorHanger dh = (DoorHanger) mContent.getChildAt(i);
if (dh.isVisible()) {
if (dh.getVisibility() == View.VISIBLE) {
dh.setBackgroundResource(R.drawable.doorhanger_bg);
break;
}

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

@ -213,7 +213,6 @@ abstract public class GeckoApp
break;
// Fall through...
case SELECTED:
updatePopups(tab);
invalidateOptionsMenu();
break;
}
@ -663,14 +662,6 @@ abstract public class GeckoApp
public void hideFormAssistPopup() {
if (mFormAssistPopup != null)
mFormAssistPopup.hide();
}
void updatePopups(final Tab tab) {
mDoorHangerPopup.updatePopup();
}
void addDoorHanger(String message, String value, JSONArray buttons, Tab tab, JSONObject options) {
mDoorHangerPopup.addDoorHanger(message, value, buttons, tab, options, null);
}
void handleLocationChange(final int tabId, final String uri,
@ -680,10 +671,6 @@ abstract public class GeckoApp
if (tab == null)
return;
// Only remove doorhangers if the popup is hidden or if we're navigating to a new URL
if (!mDoorHangerPopup.isShowing() || !uri.equals(tab.getURL()))
tab.removeTransientDoorHangers();
tab.updateURL(uri);
tab.setDocumentURI(documentURI);
@ -705,7 +692,7 @@ abstract public class GeckoApp
mMainHandler.post(new Runnable() {
public void run() {
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOCATION_CHANGE);
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.LOCATION_CHANGE, uri);
}
});
}
@ -937,10 +924,6 @@ abstract public class GeckoApp
} else if (event.equals("Content:PageShow")) {
final int tabId = message.getInt("tabID");
handlePageShow(tabId);
} else if (event.equals("Doorhanger:Add")) {
handleDoorHanger(message);
} else if (event.equals("Doorhanger:Remove")) {
handleDoorHangerRemove(message);
} else if (event.equals("Gecko:Ready")) {
sIsGeckoReady = true;
final Menu menu = mMenu;
@ -1218,41 +1201,6 @@ abstract public class GeckoApp
});
}
void handleDoorHanger(JSONObject geckoObject) throws JSONException {
final String message = geckoObject.getString("message");
final String value = geckoObject.getString("value");
final JSONArray buttons = geckoObject.getJSONArray("buttons");
final int tabId = geckoObject.getInt("tabID");
final JSONObject options = geckoObject.getJSONObject("options");
Log.i(LOGTAG, "DoorHanger received for tab " + tabId + ", msg:" + message);
mMainHandler.post(new Runnable() {
public void run() {
Tab tab = Tabs.getInstance().getTab(tabId);
if (tab != null)
addDoorHanger(message, value, buttons, tab, options);
}
});
}
void handleDoorHangerRemove(JSONObject geckoObject) throws JSONException {
final String value = geckoObject.getString("value");
final int tabId = geckoObject.getInt("tabID");
Log.i(LOGTAG, "Doorhanger:Remove received for tab " + tabId);
mMainHandler.post(new Runnable() {
public void run() {
Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
return;
tab.removeDoorHanger(value);
updatePopups(tab);
}
});
}
void handleDocumentStart(int tabId, final boolean showProgress, String uri) {
final Tab tab = Tabs.getInstance().getTab(tabId);
if (tab == null)
@ -1610,7 +1558,9 @@ abstract public class GeckoApp
((GeckoApplication) getApplication()).addApplicationLifecycleCallbacks(this);
}
void initializeChrome(String uri, Boolean isExternalURL) { }
void initializeChrome(String uri, Boolean isExternalURL) {
mDoorHangerPopup = new DoorHangerPopup(this, null);
}
private void initialize() {
mInitialized = true;
@ -1729,8 +1679,6 @@ abstract public class GeckoApp
}
mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
mDoorHangerPopup = new DoorHangerPopup(this);
mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup);
Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - UI almost up");
@ -1749,8 +1697,6 @@ abstract public class GeckoApp
GeckoAppShell.registerGeckoEventListener("Content:PageShow", this);
GeckoAppShell.registerGeckoEventListener("Reader:FaviconRequest", this);
GeckoAppShell.registerGeckoEventListener("onCameraCapture", this);
GeckoAppShell.registerGeckoEventListener("Doorhanger:Add", this);
GeckoAppShell.registerGeckoEventListener("Doorhanger:Remove", this);
GeckoAppShell.registerGeckoEventListener("Menu:Add", this);
GeckoAppShell.registerGeckoEventListener("Menu:Remove", this);
GeckoAppShell.registerGeckoEventListener("Gecko:Ready", this);
@ -2114,8 +2060,6 @@ abstract public class GeckoApp
GeckoAppShell.unregisterGeckoEventListener("Content:PageShow", this);
GeckoAppShell.unregisterGeckoEventListener("Reader:FaviconRequest", this);
GeckoAppShell.unregisterGeckoEventListener("onCameraCapture", this);
GeckoAppShell.unregisterGeckoEventListener("Doorhanger:Add", this);
GeckoAppShell.unregisterGeckoEventListener("Doorhanger:Remove", this);
GeckoAppShell.unregisterGeckoEventListener("Menu:Add", this);
GeckoAppShell.unregisterGeckoEventListener("Menu:Remove", this);
GeckoAppShell.unregisterGeckoEventListener("Gecko:Ready", this);
@ -2150,6 +2094,8 @@ abstract public class GeckoApp
mLayerController.destroy();
if (mLayerClient != null)
mLayerClient.destroy();
if (mDoorHangerPopup != null)
mDoorHangerPopup.destroy();
if (mFormAssistPopup != null)
mFormAssistPopup.destroy();
if (mPromptService != null)

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

@ -49,7 +49,6 @@ public final class Tab {
private boolean mExternal;
private boolean mBookmark;
private boolean mReadingListItem;
private HashMap<String, DoorHanger> mDoorHangers;
private long mFaviconLoadId;
private String mDocumentURI;
private String mContentType;
@ -89,7 +88,6 @@ public final class Tab {
mHistorySize = 0;
mBookmark = false;
mReadingListItem = false;
mDoorHangers = new HashMap<String, DoorHanger>();
mFaviconLoadId = 0;
mDocumentURI = "";
mContentType = "";
@ -106,7 +104,6 @@ public final class Tab {
}
public void onDestroy() {
mDoorHangers = new HashMap<String, DoorHanger>();
BrowserDB.unregisterContentObserver(mContentResolver, mContentObserver);
}
@ -492,43 +489,6 @@ public final class Tab {
return true;
}
public void addDoorHanger(String value, DoorHanger dh) {
mDoorHangers.put(value, dh);
}
public void removeDoorHanger(String value) {
mDoorHangers.remove(value);
}
public void removeTransientDoorHangers() {
// Make a temporary set to avoid a ConcurrentModificationException
final HashSet<String> valuesToRemove = new HashSet<String>();
for (String value : mDoorHangers.keySet()) {
DoorHanger dh = mDoorHangers.get(value);
if (dh.shouldRemove())
valuesToRemove.add(value);
}
for (String value : valuesToRemove) {
mDoorHangers.remove(value);
}
}
public DoorHanger getDoorHanger(String value) {
if (mDoorHangers == null)
return null;
if (mDoorHangers.containsKey(value))
return mDoorHangers.get(value);
return null;
}
public HashMap<String, DoorHanger> getDoorHangers() {
return mDoorHangers;
}
void handleSessionHistoryMessage(String event, JSONObject message) throws JSONException {
if (event.equals("New")) {
final String url = message.getString("url");

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

@ -1,6 +1,7 @@
{
"runtests": {},
"excludetests": {
"content/base/test/test_bug590812.html": "bug 687032",
"content/base/test/test_CSP.html": "TIMED_OUT",
"content/base/test/test_CSP_frameancestors.html": "",
"content/base/test/test_CSP_inlinescript.html": "",
@ -124,7 +125,6 @@
"docshell/test/test_bug637644.html": "",
"docshell/test/test_bug668513.html": "RANDOM",
"dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html": "TIMED_OUT, bug 766586",
"dom/browser-element/mochitest/test_browserElement_inproc_Iconchange.html": "bug 775227",
"dom/browser-element/mochitest/test_browserElement_inproc_SecurityChange.html": "TIMED_OUT, bug 766586",
"dom/imptests/editing/conformancetest/test_event.html": "",
"dom/imptests/editing/conformancetest/test_runtest.html": "",
@ -140,7 +140,7 @@
"dom/imptests/webapps/DOMCore/tests/approved/test_Range-mutations.html": "bug 775227",
"dom/imptests/webapps/DOMCore/tests/approved/test_Range-set.html": "bug 775227",
"dom/imptests/webapps/DOMCore/tests/approved/test_Range-surroundContents.html": "bug 775227",
"dom/imptests/webapps/WebStorage/tests/submissions/Infraware/test_event_session_key.html": "bug 775227",
"dom/imptests/webapps/WebStorage/tests/submissions/Infraware/test_storage_local_key.html": "bug 775227",
"dom/indexedDB/test/test_third_party.html": "TIMED_OUT",
"dom/network/tests/test_network_basics.html": "",
"dom/settings/tests/test_settings_events.html": "",