Merge mozilla-central into build-system

This commit is contained in:
Gregory Szorc 2012-12-30 13:47:04 -08:00
commit 86ec7725e5
610 changed files with 17510 additions and 9756 deletions

View File

@ -62,8 +62,8 @@ interface nsIAccessibleProvider : nsISupports
const long XULTab = 0x00001017;
/** Used for XUL tabs element, a container for tab elements */
const long XULTabs = 0x00001018;
/** Used for XUL deck frame */
const long XULDeck = 0x00001019;
/** Used for XUL tabpanels element */
const long XULTabpanels = 0x00001019;
const long XULText = 0x0000101A;
const long XULTextBox = 0x0000101B;

View File

@ -52,7 +52,7 @@ enum AccType {
eMenuPopupType,
eProgressType,
eRootType,
eXULDeckType,
eXULTabpanelsType,
eXULTreeType,
eLastAccType = eXULTreeType

View File

@ -49,7 +49,7 @@ DocManager::GetDocAccessible(nsIDocument* aDocument)
// Ensure CacheChildren is called before we query cache.
ApplicationAcc()->EnsureChildren();
DocAccessible* docAcc = mDocAccessibleCache.GetWeak(aDocument);
DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
if (docAcc)
return docAcc;
@ -181,7 +181,7 @@ DocManager::OnStateChange(nsIWebProgress* aWebProgress,
logging::DocLoad("start document loading", aWebProgress, aRequest, aStateFlags);
#endif
DocAccessible* docAcc = mDocAccessibleCache.GetWeak(document);
DocAccessible* docAcc = GetExistingDocAccessible(document);
if (!docAcc)
return NS_OK;
@ -280,7 +280,7 @@ DocManager::HandleEvent(nsIDOMEvent* aEvent)
// We're allowed to not remove listeners when accessible document is
// shutdown since we don't keep strong reference on chrome event target and
// listeners are removed automatically when chrome event target goes away.
DocAccessible* docAccessible = mDocAccessibleCache.GetWeak(document);
DocAccessible* docAccessible = GetExistingDocAccessible(document);
if (docAccessible)
docAccessible->Shutdown();
@ -312,7 +312,7 @@ DocManager::HandleDOMDocumentLoad(nsIDocument* aDocument,
{
// Document accessible can be created before we were notified the DOM document
// was loaded completely. However if it's not created yet then create it.
DocAccessible* docAcc = mDocAccessibleCache.GetWeak(aDocument);
DocAccessible* docAcc = GetExistingDocAccessible(aDocument);
if (!docAcc) {
docAcc = CreateDocOrRootAccessible(aDocument);
if (!docAcc)
@ -358,7 +358,7 @@ DocManager::CreateDocOrRootAccessible(nsIDocument* aDocument)
// Ignore documents without presshell and not having root frame.
nsIPresShell* presShell = aDocument->GetShell();
if (!presShell || !presShell->GetRootFrame() || presShell->IsDestroying())
if (!presShell || presShell->IsDestroying())
return nullptr;
bool isRootDoc = nsCoreUtils::IsRootDocument(aDocument);

View File

@ -59,14 +59,6 @@ public:
*/
Accessible* FindAccessibleInCache(nsINode* aNode) const;
/**
* Return document accessible from the cache. Convenient method for testing.
*/
inline DocAccessible* GetDocAccessibleFromCache(nsIDocument* aDocument) const
{
return mDocAccessibleCache.GetWeak(aDocument);
}
/**
* Called by document accessible when it gets shutdown.
*/
@ -154,6 +146,18 @@ private:
DocAccessibleHashtable mDocAccessibleCache;
};
/**
* Return the existing document accessible for the document if any.
* Note this returns the doc accessible for the primary pres shell if there is
* more than one.
*/
inline DocAccessible*
GetExistingDocAccessible(const nsIDocument* aDocument)
{
nsIPresShell* ps = aDocument->GetShell();
return ps ? ps->GetDocAccessible() : nullptr;
}
} // namespace a11y
} // namespace mozilla

View File

@ -400,8 +400,7 @@ logging::DocLoad(const char* aMsg, nsIWebProgress* aWebProgress,
}
nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(DOMDocument));
DocAccessible* document =
GetAccService()->GetDocAccessibleFromCache(documentNode);
DocAccessible* document = GetExistingDocAccessible(documentNode);
LogDocInfo(documentNode, document);
@ -425,8 +424,7 @@ logging::DocLoad(const char* aMsg, nsIDocument* aDocumentNode)
{
MsgBegin(sDocLoadTitle, aMsg);
DocAccessible* document =
GetAccService()->GetDocAccessibleFromCache(aDocumentNode);
DocAccessible* document = GetExistingDocAccessible(aDocumentNode);
LogDocInfo(aDocumentNode, document);
MsgEnd();
@ -486,7 +484,7 @@ logging::DocCreate(const char* aMsg, nsIDocument* aDocumentNode,
DocAccessible* aDocument)
{
DocAccessible* document = aDocument ?
aDocument : GetAccService()->GetDocAccessibleFromCache(aDocumentNode);
aDocument : GetExistingDocAccessible(aDocumentNode);
MsgBegin(sDocCreateTitle, aMsg);
LogDocInfo(aDocumentNode, document);
@ -498,7 +496,7 @@ logging::DocDestroy(const char* aMsg, nsIDocument* aDocumentNode,
DocAccessible* aDocument)
{
DocAccessible* document = aDocument ?
aDocument : GetAccService()->GetDocAccessibleFromCache(aDocumentNode);
aDocument : GetExistingDocAccessible(aDocumentNode);
MsgBegin(sDocDestroyTitle, aMsg);
LogDocInfo(aDocumentNode, document);

View File

@ -9,7 +9,7 @@
#include "nsAccessibilityService.h"
#include "nsAccUtils.h"
#include "nsCoreUtils.h"
#include "DocAccessible.h"
#include "DocAccessible-inl.h"
#include "nsEventShell.h"
#include "FocusManager.h"
#include "Role.h"
@ -213,6 +213,10 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
"Pending content insertions while initial accessible tree isn't created!");
}
// Initialize scroll support if needed.
if (!(mDocument->mDocFlags & DocAccessible::eScrollInitialized))
mDocument->AddScrollListener();
// Process content inserted notifications to update the tree. Process other
// notifications like DOM events and then flush event queue. If any new
// notifications are queued during this processing then they will be processed

View File

@ -60,6 +60,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/Util.h"
#include "nsDeckFrame.h"
#ifdef MOZ_XUL
#include "XULAlertAccessible.h"
@ -185,6 +186,7 @@ Accessible*
nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
bool aCanCreate)
{
nsIPresShell* ps = aPresShell;
nsIDocument* documentNode = aPresShell->GetDocument();
if (documentNode) {
nsCOMPtr<nsISupports> container = documentNode->GetContainer();
@ -196,11 +198,10 @@ nsAccessibilityService::GetRootDocumentAccessible(nsIPresShell* aPresShell,
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(rootTreeItem));
nsCOMPtr<nsIPresShell> presShell;
docShell->GetPresShell(getter_AddRefs(presShell));
documentNode = presShell->GetDocument();
ps = presShell;
}
return aCanCreate ?
GetDocAccessible(documentNode) : GetDocAccessibleFromCache(documentNode);
return aCanCreate ? GetDocAccessible(ps) : ps->GetDocAccessible();
}
}
return nullptr;
@ -254,6 +255,47 @@ nsAccessibilityService::CreatePluginAccessible(nsObjectFrame* aFrame,
return nullptr;
}
void
nsAccessibilityService::DeckPanelSwitched(nsIPresShell* aPresShell,
nsIContent* aDeckNode,
nsIFrame* aPrevBoxFrame,
nsIFrame* aCurrentBoxFrame)
{
// Ignore tabpanels elements (a deck having an accessible) since their
// children are accessible not depending on selected tab.
DocAccessible* document = GetDocAccessible(aPresShell);
if (!document || document->HasAccessible(aDeckNode))
return;
if (aPrevBoxFrame) {
nsIContent* panelNode = aPrevBoxFrame->GetContent();
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree)) {
logging::MsgBegin("TREE", "deck panel unselected");
logging::Node("container", panelNode);
logging::Node("content", aDeckNode);
logging::MsgEnd();
}
#endif
document->ContentRemoved(aDeckNode, panelNode);
}
if (aCurrentBoxFrame) {
nsIContent* panelNode = aCurrentBoxFrame->GetContent();
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eTree)) {
logging::MsgBegin("TREE", "deck panel selected");
logging::Node("container", panelNode);
logging::Node("content", aDeckNode);
logging::MsgEnd();
}
#endif
document->ContentInserted(aDeckNode, panelNode, panelNode->GetNextSibling());
}
}
void
nsAccessibilityService::ContentRangeInserted(nsIPresShell* aPresShell,
nsIContent* aContainer,
@ -364,15 +406,12 @@ nsAccessibilityService::UpdateImageMap(nsImageFrame* aImageFrame)
void
nsAccessibilityService::PresShellActivated(nsIPresShell* aPresShell)
{
nsIDocument* DOMDoc = aPresShell->GetDocument();
if (DOMDoc) {
DocAccessible* document = GetDocAccessibleFromCache(DOMDoc);
if (document) {
RootAccessible* rootDocument = document->RootAccessible();
NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!");
if (rootDocument)
rootDocument->DocumentActivated(document);
}
DocAccessible* document = aPresShell->GetDocAccessible();
if (document) {
RootAccessible* rootDocument = document->RootAccessible();
NS_ASSERTION(rootDocument, "Entirely broken tree: no root document!");
if (rootDocument)
rootDocument->DocumentActivated(document);
}
}
@ -608,7 +647,7 @@ nsAccessibilityService::GetAccessibleFromCache(nsIDOMNode* aNode,
if (!accessible) {
nsCOMPtr<nsIDocument> document(do_QueryInterface(node));
if (document)
accessible = GetDocAccessibleFromCache(document);
accessible = GetExistingDocAccessible(document);
}
NS_IF_ADDREF(*aAccessible = accessible);
@ -843,28 +882,43 @@ nsAccessibilityService::GetOrCreateAccessible(nsINode* aNode,
}
}
if (!newAcc) {
// Accessible XBL types and deck stuff are used in XUL only currently.
if (!newAcc && content->IsXUL()) {
// No accessible for not selected deck panel and its children.
if (!aContext->IsXULTabpanels()) {
nsDeckFrame* deckFrame = do_QueryFrame(frame->GetParent());
if (deckFrame && deckFrame->GetSelectedBox() != frame) {
if (aIsSubtreeHidden)
*aIsSubtreeHidden = true;
return nullptr;
}
}
// Elements may implement nsIAccessibleProvider via XBL. This allows them to
// say what kind of accessible to create.
newAcc = CreateAccessibleByType(content, document);
// Any XUL box can be used as tabpanel, make sure we create a proper
// accessible for it.
if (!newAcc && aContext->IsXULTabpanels() &&
content->GetParent() == aContext->GetContent()) {
nsIAtom* frameType = frame->GetType();
if (frameType == nsGkAtoms::boxFrame ||
frameType == nsGkAtoms::scrollFrame) {
newAcc = new XULTabpanelAccessible(content, document);
}
}
}
if (!newAcc) {
// xul:deck does not have XBL and nsIFrame::CreateAccessible() is only called
// on HTML elements
nsIAtom* tag = content->Tag();
if ((tag == nsGkAtoms::deck) || (tag == nsGkAtoms::tabpanels)) {
newAcc = new XULDeckAccessible(content, document);
} else if (content->IsSVG(nsGkAtoms::svg)) {
if (content->IsSVG(nsGkAtoms::svg)) {
newAcc = new EnumRoleAccessible(content, document, roles::DIAGRAM);
} else if (content->IsMathML(nsGkAtoms::math)) {
newAcc = new EnumRoleAccessible(content, document, roles::EQUATION);
}
}
if (!newAcc)
newAcc = CreateAccessibleForDeckChild(frame, content, document);
// If no accessible, see if we need to create a generic accessible because
// of some property that makes this object interesting
// We don't do this for <body>, <html>, <window>, <dialog> etc. which
@ -1011,8 +1065,8 @@ nsAccessibilityService::CreateAccessibleByType(nsIContent* aContent,
accessible = new XULComboboxAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULDeck:
accessible = new XULDeckAccessible(aContent, aDoc);
case nsIAccessibleProvider::XULTabpanels:
accessible = new XULTabpanelsAccessible(aContent, aDoc);
break;
case nsIAccessibleProvider::XULDropmarker:
@ -1480,37 +1534,6 @@ NS_GetAccessibilityService(nsIAccessibilityService** aResult)
////////////////////////////////////////////////////////////////////////////////
// nsAccessibilityService private (DON'T put methods here)
already_AddRefed<Accessible>
nsAccessibilityService::CreateAccessibleForDeckChild(nsIFrame* aFrame,
nsIContent* aContent,
DocAccessible* aDoc)
{
if (aFrame->GetType() == nsGkAtoms::boxFrame ||
aFrame->GetType() == nsGkAtoms::scrollFrame) {
nsIFrame* parentFrame = aFrame->GetParent();
if (parentFrame && parentFrame->GetType() == nsGkAtoms::deckFrame) {
// If deck frame is for xul:tabpanels element then the given node has
// tabpanel accessible.
nsIContent* parentContent = parentFrame->GetContent();
#ifdef MOZ_XUL
if (parentContent->NodeInfo()->Equals(nsGkAtoms::tabpanels,
kNameSpaceID_XUL)) {
Accessible* accessible = new XULTabpanelAccessible(aContent, aDoc);
NS_ADDREF(accessible);
return accessible;
}
#endif
Accessible* accessible = new EnumRoleAccessible(aContent, aDoc,
roles::PROPERTYPAGE);
NS_ADDREF(accessible);
return accessible;
}
}
return nullptr;
}
#ifdef MOZ_XUL
already_AddRefed<Accessible>
nsAccessibilityService::CreateAccessibleForXULTree(nsIContent* aContent,

View File

@ -64,6 +64,13 @@ public:
virtual Accessible* AddNativeRootAccessible(void* aAtkAccessible);
virtual void RemoveNativeRootAccessible(Accessible* aRootAccessible);
/**
* Notification used to update the accessible tree when deck panel is
* switched.
*/
void DeckPanelSwitched(nsIPresShell* aPresShell, nsIContent* aDeckNode,
nsIFrame* aPrevBoxFrame, nsIFrame* aCurrentBoxFrame);
/**
* Notification used to update the accessible tree when new content is
* inserted.
@ -173,13 +180,6 @@ private:
CreateAccessibleByFrameType(nsIFrame* aFrame, nsIContent* aContent,
Accessible* aContext);
/**
* Create accessible if parent is a deck frame.
*/
already_AddRefed<Accessible>
CreateAccessibleForDeckChild(nsIFrame* aFrame, nsIContent* aContent,
DocAccessible* aDoc);
#ifdef MOZ_XUL
/**
* Create accessible for XUL tree element.

View File

@ -612,6 +612,7 @@ Accessible::VisibilityState()
deckFrame->GetContent()->Tag() == nsGkAtoms::tabpanels)
return states::OFFSCREEN;
NS_NOTREACHED("Children of not selected deck panel are not accessible.");
return states::INVISIBLE;
}

View File

@ -520,7 +520,7 @@ public:
bool IsTextLeaf() const { return mType == eTextLeafType; }
TextLeafAccessible* AsTextLeaf();
bool IsXULDeck() const { return mType == eXULDeckType; }
bool IsXULTabpanels() const { return mType == eXULTabpanelsType; }
bool IsXULTree() const { return mType == eXULTreeType; }
XULTreeAccessible* AsXULTree();

View File

@ -65,6 +65,33 @@ DocAccessible::UpdateText(nsIContent* aTextNode)
mNotificationController->ScheduleTextUpdate(aTextNode);
}
inline void
DocAccessible::AddScrollListener()
{
// Delay scroll initializing until the document has a root frame.
if (!mPresShell->GetRootFrame())
return;
mDocFlags |= eScrollInitialized;
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
if (sf) {
sf->AddScrollPositionListener(this);
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eDocCreate))
logging::Text("add scroll listener");
#endif
}
}
inline void
DocAccessible::RemoveScrollListener()
{
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollable();
if (sf)
sf->RemoveScrollPositionListener(this);
}
inline void
DocAccessible::NotifyOfLoad(uint32_t aLoadEventType)
{

View File

@ -75,7 +75,7 @@ DocAccessible::
nsIPresShell* aPresShell) :
HyperTextAccessibleWrap(aRootContent, this),
mDocumentNode(aDocument), mScrollPositionChangedTicks(0),
mLoadState(eTreeConstructionPending), mLoadEventType(0),
mLoadState(eTreeConstructionPending), mDocFlags(0), mLoadEventType(0),
mVirtualCursor(nullptr),
mPresShell(aPresShell)
{
@ -93,18 +93,6 @@ DocAccessible::
// If this is a XUL Document, it should not implement nsHyperText
if (mDocumentNode && mDocumentNode->IsXUL())
mGenericTypes &= ~eHyperText;
// For GTK+ native window, we do nothing here.
if (!mDocumentNode)
return;
// DocManager creates document accessible when scrollable frame is
// available already, it should be safe time to add scroll listener.
AddScrollListener();
// We provide a virtual cursor if this is a root doc or if it's a tab doc.
mIsCursorable = (!(mDocumentNode->GetParentDocument()) ||
nsCoreUtils::IsTabDocument(mDocumentNode));
}
DocAccessible::~DocAccessible()
@ -145,7 +133,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DocAccessible)
NS_INTERFACE_MAP_ENTRY(nsIAccessiblePivotObserver)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessibleDocument)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleCursorable,
mIsCursorable)
(mDocFlags & eCursorable))
foundInterface = 0;
nsresult status;
@ -502,7 +490,8 @@ DocAccessible::GetVirtualCursor(nsIAccessiblePivot** aVirtualCursor)
if (IsDefunct())
return NS_ERROR_FAILURE;
NS_ENSURE_TRUE(mIsCursorable, NS_ERROR_NOT_IMPLEMENTED);
if (!(mDocFlags & eCursorable))
return NS_OK;
if (!mVirtualCursor) {
mVirtualCursor = new nsAccessiblePivot(this);
@ -603,8 +592,6 @@ DocAccessible::Shutdown()
logging::DocDestroy("document shutdown", mDocumentNode, this);
#endif
mPresShell->SetDocAccessible(nullptr);
if (mNotificationController) {
mNotificationController->Shutdown();
mNotificationController = nullptr;
@ -640,6 +627,7 @@ DocAccessible::Shutdown()
mVirtualCursor = nullptr;
}
mPresShell->SetDocAccessible(nullptr);
mPresShell = nullptr; // Avoid reentrancy
mDependentIDsHash.Clear();
@ -798,36 +786,6 @@ DocAccessible::ScrollTimerCallback(nsITimer* aTimer, void* aClosure)
}
}
// DocAccessible protected member
void
DocAccessible::AddScrollListener()
{
if (!mPresShell)
return;
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollableExternal();
if (sf) {
sf->AddScrollPositionListener(this);
#ifdef A11Y_LOG
if (logging::IsEnabled(logging::eDocCreate))
logging::Text("add scroll listener");
#endif
}
}
// DocAccessible protected member
void
DocAccessible::RemoveScrollListener()
{
if (!mPresShell)
return;
nsIScrollableFrame* sf = mPresShell->GetRootScrollFrameAsScrollableExternal();
if (sf) {
sf->RemoveScrollPositionListener(this);
}
}
////////////////////////////////////////////////////////////////////////////////
// nsIScrollPositionListener
@ -1511,14 +1469,23 @@ DocAccessible::NotifyOfLoading(bool aIsReloading)
void
DocAccessible::DoInitialUpdate()
{
if (nsCoreUtils::IsTabDocument(mDocumentNode))
mDocFlags |= eTabDocument;
// We provide a virtual cursor if this is a root doc or if it's a tab doc.
if (!mDocumentNode->GetParentDocument() || (mDocFlags & eTabDocument))
mDocFlags |= eCursorable;
mLoadState |= eTreeConstructed;
// The content element may be changed before the initial update and then we
// miss the notification (since content tree change notifications are ignored
// prior to initial update). Make sure the content element is valid.
nsIContent* contentElm = nsCoreUtils::GetRoleContent(mDocumentNode);
if (mContent != contentElm)
if (mContent != contentElm) {
mContent = contentElm;
SetRoleMapEntry(aria::GetRoleMap(mContent));
}
// Build initial tree.
CacheChildrenInSubtree(this);
@ -1739,8 +1706,10 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer,
if (aContainer == this) {
// If new root content has been inserted then update it.
nsIContent* rootContent = nsCoreUtils::GetRoleContent(mDocumentNode);
if (rootContent != mContent)
if (rootContent != mContent) {
mContent = rootContent;
SetRoleMapEntry(aria::GetRoleMap(mContent));
}
// Continue to update the tree even if we don't have root content.
// For example, elements may be inserted under the document element while

View File

@ -333,8 +333,11 @@ protected:
*/
void ProcessLoad();
void AddScrollListener();
void RemoveScrollListener();
/**
* Add/remove scroll listeners, @see nsIScrollPositionListener interface.
*/
void AddScrollListener();
void RemoveScrollListener();
/**
* Append the given document accessible to this document's child document
@ -482,6 +485,20 @@ protected:
protected:
/**
* State and property flags, kept by mDocFlags.
*/
enum {
// Whether scroll listeners were added.
eScrollInitialized = 1 << 0,
// Whether we support nsIAccessibleCursorable.
eCursorable = 1 << 1,
// Whether the document is a tab document.
eTabDocument = 1 << 2
};
/**
* Cache of accessibles within this document accessible.
*/
@ -496,7 +513,12 @@ protected:
/**
* Bit mask of document load states (@see LoadState).
*/
uint32_t mLoadState;
uint32_t mLoadState : 3;
/**
* Bit mask of other states and props.
*/
uint32_t mDocFlags : 28;
/**
* Type of document load event fired after the document is loaded completely.
@ -516,11 +538,6 @@ protected:
nsTArray<nsRefPtr<DocAccessible> > mChildDocuments;
/**
* Whether we support nsIAccessibleCursorable, used when querying the interface.
*/
bool mIsCursorable;
/**
* The virtual cursor of the document when it supports nsIAccessibleCursorable.
*/

View File

@ -191,7 +191,7 @@ this.EventManager = {
if (txtIface.characterCount)
throw x;
}
this.present(Presentation, textChanged(
this.present(Presentation.textChanged(
isInserted, event.start, event.length,
text, event.modifiedText));
}

View File

@ -60,9 +60,9 @@ AccessibleWrap::GetNativeType ()
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
if (IsXULDeck())
if (IsXULTabpanels())
return [mozPaneAccessible class];
roles::Role role = Role();
switch (role) {
case roles::PUSHBUTTON:

View File

@ -223,7 +223,7 @@ DocAccessibleWrap::Shutdown()
// Do window emulation specific shutdown if emulation was started.
if (nsWinUtils::IsWindowEmulationStarted()) {
// Destroy window created for root document.
if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
if (mDocFlags & eTabDocument) {
sHWNDCache.Remove(mHWND);
::DestroyWindow(static_cast<HWND>(mHWND));
}
@ -253,7 +253,7 @@ DocAccessibleWrap::DoInitialUpdate()
if (nsWinUtils::IsWindowEmulationStarted()) {
// Create window for tab document.
if (nsCoreUtils::IsTabDocument(mDocumentNode)) {
if (mDocFlags & eTabDocument) {
mozilla::dom::TabChild* tabChild =
mozilla::dom::GetTabChildFrom(mDocumentNode->GetShell());

View File

@ -18,9 +18,7 @@ namespace a11y {
inline DocAccessible*
sdnAccessible::GetDocument() const
{
DocManager* docMgr = GetAccService();
return docMgr ?
docMgr->GetDocAccessibleFromCache(mNode->OwnerDoc()) : nullptr;
return GetExistingDocAccessible(mNode->OwnerDoc());
}
inline Accessible*

View File

@ -163,11 +163,11 @@ XULTabsAccessible::NativeName(nsString& aName)
////////////////////////////////////////////////////////////////////////////////
// XULDeckAccessible
// XULTabpanelsAccessible
////////////////////////////////////////////////////////////////////////////////
role
XULDeckAccessible::NativeRole()
XULTabpanelsAccessible::NativeRole()
{
return roles::PANE;
}

View File

@ -62,12 +62,12 @@ protected:
/**
* A container of tab panels, xul:tabpanels element.
*/
class XULDeckAccessible : public AccessibleWrap
class XULTabpanelsAccessible : public AccessibleWrap
{
public:
XULDeckAccessible(nsIContent* aContent, DocAccessible* aDoc) :
XULTabpanelsAccessible(nsIContent* aContent, DocAccessible* aDoc) :
AccessibleWrap(aContent, aDoc)
{ mType = eXULDeckType; }
{ mType = eXULTabpanelsType; }
// Accessible
virtual a11y::role NativeRole();

View File

@ -32,7 +32,6 @@
"test1: frameDocCheckbox");
testStates(frameDocTextbox, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0,
"test1: frameDocTextbox");
frameDoc.designMode = "on";
testStates(frameDoc, 0, EXT_STATE_EDITABLE, STATE_READONLY, 0,
"test2: frameDoc");

View File

@ -20,7 +20,6 @@
<![CDATA[
function doTest()
{
testStates("deck_pane1", STATE_INVISIBLE, 0, STATE_OFFSCREEN);
testStates("deck_pane2", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
testStates("tabs_pane1", 0, 0, STATE_INVISIBLE | STATE_OFFSCREEN);
testStates("tabs_pane2", STATE_OFFSCREEN, 0, STATE_INVISIBLE);

View File

@ -17,6 +17,7 @@ MOCHITEST_A11Y_FILES =\
test_colorpicker.xul \
test_cssoverflow.html \
test_contextmenu.xul \
test_deck.xul \
test_doc.html \
test_gencontent.html \
test_hidden.html \

View File

@ -0,0 +1,109 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Tree update on XUL deck panel switching">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="../common.js" />
<script type="application/javascript"
src="../role.js" />
<script type="application/javascript"
src="../states.js" />
<script type="application/javascript"
src="../events.js" />
<script type="application/javascript">
<![CDATA[
function switchDeckPanel(aContainerID, aDeckID)
{
this.panelIndex = 0;
this.container = getAccessible(aContainerID);
this.deckNode = getNode(aDeckID);
this.prevPanel = getAccessible(this.deckNode.selectedPanel);
this.panelNode = this.deckNode.childNodes[this.panelIndex];
this.eventSeq = [
new invokerChecker(EVENT_HIDE, this.prevPanel),
new invokerChecker(EVENT_SHOW, this.panelNode),
new invokerChecker(EVENT_REORDER, this.container)
];
this.invoke = function switchDeckPanel_invoke()
{
var tree =
{ GROUPING: [ // role="group"
{ GROUPING: [ // groupbox, a selected panel #2
{ PUSHBUTTON: [ ] } // button
] }
] };
testAccessibleTree(this.container, tree);
this.deckNode.selectedIndex = this.panelIndex;
}
this.finalCheck = function switchDeckPanel_finalCheck()
{
var tree =
{ GROUPING: [ // role="group"
{ LABEL: [ // description, a selected panel #1
{ TEXT_LEAF: [] } // text leaf, a description value
] }
] };
testAccessibleTree(this.container, tree);
}
this.getID = function switchDeckPanel_getID()
{
return "switch deck panel";
}
}
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new switchDeckPanel("container", "deck"));
gQueue.invoke(); // will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=814836"
title=" xul:deck element messes up screen reader">
Mozilla Bug 814836
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1" id="container" role="group">
<deck id="deck" selectedIndex="1">
<description>This is the first page</description>
<groupbox>
<button label="This is the second page"/>
</groupbox>
</deck>
</vbox>
</hbox>
</window>

View File

@ -32,7 +32,7 @@
return getDocNode(aID).body.firstChild;
}
function rootContentReplaced(aID, aTextName)
function rootContentReplaced(aID, aTextName, aRootContentRole)
{
this.eventSeq = [
new invokerChecker(EVENT_SHOW, getDocChildNode, aID),
@ -42,7 +42,7 @@
this.finalCheck = function rootContentReplaced_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
role: aRootContentRole || ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
@ -142,14 +142,14 @@
docNode.replaceChild(newHTMLNode, docNode.documentElement);
}
this.getID = function replaceIFrameBody_getID()
this.getID = function replaceIFrameHTMLElm_getID()
{
return "replace HTML element";
}
}
/**
* Replace HTML body.
* Replace HTML body on new body having ARIA role.
*/
function replaceIFrameBody(aID)
{
@ -164,26 +164,36 @@
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
}
this.finalCheck = function replaceIFrameBody_finalCheck()
{
var tree = {
role: ROLE_DOCUMENT,
children: [
{
role: ROLE_TEXT_LEAF,
name: "New Hello"
}
]
};
testAccessibleTree(getDocNode(aID), tree);
}
this.getID = function replaceIFrameBody_getID()
{
return "replace body";
}
}
/**
* Replace HTML body on new body having ARIA role.
*/
function replaceIFrameBodyOnARIARoleBody(aID)
{
this.__proto__ = new rootContentReplaced(aID, "New Hello",
ROLE_PUSHBUTTON);
this.invoke = function replaceIFrameBodyOnARIARoleBody_invoke()
{
var docNode = getDocNode(aID);
var newBodyNode = docNode.createElement("body");
var newTextNode = docNode.createTextNode("New Hello");
newBodyNode.appendChild(newTextNode);
newBodyNode.setAttribute("role", "button");
docNode.documentElement.replaceChild(newBodyNode, docNode.body);
}
this.getID = function replaceIFrameBodyOnARIARoleBody_getID()
{
return "replace body on body having ARIA role";
}
}
/**
* Open/close document pair.
*/
@ -401,6 +411,7 @@
gQueue.push(new insertElmUnderDocElmWhileBodyMissed("iframe"));
gQueue.push(new insertBodyToIFrameDoc("iframe"));
gQueue.push(new changeSrc("iframe"));
gQueue.push(new replaceIFrameBodyOnARIARoleBody("iframe"));
gQueue.invoke(); // SimpleTest.finish() will be called in the end
}
@ -420,6 +431,9 @@
<a target="_blank"
title="Reorder event for document must be fired after document initial tree creation"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=669263">Mozilla Bug 669263</a>
<a target="_blank"
title="Changing the HTML body doesn't pick up ARIA role"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=818407">Mozilla Bug 818407</a>
<p id="display"></p>
<div id="content" style="display: none"></div>

View File

@ -356,13 +356,6 @@ pref("content.ime.strict_policy", true);
// $ adb shell start
pref("browser.dom.window.dump.enabled", false);
// Temporarily relax file:// origin checks so that we can use <img>s
// from other dirs as webgl textures and more. Remove me when we have
// installable apps or wifi support.
pref("security.fileuri.strict_origin_policy", false);
// Default Content Security Policy to apply to privileged and certified apps
pref("security.apps.privileged.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'");
pref("security.apps.certified.CSP.default", "default-src *; script-src 'self'; object-src 'none'; style-src 'self'");
@ -461,9 +454,6 @@ pref("shutdown.watchdog.timeoutSecs", 5);
pref("b2g.update.apply-prompt-timeout", 60000); // milliseconds
// Amount of time to wait after the user is idle before prompting to apply an update
pref("b2g.update.apply-idle-timeout", 600000); // milliseconds
// Amount of time the updater waits for the process to exit cleanly before
// forcefully exiting the process
pref("b2g.update.self-destruct-timeout", 5000); // milliseconds
pref("app.update.enabled", true);
pref("app.update.auto", false);
@ -601,6 +591,13 @@ pref("browser.prompt.allowNative", false);
// a restart is required to enable a new value.
pref("network.activity.blipIntervalMilliseconds", 250);
// By default we want the NetworkManager service to manage Gecko's offline
// status for us according to the state of Wifi/cellular data connections.
// In some environments, such as the emulator or hardware with other network
// connectivity, this is not desireable, however, in which case this pref
// can be flipped to false.
pref("network.gonk.manage-offline-status", true);
pref("jsloader.reuseGlobal", true);
// Enable font inflation for browser tab content.

View File

@ -282,14 +282,12 @@ function getJSON(element) {
// Until the input type=date/datetime/time have been implemented
// let's return their real type even if the platform returns 'text'
// Related to Bug 769352 - Implement <input type=date>
// Related to Bug 777279 - Implement <input type=time>
let attributeType = element.getAttribute("type") || "";
if (attributeType) {
var typeLowerCase = attributeType.toLowerCase();
switch (typeLowerCase) {
case "date":
case "time":
case "datetime":
case "datetime-local":

View File

@ -103,7 +103,7 @@ var shell = {
} catch(e) { }
// Bail if there isn't a valid crashID.
if (!crashID) {
if (!crashID && !this.CrashSubmit.pendingIDs().length) {
return;
}
@ -125,10 +125,20 @@ var shell = {
});
},
// this function submit the pending crashes.
// make sure you are online.
submitQueuedCrashes: function shell_submitQueuedCrashes() {
// submit the pending queue.
let pending = shell.CrashSubmit.pendingIDs();
for (let crashid of pending) {
shell.CrashSubmit.submit(crashid);
}
},
// This function submits a crash when we're online.
submitCrash: function shell_submitCrash(aCrashID) {
if (this.onlineForCrashReport()) {
this.CrashSubmit.submit(aCrashID);
this.submitQueuedCrashes();
return;
}
@ -136,13 +146,7 @@ var shell = {
let network = subject.QueryInterface(Ci.nsINetworkInterface);
if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_CONNECTED
&& network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
shell.CrashSubmit.submit(aCrashID);
// submit the pending queue.
let pending = shell.CrashSubmit.pendingIDs();
for (let crashid of pending) {
shell.CrashSubmit.submit(crashid);
}
shell.submitQueuedCrashes();
Services.obs.removeObserver(observer, topic);
}
@ -684,7 +688,7 @@ var AlertsHelper = {
let message = messages[i];
if (message === "notification") {
return helper.fullLaunchPath();
} else if ("notification" in message) {
} else if (typeof message == "object" && "notification" in message) {
return helper.resolveFromOrigin(message["notification"]);
}
}

View File

@ -18,14 +18,9 @@ let log =
function log_dump(msg) { dump("UpdatePrompt: "+ msg +"\n"); } :
function log_noop(msg) { };
const APPLY_PROMPT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.apply-prompt-timeout");
const APPLY_IDLE_TIMEOUT =
Services.prefs.getIntPref("b2g.update.apply-idle-timeout");
const SELF_DESTRUCT_TIMEOUT =
Services.prefs.getIntPref("b2g.update.self-destruct-timeout");
const PREF_APPLY_PROMPT_TIMEOUT = "b2g.update.apply-prompt-timeout";
const PREF_APPLY_IDLE_TIMEOUT = "b2g.update.apply-idle-timeout";
const APPLY_IDLE_TIMEOUT_SECONDS = APPLY_IDLE_TIMEOUT / 1000;
const NETWORK_ERROR_OFFLINE = 111;
XPCOMUtils.defineLazyServiceGetter(Services, "aus",
@ -108,6 +103,14 @@ UpdatePrompt.prototype = {
_waitingForIdle: false,
_updateCheckListner: null,
get applyPromptTimeout() {
return Services.prefs.getIntPref(PREF_APPLY_PROMPT_TIMEOUT);
},
get applyIdleTimeout() {
return Services.prefs.getIntPref(PREF_APPLY_IDLE_TIMEOUT);
},
// nsIUpdatePrompt
// FIXME/bug 737601: we should have users opt-in to downloading
@ -130,14 +133,15 @@ UpdatePrompt.prototype = {
// update quietly without user intervention.
this.sendUpdateEvent("update-downloaded", aUpdate);
if (Services.idle.idleTime >= APPLY_IDLE_TIMEOUT) {
if (Services.idle.idleTime >= this.applyIdleTimeout) {
this.showApplyPrompt(aUpdate);
return;
}
let applyIdleTimeoutSeconds = this.applyIdleTimeout / 1000;
// We haven't been idle long enough, so register an observer
log("Update is ready to apply, registering idle timeout of " +
APPLY_IDLE_TIMEOUT_SECONDS + " seconds before prompting.");
applyIdleTimeoutSeconds + " seconds before prompting.");
this._update = aUpdate;
this.waitForIdle();
@ -165,7 +169,7 @@ UpdatePrompt.prototype = {
}
this._waitingForIdle = true;
Services.idle.addIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
Services.idle.addIdleObserver(this, this.applyIdleTimeout / 1000);
Services.obs.addObserver(this, "quit-application", false);
},
@ -185,7 +189,7 @@ UpdatePrompt.prototype = {
// Schedule a fallback timeout in case the UI is unable to respond or show
// a prompt for some reason.
this._applyPromptTimer = this.createTimer(APPLY_PROMPT_TIMEOUT);
this._applyPromptTimer = this.createTimer(this.applyPromptTimeout);
},
sendUpdateEvent: function UP_sendUpdateEvent(aType, aUpdate) {
@ -429,7 +433,7 @@ UpdatePrompt.prototype = {
this.showApplyPrompt(this._update);
// Fall through
case "quit-application":
Services.idle.removeIdleObserver(this, APPLY_IDLE_TIMEOUT_SECONDS);
Services.idle.removeIdleObserver(this, this.applyIdleTimeout / 1000);
Services.obs.removeObserver(this, "quit-application");
break;
case "update-check-start":

View File

@ -16,17 +16,6 @@ XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
.getService(Ci.nsIMessageSender);
});
// Splits parameters in a query string.
function extractParameters(aQuery) {
let params = aQuery.split("&");
let res = {};
params.forEach(function(aParam) {
let obj = aParam.split("=");
res[obj[0]] = decodeURIComponent(obj[1]);
});
return res;
}
function YoutubeProtocolHandler() {
}
@ -61,24 +50,95 @@ YoutubeProtocolHandler.prototype = {
.createInstance(Ci.nsIXMLHttpRequest);
xhr.open("GET", infoURI, true);
xhr.addEventListener("load", function() {
// Youtube sends the response as a double wrapped url answer:
// we first extract the url_encoded_fmt_stream_map parameter,
// and from each comma-separated entry in this value, we extract
// other parameters (url and type).
let key = "url_encoded_fmt_stream_map=";
let pos = xhr.responseText.indexOf(key);
if (pos == -1) {
return;
try {
let info = parseYoutubeVideoInfo(xhr.responseText);
cpmm.sendAsyncMessage("content-handler", info);
}
let streams = decodeURIComponent(xhr.responseText
.substring(pos + key.length)).split(",");
let uri;
let mimeType;
catch(e) {
// If parseYoutubeVideoInfo() can't find a video URL, it
// throws an Error. We report the error message here and do
// nothing. This shouldn't happen often. But if it does, the user
// will find that clicking on a video doesn't do anything.
log(e.message);
}
});
xhr.send(null);
// itag is an undocumented value which maps to resolution and mimetype
// see https://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
// Ordered from least to most preferred
let recognizedItags = [
function log(msg) {
msg = "YoutubeProtocolHandler.js: " + (msg.join ? msg.join(" ") : msg);
Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService)
.logStringMessage(msg);
}
//
// Parse the response from a youtube get_video_info query.
//
// If youtube's response is a failure, this function returns an object
// with status, errorcode, type and reason properties. Otherwise, it returns
// an object with status, url, and type properties, and optional
// title, poster, and duration properties.
//
function parseYoutubeVideoInfo(response) {
// Splits parameters in a query string.
function extractParameters(q) {
let params = q.split("&");
let result = {};
for(let i = 0, n = params.length; i < n; i++) {
let param = params[i];
let pos = param.indexOf('=');
if (pos === -1)
continue;
let name = param.substring(0, pos);
let value = param.substring(pos+1);
result[name] = decodeURIComponent(value);
}
return result;
}
let params = extractParameters(response);
// If the request failed, return an object with an error code
// and an error message
if (params.status === 'fail') {
//
// Hopefully this error message will be properly localized.
// Do we need to add any parameters to the XMLHttpRequest to
// specify the language we want?
//
// Note that we include fake type and url properties in the returned
// object. This is because we still need to trigger the video app's
// view activity handler to display the error message from youtube,
// and those parameters are required.
//
return {
status: params.status,
errorcode: params.errorcode,
reason: (params.reason || '').replace(/\+/g, ' '),
type: 'video/3gpp',
url: 'https://m.youtube.com'
}
}
// Otherwise, the query was successful
let result = {
status: params.status,
};
// Now parse the available streams
let streamsText = params.url_encoded_fmt_stream_map;
if (!streamsText)
throw Error("No url_encoded_fmt_stream_map parameter");
let streams = streamsText.split(',');
for(let i = 0, n = streams.length; i < n; i++) {
streams[i] = extractParameters(streams[i]);
}
// This is the list of youtube video formats, ordered from worst
// (but playable) to best. These numbers are values used as the
// itag parameter of each stream description. See
// https://en.wikipedia.org/wiki/YouTube#Quality_and_codecs
let formats = [
"17", // 144p 3GP
"36", // 240p 3GP
"43", // 360p WebM
@ -87,39 +147,39 @@ YoutubeProtocolHandler.prototype = {
#endif
];
let bestItag = -1;
let extras = { }
streams.forEach(function(aStream) {
let params = extractParameters(aStream);
let url = params["url"];
let type = params["type"] ? params["type"].split(";")[0] : null;
let itag = params["itag"];
let index;
if (url && type && ((index = recognizedItags.indexOf(itag)) != -1) &&
index > bestItag) {
uri = url + '&signature=' + (params["sig"] ? params['sig'] : '');
mimeType = type;
bestItag = index;
}
for (let param in params) {
if (["thumbnail_url", "length_seconds", "title"].indexOf(param) != -1) {
extras[param] = decodeURIComponent(params[param]);
}
}
// Sort the array of stream descriptions in order of format
// preference, so that the first item is the most preferred one
streams.sort(function(a, b) {
let x = a.itag ? formats.indexOf(a.itag) : -1;
let y = b.itag ? formats.indexOf(b.itag) : -1;
return y - x;
});
if (uri && mimeType) {
cpmm.sendAsyncMessage("content-handler", {
url: uri,
type: mimeType,
extras: extras
});
let bestStream = streams[0];
// If the best stream is a format we don't support just return
if (formats.indexOf(bestStream.itag) === -1)
throw Error("No supported video formats");
result.url = bestStream.url + '&signature=' + (bestStream.sig || '');
result.type = bestStream.type;
// Strip codec information off of the mime type
if (result.type && result.type.indexOf(';') !== -1) {
result.type = result.type.split(';',1)[0];
}
});
xhr.send(null);
if (params.title) {
result.title = params.title.replace(/\+/g, ' ');
}
if (params.length_seconds) {
result.duration = params.length_seconds;
}
if (params.thumbnail_url) {
result.poster = params.thumbnail_url;
}
return result;
}
throw Components.results.NS_ERROR_ILLEGAL_VALUE;
},

View File

@ -1,6 +1,6 @@
[
{
"clang_version": "r170377"
"clang_version": "r170890"
},
{
"size": 47,
@ -9,8 +9,8 @@
"filename": "setup.sh"
},
{
"size": 56131193,
"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
"size": 56126352,
"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

View File

@ -244,7 +244,6 @@ pref("browser.chrome.site_icons", true);
pref("browser.chrome.favicons", true);
// browser.warnOnQuit == false will override all other possible prompts when quitting or restarting
pref("browser.warnOnQuit", true);
pref("browser.warnOnRestart", false);
// browser.showQuitWarning specifically controls the quit warning dialog. We
// might still show the window closing dialog with showQuitWarning == false.
pref("browser.showQuitWarning", false);

View File

@ -5,6 +5,10 @@
var FullScreen = {
_XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
get _fullScrToggler() {
delete this._fullScrToggler;
return this._fullScrToggler = document.getElementById("fullscr-toggler");
},
toggle: function (event) {
var enterFS = window.fullScreen;
@ -46,15 +50,8 @@ var FullScreen = {
// events than raw listening of mouse coords. We don't add the toolbar in DOM full-screen
// mode, only browser full-screen mode.
if (!document.mozFullScreen) {
let fullScrToggler = document.getElementById("fullscr-toggler");
if (!fullScrToggler) {
fullScrToggler = document.createElement("hbox");
fullScrToggler.id = "fullscr-toggler";
fullScrToggler.collapsed = true;
gNavToolbox.parentNode.insertBefore(fullScrToggler, gNavToolbox.nextSibling);
}
fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false);
}
if (gPrefService.getBoolPref("browser.fullscreen.autohide"))
gBrowser.mPanelContainer.addEventListener("mousemove",
@ -152,13 +149,10 @@ var FullScreen = {
this._cancelAnimation();
this.mouseoverToggle(false);
// If there's a full-screen toggler, remove its listeners, so that mouseover
// Remove listeners on the full-screen toggler, so that mouseover
// the top of the screen will not cause the toolbar to re-appear.
let fullScrToggler = document.getElementById("fullscr-toggler");
if (fullScrToggler) {
fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
}
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
},
cleanup: function () {
@ -170,11 +164,8 @@ var FullScreen = {
document.removeEventListener("popuphidden", this._setPopupOpen, false);
gPrefService.removeObserver("browser.fullscreen", this);
let fullScrToggler = document.getElementById("fullscr-toggler");
if (fullScrToggler) {
fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
}
this._fullScrToggler.removeEventListener("mouseover", this._expandCallback, false);
this._fullScrToggler.removeEventListener("dragenter", this._expandCallback, false);
this.cancelWarning();
gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
@ -506,10 +497,7 @@ var FullScreen = {
gNavToolbox.style.marginTop =
aShow ? "" : -gNavToolbox.getBoundingClientRect().height + "px";
let toggler = document.getElementById("fullscr-toggler");
if (toggler) {
toggler.collapsed = aShow;
}
this._fullScrToggler.collapsed = aShow;
this._isChromeCollapsed = !aShow;
if (gPrefService.getIntPref("browser.fullscreen.animateUp") == 2)
this._shouldAnimate = true;

View File

@ -448,7 +448,7 @@ var ctrlTab = {
if (tabs.length > 2) {
this.open();
} else if (tabs.length == 2) {
let index = gBrowser.selectedTab == tabs[0] ? 1 : 0;
let index = tabs[0].selected ? 1 : 0;
gBrowser.selectedTab = tabs[index];
}
}
@ -488,7 +488,7 @@ var ctrlTab = {
this.advanceFocus(false);
// If the current tab is removed, another tab can steal our focus.
if (aTab == gBrowser.selectedTab && this.panel.state == "open") {
if (aTab.selected && this.panel.state == "open") {
setTimeout(function (selected) {
selected.focus();
}, 0, this.selected);

View File

@ -0,0 +1,52 @@
# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
let WebrtcIndicator = {
init: function () {
let temp = {};
Cu.import("resource:///modules/webrtcUI.jsm", temp);
this.UIModule = temp.webrtcUI;
this.updateButton();
},
get button() {
delete this.button;
return this.button = document.getElementById("webrtc-status-button");
},
updateButton: function () {
this.button.hidden = !this.UIModule.showGlobalIndicator;
},
fillPopup: function (aPopup) {
this._menuitemData = new WeakMap;
for (let streamData of this.UIModule.activeStreams) {
let menuitem = document.createElement("menuitem");
menuitem.setAttribute("label", streamData.uri);
menuitem.setAttribute("tooltiptext", streamData.uri);
this._menuitemData.set(menuitem, streamData);
aPopup.appendChild(menuitem);
}
},
clearPopup: function (aPopup) {
while (aPopup.lastChild)
aPopup.removeChild(aPopup.lastChild);
},
menuCommand: function (aMenuitem) {
let streamData = this._menuitemData.get(aMenuitem);
if (!streamData)
return;
let tab = streamData.tab;
let browserWindow = tab.ownerDocument.defaultView;
browserWindow.gBrowser.selectedTab = tab;
browserWindow.focus();
}
}

View File

@ -476,10 +476,6 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
max-width: 280px;
}
#geolocation-notification {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#geolocation-notification");
}
#addon-progress-notification {
-moz-binding: url("chrome://browser/content/urlbarBindings.xml#addon-progress-notification");
}

View File

@ -155,6 +155,7 @@ let gInitialPages = [
#include browser-tabPreviews.js
#include browser-tabview.js
#include browser-thumbnails.js
#include browser-webrtcUI.js
#ifdef MOZ_SERVICES_SYNC
#include browser-syncui.js
@ -1254,6 +1255,7 @@ var gBrowserInit = {
gFormSubmitObserver.init();
SocialUI.init();
AddonManager.addAddonListener(AddonsMgrListener);
WebrtcIndicator.init();
gBrowser.addEventListener("pageshow", function(event) {
// Filter out events that are not about the document load we are interested in
@ -3772,7 +3774,7 @@ var XULBrowserWindow = {
startTime: 0,
statusText: "",
isBusy: false,
inContentWhitelist: ["about:addons", "about:permissions",
inContentWhitelist: ["about:addons", "about:downloads", "about:permissions",
"about:sync-progress", "about:preferences"],
QueryInterface: function (aIID) {

View File

@ -464,6 +464,13 @@
</menulist>
</popupnotificationcontent>
</popupnotification>
<popupnotification id="geolocation-notification" hidden="true">
<popupnotificationcontent orient="vertical" align="start">
<separator class="thin"/>
<label id="geolocation-learnmore-link" class="text-link"/>
</popupnotificationcontent>
</popupnotification>
</popupset>
#ifdef CAN_DRAW_IN_TITLEBAR
@ -521,7 +528,7 @@
toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
fullscreentoolbar="true" mode="icons" customizable="true"
iconsize="large"
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,downloads-button,home-button,bookmarks-menu-button-container,window-controls"
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,downloads-button,home-button,bookmarks-menu-button-container,window-controls"
context="toolbar-context-menu">
<toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
@ -578,6 +585,8 @@
<image id="webapps-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="blocked-plugins-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="webRTC-shareDevices-notification-icon" class="notification-anchor-icon" role="button"/>
<image id="webRTC-sharingDevices-notification-icon" class="notification-anchor-icon" role="button"/>
</box>
<!-- Use onclick instead of normal popup= syntax since the popup
code fires onmousedown, and hence eats our favicon drag events.
@ -653,6 +662,16 @@
<searchbar id="searchbar" flex="1"/>
</toolbaritem>
<toolbarbutton id="webrtc-status-button"
class="toolbarbutton-1 chromeclass-toolbar-additional"
type="menu"
hidden="true"
orient="horizontal">
<menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
onpopuphiding="WebrtcIndicator.clearPopup(this);"
oncommand="WebrtcIndicator.menuCommand(event.target);"/>
</toolbarbutton>
<toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
persist="class" removable="true"
label="&homeButton.label;"
@ -1050,6 +1069,8 @@
</toolbarpalette>
</toolbox>
<hbox id="fullscr-toggler" collapsed="true"/>
<hbox flex="1" id="browser">
<vbox id="browser-border-start" hidden="true" layer="true"/>
<vbox id="sidebar-box" hidden="true" class="chromeclass-extrachrome">

View File

@ -851,11 +851,11 @@
var oldTab = this.mCurrentTab;
// Preview mode should not reset the owner
if (!this._previewMode && oldTab != this.selectedTab)
if (!this._previewMode && !oldTab.selected)
oldTab.owner = null;
if (this._lastRelatedTab) {
if (this._lastRelatedTab != this.selectedTab)
if (!this._lastRelatedTab.selected)
this._lastRelatedTab.owner = null;
this._lastRelatedTab = null;
}
@ -876,7 +876,7 @@
newBrowser.docShellIsActive =
(window.windowState != window.STATE_MINIMIZED);
this.mCurrentBrowser = newBrowser;
this.mCurrentTab = this.selectedTab;
this.mCurrentTab = this.tabContainer.selectedItem;
this.showTab(this.mCurrentTab);
var backForwardContainer = document.getElementById("unified-back-forward-button");
@ -957,8 +957,7 @@
true, false);
}
if (this.mCurrentTab.selected)
this._setCloseKeyState(!this.mCurrentTab.pinned);
this._setCloseKeyState(!this.mCurrentTab.pinned);
// TabSelect events are suppressed during preview mode to avoid confusing extensions and other bits of code
// that might rely upon the other changes suppressed.
@ -1671,7 +1670,7 @@
const filter = this.mTabFilters[aTab._tPos];
#ifdef MOZ_E10S_COMPAT
// Bug 666801 - WebProgress support for e10s
#else
#else
browser.webProgress.removeProgressListener(filter);
#endif
filter.removeProgressListener(this.mTabListeners[aTab._tPos]);
@ -1825,7 +1824,7 @@
<parameter name="aTab"/>
<body>
<![CDATA[
if (this.mCurrentTab != aTab)
if (!aTab.selected)
return;
if (aTab.owner &&
@ -1875,7 +1874,7 @@
// The tab is definitely not loading.
aNewTab.removeAttribute("busy");
if (aNewTab == this.selectedTab) {
if (aNewTab.selected) {
this.mIsBusy = false;
}
@ -1884,7 +1883,7 @@
// Update the new tab's title.
this.setTabTitle(aNewTab);
if (aNewTab == this.selectedTab) {
if (aNewTab.selected) {
this.updateCurrentBrowser(true);
}
]]>
@ -1923,7 +1922,7 @@
if (isBusy) {
aOurTab.setAttribute("busy", "true");
this._tabAttrModified(aOurTab);
if (aOurTab == this.selectedTab)
if (aOurTab.selected)
this.mIsBusy = true;
}
@ -1939,7 +1938,7 @@
// If the tab was already selected (this happpens in the scenario
// of replaceTabWithWindow), notify onLocationChange, etc.
if (aOurTab == this.selectedTab)
if (aOurTab.selected)
this.updateCurrentBrowser(true);
]]>
</body>
@ -2136,7 +2135,7 @@
<property name="selectedTab">
<getter>
return this.mTabBox.selectedTab;
return this.mCurrentTab;
</getter>
<setter>
<![CDATA[
@ -2203,6 +2202,8 @@
this.mTabFilters.splice(aIndex, 0, this.mTabFilters.splice(aTab._tPos, 1)[0]);
this.mTabListeners.splice(aIndex, 0, this.mTabListeners.splice(aTab._tPos, 1)[0]);
let wasFocused = (document.activeElement == this.mCurrentTab);
aIndex = aIndex < aTab._tPos ? aIndex: aIndex+1;
this.mCurrentTab._selected = false;
@ -2219,6 +2220,10 @@
this.tabs[i]._selected = false;
}
this.mCurrentTab._selected = true;
if (wasFocused)
this.mCurrentTab.focus();
this.tabContainer._handleTabSelect(false);
if (aTab.pinned)
@ -2234,11 +2239,12 @@
<method name="moveTabForward">
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos < this.browsers.length - 1) {
this.moveTabTo(this.mCurrentTab, tabPos + 1);
this.mCurrentTab.focus();
}
let nextTab = this.mCurrentTab.nextSibling;
while (nextTab && nextTab.hidden)
nextTab = nextTab.nextSibling;
if (nextTab)
this.moveTabTo(this.mCurrentTab, nextTab._tPos);
else if (this.arrowKeysShouldWrap)
this.moveTabToStart();
]]>
@ -2248,11 +2254,12 @@
<method name="moveTabBackward">
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos > 0) {
this.moveTabTo(this.mCurrentTab, tabPos - 1);
this.mCurrentTab.focus();
}
let previousTab = this.mCurrentTab.previousSibling;
while (previousTab && previousTab.hidden)
previousTab = previousTab.previousSibling;
if (previousTab)
this.moveTabTo(this.mCurrentTab, previousTab._tPos);
else if (this.arrowKeysShouldWrap)
this.moveTabToEnd();
]]>
@ -2263,10 +2270,8 @@
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos > 0) {
if (tabPos > 0)
this.moveTabTo(this.mCurrentTab, 0);
this.mCurrentTab.focus();
}
]]>
</body>
</method>
@ -2275,11 +2280,8 @@
<body>
<![CDATA[
var tabPos = this.mCurrentTab._tPos;
if (tabPos < this.browsers.length - 1) {
this.moveTabTo(this.mCurrentTab,
this.browsers.length - 1);
this.mCurrentTab.focus();
}
if (tabPos < this.browsers.length - 1)
this.moveTabTo(this.mCurrentTab, this.browsers.length - 1);
]]>
</body>
</method>

View File

@ -82,7 +82,7 @@ var gWebProgressListener = {
}
ok(gNewTab, "There is a new tab.");
ok(isRedirectedURI(aLocation),
ok(isRedirectedURI(aLocation),
"onLocationChange catches only redirected URI.");
if (aLocation.ref == "BG") {
@ -97,7 +97,7 @@ var gWebProgressListener = {
ok(false, "This URI hash is not expected:" + aLocation.ref);
}
let isSelectedTab = (gNewTab == gBrowser.selectedTab);
let isSelectedTab = gNewTab.selected;
setTimeout(delayed, 0, isSelectedTab);
}
};

View File

@ -59,7 +59,7 @@ function test() {
pressCtrlTab(true);
pressCtrlTab(true);
releaseCtrl();
ok(gBrowser.selectedTab == selectedTab,
ok(selectedTab.selected,
"Ctrl+Tab*2 -> Ctrl+W -> Ctrl+Shift+Tab*2 keeps the selected tab");
}
gBrowser.removeTab(gBrowser.tabContainer.lastChild);

View File

@ -707,13 +707,12 @@ function checkPopup(popup, notificationObj) {
is(notification.getAttribute("buttonlabel"), notificationObj.mainAction.label, "main action label matches");
is(notification.getAttribute("buttonaccesskey"), notificationObj.mainAction.accessKey, "main action accesskey matches");
}
let actualSecondaryActions = notification.childNodes;
let actualSecondaryActions = Array.filter(notification.childNodes,
function (child) child.nodeName == "menuitem");
let secondaryActions = notificationObj.secondaryActions || [];
let actualSecondaryActionsCount = actualSecondaryActions.length;
if (secondaryActions.length) {
let lastChild = actualSecondaryActions.item(actualSecondaryActions.length - 1);
is(lastChild.tagName, "menuseparator", "menuseparator exists");
actualSecondaryActionsCount--;
is(notification.lastChild.tagName, "menuseparator", "menuseparator exists");
}
is(actualSecondaryActionsCount, secondaryActions.length, actualSecondaryActions.length + " secondary actions");
secondaryActions.forEach(function (a, i) {

View File

@ -903,50 +903,6 @@
</implementation>
</binding>
<binding id="geolocation-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
<content align="start">
<xul:image class="popup-notification-icon"
xbl:inherits="popupid,src=icon"/>
<xul:vbox flex="1">
<xul:description class="popup-notification-description"
xbl:inherits="xbl:text=label"/>
<xul:spacer flex="1"/>
<xul:hbox class="popup-notification-button-container"
pack="end" align="center">
<xul:label anonid="learnmore" class="text-link geolocation-text-link"/>
<xul:spacer flex="1"/>
<xul:button anonid="button"
type="menu-button"
class="popup-notification-menubutton"
xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
<xul:menupopup anonid="menupopup"
xbl:inherits="oncommand=menucommand">
<children/>
<xul:menuitem class="menuitem-iconic popup-notification-closeitem"
label="&closeNotificationItem.label;"
xbl:inherits="oncommand=closeitemcommand"/>
</xul:menupopup>
</xul:button>
</xul:hbox>
</xul:vbox>
<xul:vbox pack="start">
<xul:toolbarbutton anonid="closebutton"
class="messageCloseButton popup-notification-closebutton tabbable"
xbl:inherits="oncommand=closebuttoncommand"
tooltiptext="&closeNotification.tooltip;"/>
</xul:vbox>
</content>
<implementation>
<constructor><![CDATA[
let link = document.getAnonymousElementByAttribute(this, "anonid", "learnmore");
link.value = gNavigatorBundle.getString("geolocation.learnMore");
let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
link.href = formatter.formatURLPref("browser.geolocation.warning.infoURL");
]]></constructor>
</implementation>
</binding>
<binding id="addon-progress-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
<content align="start">
<xul:image class="popup-notification-icon"

View File

@ -80,6 +80,8 @@ static RedirEntry kRedirMap[] = {
nsIAboutModule::ALLOW_SCRIPT },
{ "preferences", "chrome://browser/content/preferences/in-content/preferences.xul",
nsIAboutModule::ALLOW_SCRIPT },
{ "downloads", "chrome://browser/content/downloads/contentAreaDownloadsView.xul",
nsIAboutModule::ALLOW_SCRIPT },
};
static const int kRedirTotal = NS_ARRAY_LENGTH(kRedirMap);

View File

@ -30,7 +30,6 @@ endif
LOCAL_INCLUDES = \
-I$(srcdir)/../shell/src \
-I$(srcdir)/../feeds/src \
-I$(srcdir)/../privatebrowsing/src \
-I$(srcdir)/../about \
-I$(srcdir)/../dirprovider \
$(NULL)
@ -41,11 +40,15 @@ endif
SHARED_LIBRARY_LIBS = \
../feeds/src/$(LIB_PREFIX)browser_feeds_s.$(LIB_SUFFIX) \
../privatebrowsing/src/$(LIB_PREFIX)privatebrowsing_s.$(LIB_SUFFIX) \
../about/$(LIB_PREFIX)browserabout_s.$(LIB_SUFFIX) \
../dirprovider/$(LIB_PREFIX)browserdir_s.$(LIB_SUFFIX) \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
LOCAL_INCLUDES += -I$(srcdir)/../privatebrowsing/src
SHARED_LIBRARY_LIBS += ../privatebrowsing/src/$(LIB_PREFIX)privatebrowsing_s.$(LIB_SUFFIX)
endif
ifneq (,$(filter windows cocoa gtk2, $(MOZ_WIDGET_TOOLKIT)))
SHARED_LIBRARY_LIBS += ../shell/src/$(LIB_PREFIX)shellservice_s.$(LIB_SUFFIX)
endif

View File

@ -25,7 +25,9 @@
#include "AboutRedirector.h"
#include "nsIAboutModule.h"
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
#include "nsPrivateBrowsingServiceWrapper.h"
#endif
#include "nsNetCID.h"
using namespace mozilla::browser;
@ -47,7 +49,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsIEHistoryEnumerator)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFeedSniffer)
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrivateBrowsingServiceWrapper, Init)
#endif
NS_DEFINE_NAMED_CID(NS_BROWSERDIRECTORYPROVIDER_CID);
#if defined(XP_WIN)
@ -62,7 +66,9 @@ NS_DEFINE_NAMED_CID(NS_WINIEHISTORYENUMERATOR_CID);
#elif defined(XP_MACOSX)
NS_DEFINE_NAMED_CID(NS_SHELLSERVICE_CID);
#endif
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
NS_DEFINE_NAMED_CID(NS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID);
#endif
static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
{ &kNS_BROWSERDIRECTORYPROVIDER_CID, false, NULL, DirectoryProviderConstructor },
@ -78,7 +84,9 @@ static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
#elif defined(XP_MACOSX)
{ &kNS_SHELLSERVICE_CID, false, NULL, nsMacShellServiceConstructor },
#endif
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
{ &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID, false, NULL, nsPrivateBrowsingServiceWrapperConstructor },
#endif
{ NULL }
};
@ -108,12 +116,15 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "newtab", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "permissions", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "preferences", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "downloads", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#if defined(XP_WIN)
{ NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
#elif defined(XP_MACOSX)
{ NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
#endif
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
{ NS_PRIVATE_BROWSING_SERVICE_CONTRACTID, &kNS_PRIVATE_BROWSING_SERVICE_WRAPPER_CID },
#endif
{ NULL }
};

View File

@ -600,6 +600,7 @@ function DownloadsPlacesView(aRichListBox) {
// Make sure to unregister the view if the window is closed.
window.addEventListener("unload", function() {
this._richlistbox.controllers.removeController(this);
downloadsData.removeView(this);
this.result = null;
}.bind(this), true);
@ -770,6 +771,7 @@ DownloadsPlacesView.prototype = {
// sibling first, if any.
if (aElement.nextSibling &&
this._richlistbox.selectedItems &&
this._richlistbox.selectedItems.length > 0 &&
this._richlistbox.selectedItems[0] == aElement) {
this._richlistbox.selectItem(aElement.nextSibling);
}
@ -882,8 +884,8 @@ DownloadsPlacesView.prototype = {
let placesNodes = [];
let selectedElements = this._richlistbox.selectedItems;
for (let elt of selectedElements) {
if (elt.placesNode)
placesNodes.push(elt.placesNode);
if (elt._shell.placesNode)
placesNodes.push(elt._shell.placesNode);
}
return placesNodes;
},

View File

@ -5,12 +5,20 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<?xml-stylesheet href="chrome://global/skin/"?>
<?xml-stylesheet href="chrome://browser/skin/downloads/contentAreaDownloadsView.css"?>
<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<!DOCTYPE window [
<!ENTITY % downloadsDTD SYSTEM "chrome://browser/locale/downloads/downloads.dtd">
%downloadsDTD;
]>
<window id="contentAreaDownloadsView"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&downloads.title;"
onload="ContentAreaDownloadsView.init();">
<script type="application/javascript"

View File

@ -107,28 +107,11 @@ DownloadsUI.prototype = {
},
/**
* Helper function that opens the right download manager UI. Either the
* new Downloads View in Places, or the toolkit download window if the
* Places Downloads View is not enabled.
* Helper function that opens the download manager UI.
*/
_showDownloadManagerUI:
function DUI_showDownloadManagerUI(aWindowContext, aID, aReason)
{
// First, determine if the Places Downloads view is preffed on.
let usePlacesView = false;
try {
usePlacesView =
Services.prefs.getBoolPref("browser.library.useNewDownloadsView");
} catch(e) {}
if (!usePlacesView) {
// If we got here, then the browser.library.useNewDownloadsView pref
// either didn't exist or was false, so just show the toolkit downloads
// manager.
this._toolkitUI.show(aWindowContext, aID, aReason);
return;
}
let organizer = Services.wm.getMostRecentWindow("Places:Organizer");
if (!organizer) {
let parentWindow = aWindowContext;

View File

@ -551,19 +551,21 @@ BrowserGlue.prototype = {
// browser.startup.page == 3 or browser.sessionstore.resume_session_once == true
// 3. browser.warnOnQuit == false
// 4. The browser is currently in Private Browsing mode
// 5. The browser will be restarted.
//
// Otherwise these are the conditions and the associated dialogs that will be shown:
// 1. aQuitType == "lastwindow" or "quit" and browser.showQuitWarning == true
// - The quit dialog will be shown
// 2. aQuitType == "restart" && browser.warnOnRestart == true
// - The restart dialog will be shown
// 3. aQuitType == "lastwindow" && browser.tabs.warnOnClose == true
// 2. aQuitType == "lastwindow" && browser.tabs.warnOnClose == true
// - The "closing multiple tabs" dialog will be shown
//
// aQuitType == "lastwindow" is overloaded. "lastwindow" is used to indicate
// "the last window is closing but we're not quitting (a non-browser window is open)"
// and also "we're quitting by closing the last window".
if (aQuitType == "restart")
return;
var windowcount = 0;
var pagecount = 0;
var browserEnum = Services.wm.getEnumerator("navigator:browser");
@ -586,12 +588,10 @@ BrowserGlue.prototype = {
if (!aQuitType)
aQuitType = "quit";
var showPrompt = false;
var mostRecentBrowserWindow;
// browser.warnOnQuit is a hidden global boolean to override all quit prompts
// browser.showQuitWarning specifically covers quitting
// browser.warnOnRestart specifically covers app-initiated restarts where we restart the app
// browser.tabs.warnOnClose is the global "warn when closing multiple tabs" pref
var sessionWillBeRestored = Services.prefs.getIntPref("browser.startup.page") == 3 ||
@ -601,19 +601,15 @@ BrowserGlue.prototype = {
// On last window close or quit && showQuitWarning, we want to show the
// quit warning.
if (aQuitType != "restart" && Services.prefs.getBoolPref("browser.showQuitWarning")) {
showPrompt = true;
}
else if (aQuitType == "restart" && Services.prefs.getBoolPref("browser.warnOnRestart")) {
showPrompt = true;
}
else if (aQuitType == "lastwindow") {
// If aQuitType is "lastwindow" and we aren't showing the quit warning,
// we should show the window closing warning instead. warnAboutClosing
// tabs checks browser.tabs.warnOnClose and returns if it's ok to close
// the window. It doesn't actually close the window.
mostRecentBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser");
aCancelQuit.data = !mostRecentBrowserWindow.gBrowser.warnAboutClosingTabs(true);
if (!Services.prefs.getBoolPref("browser.showQuitWarning")) {
if (aQuitType == "lastwindow") {
// If aQuitType is "lastwindow" and we aren't showing the quit warning,
// we should show the window closing warning instead. warnAboutClosing
// tabs checks browser.tabs.warnOnClose and returns if it's ok to close
// the window. It doesn't actually close the window.
mostRecentBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser");
aCancelQuit.data = !mostRecentBrowserWindow.gBrowser.warnAboutClosingTabs(true);
}
return;
}
@ -621,21 +617,15 @@ BrowserGlue.prototype = {
if (allWindowsPrivate)
return;
if (!showPrompt)
return;
var quitBundle = Services.strings.createBundle("chrome://browser/locale/quitDialog.properties");
var brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
var appName = brandBundle.GetStringFromName("brandShortName");
var quitTitleString = (aQuitType == "restart" ? "restart" : "quit") + "DialogTitle";
var quitTitleString = "quitDialogTitle";
var quitDialogTitle = quitBundle.formatStringFromName(quitTitleString, [appName], 1);
var message;
if (aQuitType == "restart")
message = quitBundle.formatStringFromName("messageRestart",
[appName], 1);
else if (windowcount == 1)
if (windowcount == 1)
message = quitBundle.formatStringFromName("messageNoWindows",
[appName], 1);
else
@ -646,21 +636,15 @@ BrowserGlue.prototype = {
var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2 +
promptService.BUTTON_POS_0_DEFAULT;
var neverAsk = {value:false};
var button0Title, button2Title;
var button0Title = quitBundle.GetStringFromName("saveTitle");
var button1Title = quitBundle.GetStringFromName("cancelTitle");
var button2Title = quitBundle.GetStringFromName("quitTitle");
var neverAskText = quitBundle.GetStringFromName("neverAsk");
if (aQuitType == "restart")
button0Title = quitBundle.GetStringFromName("restartTitle");
else {
flags += promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2;
button0Title = quitBundle.GetStringFromName("saveTitle");
button2Title = quitBundle.GetStringFromName("quitTitle");
}
// This wouldn't have been set above since we shouldn't be here for
// aQuitType == "lastwindow"
mostRecentBrowserWindow = Services.wm.getMostRecentWindow("navigator:browser");
@ -682,12 +666,8 @@ BrowserGlue.prototype = {
case 0: // Save & Quit
this._saveSession = true;
if (neverAsk.value) {
if (aQuitType == "restart")
Services.prefs.setBoolPref("browser.warnOnRestart", false);
else {
// always save state when shutting down
Services.prefs.setIntPref("browser.startup.page", 3);
}
// always save state when shutting down
Services.prefs.setIntPref("browser.startup.page", 3);
}
break;
}
@ -1791,6 +1771,10 @@ ContentPermissionPrompt.prototype = {
}
}
var link = chromeWin.document.getElementById("geolocation-learnmore-link");
link.value = browserBundle.GetStringFromName("geolocation.learnMore");
link.href = Services.urlFormatter.formatURLPref("browser.geolocation.warning.infoURL");
var browser = chromeWin.gBrowser.getBrowserForDocument(requestingWindow.document);
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST);

View File

@ -0,0 +1,29 @@
<!-- 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/. -->
<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
<overlay id="downloadsViewOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"><![CDATA[
const DOWNLOADS_QUERY = "place:transition=" +
Components.interfaces.nsINavHistoryService.TRANSITION_DOWNLOAD +
"&sort=" +
Components.interfaces.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
ContentArea.setContentViewForQueryString(DOWNLOADS_QUERY,
function() new DownloadsPlacesView(document.getElementById("downloadsRichListBox")),
{ showDetailsPane: false });
]]></script>
<window id="places">
<commandset id="downloadCommands"/>
<menupopup id="downloadsContextMenu"/>
</window>
<deck id="placesViewsDeck">
<richlistbox id="downloadsRichListBox"/>
</deck>
</overlay>

View File

@ -5,11 +5,6 @@
Components.utils.import("resource:///modules/MigrationUtils.jsm");
const DOWNLOADS_QUERY = "place:transition=" +
Components.interfaces.nsINavHistoryService.TRANSITION_DOWNLOAD +
"&sort=" +
Components.interfaces.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
var PlacesOrganizer = {
_places: null,
@ -87,7 +82,7 @@ var PlacesOrganizer = {
// Select the first item in the content area view.
let view = ContentArea.currentView;
let root = view.result ? view.result.root : null;
if (root && root.containerOpen && root.childCount >= 0)
if (root && root.containerOpen && root.childCount > 0)
view.selectNode(root.getChild(0));
ContentArea.focus();
},
@ -279,6 +274,13 @@ var PlacesOrganizer = {
* Handle focus changes on the places list and the current content view.
*/
updateDetailsPane: function PO_updateDetailsPane() {
let detailsDeck = document.getElementById("detailsDeck");
let detailsPaneDisabled = detailsDeck.hidden =
!ContentArea.currentViewOptions.showDetailsPane;
if (detailsPaneDisabled) {
return;
}
let view = PlacesUIUtils.getViewForNode(document.activeElement);
if (view) {
let selectedNodes = view.selectedNode ?
@ -1246,35 +1248,60 @@ let gPrivateBrowsingListener = {
#endif
let ContentArea = {
_specialViews: new Map(),
init: function CA_init() {
this._deck = document.getElementById("placesViewsDeck");
this._specialViews = new Map();
ContentTree.init();
},
_shouldUseNewDownloadsView: function CA_shouldUseNewDownloadsView() {
try {
return Services.prefs.getBoolPref("browser.library.useNewDownloadsView");
}
catch(ex) { }
return false;
},
/**
* Gets the content view to be used for loading the given query.
* If a custom view was set by setContentViewForQueryString, that
* view would be returned, else the default tree view is returned
*
* @param aQueryString
* a query string
* @return the view to be used for loading aQueryString.
*/
getContentViewForQueryString:
function CA_getContentViewForQueryString(aQueryString) {
if (this._specialViews.has(aQueryString))
return this._specialViews.get(aQueryString);
if (aQueryString == DOWNLOADS_QUERY && this._shouldUseNewDownloadsView()) {
let view = new DownloadsPlacesView(document.getElementById("downloadsRichListBox"));
this.setContentViewForQueryString(aQueryString, view);
return view;
try {
if (this._specialViews.has(aQueryString)) {
let { view, options } = this._specialViews.get(aQueryString);
if (typeof view == "function") {
view = view();
this._specialViews.set(aQueryString, { view: view, options: options });
}
return view;
}
}
catch(ex) {
Cu.reportError(ex);
}
return ContentTree.view;
},
/**
* Sets a custom view to be used rather than the default places tree
* whenever the given query is selected in the left pane.
* @param aQueryString
* a query string
* @param aView
* Either the custom view or a function that will return the view
* the first (and only) time it's called.
* @param [optional] aOptions
* Object defining special options for the view.
* @see ContentTree.viewOptions for supported options and default values.
*/
setContentViewForQueryString:
function CA_setContentViewForQueryString(aQueryString, aView) {
this._specialViews.set(aQueryString, aView);
function CA_setContentViewForQueryString(aQueryString, aView, aOptions) {
if (!aQueryString ||
typeof aView != "object" && typeof aView != "function")
throw new Error("Invalid arguments");
this._specialViews.set(aQueryString, { view: aView,
options: aOptions || new Object() });
},
get currentView() PlacesUIUtils.getViewForNode(this._deck.selectedPanel),
@ -1291,6 +1318,23 @@ let ContentArea = {
return aQueryString;
},
/**
* Options for the current view.
*
* @see ContentTree.viewOptions for supported options and default values.
*/
get currentViewOptions() {
// Use ContentTree options as default.
let viewOptions = ContentTree.viewOptions;
if (this._specialViews.has(this.currentPlace)) {
let { view, options } = this._specialViews.get(this.currentPlace);
for (let option in options) {
viewOptions[option] = options[option];
}
}
return viewOptions;
},
focus: function() {
this._deck.selectedPanel.focus();
}
@ -1303,6 +1347,8 @@ let ContentTree = {
get view() this._view,
get viewOptions() Object.seal({ showDetailsPane: true }),
openSelectedNode: function CT_openSelectedNode(aEvent) {
let view = this.view;
PlacesUIUtils.openNodeWithEvent(view.selectedNode, aEvent, view);

View File

@ -12,7 +12,6 @@
<?xml-stylesheet href="chrome://browser/skin/places/organizer.css"?>
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/downloads/allDownloadsViewOverlay.xul"?>
#ifdef XP_MACOSX
<?xul-overlay href="chrome://browser/content/macBrowserOverlay.xul"?>
@ -405,7 +404,6 @@
</treecols>
<treechildren flex="1"/>
</tree>
<richlistbox id="downloadsRichListBox"/>
</deck>
<deck id="detailsDeck" style="height: 11em;">
<vbox id="itemsCountBox" align="center">
@ -440,7 +438,4 @@
</deck>
</vbox>
</hbox>
<commandset id="downloadCommands"/>
<menupopup id="downloadsContextMenu"/>
</window>

View File

@ -3,6 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
% overlay chrome://browser/content/places/places.xul chrome://browser/content/places/downloadsViewOverlay.xul
# Provide another URI for the bookmarkProperties dialog so we can persist the
# attributes separately
content/browser/places/bookmarkProperties2.xul (content/bookmarkProperties.xul)
@ -30,3 +31,4 @@ browser.jar:
content/browser/places/moveBookmarks.js (content/moveBookmarks.js)
content/browser/places/editBookmarkOverlay.xul (content/editBookmarkOverlay.xul)
content/browser/places/editBookmarkOverlay.js (content/editBookmarkOverlay.js)
content/browser/places/downloadsViewOverlay.xul (content/downloadsViewOverlay.xul)

View File

@ -15,42 +15,56 @@ let now = Date.now();
function test() {
waitForExplicitFinish();
function onLibraryReady(win) {
let onLibraryReady = function(win) {
// Add visits to compare contents with.
fastAddVisit("http://mozilla.com",
PlacesUtils.history.TRANSITION_TYPED);
fastAddVisit("http://google.com",
PlacesUtils.history.TRANSITION_DOWNLOAD);
fastAddVisit("http://en.wikipedia.org",
PlacesUtils.history.TRANSITION_TYPED);
fastAddVisit("http://ubuntu.org",
PlacesUtils.history.TRANSITION_DOWNLOAD);
let places = [
{ uri: NetUtil.newURI("http://mozilla.com"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_TYPED) ]
},
{ uri: NetUtil.newURI("http://google.com"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_DOWNLOAD) ]
},
{ uri: NetUtil.newURI("http://en.wikipedia.org"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_TYPED) ]
},
{ uri: NetUtil.newURI("http://ubuntu.org"),
visits: [ new VisitInfo(PlacesUtils.history.TRANSITION_DOWNLOAD) ]
},
]
PlacesUtils.asyncHistory.updatePlaces(places, {
handleResult: function () {},
handleError: function () {
ok(false, "gHistory.updatePlaces() failed");
},
handleCompletion: function () {
// Make sure Downloads is present.
isnot(win.PlacesOrganizer._places.selectedNode, null,
"Downloads is present and selected");
// Make sure Downloads is present.
isnot(win.PlacesOrganizer._places.selectedNode, null,
"Downloads is present and selected");
// Make sure content in right pane exists.
let tree = win.document.getElementById("placeContent");
isnot(tree, null, "placeContent tree exists");
// Check results.
let contentRoot = win.ContentArea.currentView.result.root;
let len = contentRoot.childCount;
const TEST_URIS = ["http://ubuntu.org/", "http://google.com/"];
for (let i = 0; i < len; i++) {
is(contentRoot.getChild(i).uri, TEST_URIS[i],
"Comparing downloads shown at index " + i);
}
// Check results.
var contentRoot = tree.result.root;
var len = contentRoot.childCount;
var testUris = ["http://ubuntu.org/", "http://google.com/"];
for (var i = 0; i < len; i++) {
is(contentRoot.getChild(i).uri, testUris[i],
"Comparing downloads shown at index " + i);
}
win.close();
waitForClearHistory(finish);
win.close();
waitForClearHistory(finish);
}
})
}
openLibrary(onLibraryReady, "Downloads");
}
function fastAddVisit(uri, transition) {
PlacesUtils.history.addVisit(PlacesUtils._uri(uri), now++ * 1000,
null, transition, false, 0);
function VisitInfo(aTransitionType)
{
this.transitionType =
aTransitionType === undefined ?
PlacesUtils.history.TRANSITION_LINK : aTransitionType;
this.visitDate = now++ * 1000;
}
VisitInfo.prototype = {}

View File

@ -11,7 +11,7 @@ browser.jar:
* content/browser/preferences/in-content/tabs.xul
* content/browser/preferences/in-content/tabs.js
content/browser/preferences/in-content/privacy.xul
content/browser/preferences/in-content/privacy.js
* content/browser/preferences/in-content/privacy.js
* content/browser/preferences/in-content/advanced.xul
* content/browser/preferences/in-content/advanced.js
content/browser/preferences/in-content/applications.xul

View File

@ -2,6 +2,9 @@
* 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/. */
XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon",
"resource:///modules/DownloadsCommon.jsm");
var gMainPane = {
_pane: null,
@ -18,12 +21,25 @@ var gMainPane = {
this.updateBrowserStartupLastSession();
this.setupDownloadsWindowOptions();
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded", null);
},
setupDownloadsWindowOptions: function ()
{
let showWhenDownloading = document.getElementById("showWhenDownloading");
let closeWhenDone = document.getElementById("closeWhenDone");
// These radio buttons should be hidden when the Downloads Panel is enabled.
let shouldHide = !DownloadsCommon.useToolkitUI;
showWhenDownloading.hidden = shouldHide;
closeWhenDone.hidden = shouldHide;
},
// HOME PAGE
/*

View File

@ -9,6 +9,11 @@ var gPrivacyPane = {
*/
_autoStartPrivateBrowsing: false,
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
_shouldPromptForRestart: true,
/**
* Sets up the UI for the number of days of history to keep, and updates the
* label of the "Clear Now..." button.
@ -127,7 +132,8 @@ var gPrivacyPane = {
let pref = document.getElementById("browser.privatebrowsing.autostart");
switch (document.getElementById("historyMode").value) {
case "remember":
pref.value = false;
if (pref.value)
pref.value = false;
// select the remember history option if needed
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
@ -146,7 +152,8 @@ var gPrivacyPane = {
document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false;
break;
case "dontremember":
pref.value = true;
if (!pref.value)
pref.value = true;
break;
}
},
@ -219,19 +226,65 @@ var gPrivacyPane = {
observe: function PPP_observe(aSubject, aTopic, aData)
{
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
if (!gPrivacyPane._shouldPromptForRestart) {
// We're performing a revert. Just let it happen.
gPrivacyPane._shouldPromptForRestart = true;
return;
}
const Cc = Components.classes, Ci = Components.interfaces;
let pref = document.getElementById("browser.privatebrowsing.autostart");
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
let bundle = document.getElementById("bundlePreferences");
let msg = bundle.getFormattedString(pref.value ?
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
[brandName]);
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
let shouldProceed = prompts.confirm(window, title, msg)
if (shouldProceed) {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
"restart");
shouldProceed = !cancelQuit.data;
if (shouldProceed) {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
.getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
return;
}
}
gPrivacyPane._shouldPromptForRestart = false;
pref.value = !pref.value;
let mode = document.getElementById("historyMode");
if (mode.value != "custom") {
mode.selectedIndex = pref.value ? 1 : 0;
mode.doCommand();
} else {
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
rememberHistory.checked = pref.value;
}
#else
// Toggle the private browsing mode without switching the session
let prefValue = document.getElementById("browser.privatebrowsing.autostart").value;
let keepCurrentSession = document.getElementById("browser.privatebrowsing.keep_current_session");
keepCurrentSession.value = true;
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
// If activating from within the private browsing mode, reset the
// private session
if (prefValue && privateBrowsingService.privateBrowsingEnabled)
privateBrowsingService.privateBrowsingEnabled = false;
privateBrowsingService.privateBrowsingEnabled = prefValue;
keepCurrentSession.reset();
#endif
}
},

View File

@ -15,22 +15,31 @@ _BROWSER_FILES = \
head.js \
browser_advanced_update.js \
browser_bug410900.js \
browser_bug567487.js \
browser_bug731866.js \
browser_connection.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += \
privacypane_tests.js \
browser_bug567487.js \
browser_privacypane_1.js \
browser_privacypane_2.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += \
browser_privacypane_6.js \
browser_privacypane_7.js \
browser_privacypane_8.js \
$(NULL)
else
_BROWSER_FILES += \
privacypane_tests_perwindow.js \
browser_privacypane_1.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
$(NULL)
endif

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_pane_visibility,

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_historymode_retention("remember", undefined),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("rememberHistory", "remember"),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("acceptCookies", "remember"),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_locbar_suggestion_retention(-1, undefined),

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_toggle,

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_ui,

View File

@ -10,7 +10,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
// history mode should be initialized to remember

View File

@ -0,0 +1,344 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
function runTestOnPrivacyPrefPane(testFunc) {
gBrowser.tabContainer.addEventListener("TabOpen", function(aEvent) {
gBrowser.tabContainer.removeEventListener("TabOpen", arguments.callee, true);
let browser = aEvent.originalTarget.linkedBrowser;
browser.addEventListener("Initialized", function(aEvent) {
browser.removeEventListener("Initialized", arguments.callee, true);
is(browser.contentWindow.location.href, "about:preferences", "Checking if the preferences tab was opened");
testFunc(browser.contentWindow);
gBrowser.removeCurrentTab();
testRunner.runNext();
}, true);
}, true);
gBrowser.selectedTab = gBrowser.addTab("about:preferences");
}
function controlChanged(element) {
element.doCommand();
}
// We can only test the panes that don't trigger a preference update
function test_pane_visibility(win) {
let modes = {
"remember": "historyRememberPane",
"custom": "historyCustomPane"
};
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let historypane = win.document.getElementById("historyPane");
ok(historypane, "history mode pane should exist");
for (let mode in modes) {
historymode.value = mode;
controlChanged(historymode);
is(historypane.selectedPanel, win.document.getElementById(modes[mode]),
"The correct pane should be selected for the " + mode + " mode");
}
}
function test_dependent_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
win.document.getElementById("alwaysClear"),
];
controls.forEach(function(control) {
ok(control, "the dependent controls should exist");
});
let independents = [
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
independents.forEach(function(control) {
ok(control, "the independent controls should exist");
});
let cookieexceptions = win.document.getElementById("cookieExceptions");
ok(cookieexceptions, "the cookie exceptions button should exist");
let keepuntil = win.document.getElementById("keepCookiesUntil");
ok(keepuntil, "the keep cookies until menulist should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let rememberhistory = win.document.getElementById("rememberHistory");
ok(rememberhistory, "the remember history checkbox should exist");
let rememberforms = win.document.getElementById("rememberForms");
ok(rememberforms, "the remember forms checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
is(keepuntil.value, disabled ? 2 : 0,
"the keep cookies until menulist value should be as expected");
if (disabled) {
ok(!alwaysclear.checked,
"the clear data on close checkbox value should be as expected");
ok(!rememberhistory.checked,
"the remember history checkbox value should be as expected");
ok(!rememberforms.checked,
"the remember forms checkbox value should be as expected");
}
}
function check_independents(expected) {
independents.forEach(function(control) {
is(control.disabled, expected,
control.getAttribute("id") + " should " + (expected ? "" : "not ") + "be disabled");
});
ok(!cookieexceptions.disabled,
"the cookie exceptions button should never be disabled");
ok(alwaysclearsettings.disabled,
"the clear data settings button should always be disabled");
}
// controls should only change in custom mode
historymode.value = "remember";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
// setting the mode to custom shouldn't change anything
historymode.value = "custom";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
}
function test_dependent_cookie_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("acceptThirdParty"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
];
controls.forEach(function(control) {
ok(control, "the dependent cookie controls should exist");
});
let acceptcookies = win.document.getElementById("acceptCookies");
ok(acceptcookies, "the accept cookies checkbox should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(false);
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
let accessthirdparty = controls.shift();
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
ok(!accessthirdparty.disabled, "access third party button should be enabled");
}
function test_dependent_clearonclose_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
is(alwaysclearsettings.disabled, disabled,
"the clear data settings should " + (disabled ? "" : "not ") + "be disabled");
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
alwaysclear.checked = true;
controlChanged(alwaysclear);
expect_disabled(false);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
}
function test_dependent_prefs(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
controls.forEach(function(control) {
ok(control, "the micro-management controls should exist");
});
function expect_checked(checked) {
controls.forEach(function(control) {
is(control.checked, checked,
control.getAttribute("id") + " should " + (checked ? "not " : "") + "be checked");
});
}
// controls should be checked in remember mode
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
// even if they're unchecked in custom mode
historymode.value = "custom";
controlChanged(historymode);
controls.forEach(function(control) {
control.checked = false;
controlChanged(control);
});
expect_checked(false);
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
}
function test_historymode_retention(mode, expect) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if ((historymode.value == "remember" && mode == "dontremember") ||
(historymode.value == "dontremember" && mode == "remember") ||
(historymode.value == "custom" && mode == "dontremember")) {
return;
}
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = mode;
controlChanged(historymode);
};
}
function test_custom_retention(controlToChange, expect, valueIncrement) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = "custom";
controlChanged(historymode);
controlToChange = win.document.getElementById(controlToChange);
ok(controlToChange, "the control to change should exist");
switch (controlToChange.localName) {
case "checkbox":
controlToChange.checked = !controlToChange.checked;
break;
case "textbox":
controlToChange.value = parseInt(controlToChange.value) + valueIncrement;
break;
case "menulist":
controlToChange.value = valueIncrement;
break;
}
controlChanged(controlToChange);
};
}
function test_locbar_suggestion_retention(mode, expect) {
return function(win) {
let locbarsuggest = win.document.getElementById("locationBarSuggestion");
ok(locbarsuggest, "location bar suggestion menulist should exist");
if (expect !== undefined) {
is(locbarsuggest.value, expect,
"location bar suggestion is expected to remain " + expect);
}
locbarsuggest.value = mode;
controlChanged(locbarsuggest);
};
}
function reset_preferences(win) {
let prefs = win.document.querySelectorAll("#privacyPreferences > preference");
for (let i = 0; i < prefs.length; ++i)
if (prefs[i].hasUserValue)
prefs[i].reset();
}
let testRunner;
function run_test_subset(subset) {
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
waitForExplicitFinish();
registerCleanupFunction(function() {
// Reset pref to its default
Services.prefs.clearUserPref("browser.preferences.instantApply");
});
testRunner = {
tests: subset,
counter: 0,
runNext: function() {
if (this.counter == this.tests.length) {
finish();
} else {
let self = this;
setTimeout(function() {
runTestOnPrivacyPrefPane(self.tests[self.counter++]);
}, 0);
}
}
};
testRunner.runNext();
}

View File

@ -23,12 +23,25 @@ var gMainPane = {
this.updateBrowserStartupLastSession();
this.setupDownloadsWindowOptions();
// Notify observers that the UI is now ready
Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService)
.notifyObservers(window, "main-pane-loaded", null);
},
setupDownloadsWindowOptions: function ()
{
let showWhenDownloading = document.getElementById("showWhenDownloading");
let closeWhenDone = document.getElementById("closeWhenDone");
// These radio buttons should be hidden when the Downloads Panel is enabled.
let shouldHide = !DownloadsCommon.useToolkitUI;
showWhenDownloading.hidden = shouldHide;
closeWhenDone.hidden = shouldHide;
},
// HOME PAGE
/*

View File

@ -12,6 +12,11 @@ var gPrivacyPane = {
*/
_autoStartPrivateBrowsing: false,
/**
* Whether the prompt to restart Firefox should appear when changing the autostart pref.
*/
_shouldPromptForRestart: true,
/**
* Sets up the UI for the number of days of history to keep, and updates the
* label of the "Clear Now..." button.
@ -130,7 +135,8 @@ var gPrivacyPane = {
let pref = document.getElementById("browser.privatebrowsing.autostart");
switch (document.getElementById("historyMode").value) {
case "remember":
pref.value = false;
if (pref.value)
pref.value = false;
// select the remember history option if needed
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
@ -149,7 +155,8 @@ var gPrivacyPane = {
document.getElementById("privacy.sanitize.sanitizeOnShutdown").value = false;
break;
case "dontremember":
pref.value = true;
if (!pref.value)
pref.value = true;
break;
}
},
@ -222,12 +229,54 @@ var gPrivacyPane = {
observe: function PPP_observe(aSubject, aTopic, aData)
{
#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
if (!gPrivacyPane._shouldPromptForRestart) {
// We're performing a revert. Just let it happen.
gPrivacyPane._shouldPromptForRestart = true;
return;
}
const Cc = Components.classes, Ci = Components.interfaces;
let pref = document.getElementById("browser.privatebrowsing.autostart");
let brandName = document.getElementById("bundleBrand").getString("brandShortName");
let bundle = document.getElementById("bundlePreferences");
let msg = bundle.getFormattedString(pref.value ?
"featureEnableRequiresRestart" : "featureDisableRequiresRestart",
[brandName]);
let title = bundle.getFormattedString("shouldRestartTitle", [brandName]);
let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
let shouldProceed = prompts.confirm(window, title, msg)
if (shouldProceed) {
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]
.createInstance(Ci.nsISupportsPRBool);
Services.obs.notifyObservers(cancelQuit, "quit-application-requested",
"restart");
shouldProceed = !cancelQuit.data;
if (shouldProceed) {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
.getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
return;
}
}
gPrivacyPane._shouldPromptForRestart = false;
pref.value = !pref.value;
let mode = document.getElementById("historyMode");
if (mode.value != "custom") {
mode.selectedIndex = pref.value ? 1 : 0;
mode.doCommand();
} else {
let rememberHistoryCheckbox = document.getElementById("rememberHistory");
rememberHistory.checked = pref.value;
}
#else
// Toggle the private browsing mode without switching the session
let prefValue = document.getElementById("browser.privatebrowsing.autostart").value;
let keepCurrentSession = document.getElementById("browser.privatebrowsing.keep_current_session");
keepCurrentSession.value = true;
#ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
let privateBrowsingService = Components.classes["@mozilla.org/privatebrowsing;1"].
getService(Components.interfaces.nsIPrivateBrowsingService);
@ -236,9 +285,9 @@ var gPrivacyPane = {
if (prefValue && privateBrowsingService.privateBrowsingEnabled)
privateBrowsingService.privateBrowsingEnabled = false;
privateBrowsingService.privateBrowsingEnabled = prefValue;
#endif
keepCurrentSession.reset();
#endif
}
},

View File

@ -14,23 +14,32 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_advanced_update.js \
browser_bug410900.js \
browser_bug567487.js \
browser_bug705422.js \
privacypane_tests.js \
browser_privacypane_1.js \
browser_privacypane_2.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
browser_permissions.js \
browser_chunk_permissions.js \
$(NULL)
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
_BROWSER_FILES += \
privacypane_tests.js \
browser_bug567487.js \
browser_privacypane_1.js \
browser_privacypane_2.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_6.js \
browser_privacypane_7.js \
browser_privacypane_8.js \
$(NULL)
else
_BROWSER_FILES += \
privacypane_tests_perwindow.js \
browser_privacypane_1.js \
browser_privacypane_3.js \
browser_privacypane_4.js \
browser_privacypane_5.js \
browser_privacypane_8.js \
$(NULL)
endif

View File

@ -12,7 +12,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_pane_visibility,

View File

@ -12,7 +12,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_historymode_retention("remember", undefined),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("rememberHistory", "remember"),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_custom_retention("acceptCookies", "remember"),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_locbar_suggestion_retention(-1, undefined),

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_toggle,

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
test_privatebrowsing_ui,

View File

@ -11,7 +11,11 @@ function test() {
let tmpdir = extractJarToTmp(jar);
rootDir = "file://" + tmpdir.path + '/';
}
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
try {
loader.loadSubScript(rootDir + "privacypane_tests_perwindow.js", this);
} catch(x) {
loader.loadSubScript(rootDir + "privacypane_tests.js", this);
}
run_test_subset([
// history mode should be initialized to remember

View File

@ -0,0 +1,352 @@
/* 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/. */
function runTestOnPrivacyPrefPane(testFunc) {
let observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == "domwindowopened") {
Services.ww.unregisterNotification(this);
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function() {
win.removeEventListener("load", arguments.callee, false);
testFunc(dialog.document.defaultView);
Services.ww.registerNotification(observer);
dialog.close();
}, false);
} else if (aTopic == "domwindowclosed") {
Services.ww.unregisterNotification(this);
testRunner.runNext();
}
}
};
Services.ww.registerNotification(observer);
let dialog = openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
"chrome,titlebar,toolbar,centerscreen,dialog=no", "panePrivacy");
}
function controlChanged(element) {
element.doCommand();
}
// We can only test the panes that don't trigger a preference update
function test_pane_visibility(win) {
let modes = {
"remember": "historyRememberPane",
"custom": "historyCustomPane"
};
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let historypane = win.document.getElementById("historyPane");
ok(historypane, "history mode pane should exist");
for (let mode in modes) {
historymode.value = mode;
controlChanged(historymode);
is(historypane.selectedPanel, win.document.getElementById(modes[mode]),
"The correct pane should be selected for the " + mode + " mode");
}
}
function test_dependent_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
win.document.getElementById("alwaysClear"),
];
controls.forEach(function(control) {
ok(control, "the dependent controls should exist");
});
let independents = [
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
independents.forEach(function(control) {
ok(control, "the independent controls should exist");
});
let cookieexceptions = win.document.getElementById("cookieExceptions");
ok(cookieexceptions, "the cookie exceptions button should exist");
let keepuntil = win.document.getElementById("keepCookiesUntil");
ok(keepuntil, "the keep cookies until menulist should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let rememberhistory = win.document.getElementById("rememberHistory");
ok(rememberhistory, "the remember history checkbox should exist");
let rememberforms = win.document.getElementById("rememberForms");
ok(rememberforms, "the remember forms checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
is(keepuntil.value, disabled ? 2 : 0,
"the keep cookies until menulist value should be as expected");
if (disabled) {
ok(!alwaysclear.checked,
"the clear data on close checkbox value should be as expected");
ok(!rememberhistory.checked,
"the remember history checkbox value should be as expected");
ok(!rememberforms.checked,
"the remember forms checkbox value should be as expected");
}
}
function check_independents(expected) {
independents.forEach(function(control) {
is(control.disabled, expected,
control.getAttribute("id") + " should " + (expected ? "" : "not ") + "be disabled");
});
ok(!cookieexceptions.disabled,
"the cookie exceptions button should never be disabled");
ok(alwaysclearsettings.disabled,
"the clear data settings button should always be disabled");
}
// controls should only change in custom mode
historymode.value = "remember";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
// setting the mode to custom shouldn't change anything
historymode.value = "custom";
controlChanged(historymode);
expect_disabled(false);
check_independents(false);
}
function test_dependent_cookie_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let controls = [
win.document.getElementById("acceptThirdParty"),
win.document.getElementById("keepUntil"),
win.document.getElementById("keepCookiesUntil"),
];
controls.forEach(function(control) {
ok(control, "the dependent cookie controls should exist");
});
let acceptcookies = win.document.getElementById("acceptCookies");
ok(acceptcookies, "the accept cookies checkbox should exist");
function expect_disabled(disabled) {
controls.forEach(function(control) {
is(control.disabled, disabled,
control.getAttribute("id") + " should " + (disabled ? "" : "not ") + "be disabled");
});
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(false);
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
let accessthirdparty = controls.shift();
acceptcookies.checked = false;
controlChanged(acceptcookies);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
pbautostart.checked = false;
controlChanged(pbautostart);
expect_disabled(true);
ok(accessthirdparty.disabled, "access third party button should be disabled");
acceptcookies.checked = true;
controlChanged(acceptcookies);
expect_disabled(false);
ok(!accessthirdparty.disabled, "access third party button should be enabled");
}
function test_dependent_clearonclose_elements(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let pbautostart = win.document.getElementById("privateBrowsingAutoStart");
ok(pbautostart, "the private browsing auto-start checkbox should exist");
let alwaysclear = win.document.getElementById("alwaysClear");
ok(alwaysclear, "the clear data on close checkbox should exist");
let alwaysclearsettings = win.document.getElementById("clearDataSettings");
ok(alwaysclearsettings, "the clear data settings button should exist");
function expect_disabled(disabled) {
is(alwaysclearsettings.disabled, disabled,
"the clear data settings should " + (disabled ? "" : "not ") + "be disabled");
}
historymode.value = "custom";
controlChanged(historymode);
pbautostart.checked = false;
controlChanged(pbautostart);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
alwaysclear.checked = true;
controlChanged(alwaysclear);
expect_disabled(false);
alwaysclear.checked = false;
controlChanged(alwaysclear);
expect_disabled(true);
}
function test_dependent_prefs(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
let controls = [
win.document.getElementById("rememberHistory"),
win.document.getElementById("rememberForms"),
win.document.getElementById("acceptCookies"),
win.document.getElementById("acceptThirdParty"),
];
controls.forEach(function(control) {
ok(control, "the micro-management controls should exist");
});
function expect_checked(checked) {
controls.forEach(function(control) {
is(control.checked, checked,
control.getAttribute("id") + " should " + (checked ? "not " : "") + "be checked");
});
}
// controls should be checked in remember mode
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
// even if they're unchecked in custom mode
historymode.value = "custom";
controlChanged(historymode);
controls.forEach(function(control) {
control.checked = false;
controlChanged(control);
});
expect_checked(false);
historymode.value = "remember";
controlChanged(historymode);
expect_checked(true);
}
function test_historymode_retention(mode, expect) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if ((historymode.value == "remember" && mode == "dontremember") ||
(historymode.value == "dontremember" && mode == "remember") ||
(historymode.value == "custom" && mode == "dontremember")) {
return;
}
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = mode;
controlChanged(historymode);
};
}
function test_custom_retention(controlToChange, expect, valueIncrement) {
return function(win) {
let historymode = win.document.getElementById("historyMode");
ok(historymode, "history mode menulist should exist");
if (expect !== undefined) {
is(historymode.value, expect,
"history mode is expected to remain " + expect);
}
historymode.value = "custom";
controlChanged(historymode);
controlToChange = win.document.getElementById(controlToChange);
ok(controlToChange, "the control to change should exist");
switch (controlToChange.localName) {
case "checkbox":
controlToChange.checked = !controlToChange.checked;
break;
case "textbox":
controlToChange.value = parseInt(controlToChange.value) + valueIncrement;
break;
case "menulist":
controlToChange.value = valueIncrement;
break;
}
controlChanged(controlToChange);
};
}
function test_locbar_suggestion_retention(mode, expect) {
return function(win) {
let locbarsuggest = win.document.getElementById("locationBarSuggestion");
ok(locbarsuggest, "location bar suggestion menulist should exist");
if (expect !== undefined) {
is(locbarsuggest.value, expect,
"location bar suggestion is expected to remain " + expect);
}
locbarsuggest.value = mode;
controlChanged(locbarsuggest);
};
}
function reset_preferences(win) {
let prefs = win.document.getElementsByTagName("preference");
for (let i = 0; i < prefs.length; ++i)
if (prefs[i].hasUserValue)
prefs[i].reset();
}
let testRunner;
function run_test_subset(subset) {
let instantApplyOrig = Services.prefs.getBoolPref("browser.preferences.instantApply");
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
waitForExplicitFinish();
testRunner = {
tests: subset,
counter: 0,
runNext: function() {
if (this.counter == this.tests.length) {
// cleanup
Services.prefs.setBoolPref("browser.preferences.instantApply", instantApplyOrig);
finish();
} else {
let self = this;
setTimeout(function() {
runTestOnPrivacyPrefPane(self.tests[self.counter++]);
}, 0);
}
}
};
testRunner.runNext();
}

View File

@ -11,7 +11,9 @@ include $(DEPTH)/config/autoconf.mk
MODULE = privatebrowsing
ifndef MOZ_PER_WINDOW_PRIVATE_BROWSING
DIRS = src
endif
TEST_DIRS += test

View File

@ -3728,6 +3728,9 @@ let SessionStoreInternal = {
for (let i = oState.windows.length - 1; i >= 0; i--) {
if (oState.windows[i].isPrivate) {
oState.windows.splice(i, 1);
if (oState.selectedWindow >= i) {
oState.selectedWindow--;
}
}
}
for (let i = oState._closedWindows.length - 1; i >= 0; i--) {

View File

@ -141,6 +141,7 @@ ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
MOCHITEST_BROWSER_FILES += \
browser_354894_perwindowpb.js \
browser_394759_perwindowpb.js \
browser_819510_perwindowpb.js \
$(NULL)
else
MOCHITEST_BROWSER_FILES += \

View File

@ -38,7 +38,7 @@ function test() {
tab = window.gBrowser.tabs[i];
}
ok(tab.pinned || gBrowser.selectedTab == tab,
ok(tab.pinned || tab.selected,
"load came from pinned or selected tab");
// We should get 4 loads: 3 app tabs + 1 normal selected tab

View File

@ -37,7 +37,7 @@ function test() {
}
// Check that the load only comes from the selected tab.
ok(gBrowser.selectedTab == tab, "load came from selected tab");
ok(tab.selected, "load came from selected tab");
is(aNeedRestore, 6, "six tabs left to restore");
is(aRestoring, 1, "one tab is restoring");
is(aRestored, 0, "no tabs have been restored, yet");

View File

@ -0,0 +1,181 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const originalState = ss.getBrowserState();
/** Private Browsing Test for Bug 819510 **/
function test() {
waitForExplicitFinish();
registerCleanupFunction(function() {
Services.prefs.clearUserPref("browser.sessionstore.interval");
ss.setBrowserState(originalState);
});
runNextTest();
}
let tests = [test_1, test_2, test_3 ];
const testState = {
windows: [{
tabs: [
{ entries: [{ url: "about:blank" }] },
]
}]
};
function runNextTest() {
// Set an empty state
closeAllButPrimaryWindow();
// Run the next test, or finish
if (tests.length) {
let currentTest = tests.shift();
waitForBrowserState(testState, currentTest);
} else {
Services.prefs.clearUserPref("browser.sessionstore.interval");
ss.setBrowserState(originalState);
finish();
}
}
// Test opening default mochitest-normal-private-normal-private windows
// (saving the state with last window being private)
function test_1() {
testOnWindow(false, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/1");
testOnWindow(true, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/2");
testOnWindow(false, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/3");
testOnWindow(true, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/4");
let curState = JSON.parse(ss.getBrowserState());
is (curState.windows.length, 5, "Browser has opened 5 windows");
is (curState.windows[2].isPrivate, true, "Window is private");
is (curState.windows[4].isPrivate, true, "Last window is private");
is (curState.selectedWindow, 5, "Last window opened is the one selected");
forceWriteState(function(state) {
is(state.windows.length, 3,
"sessionstore state: 3 windows in data being written to disk");
is (state.selectedWindow, 3,
"Selected window is updated to match one of the saved windows");
state.windows.forEach(function(win) {
is(!win.isPrivate, true, "Saved window is not private");
});
is(state._closedWindows.length, 0,
"sessionstore state: no closed windows in data being written to disk");
runNextTest();
});
});
});
});
});
}
// Test opening default mochitest window + 2 private windows
function test_2() {
testOnWindow(true, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/1");
testOnWindow(true, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/2");
let curState = JSON.parse(ss.getBrowserState());
is (curState.windows.length, 3, "Browser has opened 3 windows");
is (curState.windows[1].isPrivate, true, "Window 1 is private");
is (curState.windows[2].isPrivate, true, "Window 2 is private");
is (curState.selectedWindow, 3, "Last window opened is the one selected");
forceWriteState(function(state) {
is(state.windows.length, 1,
"sessionstore state: 1 windows in data being writted to disk");
is (state.selectedWindow, 1,
"Selected window is updated to match one of the saved windows");
is(state._closedWindows.length, 0,
"sessionstore state: no closed windows in data being writted to disk");
runNextTest();
});
});
});
}
// Test opening default-normal-private-normal windows and closing a normal window
function test_3() {
testOnWindow(false, function(normalWindow) {
let tab = normalWindow.gBrowser.addTab("http://www.example.com/1");
whenBrowserLoaded(tab.linkedBrowser, function() {
testOnWindow(true, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/2");
testOnWindow(false, function(aWindow) {
aWindow.gBrowser.addTab("http://www.example.com/3");
let curState = JSON.parse(ss.getBrowserState());
is (curState.windows.length, 4, "Browser has opened 4 windows");
is (curState.windows[2].isPrivate, true, "Window 2 is private");
is (curState.selectedWindow, 4, "Last window opened is the one selected");
waitForWindowClose(normalWindow, function() {
forceWriteState(function(state) {
is(state.windows.length, 2,
"sessionstore state: 2 windows in data being writted to disk");
is(state.selectedWindow, 2,
"Selected window is updated to match one of the saved windows");
state.windows.forEach(function(win) {
is(!win.isPrivate, true, "Saved window is not private");
});
is(state._closedWindows.length, 1,
"sessionstore state: 1 closed window in data being writted to disk");
state._closedWindows.forEach(function(win) {
is(!win.isPrivate, true, "Closed window is not private");
});
runNextTest();
});
});
});
});
});
});
}
function waitForWindowClose(aWin, aCallback) {
Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
if (aTopic == "domwindowclosed" && aWin == aSubject) {
Services.obs.removeObserver(observe, aTopic);
checkWindowIsClosed(aWin, aCallback);
}
}, "domwindowclosed", false);
aWin.close();
}
function checkWindowIsClosed(aWin, aCallback) {
if (aWin.closed) {
info("Window is closed");
executeSoon(aCallback);
} else {
executeSoon(function() {
checkWindowIsClosed(aWin, aCallback);
});
}
}
function forceWriteState(aCallback) {
Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
if (aTopic == "sessionstore-state-write") {
Services.obs.removeObserver(observe, aTopic);
aSubject.QueryInterface(Ci.nsISupportsString);
aCallback(JSON.parse(aSubject.data));
}
}, "sessionstore-state-write", false);
Services.prefs.setIntPref("browser.sessionstore.interval", 0);
}
function testOnWindow(aIsPrivate, aCallback) {
let win = OpenBrowserWindow({private: aIsPrivate});
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
executeSoon(function() { aCallback(win); });
}, false);
}

View File

@ -1004,7 +1004,7 @@ GroupItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// if it matches the selected tab or no active tab and the browser
// tab is hidden, the active group item would be set.
if (item.tab == gBrowser.selectedTab ||
if (item.tab.selected ||
(!GroupItems.getActiveGroupItem() && !item.tab.hidden))
UI.setActive(this);
}
@ -2542,7 +2542,7 @@ let GroupItems = {
let groupItem;
// switch to the appropriate tab first.
if (gBrowser.selectedTab == tab) {
if (tab.selected) {
if (gBrowser.visibleTabs.length > 1) {
gBrowser._blurTab(tab);
shouldUpdateTabBar = true;

View File

@ -277,7 +277,7 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// if it matches the selected tab or no active tab and the browser
// tab is hidden, the active group item would be set.
if (this.tab == gBrowser.selectedTab ||
if (this.tab.selected ||
(!GroupItems.getActiveGroupItem() && !this.tab.hidden))
UI.setActive(this.parent);
}
@ -539,11 +539,11 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
UI.goToTab(tab);
// tab might not be selected because hideTabView() is invoked after
// tab might not be selected because hideTabView() is invoked after
// UI.goToTab() so we need to setup everything for the gBrowser.selectedTab
if (tab != gBrowser.selectedTab) {
if (!tab.selected) {
UI.onTabSelect(gBrowser.selectedTab);
} else {
} else {
if (isNewBlankTab)
gWindow.gURLBar.focus();
}

View File

@ -34,7 +34,7 @@ function onTabViewLoadedAndShown() {
gBrowser.pinTab(appTab);
// verify that the normal tab is selected
ok(gBrowser.selectedTab == originalTab, "the normal tab is selected");
ok(originalTab.selected, "the normal tab is selected");
// hit the exit button for the first time
exitButton = contentWindow.document.getElementById("exit-button");
@ -50,11 +50,11 @@ function onTabViewHiddenForNormalTab() {
ok(!TabView.isVisible(), "Tab View is not visible");
// verify that the normal tab is still selected
ok(gBrowser.selectedTab == originalTab, "the normal tab is still selected");
ok(originalTab.selected, "the normal tab is still selected");
// select the app tab
gBrowser.selectedTab = appTab;
ok(gBrowser.selectedTab == appTab, "the app tab is now selected");
ok(appTab.selected, "the app tab is now selected");
// go back to tabview
window.addEventListener("tabviewshown", onTabViewShown, false);
@ -77,14 +77,14 @@ function onTabViewHiddenForAppTab() {
ok(!TabView.isVisible(), "Tab View is not visible");
// verify that the app tab is still selected
ok(gBrowser.selectedTab == appTab, "the app tab is still selected");
ok(appTab.selected, "the app tab is still selected");
// clean up
gBrowser.selectedTab = originalTab;
gBrowser.selectedTab = originalTab;
gBrowser.removeTab(appTab);
is(gBrowser.tabs.length, 1, "we finish with one tab");
ok(gBrowser.selectedTab == originalTab,
ok(originalTab.selected,
"we finish with the normal tab selected");
ok(!TabView.isVisible(), "we finish with Tab View not visible");

View File

@ -823,7 +823,7 @@ let UI = {
// Selects the given xul:tab in the browser.
goToTab: function UI_goToTab(xulTab) {
// If it's not focused, the onFocus listener would handle it.
if (gBrowser.selectedTab == xulTab)
if (xulTab.selected)
this.onTabSelect(xulTab);
else
gBrowser.selectedTab = xulTab;
@ -936,7 +936,7 @@ let UI = {
// TabView is hidden and that the correct group is activated. When a modal
// dialog is shown for currently selected tab the onTabSelect event handler
// is not called, so we need to do it.
if (gBrowser.selectedTab == tab && this._currentTab == tab)
if (tab.selected && this._currentTab == tab)
this.onTabSelect(tab);
},

View File

@ -1,16 +0,0 @@
. $topsrcdir/build/macosx/mozconfig.leopard
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar
ENABLE_MARIONETTE=1
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1
ac_add_options --with-macbundlename-prefix=Firefox
# Package js shell.
export MOZ_PACKAGE_JSSHELL=1
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -1,6 +1,6 @@
[
{
"clang_version": "r170377"
"clang_version": "r170890"
},
{
"size": 47,
@ -9,8 +9,8 @@
"filename": "setup.sh"
},
{
"size": 61878564,
"digest": "bc344ad6cb8f4d7b25447a8f06ae3a22c6b90283fcc70f28f12578bdaf01ec960a774cdc215bdda4960cef04b6a991e462daeeda4f7e802bf65e6c9a3967f66c",
"size": 61878284,
"digest": "a3f924e7a6d8651b3466f3dc4625eaa00f90ee6cc824ddd4da7a27ce26916220615c1aa33e4a286b757b9283c536b8311edddf469d23e9e1306b90dff19ae11f",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

View File

@ -1,6 +1,6 @@
[
{
"clang_version": "r170377"
"clang_version": "r170890"
},
{
"size": 47,
@ -9,8 +9,8 @@
"filename": "setup.sh"
},
{
"size": 62277867,
"digest": "b9c6ab4069e336fcbe705f07fd2beda37aecfd4078863898826c9591305b92f3f3f762e7f5c1b0eeb7e0fb1c0dacbca60f24868e0b3181bd34dcd9c5d44d20ee",
"size": 62279506,
"digest": "aa886361161a7d32aad71dfe5fd6b6cdff25610d8e32153a80caea66a8475aa8526d8529d8ac26e8ac26bd32878ee0df6d8dbef95dfd9faacec45b4ab918d52d",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

View File

@ -1,17 +0,0 @@
[
{
"clang_version": "r170377"
},
{
"size": 47,
"digest": "2005a41fe97a5e00997063705f39d42b6a43b1cf7ba306cbc7b1513de34cdcd050fc6326efa2107f19ba0cc67914745dbf13154fa748010a93cf072481ef4aaa",
"algorithm": "sha512",
"filename": "setup.sh"
},
{
"size": 56131193,
"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}
]

View File

@ -1,6 +1,6 @@
[
{
"clang_version": "r170377"
"clang_version": "r170890"
},
{
"size": 47,
@ -9,8 +9,8 @@
"filename": "setup.sh"
},
{
"size": 56131193,
"digest": "a1e705d3a72e0e95eeb15722f538a3908277f9f756909ce5e67f0a09b8531c1ba7fcc4816e20795af2e98839e0308b1bc6df95308cda310ae06abf21d429624f",
"size": 56126352,
"digest": "e156e2a39abd5bf272ee30748a6825f22ddd27565b097c66662a2a6f2e9892bc5b4bf30a3552dffbe867dbfc39e7ee086e0b2cd7935f6ea216c0cf936178a88f",
"algorithm": "sha512",
"filename": "clang.tar.bz2"
}

View File

@ -1,4 +1,4 @@
This is the pdf.js project output, https://github.com/mozilla/pdf.js
Current extension version is: 0.6.172
Current extension version is: 0.7.28

View File

@ -30,31 +30,19 @@ const PDF_CONTENT_TYPE = 'application/pdf';
const PREF_PREFIX = 'pdfjs';
const PDF_VIEWER_WEB_PAGE = 'resource://pdf.js/web/viewer.html';
const MAX_DATABASE_LENGTH = 4096;
const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}';
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/NetUtil.jsm');
XPCOMUtils.defineLazyModuleGetter(this, 'PrivateBrowsingUtils',
'resource://gre/modules/PrivateBrowsingUtils.jsm');
let appInfo = Cc['@mozilla.org/xre/app-info;1']
.getService(Ci.nsIXULAppInfo);
let Svc = {};
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
'@mozilla.org/mime;1',
'nsIMIMEService');
let isInPrivateBrowsing;
if (appInfo.ID === FIREFOX_ID) {
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
.getService(Ci.nsIPrivateBrowsingService);
isInPrivateBrowsing = function getInPrivateBrowsing() {
return privateBrowsing.privateBrowsingEnabled;
};
} else {
isInPrivateBrowsing = function() { return false; };
}
function getChromeWindow(domWindow) {
var containingBrowser = domWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
@ -71,6 +59,14 @@ function getBoolPref(pref, def) {
}
}
function getIntPref(pref, def) {
try {
return Services.prefs.getIntPref(pref);
} catch (ex) {
return def;
}
}
function setStringPref(pref, value) {
let str = Cc['@mozilla.org/supports-string;1']
.createInstance(Ci.nsISupportsString);
@ -211,6 +207,30 @@ function ChromeActions(domWindow, dataListener) {
}
ChromeActions.prototype = {
isInPrivateBrowsing: function() {
let docIsPrivate;
try {
docIsPrivate = PrivateBrowsingUtils.isWindowPrivate(this.domWindow);
} catch (x) {
// unable to use PrivateBrowsingUtils, e.g. FF15
}
if (typeof docIsPrivate === 'undefined') {
// per-window Private Browsing is not supported, trying global service
try {
let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1']
.getService(Ci.nsIPrivateBrowsingService);
docIsPrivate = privateBrowsing.privateBrowsingEnabled;
} catch (x) {
// unable to get nsIPrivateBrowsingService (e.g. not Firefox)
docIsPrivate = false;
}
}
// caching the result
this.isInPrivateBrowsing = function isInPrivateBrowsingCached() {
return docIsPrivate;
};
return docIsPrivate;
},
download: function(data, sendResponse) {
var originalUrl = data.originalUrl;
// The data may not be downloaded so we need just retry getting the pdf with
@ -223,16 +243,7 @@ ChromeActions.prototype = {
var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1'].
getService(Ci.nsIWindowWatcher).activeWindow;
let docIsPrivate = false;
try {
docIsPrivate = this.domWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext)
.usePrivateBrowsing;
} catch (x) {
}
let docIsPrivate = this.isInPrivateBrowsing();
let netChannel = NetUtil.newChannel(blobUri);
if ('nsIPrivateBrowsingChannel' in Ci &&
netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
@ -281,7 +292,7 @@ ChromeActions.prototype = {
});
},
setDatabase: function(data) {
if (isInPrivateBrowsing())
if (this.isInPrivateBrowsing())
return;
// Protect against something sending tons of data to setDatabase.
if (data.length > MAX_DATABASE_LENGTH)
@ -289,7 +300,7 @@ ChromeActions.prototype = {
setStringPref(PREF_PREFIX + '.database', data);
},
getDatabase: function() {
if (isInPrivateBrowsing())
if (this.isInPrivateBrowsing())
return '{}';
return getStringPref(PREF_PREFIX + '.database', '{}');
},
@ -351,6 +362,10 @@ ChromeActions.prototype = {
getChromeWindow(this.domWindow).gFindBar &&
'updateControlState' in getChromeWindow(this.domWindow).gFindBar;
},
supportsDocumentFonts: function() {
var pref = getIntPref('browser.display.use_document_fonts', 1);
return !!pref;
},
fallback: function(url, sendResponse) {
var self = this;
var domWindow = this.domWindow;

View File

@ -156,6 +156,13 @@ let PdfJs = {
types.push(PDF_CONTENT_TYPE);
}
prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(','));
// Update the category manager in case the plugins are already loaded.
let categoryManager = Cc["@mozilla.org/categorymanager;1"];
categoryManager.getService(Ci.nsICategoryManager).
deleteCategoryEntry("Gecko-Content-Viewers",
PDF_CONTENT_TYPE,
false);
},
// nsIObserver

File diff suppressed because it is too large Load Diff

View File

@ -521,7 +521,7 @@ html[dir='rtl'] .splitToolbarButtonSeparator {
.splitToolbarButton:hover > .splitToolbarButtonSeparator,
.splitToolbarButton.toggled > .splitToolbarButtonSeparator {
padding: 12px 0;
margin: 0;
margin: 1px 0;
box-shadow: 0 0 0 1px hsla(0,0%,100%,.03);
-webkit-transition-property: padding;
-webkit-transition-duration: 10ms;

View File

@ -936,6 +936,21 @@ var PDFView = {
return support;
},
get supportsDocumentFonts() {
var support = true;
support = FirefoxCom.requestSync('supportsDocumentFonts');
Object.defineProperty(this, 'supportsDocumentFonts', { value: support,
enumerable: true,
configurable: true,
writable: false });
return support;
},
get isHorizontalScrollbarEnabled() {
var div = document.getElementById('viewerContainer');
return div.scrollWidth > div.clientWidth;
},
initPassiveLoading: function pdfViewInitPassiveLoading() {
if (!PDFView.loadingBar) {
PDFView.loadingBar = new ProgressBar('#loadingBar', {});
@ -2037,6 +2052,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
if (outputScale.scaled) {
ctx.scale(outputScale.sx, outputScale.sy);
}
// Checking if document fonts are used only once
var checkIfDocumentFontsUsed = !PDFView.pdfDocument.embeddedFontsUsed;
// Rendering area
@ -2049,6 +2066,12 @@ var PageView = function pageView(container, pdfPage, id, scale,
delete self.loadingIconDiv;
}
if (checkIfDocumentFontsUsed && PDFView.pdfDocument.embeddedFontsUsed &&
!PDFView.supportsDocumentFonts) {
console.error(mozL10n.get('web_fonts_disabled', null,
'Web fonts are disabled: unable to use embedded PDF fonts.'));
PDFView.fallback();
}
if (error) {
PDFView.error(mozL10n.get('rendering_error', null,
'An error occurred while rendering the page.'), error);
@ -3095,6 +3118,7 @@ window.addEventListener('keydown', function keydown(evt) {
case 61: // FF/Mac '='
case 107: // FF '+' and '='
case 187: // Chrome '+'
case 171: // FF with German keyboard
PDFView.zoomIn();
handled = true;
break;
@ -3105,6 +3129,7 @@ window.addEventListener('keydown', function keydown(evt) {
handled = true;
break;
case 48: // '0'
case 96: // '0' on Numpad of Swedish keyboard
PDFView.parseScale(DEFAULT_SCALE, true);
handled = true;
break;
@ -3152,6 +3177,10 @@ window.addEventListener('keydown', function keydown(evt) {
}
// in fullscreen mode falls throw here
case 37: // left arrow
// horizontal scrolling using arrow keys
if (PDFView.isHorizontalScrollbarEnabled) {
break;
}
case 75: // 'k'
case 80: // 'p'
PDFView.page--;
@ -3165,6 +3194,10 @@ window.addEventListener('keydown', function keydown(evt) {
}
// in fullscreen mode falls throw here
case 39: // right arrow
// horizontal scrolling using arrow keys
if (PDFView.isHorizontalScrollbarEnabled) {
break;
}
case 74: // 'j'
case 78: // 'n'
PDFView.page++;

Some files were not shown because too many files have changed in this diff Show More