Merge m-c to b2g-inbound.

This commit is contained in:
Ryan VanderMeulen 2014-02-12 08:39:43 -05:00
commit ff776dff9f
301 changed files with 7662 additions and 5132 deletions

View File

@ -12,6 +12,7 @@
#include "States.h" #include "States.h"
#include "nsEventStateManager.h" #include "nsEventStateManager.h"
#include "mozilla/Selection.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::a11y; using namespace mozilla::a11y;
@ -126,13 +127,22 @@ AccShowEvent::
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget, AccTextSelChangeEvent::AccTextSelChangeEvent(HyperTextAccessible* aTarget,
nsISelection* aSelection) : Selection* aSelection,
int32_t aReason) :
AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget, AccEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, aTarget,
eAutoDetect, eCoalesceTextSelChange), eAutoDetect, eCoalesceTextSelChange),
mSel(aSelection) {} mSel(aSelection), mReason(aReason) {}
AccTextSelChangeEvent::~AccTextSelChangeEvent() { } AccTextSelChangeEvent::~AccTextSelChangeEvent() { }
bool
AccTextSelChangeEvent::IsCaretMoveOnly() const
{
return mSel->GetRangeCount() == 1 && mSel->IsCollapsed() &&
((mReason & (nsISelectionListener::COLLAPSETOSTART_REASON |
nsISelectionListener::COLLAPSETOEND_REASON)) == 0);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// AccSelChangeEvent // AccSelChangeEvent
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -10,9 +10,10 @@
#include "mozilla/a11y/Accessible.h" #include "mozilla/a11y/Accessible.h"
class nsISelection;
namespace mozilla { namespace mozilla {
class Selection;
namespace a11y { namespace a11y {
class DocAccessible; class DocAccessible;
@ -366,7 +367,8 @@ private:
class AccTextSelChangeEvent : public AccEvent class AccTextSelChangeEvent : public AccEvent
{ {
public: public:
AccTextSelChangeEvent(HyperTextAccessible* aTarget, nsISelection* aSelection); AccTextSelChangeEvent(HyperTextAccessible* aTarget, Selection* aSelection,
int32_t aReason);
virtual ~AccTextSelChangeEvent(); virtual ~AccTextSelChangeEvent();
// AccEvent // AccEvent
@ -376,8 +378,16 @@ public:
return AccEvent::GetEventGroups() | (1U << eTextSelChangeEvent); return AccEvent::GetEventGroups() | (1U << eTextSelChangeEvent);
} }
// AccTextSelChangeEvent
/**
* Return true if the text selection change wasn't caused by pure caret move.
*/
bool IsCaretMoveOnly() const;
private: private:
nsCOMPtr<nsISelection> mSel; nsRefPtr<Selection> mSel;
int32_t mReason;
friend class EventQueue; friend class EventQueue;
friend class SelectionManager; friend class SelectionManager;

View File

@ -582,7 +582,8 @@ logging::FocusDispatched(Accessible* aTarget)
} }
void void
logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument) logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument,
int16_t aReason)
{ {
nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection)); nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
@ -598,8 +599,10 @@ logging::SelChange(nsISelection* aSelection, DocAccessible* aDocument)
strType = "unknown"; strType = "unknown";
bool isIgnored = !aDocument || !aDocument->IsContentLoaded(); bool isIgnored = !aDocument || !aDocument->IsContentLoaded();
printf("\nSelection changed, selection type: %s, notification %s\n", printf("\nSelection changed, selection type: %s, notification %s, reason: %d\n",
strType, (isIgnored ? "ignored" : "pending")); strType, (isIgnored ? "ignored" : "pending"), aReason);
Stack();
} }
void void

View File

@ -118,7 +118,8 @@ void FocusDispatched(Accessible* aTarget);
/** /**
* Log the selection change. * Log the selection change.
*/ */
void SelChange(nsISelection* aSelection, DocAccessible* aDocument); void SelChange(nsISelection* aSelection, DocAccessible* aDocument,
int16_t aReason);
/** /**
* Log the message ('title: text' format) on new line. Print the start and end * Log the message ('title: text' format) on new line. Print the start and end

View File

@ -14,13 +14,23 @@
#include "nsIAccessibleTypes.h" #include "nsIAccessibleTypes.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsIPresShell.h" #include "nsIPresShell.h"
#include "nsISelectionPrivate.h"
#include "mozilla/Selection.h" #include "mozilla/Selection.h"
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::a11y; using namespace mozilla::a11y;
struct mozilla::a11y::SelData
{
SelData(Selection* aSel, int32_t aReason) :
mSel(aSel), mReason(aReason) {}
nsRefPtr<Selection> mSel;
int16_t mReason;
NS_INLINE_DECL_REFCOUNTING(SelData);
};
void void
SelectionManager::ClearControlSelectionListener() SelectionManager::ClearControlSelectionListener()
{ {
@ -110,17 +120,16 @@ SelectionManager::RemoveDocSelectionListener(nsIPresShell* aPresShell)
void void
SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent) SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent)
{ {
// Fire selection change event if it's not pure caret-move selection change,
// i.e. the accessible has or had not collapsed selection.
AccTextSelChangeEvent* event = downcast_accEvent(aEvent); AccTextSelChangeEvent* event = downcast_accEvent(aEvent);
Selection* sel = static_cast<Selection*>(event->mSel.get()); if (!event->IsCaretMoveOnly())
// Fire selection change event if it's not pure caret-move selection change.
if (sel->GetRangeCount() != 1 || !sel->IsCollapsed())
nsEventShell::FireEvent(aEvent); nsEventShell::FireEvent(aEvent);
// Fire caret move event if there's a caret in the selection. // Fire caret move event if there's a caret in the selection.
nsINode* caretCntrNode = nsINode* caretCntrNode =
nsCoreUtils::GetDOMNodeFromDOMPoint(sel->GetFocusNode(), nsCoreUtils::GetDOMNodeFromDOMPoint(event->mSel->GetFocusNode(),
sel->FocusOffset()); event->mSel->FocusOffset());
if (!caretCntrNode) if (!caretCntrNode)
return; return;
@ -150,7 +159,7 @@ SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
#ifdef A11Y_LOG #ifdef A11Y_LOG
if (logging::IsEnabled(logging::eSelection)) if (logging::IsEnabled(logging::eSelection))
logging::SelChange(aSelection, document); logging::SelChange(aSelection, document, aReason);
#endif #endif
// Don't fire events until document is loaded. // Don't fire events until document is loaded.
@ -158,17 +167,19 @@ SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
// Selection manager has longer lifetime than any document accessible, // Selection manager has longer lifetime than any document accessible,
// so that we are guaranteed that the notification is processed before // so that we are guaranteed that the notification is processed before
// the selection manager is destroyed. // the selection manager is destroyed.
document->HandleNotification<SelectionManager, nsISelection> nsRefPtr<SelData> selData =
(this, &SelectionManager::ProcessSelectionChanged, aSelection); new SelData(static_cast<Selection*>(aSelection), aReason);
document->HandleNotification<SelectionManager, SelData>
(this, &SelectionManager::ProcessSelectionChanged, selData);
} }
return NS_OK; return NS_OK;
} }
void void
SelectionManager::ProcessSelectionChanged(nsISelection* aSelection) SelectionManager::ProcessSelectionChanged(SelData* aSelData)
{ {
Selection* selection = static_cast<Selection*>(aSelection); Selection* selection = aSelData->mSel;
if (!selection->GetPresShell()) if (!selection->GetPresShell())
return; return;
@ -176,11 +187,12 @@ SelectionManager::ProcessSelectionChanged(nsISelection* aSelection)
nsINode* cntrNode = nullptr; nsINode* cntrNode = nullptr;
if (range) if (range)
cntrNode = range->GetCommonAncestor(); cntrNode = range->GetCommonAncestor();
if (!cntrNode) { if (!cntrNode) {
cntrNode = selection->GetFrameSelection()->GetAncestorLimiter(); cntrNode = selection->GetFrameSelection()->GetAncestorLimiter();
if (!cntrNode) { if (!cntrNode) {
cntrNode = selection->GetPresShell()->GetDocument(); cntrNode = selection->GetPresShell()->GetDocument();
NS_ASSERTION(selection->GetPresShell()->ConstFrameSelection() == selection->GetFrameSelection(), NS_ASSERTION(aSelData->mSel->GetPresShell()->ConstFrameSelection() == selection->GetFrameSelection(),
"Wrong selection container was used!"); "Wrong selection container was used!");
} }
} }
@ -192,7 +204,8 @@ SelectionManager::ProcessSelectionChanged(nsISelection* aSelection)
} }
if (selection->GetType() == nsISelectionController::SELECTION_NORMAL) { if (selection->GetType() == nsISelectionController::SELECTION_NORMAL) {
nsRefPtr<AccEvent> event = new AccTextSelChangeEvent(text, aSelection); nsRefPtr<AccEvent> event =
new AccTextSelChangeEvent(text, selection, aSelData->mReason);
text->Document()->FireDelayedEvent(event); text->Document()->FireDelayedEvent(event);
} else if (selection->GetType() == nsISelectionController::SELECTION_SPELLCHECK) { } else if (selection->GetType() == nsISelectionController::SELECTION_SPELLCHECK) {

View File

@ -38,6 +38,8 @@ class AccEvent;
* selection change events. * selection change events.
*/ */
struct SelData;
class SelectionManager : public nsISelectionListener class SelectionManager : public nsISelectionListener
{ {
public: public:
@ -83,7 +85,7 @@ protected:
/** /**
* Process DOM selection change. Fire selection and caret move events. * Process DOM selection change. Fire selection and caret move events.
*/ */
void ProcessSelectionChanged(nsISelection* aSelection); void ProcessSelectionChanged(SelData* aSelData);
private: private:
// Currently focused control. // Currently focused control.

View File

@ -155,12 +155,18 @@ this.EventManager.prototype = {
let event = aEvent. let event = aEvent.
QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent); QueryInterface(Ci.nsIAccessibleVirtualCursorChangeEvent);
let reason = event.reason; let reason = event.reason;
let oldAccessible = event.oldAccessible;
if (oldAccessible && oldAccessible.role == Roles.INTERNAL_FRAME) {
let mm = Utils.getMessageManager(oldAccessible.DOMNode);
mm.sendAsyncMessage('AccessFu:ClearCursor', {});
}
if (this.editState.editing) { if (this.editState.editing) {
aEvent.accessibleDocument.takeFocus(); aEvent.accessibleDocument.takeFocus();
} }
this.present( this.present(
Presentation.pivotChanged(position, event.oldAccessible, reason, Presentation.pivotChanged(position, oldAccessible, reason,
pivot.startOffset, pivot.endOffset)); pivot.startOffset, pivot.endOffset));
break; break;
@ -184,7 +190,7 @@ this.EventManager.prototype = {
} }
case Events.SCROLLING_START: case Events.SCROLLING_START:
{ {
let vc = Utils.getVirtualCursor(aEvent.accessibleDocument); let vc = Utils.getVirtualCursor(this.contentScope.content.document);
vc.moveNext(TraversalRules.Simple, aEvent.accessible, true); vc.moveNext(TraversalRules.Simple, aEvent.accessible, true);
break; break;
} }
@ -275,7 +281,7 @@ this.EventManager.prototype = {
let doc = aEvent.accessibleDocument; let doc = aEvent.accessibleDocument;
if (acc.role != Roles.DOCUMENT && doc.role != Roles.CHROME_WINDOW) { if (acc.role != Roles.DOCUMENT && doc.role != Roles.CHROME_WINDOW) {
this.contentScope.content.clearTimeout(this._autoMove); this.contentScope.content.clearTimeout(this._autoMove);
let vc = Utils.getVirtualCursor(doc); let vc = Utils.getVirtualCursor(this.contentScope.content.document);
vc.moveNext(TraversalRules.Simple, acc, true); vc.moveNext(TraversalRules.Simple, acc, true);
} }
break; break;
@ -283,7 +289,7 @@ this.EventManager.prototype = {
case Events.DOCUMENT_LOAD_COMPLETE: case Events.DOCUMENT_LOAD_COMPLETE:
{ {
this._autoMove = this.contentScope.content.setTimeout(() => { this._autoMove = this.contentScope.content.setTimeout(() => {
Utils.getVirtualCursor(aEvent.accessibleDocument) Utils.getVirtualCursor(this.contentScope.content.document)
.moveNext(TraversalRules.Simple, aEvent.accessible, true); .moveNext(TraversalRules.Simple, aEvent.accessible, true);
}, 500); }, 500);
break; break;

View File

@ -27,6 +27,15 @@ Logger.debug('content-script.js');
let eventManager = null; let eventManager = null;
function clearCursor(aMessage) {
try {
Utils.getVirtualCursor(content.document).position = null;
forwardToChild(aMessage);
} catch (x) {
Logger.logException(x);
}
}
function moveCursor(aMessage) { function moveCursor(aMessage) {
if (Logger.logLevel >= Logger.DEBUG) { if (Logger.logLevel >= Logger.DEBUG) {
Logger.debug(aMessage.name, JSON.stringify(aMessage.json, null, ' ')); Logger.debug(aMessage.name, JSON.stringify(aMessage.json, null, ' '));
@ -144,7 +153,11 @@ function forwardToChild(aMessage, aListener, aVCPosition) {
} }
let mm = Utils.getMessageManager(acc.DOMNode); let mm = Utils.getMessageManager(acc.DOMNode);
mm.addMessageListener(aMessage.name, aListener);
if (aListener) {
mm.addMessageListener(aMessage.name, aListener);
}
// XXX: This is a silly way to make a deep copy // XXX: This is a silly way to make a deep copy
let newJSON = JSON.parse(JSON.stringify(aMessage.json)); let newJSON = JSON.parse(JSON.stringify(aMessage.json));
newJSON.origin = 'parent'; newJSON.origin = 'parent';
@ -381,6 +394,7 @@ addMessageListener(
addMessageListener('AccessFu:AdjustRange', adjustRange); addMessageListener('AccessFu:AdjustRange', adjustRange);
addMessageListener('AccessFu:MoveCaret', moveCaret); addMessageListener('AccessFu:MoveCaret', moveCaret);
addMessageListener('AccessFu:MoveByGranularity', moveByGranularity); addMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
addMessageListener('AccessFu:ClearCursor', clearCursor);
if (!eventManager) { if (!eventManager) {
eventManager = new EventManager(this); eventManager = new EventManager(this);
@ -401,6 +415,7 @@ addMessageListener(
removeMessageListener('AccessFu:Scroll', scroll); removeMessageListener('AccessFu:Scroll', scroll);
removeMessageListener('AccessFu:MoveCaret', moveCaret); removeMessageListener('AccessFu:MoveCaret', moveCaret);
removeMessageListener('AccessFu:MoveByGranularity', moveByGranularity); removeMessageListener('AccessFu:MoveByGranularity', moveByGranularity);
removeMessageListener('AccessFu:ClearCursor', clearCursor);
eventManager.stop(); eventManager.stop();
}); });

View File

@ -16,7 +16,7 @@
#include "nsIArray.h" #include "nsIArray.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeItem.h"
#include "nsIXULRuntime.h" #include "nsXULAppAPI.h"
using namespace mozilla; using namespace mozilla;
using namespace mozilla::a11y; using namespace mozilla::a11y;
@ -59,7 +59,7 @@ nsWinUtils::MaybeStartWindowEmulation()
// with tabs. // with tabs.
if (Compatibility::IsJAWS() || Compatibility::IsWE() || if (Compatibility::IsJAWS() || Compatibility::IsWE() ||
Compatibility::IsDolphin() || Compatibility::IsDolphin() ||
BrowserTabsRemote()) { XRE_GetProcessType() == GeckoProcessType_Content) {
RegisterNativeWindow(kClassNameTabContent); RegisterNativeWindow(kClassNameTabContent);
sHWNDCache = new nsRefPtrHashtable<nsPtrHashKey<void>, DocAccessible>(4); sHWNDCache = new nsRefPtrHashtable<nsPtrHashKey<void>, DocAccessible>(4);
return true; return true;

View File

@ -1212,17 +1212,17 @@ function synthUpKey(aNodeOrID, aCheckerOrEventSeq, aArgs)
/** /**
* Left arrow key invoker. * Left arrow key invoker.
*/ */
function synthLeftKey(aNodeOrID, aCheckerOrEventSeq) function synthLeftKey(aNodeOrID, aCheckerOrEventSeq, aArgs)
{ {
this.__proto__ = new synthKey(aNodeOrID, "VK_LEFT", null, aCheckerOrEventSeq); this.__proto__ = new synthKey(aNodeOrID, "VK_LEFT", aArgs, aCheckerOrEventSeq);
} }
/** /**
* Right arrow key invoker. * Right arrow key invoker.
*/ */
function synthRightKey(aNodeOrID, aCheckerOrEventSeq) function synthRightKey(aNodeOrID, aCheckerOrEventSeq, aArgs)
{ {
this.__proto__ = new synthKey(aNodeOrID, "VK_RIGHT", null, aCheckerOrEventSeq); this.__proto__ = new synthKey(aNodeOrID, "VK_RIGHT", aArgs, aCheckerOrEventSeq);
} }
/** /**
@ -1764,7 +1764,12 @@ function textSelectionChecker(aID, aStartOffset, aEndOffset)
this.check = function textSelectionChecker_check(aEvent) this.check = function textSelectionChecker_check(aEvent)
{ {
testTextGetSelection(aID, aStartOffset, aEndOffset, 0); if (aStartOffset == aEndOffset) {
is(getAccessible(aID, [nsIAccessibleText]).caretOffset, aStartOffset,
"Wrong collapsed selection!");
} else {
testTextGetSelection(aID, aStartOffset, aEndOffset, 0);
}
} }
} }

View File

@ -24,19 +24,30 @@
// gA11yEventDumpID = "eventdump"; // debug stuff // gA11yEventDumpID = "eventdump"; // debug stuff
//gA11yEventDumpToConsole = true; //gA11yEventDumpToConsole = true;
function getOnclickSeq(aID)
{
return [
new caretMoveChecker(0, aID),
new unexpectedInvokerChecker(EVENT_TEXT_SELECTION_CHANGED, aID)
];
}
function doTests() function doTests()
{ {
// test caret move events and caret offsets // test caret move events and caret offsets
gQueue = new eventQueue(); gQueue = new eventQueue();
var onclickSeq = [ gQueue.push(new synthClick("c1_p1", getOnclickSeq("c1_p1")));
new caretMoveChecker(0, "c1_p1"),
new unexpectedInvokerChecker(EVENT_TEXT_SELECTION_CHANGED, "c1_p1")
];
gQueue.push(new synthClick("c1_p1", onclickSeq));
gQueue.push(new synthDownKey("c1", new textSelectionChecker("c1", 0, 1), { shiftKey: true })); gQueue.push(new synthDownKey("c1", new textSelectionChecker("c1", 0, 1), { shiftKey: true }));
gQueue.push(new synthDownKey("c1", new textSelectionChecker("c1", 0, 2), { shiftKey: true })); gQueue.push(new synthDownKey("c1", new textSelectionChecker("c1", 0, 2), { shiftKey: true }));
gQueue.push(new synthClick("ta1", getOnclickSeq("ta1")));
gQueue.push(new synthRightKey("ta1",
new textSelectionChecker("ta1", 0, 1),
{ shiftKey: true }));
gQueue.push(new synthLeftKey("ta1",
new textSelectionChecker("ta1", 0, 0)));
gQueue.invoke(); // Will call SimpleTest.finish(); gQueue.invoke(); // Will call SimpleTest.finish();
} }
@ -52,6 +63,11 @@
title="Text selection change event has a wrong target when selection is spanned through several objects"> title="Text selection change event has a wrong target when selection is spanned through several objects">
Bug 762934 Bug 762934
</a> </a>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=956032"
title="Text selection change event missed when selected text becomes unselected">
Bug 956032
</a>
<p id="display"></p> <p id="display"></p>
<div id="content" style="display: none"></div> <div id="content" style="display: none"></div>
<pre id="test"> <pre id="test">
@ -62,6 +78,8 @@
<p id="c1_p2">paragraph</p> <p id="c1_p2">paragraph</p>
</div> </div>
<textarea id="ta1">Hello world</textarea>
<div id="eventdump"></div> <div id="eventdump"></div>
</body> </body>
</html> </html>

View File

@ -978,7 +978,16 @@ pref("dom.ipc.plugins.enabled.x86_64", true);
pref("dom.ipc.plugins.enabled", true); pref("dom.ipc.plugins.enabled", true);
#endif #endif
#if defined(NIGHTLY_BUILD) && defined(XP_MACOSX)
// In Nightly, browser.tabs.remote is enabled on platforms that
// support OMTC. However, users won't actually get remote tabs unless
// they enable browser.tabs.remote.autostart or they use the "New OOP
// Window" menu option.
pref("browser.tabs.remote", true);
#else
pref("browser.tabs.remote", false); pref("browser.tabs.remote", false);
#endif
pref("browser.tabs.remote.autostart", false);
// This pref governs whether we attempt to work around problems caused by // This pref governs whether we attempt to work around problems caused by
// plugins using OS calls to manipulate the cursor while running out-of- // plugins using OS calls to manipulate the cursor while running out-of-

View File

@ -27,6 +27,14 @@
accesskey="&newPrivateWindow.accesskey;" accesskey="&newPrivateWindow.accesskey;"
command="Tools:PrivateBrowsing" command="Tools:PrivateBrowsing"
key="key_privatebrowsing"/> key="key_privatebrowsing"/>
<menuitem id="menu_newRemoteWindow"
label="New OOP Window"
hidden="true"
command="Tools:RemoteWindow"/>
<menuitem id="menu_newNonRemoteWindow"
label="New In-process Window"
hidden="true"
command="Tools:NonRemoteWindow"/>
<menuitem id="menu_openFile" <menuitem id="menu_openFile"
label="&openFileCmd.label;" label="&openFileCmd.label;"
command="Browser:OpenFile" command="Browser:OpenFile"

View File

@ -20,7 +20,7 @@
<command id="cmd_handleBackspace" oncommand="BrowserHandleBackspace();" /> <command id="cmd_handleBackspace" oncommand="BrowserHandleBackspace();" />
<command id="cmd_handleShiftBackspace" oncommand="BrowserHandleShiftBackspace();" /> <command id="cmd_handleShiftBackspace" oncommand="BrowserHandleShiftBackspace();" />
<command id="cmd_newNavigatorTab" oncommand="BrowserOpenTab();"/> <command id="cmd_newNavigatorTab" oncommand="BrowserOpenNewTabOrWindow(event);"/>
<command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/> <command id="Browser:OpenFile" oncommand="BrowserOpenFileWindow();"/>
<command id="Browser:SavePage" oncommand="saveDocument(window.content.document);"/> <command id="Browser:SavePage" oncommand="saveDocument(window.content.document);"/>
@ -106,6 +106,10 @@
oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/> oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/>
<command id="Tools:PrivateBrowsing" <command id="Tools:PrivateBrowsing"
oncommand="OpenBrowserWindow({private: true});"/> oncommand="OpenBrowserWindow({private: true});"/>
<command id="Tools:RemoteWindow"
oncommand="OpenBrowserWindow({remote: true});"/>
<command id="Tools:NonRemoteWindow"
oncommand="OpenBrowserWindow({remote: false});"/>
<command id="History:UndoCloseTab" oncommand="undoCloseTab();"/> <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
<command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/> <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
<command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/> <command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>

View File

@ -202,14 +202,9 @@ var ctrlTab = {
list = list.filter(function (tab) !tab.closing); list = list.filter(function (tab) !tab.closing);
if (this.recentlyUsedLimit != 0) { if (this.recentlyUsedLimit != 0) {
let recentlyUsedTabs = []; let recentlyUsedTabs = this._recentlyUsedTabs;
for (let tab of this._recentlyUsedTabs) { if (this.recentlyUsedLimit > 0)
if (!tab.hidden && !tab.closing) { recentlyUsedTabs = this._recentlyUsedTabs.slice(0, this.recentlyUsedLimit);
recentlyUsedTabs.push(tab);
if (this.recentlyUsedLimit > 0 && recentlyUsedTabs.length >= this.recentlyUsedLimit)
break;
}
}
for (let i = recentlyUsedTabs.length - 1; i >= 0; i--) { for (let i = recentlyUsedTabs.length - 1; i >= 0; i--) {
list.splice(list.indexOf(recentlyUsedTabs[i]), 1); list.splice(list.indexOf(recentlyUsedTabs[i]), 1);
list.unshift(recentlyUsedTabs[i]); list.unshift(recentlyUsedTabs[i]);

View File

@ -757,7 +757,11 @@ var gBrowserInit = {
delayedStartupFinished: false, delayedStartupFinished: false,
onLoad: function() { onLoad: function() {
gMultiProcessBrowser = Services.appinfo.browserTabsRemote; gMultiProcessBrowser =
window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext)
.useRemoteTabs;
var mustLoadSidebar = false; var mustLoadSidebar = false;
@ -1023,6 +1027,7 @@ var gBrowserInit = {
IndexedDBPromptHelper.init(); IndexedDBPromptHelper.init();
gFormSubmitObserver.init(); gFormSubmitObserver.init();
SocialUI.init(); SocialUI.init();
gRemoteTabsUI.init();
// Initialize the full zoom setting. // Initialize the full zoom setting.
// We do this before the session restore service gets initialized so we can // We do this before the session restore service gets initialized so we can
@ -3186,6 +3191,12 @@ function OpenBrowserWindow(options)
extraFeatures = ",non-private"; extraFeatures = ",non-private";
} }
if (options && options.remote) {
extraFeatures += ",remote";
} else if (options && options.remote === false) {
extraFeatures += ",non-remote";
}
// if and only if the current window is a browser window and it has a document with a character // if and only if the current window is a browser window and it has a document with a character
// set, then extract the current charset menu setting from the current document and use it to // set, then extract the current charset menu setting from the current document and use it to
// initialize the new browser window... // initialize the new browser window...
@ -6866,6 +6877,28 @@ let gPrivateBrowsingUI = {
} }
}; };
let gRemoteTabsUI = {
init: function() {
if (window.location.href != getBrowserURL()) {
return;
}
let remoteTabs = gPrefService.getBoolPref("browser.tabs.remote");
let autostart = gPrefService.getBoolPref("browser.tabs.remote.autostart");
let newRemoteWindow = document.getElementById("menu_newRemoteWindow");
let newNonRemoteWindow = document.getElementById("menu_newNonRemoteWindow");
if (!remoteTabs) {
newRemoteWindow.hidden = true;
newNonRemoteWindow.hidden = true;
return;
}
newRemoteWindow.hidden = autostart;
newNonRemoteWindow.hidden = !autostart;
}
};
/** /**
* Switch to a tab that has a given URI, and focusses its browser window. * Switch to a tab that has a given URI, and focusses its browser window.
@ -7203,3 +7236,11 @@ let BrowserChromeTest = {
this._cb = cb; this._cb = cb;
} }
}; };
function BrowserOpenNewTabOrWindow(event) {
if (event.shiftKey) {
OpenBrowserWindow();
} else {
BrowserOpenTab();
}
}

View File

@ -35,7 +35,7 @@ addMessageListener("Browser:HideSessionRestoreButton", function (message) {
} }
}); });
if (Services.prefs.getBoolPref("browser.tabs.remote")) { if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
addEventListener("contextmenu", function (event) { addEventListener("contextmenu", function (event) {
sendAsyncMessage("contextmenu", {}, { event: event }); sendAsyncMessage("contextmenu", {}, { event: event });
}, false); }, false);

View File

@ -3054,7 +3054,11 @@
"-moz-default-background-color" : "-moz-default-background-color" :
Services.prefs.getCharPref("browser.display.background_color"); Services.prefs.getCharPref("browser.display.background_color");
if (Services.appinfo.browserTabsRemote) { let remote = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsILoadContext)
.useRemoteTabs;
if (remote) {
messageManager.addMessageListener("DOMTitleChanged", this); messageManager.addMessageListener("DOMTitleChanged", this);
messageManager.addMessageListener("contextmenu", this); messageManager.addMessageListener("contextmenu", this);
} }
@ -3121,7 +3125,7 @@
document.removeEventListener("keypress", this, false); document.removeEventListener("keypress", this, false);
window.removeEventListener("sizemodechange", this, false); window.removeEventListener("sizemodechange", this, false);
if (Services.appinfo.browserTabsRemote) { if (gMultiProcessBrowser) {
messageManager.removeMessageListener("DOMTitleChanged", this); messageManager.removeMessageListener("DOMTitleChanged", this);
messageManager.removeMessageListener("contextmenu", this); messageManager.removeMessageListener("contextmenu", this);
} }

View File

@ -729,21 +729,23 @@ function test22() {
is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 22, plugin should have started"); is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 22, plugin should have started");
ok(pluginNode.activated, "Test 22, plugin should be activated"); ok(pluginNode.activated, "Test 22, plugin should be activated");
// Reload plugin // Spin event loop for plugin to finish spawning
var oldVal = pluginNode.getObjectValue(); executeSoon(function() {
pluginNode.src = pluginNode.src; var oldVal = pluginNode.getObjectValue();
is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 22, Plugin should have retained activated state"); pluginNode.src = pluginNode.src;
ok(pluginNode.activated, "Test 22, plugin should have remained activated"); is(objLoadingContent.displayedType, Ci.nsIObjectLoadingContent.TYPE_PLUGIN, "Test 22, Plugin should have retained activated state");
// Sanity, ensure that we actually reloaded the instance, since this behavior might change in the future. ok(pluginNode.activated, "Test 22, plugin should have remained activated");
var pluginsDiffer; // Sanity, ensure that we actually reloaded the instance, since this behavior might change in the future.
try { var pluginsDiffer;
pluginNode.checkObjectValue(oldVal); try {
} catch (e) { pluginNode.checkObjectValue(oldVal);
pluginsDiffer = true; } catch (e) {
} pluginsDiffer = true;
ok(pluginsDiffer, "Test 22, plugin should have reloaded"); }
ok(pluginsDiffer, "Test 22, plugin should have reloaded");
prepareTest(runAfterPluginBindingAttached(test23), gTestRoot + "plugin_test.html"); prepareTest(runAfterPluginBindingAttached(test23), gTestRoot + "plugin_test.html");
});
} }
// Tests that a click-to-play plugin resets its activated state when changing types // Tests that a click-to-play plugin resets its activated state when changing types

View File

@ -120,7 +120,6 @@
oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); PanelUI.hide();"/> oncommand="PlacesCommandHook.showPlacesOrganizer('UnfiledBookmarks'); PanelUI.hide();"/>
<toolbarseparator/> <toolbarseparator/>
<toolbaritem id="panelMenu_bookmarksMenu" <toolbaritem id="panelMenu_bookmarksMenu"
flex="1"
orient="vertical" orient="vertical"
smoothscroll="false" smoothscroll="false"
onclick="if (event.button == 1) BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);" onclick="if (event.button == 1) BookmarkingUI.onPanelMenuViewCommand(event, this._placesView);"
@ -145,7 +144,7 @@
<panelview id="PanelUI-helpView" flex="1" class="PanelUI-subView"> <panelview id="PanelUI-helpView" flex="1" class="PanelUI-subView">
<label value="&helpMenu.label;" class="panel-subview-header"/> <label value="&helpMenu.label;" class="panel-subview-header"/>
<vbox id="PanelUI-helpItems"/> <vbox id="PanelUI-helpItems" class="panel-subview-body"/>
</panelview> </panelview>
<panelview id="PanelUI-developer" flex="1"> <panelview id="PanelUI-developer" flex="1">

View File

@ -303,6 +303,7 @@ const PanelUI = {
let multiView = document.createElement("panelmultiview"); let multiView = document.createElement("panelmultiview");
tempPanel.appendChild(multiView); tempPanel.appendChild(multiView);
multiView.setAttribute("mainViewIsSubView", "true");
multiView.setMainView(viewNode); multiView.setMainView(viewNode);
viewNode.classList.add("cui-widget-panelview"); viewNode.classList.add("cui-widget-panelview");
CustomizableUI.addPanelCloseListeners(tempPanel); CustomizableUI.addPanelCloseListeners(tempPanel);

View File

@ -66,6 +66,8 @@
<property name="_mainViewId" onget="return this.getAttribute('mainViewId');" onset="this.setAttribute('mainViewId', val); return val;"/> <property name="_mainViewId" onget="return this.getAttribute('mainViewId');" onset="this.setAttribute('mainViewId', val); return val;"/>
<property name="_mainView" readonly="true" <property name="_mainView" readonly="true"
onget="return this._mainViewId ? document.getElementById(this._mainViewId) : null;"/> onget="return this._mainViewId ? document.getElementById(this._mainViewId) : null;"/>
<property name="showingSubViewAsMainView" readonly="true"
onget="return this.getAttribute('mainViewIsSubView') == 'true'"/>
<property name="ignoreMutations"> <property name="ignoreMutations">
<getter> <getter>
@ -322,8 +324,13 @@
<method name="_syncContainerWithMainView"> <method name="_syncContainerWithMainView">
<body><![CDATA[ <body><![CDATA[
if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) { if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) {
this._viewContainer.style.height = let height;
this._mainView.scrollHeight + "px"; if (this.showingSubViewAsMainView) {
height = this._heightOfSubview(this._mainView);
} else {
height = this._mainView.scrollHeight;
}
this._viewContainer.style.height = height + "px";
} }
]]></body> ]]></body>
</method> </method>

View File

@ -3139,7 +3139,7 @@ function WidgetSingleWrapper(aWidget, aNode) {
this.__defineGetter__("anchor", function() { this.__defineGetter__("anchor", function() {
let anchorId; let anchorId;
// First check for an anchor for the area: // First check for an anchor for the area:
let placement = CustomizableUIInternal.getPlacementOfWidget(aWidgetId); let placement = CustomizableUIInternal.getPlacementOfWidget(aWidget.id);
if (placement) { if (placement) {
anchorId = gAreas.get(placement.area).get("anchor"); anchorId = gAreas.get(placement.area).get("anchor");
} }

View File

@ -854,6 +854,7 @@ CustomizeMode.prototype = {
this.persistCurrentSets(true); this.persistCurrentSets(true);
this._updateResetButton(); this._updateResetButton();
this._updateEmptyPaletteNotice();
this._showPanelCustomizationPlaceholders(); this._showPanelCustomizationPlaceholders();
this.resetting = false; this.resetting = false;
}.bind(this)).then(null, ERROR); }.bind(this)).then(null, ERROR);
@ -955,8 +956,10 @@ CustomizeMode.prototype = {
_onUIChange: function() { _onUIChange: function() {
this._changed = true; this._changed = true;
this._updateResetButton(); if (!this.resetting) {
this._updateEmptyPaletteNotice(); this._updateResetButton();
this._updateEmptyPaletteNotice();
}
this.dispatchToolboxEvent("customizationchange"); this.dispatchToolboxEvent("customizationchange");
}, },

View File

@ -0,0 +1,18 @@
# This mozconfig is used when compiling the browser for the SM(Hf) rooting
# hazard analysis build, see
# https://wiki.mozilla.org/Javascript:SpiderMonkey:ExactStackRooting
. "$topsrcdir/build/unix/mozconfig.linux"
# The configuration options are chosen to compile the most code
# (--enable-debug, --enable-tests) in the trickiest way possible
# (--enable-optimize) to maximize the chance of seeing tricky static orderings.
ac_add_options --enable-debug
ac_add_options --enable-tests
ac_add_options --enable-optimize
CFLAGS="$CFLAGS -Wno-attributes"
CPPFLAGS="$CPPFLAGS -Wno-attributes"
CXXFLAGS="$CXXFLAGS -Wno-attributes"
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -29,6 +29,9 @@ const EVENTS = {
SOURCE_SHOWN: "Debugger:EditorSourceShown", SOURCE_SHOWN: "Debugger:EditorSourceShown",
SOURCE_ERROR_SHOWN: "Debugger:EditorSourceErrorShown", SOURCE_ERROR_SHOWN: "Debugger:EditorSourceErrorShown",
// When the editor has shown a source and set the line / column position
EDITOR_LOCATION_SET: "Debugger:EditorLocationSet",
// When scopes, variables, properties and watch expressions are fetched and // When scopes, variables, properties and watch expressions are fetched and
// displayed in the variables view. // displayed in the variables view.
FETCHED_SCOPES: "Debugger:FetchedScopes", FETCHED_SCOPES: "Debugger:FetchedScopes",
@ -1300,7 +1303,7 @@ SourceScripts.prototype = {
deferred.promise.pretty = wantPretty; deferred.promise.pretty = wantPretty;
this._cache.set(aSource.url, deferred.promise); this._cache.set(aSource.url, deferred.promise);
const afterToggle = ({ error, message, source: text }) => { const afterToggle = ({ error, message, source: text, contentType }) => {
if (error) { if (error) {
// Revert the rejected promise from the cache, so that the original // Revert the rejected promise from the cache, so that the original
// source's text may be shown when the source is selected. // source's text may be shown when the source is selected.
@ -1308,7 +1311,7 @@ SourceScripts.prototype = {
deferred.reject([aSource, message || error]); deferred.reject([aSource, message || error]);
return; return;
} }
deferred.resolve([aSource, text]); deferred.resolve([aSource, text, contentType]);
}; };
if (wantPretty) { if (wantPretty) {
@ -1360,14 +1363,15 @@ SourceScripts.prototype = {
} }
// Get the source text from the active thread. // Get the source text from the active thread.
this.activeThread.source(aSource).source(({ error, message, source: text }) => { this.activeThread.source(aSource)
.source(({ error, message, source: text, contentType }) => {
if (aOnTimeout) { if (aOnTimeout) {
window.clearTimeout(fetchTimeout); window.clearTimeout(fetchTimeout);
} }
if (error) { if (error) {
deferred.reject([aSource, message || error]); deferred.reject([aSource, message || error]);
} else { } else {
deferred.resolve([aSource, text]); deferred.resolve([aSource, text, contentType]);
} }
}); });
@ -1406,13 +1410,13 @@ SourceScripts.prototype = {
} }
/* Called if fetching a source finishes successfully. */ /* Called if fetching a source finishes successfully. */
function onFetch([aSource, aText]) { function onFetch([aSource, aText, aContentType]) {
// If fetching the source has previously timed out, discard it this time. // If fetching the source has previously timed out, discard it this time.
if (!pending.has(aSource.url)) { if (!pending.has(aSource.url)) {
return; return;
} }
pending.delete(aSource.url); pending.delete(aSource.url);
fetched.push([aSource.url, aText]); fetched.push([aSource.url, aText, aContentType]);
maybeFinish(); maybeFinish();
} }

View File

@ -388,7 +388,8 @@ let DebuggerView = {
this._setEditorText(L10N.getStr("loadingText")); this._setEditorText(L10N.getStr("loadingText"));
this._editorSource = { url: aSource.url, promise: deferred.promise }; this._editorSource = { url: aSource.url, promise: deferred.promise };
DebuggerController.SourceScripts.getText(aSource).then(([, aText]) => { DebuggerController.SourceScripts.getText(aSource)
.then(([, aText, aContentType]) => {
// Avoid setting an unexpected source. This may happen when switching // Avoid setting an unexpected source. This may happen when switching
// very fast between sources that haven't been fetched yet. // very fast between sources that haven't been fetched yet.
if (this._editorSource.url != aSource.url) { if (this._editorSource.url != aSource.url) {
@ -396,7 +397,7 @@ let DebuggerView = {
} }
this._setEditorText(aText); this._setEditorText(aText);
this._setEditorMode(aSource.url, aSource.contentType, aText); this._setEditorMode(aSource.url, aContentType, aText);
// Synchronize any other components with the currently displayed source. // Synchronize any other components with the currently displayed source.
DebuggerView.Sources.selectedValue = aSource.url; DebuggerView.Sources.selectedValue = aSource.url;
@ -406,7 +407,7 @@ let DebuggerView = {
// Resolve and notify that a source file was shown. // Resolve and notify that a source file was shown.
window.emit(EVENTS.SOURCE_SHOWN, aSource); window.emit(EVENTS.SOURCE_SHOWN, aSource);
deferred.resolve([aSource, aText]); deferred.resolve([aSource, aText, aContentType]);
}, },
([, aError]) => { ([, aError]) => {
let msg = L10N.getStr("errorLoadingText") + DevToolsUtils.safeErrorString(aError); let msg = L10N.getStr("errorLoadingText") + DevToolsUtils.safeErrorString(aError);
@ -466,10 +467,14 @@ let DebuggerView = {
// Make sure the requested source client is shown in the editor, then // Make sure the requested source client is shown in the editor, then
// update the source editor's caret position and debug location. // update the source editor's caret position and debug location.
return this._setEditorSource(sourceForm, aFlags).then(() => { return this._setEditorSource(sourceForm, aFlags)
.then(([,, aContentType]) => {
// Record the contentType learned from fetching
sourceForm.contentType = aContentType;
// Line numbers in the source editor should start from 1. If invalid // Line numbers in the source editor should start from 1. If invalid
// or not specified, then don't do anything. // or not specified, then don't do anything.
if (aLine < 1) { if (aLine < 1) {
window.emit(EVENTS.EDITOR_LOCATION_SET);
return; return;
} }
if (aFlags.charOffset) { if (aFlags.charOffset) {
@ -485,6 +490,7 @@ let DebuggerView = {
if (!aFlags.noDebug) { if (!aFlags.noDebug) {
this.editor.setDebugLocation(aLine - 1); this.editor.setDebugLocation(aLine - 1);
} }
window.emit(EVENTS.EDITOR_LOCATION_SET);
}).then(null, console.error); }).then(null, console.error);
}, },

View File

@ -28,6 +28,8 @@ support-files =
code_ugly-5.js code_ugly-5.js
code_ugly-6.js code_ugly-6.js
code_ugly-7.js code_ugly-7.js
code_ugly-8
code_ugly-8^headers^
doc_auto-pretty-print-01.html doc_auto-pretty-print-01.html
doc_auto-pretty-print-02.html doc_auto-pretty-print-02.html
doc_binary_search.html doc_binary_search.html
@ -56,6 +58,7 @@ support-files =
doc_pause-exceptions.html doc_pause-exceptions.html
doc_pretty-print.html doc_pretty-print.html
doc_pretty-print-2.html doc_pretty-print-2.html
doc_pretty-print-3.html
doc_random-javascript.html doc_random-javascript.html
doc_recursion-stack.html doc_recursion-stack.html
doc_scope-variable.html doc_scope-variable.html
@ -161,6 +164,7 @@ support-files =
[browser_dbg_pretty-print-10.js] [browser_dbg_pretty-print-10.js]
[browser_dbg_pretty-print-11.js] [browser_dbg_pretty-print-11.js]
[browser_dbg_pretty-print-12.js] [browser_dbg_pretty-print-12.js]
[browser_dbg_pretty-print-13.js]
[browser_dbg_progress-listener-bug.js] [browser_dbg_progress-listener-bug.js]
[browser_dbg_reload-preferred-script-01.js] [browser_dbg_reload-preferred-script-01.js]
[browser_dbg_reload-preferred-script-02.js] [browser_dbg_reload-preferred-script-02.js]

View File

@ -0,0 +1,87 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Make sure that clicking the pretty print button prettifies the source, even
* when the source URL does not end in ".js", but the content type is
* JavaScript.
*/
const TAB_URL = EXAMPLE_URL + "doc_pretty-print-3.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor, gSources;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
gSources = gDebugger.DebuggerView.Sources;
promise.all([waitForSourceShown(gPanel, "code_ugly-8"),
waitForEditorLocationSet(gPanel)])
.then(testSourceIsUgly)
.then(() => {
const finished = waitForSourceShown(gPanel, "code_ugly-8");
clickPrettyPrintButton();
testProgressBarShown();
return finished;
})
.then(testSourceIsPretty)
.then(testEditorShown)
.then(testSourceIsStillPretty)
.then(() => closeDebuggerAndFinish(gPanel))
.then(null, aError => {
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(aError));
});
});
}
function testSourceIsUgly() {
ok(!gEditor.getText().contains("\n "),
"The source shouldn't be pretty printed yet.");
}
function clickPrettyPrintButton() {
gDebugger.document.getElementById("pretty-print").click();
}
function testProgressBarShown() {
const deck = gDebugger.document.getElementById("editor-deck");
is(deck.selectedIndex, 2, "The progress bar should be shown");
}
function testSourceIsPretty() {
ok(gEditor.getText().contains("\n "),
"The source should be pretty printed.")
}
function testEditorShown() {
const deck = gDebugger.document.getElementById("editor-deck");
is(deck.selectedIndex, 0, "The editor should be shown");
}
function testSourceIsStillPretty() {
const deferred = promise.defer();
const { source } = gSources.selectedItem.attachment;
gDebugger.DebuggerController.SourceScripts.getText(source).then(([, text]) => {
ok(text.contains("\n "),
"Subsequent calls to getText return the pretty printed source.");
deferred.resolve();
});
return deferred.promise;
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;
gSources = null;
});

View File

@ -0,0 +1,3 @@
function foo() { var a=1; var b=2; bar(a, b); }
function bar(c, d) { debugger; }
foo();

View File

@ -0,0 +1 @@
Content-Type: application/javascript

View File

@ -0,0 +1,8 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE html>
<head>
<meta charset="utf-8"/>
<title>Debugger Pretty Printing Test Page</title>
</head>
<script src="code_ugly-8"></script>

View File

@ -236,6 +236,11 @@ function waitForSourceShown(aPanel, aUrl) {
}); });
} }
function waitForEditorLocationSet(aPanel) {
return waitForDebuggerEvents(aPanel,
aPanel.panelWin.EVENTS.EDITOR_LOCATION_SET);
}
function ensureSourceIs(aPanel, aUrl, aWaitFlag = false) { function ensureSourceIs(aPanel, aUrl, aWaitFlag = false) {
if (aPanel.panelWin.DebuggerView.Sources.selectedValue.contains(aUrl)) { if (aPanel.panelWin.DebuggerView.Sources.selectedValue.contains(aUrl)) {
ok(true, "Expected source is shown: " + aUrl); ok(true, "Expected source is shown: " + aUrl);

View File

@ -205,7 +205,8 @@ StyleEditorUI.prototype = {
// remember saved file locations // remember saved file locations
for (let editor of this.editors) { for (let editor of this.editors) {
if (editor.savedFile) { if (editor.savedFile) {
this.savedLocations[editor.styleSheet.href] = editor.savedFile; let identifier = this.getStyleSheetIdentifier(editor.styleSheet);
this.savedLocations[identifier] = editor.savedFile;
} }
} }
@ -257,7 +258,8 @@ StyleEditorUI.prototype = {
*/ */
_addStyleSheetEditor: function(styleSheet, file, isNew) { _addStyleSheetEditor: function(styleSheet, file, isNew) {
// recall location of saved file for this sheet after page reload // recall location of saved file for this sheet after page reload
let savedFile = this.savedLocations[styleSheet.href]; let identifier = this.getStyleSheetIdentifier(styleSheet);
let savedFile = this.savedLocations[identifier];
if (savedFile && !file) { if (savedFile && !file) {
file = savedFile; file = savedFile;
} }
@ -526,6 +528,18 @@ StyleEditorUI.prototype = {
return deferred.promise; return deferred.promise;
}, },
/**
* Returns an identifier for the given style sheet.
*
* @param {StyleSheet} aStyleSheet
* The style sheet to be identified.
*/
getStyleSheetIdentifier: function (aStyleSheet) {
// Identify inline style sheets by their host page URI and index at the page.
return aStyleSheet.href ? aStyleSheet.href :
"inline-" + aStyleSheet.styleSheetIndex + "-at-" + aStyleSheet.nodeHref;
},
/** /**
* selects a stylesheet and optionally moves the cursor to a selected line * selects a stylesheet and optionally moves the cursor to a selected line
* *

View File

@ -7,6 +7,8 @@ support-files =
import.css import.css
import.html import.html
import2.css import2.css
inline-1.html
inline-2.html
longload.html longload.html
media-small.css media-small.css
media.html media.html
@ -37,6 +39,7 @@ support-files =
[browser_styleeditor_import.js] [browser_styleeditor_import.js]
[browser_styleeditor_import_rule.js] [browser_styleeditor_import_rule.js]
[browser_styleeditor_init.js] [browser_styleeditor_init.js]
[browser_styleeditor_inline_friendly_names.js]
[browser_styleeditor_loading.js] [browser_styleeditor_loading.js]
[browser_styleeditor_new.js] [browser_styleeditor_new.js]
[browser_styleeditor_nostyle.js] [browser_styleeditor_nostyle.js]

View File

@ -0,0 +1,150 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
let gUI;
const FIRST_TEST_PAGE = TEST_BASE + "inline-1.html"
const SECOND_TEST_PAGE = TEST_BASE + "inline-2.html"
const SAVE_PATH = "test.css";
function test()
{
waitForExplicitFinish();
addTabAndOpenStyleEditor(function(panel) {
gUI = panel.UI;
// First test that identifiers are correcly generated. If not other tests
// are likely to fail.
testIndentifierGeneration();
waitForEditors(2)
.then(saveFirstInlineStyleSheet)
.then(testFriendlyNamesAfterSave)
.then(reloadPage)
.then(testFriendlyNamesAfterSave)
.then(navigateToAnotherPage)
.then(testFriendlyNamesAfterNavigation)
.then(finishTests);
});
content.location = FIRST_TEST_PAGE;
}
function testIndentifierGeneration() {
let fakeStyleSheetFile = {
"href": "http://example.com/test.css",
"nodeHref": "http://example.com/",
"styleSheetIndex": 1
}
let fakeInlineStyleSheet = {
"href": null,
"nodeHref": "http://example.com/",
"styleSheetIndex": 2
}
is(gUI.getStyleSheetIdentifier(fakeStyleSheetFile), "http://example.com/test.css",
"URI is the identifier of style sheet file.");
is(gUI.getStyleSheetIdentifier(fakeInlineStyleSheet), "inline-2-at-http://example.com/",
"Inline style sheets are identified by their page and position at that page.");
}
function saveFirstInlineStyleSheet() {
let deferred = promise.defer();
let editor = gUI.editors[0];
let destFile = FileUtils.getFile("ProfD", [SAVE_PATH]);
editor.saveToFile(destFile, function (file) {
ok(file, "File was correctly saved.");
deferred.resolve();
});
return deferred.promise;
}
function testFriendlyNamesAfterSave() {
let firstEditor = gUI.editors[0];
let secondEditor = gUI.editors[1];
// The friendly name of first sheet should've been remembered, the second should
// not be the same (bug 969900).
is(firstEditor.friendlyName, SAVE_PATH,
"Friendly name is correct for the saved inline style sheet.");
isnot(secondEditor.friendlyName, SAVE_PATH,
"Friendly name is for the second inline style sheet is not the same as first.");
return promise.resolve(null);
}
function reloadPage() {
info("Reloading page.");
content.location.reload();
return waitForEditors(2);
}
function navigateToAnotherPage() {
info("Navigating to another page.");
let deferred = promise.defer();
gBrowser.removeCurrentTab();
gUI = null;
addTabAndOpenStyleEditor(function(panel) {
gUI = panel.UI;
waitForEditors(2).then(deferred.resolve);
});
content.location = SECOND_TEST_PAGE;
return deferred.promise;
}
function testFriendlyNamesAfterNavigation() {
let firstEditor = gUI.editors[0];
let secondEditor = gUI.editors[1];
// Inline style sheets shouldn't have the name of previously saved file as the
// page is different.
isnot(firstEditor.friendlyName, SAVE_PATH,
"The first editor doesn't have the save path as a friendly name.");
isnot(secondEditor.friendlyName, SAVE_PATH,
"The second editor doesn't have the save path as a friendly name.");
return promise.resolve(null);
}
function finishTests() {
gUI = null;
finish();
}
/**
* Waits for all editors to be added.
*
* @param {int} aNumberOfEditors
* The number of editors to wait until proceeding.
*
* Returns a promise that's resolved once all editors are added.
*/
function waitForEditors(aNumberOfEditors) {
let deferred = promise.defer();
let count = 0;
info("Waiting for " + aNumberOfEditors + " editors to be added");
gUI.on("editor-added", function editorAdded(event, editor) {
if (++count == aNumberOfEditors) {
info("All editors added. Resolving promise.");
gUI.off("editor-added", editorAdded);
gUI.editors[0].getSourceEditor().then(deferred.resolve);
}
else {
info ("Editor " + count + " of " + aNumberOfEditors + " added.");
}
});
return deferred.promise;
}

View File

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Inline test page #1</title>
<style type="text/css">
.second {
font-size:2em;
}
</style>
<style type="text/css">
.first {
font-size:3em;
}
</style>
</head>
<body class="first">
Inline test page #1
</body>
</html>

View File

@ -0,0 +1,19 @@
<!doctype html>
<html>
<head>
<title>Inline test page #2</title>
<style type="text/css">
.second {
font-size:2em;
}
</style>
<style type="text/css">
.first {
font-size:3em;
}
</style>
</head>
<body class="second">
Inline test page #2
</body>
</html>

View File

@ -1,59 +1,71 @@
/* vim:set ts=2 sw=2 sts=2 et: */ /* This Source Code Form is subject to the terms of the Mozilla Public
/* ***** BEGIN LICENSE BLOCK ***** * License, v. 2.0. If a copy of the MPL was not distributed with this
* Any copyright is dedicated to the Public Domain. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
* http://creativecommons.org/publicdomain/zero/1.0/
*
* Contributor(s):
* Mihai Șucan <mihai.sucan@gmail.com>
*
* ***** END LICENSE BLOCK ***** */
function consoleOpened(HUD) { // Test that the console output scrolls to JS eval results when there are many
HUD.jsterm.clearOutput(); // messages displayed. See bug 601352.
let longMessage = ""; function test() {
for (let i = 0; i < 50; i++) { Task.spawn(runner).then(finishTest);
longMessage += "LongNonwrappingMessage";
}
for (let i = 0; i < 50; i++) { function* runner() {
content.console.log("test message " + i); let {tab} = yield loadTab("data:text/html;charset=utf-8,Web Console test for bug 601352");
} let hud = yield openConsole(tab);
hud.jsterm.clearOutput();
content.console.log(longMessage); let longMessage = "";
for (let i = 0; i < 50; i++) {
longMessage += "LongNonwrappingMessage";
}
for (let i = 0; i < 50; i++) { for (let i = 0; i < 50; i++) {
content.console.log("test message " + i); content.console.log("test1 message " + i);
} }
HUD.jsterm.execute("1+1", performTest); content.console.log(longMessage);
function performTest(node) { for (let i = 0; i < 50; i++) {
let scrollNode = HUD.outputNode.parentNode; content.console.log("test2 message " + i);
}
yield waitForMessages({
webconsole: hud,
messages: [{
text: "test1 message 0",
}, {
text: "test1 message 49",
}, {
text: "LongNonwrappingMessage",
}, {
text: "test2 message 0",
}, {
text: "test2 message 49",
}],
});
let nodeDeferred = promise.defer();
hud.jsterm.execute("1+1", (node) => { nodeDeferred.resolve(node); });
let node = yield nodeDeferred.promise;
let scrollNode = hud.outputNode.parentNode;
let rectNode = node.getBoundingClientRect(); let rectNode = node.getBoundingClientRect();
let rectOutput = scrollNode.getBoundingClientRect(); let rectOutput = scrollNode.getBoundingClientRect();
console.debug("rectNode", rectNode, "rectOutput", rectOutput);
console.log("scrollNode scrollHeight", scrollNode.scrollHeight, "scrollTop", scrollNode.scrollTop, "clientHeight", scrollNode.clientHeight);
isnot(scrollNode.scrollTop, 0, "scroll location is not at the top"); isnot(scrollNode.scrollTop, 0, "scroll location is not at the top");
// Visible scroll viewport. // The bounding client rect .top/left coordinates are relative to the
let height = scrollNode.scrollHeight - scrollNode.scrollTop; // console iframe.
// Top position of the last message node, relative to the outputNode. // Visible scroll viewport.
let top = rectNode.top + scrollNode.scrollTop; let height = rectOutput.height;
let bottom = top + node.clientHeight;
info("output height " + height + " node top " + top + " node bottom " + bottom + " node height " + node.clientHeight); // Top and bottom coordinates of the last message node, relative to the outputNode.
let top = rectNode.top - rectOutput.top;
let bottom = top + rectNode.height;
info("node top " + top + " node bottom " + bottom + " node clientHeight " + node.clientHeight);
ok(top >= 0 && bottom <= height, "last message is visible"); ok(top >= 0 && bottom <= height, "last message is visible");
}
finishTest();
};
} }
function test() {
addTab("data:text/html;charset=utf-8,Web Console test for bug 601352");
browser.addEventListener("load", function tabLoad(aEvent) {
browser.removeEventListener(aEvent.type, tabLoad, true);
openConsole(null, consoleOpened);
}, true);
}

View File

@ -196,7 +196,7 @@
if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) { if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
if (typeof SelectionHelperUI != 'undefined') { if (typeof SelectionHelperUI != 'undefined') {
SelectionHelperUI.attachEditSession(ChromeSelectionHandler, SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
event.clientX, event.clientY); event.clientX, event.clientY, this);
} else { } else {
// If we don't have access to SelectionHelperUI then we are using this // If we don't have access to SelectionHelperUI then we are using this
// binding for browser content (e.g. about:config) // binding for browser content (e.g. about:config)
@ -295,7 +295,7 @@
if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) { if (event.mozInputSource == Ci.nsIDOMMouseEvent.MOZ_SOURCE_TOUCH) {
if (typeof SelectionHelperUI != 'undefined') { if (typeof SelectionHelperUI != 'undefined') {
SelectionHelperUI.attachEditSession(ChromeSelectionHandler, SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
event.clientX, event.clientY); event.clientX, event.clientY, this);
} else { } else {
// If we don't have access to SelectionHelperUI then we are using this // If we don't have access to SelectionHelperUI then we are using this
// binding for browser content (e.g. about:config) // binding for browser content (e.g. about:config)

View File

@ -292,6 +292,12 @@
if (aShouldDismiss) if (aShouldDismiss)
ContextUI.dismissTabs(); ContextUI.dismissTabs();
if (!InputSourceHelper.isPrecise && this.textLength) {
let inputRectangle = this.inputField.getBoundingClientRect();
SelectionHelperUI.attachEditSession(ChromeSelectionHandler,
inputRectangle.left, inputRectangle.top, this);
}
]]> ]]>
</body> </body>
</method> </method>
@ -448,6 +454,15 @@
<handler event="click" phase="capturing"> <handler event="click" phase="capturing">
<![CDATA[ <![CDATA[
// workaround for bug 925457: taping browser chrome resets last tap
// co-ordinates to 'undefined' so that we know not to shift the
// browser when the keyboard is up in SelectionHandler's
// _calcNewContentPosition().
Browser.selectedTab.browser.messageManager.sendAsyncMessage(
"Browser:ResetLastPos", {
xPos: null,
yPos: null
});
this.beginEditing(true); this.beginEditing(true);
]]> ]]>
</handler> </handler>

View File

@ -482,8 +482,7 @@ Desktop browser's sync prefs.
autocompletepopup="urlbar-autocomplete" autocompletepopup="urlbar-autocomplete"
completeselectedindex="true" completeselectedindex="true"
placeholder="&urlbar.emptytext;" placeholder="&urlbar.emptytext;"
tabscrolling="true" tabscrolling="true" />
onclick="SelectionHelperUI.urlbarTextboxClick(this);"/>
<toolbarbutton id="go-button" <toolbarbutton id="go-button"
class="urlbar-button" class="urlbar-button"

View File

@ -33,7 +33,7 @@ var ChromeSelectionHandler = {
_onSelectionAttach: function _onSelectionAttach(aJson) { _onSelectionAttach: function _onSelectionAttach(aJson) {
this._domWinUtils = Util.getWindowUtils(window); this._domWinUtils = Util.getWindowUtils(window);
this._contentWindow = window; this._contentWindow = window;
this._targetElement = this._domWinUtils.elementFromPoint(aJson.xPos, aJson.yPos, true, false); this._targetElement = aJson.target;
this._targetIsEditable = this._targetElement instanceof Components.interfaces.nsIDOMXULTextBoxElement; this._targetIsEditable = this._targetElement instanceof Components.interfaces.nsIDOMXULTextBoxElement;
if (!this._targetIsEditable) { if (!this._targetIsEditable) {
this._onFail("not an editable?", this._targetElement); this._onFail("not an editable?", this._targetElement);

View File

@ -435,10 +435,12 @@ var SelectionHelperUI = {
* *
* Attaches to existing selection and begins editing. * Attaches to existing selection and begins editing.
* *
* @param aMsgTarget - Browser or chrome message target * @param aMsgTarget - Browser or chrome message target.
* @param aX, aY - Browser relative client coordinates. * @param aX Tap browser relative client X coordinate.
* @param aY Tap browser relative client Y coordinate.
* @param aTarget Actual tap target (optional).
*/ */
attachEditSession: function attachEditSession(aMsgTarget, aX, aY) { attachEditSession: function attachEditSession(aMsgTarget, aX, aY, aTarget) {
if (!aMsgTarget || this.isActive) if (!aMsgTarget || this.isActive)
return; return;
this._init(aMsgTarget); this._init(aMsgTarget);
@ -448,6 +450,7 @@ var SelectionHelperUI = {
// back with information on the current selection. SelectionAttach // back with information on the current selection. SelectionAttach
// takes client coordinates. // takes client coordinates.
this._sendAsyncMessage("Browser:SelectionAttach", { this._sendAsyncMessage("Browser:SelectionAttach", {
target: aTarget,
xPos: aX, xPos: aX,
yPos: aY yPos: aY
}); });
@ -464,11 +467,12 @@ var SelectionHelperUI = {
* Once the user starts a drag, the caret marker is hidden, and * Once the user starts a drag, the caret marker is hidden, and
* the start and end markers take over. * the start and end markers take over.
* *
* @param aMsgTarget - Browser or chrome message target * @param aMsgTarget - Browser or chrome message target.
* @param aX, aY - Browser relative client coordinates of the tap * @param aX Tap browser relative client X coordinate.
* that initiated the session. * @param aY Tap browser relative client Y coordinate.
* @param aTarget Actual tap target (optional).
*/ */
attachToCaret: function attachToCaret(aMsgTarget, aX, aY) { attachToCaret: function attachToCaret(aMsgTarget, aX, aY, aTarget) {
if (!this.isActive) { if (!this.isActive) {
this._init(aMsgTarget); this._init(aMsgTarget);
this._setupDebugOptions(); this._setupDebugOptions();
@ -476,9 +480,14 @@ var SelectionHelperUI = {
this._hideMonocles(); this._hideMonocles();
} }
this._lastPoint = { xPos: aX, yPos: aY }; this._lastCaretAttachment = {
target: aTarget,
xPos: aX,
yPos: aY
};
this._sendAsyncMessage("Browser:CaretAttach", { this._sendAsyncMessage("Browser:CaretAttach", {
target: aTarget,
xPos: aX, xPos: aX,
yPos: aY yPos: aY
}); });
@ -516,38 +525,14 @@ var SelectionHelperUI = {
}); });
}, },
/*
* Event handler on the navbar text input. Called from navbar bindings
* when focus is applied to the edit.
*/
urlbarTextboxClick: function(aEdit) {
// workaround for bug 925457: taping browser chrome resets last tap
// co-ordinates to 'undefined' so that we know not to shift the browser
// when the keyboard is up in SelectionHandler's _calcNewContentPosition().
Browser.selectedTab.browser.messageManager.sendAsyncMessage("Browser:ResetLastPos", {
xPos: null,
yPos: null
});
if (InputSourceHelper.isPrecise || !aEdit.textLength) {
return;
}
// Enable selection when there's text in the control
let innerRect = aEdit.inputField.getBoundingClientRect();
this.attachEditSession(ChromeSelectionHandler,
innerRect.left,
innerRect.top);
},
/* /*
* Click handler for chrome pages loaded into the browser (about:config). * Click handler for chrome pages loaded into the browser (about:config).
* Called from the text input bindings via the attach_edit_session_to_content * Called from the text input bindings via the attach_edit_session_to_content
* observer. * observer.
*/ */
chromeTextboxClick: function (aEvent) { chromeTextboxClick: function (aEvent) {
this.attachEditSession(Browser.selectedTab.browser, this.attachEditSession(Browser.selectedTab.browser, aEvent.clientX,
aEvent.clientX, aEvent.clientY); aEvent.clientY, aEvent.target);
}, },
/* /*
@ -875,12 +860,13 @@ var SelectionHelperUI = {
/* /*
* Handles taps that move the current caret around in text edits, * Handles taps that move the current caret around in text edits,
* clear active selection and focus when neccessary, or change * clear active selection and focus when necessary, or change
* modes. Only active afer SelectionHandlerUI is initialized. * modes. Only active after SelectionHandlerUI is initialized.
*/ */
_onClick: function(aEvent) { _onClick: function(aEvent) {
if (this.layerMode == kChromeLayer && this._targetIsEditable) { if (this.layerMode == kChromeLayer && this._targetIsEditable) {
this.attachToCaret(this._msgTarget, aEvent.clientX, aEvent.clientY); this.attachToCaret(this._msgTarget, aEvent.clientX, aEvent.clientY,
aEvent.target);
} }
}, },
@ -909,7 +895,8 @@ var SelectionHelperUI = {
*/ */
_onDeckOffsetChanged: function _onDeckOffsetChanged(aEvent) { _onDeckOffsetChanged: function _onDeckOffsetChanged(aEvent) {
// Update the monocle position and display // Update the monocle position and display
this.attachToCaret(null, this._lastPoint.xPos, this._lastPoint.yPos); this.attachToCaret(null, this._lastCaretAttachment.xPos,
this._lastCaretAttachment.yPos, this._lastCaretAttachment.target);
}, },
/* /*

View File

@ -107,7 +107,8 @@ gTests.push({
let autocompletePopup = document.getElementById("urlbar-autocomplete-scroll"); let autocompletePopup = document.getElementById("urlbar-autocomplete-scroll");
yield waitForEvent(autocompletePopup, "transitionend"); yield waitForEvent(autocompletePopup, "transitionend");
SelectionHelperUI.attachEditSession(ChromeSelectionHandler, editCoords.x, editCoords.y); SelectionHelperUI.attachEditSession(ChromeSelectionHandler, editCoords.x,
editCoords.y, edit);
ok(SelectionHelperUI.isSelectionUIVisible, "selection enabled"); ok(SelectionHelperUI.isSelectionUIVisible, "selection enabled");
let selection = edit.QueryInterface(Components.interfaces.nsIDOMXULTextBoxElement) let selection = edit.QueryInterface(Components.interfaces.nsIDOMXULTextBoxElement)
@ -136,7 +137,8 @@ gTests.push({
edit.value = "wikipedia.org"; edit.value = "wikipedia.org";
edit.select(); edit.select();
let editCoords = logicalCoordsForElement(edit); let editCoords = logicalCoordsForElement(edit);
SelectionHelperUI.attachEditSession(ChromeSelectionHandler, editCoords.x, editCoords.y); SelectionHelperUI.attachEditSession(ChromeSelectionHandler, editCoords.x,
editCoords.y, edit);
edit.blur(); edit.blur();
ok(!SelectionHelperUI.isSelectionUIVisible, "selection no longer enabled"); ok(!SelectionHelperUI.isSelectionUIVisible, "selection no longer enabled");
clearSelection(edit); clearSelection(edit);
@ -228,6 +230,26 @@ gTests.push({
} }
}); });
gTests.push({
desc: "Bug 957646 - Selection monocles sometimes don't display when tapping" +
" text ion the nav bar.",
run: function() {
yield showNavBar();
let edit = document.getElementById("urlbar-edit");
edit.value = "about:mozilla";
let editRectangle = edit.getBoundingClientRect();
// Tap outside the input but close enough for fluffing to take effect.
sendTap(window, editRectangle.left + 50, editRectangle.top - 2);
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
});
}
});
function test() { function test() {
if (!isLandscapeMode()) { if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run."); todo(false, "browser_selection_tests need landscape mode to run.");

View File

@ -26,3 +26,41 @@ gTests.push({
ok(simpleMeasurements.UITelemetry["metro-ui"]["window-height"], "window-height measurement was captured"); ok(simpleMeasurements.UITelemetry["metro-ui"]["window-height"], "window-height measurement was captured");
} }
}); });
gTests.push({
desc: "Test tab count telemetry",
run: function() {
// Wait for Session Manager to be initialized.
yield waitForCondition(() => window.__SSID);
Services.obs.notifyObservers(null, "reset-telemetry-vars", null);
yield waitForCondition(function () {
let simpleMeasurements = getTelemetryPayload().simpleMeasurements;
return simpleMeasurements.UITelemetry["metro-tabs"]["currTabCount"] == 1;
});
let simpleMeasurements = getTelemetryPayload().simpleMeasurements;
is(simpleMeasurements.UITelemetry["metro-tabs"]["currTabCount"], 1);
is(simpleMeasurements.UITelemetry["metro-tabs"]["maxTabCount"], 1);
let tab2 = Browser.addTab("about:mozilla");
simpleMeasurements = getTelemetryPayload().simpleMeasurements;
is(simpleMeasurements.UITelemetry["metro-tabs"]["currTabCount"], 2);
is(simpleMeasurements.UITelemetry["metro-tabs"]["maxTabCount"], 2);
let tab3 = Browser.addTab("about:config");
simpleMeasurements = getTelemetryPayload().simpleMeasurements;
is(simpleMeasurements.UITelemetry["metro-tabs"]["currTabCount"], 3);
is(simpleMeasurements.UITelemetry["metro-tabs"]["maxTabCount"], 3);
Browser.closeTab(tab2, { forceClose: true } );
simpleMeasurements = getTelemetryPayload().simpleMeasurements;
is(simpleMeasurements.UITelemetry["metro-tabs"]["currTabCount"], 2);
is(simpleMeasurements.UITelemetry["metro-tabs"]["maxTabCount"], 3);
Browser.closeTab(tab3, { forceClose: true } );
simpleMeasurements = getTelemetryPayload().simpleMeasurements;
is(simpleMeasurements.UITelemetry["metro-tabs"]["currTabCount"], 1);
is(simpleMeasurements.UITelemetry["metro-tabs"]["maxTabCount"], 3);
}
});

View File

@ -24,6 +24,9 @@ XPCOMUtils.defineLazyGetter(this, "NetUtil", function() {
return NetUtil; return NetUtil;
}); });
XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
"resource://gre/modules/UITelemetry.jsm");
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Session Store // Session Store
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -52,6 +55,9 @@ SessionStore.prototype = {
_maxTabsUndo: 1, _maxTabsUndo: 1,
_shouldRestore: false, _shouldRestore: false,
// Tab telemetry variables
_maxTabsOpen: 1,
init: function ss_init() { init: function ss_init() {
// Get file references // Get file references
this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile); this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
@ -63,6 +69,13 @@ SessionStore.prototype = {
this._loadState = STATE_STOPPED; this._loadState = STATE_STOPPED;
try {
UITelemetry.addSimpleMeasureFunction("metro-tabs",
this._getTabStats.bind(this));
} catch (ex) {
// swallow exception that occurs if metro-tabs measure is already set up
}
try { try {
let shutdownWasUnclean = false; let shutdownWasUnclean = false;
@ -184,6 +197,13 @@ SessionStore.prototype = {
}) })
}, },
_getTabStats: function() {
return {
currTabCount: this._currTabCount,
maxTabCount: this._maxTabsOpen
};
},
observe: function ss_observe(aSubject, aTopic, aData) { observe: function ss_observe(aSubject, aTopic, aData) {
let self = this; let self = this;
let observerService = Services.obs; let observerService = Services.obs;
@ -197,6 +217,7 @@ SessionStore.prototype = {
observerService.addObserver(this, "quit-application-requested", true); observerService.addObserver(this, "quit-application-requested", true);
observerService.addObserver(this, "quit-application-granted", true); observerService.addObserver(this, "quit-application-granted", true);
observerService.addObserver(this, "quit-application", true); observerService.addObserver(this, "quit-application", true);
observerService.addObserver(this, "reset-telemetry-vars", true);
break; break;
case "final-ui-startup": case "final-ui-startup":
observerService.removeObserver(this, "final-ui-startup"); observerService.removeObserver(this, "final-ui-startup");
@ -264,6 +285,7 @@ SessionStore.prototype = {
observerService.removeObserver(this, "quit-application-requested"); observerService.removeObserver(this, "quit-application-requested");
observerService.removeObserver(this, "quit-application-granted"); observerService.removeObserver(this, "quit-application-granted");
observerService.removeObserver(this, "quit-application"); observerService.removeObserver(this, "quit-application");
observerService.removeObserver(this, "reset-telemetry-vars");
// If a save has been queued, kill the timer and save state now // If a save has been queued, kill the timer and save state now
if (this._saveTimer) { if (this._saveTimer) {
@ -295,13 +317,24 @@ SessionStore.prototype = {
this._saveTimer = null; this._saveTimer = null;
this.saveState(); this.saveState();
break; break;
case "reset-telemetry-vars":
// Used in mochitests only.
this._maxTabsOpen = 1;
} }
}, },
updateTabTelemetryVars: function(window) {
this._currTabCount = window.Browser.tabs.length;
if (this._currTabCount > this._maxTabsOpen) {
this._maxTabsOpen = this._currTabCount;
}
},
handleEvent: function ss_handleEvent(aEvent) { handleEvent: function ss_handleEvent(aEvent) {
let window = aEvent.currentTarget.ownerDocument.defaultView; let window = aEvent.currentTarget.ownerDocument.defaultView;
switch (aEvent.type) { switch (aEvent.type) {
case "TabOpen": case "TabOpen":
this.updateTabTelemetryVars(window);
case "TabClose": { case "TabClose": {
let browser = aEvent.originalTarget.linkedBrowser; let browser = aEvent.originalTarget.linkedBrowser;
if (aEvent.type == "TabOpen") { if (aEvent.type == "TabOpen") {
@ -313,6 +346,9 @@ SessionStore.prototype = {
} }
break; break;
} }
case "TabRemove":
this.updateTabTelemetryVars(window);
break;
case "TabSelect": { case "TabSelect": {
let browser = aEvent.originalTarget.linkedBrowser; let browser = aEvent.originalTarget.linkedBrowser;
this.onTabSelect(window, browser); this.onTabSelect(window, browser);
@ -361,6 +397,7 @@ SessionStore.prototype = {
let tabContainer = aWindow.document.getElementById("tabs"); let tabContainer = aWindow.document.getElementById("tabs");
tabContainer.addEventListener("TabOpen", this, true); tabContainer.addEventListener("TabOpen", this, true);
tabContainer.addEventListener("TabClose", this, true); tabContainer.addEventListener("TabClose", this, true);
tabContainer.addEventListener("TabRemove", this, true);
tabContainer.addEventListener("TabSelect", this, true); tabContainer.addEventListener("TabSelect", this, true);
}, },
@ -372,6 +409,7 @@ SessionStore.prototype = {
let tabContainer = aWindow.document.getElementById("tabs"); let tabContainer = aWindow.document.getElementById("tabs");
tabContainer.removeEventListener("TabOpen", this, true); tabContainer.removeEventListener("TabOpen", this, true);
tabContainer.removeEventListener("TabClose", this, true); tabContainer.removeEventListener("TabClose", this, true);
tabContainer.removeEventListener("TabRemove", this, true);
tabContainer.removeEventListener("TabSelect", this, true); tabContainer.removeEventListener("TabSelect", this, true);
if (this._loadState == STATE_RUNNING) { if (this._loadState == STATE_RUNNING) {

View File

@ -640,10 +640,12 @@ tabmodalprompt:not([promptType="promptUserAndPass"]) .infoContainer {
.meta { .meta {
background-color: @panel_light_color@; background-color: @panel_light_color@;
/* bug 969354
background-image: url("chrome://browser/skin/images/firefox-watermark.png"); background-image: url("chrome://browser/skin/images/firefox-watermark.png");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center center; background-position: center center;
background-attachment: fixed; background-attachment: fixed;
*/
} }
/* needs to observe the viewstate */ /* needs to observe the viewstate */

View File

@ -560,6 +560,11 @@ menuitem:not([type]):not(.menuitem-tooltip):not(.menuitem-iconic-tooltip) {
-moz-appearance: none; -moz-appearance: none;
} }
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1[open="true"],
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1:hover:active {
padding: 3px;
}
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon, :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon, :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon,
:-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-icon { :-moz-any(#TabsToolbar, #nav-bar) .toolbarbutton-1 > .toolbarbutton-icon {

View File

@ -41,7 +41,8 @@ body {
} }
.property-name { .property-name {
width: 50%; /* -12px is so the expander triangle isn't pushed up above the property */
width: calc(100% - 12px);
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -49,8 +50,7 @@ body {
} }
.property-value { .property-value {
width: 50%; width: 100%;
max-width: 100%;
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -75,7 +75,8 @@ body {
width: 200px; width: 200px;
} }
.property-value { .property-value {
width: auto; /* -212px is accounting for the 200px property-name and the 12px triangle */
width: calc(100% - 212px);
} }
} }

View File

@ -22,6 +22,8 @@
#downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon { #downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon {
background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), background: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"),
0, 198, 18, 180) center no-repeat; 0, 198, 18, 180) center no-repeat;
min-width: 18px;
min-height: 18px;
} }
#downloads-button[cui-areatype="toolbar"][attention] > #downloads-indicator-anchor > #downloads-indicator-icon { #downloads-button[cui-areatype="toolbar"][attention] > #downloads-indicator-anchor > #downloads-indicator-icon {

View File

@ -2573,24 +2573,13 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png); url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png);
} }
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
.tabs-newtab-button:hover { .tabs-newtab-button:hover {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png), background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png),
url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png), url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png),
url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png); url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png);
} }
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-middle:not([selected=true]) {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-middle@2x.png);
}
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-start:not([selected=true]) {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-start@2x.png);
}
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-end:not([selected=true]) {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-end@2x.png);
}
.tab-background-middle[selected=true] { .tab-background-middle[selected=true] {
background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png), background-image: url(chrome://browser/skin/tabbrowser/tab-active-middle@2x.png),
@fgTabTexture@, @fgTabTexture@,
@ -4125,6 +4114,10 @@ window > chatbox {
margin-bottom: 0px; margin-bottom: 0px;
} }
#main-window:not([tabsintitlebar]):-moz-lwtheme > #titlebar {
margin-bottom: 5px;
}
#main-window[tabsintitlebar]:-moz-lwtheme > #titlebar > #titlebar-content { #main-window[tabsintitlebar]:-moz-lwtheme > #titlebar > #titlebar-content {
margin-top: 11px; margin-top: 11px;
margin-bottom: 11px; margin-bottom: 11px;

View File

@ -59,7 +59,8 @@ body {
} }
.property-name { .property-name {
width: 50%; /* -12px is so the expander triangle isn't pushed up above the property */
width: calc(100% - 12px);
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -67,8 +68,7 @@ body {
} }
.property-value { .property-value {
width: 50%; width: 100%;
max-width: 100%;
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -93,7 +93,8 @@ body {
width: 200px; width: 200px;
} }
.property-value { .property-value {
width: auto; /* -212px is accounting for the 200px property-name and the 12px triangle */
width: calc(100% - 212px);
} }
} }

View File

@ -494,15 +494,15 @@ box.requests-menu-status {
/* Footer */ /* Footer */
#requests-menu-footer {
border-top: solid 1px hsla(210,5%,5%,.3);
}
.theme-dark #requests-menu-footer { .theme-dark #requests-menu-footer {
border-top: 1px solid @table_itemDarkStartBorder@;
box-shadow: 0 1px 0 @table_itemDarkEndBorder@ inset;
background: url(background-noise-toolbar.png), #343c45; /* Toolbars */ background: url(background-noise-toolbar.png), #343c45; /* Toolbars */
} }
.theme-light #requests-menu-footer { .theme-light #requests-menu-footer {
border-top: 1px solid @table_itemLightStartBorder@;
box-shadow: 0 1px 0 @table_itemLightEndBorder@ inset;
background: url(background-noise-toolbar.png), #f0f1f2; /* Toolbars */ background: url(background-noise-toolbar.png), #f0f1f2; /* Toolbars */
} }
@ -530,14 +530,14 @@ box.requests-menu-status {
.theme-dark .requests-menu-footer-spacer:not(:first-child), .theme-dark .requests-menu-footer-spacer:not(:first-child),
.theme-dark .requests-menu-footer-button:not(:first-child) { .theme-dark .requests-menu-footer-button:not(:first-child) {
-moz-border-start: 1px solid @table_itemDarkStartBorder@; -moz-border-start: 1px solid @table_itemDarkEndBorder@;
box-shadow: -1px 0 0 @table_itemDarkEndBorder@; box-shadow: -1px 0 0 @table_itemDarkStartBorder@;
} }
.theme-light .requests-menu-footer-spacer:not(:first-child), .theme-light .requests-menu-footer-spacer:not(:first-child),
.theme-light .requests-menu-footer-button:not(:first-child) { .theme-light .requests-menu-footer-button:not(:first-child) {
-moz-border-start: 1px solid @table_itemLightStartBorder@; -moz-border-start: 1px solid @table_itemLightEndBorder@;
box-shadow: -1px 0 0 @table_itemLightEndBorder@; box-shadow: -1px 0 0 @table_itemLightStartBorder@;
} }
.requests-menu-footer-button { .requests-menu-footer-button {
@ -546,18 +546,25 @@ box.requests-menu-status {
} }
.requests-menu-footer-button:hover { .requests-menu-footer-button:hover {
background: rgba(0,0,0,0.20); background: rgba(0,0,0,0.10);
} }
.requests-menu-footer-button:hover:active { .theme-dark .requests-menu-footer-button:hover:active {
background: rgba(0,0,0,0.35); background-color: rgba(29,79,115,0.4); /* Select Highlight Blue at 40% opacity */
} }
.requests-menu-footer-button:not(:active)[checked] { .theme-light .requests-menu-footer-button:hover:active {
background-color: rgba(0,0,0,0.25); background-color: rgba(76,158,217,0.4); /* Select Highlight Blue at 40% opacity */
background-image: radial-gradient(farthest-side at center top, hsla(200,100%,70%,.7), hsla(200,100%,70%,0.3)); }
background-size: 100% 1px;
background-repeat: no-repeat; .theme-dark .requests-menu-footer-button:not(:active)[checked] {
background-color: rgba(29,79,115,1); /* Select Highlight Blue */
color: rgba(245,247,250,1); /* Light foreground text */
}
.theme-light .requests-menu-footer-button:not(:active)[checked] {
background-color: rgba(76,158,217,1); /* Select Highlight Blue */
color: rgba(245,247,250,1); /* Light foreground text */
} }
.requests-menu-footer-label { .requests-menu-footer-label {

View File

@ -393,6 +393,10 @@
background-image: linear-gradient(transparent, transparent), @smallSeparatorDark@; background-image: linear-gradient(transparent, transparent), @smallSeparatorDark@;
} }
.theme-dark .devtools-sidebar-tabs > tabs > tab:hover {
background-image: linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.2)), @smallSeparatorDark@;
}
.theme-dark .devtools-sidebar-tabs > tabs > tab:hover:active { .theme-dark .devtools-sidebar-tabs > tabs > tab:hover:active {
background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @smallSeparatorDark@; background-image: linear-gradient(hsla(206,37%,4%,.4), hsla(206,37%,4%,.4)), @smallSeparatorDark@;
} }

View File

@ -224,6 +224,7 @@
/* End selected tab */ /* End selected tab */
/* new tab button border and gradient on hover */ /* new tab button border and gradient on hover */
.tabbrowser-tab:hover > .tab-stack > .tab-background:not([selected=true]),
.tabs-newtab-button:hover { .tabs-newtab-button:hover {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-start.png), background-image: url(chrome://browser/skin/tabbrowser/tab-background-start.png),
url(chrome://browser/skin/tabbrowser/tab-background-middle.png), url(chrome://browser/skin/tabbrowser/tab-background-middle.png),
@ -233,27 +234,6 @@
background-size: @tabCurveWidth@ 100%, calc(100% - (2 * @tabCurveWidth@)) 100%, @tabCurveWidth@ 100%; background-size: @tabCurveWidth@ 100%, calc(100% - (2 * @tabCurveWidth@)) 100%, @tabCurveWidth@ 100%;
} }
/* normal tab border and gradient on hover */
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-middle:not([selected=true]) {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-middle.png);
background-repeat: repeat-x;
background-size: auto 100%;
}
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-start:not([selected=true]),
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-end:not([selected=true]) {
background-repeat: no-repeat;
background-size: 100% 100%;
}
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-start:not([selected=true]) {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-start.png);
}
.tabbrowser-tab:hover > .tab-stack > .tab-background > .tab-background-end:not([selected=true]) {
background-image: url(chrome://browser/skin/tabbrowser/tab-background-end.png);
}
/* Tab pointer-events */ /* Tab pointer-events */
.tabbrowser-tab { .tabbrowser-tab {
pointer-events: none; pointer-events: none;

View File

@ -59,7 +59,8 @@ body {
} }
.property-name { .property-name {
width: 50%; /* -12px is so the expander triangle isn't pushed up above the property */
width: calc(100% - 12px);
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -67,8 +68,7 @@ body {
} }
.property-value { .property-value {
width: 50%; width: 100%;
max-width: 100%;
overflow-x: hidden; overflow-x: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
@ -93,7 +93,8 @@ body {
width: 200px; width: 200px;
} }
.property-value { .property-value {
width: auto; /* -212px is accounting for the 200px property-name and the 12px triangle */
width: calc(100% - 212px);
} }
} }

View File

@ -140,11 +140,9 @@ class B2GRemoteAutomation(Automation):
output. output.
""" """
timeout = timeout or 120 timeout = timeout or 120
responseDueBy = time.time() + timeout
while True: while True:
currentlog = proc.stdout currentlog = proc.getStdoutLines(timeout)
if currentlog: if currentlog:
responseDueBy = time.time() + timeout
print currentlog print currentlog
# Match the test filepath from the last TEST-START line found in the new # Match the test filepath from the last TEST-START line found in the new
# log content. These lines are in the form: # log content. These lines are in the form:
@ -155,11 +153,10 @@ class B2GRemoteAutomation(Automation):
if hasattr(self, 'logFinish') and self.logFinish in currentlog: if hasattr(self, 'logFinish') and self.logFinish in currentlog:
return 0 return 0
else: else:
if time.time() > responseDueBy: self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed "
self.log.info("TEST-UNEXPECTED-FAIL | %s | application timed " "out after %d seconds with no output",
"out after %d seconds with no output", self.lastTestSeen, int(timeout))
self.lastTestSeen, int(timeout)) return 1
return 1
def getDeviceStatus(self, serial=None): def getDeviceStatus(self, serial=None):
# Get the current status of the device. If we know the device # Get the current status of the device. If we know the device
@ -329,16 +326,22 @@ class B2GRemoteAutomation(Automation):
# a dummy value to make the automation happy # a dummy value to make the automation happy
return 0 return 0
@property def getStdoutLines(self, timeout):
def stdout(self):
# Return any lines in the queue used by the # Return any lines in the queue used by the
# b2g process handler. # b2g process handler.
lines = [] lines = []
# get all of the lines that are currently available
while True: while True:
try: try:
lines.append(self.queue.get_nowait()) lines.append(self.queue.get_nowait())
except Queue.Empty: except Queue.Empty:
break break
# wait 'timeout' for any additional lines
try:
lines.append(self.queue.get(True, timeout))
except Queue.Empty:
pass
return '\n'.join(lines) return '\n'.join(lines)
def wait(self, timeout=None): def wait(self, timeout=None):

View File

@ -12,10 +12,10 @@ public interface Driver {
* Find the first Element using the given method. * Find the first Element using the given method.
* *
* @param activity The activity the element belongs to * @param activity The activity the element belongs to
* @param name The name of the element * @param id The resource id of the element
* @return The first matching element on the current context, or null if not found. * @return The first matching element on the current context, or null if not found.
*/ */
Element findElement(Activity activity, String name); Element findElement(Activity activity, int id);
/** /**
* Sets up scroll handling so that data is received from the extension. * Sets up scroll handling so that data is received from the extension.

View File

@ -16,16 +16,13 @@ import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.IntBuffer; import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import android.app.Activity; import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.view.View; import android.view.View;
import android.util.Log; import android.util.Log;
@ -36,8 +33,6 @@ import com.jayway.android.robotium.solo.Solo;
public class FennecNativeDriver implements Driver { public class FennecNativeDriver implements Driver {
private static final int FRAME_TIME_THRESHOLD = 25; // allow 25ms per frame (40fps) private static final int FRAME_TIME_THRESHOLD = 25; // allow 25ms per frame (40fps)
// Map of IDs to element names.
private HashMap mLocators = null;
private Activity mActivity; private Activity mActivity;
private Solo mSolo; private Solo mSolo;
private String mRootPath; private String mRootPath;
@ -67,9 +62,6 @@ public class FennecNativeDriver implements Driver {
mActivity = activity; mActivity = activity;
mSolo = robocop; mSolo = robocop;
mRootPath = rootPath; mRootPath = rootPath;
// Set up table of fennec_ids.
mLocators = convertTextToTable(getFile(mRootPath + "/fennec_ids.txt"));
} }
//Information on the location of the Gecko Frame. //Information on the location of the Gecko Frame.
@ -80,7 +72,7 @@ public class FennecNativeDriver implements Driver {
private int mGeckoWidth = 1024; private int mGeckoWidth = 1024;
private void getGeckoInfo() { private void getGeckoInfo() {
View geckoLayout = mActivity.findViewById(Integer.decode((String)mLocators.get("gecko_layout"))); View geckoLayout = mActivity.findViewById(R.id.gecko_layout);
if (geckoLayout != null) { if (geckoLayout != null) {
int[] pos = new int[2]; int[] pos = new int[2];
geckoLayout.getLocationOnScreen(pos); geckoLayout.getLocationOnScreen(pos);
@ -122,21 +114,12 @@ public class FennecNativeDriver implements Driver {
return mGeckoWidth; return mGeckoWidth;
} }
/** Find the named element in the list of known Fennec views. /** Find the element with given id.
*
* @return An Element representing the view, or null if the view is not found. * @return An Element representing the view, or null if the view is not found.
*/ */
public Element findElement(Activity activity, String name) { public Element findElement(Activity activity, int id) {
if (name == null) { return new FennecNativeElement(id, activity);
FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR,
"Can not findElements when passed a null");
return null;
}
if (mLocators.containsKey(name)) {
return new FennecNativeElement(Integer.decode((String)mLocators.get(name)), activity, mSolo);
}
FennecNativeDriver.log(FennecNativeDriver.LogLevel.ERROR,
"findElement: Element '"+name+"' does not exist in the list");
return null;
} }
public void startFrameRecording() { public void startFrameRecording() {

View File

@ -7,26 +7,17 @@ package org.mozilla.gecko;
import android.app.Activity; import android.app.Activity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextSwitcher; import android.widget.TextSwitcher;
import android.app.Instrumentation; import android.widget.TextView;
import com.jayway.android.robotium.solo.Solo;
import java.util.List;
public class FennecNativeElement implements Element { public class FennecNativeElement implements Element {
private final Activity mActivity; private final Activity mActivity;
private Integer mId; private Integer mId;
private Solo mSolo;
// max time to wait for thread synchronization
private static final int MAX_WAIT_MS = 60000;
public FennecNativeElement(Integer id, Activity activity, Solo solo) { public FennecNativeElement(Integer id, Activity activity) {
mId = id; mId = id;
mActivity = activity; mActivity = activity;
mSolo = solo;
} }
public Integer getId() { public Integer getId() {

View File

@ -83,9 +83,17 @@ ifdef JAVA_JAR_TARGETS #{
# Arg 3: List of extra jars to link against. We do not use VPATH so # Arg 3: List of extra jars to link against. We do not use VPATH so
# jars must be relative to $(CURDIR). # jars must be relative to $(CURDIR).
# Arg 4: Additional JAVAC_FLAGS. # Arg 4: Additional JAVAC_FLAGS.
# Note: Proguard fails when stale .class files corresponding to
# removed inner classes are present in the object directory. These
# stale class files get packaged into the .jar file, which then gets
# processed by Proguard. To work around this, we always delete any
# existing jarfile-classes directory and start fresh.
define java_jar_template define java_jar_template
$(1): $(2) $(3) $(1): $(2) $(3)
$$(REPORT_BUILD) $$(REPORT_BUILD)
@$$(RM) -rf $(1:.jar=)-classes
@$$(NSINSTALL) -D $(1:.jar=)-classes @$$(NSINSTALL) -D $(1:.jar=)-classes
@$$(if $$(filter-out .,$$(@D)),$$(NSINSTALL) -D $$(@D)) @$$(if $$(filter-out .,$$(@D)),$$(NSINSTALL) -D $$(@D))
$$(JAVAC) $$(JAVAC_FLAGS)\ $$(JAVAC) $$(JAVAC_FLAGS)\

View File

@ -29,7 +29,6 @@
#include "nsIDOMClassInfo.h" #include "nsIDOMClassInfo.h"
#include "nsIDOMFile.h" #include "nsIDOMFile.h"
#include "xpcpublic.h" #include "xpcpublic.h"
#include "mozilla/Debug.h"
#include "mozilla/Preferences.h" #include "mozilla/Preferences.h"
#include "mozilla/dom/StructuredCloneUtils.h" #include "mozilla/dom/StructuredCloneUtils.h"
#include "JavaScriptChild.h" #include "JavaScriptChild.h"
@ -38,6 +37,9 @@
#include "nsPrintfCString.h" #include "nsPrintfCString.h"
#include <algorithm> #include <algorithm>
#ifdef ANDROID
#include <android/log.h>
#endif
#ifdef XP_WIN #ifdef XP_WIN
#include <windows.h> #include <windows.h>
# if defined(SendMessage) # if defined(SendMessage)
@ -721,7 +723,16 @@ nsFrameMessageManager::GetChildAt(uint32_t aIndex,
NS_IMETHODIMP NS_IMETHODIMP
nsFrameMessageManager::Dump(const nsAString& aStr) nsFrameMessageManager::Dump(const nsAString& aStr)
{ {
PrintToDebugger(aStr, stdout); #ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
#endif
#ifdef XP_WIN
if (IsDebuggerPresent()) {
OutputDebugStringW(PromiseFlatString(aStr).get());
}
#endif
fputs(NS_ConvertUTF16toUTF8(aStr).get(), stdout);
fflush(stdout);
return NS_OK; return NS_OK;
} }

View File

@ -2622,7 +2622,7 @@ nsObjectLoadingContent::ScriptRequestPluginInstance(JSContext* aCx,
NS_NOTREACHED("failed to dispatch PluginScripted event"); NS_NOTREACHED("failed to dispatch PluginScripted event");
} }
mScriptRequested = true; mScriptRequested = true;
} else if (mType == eType_Plugin && !mInstanceOwner && } else if (callerIsContentJS && mType == eType_Plugin && !mInstanceOwner &&
nsContentUtils::IsSafeToRunScript() && nsContentUtils::IsSafeToRunScript() &&
InActiveDocument(thisContent)) { InActiveDocument(thisContent)) {
// If we're configured as a plugin in an active document and it's safe to // If we're configured as a plugin in an active document and it's safe to
@ -3434,7 +3434,8 @@ nsObjectLoadingContent::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObje
JS::Handle<jsid> aId, JS::Handle<jsid> aId,
JS::MutableHandle<JSPropertyDescriptor> aDesc) JS::MutableHandle<JSPropertyDescriptor> aDesc)
{ {
// We don't resolve anything; we just try to make sure we're instantiated // We don't resolve anything; we just try to make sure we're instantiated.
// This purposefully does not fire for chrome/xray resolves, see bug 967694
nsRefPtr<nsNPAPIPluginInstance> pi; nsRefPtr<nsNPAPIPluginInstance> pi;
nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi)); nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
@ -3450,8 +3451,8 @@ nsObjectLoadingContent::GetOwnPropertyNames(JSContext* aCx,
ErrorResult& aRv) ErrorResult& aRv)
{ {
// Just like DoNewResolve, just make sure we're instantiated. That will do // Just like DoNewResolve, just make sure we're instantiated. That will do
// the work our Enumerate hook needs to do, and we don't want to return these // the work our Enumerate hook needs to do. This purposefully does not fire
// property names from Xrays anyway. // for xray resolves, see bug 967694
nsRefPtr<nsNPAPIPluginInstance> pi; nsRefPtr<nsNPAPIPluginInstance> pi;
aRv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi)); aRv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
} }

View File

@ -367,6 +367,7 @@ public:
void GetShaderInfoLog(WebGLShader *shader, nsACString& retval); void GetShaderInfoLog(WebGLShader *shader, nsACString& retval);
void GetShaderInfoLog(WebGLShader *shader, nsAString& retval); void GetShaderInfoLog(WebGLShader *shader, nsAString& retval);
void GetShaderSource(WebGLShader *shader, nsAString& retval); void GetShaderSource(WebGLShader *shader, nsAString& retval);
void GetShaderTranslatedSource(WebGLShader *shader, nsAString& retval);
JS::Value GetTexParameter(GLenum target, GLenum pname); JS::Value GetTexParameter(GLenum target, GLenum pname);
JS::Value GetTexParameter(JSContext * /* unused */, GLenum target, JS::Value GetTexParameter(JSContext * /* unused */, GLenum target,
GLenum pname) { GLenum pname) {
@ -906,6 +907,7 @@ protected:
WEBGL_compressed_texture_pvrtc, WEBGL_compressed_texture_pvrtc,
WEBGL_compressed_texture_s3tc, WEBGL_compressed_texture_s3tc,
WEBGL_debug_renderer_info, WEBGL_debug_renderer_info,
WEBGL_debug_shaders,
WEBGL_depth_texture, WEBGL_depth_texture,
WEBGL_lose_context, WEBGL_lose_context,
WEBGL_draw_buffers, WEBGL_draw_buffers,

View File

@ -29,6 +29,7 @@ static const char *sExtensionNames[] = {
"WEBGL_compressed_texture_pvrtc", "WEBGL_compressed_texture_pvrtc",
"WEBGL_compressed_texture_s3tc", "WEBGL_compressed_texture_s3tc",
"WEBGL_debug_renderer_info", "WEBGL_debug_renderer_info",
"WEBGL_debug_shaders",
"WEBGL_depth_texture", "WEBGL_depth_texture",
"WEBGL_lose_context", "WEBGL_lose_context",
"WEBGL_draw_buffers", "WEBGL_draw_buffers",
@ -53,13 +54,23 @@ WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const {
bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const
{ {
bool allowPrivilegedExts = false;
// Chrome contexts need access to debug information even when // Chrome contexts need access to debug information even when
// webgl.disable-extensions is set. This is used in the graphics // webgl.disable-extensions is set. This is used in the graphics
// section of about:support. // section of about:support.
if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) { if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx)))
allowPrivilegedExts = true;
if (Preferences::GetBool("webgl.enable-privileged-extensions", false))
allowPrivilegedExts = true;
if (allowPrivilegedExts) {
switch (ext) { switch (ext) {
case WEBGL_debug_renderer_info: case WEBGL_debug_renderer_info:
return true; return true;
case WEBGL_debug_shaders:
return true;
default: default:
// For warnings-as-errors. // For warnings-as-errors.
break; break;
@ -163,7 +174,7 @@ WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, ErrorResult& r
for (size_t i = 0; i < size_t(WebGLExtensionID_max); i++) for (size_t i = 0; i < size_t(WebGLExtensionID_max); i++)
{ {
WebGLExtensionID extension = WebGLExtensionID(i); WebGLExtensionID extension = WebGLExtensionID(i);
if (CompareWebGLExtensionName(name, GetExtensionString(extension))) { if (CompareWebGLExtensionName(name, GetExtensionString(extension))) {
ext = extension; ext = extension;
break; break;
@ -251,6 +262,9 @@ WebGLContext::EnableExtension(WebGLExtensionID ext)
case WEBGL_debug_renderer_info: case WEBGL_debug_renderer_info:
obj = new WebGLExtensionDebugRendererInfo(this); obj = new WebGLExtensionDebugRendererInfo(this);
break; break;
case WEBGL_debug_shaders:
obj = new WebGLExtensionDebugShaders(this);
break;
case WEBGL_depth_texture: case WEBGL_depth_texture:
obj = new WebGLExtensionDepthTexture(this); obj = new WebGLExtensionDepthTexture(this);
break; break;

View File

@ -3299,13 +3299,17 @@ WebGLContext::CompileShader(WebGLShader *shader)
nsDependentCString(mapped_name))); nsDependentCString(mapped_name)));
} }
size_t len = 0; size_t lenWithNull = 0;
ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &len); ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &lenWithNull);
MOZ_ASSERT(lenWithNull >= 1);
size_t len = lenWithNull - 1;
nsAutoCString translatedSrc; nsAutoCString translatedSrc;
translatedSrc.SetLength(len); translatedSrc.SetLength(len); // Allocates len+1, for the null-term.
ShGetObjectCode(compiler, translatedSrc.BeginWriting()); ShGetObjectCode(compiler, translatedSrc.BeginWriting());
CopyASCIItoUTF16(translatedSrc, shader->mTranslatedSource);
const char *ts = translatedSrc.get(); const char *ts = translatedSrc.get();
#ifdef WEBGL2_BYPASS_ANGLE #ifdef WEBGL2_BYPASS_ANGLE
@ -3324,6 +3328,8 @@ WebGLContext::CompileShader(WebGLShader *shader)
// that's really bad, as that means we can't be 100% conformant. We should work towards always // that's really bad, as that means we can't be 100% conformant. We should work towards always
// using ANGLE identifier mapping. // using ANGLE identifier mapping.
gl->fShaderSource(shadername, 1, &s, nullptr); gl->fShaderSource(shadername, 1, &s, nullptr);
CopyASCIItoUTF16(s, shader->mTranslatedSource);
} }
shader->SetTranslationSuccess(); shader->SetTranslationSuccess();
@ -3617,8 +3623,7 @@ WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
void void
WebGLContext::GetShaderSource(WebGLShader *shader, nsAString& retval) WebGLContext::GetShaderSource(WebGLShader *shader, nsAString& retval)
{ {
if (IsContextLost()) if (IsContextLost()) {
{
retval.SetIsVoid(true); retval.SetIsVoid(true);
return; return;
} }
@ -3651,6 +3656,20 @@ WebGLContext::ShaderSource(WebGLShader *shader, const nsAString& source)
shader->SetNeedsTranslation(); shader->SetNeedsTranslation();
} }
void
WebGLContext::GetShaderTranslatedSource(WebGLShader *shader, nsAString& retval)
{
if (IsContextLost()) {
retval.SetIsVoid(true);
return;
}
if (!ValidateObject("getShaderTranslatedSource: shader", shader))
return;
retval.Assign(shader->TranslatedSource());
}
GLenum WebGLContext::CheckedTexImage2D(GLenum target, GLenum WebGLContext::CheckedTexImage2D(GLenum target,
GLint level, GLint level,
GLenum internalFormat, GLenum internalFormat,

View File

@ -0,0 +1,36 @@
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLContext.h"
#include "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
using namespace mozilla;
WebGLExtensionDebugShaders::WebGLExtensionDebugShaders(WebGLContext* context)
: WebGLExtensionBase(context)
{
}
WebGLExtensionDebugShaders::~WebGLExtensionDebugShaders()
{
}
/* If no source has been defined, compileShader() has not been called,
* or the translation has failed for shader, an empty string is
* returned; otherwise, return the translated source.
*/
void
WebGLExtensionDebugShaders::GetTranslatedShaderSource(WebGLShader* shader,
nsAString& retval)
{
mContext->GetShaderTranslatedSource(shader, retval);
if (retval.IsVoid()) {
CopyASCIItoUTF16("", retval);
}
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionDebugShaders)

View File

@ -76,6 +76,18 @@ public:
DECL_WEBGL_EXTENSION_GOOP DECL_WEBGL_EXTENSION_GOOP
}; };
class WebGLExtensionDebugShaders
: public WebGLExtensionBase
{
public:
WebGLExtensionDebugShaders(WebGLContext*);
virtual ~WebGLExtensionDebugShaders();
void GetTranslatedShaderSource(WebGLShader* shader, nsAString& retval);
DECL_WEBGL_EXTENSION_GOOP
};
class WebGLExtensionDepthTexture class WebGLExtensionDepthTexture
: public WebGLExtensionBase : public WebGLExtensionBase
{ {

View File

@ -72,6 +72,8 @@ public:
const nsCString& TranslationLog() const { return mTranslationLog; } const nsCString& TranslationLog() const { return mTranslationLog; }
const nsString& TranslatedSource() const { return mTranslatedSource; }
WebGLContext *GetParentObject() const { WebGLContext *GetParentObject() const {
return Context(); return Context();
} }
@ -87,6 +89,7 @@ protected:
GLuint mGLName; GLuint mGLName;
GLenum mType; GLenum mType;
nsString mSource; nsString mSource;
nsString mTranslatedSource;
nsCString mTranslationLog; // The translation log should contain only ASCII characters nsCString mTranslationLog; // The translation log should contain only ASCII characters
bool mNeedsTranslation; bool mNeedsTranslation;
nsTArray<WebGLMappedIdentifier> mAttributes; nsTArray<WebGLMappedIdentifier> mAttributes;

View File

@ -48,6 +48,7 @@ if CONFIG['MOZ_WEBGL']:
'WebGLExtensionCompressedTexturePVRTC.cpp', 'WebGLExtensionCompressedTexturePVRTC.cpp',
'WebGLExtensionCompressedTextureS3TC.cpp', 'WebGLExtensionCompressedTextureS3TC.cpp',
'WebGLExtensionDebugRendererInfo.cpp', 'WebGLExtensionDebugRendererInfo.cpp',
'WebGLExtensionDebugShaders.cpp',
'WebGLExtensionDepthTexture.cpp', 'WebGLExtensionDepthTexture.cpp',
'WebGLExtensionDrawBuffers.cpp', 'WebGLExtensionDrawBuffers.cpp',
'WebGLExtensionElementIndexUint.cpp', 'WebGLExtensionElementIndexUint.cpp',

View File

@ -75,9 +75,9 @@ function runTestEnabled() {
// if no source has been defined or compileShader() has not been called, // if no source has been defined or compileShader() has not been called,
// getTranslatedShaderSource() should return an empty string. // getTranslatedShaderSource() should return an empty string.
shouldBeNull("ext.getTranslatedShaderSource(shader)"); shouldBe("ext.getTranslatedShaderSource(shader)", '""');
gl.shaderSource(shader, source); gl.shaderSource(shader, source);
shouldBeNull("ext.getTranslatedShaderSource(shader)"); shouldBe("ext.getTranslatedShaderSource(shader)", '""');
gl.compileShader(shader); gl.compileShader(shader);
shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)"); shouldBeTrue("gl.getShaderParameter(shader, gl.COMPILE_STATUS)");
var translatedSource = ext.getTranslatedShaderSource(shader); var translatedSource = ext.getTranslatedShaderSource(shader);

View File

@ -5,6 +5,7 @@ support-files =
[test_highp_fs.html] [test_highp_fs.html]
[test_no_arr_points.html] [test_no_arr_points.html]
[test_privileged_exts.html]
[test_webgl_available.html] [test_webgl_available.html]
[test_webgl_conformance.html] [test_webgl_conformance.html]
[test_webgl_request_context.html] [test_webgl_request_context.html]

View File

@ -0,0 +1,33 @@
<!DOCTYPE HTML>
<html>
<head>
<title>WebGL test: Check for privileged ext access.</title>
<script src="/MochiKit/MochiKit.js"></script>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<script src="webgl-util.js"></script>
<script src="driver-info.js"></script>
</head>
<body>
<canvas id="c"></canvas>
<script>
function TestExt(gl, name) {
var ext = gl.getExtension(name);
ok(!ext, 'Should not have access to \'' + name + '\'.');
}
(function() {
var gl = WebGLUtil.getWebGL('c');
if (!gl) {
todo(gl, 'Get GL working here first.');
return;
}
// Privileged extensions:
TestExt(gl, 'WEBGL_debug_renderer_info');
})();
</script>
</body>
</html>

View File

@ -416,15 +416,23 @@ const int16_t irc_composite_c_r0195_p090[][256] =
{/* IRC_Composite_C_R0195_T000_P090.wav */ {/* IRC_Composite_C_R0195_T000_P090.wav */
{-1,1,-1,1,-1,1,-1,2,-2,2,-3,3,-3,4,-5,5,-7,8,-10,14,-25,-385,-133,-356,-344,-390,-312,-438,-400,-852,-107,-995,-245,-186,1358,-771,1473,28,-1710,-3762,-3025,4119,8200,5927,-785,1558,2250,1837,2098,631,-318,150,-77,1215,-23,792,865,600,981,659,366,950,511,766,502,516,589,299,331,571,105,609,462,485,538,594,470,640,393,432,325,604,259,355,336,454,33,263,182,-24,-124,121,-231,-50,-93,49,-230,-101,25,-196,-123,-21,-160,-161,-132,-136,-155,-268,-121,-146,-311,-112,-328,-201,-220,-280,-214,-304,-233,-227,-250,-242,-334,-256,-283,-393,-267,-285,-332,-331,-224,-295,-279,-171,-151,-361,-199,-239,-227,-317,-168,-211,-370,-182,-150,-343,-204,-192,-224,-319,-203,-137,-357,-146,-223,-237,-276,-162,-201,-262,-186,-209,-147,-267,-46,-252,-162,-146,-182,-199,-143,-218,-204,-108,-250,-163,-90,-241,-137,-125,-122,-272,-111,-188,-211,-160,-160,-164,-201,-231,-114,-175,-180,-212,-172,-181,-129,-130,-77,-150,-114,-39,12,-122,-9,-11,-46,-21,-4,7,-73,-20,-50,-21,-80,-102,2,-103,-66,-67,-8,-41,-119,-26,29,-208,3,-108,-34,-228,114,-196,-84,-28,1,-109,-92,77,-169,-27,48,-12,-79,3,-100,-44,-53,13,-103,-90,-14,-91,-23,-64,-21,-116}}; {-1,1,-1,1,-1,1,-1,2,-2,2,-3,3,-3,4,-5,5,-7,8,-10,14,-25,-385,-133,-356,-344,-390,-312,-438,-400,-852,-107,-995,-245,-186,1358,-771,1473,28,-1710,-3762,-3025,4119,8200,5927,-785,1558,2250,1837,2098,631,-318,150,-77,1215,-23,792,865,600,981,659,366,950,511,766,502,516,589,299,331,571,105,609,462,485,538,594,470,640,393,432,325,604,259,355,336,454,33,263,182,-24,-124,121,-231,-50,-93,49,-230,-101,25,-196,-123,-21,-160,-161,-132,-136,-155,-268,-121,-146,-311,-112,-328,-201,-220,-280,-214,-304,-233,-227,-250,-242,-334,-256,-283,-393,-267,-285,-332,-331,-224,-295,-279,-171,-151,-361,-199,-239,-227,-317,-168,-211,-370,-182,-150,-343,-204,-192,-224,-319,-203,-137,-357,-146,-223,-237,-276,-162,-201,-262,-186,-209,-147,-267,-46,-252,-162,-146,-182,-199,-143,-218,-204,-108,-250,-163,-90,-241,-137,-125,-122,-272,-111,-188,-211,-160,-160,-164,-201,-231,-114,-175,-180,-212,-172,-181,-129,-130,-77,-150,-114,-39,12,-122,-9,-11,-46,-21,-4,7,-73,-20,-50,-21,-80,-102,2,-103,-66,-67,-8,-41,-119,-26,29,-208,3,-108,-34,-228,114,-196,-84,-28,1,-109,-92,77,-169,-27,48,-12,-79,3,-100,-44,-53,13,-103,-90,-14,-91,-23,-64,-21,-116}};
struct Elevation
{
/**
* An array of |count| impulse responses of 256 samples for the left ear.
* The impulse responses in each elevation are at equally spaced azimuths
* for a full 360 degree revolution, ordered clockwise from in front the
* listener.
*/
const int16_t (*azimuths)[256];
int count;
};
/** /**
* irc_composite_c_r0195 is an array with each element containing data for one * irc_composite_c_r0195 is an array with each element containing data for one
* elevation. For each elevation, |azimuths| is an array of |count| impulse * elevation.
* responses of 256 samples for the left ear. The impulse responses in each
* elevation are at equally spaced azimuths for a full 360 degree revolution,
* ordered clockwise from in front the listener.
*/ */
const struct { const int16_t (*azimuths)[256]; int count; } const Elevation irc_composite_c_r0195[] =
irc_composite_c_r0195[] =
{{irc_composite_c_r0195_p315, MOZ_ARRAY_LENGTH(irc_composite_c_r0195_p315)}, {{irc_composite_c_r0195_p315, MOZ_ARRAY_LENGTH(irc_composite_c_r0195_p315)},
{irc_composite_c_r0195_p330, MOZ_ARRAY_LENGTH(irc_composite_c_r0195_p330)}, {irc_composite_c_r0195_p330, MOZ_ARRAY_LENGTH(irc_composite_c_r0195_p330)},
{irc_composite_c_r0195_p345, MOZ_ARRAY_LENGTH(irc_composite_c_r0195_p345)}, {irc_composite_c_r0195_p345, MOZ_ARRAY_LENGTH(irc_composite_c_r0195_p345)},

View File

@ -6,7 +6,6 @@
#include "mozilla/dom/SVGFEOffsetElement.h" #include "mozilla/dom/SVGFEOffsetElement.h"
#include "mozilla/dom/SVGFEOffsetElementBinding.h" #include "mozilla/dom/SVGFEOffsetElementBinding.h"
#include "nsSVGFilterInstance.h" #include "nsSVGFilterInstance.h"
#include "gfxContext.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEOffset) NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(FEOffset)
@ -60,15 +59,6 @@ SVGFEOffsetElement::Dy()
return mNumberAttributes[DY].ToDOMAnimatedNumber(this); return mNumberAttributes[DY].ToDOMAnimatedNumber(this);
} }
nsIntPoint
SVGFEOffsetElement::GetOffset(const nsSVGFilterInstance& aInstance)
{
return nsIntPoint(int32_t(aInstance.GetPrimitiveNumber(
SVGContentUtils::X, &mNumberAttributes[DX])),
int32_t(aInstance.GetPrimitiveNumber(
SVGContentUtils::Y, &mNumberAttributes[DY])));
}
FilterPrimitiveDescription FilterPrimitiveDescription
SVGFEOffsetElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance, SVGFEOffsetElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
const IntRect& aFilterSubregion, const IntRect& aFilterSubregion,
@ -76,8 +66,11 @@ SVGFEOffsetElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance,
nsTArray<RefPtr<SourceSurface>>& aInputImages) nsTArray<RefPtr<SourceSurface>>& aInputImages)
{ {
FilterPrimitiveDescription descr(FilterPrimitiveDescription::eOffset); FilterPrimitiveDescription descr(FilterPrimitiveDescription::eOffset);
nsIntPoint offset = GetOffset(*aInstance); IntPoint offset(int32_t(aInstance->GetPrimitiveNumber(
descr.Attributes().Set(eOffsetOffset, IntPoint(offset.x, offset.y)); SVGContentUtils::X, &mNumberAttributes[DX])),
int32_t(aInstance->GetPrimitiveNumber(
SVGContentUtils::Y, &mNumberAttributes[DY])));
descr.Attributes().Set(eOffsetOffset, offset);
return descr; return descr;
} }

View File

@ -49,8 +49,6 @@ public:
already_AddRefed<SVGAnimatedNumber> Dy(); already_AddRefed<SVGAnimatedNumber> Dy();
protected: protected:
nsIntPoint GetOffset(const nsSVGFilterInstance& aInstance);
virtual NumberAttributesInfo GetNumberInfo() MOZ_OVERRIDE; virtual NumberAttributesInfo GetNumberInfo() MOZ_OVERRIDE;
virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE; virtual StringAttributesInfo GetStringInfo() MOZ_OVERRIDE;

View File

@ -160,7 +160,7 @@ SVGFilterElement::Invalidate()
nsTObserverArray<nsIMutationObserver*>::ForwardIterator iter(*observers); nsTObserverArray<nsIMutationObserver*>::ForwardIterator iter(*observers);
while (iter.HasMore()) { while (iter.HasMore()) {
nsCOMPtr<nsIMutationObserver> obs(iter.GetNext()); nsCOMPtr<nsIMutationObserver> obs(iter.GetNext());
nsCOMPtr<nsISVGFilterProperty> filter = do_QueryInterface(obs); nsCOMPtr<nsISVGFilterReference> filter = do_QueryInterface(obs);
if (filter) if (filter)
filter->Invalidate(); filter->Invalidate();
} }

View File

@ -89,6 +89,26 @@ LoadContext::SetPrivateBrowsing(bool aUsePrivateBrowsing)
return NS_ERROR_UNEXPECTED; return NS_ERROR_UNEXPECTED;
} }
NS_IMETHODIMP
LoadContext::GetUseRemoteTabs(bool* aUseRemoteTabs)
{
MOZ_ASSERT(mIsNotNull);
NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
*aUseRemoteTabs = mUseRemoteTabs;
return NS_OK;
}
NS_IMETHODIMP
LoadContext::SetRemoteTabs(bool aUseRemoteTabs)
{
MOZ_ASSERT(mIsNotNull);
// We shouldn't need this on parent...
return NS_ERROR_UNEXPECTED;
}
NS_IMETHODIMP NS_IMETHODIMP
LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement) LoadContext::GetIsInBrowserElement(bool* aIsInBrowserElement)
{ {

View File

@ -48,6 +48,7 @@ public:
, mAppId(aAppId) , mAppId(aAppId)
, mIsContent(aToCopy.mIsContent) , mIsContent(aToCopy.mIsContent)
, mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing) , mUsePrivateBrowsing(aToCopy.mUsePrivateBrowsing)
, mUseRemoteTabs(aToCopy.mUseRemoteTabs)
, mIsInBrowserElement(aInBrowser) , mIsInBrowserElement(aInBrowser)
#ifdef DEBUG #ifdef DEBUG
, mIsNotNull(aToCopy.mIsNotNull) , mIsNotNull(aToCopy.mIsNotNull)
@ -58,11 +59,13 @@ public:
uint32_t aAppId, uint32_t aAppId,
bool aIsContent, bool aIsContent,
bool aUsePrivateBrowsing, bool aUsePrivateBrowsing,
bool aUseRemoteTabs,
bool aIsInBrowserElement) bool aIsInBrowserElement)
: mTopFrameElement(do_GetWeakReference(aTopFrameElement)) : mTopFrameElement(do_GetWeakReference(aTopFrameElement))
, mAppId(aAppId) , mAppId(aAppId)
, mIsContent(aIsContent) , mIsContent(aIsContent)
, mUsePrivateBrowsing(aUsePrivateBrowsing) , mUsePrivateBrowsing(aUsePrivateBrowsing)
, mUseRemoteTabs(aUseRemoteTabs)
, mIsInBrowserElement(aIsInBrowserElement) , mIsInBrowserElement(aIsInBrowserElement)
#ifdef DEBUG #ifdef DEBUG
, mIsNotNull(true) , mIsNotNull(true)
@ -75,6 +78,7 @@ public:
, mAppId(aAppId) , mAppId(aAppId)
, mIsContent(false) , mIsContent(false)
, mUsePrivateBrowsing(false) , mUsePrivateBrowsing(false)
, mUseRemoteTabs(false)
, mIsInBrowserElement(false) , mIsInBrowserElement(false)
#ifdef DEBUG #ifdef DEBUG
, mIsNotNull(true) , mIsNotNull(true)
@ -86,6 +90,7 @@ private:
uint32_t mAppId; uint32_t mAppId;
bool mIsContent; bool mIsContent;
bool mUsePrivateBrowsing; bool mUsePrivateBrowsing;
bool mUseRemoteTabs;
bool mIsInBrowserElement; bool mIsInBrowserElement;
#ifdef DEBUG #ifdef DEBUG
bool mIsNotNull; bool mIsNotNull;

View File

@ -59,6 +59,7 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext)
mIsPrivateBitValid = true; mIsPrivateBitValid = true;
aLoadContext->GetIsContent(&mIsContent); aLoadContext->GetIsContent(&mIsContent);
aLoadContext->GetUsePrivateBrowsing(&mUsePrivateBrowsing); aLoadContext->GetUsePrivateBrowsing(&mUsePrivateBrowsing);
aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs);
aLoadContext->GetAppId(&mAppId); aLoadContext->GetAppId(&mAppId);
aLoadContext->GetIsInBrowserElement(&mIsInBrowserElement); aLoadContext->GetIsInBrowserElement(&mIsInBrowserElement);
} else { } else {
@ -68,6 +69,7 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext)
// we won't be GetInterfaced to nsILoadContext // we won't be GetInterfaced to nsILoadContext
mIsContent = true; mIsContent = true;
mUsePrivateBrowsing = false; mUsePrivateBrowsing = false;
mUseRemoteTabs = false;
mAppId = 0; mAppId = 0;
mIsInBrowserElement = false; mIsInBrowserElement = false;
} }

View File

@ -54,6 +54,7 @@ public:
bool mIsPrivateBitValid; bool mIsPrivateBitValid;
bool mIsContent; bool mIsContent;
bool mUsePrivateBrowsing; bool mUsePrivateBrowsing;
bool mUseRemoteTabs;
bool mIsInBrowserElement; bool mIsInBrowserElement;
uint32_t mAppId; uint32_t mAppId;
}; };
@ -70,6 +71,7 @@ struct ParamTraits<SerializedLoadContext>
WriteParam(aMsg, aParam.mIsContent); WriteParam(aMsg, aParam.mIsContent);
WriteParam(aMsg, aParam.mIsPrivateBitValid); WriteParam(aMsg, aParam.mIsPrivateBitValid);
WriteParam(aMsg, aParam.mUsePrivateBrowsing); WriteParam(aMsg, aParam.mUsePrivateBrowsing);
WriteParam(aMsg, aParam.mUseRemoteTabs);
WriteParam(aMsg, aParam.mAppId); WriteParam(aMsg, aParam.mAppId);
WriteParam(aMsg, aParam.mIsInBrowserElement); WriteParam(aMsg, aParam.mIsInBrowserElement);
} }
@ -80,6 +82,7 @@ struct ParamTraits<SerializedLoadContext>
!ReadParam(aMsg, aIter, &aResult->mIsContent) || !ReadParam(aMsg, aIter, &aResult->mIsContent) ||
!ReadParam(aMsg, aIter, &aResult->mIsPrivateBitValid) || !ReadParam(aMsg, aIter, &aResult->mIsPrivateBitValid) ||
!ReadParam(aMsg, aIter, &aResult->mUsePrivateBrowsing) || !ReadParam(aMsg, aIter, &aResult->mUsePrivateBrowsing) ||
!ReadParam(aMsg, aIter, &aResult->mUseRemoteTabs) ||
!ReadParam(aMsg, aIter, &aResult->mAppId) || !ReadParam(aMsg, aIter, &aResult->mAppId) ||
!ReadParam(aMsg, aIter, &aResult->mIsInBrowserElement)) { !ReadParam(aMsg, aIter, &aResult->mIsInBrowserElement)) {
return false; return false;

View File

@ -829,6 +829,7 @@ nsDocShell::nsDocShell():
mIsAppTab(false), mIsAppTab(false),
mUseGlobalHistory(false), mUseGlobalHistory(false),
mInPrivateBrowsing(false), mInPrivateBrowsing(false),
mUseRemoteTabs(false),
mDeviceSizeIsPageSize(false), mDeviceSizeIsPageSize(false),
mCanExecuteScripts(false), mCanExecuteScripts(false),
mFiredUnloadEvent(false), mFiredUnloadEvent(false),
@ -2245,6 +2246,29 @@ nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs)
{
NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
*aUseRemoteTabs = mUseRemoteTabs;
return NS_OK;
}
NS_IMETHODIMP
nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
{
#ifdef MOZ_CRASHREPORTER
if (aUseRemoteTabs) {
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"),
NS_LITERAL_CSTRING("1"));
}
#endif
mUseRemoteTabs = aUseRemoteTabs;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime) nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
{ {

View File

@ -213,6 +213,8 @@ public:
NS_IMETHOD GetUsePrivateBrowsing(bool*); NS_IMETHOD GetUsePrivateBrowsing(bool*);
NS_IMETHOD SetUsePrivateBrowsing(bool); NS_IMETHOD SetUsePrivateBrowsing(bool);
NS_IMETHOD SetPrivateBrowsing(bool); NS_IMETHOD SetPrivateBrowsing(bool);
NS_IMETHOD GetUseRemoteTabs(bool*);
NS_IMETHOD SetRemoteTabs(bool);
// Restores a cached presentation from history (mLSHE). // Restores a cached presentation from history (mLSHE).
// This method swaps out the content viewer and simulates loads for // This method swaps out the content viewer and simulates loads for
@ -830,6 +832,7 @@ protected:
bool mIsAppTab; bool mIsAppTab;
bool mUseGlobalHistory; bool mUseGlobalHistory;
bool mInPrivateBrowsing; bool mInPrivateBrowsing;
bool mUseRemoteTabs;
bool mDeviceSizeIsPageSize; bool mDeviceSizeIsPageSize;
// Because scriptability depends on the mAllowJavascript values of our // Because scriptability depends on the mAllowJavascript values of our

View File

@ -14,7 +14,7 @@ interface nsIDOMElement;
* can be queried for various information about where the load is * can be queried for various information about where the load is
* happening. * happening.
*/ */
[scriptable, uuid(d0029474-0cc4-42fd-bb21-d9ff22f5293c)] [scriptable, uuid(852ed1f0-8ec0-11e3-baa8-0800200c9a66)]
interface nsILoadContext : nsISupports interface nsILoadContext : nsISupports
{ {
/** /**
@ -66,6 +66,11 @@ interface nsILoadContext : nsISupports
*/ */
attribute boolean usePrivateBrowsing; attribute boolean usePrivateBrowsing;
/**
* Attribute that determines if remote (out-of-process) tabs should be used.
*/
readonly attribute boolean useRemoteTabs;
%{C++ %{C++
/** /**
* De-XPCOMed getter to make call-sites cleaner. * De-XPCOMed getter to make call-sites cleaner.
@ -75,6 +80,12 @@ interface nsILoadContext : nsISupports
GetUsePrivateBrowsing(&usingPB); GetUsePrivateBrowsing(&usingPB);
return usingPB; return usingPB;
} }
bool UseRemoteTabs() {
bool usingRT;
GetUseRemoteTabs(&usingRT);
return usingRT;
}
%} %}
/** /**
@ -82,6 +93,11 @@ interface nsILoadContext : nsISupports
*/ */
[noscript] void SetPrivateBrowsing(in boolean aInPrivateBrowsing); [noscript] void SetPrivateBrowsing(in boolean aInPrivateBrowsing);
/**
* Set the remote tabs state of the load context, meant to be used internally.
*/
[noscript] void SetRemoteTabs(in boolean aUseRemoteTabs);
/** /**
* Returns true iff the load is occurring inside a browser element. * Returns true iff the load is occurring inside a browser element.
*/ */

View File

@ -232,6 +232,10 @@ class nsIScriptTimeoutHandler;
#endif // check #endif // check
#include "AccessCheck.h" #include "AccessCheck.h"
#ifdef ANDROID
#include <android/log.h>
#endif
#ifdef PR_LOGGING #ifdef PR_LOGGING
static PRLogModuleInfo* gDOMLeakPRLog; static PRLogModuleInfo* gDOMLeakPRLog;
#endif #endif
@ -5809,7 +5813,31 @@ nsGlobalWindow::Dump(const nsAString& aStr)
return NS_OK; return NS_OK;
} }
PrintToDebugger(aStr, gDumpFile ? gDumpFile : stdout); char *cstr = ToNewUTF8String(aStr);
#if defined(XP_MACOSX)
// have to convert \r to \n so that printing to the console works
char *c = cstr, *cEnd = cstr + strlen(cstr);
while (c < cEnd) {
if (*c == '\r')
*c = '\n';
c++;
}
#endif
if (cstr) {
#ifdef XP_WIN
PrintToDebugger(cstr);
#endif
#ifdef ANDROID
__android_log_write(ANDROID_LOG_INFO, "GeckoDump", cstr);
#endif
FILE *fp = gDumpFile ? gDumpFile : stdout;
fputs(cstr, fp);
fflush(fp);
nsMemory::Free(cstr);
}
return NS_OK; return NS_OK;
} }

View File

@ -1370,6 +1370,11 @@ DOMInterfaces = {
'headerFile': 'WebGLExtensions.h' 'headerFile': 'WebGLExtensions.h'
}, },
'WebGLExtensionDebugShaders': {
'nativeType': 'mozilla::WebGLExtensionDebugShaders',
'headerFile': 'WebGLExtensions.h'
},
'WebGLExtensionElementIndexUint': { 'WebGLExtensionElementIndexUint': {
'nativeType': 'mozilla::WebGLExtensionElementIndexUint', 'nativeType': 'mozilla::WebGLExtensionElementIndexUint',
'headerFile': 'WebGLExtensions.h' 'headerFile': 'WebGLExtensions.h'

View File

@ -696,6 +696,8 @@ TabChild::Init()
MOZ_ASSERT(loadContext); MOZ_ASSERT(loadContext);
loadContext->SetPrivateBrowsing( loadContext->SetPrivateBrowsing(
mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW); mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW);
loadContext->SetRemoteTabs(
mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW);
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell); nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE); NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE);

View File

@ -1919,6 +1919,7 @@ TabParent::GetLoadContext()
OwnOrContainingAppId(), OwnOrContainingAppId(),
true /* aIsContent */, true /* aIsContent */,
mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW, mChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW,
mChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW,
IsBrowserElement()); IsBrowserElement());
mLoadContext = loadContext; mLoadContext = loadContext;
} }

View File

@ -32,6 +32,7 @@ support-files =
[test_bug813906.html] [test_bug813906.html]
[test_bug854082.html] [test_bug854082.html]
[test_bug863792.html] [test_bug863792.html]
[test_bug967694.html]
[test_cocoa_focus.html] [test_cocoa_focus.html]
skip-if = toolkit != "cocoa" skip-if = toolkit != "cocoa"
support-files = cocoa_focus.html support-files = cocoa_focus.html

View File

@ -0,0 +1,78 @@
<!doctype html>
<html>
<head>
<title>Test for Bug 967694</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<script type="application/javascript">
// Touching a plugin from chrome scope should not spawn it, bug should
// synchronously spawn it from content scope
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
var plugin;
var spPlugin;
function recreatePlugin() {
if (plugin) {
document.body.removeChild(plugin);
}
plugin = document.createElement("embed");
plugin.type = "application/x-test";
document.body.appendChild(plugin);
// Plugin should now be queued for async spawning.
spPlugin = SpecialPowers.wrap(plugin);
is(spPlugin.displayedType, spPlugin.TYPE_PLUGIN, "Should be configured as plugin");
ok(!spPlugin.hasRunningPlugin, "Should not be spawned yet");
}
recreatePlugin();
// Try various JS operations with chrome context
var thrown = false;
// Get and set non-existent Property
var hi = spPlugin._testShouldntExist;
spPlugin._testShouldntExist = 5;
// Call some test-plugin function
try {
var val = spPlugin.getObjectValue();
} catch (e) {
thrown = true;
}
ok(thrown, "Function call should have thrown");
ok(!spPlugin.hasRunningPlugin, "Plugin should not have spawned");
// Try property access from content
var hi = plugin._testShouldntExistContent;
ok(spPlugin.hasRunningPlugin, "Should've caused plugin to spawn");
// Property set
recreatePlugin();
plugin._testShouldntExistContent = 5;
ok(spPlugin.hasRunningPlugin, "Should've caused plugin to spawn");
// Call test plugin function. Should succeed.
recreatePlugin();
thrown = false;
try {
var value = plugin.getObjectValue();
} catch (e) {
thrown = true;
}
ok(!thrown, "Call should have succeeded");
ok(spPlugin.hasRunningPlugin, "Call should have synchronously spawned plugin");
ok(plugin.checkObjectValue(value), "Plugin should recognize self");
</script>
</body>
</html>

View File

@ -21,12 +21,17 @@
const FLAG_CLEAR_ALL = pluginHostIface.FLAG_CLEAR_ALL; const FLAG_CLEAR_ALL = pluginHostIface.FLAG_CLEAR_ALL;
const FLAG_CLEAR_CACHE = pluginHostIface.FLAG_CLEAR_CACHE; const FLAG_CLEAR_CACHE = pluginHostIface.FLAG_CLEAR_CACHE;
// Make sure clearing by timerange is supported.
var p = document.getElementById("plugin1"); var p = document.getElementById("plugin1");
p.setSitesWithDataCapabilities(true);
ok(PluginUtils.withTestPlugin(runTest), "Test plugin found"); // Since we're running with chrome permissions, accessing the plugin wont
SimpleTest.finish(); // synchronously spawn it -- wait for the async spawning to finish.
SimpleTest.executeSoon(function() {
// Make sure clearing by timerange is supported.
p.setSitesWithDataCapabilities(true);
ok(PluginUtils.withTestPlugin(runTest), "Test plugin found");
SimpleTest.finish();
});
function stored(needles) { function stored(needles) {
var something = pluginHost.siteHasData(this.pluginTag, null); var something = pluginHost.siteHasData(this.pluginTag, null);

View File

@ -161,14 +161,15 @@ namespace {
class StorageNotifierRunnable : public nsRunnable class StorageNotifierRunnable : public nsRunnable
{ {
public: public:
StorageNotifierRunnable(nsISupports* aSubject) StorageNotifierRunnable(nsISupports* aSubject, const char16_t* aType)
: mSubject(aSubject) : mSubject(aSubject), mType(aType)
{ } { }
NS_DECL_NSIRUNNABLE NS_DECL_NSIRUNNABLE
private: private:
nsCOMPtr<nsISupports> mSubject; nsCOMPtr<nsISupports> mSubject;
const char16_t* mType;
}; };
NS_IMETHODIMP NS_IMETHODIMP
@ -177,7 +178,7 @@ StorageNotifierRunnable::Run()
nsCOMPtr<nsIObserverService> observerService = nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService(); mozilla::services::GetObserverService();
if (observerService) { if (observerService) {
observerService->NotifyObservers(mSubject, "dom-storage2-changed", nullptr); observerService->NotifyObservers(mSubject, "dom-storage2-changed", mType);
} }
return NS_OK; return NS_OK;
} }
@ -207,7 +208,11 @@ DOMStorage::BroadcastChangeNotification(const nsSubstring& aKey,
return; return;
} }
nsRefPtr<StorageNotifierRunnable> r = new StorageNotifierRunnable(event); nsRefPtr<StorageNotifierRunnable> r =
new StorageNotifierRunnable(event,
GetType() == LocalStorage
? MOZ_UTF16("localStorage")
: MOZ_UTF16("sessionStorage"));
NS_DispatchToMainThread(r); NS_DispatchToMainThread(r);
} }

View File

@ -13,9 +13,13 @@
#include "unistd.h" #include "unistd.h"
#include "dirent.h" #include "dirent.h"
#include "sys/stat.h" #include "sys/stat.h"
#if !defined(ANDROID) #if defined(ANDROID)
#include <sys/vfs.h>
#define statvfs statfs
#else
#include "sys/statvfs.h"
#include <spawn.h> #include <spawn.h>
#endif // !defined(ANDROID) #endif // defined(ANDROID)
#endif // defined(XP_UNIX) #endif // defined(XP_UNIX)
#if defined(XP_LINUX) #if defined(XP_LINUX)
@ -526,6 +530,9 @@ static const dom::ConstantSpec gLibcProperties[] =
// The size of |time_t|. // The size of |time_t|.
{ "OSFILE_SIZEOF_TIME_T", INT_TO_JSVAL(sizeof (time_t)) }, { "OSFILE_SIZEOF_TIME_T", INT_TO_JSVAL(sizeof (time_t)) },
// The size of |fsblkcnt_t|.
{ "OSFILE_SIZEOF_FSBLKCNT_T", INT_TO_JSVAL(sizeof (fsblkcnt_t)) },
#if !defined(ANDROID) #if !defined(ANDROID)
// The size of |posix_spawn_file_actions_t|. // The size of |posix_spawn_file_actions_t|.
{ "OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T", INT_TO_JSVAL(sizeof (posix_spawn_file_actions_t)) }, { "OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T", INT_TO_JSVAL(sizeof (posix_spawn_file_actions_t)) },
@ -585,6 +592,13 @@ static const dom::ConstantSpec gLibcProperties[] =
{ "OSFILE_OFFSETOF_STAT_ST_BIRTHTIME", INT_TO_JSVAL(offsetof (struct stat, st_birthtime)) }, { "OSFILE_OFFSETOF_STAT_ST_BIRTHTIME", INT_TO_JSVAL(offsetof (struct stat, st_birthtime)) },
#endif // defined(_DARWIN_FEATURE_64_BIT_INODE) #endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
// Defining |statvfs|
{ "OSFILE_SIZEOF_STATVFS", INT_TO_JSVAL(sizeof (struct statvfs)) },
{ "OSFILE_OFFSETOF_STATVFS_F_BSIZE", INT_TO_JSVAL(offsetof (struct statvfs, f_bsize)) },
{ "OSFILE_OFFSETOF_STATVFS_F_BAVAIL", INT_TO_JSVAL(offsetof (struct statvfs, f_bavail)) },
#endif // defined(XP_UNIX) #endif // defined(XP_UNIX)

View File

@ -12,5 +12,6 @@ support-files =
[test_storageLocalStorageEventCheckNoPropagation.html] [test_storageLocalStorageEventCheckNoPropagation.html]
[test_storageLocalStorageEventCheckPropagation.html] [test_storageLocalStorageEventCheckPropagation.html]
[test_storageNotifications.html]
[test_storageSessionStorageEventCheckNoPropagation.html] [test_storageSessionStorageEventCheckNoPropagation.html]
[test_storageSessionStorageEventCheckPropagation.html] [test_storageSessionStorageEventCheckPropagation.html]

View File

@ -0,0 +1,127 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>sessionStorage basic test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="application/javascript;version=1.7">
var expectedTypes = [
"localStorage",
"localStorage",
"sessionStorage",
"localStorage",
"sessionStorage",
"sessionStorage",
"localStorage",
"sessionStorage",
"localStorage",
"sessionStorage",
"localStorage",
"sessionStorage",
"sessionStorage",
"localStorage",
"sessionStorage",
"localStorage",
];
var tests = Tests();
function setup() {
sessionStorage.clear();
SimpleTest.executeSoon(function() {
tests.next();
});
}
function Tests()
{
// Initially check the both storages are empty
is(sessionStorage.length, 0, "Session storage is empty [1]");
is(localStorage.length, 0, "Local storage is empty [1]");
var onStorageChanged = {
observe: function(subject, topic, type) {
if (topic == "dom-storage2-changed") {
ok(expectedTypes.length > 0, "Not more then expected events encountered");
is(type, expectedTypes.shift(), "Expected type of the storage notificaiton");
tests.next();
}
}
}
// Listen for dom-storage2-changed notification
SpecialPowers.Services.obs.addObserver(onStorageChanged,
"dom-storage2-changed", false);
// add an empty-value key
localStorage.setItem("empty", "");
yield undefined;
localStorage.setItem("empty", "value-1");
yield undefined;
sessionStorage.setItem("empty", "");
yield undefined;
localStorage.removeItem("empty");
yield undefined;
sessionStorage.setItem("empty", "value-1");
yield undefined;
sessionStorage.removeItem("empty");
yield undefined;
localStorage.setItem("key1", "value-1");
yield undefined;
sessionStorage.setItem("key2", "value-2");
yield undefined;
localStorage.setItem("key1", "value-1-2");
yield undefined;
sessionStorage.setItem("key2", "value-2-2");
yield undefined;
localStorage.setItem("key3", "value-3");
yield undefined;
sessionStorage.setItem("key4", "value-4");
yield undefined;
sessionStorage.removeItem("key4");
yield undefined;
localStorage.setItem("key4", "value-4");
yield undefined;
sessionStorage.clear();
yield undefined;
localStorage.clear();
yield undefined;
SimpleTest.executeSoon(function () {
SpecialPowers.Services.obs.removeObserver(onStorageChanged,
"dom-storage2-changed", false);
is(expectedTypes.length, 0, "received the correct number of events");
sessionStorage.clear();
localStorage.clear();
tests = null;
SimpleTest.finish();
});
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="setup();">
</body>
</html>

View File

@ -805,6 +805,12 @@ interface WebGLExtensionDebugRendererInfo
const GLenum UNMASKED_RENDERER_WEBGL = 0x9246; const GLenum UNMASKED_RENDERER_WEBGL = 0x9246;
}; };
[NoInterfaceObject]
interface WebGLExtensionDebugShaders
{
DOMString getTranslatedShaderSource(WebGLShader? shader);
};
[NoInterfaceObject] [NoInterfaceObject]
interface WebGLExtensionDepthTexture interface WebGLExtensionDepthTexture
{ {

View File

@ -7,11 +7,14 @@
#include "WorkerScope.h" #include "WorkerScope.h"
#include "jsapi.h" #include "jsapi.h"
#include "mozilla/Debug.h"
#include "mozilla/dom/FunctionBinding.h" #include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h" #include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
#include "mozilla/dom/SharedWorkerGlobalScopeBinding.h" #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h"
#ifdef ANDROID
#include <android/log.h>
#endif
#include "Console.h" #include "Console.h"
#include "Location.h" #include "Location.h"
#include "Navigator.h" #include "Navigator.h"
@ -258,8 +261,13 @@ WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const
return; return;
} }
PrintToDebugger(aString.Value(), stdout, kPrintToStream NS_ConvertUTF16toUTF8 str(aString.Value());
| kPrintInfoLog);
#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", str.get());
#endif
fputs(str.get(), stdout);
fflush(stdout);
} }
DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate) DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(WorkerPrivate* aWorkerPrivate)

View File

@ -80,6 +80,9 @@ interface nsIWebBrowserChrome : nsISupports
// Whether this was opened by nsGlobalWindow::ShowModalDialog. // Whether this was opened by nsGlobalWindow::ShowModalDialog.
const unsigned long CHROME_MODAL_CONTENT_WINDOW = 0x00080000; const unsigned long CHROME_MODAL_CONTENT_WINDOW = 0x00080000;
// Whether this window should use remote (out-of-process) tabs.
const unsigned long CHROME_REMOTE_WINDOW = 0x00100000;
// Prevents new window animations on Mac OS X Lion. Ignored on other // Prevents new window animations on Mac OS X Lion. Ignored on other
// platforms. // platforms.
const unsigned long CHROME_MAC_SUPPRESS_ANIMATION = 0x01000000; const unsigned long CHROME_MAC_SUPPRESS_ANIMATION = 0x01000000;

View File

@ -17,7 +17,7 @@ NS_NewControllerCommandTable(nsIControllerCommandTable** aResult);
nsControllerCommandTable::nsControllerCommandTable() nsControllerCommandTable::nsControllerCommandTable()
: mCommandsTable(NUM_COMMANDS_BOUNDS, false) : mCommandsTable(NUM_COMMANDS_BOUNDS)
, mMutable(true) , mMutable(true)
{ {
} }
@ -40,15 +40,9 @@ NS_IMETHODIMP
nsControllerCommandTable::RegisterCommand(const char * aCommandName, nsIControllerCommand *aCommand) nsControllerCommandTable::RegisterCommand(const char * aCommandName, nsIControllerCommand *aCommand)
{ {
NS_ENSURE_TRUE(mMutable, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mMutable, NS_ERROR_FAILURE);
nsCStringKey commandKey(aCommandName); mCommandsTable.Put(nsDependentCString(aCommandName), aCommand);
if (mCommandsTable.Put(&commandKey, aCommand))
{
#if DEBUG
NS_WARNING("Replacing existing command -- ");
#endif
}
return NS_OK; return NS_OK;
} }
@ -58,10 +52,14 @@ nsControllerCommandTable::UnregisterCommand(const char * aCommandName, nsIContro
{ {
NS_ENSURE_TRUE(mMutable, NS_ERROR_FAILURE); NS_ENSURE_TRUE(mMutable, NS_ERROR_FAILURE);
nsCStringKey commandKey(aCommandName); nsDependentCString commandKey(aCommandName);
bool wasRemoved = mCommandsTable.Remove(&commandKey); if (!mCommandsTable.Get(commandKey, nullptr)) {
return wasRemoved ? NS_OK : NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
}
mCommandsTable.Remove(commandKey);
return NS_OK;
} }
@ -69,15 +67,14 @@ NS_IMETHODIMP
nsControllerCommandTable::FindCommandHandler(const char * aCommandName, nsIControllerCommand **outCommand) nsControllerCommandTable::FindCommandHandler(const char * aCommandName, nsIControllerCommand **outCommand)
{ {
NS_ENSURE_ARG_POINTER(outCommand); NS_ENSURE_ARG_POINTER(outCommand);
*outCommand = nullptr; *outCommand = nullptr;
nsCStringKey commandKey(aCommandName); nsCOMPtr<nsIControllerCommand> foundCommand;
nsISupports* foundCommand = mCommandsTable.Get(&commandKey); mCommandsTable.Get(nsDependentCString(aCommandName), getter_AddRefs(foundCommand));
if (!foundCommand) return NS_ERROR_FAILURE; if (!foundCommand) return NS_ERROR_FAILURE;
// no need to addref since the .Get does it for us foundCommand.forget(outCommand);
*outCommand = reinterpret_cast<nsIControllerCommand*>(foundCommand);
return NS_OK; return NS_OK;
} }
@ -90,18 +87,18 @@ nsControllerCommandTable::IsCommandEnabled(const char * aCommandName, nsISupport
NS_ENSURE_ARG_POINTER(aResult); NS_ENSURE_ARG_POINTER(aResult);
*aResult = false; *aResult = false;
// find the command // find the command
nsCOMPtr<nsIControllerCommand> commandHandler; nsCOMPtr<nsIControllerCommand> commandHandler;
FindCommandHandler(aCommandName, getter_AddRefs(commandHandler)); FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
if (!commandHandler) if (!commandHandler)
{ {
#if DEBUG #if DEBUG
NS_WARNING("Controller command table asked about a command that it does not handle -- "); NS_WARNING("Controller command table asked about a command that it does not handle -- ");
#endif #endif
return NS_OK; // we don't handle this command return NS_OK; // we don't handle this command
} }
return commandHandler->IsCommandEnabled(aCommandName, aCommandRefCon, aResult); return commandHandler->IsCommandEnabled(aCommandName, aCommandRefCon, aResult);
} }
@ -109,9 +106,9 @@ nsControllerCommandTable::IsCommandEnabled(const char * aCommandName, nsISupport
NS_IMETHODIMP NS_IMETHODIMP
nsControllerCommandTable::UpdateCommandState(const char * aCommandName, nsISupports *aCommandRefCon) nsControllerCommandTable::UpdateCommandState(const char * aCommandName, nsISupports *aCommandRefCon)
{ {
// find the command // find the command
nsCOMPtr<nsIControllerCommand> commandHandler; nsCOMPtr<nsIControllerCommand> commandHandler;
FindCommandHandler(aCommandName, getter_AddRefs(commandHandler)); FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
if (!commandHandler) if (!commandHandler)
{ {
#if DEBUG #if DEBUG
@ -119,7 +116,7 @@ nsControllerCommandTable::UpdateCommandState(const char * aCommandName, nsISuppo
#endif #endif
return NS_OK; // we don't handle this command return NS_OK; // we don't handle this command
} }
return NS_ERROR_NOT_IMPLEMENTED; return NS_ERROR_NOT_IMPLEMENTED;
} }
@ -131,8 +128,8 @@ nsControllerCommandTable::SupportsCommand(const char * aCommandName, nsISupports
// XXX: need to check the readonly and disabled states // XXX: need to check the readonly and disabled states
*aResult = false; *aResult = false;
// find the command // find the command
nsCOMPtr<nsIControllerCommand> commandHandler; nsCOMPtr<nsIControllerCommand> commandHandler;
FindCommandHandler(aCommandName, getter_AddRefs(commandHandler)); FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
@ -144,7 +141,7 @@ nsControllerCommandTable::SupportsCommand(const char * aCommandName, nsISupports
NS_IMETHODIMP NS_IMETHODIMP
nsControllerCommandTable::DoCommand(const char * aCommandName, nsISupports *aCommandRefCon) nsControllerCommandTable::DoCommand(const char * aCommandName, nsISupports *aCommandRefCon)
{ {
// find the command // find the command
nsCOMPtr<nsIControllerCommand> commandHandler; nsCOMPtr<nsIControllerCommand> commandHandler;
FindCommandHandler(aCommandName, getter_AddRefs(commandHandler)); FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
if (!commandHandler) if (!commandHandler)
@ -154,14 +151,14 @@ nsControllerCommandTable::DoCommand(const char * aCommandName, nsISupports *aCom
#endif #endif
return NS_OK; // we don't handle this command return NS_OK; // we don't handle this command
} }
return commandHandler->DoCommand(aCommandName, aCommandRefCon); return commandHandler->DoCommand(aCommandName, aCommandRefCon);
} }
NS_IMETHODIMP NS_IMETHODIMP
nsControllerCommandTable::DoCommandParams(const char *aCommandName, nsICommandParams *aParams, nsISupports *aCommandRefCon) nsControllerCommandTable::DoCommandParams(const char *aCommandName, nsICommandParams *aParams, nsISupports *aCommandRefCon)
{ {
// find the command // find the command
nsCOMPtr<nsIControllerCommand> commandHandler; nsCOMPtr<nsIControllerCommand> commandHandler;
FindCommandHandler(aCommandName, getter_AddRefs(commandHandler)); FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
if (!commandHandler) if (!commandHandler)
@ -178,7 +175,7 @@ nsControllerCommandTable::DoCommandParams(const char *aCommandName, nsICommandPa
NS_IMETHODIMP NS_IMETHODIMP
nsControllerCommandTable::GetCommandState(const char *aCommandName, nsICommandParams *aParams, nsISupports *aCommandRefCon) nsControllerCommandTable::GetCommandState(const char *aCommandName, nsICommandParams *aParams, nsISupports *aCommandRefCon)
{ {
// find the command // find the command
nsCOMPtr<nsIControllerCommand> commandHandler; nsCOMPtr<nsIControllerCommand> commandHandler;
FindCommandHandler(aCommandName, getter_AddRefs(commandHandler)); FindCommandHandler(aCommandName, getter_AddRefs(commandHandler));
if (!commandHandler) if (!commandHandler)
@ -207,6 +204,3 @@ NS_NewControllerCommandTable(nsIControllerCommandTable** aResult)
*aResult = newCommandTable; *aResult = newCommandTable;
return NS_OK; return NS_OK;
} }

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