зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-i to m-c.
This commit is contained in:
Коммит
579ea680e3
|
@ -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=$@
|
||||
|
|
16
hal/Hal.cpp
16
hal/Hal.cpp
|
@ -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": "",
|
||||
|
|
Загрузка…
Ссылка в новой задаче