author | David Anderson <danderson@mozilla.com> |
Tue, 29 Nov 2011 16:44:03 -0800 | |
changeset 105366 | a64147b4cccbdecd64ad218625df24981f5e86c5 |
parent 105365 | c1fbc6e49167ec14799de677940ebbbc81337912 (current diff) |
parent 80933 | 95bca70369ef6cbcbb642143ae8dc488b3cbf109 (diff) |
child 105367 | 485dcdd9dabd6133a9d86bd46c124424da462ae5 |
push id | 23447 |
push user | danderson@mozilla.com |
push date | Tue, 11 Sep 2012 17:34:27 +0000 |
treeherder | mozilla-central@fdfaef738a00 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 11.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/src/atk/nsApplicationAccessibleWrap.cpp +++ b/accessible/src/atk/nsApplicationAccessibleWrap.cpp @@ -39,37 +39,42 @@ * ***** END LICENSE BLOCK ***** */ #include "nsApplicationAccessibleWrap.h" #include "nsCOMPtr.h" #include "nsMai.h" #include "prlink.h" #include "prenv.h" -#include "nsIPrefBranch.h" +#include "mozilla/Preferences.h" +#include "nsIGConfService.h" #include "nsIServiceManager.h" #include "nsAutoPtr.h" #include "nsAccessibilityService.h" #include "AtkSocketAccessible.h" #include <gtk/gtk.h> #include <atk/atk.h> +using namespace mozilla; + typedef GType (* AtkGetTypeType) (void); GType g_atk_hyperlink_impl_type = G_TYPE_INVALID; static bool sATKChecked = false; static PRLibrary *sATKLib = nsnull; static const char sATKLibName[] = "libatk-1.0.so.0"; static const char sATKHyperlinkImplGetTypeSymbol[] = "atk_hyperlink_impl_get_type"; static const char sAccEnv [] = "GNOME_ACCESSIBILITY"; -static const char sSysPrefService [] = - "@mozilla.org/system-preference-service;1"; +static const char sUseSystemPrefsKey[] = + "config.use_system_prefs"; static const char sAccessibilityKey [] = "config.use_system_prefs.accessibility"; +static const char sGconfAccessibilityKey[] = + "/desktop/gnome/interface/accessibility"; /* gail function pointer */ static guint (* gail_add_global_event_listener) (GSignalEmissionHook listener, const gchar *event_type); static void (* gail_remove_global_event_listener) (guint remove_listener); static void (* gail_remove_key_event_listener) (guint remove_listener); static AtkObject * (*gail_get_root) (void); @@ -620,21 +625,27 @@ nsApplicationAccessibleWrap::Init() // check if accessibility enabled/disabled by environment variable bool isGnomeATEnabled = false; const char *envValue = PR_GetEnv(sAccEnv); if (envValue) { isGnomeATEnabled = !!atoi(envValue); } else { //check gconf-2 setting - nsresult rv; - nsCOMPtr<nsIPrefBranch> sysPrefService = - do_GetService(sSysPrefService, &rv); - if (NS_SUCCEEDED(rv) && sysPrefService) { - sysPrefService->GetBoolPref(sAccessibilityKey, &isGnomeATEnabled); + if (Preferences::GetBool(sUseSystemPrefsKey, false)) { + nsresult rv; + nsCOMPtr<nsIGConfService> gconf = + do_GetService(NS_GCONFSERVICE_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv) && gconf) { + gconf->GetBool(NS_LITERAL_CSTRING(sGconfAccessibilityKey), + &isGnomeATEnabled); + } + } else { + isGnomeATEnabled = + Preferences::GetBool(sAccessibilityKey, false); } } if (isGnomeATEnabled) { // load and initialize gail library nsresult rv = LoadGtkModule(sGail); if (NS_SUCCEEDED(rv)) { (*sGail.init)();
--- a/accessible/src/base/nsAccessibilityService.cpp +++ b/accessible/src/base/nsAccessibilityService.cpp @@ -45,16 +45,17 @@ #include "nsApplicationAccessibleWrap.h" #include "nsARIAGridAccessibleWrap.h" #include "nsARIAMap.h" #include "FocusManager.h" #include "nsIContentViewer.h" #include "nsCURILoader.h" #include "nsDocAccessible.h" +#include "nsHTMLCanvasAccessible.h" #include "nsHTMLImageMapAccessible.h" #include "nsHTMLLinkAccessible.h" #include "nsHTMLSelectAccessible.h" #include "nsHTMLTableAccessibleWrap.h" #include "nsHTMLTextAccessible.h" #include "nsHyperTextAccessibleWrap.h" #include "nsIAccessibilityService.h" #include "nsIAccessibleProvider.h" @@ -271,16 +272,26 @@ nsAccessibilityService::CreateHTMLCombob { nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell)); nsAccessible* accessible = new nsHTMLComboboxAccessible(aContent, weakShell); NS_IF_ADDREF(accessible); return accessible; } already_AddRefed<nsAccessible> +nsAccessibilityService::CreateHTMLCanvasAccessible(nsIContent* aContent, + nsIPresShell* aPresShell) +{ + nsCOMPtr<nsIWeakReference> weakShell(do_GetWeakReference(aPresShell)); + nsAccessible* accessible = new nsHTMLCanvasAccessible(aContent, weakShell); + NS_IF_ADDREF(accessible); + return accessible; +} + +already_AddRefed<nsAccessible> nsAccessibilityService::CreateHTMLImageAccessible(nsIContent* aContent, nsIPresShell* aPresShell) { nsAutoString mapElmName; aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::usemap, mapElmName); nsCOMPtr<nsIDOMHTMLMapElement> mapElm; if (nsIDocument* document = aContent->GetCurrentDoc()) { mapElm = do_QueryInterface(document->FindImageMap(mapElmName));
--- a/accessible/src/base/nsAccessibilityService.h +++ b/accessible/src/base/nsAccessibilityService.h @@ -78,16 +78,18 @@ public: bool aCanCreate); virtual already_AddRefed<nsAccessible> CreateHTMLBRAccessible(nsIContent* aContent, nsIPresShell* aPresShell); virtual already_AddRefed<nsAccessible> CreateHTML4ButtonAccessible(nsIContent* aContent, nsIPresShell* aPresShell); virtual already_AddRefed<nsAccessible> CreateHTMLButtonAccessible(nsIContent* aContent, nsIPresShell* aPresShell); + already_AddRefed<nsAccessible> + CreateHTMLCanvasAccessible(nsIContent* aContent, nsIPresShell* aPresShell); virtual already_AddRefed<nsAccessible> CreateHTMLCaptionAccessible(nsIContent* aContent, nsIPresShell* aPresShell); virtual already_AddRefed<nsAccessible> CreateHTMLCheckboxAccessible(nsIContent* aContent, nsIPresShell* aPresShell); virtual already_AddRefed<nsAccessible> CreateHTMLComboboxAccessible(nsIContent* aContent, nsIPresShell* aPresShell); virtual already_AddRefed<nsAccessible> CreateHTMLGroupboxAccessible(nsIContent* aContent, nsIPresShell* aPresShell);
--- a/accessible/src/base/nsAccessible.h +++ b/accessible/src/base/nsAccessible.h @@ -399,16 +399,22 @@ public: * Assert if child not in parent's cache if the cache was initialized at this * point. */ void TestChildCache(nsAccessible* aCachedChild) const; ////////////////////////////////////////////////////////////////////////////// // Downcasting and types + inline bool IsAbbreviation() const + { + return mContent->IsHTML() && + (mContent->Tag() == nsGkAtoms::abbr || mContent->Tag() == nsGkAtoms::acronym); + } + inline bool IsApplication() const { return mFlags & eApplicationAccessible; } bool IsAutoComplete() const { return mFlags & eAutoCompleteAccessible; } inline bool IsAutoCompletePopup() const { return mFlags & eAutoCompletePopupAccessible; } inline bool IsCombobox() const { return mFlags & eComboboxAccessible; }
--- a/accessible/src/base/nsRootAccessible.cpp +++ b/accessible/src/base/nsRootAccessible.cpp @@ -386,39 +386,35 @@ nsRootAccessible::ProcessDOMEvent(nsIDOM return; nsDocAccessible* targetDocument = accessible->GetDocAccessible(); NS_ASSERTION(targetDocument, "No document while accessible is in document?!"); nsINode* targetNode = accessible->GetNode(); #ifdef MOZ_XUL - bool isTree = targetNode->IsElement() && - targetNode->AsElement()->NodeInfo()->Equals(nsGkAtoms::tree, kNameSpaceID_XUL); - - if (isTree) { - nsRefPtr<nsXULTreeAccessible> treeAcc = do_QueryObject(accessible); - NS_ASSERTION(treeAcc, - "Accessible for xul:tree isn't nsXULTreeAccessible."); + nsRefPtr<nsXULTreeAccessible> treeAcc; + if (targetNode->IsElement() && + targetNode->AsElement()->NodeInfo()->Equals(nsGkAtoms::tree, + kNameSpaceID_XUL)) { + treeAcc = do_QueryObject(accessible); - if (treeAcc) { - if (eventType.EqualsLiteral("TreeViewChanged")) { - treeAcc->TreeViewChanged(); - return; - } + if (eventType.EqualsLiteral("TreeViewChanged")) { + treeAcc->TreeViewChanged(); + return; + } - if (eventType.EqualsLiteral("TreeRowCountChanged")) { - HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc); - return; - } - - if (eventType.EqualsLiteral("TreeInvalidated")) { - HandleTreeInvalidatedEvent(aDOMEvent, treeAcc); - return; - } + if (eventType.EqualsLiteral("TreeRowCountChanged")) { + HandleTreeRowCountChangedEvent(aDOMEvent, treeAcc); + return; + } + + if (eventType.EqualsLiteral("TreeInvalidated")) { + HandleTreeInvalidatedEvent(aDOMEvent, treeAcc); + return; } } #endif if (eventType.EqualsLiteral("RadioStateChange")) { PRUint64 state = accessible->State(); // radiogroup in prefWindow is exposed as a list, @@ -446,38 +442,36 @@ nsRootAccessible::ProcessDOMEvent(nsIDOM nsRefPtr<AccEvent> accEvent = new AccStateChangeEvent(accessible, states::CHECKED, isEnabled); nsEventShell::FireEvent(accEvent); return; } - nsAccessible *treeItemAccessible = nsnull; + nsAccessible* treeItemAcc = nsnull; #ifdef MOZ_XUL - // If it's a tree element, need the currently selected item - if (isTree) { - treeItemAccessible = accessible->CurrentItem(); - if (treeItemAccessible) - accessible = treeItemAccessible; + // If it's a tree element, need the currently selected item. + if (treeAcc) { + treeItemAcc = accessible->CurrentItem(); + if (treeItemAcc) + accessible = treeItemAcc; } -#endif -#ifdef MOZ_XUL - if (treeItemAccessible && eventType.EqualsLiteral("OpenStateChange")) { + if (treeItemAcc && eventType.EqualsLiteral("OpenStateChange")) { PRUint64 state = accessible->State(); bool isEnabled = (state & states::EXPANDED) != 0; nsRefPtr<AccEvent> accEvent = new AccStateChangeEvent(accessible, states::EXPANDED, isEnabled); nsEventShell::FireEvent(accEvent); return; } - if (treeItemAccessible && eventType.EqualsLiteral("select")) { + if (treeItemAcc && eventType.EqualsLiteral("select")) { // XXX: We shouldn't be based on DOM select event which doesn't provide us // any context info. We should integrate into nsTreeSelection instead. // If multiselect tree, we should fire selectionadd or selection removed if (FocusMgr()->HasDOMFocus(targetNode)) { nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSel = do_QueryInterface(targetNode); nsAutoString selType; multiSel->GetSelType(selType); @@ -486,18 +480,20 @@ nsRootAccessible::ProcessDOMEvent(nsIDOM // for each tree item. Perhaps each tree item will need to cache its // selection state and fire an event after a DOM "select" event when // that state changes. nsXULTreeAccessible::UpdateTreeSelection(); nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION_WITHIN, accessible); return; } - nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_SELECTION, - treeItemAccessible); + nsRefPtr<AccSelChangeEvent> selChangeEvent = + new AccSelChangeEvent(treeAcc, treeItemAcc, + AccSelChangeEvent::eSelectionAdd); + nsEventShell::FireEvent(selChangeEvent); return; } } else #endif if (eventType.EqualsLiteral("AlertActive")) { nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_ALERT, accessible); }
--- a/accessible/src/html/Makefile.in +++ b/accessible/src/html/Makefile.in @@ -45,16 +45,17 @@ include $(DEPTH)/config/autoconf.mk MODULE = accessibility LIBRARY_NAME = accessibility_html_s LIBXUL_LIBRARY = 1 CPPSRCS = \ + nsHTMLCanvasAccessible.cpp \ nsHTMLFormControlAccessible.cpp \ nsHTMLImageAccessible.cpp \ nsHTMLImageMapAccessible.cpp \ nsHTMLLinkAccessible.cpp \ nsHTMLSelectAccessible.cpp \ nsHTMLTableAccessible.cpp \ nsHTMLTextAccessible.cpp \ nsHyperTextAccessible.cpp \
new file mode 100644 --- /dev/null +++ b/accessible/src/html/nsHTMLCanvasAccessible.cpp @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsHTMLCanvasAccessible.h" + +using namespace mozilla::a11y; + +nsHTMLCanvasAccessible:: + nsHTMLCanvasAccessible(nsIContent* aContent, nsIWeakReference* aShell) : + nsHyperTextAccessible(aContent, aShell) +{ +} + +PRUint32 +nsHTMLCanvasAccessible::NativeRole() +{ + return nsIAccessibleRole::ROLE_CANVAS; +}
new file mode 100644 --- /dev/null +++ b/accessible/src/html/nsHTMLCanvasAccessible.h @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsHyperTextAccessible.h" + +#ifndef _nsHTMLCanvasAccessible_H_ +#define _nsHTMLCanvasAccessible_H_ + +/** + * HTML canvas accessible (html:canvas). + */ +class nsHTMLCanvasAccessible : public nsHyperTextAccessible +{ +public: + nsHTMLCanvasAccessible(nsIContent* aContent, nsIWeakReference* aShell); + virtual ~nsHTMLCanvasAccessible() { } + + // nsAccessible + virtual PRUint32 NativeRole(); +}; + +#endif
--- a/accessible/src/html/nsHTMLTableAccessible.cpp +++ b/accessible/src/html/nsHTMLTableAccessible.cpp @@ -119,31 +119,58 @@ nsresult nsHTMLTableCellAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes) { if (IsDefunct()) return NS_ERROR_FAILURE; nsresult rv = nsHyperTextAccessibleWrap::GetAttributesInternal(aAttributes); NS_ENSURE_SUCCESS(rv, rv); + // table-cell-index attribute nsCOMPtr<nsIAccessibleTable> tableAcc(GetTableAccessible()); if (!tableAcc) return NS_OK; PRInt32 rowIdx = -1, colIdx = -1; rv = GetCellIndexes(rowIdx, colIdx); NS_ENSURE_SUCCESS(rv, rv); PRInt32 idx = -1; rv = tableAcc->GetCellIndexAt(rowIdx, colIdx, &idx); NS_ENSURE_SUCCESS(rv, rv); nsAutoString stringIdx; stringIdx.AppendInt(idx); nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::tableCellIndex, stringIdx); + + // abbr attribute + + // Pick up object attribute from abbr DOM element (a child of the cell) or + // from abbr DOM attribute. + nsAutoString abbrText; + if (GetChildCount() == 1) { + nsAccessible* abbr = FirstChild(); + if (abbr->IsAbbreviation()) { + nsTextEquivUtils:: + AppendTextEquivFromTextContent(abbr->GetContent()->GetFirstChild(), + &abbrText); + } + } + if (abbrText.IsEmpty()) + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::abbr, abbrText); + + if (!abbrText.IsEmpty()) + nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::abbr, abbrText); + + // axis attribute + nsAutoString axisText; + mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::axis, axisText); + if (!axisText.IsEmpty()) + nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::axis, axisText); + return NS_OK; } //////////////////////////////////////////////////////////////////////////////// // nsHTMLTableCellAccessible: nsIAccessibleTableCell implementation NS_IMETHODIMP nsHTMLTableCellAccessible::GetTable(nsIAccessibleTable **aTable)
--- a/accessible/src/html/nsHyperTextAccessible.cpp +++ b/accessible/src/html/nsHyperTextAccessible.cpp @@ -2054,16 +2054,35 @@ nsHyperTextAccessible::ScrollSubstringTo } return NS_OK; } //////////////////////////////////////////////////////////////////////////////// // nsAccessible public +nsresult +nsHyperTextAccessible::GetNameInternal(nsAString& aName) +{ + nsresult rv = nsAccessibleWrap::GetNameInternal(aName); + NS_ENSURE_SUCCESS(rv, rv); + + // Get name from title attribute for HTML abbr and acronym elements making it + // a valid name from markup. Otherwise their name isn't picked up by recursive + // name computation algorithm. See NS_OK_NAME_FROM_TOOLTIP. + if (aName.IsEmpty() && IsAbbreviation()) { + nsAutoString name; + if (mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, name)) { + name.CompressWhitespace(); + aName = name; + } + } + return NS_OK; +} + void nsHyperTextAccessible::InvalidateChildren() { mOffsets.Clear(); nsAccessibleWrap::InvalidateChildren(); }
--- a/accessible/src/html/nsHyperTextAccessible.h +++ b/accessible/src/html/nsHyperTextAccessible.h @@ -81,16 +81,17 @@ public: NS_DECL_NSIACCESSIBLETEXT NS_DECL_NSIACCESSIBLEHYPERTEXT NS_DECL_NSIACCESSIBLEEDITABLETEXT NS_DECLARE_STATIC_IID_ACCESSOR(NS_HYPERTEXTACCESSIBLE_IMPL_CID) // nsAccessible virtual PRInt32 GetLevelInternal(); virtual nsresult GetAttributesInternal(nsIPersistentProperties *aAttributes); + virtual nsresult GetNameInternal(nsAString& aName); virtual PRUint32 NativeRole(); virtual PRUint64 NativeState(); virtual void InvalidateChildren(); virtual bool RemoveChild(nsAccessible* aAccessible); // nsHyperTextAccessible (static helper method)
--- a/accessible/src/msaa/nsWinUtils.cpp +++ b/accessible/src/msaa/nsWinUtils.cpp @@ -38,19 +38,22 @@ * * ***** END LICENSE BLOCK ***** */ #include "nsWinUtils.h" #include "nsIWinAccessNode.h" #include "nsRootAccessible.h" +#include "mozilla/Preferences.h" #include "nsArrayUtils.h" #include "nsIDocShellTreeItem.h" +using namespace mozilla; + // Window property used by ipc related code in identifying accessible // tab windows. const PRUnichar* kPropNameTabContent = L"AccessibleTabWindow"; HRESULT nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array, long *aIA2ArrayLen) { @@ -180,18 +183,17 @@ nsWinUtils::HideNativeWindow(HWND aWnd) ::SetWindowPos(aWnd, NULL, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); } bool nsWinUtils::IsWindowEmulationFor(LPCWSTR kModuleHandle) { -#ifdef MOZ_E10S_COMPAT // Window emulation is always enabled in multiprocess Firefox. - return kModuleHandle ? ::GetModuleHandleW(kModuleHandle) : true; -#else + if (Preferences::GetBool("browser.tabs.remote")) + return kModuleHandle ? ::GetModuleHandleW(kModuleHandle) : true; + return kModuleHandle ? ::GetModuleHandleW(kModuleHandle) : ::GetModuleHandleW(kJAWSModuleHandle) || ::GetModuleHandleW(kWEModuleHandle) || ::GetModuleHandleW(kDolphinModuleHandle); -#endif }
--- a/accessible/tests/mochitest/attributes/test_obj.html +++ b/accessible/tests/mochitest/attributes/test_obj.html @@ -86,17 +86,20 @@ https://bugzilla.mozilla.org/show_bug.cg testAttrs("liveGroup", {"live" : "polite"}, true); testAttrs("liveGroupChild", {"container-live" : "polite"}, true); testAttrs("liveGroup", {"container-live-role" : "group"}, true); testAttrs("liveGroupChild", {"container-live-role" : "group"}, true); // html testAttrs("radio", {"checkable" : "true"}, true); testAttrs("checkbox", {"checkable" : "true"}, true); - testAttrs("draggable", {"draggable" : "true"}, true); + testAttrs("draggable", {"draggable" : "true"}, true); + testAttrs("th1", { "abbr": "SS#" }, true); + testAttrs("th2", { "abbr": "SS#" }, true); + testAttrs("th2", { "axis": "social" }, true); SimpleTest.finish(); } SimpleTest.waitForExplicitFinish(); addA11yLoadEvent(doTest); </script> </head> @@ -170,10 +173,16 @@ https://bugzilla.mozilla.org/show_bug.cg <div id="liveGroup" role="group" aria-live="polite"> excuse <div id="liveGroupChild">me</div> </div> <!-- html --> <input id="radio" type="radio"/> <input id="checkbox" type="checkbox"/> <div id="draggable" draggable="true">Draggable div</div> + <table> + <tr> + <th id="th1"><abbr title="Social Security Number">SS#</abbr></th> + <th id="th2" abbr="SS#" axis="social">Social Security Number</th> + </tr> + </table> </body> </html>
--- a/accessible/tests/mochitest/name/test_general.html +++ b/accessible/tests/mochitest/name/test_general.html @@ -127,16 +127,20 @@ // ARIA role option is presented allowing the name calculation from // visible children (bug 443081). testName("lb_opt1_children_hidden", "i am visible"); // Get the name from subtree of menuitem crossing role nothing to get // the name from its children. testName("tablemenuitem", "menuitem 1"); + // Get the name from child acronym title attribute rather than from + // acronym content. + testName("label_with_acronym", "O A T F World Wide Web"); + ////////////////////////////////////////////////////////////////////////// // title attribute // If nothing is left. Let's try title attribute. testName("btn_title", "title"); ////////////////////////////////////////////////////////////////////////// // textarea name @@ -215,16 +219,21 @@ title="Use placeholder as name if name is otherwise empty"> Mozilla Bug 604391 </a> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=669312" title="Accessible name is duplicated when input has a label associated uisng for/id and is wrapped around the input"> Mozilla Bug 669312 </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=704416" + title="HTML acronym and abbr names should be provided by @title"> + Mozilla Bug 704416 + </a> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"> </pre> <!-- aria-label, simple label --> <span id="btn_simple_aria_label" role="button" aria-label="I am a button"/> <br/> @@ -390,16 +399,21 @@ <tr role="menuitem" id="tablemenuitem"> <td>menuitem 1</td> </tr> <tr role="menuitem"> <td>menuitem 2</td> </tr> </table> + <label id="label_with_acronym"> + <acronym title="O A T F">OATF</acronym> + <abbr title="World Wide Web">WWW</abbr> + </label> + <!-- name from title attribute --> <span id="btn_title" role="group" title="title">15</span> <!-- A textarea nested in a label with a text child (bug #453371). --> <form> <label>Story <textarea id="textareawithchild" name="name">Foo</textarea> is ended.
--- a/accessible/tests/mochitest/role.js +++ b/accessible/tests/mochitest/role.js @@ -2,16 +2,17 @@ // Role constants const ROLE_ALERT = nsIAccessibleRole.ROLE_ALERT; const ROLE_ANIMATION = nsIAccessibleRole.ROLE_ANIMATION; const ROLE_APPLICATION = nsIAccessibleRole.ROLE_APPLICATION; const ROLE_APP_ROOT = nsIAccessibleRole.ROLE_APP_ROOT; const ROLE_AUTOCOMPLETE = nsIAccessibleRole.ROLE_AUTOCOMPLETE; const ROLE_BUTTONDROPDOWNGRID = nsIAccessibleRole.ROLE_BUTTONDROPDOWNGRID; +const ROLE_CANVAS = nsIAccessibleRole.ROLE_CANVAS; const ROLE_CAPTION = nsIAccessibleRole.ROLE_CAPTION; const ROLE_CELL = nsIAccessibleRole.ROLE_CELL; const ROLE_CHECKBUTTON = nsIAccessibleRole.ROLE_CHECKBUTTON; const ROLE_CHROME_WINDOW = nsIAccessibleRole.ROLE_CHROME_WINDOW; const ROLE_COMBOBOX = nsIAccessibleRole.ROLE_COMBOBOX; const ROLE_COMBOBOX_LIST = nsIAccessibleRole.ROLE_COMBOBOX_LIST; const ROLE_COMBOBOX_OPTION = nsIAccessibleRole.ROLE_COMBOBOX_OPTION; const ROLE_COLUMNHEADER = nsIAccessibleRole.ROLE_COLUMNHEADER;
--- a/accessible/tests/mochitest/tree/Makefile.in +++ b/accessible/tests/mochitest/tree/Makefile.in @@ -47,16 +47,17 @@ include $(topsrcdir)/config/rules.mk _TEST_FILES =\ dockids.html \ $(warning test_applicationacc.xul temporarily disabled, see bug 561508) \ test_aria_globals.html \ test_aria_imgmap.html \ test_aria_presentation.html \ test_button.xul \ + test_canvas.html \ test_combobox.xul \ test_cssoverflow.html \ test_dochierarchy.html \ test_dockids.html \ test_filectrl.html \ test_formctrl.html \ test_formctrl.xul \ test_gencontent.html \
new file mode 100644 --- /dev/null +++ b/accessible/tests/mochitest/tree/test_canvas.html @@ -0,0 +1,57 @@ +<!DOCTYPE html> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=495912 +--> +<head> + <title>File Input Control tests</title> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script type="application/javascript" + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../role.js"></script> + + <script type="application/javascript"> + function doTest() + { + var accTree = { + role: ROLE_CANVAS, + children: [ + ] + }; + testAccessibleTree("canvas", accTree); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTest); + </script> +</head> +<body> + + <a target="_blank" + title="Expose alternative content in Canvas element to ATs" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=495912">Mozilla Bug 495912</a> + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <canvas id="canvas" tabindex="0"> + fallback content. + </canvas> + + <script type="text/javascript"> + var c=document.getElementById("canvas"); + var cxt=c.getContext("2d"); + cxt.fillStyle="#005500"; + cxt.fillRect(0,0,150,75); + </script> + +</body> +</html>
--- a/aclocal.m4 +++ b/aclocal.m4 @@ -7,16 +7,17 @@ builtin(include, build/autoconf/glib.m4) builtin(include, build/autoconf/nspr.m4)dnl builtin(include, build/autoconf/nss.m4)dnl builtin(include, build/autoconf/pkg.m4)dnl builtin(include, build/autoconf/freetype2.m4)dnl builtin(include, build/autoconf/codeset.m4)dnl builtin(include, build/autoconf/altoptions.m4)dnl builtin(include, build/autoconf/mozprog.m4)dnl builtin(include, build/autoconf/mozheader.m4)dnl +builtin(include, build/autoconf/mozcommonheader.m4)dnl builtin(include, build/autoconf/acwinpaths.m4)dnl builtin(include, build/autoconf/lto.m4)dnl builtin(include, build/autoconf/gcc-pr49911.m4)dnl builtin(include, build/autoconf/frameptr.m4)dnl MOZ_PROG_CHECKMSYS() # Read the user's .mozconfig script. We can't do this in
--- a/browser/app/blocklist.xml +++ b/browser/app/blocklist.xml @@ -1,10 +1,10 @@ <?xml version="1.0"?> -<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1318359094000"> +<blocklist xmlns="http://www.mozilla.org/2006/addons-blocklist" lastupdate="1321712096000"> <emItems> <emItem blockID="i41" id="{99079a25-328f-4bd4-be04-00955acaa0a7}"> <versionRange minVersion="0.1" maxVersion="4.3.1.00" severity="1"> </versionRange> </emItem> <emItem blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}"> <versionRange minVersion=" " severity="1"> </versionRange> @@ -112,16 +112,23 @@ <versionRange minVersion="3.5.7" maxVersion="*" /> </targetApplication> </versionRange> </emItem> <emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}"> <versionRange minVersion="2.2" maxVersion="2.2"> </versionRange> </emItem> + <emItem blockID="i45" id="{22119944-ED35-4ab1-910B-E619EA06A115}"> + <versionRange minVersion="0.1" maxVersion="7.6.1"> + <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"> + <versionRange minVersion="8.0a1" maxVersion="*" /> + </targetApplication> + </versionRange> + </emItem> <emItem blockID="i3" id="langpack-vi-VN@firefox.mozilla.org"> <versionRange minVersion="2.0" maxVersion="2.0"> </versionRange> </emItem> <emItem blockID="i7" id="{2224e955-00e9-4613-a844-ce69fccaae91}"> </emItem> <emItem blockID="i24" id="{6E19037A-12E3-4295-8915-ED48BC341614}"> <versionRange minVersion="0.1" maxVersion="1.3.328.4" severity="1">
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1033,16 +1033,28 @@ pref("devtools.gcli.enable", false); pref("devtools.hud.height", 0); // Remember the Web Console position. Possible values: // above - above the web page, // below - below the web page, // window - in a separate window/popup panel. pref("devtools.webconsole.position", "above"); +// Remember the Web Console filters +pref("devtools.webconsole.filter.network", true); +pref("devtools.webconsole.filter.networkinfo", true); +pref("devtools.webconsole.filter.csserror", true); +pref("devtools.webconsole.filter.cssparser", true); +pref("devtools.webconsole.filter.exception", true); +pref("devtools.webconsole.filter.jswarn", true); +pref("devtools.webconsole.filter.error", true); +pref("devtools.webconsole.filter.warn", true); +pref("devtools.webconsole.filter.info", true); +pref("devtools.webconsole.filter.log", true); + // The number of lines that are displayed in the web console for the Net, // CSS, JS and Web Developer categories. pref("devtools.hud.loglimit.network", 200); pref("devtools.hud.loglimit.cssparser", 200); pref("devtools.hud.loglimit.exception", 200); pref("devtools.hud.loglimit.console", 200); // The developer tools editor configuration:
--- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -236,18 +236,30 @@ #ifdef XP_GNOME <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/> <key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/> #else <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/> #endif <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/> <key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/> - <key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();" modifiers="accel,shift"/> - <key id="key_inspect" key="&inspectMenu.commandkey;" command="Tools:Inspect" modifiers="accel,shift"/> + <key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();" +#ifdef XP_MACOSX + modifiers="accel,alt" +#else + modifiers="accel,shift" +#endif + /> + <key id="key_inspect" key="&inspectMenu.commandkey;" command="Tools:Inspect" +#ifdef XP_MACOSX + modifiers="accel,alt" +#else + modifiers="accel,shift" +#endif + /> <key id="key_scratchpad" keycode="&scratchpad.keycode;" modifiers="shift" keytext="&scratchpad.keytext;" command="Tools:Scratchpad"/> <key id="key_styleeditor" keycode="&styleeditor.keycode;" modifiers="shift" keytext="&styleeditor.keytext;" command="Tools:StyleEditor"/> <key id="openFileKb" key="&openFileCmd.commandkey;" command="Browser:OpenFile" modifiers="accel"/> <key id="key_savePage" key="&savePageCmd.commandkey;" command="Browser:SavePage" modifiers="accel"/> <key id="printKb" key="&printCmd.commandkey;" command="cmd_print" modifiers="accel"/> <key id="key_close" key="&closeCmd.key;" command="cmd_close" modifiers="accel"/>
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3476,17 +3476,16 @@ const BrowserSearch = { // SearchService._addEngineToStore() should fail for such an engine), // but let's be on the safe side. if (!submission) return; openLinkIn(submission.uri.spec, useNewTab ? "tab" : "current", { postData: submission.postData, - inBackground: false, relatedToCurrent: true }); }, /** * Returns the search bar element if it is present in the toolbar, null otherwise. */ get searchBar() { return document.getElementById("searchbar"); @@ -3946,16 +3945,19 @@ var FullScreen = { let focusManger = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); if (focusManger.activeWindow != window) { // The top-level window has lost focus since the request to enter // full-screen was made. Cancel full-screen. document.mozCancelFullScreen(); return; } + if (gFindBarInitialized) + gFindBar.close(); + this.showWarning(true); // Exit DOM full-screen mode upon open, close, or change tab. gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen); gBrowser.tabContainer.addEventListener("TabClose", this.exitDomFullScreen); gBrowser.tabContainer.addEventListener("TabSelect", this.exitDomFullScreen); // Exit DOM full-screen mode when the browser window loses focus (ALT+TAB, etc).
--- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -413,17 +413,17 @@ nsContextMenu.prototype = { var onMedia = (this.onVideo || this.onAudio); // Several mutually exclusive items... play/pause, mute/unmute, show/hide this.showItem("context-media-play", onMedia && (this.target.paused || this.target.ended)); this.showItem("context-media-pause", onMedia && !this.target.paused && !this.target.ended); this.showItem("context-media-mute", onMedia && !this.target.muted); this.showItem("context-media-unmute", onMedia && this.target.muted); this.showItem("context-media-showcontrols", onMedia && !this.target.controls); this.showItem("context-media-hidecontrols", onMedia && this.target.controls); - this.showItem("context-video-fullscreen", this.onVideo); + this.showItem("context-video-fullscreen", this.onVideo && this.target.ownerDocument.mozFullScreenElement == null); var statsShowing = this.onVideo && this.target.wrappedJSObject.mozMediaStatisticsShowing; this.showItem("context-video-showstats", this.onVideo && this.target.controls && !statsShowing); this.showItem("context-video-hidestats", this.onVideo && this.target.controls && statsShowing); // Disable them when there isn't a valid media source loaded. if (onMedia) { var hasError = this.target.error != null || this.target.networkState == this.target.NETWORK_NO_SOURCE; @@ -854,20 +854,25 @@ nsContextMenu.prototype = { canvas.width = video.videoWidth; canvas.height = video.videoHeight; var ctxDraw = canvas.getContext("2d"); ctxDraw.drawImage(video, 0, 0); saveImageURL(canvas.toDataURL("image/jpeg", ""), name, "SaveImageTitle", true, false, document.documentURIObject); }, fullScreenVideo: function () { - this.target.pause(); - - openDialog("chrome://browser/content/fullscreen-video.xhtml", - "", "chrome,centerscreen,dialog=no", this.target); + let video = this.target; + if (document.mozFullScreenEnabled) + video.mozRequestFullScreen(); + else { + // Fallback for the legacy full-screen video implementation. + video.pause(); + openDialog("chrome://browser/content/fullscreen-video.xhtml", + "", "chrome,centerscreen,dialog=no", video); + } }, // Change current window to the URL of the background image. viewBGImage: function(e) { urlSecurityCheck(this.bgImageURL, this.browser.contentPrincipal, Ci.nsIScriptSecurityManager.DISALLOW_SCRIPT); var doc = this.target.ownerDocument;
--- a/browser/components/migration/content/migration.js +++ b/browser/components/migration/content/migration.js @@ -335,16 +335,19 @@ var MigrationWizard = { source = "sourceNameIE"; break; case "opera": source = "sourceNameOpera"; break; case "safari": source = "sourceNameSafari"; break; + case "chrome": + source = "sourceNameChrome"; + break; } // semi-wallpaper for crash when multiple profiles exist, since we haven't initialized mSourceProfile in places this._migrator.getMigrateData(this._selectedProfile, this._autoMigrate); var oldHomePageURL = this._migrator.sourceHomePageURL; if (oldHomePageURL && source) {
--- a/browser/components/migration/content/migration.xul +++ b/browser/components/migration/content/migration.xul @@ -74,16 +74,17 @@ #elifdef XP_UNIX <radio id="opera" label="&importFromOpera.label;" accesskey="&importFromOpera.accesskey;"/> #elifdef XP_WIN #ifndef NO_IE_MIGRATOR <radio id="ie" label="&importFromIE.label;" accesskey="&importFromIE.accesskey;"/> #endif <radio id="opera" label="&importFromOpera.label;" accesskey="&importFromOpera.accesskey;"/> #endif + <radio id="chrome" label="&importFromChrome.label;" accesskey="&importFromChrome.accesskey;"/> <radio id="fromfile" label="&importFromHTMLFile.label;" accesskey="&importFromHTMLFile.accesskey;" hidden="true"/> <radio id="nothing" label="&importFromNothing.label;" accesskey="&importFromNothing.accesskey;" hidden="true"/> </radiogroup> <label id="noSources" hidden="true">&noMigrationSources.label;</label> </wizardpage> <wizardpage id="selectProfile" pageid="selectProfile" label="&selectProfile.title;" next="importItems"
new file mode 100644 --- /dev/null +++ b/browser/components/migration/src/BrowserProfileMigrators.manifest @@ -0,0 +1,2 @@ +component {4cec1de4-1671-4fc3-a53e-6c539dc77a26} ChromeProfileMigrator.js +contract @mozilla.org/profile/migrator;1?app=browser&type=chrome {4cec1de4-1671-4fc3-a53e-6c539dc77a26}
new file mode 100644 --- /dev/null +++ b/browser/components/migration/src/ChromeProfileMigrator.js @@ -0,0 +1,532 @@ +/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 sts=2 et + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * The Original Code is the Browser Profile Migrator. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Makoto Kato <m_kato@ga2.so-net.ne.jp> (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +const LOCAL_FILE_CID = "@mozilla.org/file/local;1"; +const FILE_INPUT_STREAM_CID = "@mozilla.org/network/file-input-stream;1"; + +const BUNDLE_MIGRATION = "chrome://browser/locale/migration/migration.properties"; + +const MIGRATE_ALL = 0x0000; +const MIGRATE_SETTINGS = 0x0001; +const MIGRATE_COOKIES = 0x0002; +const MIGRATE_HISTORY = 0x0004; +const MIGRATE_FORMDATA = 0x0008; +const MIGRATE_PASSWORDS = 0x0010; +const MIGRATE_BOOKMARKS = 0x0020; +const MIGRATE_OTHERDATA = 0x0040; + +const S100NS_FROM1601TO1970 = 0x19DB1DED53E8000; +const S100NS_PER_MS = 10; + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/Services.jsm"); +Components.utils.import("resource://gre/modules/PlacesUtils.jsm"); +Components.utils.import("resource://gre/modules/NetUtil.jsm"); + +XPCOMUtils.defineLazyGetter(this, "bookmarksSubfolderTitle", function () { + // get "import from google chrome" string for folder + let strbundle = + Services.strings.createBundle(BUNDLE_MIGRATION); + let sourceNameChrome = strbundle.GetStringFromName("sourceNameChrome"); + return strbundle.formatStringFromName("importedBookmarksFolder", + [sourceNameChrome], + 1); +}); + +/* + * Convert Chrome time format to Date object + * + * @param aTime + * Chrome time + * @return converted Date object + * @note Google Chrome uses FILETIME / 10 as time. + * FILETIME is based on same structure of Windows. + */ +function chromeTimeToDate(aTime) +{ + return new Date((aTime * S100NS_PER_MS - S100NS_FROM1601TO1970 ) / 10000); +} + +/* + * Insert bookmark items into specific folder. + * + * @param aFolderId + * id of folder where items will be inserted + * @param aItems + * bookmark items to be inserted + */ +function insertBookmarkItems(aFolderId, aItems) +{ + for (let i = 0; i < aItems.length; i++) { + let item = aItems[i]; + + try { + if (item.type == "url") { + PlacesUtils.bookmarks.insertBookmark(aFolderId, + NetUtil.newURI(item.url), + PlacesUtils.bookmarks.DEFAULT_INDEX, + item.name); + } else if (item.type == "folder") { + let newFolderId = + PlacesUtils.bookmarks.createFolder(aFolderId, + item.name, + PlacesUtils.bookmarks.DEFAULT_INDEX); + + insertBookmarkItems(newFolderId, item.children); + } + } catch (e) { + Cu.reportError(e); + } + } +} + +function ChromeProfileMigrator() +{ +} + +ChromeProfileMigrator.prototype = { + _paths: { + bookmarks : null, + cookies : null, + history : null, + prefs : null, + }, + + _homepageURL : null, + _replaceBookmarks : false, + + /* + * Notify to observers to start migration + * + * @param aType + * notification type such as MIGRATE_BOOKMARKS + */ + + _notifyStart : function Chrome_notifyStart(aType) + { + Services.obs.notifyObservers(null, "Migration:ItemBeforeMigrate", aType); + this._pendingCount++; + }, + + /* + * Notify to observers to finish migration for item + * If all items are finished, it sends migration end notification. + * + * @param aType + * notification type such as MIGRATE_BOOKMARKS + */ + _notifyCompleted : function Chrome_notifyIfCompleted(aType) + { + Services.obs.notifyObservers(null, "Migration:ItemAfterMigrate", aType); + if (--this._pendingCount == 0) { + // All items are migrated, so we have to send end notification. + Services.obs.notifyObservers(null, "Migration:Ended", null); + } + }, + + /* + * Migrating bookmark items + */ + _migrateBookmarks : function Chrome_migrateBookmarks() + { + this._notifyStart(MIGRATE_BOOKMARKS); + + try { + PlacesUtils.bookmarks.runInBatchMode({ + _self : this, + runBatched : function (aUserData) { + let migrator = this._self; + let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile); + file.initWithPath(migrator._paths.bookmarks); + + NetUtil.asyncFetch(file, function(aInputStream, aResultCode) { + if (!Components.isSuccessCode(aResultCode)) { + migrator._notifyCompleted(MIGRATE_BOOKMARKS); + return; + } + + // Parse Chrome bookmark file that is JSON format + let bookmarkJSON = NetUtil.readInputStreamToString(aInputStream, + aInputStream.available(), + { charset : "UTF-8" }); + let roots = JSON.parse(bookmarkJSON).roots; + + // Importing bookmark bar items + if (roots.bookmark_bar.children && + roots.bookmark_bar.children.length > 0) { + // Toolbar + let parentId = PlacesUtils.toolbarFolderId; + if (!migrator._replaceBookmarks) { + parentId = + PlacesUtils.bookmarks.createFolder(parentId, + bookmarksSubfolderTitle, + PlacesUtils.bookmarks.DEFAULT_INDEX); + } + insertBookmarkItems(parentId, roots.bookmark_bar.children); + } + + // Importing bookmark menu items + if (roots.other.children && + roots.other.children.length > 0) { + // Bookmark menu + let parentId = PlacesUtils.bookmarksMenuFolderId; + if (!migrator._replaceBookmarks) { + parentId = + PlacesUtils.bookmarks.createFolder(parentId, + bookmarksSubfolderTitle, + PlacesUtils.bookmarks.DEFAULT_INDEX); + } + insertBookmarkItems(parentId, roots.other.children); + } + + migrator._notifyCompleted(MIGRATE_BOOKMARKS); + }); + } + }, null); + } catch (e) { + Cu.reportError(e); + this._notifyCompleted(MIGRATE_BOOKMARKS); + } + }, + + /* + * Migrating history + */ + _migrateHistory : function Chrome_migrateHistory() + { + this._notifyStart(MIGRATE_HISTORY); + + try { + PlacesUtils.history.runInBatchMode({ + _self : this, + runBatched : function (aUserData) { + // access sqlite3 database of Chrome's history + let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile); + file.initWithPath(this._self._paths.history); + + let dbConn = Services.storage.openUnsharedDatabase(file); + let stmt = dbConn.createAsyncStatement( + "SELECT url, title, last_visit_time, typed_count FROM urls WHERE hidden = 0"); + + stmt.executeAsync({ + _asyncHistory : Cc["@mozilla.org/browser/history;1"] + .getService(Ci.mozIAsyncHistory), + _db : dbConn, + _self : this._self, + handleResult : function(aResults) { + let places = []; + for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) { + try { + // if having typed_count, we changes transition type to typed. + let transType = PlacesUtils.history.TRANSITION_LINK; + if (row.getResultByName("typed_count") > 0) + transType = PlacesUtils.history.TRANSITION_TYPED; + + places.push({ + uri: NetUtil.newURI(row.getResultByName("url")), + title: row.getResultByName("title"), + visits: [{ + transitionType: transType, + visitDate: chromeTimeToDate( + row.getResultByName( + "last_visit_time")) * 1000, + }], + }); + } catch (e) { + Cu.reportError(e); + } + } + + try { + this._asyncHistory.updatePlaces(places); + } catch (e) { + Cu.reportError(e); + } + }, + + handleError : function(aError) { + Cu.reportError("Async statement execution returned with '" + + aError.result + "', '" + aError.message + "'"); + }, + + handleCompletion : function(aReason) { + this._db.asyncClose(); + this._self._notifyCompleted(MIGRATE_HISTORY); + } + }); + stmt.finalize(); + } + }, null); + } catch (e) { + Cu.reportError(e); + this._notifyCompleted(MIGRATE_HISTORY); + } + }, + + /* + * Migrating cookies + */ + _migrateCookies : function Chrome_migrateCookies() + { + this._notifyStart(MIGRATE_COOKIES); + + try { + // Access sqlite3 database of Chrome's cookie + let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile); + file.initWithPath(this._paths.cookies); + + let dbConn = Services.storage.openUnsharedDatabase(file); + let stmt = dbConn.createAsyncStatement( + "SELECT host_key, path, name, value, secure, httponly, expires_utc FROM cookies"); + + stmt.executeAsync({ + _db : dbConn, + _self : this, + handleResult : function(aResults) { + for (let row = aResults.getNextRow(); row; row = aResults.getNextRow()) { + let host_key = row.getResultByName("host_key"); + if (host_key.match(/^\./)) { + // 1st character of host_key may be ".", so we have to remove it + host_key = host_key.substr(1); + } + + try { + let expiresUtc = + chromeTimeToDate(row.getResultByName("expires_utc")) / 1000; + Services.cookies.add(host_key, + row.getResultByName("path"), + row.getResultByName("name"), + row.getResultByName("value"), + row.getResultByName("secure"), + row.getResultByName("httponly"), + false, + parseInt(expiresUtc)); + } catch (e) { + Cu.reportError(e); + } + } + }, + + handleError : function(aError) { + Cu.reportError("Async statement execution returned with '" + + aError.result + "', '" + aError.message + "'"); + }, + + handleCompletion : function(aReason) { + this._db.asyncClose(); + this._self._notifyCompleted(MIGRATE_COOKIES); + }, + }); + stmt.finalize(); + } catch (e) { + Cu.reportError(e); + this._notifyCompleted(MIGRATE_COOKIES); + } + }, + + /* + * nsIBrowserProfileMigrator interface implementation + */ + + /* + * Let's migrate all items + * + * @param aItems + * list of data items to migrate. but this is unused. + * @param aStartup + * non-null if called during startup. + * @param aProfile + * this is unused due to single profile support only + */ + migrate : function Chrome_migrate(aItems, aStartup, aProfile) + { + if (aStartup) { + aStartup.doStartup(); + this._replaceBookmarks = true; + } + + Services.obs.notifyObservers(null, "Migration:Started", null); + + // Reset panding count. If this count becomes 0, "Migration:Ended" + // notification is sent + this._pendingCount = 1; + + if (aItems & MIGRATE_HISTORY) + this._migrateHistory(); + + if (aItems & MIGRATE_COOKIES) + this._migrateCookies(); + + if (aItems & MIGRATE_BOOKMARKS) + this._migrateBookmarks(); + + if (--this._pendingCount == 0) { + // When async imports are immeditelly completed unfortunately, + // this will be called. + // Usually, this notification is sent by _notifyCompleted() + Services.obs.notifyObservers(null, "Migration:Ended", null); + } + }, + + /* + * return supported migration types + * + * @param aProfile + * this is unused due to single profile support only + * @param aDoingStartup + * non-null if called during startup. + * @return supported migration types + */ + getMigrateData: function Chrome_getMigrateData(aProfile, aDoingStartup) + { +#ifdef XP_WIN + let chromepath = Services.dirsvc.get("LocalAppData", Ci.nsIFile).path + + "\\Google\\Chrome\\User Data\\Default\\"; +#elifdef XP_MACOSX + let chromepath = Services.dirsvc.get("Home", Ci.nsIFile).path + + "/Library/Application Support/Google/Chrome/Default/"; +#else + let chromepath = Services.dirsvc.get("Home", Ci.nsIFile).path + + "/.config/google-chrome/Default/"; +#endif + + let result = 0; + + // bookmark and preference are JSON format + + try { + let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile); + file.initWithPath(chromepath + "Bookmarks"); + if (file.exists()) { + this._paths.bookmarks = file.path + result += MIGRATE_BOOKMARKS; + } + } catch (e) { + Cu.reportError(e); + } + + if (!this._paths.prefs) + this._paths.prefs = chromepath + "Preferences"; + + // history and cookies are SQLite database + + try { + let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile); + file.initWithPath(chromepath + "History"); + if (file.exists()) { + this._paths.history = file.path + result += MIGRATE_HISTORY; + } + } catch (e) { + Cu.reportError(e); + } + + try { + let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile); + file.initWithPath(chromepath + "Cookies"); + if (file.exists()) { + this._paths.cookies = file.path + result += MIGRATE_COOKIES; + } + } catch (e) { + Cu.reportError(e); + } + + return result; + }, + + /* + * Whether we support migration of Chrome + * + * @return true if supported + */ + sourceExists: function Chrome_sourceExists() + { + let result = this.getMigrateData(null, false); + return result != 0; + }, + + // Although Chrome supports multi-profiles, there is no way + // to get profile lists. + sourceHasMultipleProfiles: false, + sourceProfiles: null, + + /* + * Return home page URL + * + * @return home page URL + */ + sourceHomePageURL: function Chrome_sourceHomePageURL() + { + try { + if (this._homepageURL) + return this._homepageURL; + + if (!this._paths.prefs) + this.getMigrateData(null, false); + + // XXX reading and parsing JSON is synchronous. + let file = Cc[LOCAL_FILE_CID].createInstance(Ci.nsILocalFile); + file.initWithPath(this._paths.prefs); + let fstream = Cc[FILE_INPUT_STREAM_CID]. + createInstance(Ci.nsIFileInputStream); + fstream.init(file, -1, 0, 0); + this._homepageURL = JSON.parse( + NetUtil.readInputStreamToString(fstream, fstream.available(), + { charset: "UTF-8" })).homepage; + return this._homepageURL; + } catch (e) { + Cu.reportError(e); + } + return ""; + }, + + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsIBrowserProfileMigrator + ]), + + classDescription: "Chrome Profile Migrator", + contractID: "@mozilla.org/profile/migrator;1?app=browser&type=chrome", + classID: Components.ID("{4cec1de4-1671-4fc3-a53e-6c539dc77a26}") +}; + +const NSGetFactory = XPCOMUtils.generateNSGetFactory([ChromeProfileMigrator]);
--- a/browser/components/migration/src/Makefile.in +++ b/browser/components/migration/src/Makefile.in @@ -62,10 +62,18 @@ CPPSRCS += nsIEProfileMigrator.cpp \ $(NULL) endif ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT)) CPPSRCS += nsSafariProfileMigrator.cpp \ $(NULL) endif +EXTRA_PP_COMPONENTS = \ + ChromeProfileMigrator.js \ + $(NULL) + +EXTRA_COMPONENTS = \ + BrowserProfileMigrators.manifest \ + $(NULL) + include $(topsrcdir)/config/rules.mk
--- a/browser/components/migration/src/nsProfileMigrator.cpp +++ b/browser/components/migration/src/nsProfileMigrator.cpp @@ -158,16 +158,17 @@ nsProfileMigrator::Import() NS_IMPL_ISUPPORTS1(nsProfileMigrator, nsIProfileMigrator) #ifdef XP_WIN #define INTERNAL_NAME_IEXPLORE "iexplore" #define INTERNAL_NAME_MOZILLA_SUITE "apprunner" #define INTERNAL_NAME_OPERA "opera" +#define INTERNAL_NAME_CHROME "chrome" #endif nsresult nsProfileMigrator::GetDefaultBrowserMigratorKey(nsACString& aKey, nsCOMPtr<nsIBrowserProfileMigrator>& bpm) { #if XP_WIN @@ -241,32 +242,37 @@ nsProfileMigrator::GetDefaultBrowserMigr if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_IEXPLORE)) { aKey = "ie"; return NS_OK; } else if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_OPERA)) { aKey = "opera"; return NS_OK; } + else if (internalName.LowerCaseEqualsLiteral(INTERNAL_NAME_CHROME)) { + aKey = "chrome"; + return NS_OK; + } #else bool exists = false; #define CHECK_MIGRATOR(browser) do {\ bpm = do_CreateInstance(NS_BROWSERPROFILEMIGRATOR_CONTRACTID_PREFIX browser);\ if (bpm)\ bpm->GetSourceExists(&exists);\ if (exists) {\ aKey = browser;\ return NS_OK;\ }} while(0) #if defined(XP_MACOSX) CHECK_MIGRATOR("safari"); #endif CHECK_MIGRATOR("opera"); + CHECK_MIGRATOR("chrome"); #undef CHECK_MIGRATOR #endif return NS_ERROR_FAILURE; } bool nsProfileMigrator::ImportRegistryProfiles(const nsACString& aAppName)
--- a/browser/components/places/content/controller.js +++ b/browser/components/places/content/controller.js @@ -442,17 +442,16 @@ PlacesController.prototype = { * Gathers information about the selected nodes according to the following * rules: * "link" node is a URI * "bookmark" node is a bookamrk * "livemarkChild" node is a child of a livemark * "tagChild" node is a child of a tag * "folder" node is a folder * "query" node is a query - * "dynamiccontainer" node is a dynamic container * "separator" node is a separator line * "host" node is a host * * @returns an array of objects corresponding the selected nodes. Each * object has each of the properties above set if its corresponding * node matches the rule. In addition, the annotations names for each * node are set on its corresponding object as properties. * Notes: @@ -485,19 +484,16 @@ PlacesController.prototype = { break; case Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY: case Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY: nodeData["day"] = true; break; } } break; - case Ci.nsINavHistoryResultNode.RESULT_TYPE_DYNAMIC_CONTAINER: - nodeData["dynamiccontainer"] = true; - break; case Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER: case Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT: nodeData["folder"] = true; break; case Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR: nodeData["separator"] = true; break; case Ci.nsINavHistoryResultNode.RESULT_TYPE_URI:
--- a/browser/config/mozconfigs/linux32/debug +++ b/browser/config/mozconfigs/linux32/debug @@ -1,13 +1,13 @@ ac_add_options --enable-debug ac_add_options --enable-trace-malloc -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 # Enable parallel compiling mk_add_options MOZ_MAKE_FLAGS="-j4"
--- a/browser/config/mozconfigs/linux32/l10n-mozconfig +++ b/browser/config/mozconfigs/linux32/l10n-mozconfig @@ -1,7 +1,7 @@ ac_add_options --with-l10n-base=../../l10n-central ac_add_options --enable-official-branding ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux +
--- a/browser/config/mozconfigs/linux32/nightly +++ b/browser/config/mozconfigs/linux32/nightly @@ -1,17 +1,17 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-codesighs # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/linux32/qt +++ b/browser/config/mozconfigs/linux32/qt @@ -1,13 +1,13 @@ ac_add_options --enable-update-packaging ac_add_options --enable-codesighs -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 # PGO mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10'
--- a/browser/config/mozconfigs/linux32/release +++ b/browser/config/mozconfigs/linux32/release @@ -1,14 +1,14 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-official-branding -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # PGO mk_add_options MOZ_PGO=1 mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10' # Needed to enable breakpad in application.ini
--- a/browser/config/mozconfigs/linux32/rpm +++ b/browser/config/mozconfigs/linux32/rpm @@ -4,18 +4,18 @@ ac_add_options --enable-codesighs # Options for rpm versions of mozconfigs PREFIX=/usr LIBDIR=${PREFIX}/lib ac_add_options --with-app-name=mozilla-nightly ac_add_options --disable-updater ac_add_options --prefix=$PREFIX ac_add_options --libdir=$LIBDIR -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/linux64/debug +++ b/browser/config/mozconfigs/linux64/debug @@ -1,13 +1,13 @@ ac_add_options --enable-debug ac_add_options --enable-trace-malloc -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 # Enable parallel compiling mk_add_options MOZ_MAKE_FLAGS="-j4"
--- a/browser/config/mozconfigs/linux64/l10n-mozconfig +++ b/browser/config/mozconfigs/linux64/l10n-mozconfig @@ -1,7 +1,7 @@ ac_add_options --with-l10n-base=../../l10n-central ac_add_options --enable-official-branding ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux +
--- a/browser/config/mozconfigs/linux64/nightly +++ b/browser/config/mozconfigs/linux64/nightly @@ -1,17 +1,17 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-codesighs # Nightlies only since this has a cost in performance ac_add_options --enable-js-diagnostics -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/config/mozconfigs/linux64/release +++ b/browser/config/mozconfigs/linux64/release @@ -1,14 +1,14 @@ ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL} ac_add_options --enable-update-packaging ac_add_options --enable-official-branding -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # PGO mk_add_options MOZ_PGO=1 mk_add_options PROFILE_GEN_SCRIPT='$(PYTHON) @MOZ_OBJDIR@/_profile/pgo/profileserver.py 10' # Needed to enable breakpad in application.ini
--- a/browser/config/mozconfigs/linux64/rpm +++ b/browser/config/mozconfigs/linux64/rpm @@ -4,18 +4,18 @@ ac_add_options --enable-codesighs # Options for rpm versions of mozconfigs PREFIX=/usr LIBDIR=${PREFIX}/lib64 ac_add_options --with-app-name=mozilla-nightly ac_add_options --disable-updater ac_add_options --prefix=$PREFIX ac_add_options --libdir=$LIBDIR -CC=/tools/gcc-4.5-0moz2/bin/gcc -CXX=/tools/gcc-4.5-0moz2/bin/g++ +. $topsrcdir/build/unix/mozconfig.linux + # Avoid dependency on libstdc++ 4.5 ac_add_options --enable-stdcxx-compat # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 export MOZ_TELEMETRY_REPORTING=1
--- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -61,16 +61,19 @@ Cu.import("resource:///modules/PropertyP Cu.import("resource:///modules/source-editor.jsm"); Cu.import("resource:///modules/devtools/scratchpad-manager.jsm"); const SCRATCHPAD_CONTEXT_CONTENT = 1; const SCRATCHPAD_CONTEXT_BROWSER = 2; const SCRATCHPAD_L10N = "chrome://browser/locale/devtools/scratchpad.properties"; const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled"; +const BUTTON_POSITION_SAVE = 0; +const BUTTON_POSITION_CANCEL = 1; +const BUTTON_POSITION_DONT_SAVE = 2; /** * The scratchpad object handles the Scratchpad window functionality. */ var Scratchpad = { /** * The script execution context. This tells Scratchpad in which context the * script shall execute. @@ -596,40 +599,58 @@ var Scratchpad = { if (fp.show() != Ci.nsIFilePicker.returnCancel) { this.setFilename(fp.file.path); this.importFromFile(fp.file, false, this.onTextSaved.bind(this)); } }, /** * Save the textbox content to the currently open file. + * + * @param function aCallback + * Optional function you want to call when file is saved */ - saveFile: function SP_saveFile() + saveFile: function SP_saveFile(aCallback) { if (!this.filename) { - return this.saveFileAs(); + return this.saveFileAs(aCallback); } let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); file.initWithPath(this.filename); - this.exportToFile(file, true, false, this.onTextSaved.bind(this)); + + this.exportToFile(file, true, false, function(aStatus) { + this.onTextSaved(); + if (aCallback) { + aCallback(aStatus); + } + }); }, /** * Save the textbox content to a new file. + * + * @param function aCallback + * Optional function you want to call when file is saved */ - saveFileAs: function SP_saveFileAs() + saveFileAs: function SP_saveFileAs(aCallback) { let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); fp.init(window, this.strings.GetStringFromName("saveFileAs"), Ci.nsIFilePicker.modeSave); fp.defaultString = "scratchpad.js"; if (fp.show() != Ci.nsIFilePicker.returnCancel) { this.setFilename(fp.file.path); - this.exportToFile(fp.file, true, false, this.onTextSaved.bind(this)); + + this.exportToFile(fp.file, true, false, function(aStatus) { + this.onTextSaved(); + if (aCallback) { + aCallback(aStatus); + } + }); } }, /** * Open the Error Console. */ openErrorConsole: function SP_openErrorConsole() { @@ -840,16 +861,19 @@ var Scratchpad = { * This method adds a listener to the editor for text changes. Called when * a scratchpad is saved, opened from file, or restored from a saved file. */ onTextSaved: function SP_onTextSaved(aStatus) { if (aStatus && !Components.isSuccessCode(aStatus)) { return; } + if (!document) { + return; // file saved to disk after window has closed + } document.title = document.title.replace(/^\*/, ""); this.saved = true; this.editor.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED, this.onTextChanged); }, /** * The scratchpad handler for editor text change events. This handler @@ -877,16 +901,76 @@ var Scratchpad = { this.resetContext(); this.editor.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU, this.onContextMenu); this.editor.destroy(); this.editor = null; }, + /** + * Prompt to save scratchpad if it has unsaved changes. + * + * @param function aCallback + * Optional function you want to call when file is saved + * @return boolean + * Whether the window should be closed + */ + promptSave: function SP_promptSave(aCallback) + { + if (this.filename && !this.saved) { + let ps = Services.prompt; + let flags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_SAVE + + ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL + + ps.BUTTON_POS_2 * ps.BUTTON_TITLE_DONT_SAVE; + + let button = ps.confirmEx(window, + this.strings.GetStringFromName("confirmClose.title"), + this.strings.GetStringFromName("confirmClose"), + flags, null, null, null, null, {}); + + if (button == BUTTON_POSITION_CANCEL) { + return false; + } + if (button == BUTTON_POSITION_SAVE) { + this.saveFile(aCallback); + } + } + return true; + }, + + /** + * Handler for window close event. Prompts to save scratchpad if + * there are unsaved changes. + * + * @param nsIDOMEvent aEvent + */ + onClose: function SP_onClose(aEvent) + { + let toClose = this.promptSave(); + if (!toClose) { + aEvent.preventDefault(); + } + }, + + /** + * Close the scratchpad window. Prompts before closing if the scratchpad + * has unsaved changes. + * + * @param function aCallback + * Optional function you want to call when file is saved + */ + close: function SP_close(aCallback) + { + let toClose = this.promptSave(aCallback); + if (toClose) { + window.close(); + } + }, + _observers: [], /** * Add an observer for Scratchpad events. * * The observer implements IScratchpadObserver := { * onReady: Called when the Scratchpad and its SourceEditor are ready. * Arguments: (Scratchpad aScratchpad) @@ -946,8 +1030,9 @@ var Scratchpad = { }; XPCOMUtils.defineLazyGetter(Scratchpad, "strings", function () { return Services.strings.createBundle(SCRATCHPAD_L10N); }); addEventListener("DOMContentLoaded", Scratchpad.onLoad.bind(Scratchpad), false); addEventListener("unload", Scratchpad.onUnload.bind(Scratchpad), false); +addEventListener("close", Scratchpad.onClose.bind(Scratchpad), false);
--- a/browser/devtools/scratchpad/scratchpad.xul +++ b/browser/devtools/scratchpad/scratchpad.xul @@ -64,17 +64,17 @@ <command id="sp-cmd-openFile" oncommand="Scratchpad.openFile();"/> <command id="sp-cmd-save" oncommand="Scratchpad.saveFile();"/> <command id="sp-cmd-saveas" oncommand="Scratchpad.saveFileAs();"/> <!-- TODO: bug 650340 - implement printFile() <command id="sp-cmd-printFile" oncommand="Scratchpad.printFile();" disabled="true"/> --> - <command id="sp-cmd-close" oncommand="window.close();"/> + <command id="sp-cmd-close" oncommand="Scratchpad.close();"/> <command id="sp-cmd-run" oncommand="Scratchpad.run();"/> <command id="sp-cmd-inspect" oncommand="Scratchpad.inspect();"/> <command id="sp-cmd-display" oncommand="Scratchpad.display();"/> <command id="sp-cmd-contentContext" oncommand="Scratchpad.setContentContext();"/> <command id="sp-cmd-browserContext" oncommand="Scratchpad.setBrowserContext();" disabled="true"/> <command id="sp-cmd-resetContext" oncommand="Scratchpad.resetContext();"/> <command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/> <command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/>
--- a/browser/devtools/scratchpad/test/Makefile.in +++ b/browser/devtools/scratchpad/test/Makefile.in @@ -54,11 +54,12 @@ include $(topsrcdir)/config/rules.mk browser_scratchpad_bug_646070_chrome_context_pref.js \ browser_scratchpad_bug_660560_tab.js \ browser_scratchpad_open.js \ browser_scratchpad_restore.js \ browser_scratchpad_bug_679467_falsy.js \ browser_scratchpad_bug_699130_edit_ui_updates.js \ browser_scratchpad_bug_669612_unsaved.js \ head.js \ + browser_scratchpad_bug_653427_confirm_close.js \ libs:: $(_BROWSER_TEST_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644 --- /dev/null +++ b/browser/devtools/scratchpad/test/browser_scratchpad_bug_653427_confirm_close.js @@ -0,0 +1,188 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + + +Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/FileUtils.jsm"); + +// only finish() when correct number of tests are done +const expected = 5; +var count = 0; +function done() +{ + if (++count == expected) { + cleanup(); + finish(); + } +} + +var ScratchpadManager = Scratchpad.ScratchpadManager; +var gFile; + +var oldPrompt = Services.prompt; + +function test() +{ + waitForExplicitFinish(); + + gFile = createTempFile("fileForBug653427.tmp"); + writeFile(gFile, "text", testUnsaved.call(this)); + + testNew(); + testSavedFile(); + + content.location = "data:text/html,<p>test scratchpad save file prompt on closing"; +} + +function testNew() +{ + let win = ScratchpadManager.openScratchpad(); + + win.addEventListener("load", function() { + win.Scratchpad.close(); + + ok(win.closed, "new scratchpad window should close without prompting") + done(); + }); +} + +function testSavedFile() +{ + let win = ScratchpadManager.openScratchpad(); + + win.addEventListener("load", function() { + win.Scratchpad.filename = "test.js"; + win.Scratchpad.saved = true; + win.Scratchpad.close(); + + ok(win.closed, "scratchpad from file with no changes should close") + done(); + }); +} + +function testUnsaved() +{ + testUnsavedFileCancel(); + testUnsavedFileSave(); + testUnsavedFileDontSave(); +} + +function testUnsavedFileCancel() +{ + let win = ScratchpadManager.openScratchpad(); + + win.addEventListener("load", function() { + win.Scratchpad.filename = "test.js"; + win.Scratchpad.saved = false; + + Services.prompt = { + confirmEx: function() { + return win.BUTTON_POSITION_CANCEL; + } + } + + win.Scratchpad.close(); + + ok(!win.closed, "cancelling dialog shouldn't close scratchpad"); + + win.close(); + done(); + }); +} + +function testUnsavedFileSave() +{ + let win = ScratchpadManager.openScratchpad(); + + win.addEventListener("load", function() { + win.Scratchpad.importFromFile(gFile, true, function(status, content) { + win.Scratchpad.filename = gFile.path; + win.Scratchpad.onTextSaved(); + + let text = "new text"; + win.Scratchpad.setText(text); + + Services.prompt = { + confirmEx: function() { + return win.BUTTON_POSITION_SAVE; + } + } + + win.Scratchpad.close(function() { + readFile(gFile, function(savedContent) { + is(savedContent, text, 'prompted "Save" worked when closing scratchpad'); + done(); + }); + }); + + ok(win.closed, 'pressing "Save" in dialog should close scratchpad'); + }); + }); +} + +function testUnsavedFileDontSave() +{ + let win = ScratchpadManager.openScratchpad(); + + win.addEventListener("load", function() { + win.Scratchpad.filename = gFile.path; + win.Scratchpad.saved = false; + + Services.prompt = { + confirmEx: function() { + return win.BUTTON_POSITION_DONT_SAVE; + } + } + + win.Scratchpad.close(); + + ok(win.closed, 'pressing "Don\'t Save" in dialog should close scratchpad'); + done(); + }); +} + +function cleanup() +{ + Services.prompt = oldPrompt; + gFile.remove(false); + gFile = null; +} + +function createTempFile(name) +{ + let file = FileUtils.getFile("TmpD", [name]); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666); + file.QueryInterface(Ci.nsILocalFile) + return file; +} + +function writeFile(file, content, callback) +{ + let fout = Cc["@mozilla.org/network/file-output-stream;1"]. + createInstance(Ci.nsIFileOutputStream); + fout.init(file.QueryInterface(Ci.nsILocalFile), 0x02 | 0x08 | 0x20, + 0644, fout.DEFER_OPEN); + + let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. + createInstance(Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + let fileContentStream = converter.convertToInputStream(content); + + NetUtil.asyncCopy(fileContentStream, fout, callback); +} + +function readFile(file, callback) +{ + let channel = NetUtil.newChannel(file); + channel.contentType = "application/javascript"; + + NetUtil.asyncFetch(channel, function(inputStream, status) { + ok(Components.isSuccessCode(status), + "file was read successfully"); + + let content = NetUtil.readInputStreamToString(inputStream, + inputStream.available()); + callback(content); + }); +}
--- a/browser/devtools/webconsole/HUDService.jsm +++ b/browser/devtools/webconsole/HUDService.jsm @@ -1633,16 +1633,17 @@ HUD_SERVICE.prototype = * @param string aToggleType * @param boolean aState * @returns void */ setFilterState: function HS_setFilterState(aHUDId, aToggleType, aState) { this.filterPrefs[aHUDId][aToggleType] = aState; this.adjustVisibilityForMessageType(aHUDId, aToggleType, aState); + Services.prefs.setBoolPref(PREFS_PREFIX + aToggleType, aState); }, /** * Splits the given console messages into groups based on their timestamps. * * @param nsIDOMNode aOutputNode * The output node to alter. * @returns void @@ -6284,28 +6285,27 @@ HeadsUpDisplayUICommands = { this.setAttribute("checked", state); let prefKey = this.getAttribute("prefKey"); HUDService.setFilterState(hudId, prefKey, state); // Adjust the state of the button appropriately. let menuPopup = this.parentNode; - let allChecked = true; + let someChecked = false; let menuItem = menuPopup.firstChild; while (menuItem) { - if (menuItem.getAttribute("checked") !== "true") { - allChecked = false; + if (menuItem.getAttribute("checked") === "true") { + someChecked = true; break; } menuItem = menuItem.nextSibling; } - let toolbarButton = menuPopup.parentNode; - toolbarButton.setAttribute("checked", allChecked); + toolbarButton.setAttribute("checked", someChecked); break; } } return true; }, command: function UIC_command(aButton) { @@ -6333,126 +6333,57 @@ HeadsUpDisplayUICommands = { ////////////////////////////////////////////////////////////////////////// // ConsoleStorage ////////////////////////////////////////////////////////////////////////// var prefs = Services.prefs; const GLOBAL_STORAGE_INDEX_ID = "GLOBAL_CONSOLE"; -const PREFS_BRANCH_PREF = "devtools.hud.display.filter"; -const PREFS_PREFIX = "devtools.hud.display.filter."; +const PREFS_PREFIX = "devtools.webconsole.filter."; const PREFS = { network: PREFS_PREFIX + "network", networkinfo: PREFS_PREFIX + "networkinfo", csserror: PREFS_PREFIX + "csserror", cssparser: PREFS_PREFIX + "cssparser", exception: PREFS_PREFIX + "exception", jswarn: PREFS_PREFIX + "jswarn", error: PREFS_PREFIX + "error", info: PREFS_PREFIX + "info", warn: PREFS_PREFIX + "warn", log: PREFS_PREFIX + "log", - global: PREFS_PREFIX + "global", }; function ConsoleStorage() { this.sequencer = null; this.consoleDisplays = {}; // each display will have an index that tracks each ConsoleEntry this.displayIndexes = {}; this.globalStorageIndex = []; this.globalDisplay = {}; this.createDisplay(GLOBAL_STORAGE_INDEX_ID); // TODO: need to create a method that truncates the message // see bug 570543 - // store an index of display prefs - this.displayPrefs = {}; - - // check prefs for existence, create & load if absent, load them if present - let filterPrefs; - let defaultDisplayPrefs; - - try { - filterPrefs = prefs.getBoolPref(PREFS_BRANCH_PREF); - } - catch (ex) { - filterPrefs = false; - } - - // TODO: for FINAL release, - // use the sitePreferencesService to save specific site prefs - // see bug 570545 - - if (filterPrefs) { - defaultDisplayPrefs = { - network: (prefs.getBoolPref(PREFS.network) ? true: false), - networkinfo: (prefs.getBoolPref(PREFS.networkinfo) ? true: false), - csserror: (prefs.getBoolPref(PREFS.csserror) ? true: false), - cssparser: (prefs.getBoolPref(PREFS.cssparser) ? true: false), - exception: (prefs.getBoolPref(PREFS.exception) ? true: false), - jswarn: (prefs.getBoolPref(PREFS.jswarn) ? true: false), - error: (prefs.getBoolPref(PREFS.error) ? true: false), - info: (prefs.getBoolPref(PREFS.info) ? true: false), - warn: (prefs.getBoolPref(PREFS.warn) ? true: false), - log: (prefs.getBoolPref(PREFS.log) ? true: false), - global: (prefs.getBoolPref(PREFS.global) ? true: false), - }; - } - else { - prefs.setBoolPref(PREFS_BRANCH_PREF, false); - // default prefs for each HeadsUpDisplay - prefs.setBoolPref(PREFS.network, true); - prefs.setBoolPref(PREFS.networkinfo, true); - prefs.setBoolPref(PREFS.csserror, true); - prefs.setBoolPref(PREFS.cssparser, true); - prefs.setBoolPref(PREFS.exception, true); - prefs.setBoolPref(PREFS.jswarn, true); - prefs.setBoolPref(PREFS.error, true); - prefs.setBoolPref(PREFS.info, true); - prefs.setBoolPref(PREFS.warn, true); - prefs.setBoolPref(PREFS.log, true); - prefs.setBoolPref(PREFS.global, false); - - defaultDisplayPrefs = { - network: prefs.getBoolPref(PREFS.network), - networkinfo: prefs.getBoolPref(PREFS.networkinfo), - csserror: prefs.getBoolPref(PREFS.csserror), - cssparser: prefs.getBoolPref(PREFS.cssparser), - exception: prefs.getBoolPref(PREFS.exception), - jswarn: prefs.getBoolPref(PREFS.jswarn), - error: prefs.getBoolPref(PREFS.error), - info: prefs.getBoolPref(PREFS.info), - warn: prefs.getBoolPref(PREFS.warn), - log: prefs.getBoolPref(PREFS.log), - global: prefs.getBoolPref(PREFS.global), - }; - } - this.defaultDisplayPrefs = defaultDisplayPrefs; + this.defaultDisplayPrefs = { + network: prefs.getBoolPref(PREFS.network), + networkinfo: prefs.getBoolPref(PREFS.networkinfo), + csserror: prefs.getBoolPref(PREFS.csserror), + cssparser: prefs.getBoolPref(PREFS.cssparser), + exception: prefs.getBoolPref(PREFS.exception), + jswarn: prefs.getBoolPref(PREFS.jswarn), + error: prefs.getBoolPref(PREFS.error), + info: prefs.getBoolPref(PREFS.info), + warn: prefs.getBoolPref(PREFS.warn), + log: prefs.getBoolPref(PREFS.log), + }; } ConsoleStorage.prototype = { - updateDefaultDisplayPrefs: - function CS_updateDefaultDisplayPrefs(aPrefsObject) { - prefs.setBoolPref(PREFS.network, (aPrefsObject.network ? true : false)); - prefs.setBoolPref(PREFS.networkinfo, - (aPrefsObject.networkinfo ? true : false)); - prefs.setBoolPref(PREFS.csserror, (aPrefsObject.csserror ? true : false)); - prefs.setBoolPref(PREFS.cssparser, (aPrefsObject.cssparser ? true : false)); - prefs.setBoolPref(PREFS.exception, (aPrefsObject.exception ? true : false)); - prefs.setBoolPref(PREFS.jswarn, (aPrefsObject.jswarn ? true : false)); - prefs.setBoolPref(PREFS.error, (aPrefsObject.error ? true : false)); - prefs.setBoolPref(PREFS.info, (aPrefsObject.info ? true : false)); - prefs.setBoolPref(PREFS.warn, (aPrefsObject.warn ? true : false)); - prefs.setBoolPref(PREFS.log, (aPrefsObject.log ? true : false)); - prefs.setBoolPref(PREFS.global, (aPrefsObject.global ? true : false)); - }, - sequenceId: function CS_sequencerId() { if (!this.sequencer) { this.sequencer = this.createSequencer(); } return this.sequencer.next(); },
--- a/browser/devtools/webconsole/test/browser/Makefile.in +++ b/browser/devtools/webconsole/test/browser/Makefile.in @@ -145,16 +145,17 @@ include $(topsrcdir)/config/rules.mk browser_webconsole_bug_659907_console_dir.js \ browser_webconsole_bug_678816.js \ browser_webconsole_bug_664131_console_group.js \ browser_gcli_inspect.js \ browser_gcli_integrate.js \ browser_gcli_require.js \ browser_gcli_web.js \ browser_webconsole_bug_658368_time_methods.js \ + browser_webconsole_bug_622303_persistent_filters.js \ head.js \ $(NULL) _BROWSER_TEST_PAGES = \ test-console.html \ test-network.html \ test-network-request.html \ test-mutation.html \
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_589162_css_filter.js +++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_589162_css_filter.js @@ -22,25 +22,24 @@ function onContentLoaded() let msg = "the unknown CSS property warning is displayed"; testLogEntry(outputNode, "foobarCssParser", msg, true); HUDService.setFilterState(hudId, "cssparser", false); executeSoon( function (){ - HUDService.setFilterState(hudId, "cssparser", false); - let msg = "the unknown CSS property warning is not displayed, " + "after filtering"; testLogEntry(outputNode, "foobarCssParser", msg, true, true); + + HUDService.setFilterState(hudId, "cssparser", true); + finishTest(); } ); - - finishTest(); } /** * Unit test for bug 589162: * CSS filtering on the console does not work */ function test() {
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_597460_filter_scroll.js +++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_597460_filter_scroll.js @@ -49,16 +49,19 @@ function tabReload(aEvent) { ok(scrollBox.scrollTop > 0, "scroll location is not at the top"); // Make sure the Web Console output is scrolled as near as possible to the // bottom. let nodeHeight = hud.outputNode.querySelector(".hud-log").clientHeight; ok(scrollBox.scrollTop >= scrollBox.scrollHeight - scrollBox.clientHeight - nodeHeight * 2, "scroll location is correct"); + HUDService.setFilterState(hud.hudId, "network", true); + HUDService.setFilterState(hud.hudId, "networkinfo", true); + executeSoon(finishTest); } function test() { addTab(TEST_URI); browser.addEventListener("load", tabLoad, true); }
--- a/browser/devtools/webconsole/test/browser/browser_webconsole_bug_601667_filter_buttons.js +++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_601667_filter_buttons.js @@ -54,67 +54,78 @@ function testMenuFilterButton(aCategory) aCategory + " is checked after clicking it"); ok(HUDService.filterPrefs[hudId][prefKey], prefKey + " messages are " + "on after clicking the appropriate menu item"); menuItem = menuItem.nextSibling; } ok(isChecked(button), "the button for category " + aCategory + " is " + "checked after turning on all its menu items"); - // Turn one filter off; make sure the button is no longer checked. + // Turn one filter off; make sure the button is still checked. prefKey = firstMenuItem.getAttribute("prefKey"); chooseMenuItem(firstMenuItem); ok(!isChecked(firstMenuItem), "the first menu item for category " + aCategory + " is no longer checked after clicking it"); ok(!HUDService.filterPrefs[hudId][prefKey], prefKey + " messages are " + "turned off after clicking the appropriate menu item"); - ok(!isChecked(button), "the button for category " + aCategory + " is no " + - "longer checked after turning off its first menu item"); + ok(isChecked(button), "the button for category " + aCategory + " is still " + + "checked after turning off its first menu item"); - // Turn all the filters on by clicking the main part of the button. + // Turn all the filters off by clicking the main part of the button. let anonymousNodes = document.getAnonymousNodes(button); let subbutton; for (let i = 0; i < anonymousNodes.length; i++) { let node = anonymousNodes[i]; if (node.classList.contains("toolbarbutton-menubutton-button")) { subbutton = node; break; } } ok(subbutton, "we have the subbutton for category " + aCategory); clickButton(subbutton); + ok(!isChecked(button), "the button for category " + aCategory + " is " + + "no longer checked after clicking its main part"); + + menuItem = firstMenuItem; + while (menuItem) { + let prefKey = menuItem.getAttribute("prefKey"); + ok(!isChecked(menuItem), "menu item " + prefKey + " for category " + + aCategory + " is no longer checked after clicking the button"); + ok(!HUDService.filterPrefs[hudId][prefKey], prefKey + " messages are " + + "off after clicking the button"); + menuItem = menuItem.nextSibling; + } + + // Turn all the filters on by clicking the main part of the button. + clickButton(subbutton); + ok(isChecked(button), "the button for category " + aCategory + " is " + "checked after clicking its main part"); menuItem = firstMenuItem; while (menuItem) { let prefKey = menuItem.getAttribute("prefKey"); ok(isChecked(menuItem), "menu item " + prefKey + " for category " + aCategory + " is checked after clicking the button"); ok(HUDService.filterPrefs[hudId][prefKey], prefKey + " messages are " + "on after clicking the button"); - menuItem = menuItem.nextSibling; + menuItem = menuItem.nextSibling; } - // Turn all the filters off by clicking the main part of the button. - clickButton(subbutton); - ok(!isChecked(subbutton), "the button for category " + aCategory + " is " + - "no longer checked after clicking it"); - + // Uncheck the main button by unchecking all the filters menuItem = firstMenuItem; while (menuItem) { - let prefKey = menuItem.getAttribute("prefKey"); - ok(!isChecked(menuItem), "menu item " + prefKey + " for category " + - aCategory + " is no longer checked after clicking the button"); - ok(!HUDService.filterPrefs[hudId][prefKey], prefKey + " messages are " + - "off after clicking the button"); + chooseMenuItem(menuItem); menuItem = menuItem.nextSibling; } + ok(!isChecked(button), "the button for category " + aCategory + " is " + + "unchecked after unchecking all its filters"); + // Turn all the filters on again by clicking the button. clickButton(subbutton); } function clickButton(aNode) { EventUtils.sendMouseEvent({ type: "click" }, aNode); }
new file mode 100644 --- /dev/null +++ b/browser/devtools/webconsole/test/browser/browser_webconsole_bug_622303_persistent_filters.js @@ -0,0 +1,59 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + let prefService = Services.prefs; + let prefs = [ + "network", + "networkinfo", + "csserror", + "cssparser", + "exception", + "jswarn", + "error", + "warn", + "info", + "log" + ]; + + //Set all prefs to true + prefs.forEach(function(pref) { + prefService.setBoolPref("devtools.webconsole.filter." + pref, true); + }); + + addTab("about:blank"); + openConsole(); + + let hud = HUDService.getHudByWindow(content); + let hudId = HUDService.getHudIdByWindow(content); + + //Check if the filters menuitems exists and is checked + prefs.forEach(function(pref) { + let checked = hud.HUDBox.querySelector("menuitem[prefKey=" + pref + "]"). + getAttribute("checked"); + is(checked, "true", "menuitem for " + pref + " exists and is checked"); + }); + + //Set all prefs to false + prefs.forEach(function(pref) { + HUDService.setFilterState(hudId, pref, false); + }); + + //Re-init the console + closeConsole(); + openConsole(); + + hud = HUDService.getHudByWindow(content); + + //Check if filters menuitems exists and are unchecked + prefs.forEach(function(pref) { + let checked = hud.HUDBox.querySelector("menuitem[prefKey=" + pref + "]"). + getAttribute("checked"); + is(checked, "false", "menuitem for " + pref + " exists and is not checked"); + prefService.clearUserPref("devtools.webconsole.filter." + pref); + }); + + gBrowser.removeCurrentTab(); + + finish(); +}
--- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -143,16 +143,17 @@ @BINPATH@/components/dom_geolocation.xpt @BINPATH@/components/dom_notification.xpt @BINPATH@/components/dom_html.xpt @BINPATH@/components/dom_indexeddb.xpt @BINPATH@/components/dom_offline.xpt @BINPATH@/components/dom_json.xpt @BINPATH@/components/dom_range.xpt @BINPATH@/components/dom_sidebar.xpt +@BINPATH@/components/dom_sms.xpt @BINPATH@/components/dom_storage.xpt @BINPATH@/components/dom_stylesheets.xpt @BINPATH@/components/dom_threads.xpt @BINPATH@/components/dom_traversal.xpt @BINPATH@/components/dom_xbl.xpt @BINPATH@/components/dom_xpath.xpt @BINPATH@/components/dom_xul.xpt @BINPATH@/components/dom_loadsave.xpt @@ -351,16 +352,18 @@ @BINPATH@/components/satchel.manifest @BINPATH@/components/nsFormAutoComplete.js @BINPATH@/components/nsFormHistory.js @BINPATH@/components/nsInputListAutoComplete.js @BINPATH@/components/contentSecurityPolicy.manifest @BINPATH@/components/contentSecurityPolicy.js @BINPATH@/components/contentAreaDropListener.manifest @BINPATH@/components/contentAreaDropListener.js +@BINPATH@/components/BrowserProfileMigrators.manifest +@BINPATH@/components/ChromeProfileMigrator.js #ifdef XP_MACOSX @BINPATH@/components/libalerts_s.dylib #endif #ifdef MOZ_ENABLE_DBUS @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@ #endif @BINPATH@/components/nsINIProcessor.manifest @BINPATH@/components/nsINIProcessor.js
--- a/browser/installer/removed-files.in +++ b/browser/installer/removed-files.in @@ -309,16 +309,17 @@ searchplugins/answers.png searchplugins/answers.src searchplugins/answers.src searchplugins/atlas-sk.gif searchplugins/atlas-sk.png searchplugins/atlas-sk.src searchplugins/baidu.gif searchplugins/baidu.png searchplugins/baidu.src +searchplugins/bluu.xml searchplugins/bok-NO.gif searchplugins/bok-NO.png searchplugins/bok-NO.src searchplugins/bolcom-nl.gif searchplugins/bolcom-nl.png searchplugins/bolcom-nl.src searchplugins/bookplus-fi.gif searchplugins/bookplus-fi.png
--- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -424,32 +424,44 @@ can reach it easily. --> <!ENTITY copyAudioURLCmd.label "Copy Audio Location"> <!ENTITY copyAudioURLCmd.accesskey "o"> <!ENTITY copyEmailCmd.label "Copy Email Address"> <!ENTITY copyEmailCmd.accesskey "E"> <!ENTITY thisFrameMenu.label "This Frame"> <!ENTITY thisFrameMenu.accesskey "h"> <!-- Media (video/audio) controls --> +<!-- LOCALIZATION NOTE: The access keys for "Play" and +"Pause" are the same because the two context-menu +items are mutually exclusive. --> <!ENTITY mediaPlay.label "Play"> <!ENTITY mediaPlay.accesskey "P"> <!ENTITY mediaPause.label "Pause"> <!ENTITY mediaPause.accesskey "P"> +<!-- LOCALIZATION NOTE: The access keys for "Mute" and +"Unmute" are the same because the two context-menu +items are mutually exclusive. --> <!ENTITY mediaMute.label "Mute"> <!ENTITY mediaMute.accesskey "M"> <!ENTITY mediaUnmute.label "Unmute"> <!ENTITY mediaUnmute.accesskey "m"> +<!-- LOCALIZATION NOTE: The access keys for "Show Controls" and +"Hide Controls" are the same because the two context-menu +items are mutually exclusive. --> <!ENTITY mediaShowControls.label "Show Controls"> <!ENTITY mediaShowControls.accesskey "C"> <!ENTITY mediaHideControls.label "Hide Controls"> <!ENTITY mediaHideControls.accesskey "C"> <!ENTITY videoFullScreen.label "Full Screen"> <!ENTITY videoFullScreen.accesskey "F"> <!ENTITY videoSaveImage.label "Save Snapshot As…"> <!ENTITY videoSaveImage.accesskey "S"> +<!-- LOCALIZATION NOTE: The access keys for "Show Statistics" and +"Hide Statistics" are the same because the two context-menu +items are mutually exclusive. --> <!ENTITY videoShowStats.label "Show Statistics"> <!ENTITY videoShowStats.accesskey "t"> <!ENTITY videoHideStats.label "Hide Statistics"> <!ENTITY videoHideStats.accesskey "t"> <!-- LOCALIZATION NOTE : fullZoomEnlargeCmd.commandkey3, fullZoomReduceCmd.commandkey2 and fullZoomResetCmd.commandkey2 are alternative acceleration keys for zoom.
--- a/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties +++ b/browser/locales/en-US/chrome/browser/devtools/scratchpad.properties @@ -33,16 +33,24 @@ openFile.failed=Failed to read the file. # LOCALIZATION NOTE (saveFileAs): This is the file picker title, when you save # a file in Scratchpad. saveFileAs=Save File As # LOCALIZATION NOTE (saveFile.failed): This is the message displayed when file # save fails. saveFile.failed=The file save operation failed. +# LOCALIZATION NOTE (confirmClose): This is message in the prompt dialog when +# you try to close a scratchpad with unsaved changes. +confirmClose=Do you want to save the changes you made to this scratchpad? + +# LOCALIZATION NOTE (confirmClose.title): This is title of the prompt dialog when +# you try to close a scratchpad with unsaved changes. +confirmClose.title=Unsaved Changes + # LOCALIZATION NOTE (scratchpadIntro): This is a multi-line comment explaining # how to use the Scratchpad. Note that this should be a valid JavaScript # comment inside /* and */. scratchpadIntro=/*\n * This is a JavaScript Scratchpad.\n *\n * Enter some JavaScript, then Right Click or choose from the Execute Menu:\n * 1. Run to evaluate the selected text,\n * 2. Inspect to bring up an Object Inspector on the result, or,\n * 3. Display to insert the result in a comment after the selection.\n */\n\n # LOCALIZATION NOTE (notification.browserContext): This is the message displayed # over the top of the editor when the user has switched to browser context. browserContext.notification=This scratchpad executes in the Browser context.
--- a/browser/locales/en-US/chrome/browser/migration/migration.dtd +++ b/browser/locales/en-US/chrome/browser/migration/migration.dtd @@ -10,16 +10,18 @@ <!ENTITY importFromNothing.label "Don't import anything"> <!ENTITY importFromNothing.accesskey "D"> <!ENTITY importFromSeamonkey.label "Netscape 6, 7 or Mozilla 1.x"> <!ENTITY importFromSeamonkey.accesskey "N"> <!ENTITY importFromOpera.label "Opera"> <!ENTITY importFromOpera.accesskey "O"> <!ENTITY importFromSafari.label "Safari"> <!ENTITY importFromSafari.accesskey "S"> +<!ENTITY importFromChrome.label "Chrome"> +<!ENTITY importFromChrome.accesskey "C"> <!ENTITY importFromHTMLFile.label "From an HTML File"> <!ENTITY importFromHTMLFile.accesskey "F"> <!ENTITY noMigrationSources.label "No programs that contain bookmarks, history or password data could be found."> <!ENTITY importSource.title "Import Settings and Data"> <!ENTITY importItems.title "Items to Import"> <!ENTITY importItems.label "Select which items to import:">
--- a/browser/locales/en-US/chrome/browser/migration/migration.properties +++ b/browser/locales/en-US/chrome/browser/migration/migration.properties @@ -1,54 +1,62 @@ profileName_format=%S %S # Browser Specific sourceNameIE=Internet Explorer sourceNameSeamonkey=Netscape 6/7/Mozilla sourceNameOpera=Opera sourceNameSafari=Safari +sourceNameChrome=Google Chrome importedBookmarksFolder=From %S importedSearchURLsFolder=Keyword Searches (From %S) importedSearchURLsTitle=Search on %S importedSearchUrlDesc=Type "%S <search query>" in the Location Bar to perform a search on %S. importedSeamonkeyBookmarksTitle=From Netscape 6/7/Mozilla importedSafariBookmarks=From Safari importedOperaHotlistTitle=From Opera importedOperaSearchUrls=Keyword Searches (From Opera) # Import Sources 1_ie=Internet Options 1_opera=Preferences 1_seamonkey=Preferences 1_safari=Preferences +1_chrome=Preferences 2_ie=Cookies 2_opera=Cookies 2_seamonkey=Cookies 2_safari=Cookies +2_chrome=Cookies 4_ie=Browsing History 4_opera=Browsing History 4_seamonkey=Browsing History 4_safari=Browsing History +4_chrome=Browsing History 8_ie=Saved Form History 8_opera=Saved Form History 8_seamonkey=Saved Form History 8_safari=Saved Form History +8_chrome=Saved Form History 16_ie=Saved Passwords 16_opera=Saved Passwords 16_seamonkey=Saved Passwords 16_safari=Saved Passwords +16_chrome=Saved Passwords 32_ie=Favorites 32_opera=Bookmarks 32_seamonkey=Bookmarks 32_safari=Bookmarks +32_chrome=Bookmarks 64_ie=Other Data 64_opera=Other Data 64_seamonkey=Other Data 64_safari=Other Data +64_chrome=Other Data
--- a/browser/themes/gnomestripe/browser.css +++ b/browser/themes/gnomestripe/browser.css @@ -217,17 +217,17 @@ menuitem.bookmark-item { list-style-image: url("chrome://browser/skin/places/livemark-item.png"); } .bookmark-item[container][query] { list-style-image: url("chrome://browser/skin/places/query.png"); } .bookmark-item[query][tagContainer] { - list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png"); + list-style-image: url("chrome://browser/skin/places/tag.png"); } .bookmark-item[query][dayContainer] { list-style-image: url("chrome://browser/skin/places/calendar.png"); } .bookmark-item[query][hostContainer] { list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
deleted file mode 100644 index a788fffb00e59e3fff6931ad34cbc12a59f34254..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index f8536a4e1f9301b9d1304e575d17214325f9652f..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index a788fffb00e59e3fff6931ad34cbc12a59f34254..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index f8536a4e1f9301b9d1304e575d17214325f9652f..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
--- a/browser/themes/gnomestripe/jar.mn +++ b/browser/themes/gnomestripe/jar.mn @@ -34,20 +34,20 @@ browser.jar: skin/classic/browser/Secure.png skin/classic/browser/Security-broken.png skin/classic/browser/setDesktopBackground.css skin/classic/browser/Toolbar.png skin/classic/browser/Toolbar-small.png skin/classic/browser/urlbar-arrow.png skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png) skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png) - skin/classic/browser/feeds/videoFeedIcon.png (feeds/videoFeedIcon.png) - skin/classic/browser/feeds/videoFeedIcon16.png (feeds/videoFeedIcon16.png) - skin/classic/browser/feeds/audioFeedIcon.png (feeds/audioFeedIcon.png) - skin/classic/browser/feeds/audioFeedIcon16.png (feeds/audioFeedIcon16.png) + skin/classic/browser/feeds/videoFeedIcon.png (feeds/feedIcon.png) + skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png) + skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png) + skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png) skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css) skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css) skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png) skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png) skin/classic/browser/places/calendar.png (places/calendar.png) * skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css) skin/classic/browser/places/livemark-item.png (places/livemark-item.png) skin/classic/browser/places/pageStarred.png (places/pageStarred.png)
--- a/browser/themes/gnomestripe/places/places.css +++ b/browser/themes/gnomestripe/places/places.css @@ -72,17 +72,17 @@ treechildren::-moz-tree-image(title, que treechildren::-moz-tree-image(query, OrganizerQuery_Downloads) { list-style-image: url("chrome://browser/skin/places/downloads.png"); -moz-image-region: auto; } treechildren::-moz-tree-image(title, query, tagContainer), treechildren::-moz-tree-image(query, OrganizerQuery_Tags) { - list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png"); + list-style-image: url("chrome://browser/skin/places/tag.png"); } /* calendar icon for folders grouping items by date */ treechildren::-moz-tree-image(title, query, dayContainer) { list-style-image: url("chrome://browser/skin/places/calendar.png"); } treechildren::-moz-tree-image(title, query, hostContainer) {
--- a/browser/themes/pinstripe/browser.css +++ b/browser/themes/pinstripe/browser.css @@ -83,16 +83,27 @@ border-top: 1px solid rgba(0,0,0,0.65); } #navigator-toolbox > toolbar:not(#toolbar-menubar):not(#TabsToolbar) { -moz-box-align: center; padding: 2px 4px; } +/* Because of -moz-box-align: center above, separators will be invisible unless + we set their min-height. See bug 583510 for more information. */ +toolbarseparator { + min-height: 22px; +} + +/* We need more height when toolbar buttons show both icon and text. */ +toolbar[mode="full"] toolbarseparator { + min-height: 36px; +} + #nav-bar { padding-bottom: 4px !important; } #PersonalToolbar { -moz-appearance: none; margin-top: -2px; /* overlay the bottom border of the toolbar above us */ padding-top: 1px !important; @@ -226,17 +237,17 @@ toolbarbutton.bookmark-item > menupopup list-style-image: url("chrome://browser/skin/page-livemarks.png"); } .bookmark-item[query] { list-style-image: url("chrome://browser/skin/places/query.png"); } .bookmark-item[query][tagContainer] { - list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png"); + list-style-image: url("chrome://browser/skin/places/tag.png"); } .bookmark-item[query][dayContainer] { list-style-image: url("chrome://browser/skin/places/history.png"); } .bookmark-item[query][hostContainer] { list-style-image: url("chrome://global/skin/tree/folder.png"); @@ -1897,16 +1908,17 @@ toolbarbutton.chevron > .toolbarbutton-m box-shadow: @focusRingShadow@; } .tabbrowser-tab:not([selected="true"]):not(:hover):not(:-moz-lwtheme) { color: #222; } .tabbrowser-tab[selected="true"] { + color: #000; z-index: 1; position: relative; } .tabbrowser-tab:-moz-lwtheme { color: inherit; text-shadow: inherit; }
deleted file mode 100644 index 236b5f82106ed4e9f74eff40a29ee36701a894c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index a489de3bf858b6ea84d1470c17ab157f50adc01d..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 236b5f82106ed4e9f74eff40a29ee36701a894c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index a489de3bf858b6ea84d1470c17ab157f50adc01d..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
--- a/browser/themes/pinstripe/jar.mn +++ b/browser/themes/pinstripe/jar.mn @@ -46,20 +46,20 @@ browser.jar: skin/classic/browser/toolbarbutton-dropmarker.png skin/classic/browser/urlbar-history-dropmarker.png skin/classic/browser/urlbar-arrow.png skin/classic/browser/urlbar-popup-blocked.png skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css) skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css) skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png) skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png) - skin/classic/browser/feeds/videoFeedIcon.png (feeds/videoFeedIcon.png) - skin/classic/browser/feeds/videoFeedIcon16.png (feeds/videoFeedIcon16.png) - skin/classic/browser/feeds/audioFeedIcon.png (feeds/audioFeedIcon.png) - skin/classic/browser/feeds/audioFeedIcon16.png (feeds/audioFeedIcon16.png) + skin/classic/browser/feeds/videoFeedIcon.png (feeds/feedIcon.png) + skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png) + skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png) + skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png) skin/classic/browser/setDesktopBackground.css skin/classic/browser/inspector.css skin/classic/browser/monitor.png skin/classic/browser/monitor_16-10.png skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png) * skin/classic/browser/places/places.css (places/places.css) * skin/classic/browser/places/organizer.css (places/organizer.css) skin/classic/browser/places/query.png (places/query.png)
--- a/browser/themes/pinstripe/places/places.css +++ b/browser/themes/pinstripe/places/places.css @@ -1,18 +1,12 @@ %include ../shared.inc /* Sidebars */ -.sidebar-placesTree { - background-color: transparent !important; - -moz-appearance: none !important; - border: none !important; -} - #bookmarksPanel, #history-panel, #sidebar-search-container { -moz-appearance: none !important; background-color: transparent !important; border-top: none !important; } @@ -145,17 +139,17 @@ treechildren::-moz-tree-image(query) { } treechildren::-moz-tree-image(query, OrganizerQuery_Downloads) { list-style-image: url("chrome://browser/skin/places/downloads.png"); } treechildren::-moz-tree-image(title, query, tagContainer), treechildren::-moz-tree-image(query, OrganizerQuery_Tags) { - list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png"); + list-style-image: url("chrome://browser/skin/places/tag.png"); } /* calendar icon for folders grouping items by date */ treechildren::-moz-tree-image(title, query, dayContainer) { list-style-image: url("chrome://browser/skin/places/history.png"); } treechildren::-moz-tree-image(title, query, hostContainer) {
deleted file mode 100644 index ff2ecc2f351ef37d250264aa2bb273de08518165..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
--- a/browser/themes/winstripe/browser.css +++ b/browser/themes/winstripe/browser.css @@ -616,17 +616,17 @@ menuitem.bookmark-item { } .bookmark-item[container][query] { list-style-image: url("chrome://browser/skin/places/query.png"); -moz-image-region: auto; } .bookmark-item[query][tagContainer] { - list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png"); + list-style-image: url("chrome://browser/skin/places/tag.png"); -moz-image-region: auto; } .bookmark-item[query][dayContainer] { list-style-image: url("chrome://browser/skin/places/calendar.png"); -moz-image-region: auto; } @@ -2628,23 +2628,25 @@ panel[dimmed="true"] { background-color: rgba(0, 0, 0, 0.5); } #highlighter-closebutton { list-style-image: url("chrome://browser/skin/devtools/toolbarbutton-close.png"); -moz-image-region: rect(0, 16px, 16px, 0); min-width: 16px; width: 16px; + -moz-appearance: none; + border-style: none; } #highlighter-closebutton:hover { -moz-image-region: rect(0, 32px, 16px, 16px); } -#highlighter-closebutton:active { +#highlighter-closebutton:hover:active { -moz-image-region: rect(0, 48px, 16px, 32px); } #highlighter-veil-transparentbox { box-shadow: 0 0 0 1px rgba(0,0,0,0.5); outline: 1px dashed rgba(255,255,255,0.5); outline-offset: -1px; } @@ -2850,17 +2852,16 @@ panel[dimmed="true"] { background-color: transparent; border-width: 2px 13px; outline: none; color: hsl(210,30%,85%); max-width: 85px; /* The content of the button can be larger than the button */ overflow: hidden; min-height: 25px; - margin: 0 -11px 0 0; padding: 0 9px; } .inspector-breadcrumbs-button[checked] > .inspector-breadcrumbs-tag { color: hsl(200,100%,60%); }
deleted file mode 100644 index b4d5994995f24adf40fe10f407c9644e802b140d..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index e69bc4496139006ad20e34db308bfcc0cbc396c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 7c3aceb66f351208cf25ff02abe617cbb5e56456..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index d778807532bc0a1d47ac82370255600d503d66eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index b4d5994995f24adf40fe10f407c9644e802b140d..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index e69bc4496139006ad20e34db308bfcc0cbc396c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 7c3aceb66f351208cf25ff02abe617cbb5e56456..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index d778807532bc0a1d47ac82370255600d503d66eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
--- a/browser/themes/winstripe/jar.mn +++ b/browser/themes/winstripe/jar.mn @@ -1,17 +1,17 @@ browser.jar: % skin browser classic/1.0 %skin/classic/browser/ os=WINNT osversion<6 % skin browser classic/1.0 %skin/classic/browser/ os!=WINNT # NOTE: If you add a new file here, you'll need to add it to the aero # section at the bottom of this file skin/classic/browser/sanitizeDialog.css (sanitizeDialog.css) * skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css) * skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css) - skin/classic/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon.png) + skin/classic/browser/aboutSessionRestore-window-icon.png (preferences/application.png) skin/classic/browser/aboutCertError.css (aboutCertError.css) #ifdef MOZ_SERVICES_SYNC skin/classic/browser/aboutSyncTabs.css #endif skin/classic/browser/actionicon-tab.png skin/classic/browser/appmenu-icons.png skin/classic/browser/appmenu-dropmarker.png * skin/classic/browser/browser.css (browser.css) @@ -46,20 +46,20 @@ browser.jar: skin/classic/browser/menu-forward.png (menu-forward.png) skin/classic/browser/monitor.png skin/classic/browser/monitor_16-10.png skin/classic/browser/urlbar-arrow.png skin/classic/browser/urlbar-popup-blocked.png skin/classic/browser/urlbar-history-dropmarker.png skin/classic/browser/feeds/feedIcon.png (feeds/feedIcon.png) skin/classic/browser/feeds/feedIcon16.png (feeds/feedIcon16.png) - skin/classic/browser/feeds/audioFeedIcon.png (feeds/audioFeedIcon.png) - skin/classic/browser/feeds/audioFeedIcon16.png (feeds/audioFeedIcon16.png) - skin/classic/browser/feeds/videoFeedIcon.png (feeds/videoFeedIcon.png) - skin/classic/browser/feeds/videoFeedIcon16.png (feeds/videoFeedIcon16.png) + skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png) + skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png) + skin/classic/browser/feeds/videoFeedIcon.png (feeds/feedIcon.png) + skin/classic/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16.png) skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css) skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css) skin/classic/browser/inspector.css skin/classic/browser/places/places.css (places/places.css) * skin/classic/browser/places/organizer.css (places/organizer.css) skin/classic/browser/places/bookmark.png (places/bookmark.png) skin/classic/browser/places/editBookmark.png (places/editBookmark.png) skin/classic/browser/places/query.png (places/query.png) @@ -199,20 +199,20 @@ browser.jar: skin/classic/aero/browser/menu-forward.png (menu-forward-aero.png) skin/classic/aero/browser/monitor.png skin/classic/aero/browser/monitor_16-10.png skin/classic/aero/browser/urlbar-arrow.png skin/classic/aero/browser/urlbar-popup-blocked.png skin/classic/aero/browser/urlbar-history-dropmarker.png skin/classic/aero/browser/feeds/feedIcon.png (feeds/feedIcon-aero.png) skin/classic/aero/browser/feeds/feedIcon16.png (feeds/feedIcon16-aero.png) - skin/classic/aero/browser/feeds/audioFeedIcon.png (feeds/audioFeedIcon-aero.png) - skin/classic/aero/browser/feeds/audioFeedIcon16.png (feeds/audioFeedIcon16-aero.png) - skin/classic/aero/browser/feeds/videoFeedIcon.png (feeds/videoFeedIcon-aero.png) - skin/classic/aero/browser/feeds/videoFeedIcon16.png (feeds/videoFeedIcon16-aero.png) + skin/classic/aero/browser/feeds/audioFeedIcon.png (feeds/feedIcon-aero.png) + skin/classic/aero/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16-aero.png) + skin/classic/aero/browser/feeds/videoFeedIcon.png (feeds/feedIcon-aero.png) + skin/classic/aero/browser/feeds/videoFeedIcon16.png (feeds/feedIcon16-aero.png) skin/classic/aero/browser/feeds/subscribe.css (feeds/subscribe.css) skin/classic/aero/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css) skin/classic/aero/browser/inspector.css * skin/classic/aero/browser/places/places.css (places/places-aero.css) * skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css) skin/classic/aero/browser/places/bookmark.png (places/bookmark.png) skin/classic/aero/browser/places/editBookmark.png (places/editBookmark.png) skin/classic/aero/browser/places/query.png (places/query-aero.png) @@ -223,26 +223,25 @@ browser.jar: skin/classic/aero/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css) skin/classic/aero/browser/places/libraryToolbar.png (places/libraryToolbar-aero.png) skin/classic/aero/browser/places/starred48.png (places/starred48-aero.png) skin/classic/aero/browser/places/unstarred48.png (places/unstarred48.png) skin/classic/aero/browser/places/tag.png (places/tag-aero.png) skin/classic/aero/browser/places/history.png (places/history-aero.png) skin/classic/aero/browser/places/allBookmarks.png (places/allBookmarks-aero.png) skin/classic/aero/browser/places/unsortedBookmarks.png (places/unsortedBookmarks-aero.png) - skin/classic/aero/browser/places/searching_16.png (places/searching_16-aero.png) + skin/classic/aero/browser/places/searching_16.png (places/searching_16.png) skin/classic/aero/browser/places/downloads.png (places/downloads.png) skin/classic/aero/browser/preferences/alwaysAsk.png (preferences/alwaysAsk-aero.png) skin/classic/aero/browser/preferences/application.png (preferences/application-aero.png) skin/classic/aero/browser/preferences/mail.png (preferences/mail-aero.png) skin/classic/aero/browser/preferences/Options.png (preferences/Options-aero.png) #ifdef MOZ_SERVICES_SYNC skin/classic/aero/browser/preferences/Options-sync.png (preferences/Options-sync.png) #endif - skin/classic/aero/browser/preferences/plugin.png (preferences/plugin-aero.png) skin/classic/aero/browser/preferences/saveFile.png (preferences/saveFile-aero.png) * skin/classic/aero/browser/preferences/preferences.css (preferences/preferences.css) skin/classic/aero/browser/preferences/applications.css (preferences/applications.css) skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css) skin/classic/aero/browser/tabbrowser/alltabs.png (tabbrowser/alltabs.png) skin/classic/aero/browser/tabbrowser/newtab.png (tabbrowser/newtab.png) skin/classic/aero/browser/tabbrowser/newtab-inverted.png (tabbrowser/newtab-inverted.png) skin/classic/aero/browser/tabbrowser/connecting.png (tabbrowser/connecting.png)
--- a/browser/themes/winstripe/places/places.css +++ b/browser/themes/winstripe/places/places.css @@ -76,17 +76,17 @@ treechildren::-moz-tree-image(container, /* query-nodes should be styled even if they're not expandable */ treechildren::-moz-tree-image(title, query) { list-style-image: url("chrome://browser/skin/places/query.png"); -moz-image-region: auto; } treechildren::-moz-tree-image(title, query, tagContainer), treechildren::-moz-tree-image(query, OrganizerQuery_Tags) { - list-style-image: url("chrome://mozapps/skin/places/tagContainerIcon.png"); + list-style-image: url("chrome://browser/skin/places/tag.png"); -moz-image-region: auto; } treechildren::-moz-tree-image(query, OrganizerQuery_Downloads) { list-style-image: url("chrome://browser/skin/places/downloads.png"); -moz-image-region: auto; }
deleted file mode 100644 index 2f97e742a3f0855c97a356c9f699b3bda3ac7c7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
deleted file mode 100644 index 5d796cc4c57dd3da1669fd4e51ba8d954ed4c866..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@<O00001
new file mode 100644 --- /dev/null +++ b/build/autoconf/mozcommonheader.m4 @@ -0,0 +1,41 @@ +dnl ***** BEGIN LICENSE BLOCK ***** +dnl Version: MPL 1.1/GPL 2.0/LGPL 2.1 +dnl +dnl The contents of this file are subject to the Mozilla Public License Version +dnl 1.1 (the "License"); you may not use this file except in compliance with +dnl the License. You may obtain a copy of the License at +dnl http://www.mozilla.org/MPL/ +dnl +dnl Software distributed under the License is distributed on an "AS IS" basis, +dnl WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +dnl for the specific language governing rights and limitations under the +dnl License. +dnl +dnl The Original Code is mozilla.org code. +dnl +dnl The Initial Developer of the Original Code is the +dnl Mozilla Foundation <http://www.mozilla.org> +dnl +dnl Portions created by the Initial Developer are Copyright (C) 2009 +dnl the Initial Developer. All Rights Reserved. +dnl +dnl +dnl Alternatively, the contents of this file may be used under the terms of +dnl either of the GNU General Public License Version 2 or later (the "GPL"), +dnl or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +dnl in which case the provisions of the GPL or the LGPL are applicable instead +dnl of those above. If you wish to allow use of your version of this file only +dnl under the terms of either the GPL or the LGPL, and not to allow others to +dnl use your version of this file under the terms of the MPL, indicate your +dnl decision by deleting the provisions above and replace them with the notice +dnl and other provisions required by the GPL or the LGPL. If you do not delete +dnl the provisions above, a recipient may use your version of this file under +dnl the terms of any one of the MPL, the GPL or the LGPL. +dnl +dnl ***** END LICENSE BLOCK ***** + +AC_DEFUN(MOZ_CHECK_COMMON_HEADERS, + MOZ_CHECK_HEADERS(sys/byteorder.h compat.h getopt.h sys/bitypes.h \ + memory.h unistd.h gnu/libc-version.h nl_types.h malloc.h \ + X11/XKBlib.h io.h cpuid.h) +)
--- a/build/autoconf/mozheader.m4 +++ b/build/autoconf/mozheader.m4 @@ -31,35 +31,36 @@ dnl under the terms of either the GPL or dnl use your version of this file under the terms of the MPL, indicate your dnl decision by deleting the provisions above and replace them with the notice dnl and other provisions required by the GPL or the LGPL. If you do not delete dnl the provisions above, a recipient may use your version of this file under dnl the terms of any one of the MPL, the GPL or the LGPL. dnl dnl ***** END LICENSE BLOCK ***** -dnl MOZ_CHECK_HEADER(HEADER-FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl MOZ_CHECK_HEADER(HEADER-FILE, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]]) AC_DEFUN([MOZ_CHECK_HEADER], [ dnl Do the transliteration at runtime so arg 1 can be a shell variable. ac_safe=`echo "$1" | sed 'y%./+-%__p_%'` AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(ac_cv_header_$ac_safe, - [ AC_TRY_COMPILE([#include <$1>], , + [ AC_TRY_COMPILE([$4 +#include <$1>], , eval "ac_cv_header_$ac_safe=yes", eval "ac_cv_header_$ac_safe=no") ]) if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then AC_MSG_RESULT(yes) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) ifelse([$3], , , [$3]) fi ]) -dnl MOZ_CHECK_HEADERS(HEADER-FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl MOZ_CHECK_HEADERS(HEADER-FILE... [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, INCLUDES]]]) AC_DEFUN([MOZ_CHECK_HEADERS], [ for ac_hdr in $1 do MOZ_CHECK_HEADER($ac_hdr, [ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` - AC_DEFINE_UNQUOTED($ac_tr_hdr) $2], $3) + AC_DEFINE_UNQUOTED($ac_tr_hdr) $2], $3, [$4]) done ])
--- a/build/automation.py.in +++ b/build/automation.py.in @@ -362,16 +362,19 @@ user_pref("test.mousescroll", true); user_pref("security.default_personal_cert", "Select Automatically"); // Need to client auth test be w/o any dialogs user_pref("network.http.prompt-temp-redirect", false); user_pref("media.cache_size", 100); user_pref("security.warn_viewing_mixed", false); user_pref("app.update.enabled", false); user_pref("browser.panorama.experienced_first_run", true); // Assume experienced user_pref("dom.w3c_touch_events.enabled", true); user_pref("toolkit.telemetry.prompted", 2); +// Existing tests assume there is no font size inflation. +user_pref("font.size.inflation.emPerLine", 0); +user_pref("font.size.inflation.minTwips", 0); // Only load extensions from the application and user profile // AddonManager.SCOPE_PROFILE + AddonManager.SCOPE_APPLICATION user_pref("extensions.enabledScopes", 5); // Disable metadata caching for installed add-ons by default user_pref("extensions.getAddons.cache.enabled", false); // Disable intalling any distribution add-ons user_pref("extensions.installDistroAddons", false);
new file mode 100644 --- /dev/null +++ b/build/unix/mozconfig.linux @@ -0,0 +1,2 @@ +CC=/tools/gcc-4.5-0moz2/bin/gcc +CXX=/tools/gcc-4.5-0moz2/bin/g++
--- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -114,17 +114,16 @@ MOZ_MEMORY = @MOZ_MEMORY@ MOZ_PROFILING = @MOZ_PROFILING@ MOZ_ENABLE_PROFILER_SPS = @MOZ_ENABLE_PROFILER_SPS@ MOZ_JPROF = @MOZ_JPROF@ MOZ_SHARK = @MOZ_SHARK@ MOZ_CALLGRIND = @MOZ_CALLGRIND@ MOZ_VTUNE = @MOZ_VTUNE@ MOZ_ETW = @MOZ_ETW@ MOZ_TRACE_JSCALLS = @MOZ_TRACE_JSCALLS@ -MOZ_TRACEVIS = @MOZ_TRACEVIS@ DEHYDRA_PATH = @DEHYDRA_PATH@ NS_TRACE_MALLOC = @NS_TRACE_MALLOC@ USE_ELF_DYNSTR_GC = @USE_ELF_DYNSTR_GC@ USE_ELF_HACK = @USE_ELF_HACK@ STDCXX_COMPAT = @STDCXX_COMPAT@ MOZ_LIBSTDCXX_TARGET_VERSION=@MOZ_LIBSTDCXX_TARGET_VERSION@ MOZ_LIBSTDCXX_HOST_VERSION=@MOZ_LIBSTDCXX_HOST_VERSION@
--- a/configure.in +++ b/configure.in @@ -3404,22 +3404,17 @@ dnl Checks for header files. dnl ======================================================== AC_HEADER_DIRENT case "$target_os" in freebsd*|openbsd*) # for stuff like -lXshm CPPFLAGS="${CPPFLAGS} ${X_CFLAGS}" ;; esac -MOZ_CHECK_HEADERS(sys/byteorder.h compat.h getopt.h) -MOZ_CHECK_HEADERS(sys/bitypes.h memory.h unistd.h) -MOZ_CHECK_HEADERS(gnu/libc-version.h nl_types.h) -MOZ_CHECK_HEADERS(malloc.h) -MOZ_CHECK_HEADERS(X11/XKBlib.h) -MOZ_CHECK_HEADERS(io.h) +MOZ_CHECK_COMMON_HEADERS dnl These are all the places some variant of statfs can be hiding. MOZ_CHECK_HEADERS(sys/statvfs.h sys/statfs.h sys/vfs.h sys/mount.h) dnl Quota support MOZ_CHECK_HEADERS(sys/quota.h sys/sysmacros.h) MOZ_CHECK_HEADERS(linux/quota.h) @@ -5930,22 +5925,21 @@ MOZ_ARG_DISABLE_BOOL(xtf, [ --disable-xtf Disable XTF (pluggable xml tags) support], MOZ_XTF=, MOZ_XTF=1 ) if test "$MOZ_XTF"; then AC_DEFINE(MOZ_XTF) fi dnl ======================================================== -dnl Pref extensions (autoconfig and system-pref) +dnl Pref extensions (autoconfig) dnl ======================================================== MOZ_ARG_DISABLE_BOOL(pref-extensions, [ --disable-pref-extensions - Disable pref extensions such as autoconfig and - system-pref], + Disable pref extensions such as autoconfig], MOZ_PREF_EXTENSIONS=, MOZ_PREF_EXTENSIONS=1 ) dnl ======================================================== dnl Searching of system directories for extensions. dnl Note: this switch is meant to be used for test builds dnl whose behavior should not depend on what happens to be dnl installed on the local machine. @@ -7322,27 +7316,16 @@ MOZ_ARG_ENABLE_BOOL(trace-jscalls, [ --enable-trace-jscalls Enable JS call enter/exit callback (default=no)], MOZ_TRACE_JSCALLS=1, MOZ_TRACE_JSCALLS= ) if test -n "$MOZ_TRACE_JSCALLS"; then AC_DEFINE(MOZ_TRACE_JSCALLS) fi dnl ======================================================== -dnl = Use TraceVis -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(tracevis, -[ --enable-tracevis Enable TraceVis tracing tool (default=no)], - MOZ_TRACEVIS=1, - MOZ_TRACEVIS= ) -if test -n "$MOZ_TRACEVIS"; then - AC_DEFINE(MOZ_TRACEVIS) -fi - -dnl ======================================================== dnl = Use incremental GC dnl ======================================================== JSGC_INCREMENTAL=1 MOZ_ARG_DISABLE_BOOL(gcincremental, [ --disable-gcincremental Disable incremental GC], JSGC_INCREMENTAL= ) if test -n "$JSGC_INCREMENTAL"; then AC_DEFINE(JSGC_INCREMENTAL) @@ -8756,18 +8739,18 @@ if test -n "$MOZ_WEBGL_GLX"; then fi fi # MOZ_WEBGL_GLX fi # COMPILE_ENVIRONMENT if test "$USE_FC_FREETYPE"; then if test "$COMPILE_ENVIRONMENT"; then _SAVE_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $FT2_CFLAGS $XCFLAGS" - AC_CHECK_HEADERS(fontconfig/fcfreetype.h, , - [AC_MSG_ERROR(Can't find header fontconfig/fcfreetype.h.)]) + MOZ_CHECK_HEADERS([fontconfig/fcfreetype.h], , + [AC_MSG_ERROR(Can't find header fontconfig/fcfreetype.h.)], [#include <fontconfig/fontconfig.h>]) CPPFLAGS="$_SAVE_CPPFLAGS" else AC_DEFINE(HAVE_FONTCONFIG_FCFREETYPE_H) fi fi dnl Set various defines and substitutions dnl ========================================================
--- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1285,21 +1285,16 @@ public: #endif } } static void ReleaseWrapper(nsISupports* aScriptObjectHolder, nsWrapperCache* aCache); static void TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback, void *aClosure); - /** - * Convert nsIContent::IME_STATUS_* to nsIWidget::IME_STATUS_* - */ - static PRUint32 GetWidgetStatusFromIMEStatus(PRUint32 aState); - /* * Notify when the first XUL menu is opened and when the all XUL menus are * closed. At opening, aInstalling should be TRUE, otherwise, it should be * FALSE. */ static void NotifyInstalledMenuKeyboardListener(bool aInstalling); /**
--- a/content/base/public/nsIAttribute.h +++ b/content/base/public/nsIAttribute.h @@ -41,18 +41,18 @@ #define nsIAttribute_h___ #include "nsINode.h" class nsDOMAttributeMap; class nsIContent; #define NS_IATTRIBUTE_IID \ -{ 0xf809b623, 0x5b1e, 0x4121, \ - { 0xb8, 0x9d, 0x19, 0x24, 0x7b, 0x70, 0x77, 0x08 } } +{ 0x536167ae, 0x8a9c, 0x4712, \ + { 0x8b, 0x61, 0x3, 0x43, 0xf6, 0xbc, 0x64, 0x75 } } class nsIAttribute : public nsINode { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IATTRIBUTE_IID) virtual void SetMap(nsDOMAttributeMap *aMap) = 0;
--- a/content/base/public/nsIContent.h +++ b/content/base/public/nsIContent.h @@ -58,37 +58,42 @@ class nsTextFragment; class nsIDocShell; class nsIFrame; class nsISMILAttr; class nsIDOMCSSStyleDeclaration; namespace mozilla { namespace css { class StyleRule; -} -} +} // namespace css +namespace widget { +struct IMEState; +} // namespace widget +} // namespace mozilla enum nsLinkState { eLinkState_Unknown = 0, eLinkState_Unvisited = 1, eLinkState_Visited = 2, eLinkState_NotLink = 3 }; // IID for the nsIContent interface #define NS_ICONTENT_IID \ -{ 0xb651e0a7, 0x1471, 0x49cc, \ - { 0xb4, 0xe1, 0xc2, 0xca, 0x01, 0xfe, 0xb7, 0x80 } } +{ 0xed40a3e5, 0xd7ed, 0x473e, \ + { 0x85, 0xe3, 0x82, 0xc3, 0xf0, 0x41, 0xdb, 0x52 } } /** * A node of content in a document's content model. This interface * is supported by all content objects. */ class nsIContent : public nsINode { public: + typedef mozilla::widget::IMEState IMEState; + #ifdef MOZILLA_INTERNAL_API // If you're using the external API, the only thing you can know about // nsIContent is that it exists with an IID nsIContent(already_AddRefed<nsINodeInfo> aNodeInfo) : nsINode(aNodeInfo), mPrimaryFrame(nsnull) { @@ -599,50 +604,28 @@ public: bool aIsTrustedEvent) { } /* * Get desired IME state for the content. * * @return The desired IME status for the content. - * This is a combination of IME_STATUS_* flags, - * controlling what happens to IME when the content takes focus. - * If this is IME_STATUS_NONE, IME remains in its current state. - * IME_STATUS_ENABLE and IME_STATUS_DISABLE must not be set - * together; likewise IME_STATUS_OPEN and IME_STATUS_CLOSE must - * not be set together. - * If you return IME_STATUS_DISABLE, you should not set the - * OPEN or CLOSE flag; that way, when IME is next enabled, - * the previous OPEN/CLOSE state will be restored (unless the newly - * focused content specifies the OPEN/CLOSE state by setting the OPEN - * or CLOSE flag with the ENABLE flag). - * IME_STATUS_PASSWORD should be returned only from password editor, - * this value has a special meaning. It is used as alternative of - * IME_STATUS_DISABLED. - * IME_STATUS_PLUGIN should be returned only when plug-in has focus. - * When a plug-in is focused content, we should send native events - * directly. Because we don't process some native events, but they may - * be needed by the plug-in. + * This is a combination of an IME enabled value and + * an IME open value of widget::IMEState. + * If you return DISABLED, you should not set the OPEN and CLOSE + * value. + * PASSWORD should be returned only from password editor, this value + * has a special meaning. It is used as alternative of DISABLED. + * PLUGIN should be returned only when plug-in has focus. When a + * plug-in is focused content, we should send native events directly. + * Because we don't process some native events, but they may be needed + * by the plug-in. */ - enum { - IME_STATUS_NONE = 0x0000, - IME_STATUS_ENABLE = 0x0001, - IME_STATUS_DISABLE = 0x0002, - IME_STATUS_PASSWORD = 0x0004, - IME_STATUS_PLUGIN = 0x0008, - IME_STATUS_OPEN = 0x0010, - IME_STATUS_CLOSE = 0x0020 - }; - enum { - IME_STATUS_MASK_ENABLED = IME_STATUS_ENABLE | IME_STATUS_DISABLE | - IME_STATUS_PASSWORD | IME_STATUS_PLUGIN, - IME_STATUS_MASK_OPENED = IME_STATUS_OPEN | IME_STATUS_CLOSE - }; - virtual PRUint32 GetDesiredIMEState(); + virtual IMEState GetDesiredIMEState(); /** * Gets content node with the binding (or native code, possibly on the * frame) responsible for our construction (and existence). Used by * anonymous content (both XBL-generated and native-anonymous). * * null for all explicit content (i.e., content reachable from the top * of its GetParent() chain via child lists).
--- a/content/base/public/nsIDOMFileReader.idl +++ b/content/base/public/nsIDOMFileReader.idl @@ -36,17 +36,17 @@ * ***** END LICENSE BLOCK ***** */ #include "nsIDOMEventTarget.idl" interface nsIDOMEventListener; interface nsIDOMBlob; interface nsIDOMFileError; -[scriptable, builtinclass, uuid(fc316500-87c4-411e-ab75-dd62468f4174)] +[scriptable, builtinclass, uuid(d158de26-904e-4731-b42c-8b3a4d172703)] interface nsIDOMFileReader : nsIDOMEventTarget { [implicit_jscontext] void readAsArrayBuffer(in nsIDOMBlob filedata); void readAsBinaryString(in nsIDOMBlob filedata); void readAsText(in nsIDOMBlob filedata, [optional] in DOMString encoding); void readAsDataURL(in nsIDOMBlob file);
--- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -59,17 +59,17 @@ #include "nsIVariant.h" #include "nsIObserver.h" #include "nsGkAtoms.h" #include "nsAutoPtr.h" #include "nsPIDOMWindow.h" #include "nsSMILAnimationController.h" #include "nsIScriptGlobalObject.h" #include "nsIDocumentEncoder.h" -#include "nsIAnimationFrameListener.h" +#include "nsIFrameRequestCallback.h" #include "nsEventStates.h" #include "nsIStructuredCloneContainer.h" #include "nsIBFCacheEntry.h" #include "nsDOMMemoryReporter.h" class nsIContent; class nsPresContext; class nsIPresShell; @@ -119,18 +119,18 @@ class Loader; namespace dom { class Link; class Element; } // namespace dom } // namespace mozilla #define NS_IDOCUMENT_IID \ -{ 0x184e0a3c, 0x1899, 0x417d, \ - { 0xbf, 0xf4, 0x5a, 0x15, 0xe6, 0xe8, 0xaa, 0x94 } } +{ 0x3b78f6, 0x6dc5, 0x44c6, \ + { 0xbc, 0x28, 0x60, 0x2a, 0xb2, 0x4f, 0xfb, 0x7b } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) // Enum for requesting a particular type of document when creating a doc enum DocumentFlavor { DocumentFlavorLegacyGuess, // compat with old code until made HTML5-compliant DocumentFlavorHTML, // HTMLDocument with HTMLness bit set to true @@ -1513,28 +1513,24 @@ public: * Lookup an image element using its associated ID, which is usually provided * by |-moz-element()|. Similar to GetElementById, with the difference that * elements set using mozSetImageElement have higher priority. * @param aId the ID associated the element we want to lookup * @return the element associated with |aId| */ virtual Element* LookupImageElement(const nsAString& aElementId) = 0; - void ScheduleBeforePaintEvent(nsIAnimationFrameListener* aListener); - void BeforePaintEventFiring() - { - mHavePendingPaint = false; - } + void ScheduleFrameRequestCallback(nsIFrameRequestCallback* aCallback); - typedef nsTArray< nsCOMPtr<nsIAnimationFrameListener> > AnimationListenerList; + typedef nsTArray< nsCOMPtr<nsIFrameRequestCallback> > FrameRequestCallbackList; /** - * Put this documents animation frame listeners into the provided + * Put this document's frame request callbacks into the provided * list, and forget about them. */ - void TakeAnimationFrameListeners(AnimationListenerList& aListeners); + void TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks); // This returns true when the document tree is being teared down. bool InUnlinkOrDeletion() { return mInUnlinkOrDeletion; } /* * Image Tracking * * Style and content images register their imgIRequests with their document @@ -1741,19 +1737,16 @@ protected: bool mCreatingStaticClone; // True iff the document is being unlinked or deleted. bool mInUnlinkOrDeletion; // True if document has ever had script handling object. bool mHasHadScriptHandlingObject; - // True if we're waiting for a before-paint event. - bool mHavePendingPaint; - // True if we're an SVG document being used as an image. bool mIsBeingUsedAsImage; // True is this document is synthetic : stand alone image, video, audio // file, etc. bool mIsSyntheticDocument; // True if this document has links whose state needs updating @@ -1807,17 +1800,17 @@ protected: PRUint32 mExternalScriptsBeingEvaluated; // Weak reference to mScriptGlobalObject QI:d to nsPIDOMWindow, // updated on every set of mSecriptGlobalObject. nsPIDOMWindow *mWindow; nsCOMPtr<nsIDocumentEncoder> mCachedEncoder; - AnimationListenerList mAnimationFrameListeners; + FrameRequestCallbackList mFrameRequestCallbacks; // This object allows us to evict ourself from the back/forward cache. The // pointer is non-null iff we're currently in the bfcache. nsIBFCacheEntry *mBFCacheEntry; // Our base target. nsString mBaseTarget;
--- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -283,18 +283,18 @@ private: // Categories of node properties // 0 is global. #define DOM_USER_DATA 1 #define DOM_USER_DATA_HANDLER 2 #define SMIL_MAPPED_ATTR_ANIMVAL 3 // IID for the nsINode interface #define NS_INODE_IID \ -{ 0x20d16be2, 0x3c58, 0x4099, \ - { 0xbf, 0xa6, 0xd0, 0xe7, 0x6b, 0xb1, 0x3d, 0xc5 } } +{ 0xd026d280, 0x5b25, 0x41c0, \ + { 0x92, 0xcf, 0x6, 0xf6, 0xf, 0xb, 0x9a, 0xfe } } /** * An internal interface that abstracts some DOMNode-related parts that both * nsIContent and nsIDocument share. An instance of this interface has a list * of nsIContent children and provides access to them. */ class nsINode : public nsIDOMEventTarget, public nsWrapperCache @@ -723,16 +723,17 @@ public: return mParent && mParent->IsElement() ? mParent : nsnull; } /** * See nsIDOMEventTarget */ NS_DECL_NSIDOMEVENTTARGET using nsIDOMEventTarget::AddEventListener; + using nsIDOMEventTarget::AddSystemEventListener; /** * Adds a mutation observer to be notified when this node, or any of its * descendants, are modified. The node will hold a weak reference to the * observer, which means that it is the responsibility of the observer to * remove itself in case it dies before the node. If an observer is added * while observers are being notified, it may also be notified. In general, * adding observers while inside a notification is not a good idea. An
--- a/content/base/public/nsIXMLHttpRequest.idl +++ b/content/base/public/nsIXMLHttpRequest.idl @@ -48,28 +48,28 @@ interface nsPIDOMWindow; interface nsIInputStream; interface nsIDOMBlob; %{C++ // for jsval #include "jsapi.h" %} -[scriptable, builtinclass, uuid(dea238a1-240f-45f4-9f07-7769bc69eb76)] +[scriptable, builtinclass, uuid(e2b59e48-3655-4429-a94c-b4332c346ba2)] interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget { // event handler attributes attribute nsIDOMEventListener onabort; attribute nsIDOMEventListener onerror; attribute nsIDOMEventListener onload; attribute nsIDOMEventListener onloadstart; attribute nsIDOMEventListener onprogress; attribute nsIDOMEventListener onloadend; }; -[scriptable, builtinclass, uuid(09ff3682-7759-4441-a765-f70e1a1fabcf)] +[scriptable, builtinclass, uuid(db9357fc-edf7-42b2-aab2-c24ab19ece20)] interface nsIXMLHttpRequestUpload : nsIXMLHttpRequestEventTarget { // for future use }; /** * Mozilla's XMLHttpRequest is modelled after Microsoft's IXMLHttpRequest * object. The goal has been to make Mozilla's version match Microsoft's * version as closely as possible, but there are bound to be some differences.
--- a/content/base/src/nsCCUncollectableMarker.cpp +++ b/content/base/src/nsCCUncollectableMarker.cpp @@ -46,16 +46,19 @@ #include "nsIWindowMediator.h" #include "nsPIDOMWindow.h" #include "nsIWebNavigation.h" #include "nsISHistory.h" #include "nsISHEntry.h" #include "nsISHContainer.h" #include "nsIWindowWatcher.h" #include "mozilla/Services.h" +#include "nsIXULWindow.h" +#include "nsIAppShellService.h" +#include "nsAppShellCID.h" static bool sInited = 0; PRUint32 nsCCUncollectableMarker::sGeneration = 0; NS_IMPL_ISUPPORTS1(nsCCUncollectableMarker, nsIObserver) /* static */ nsresult @@ -226,11 +229,24 @@ nsCCUncollectableMarker::Observe(nsISupp do_GetService(NS_WINDOWWATCHER_CONTRACTID); if (ww) { rv = ww->GetWindowEnumerator(getter_AddRefs(windowList)); NS_ENSURE_SUCCESS(rv, rv); MarkWindowList(windowList); } + nsCOMPtr<nsIAppShellService> appShell = + do_GetService(NS_APPSHELLSERVICE_CONTRACTID); + if (appShell) { + nsCOMPtr<nsIXULWindow> hw; + appShell->GetHiddenWindow(getter_AddRefs(hw)); + if (hw) { + nsCOMPtr<nsIDocShell> shell; + hw->GetDocShell(getter_AddRefs(shell)); + nsCOMPtr<nsIDocShellTreeNode> shellTreeNode = do_QueryInterface(shell); + MarkDocShell(shellTreeNode); + } + } + return NS_OK; }
--- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -207,16 +207,17 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_ #include "nsIObjectLoadingContent.h" #include "mozilla/Preferences.h" #include "nsWrapperCacheInlines.h" using namespace mozilla::dom; using namespace mozilla::layers; +using namespace mozilla::widget; using namespace mozilla; const char kLoadAsData[] = "loadAsData"; static const char kJSStackContractID[] = "@mozilla.org/js/xpc/ContextStack;1"; static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID); static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID); @@ -4022,35 +4023,16 @@ nsContentUtils::DropJSObjects(void* aScr nsresult rv = sXPConnect->RemoveJSHolder(aScriptObjectHolder); if (--sJSGCThingRootCount == 0) { nsLayoutStatics::Release(); } return rv; } /* static */ -PRUint32 -nsContentUtils::GetWidgetStatusFromIMEStatus(PRUint32 aState) -{ - switch (aState & nsIContent::IME_STATUS_MASK_ENABLED) { - case nsIContent::IME_STATUS_DISABLE: - return nsIWidget::IME_STATUS_DISABLED; - case nsIContent::IME_STATUS_ENABLE: - return nsIWidget::IME_STATUS_ENABLED; - case nsIContent::IME_STATUS_PASSWORD: - return nsIWidget::IME_STATUS_PASSWORD; - case nsIContent::IME_STATUS_PLUGIN: - return nsIWidget::IME_STATUS_PLUGIN; - default: - NS_ERROR("The given state doesn't have valid enable state"); - return nsIWidget::IME_STATUS_ENABLED; - } -} - -/* static */ void nsContentUtils::NotifyInstalledMenuKeyboardListener(bool aInstalling) { nsIMEStateManager::OnInstalledMenuKeyboardListener(aInstalling); } static bool SchemeIs(nsIURI* aURI, const char* aScheme) { @@ -5439,16 +5421,20 @@ public: nsCycleCollectionParticipant* helper) { } NS_IMETHOD_(void) NoteNextEdgeName(const char* name) { } + NS_IMETHOD_(void) NoteWeakMapping(void* map, void* key, void* val) + { + } + bool mFound; private: void* mWrapper; }; static void DebugWrapperTraceCallback(PRUint32 langID, void *p, const char *name,
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1876,19 +1876,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFullScreenElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStateObjectCached) // Traverse all our nsCOMArrays. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPreloadingImages) - for (PRUint32 i = 0; i < tmp->mAnimationFrameListeners.Length(); ++i) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mAnimationFrameListeners[i]"); - cb.NoteXPCOMChild(tmp->mAnimationFrameListeners[i]); + for (PRUint32 i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]"); + cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i]); } // Traverse animation components if (tmp->mAnimationController) { tmp->mAnimationController->Traverse(&cb); } if (tmp->mSubDocuments && tmp->mSubDocuments->ops) { @@ -1946,17 +1946,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns tmp->mListenerManager = nsnull; } if (tmp->mSubDocuments) { PL_DHashTableDestroy(tmp->mSubDocuments); tmp->mSubDocuments = nsnull; } - tmp->mAnimationFrameListeners.Clear(); + tmp->mFrameRequestCallbacks.Clear(); tmp->mRadioGroups.Clear(); // nsDocument has a pretty complex destructor, so we're going to // assume that *most* cycles you actually want to break somewhere // else, and not unlink an awful lot here. tmp->mIdentifierMap.Clear(); @@ -3209,51 +3209,45 @@ void nsDocument::MaybeRescheduleAnimationFrameNotifications() { if (!mPresShell || !IsEventHandlingEnabled()) { // bail out for now, until one of those conditions changes return; } nsRefreshDriver* rd = mPresShell->GetPresContext()->RefreshDriver(); - if (mHavePendingPaint) { - rd->ScheduleBeforePaintEvent(this); - } - if (!mAnimationFrameListeners.IsEmpty()) { - rd->ScheduleAnimationFrameListeners(this); - } -} - -void -nsIDocument::TakeAnimationFrameListeners(AnimationListenerList& aListeners) -{ - aListeners.AppendElements(mAnimationFrameListeners); - mAnimationFrameListeners.Clear(); + if (!mFrameRequestCallbacks.IsEmpty()) { + rd->ScheduleFrameRequestCallbacks(this); + } +} + +void +nsIDocument::TakeFrameRequestCallbacks(FrameRequestCallbackList& aCallbacks) +{ + aCallbacks.AppendElements(mFrameRequestCallbacks); + mFrameRequestCallbacks.Clear(); } void nsDocument::DeleteShell() { mExternalResourceMap.HideViewers(); if (IsEventHandlingEnabled()) { RevokeAnimationFrameNotifications(); } mPresShell = nsnull; } void nsDocument::RevokeAnimationFrameNotifications() { - if (mHavePendingPaint) { - mPresShell->GetPresContext()->RefreshDriver()->RevokeBeforePaintEvent(this); - } - if (!mAnimationFrameListeners.IsEmpty()) { + if (!mFrameRequestCallbacks.IsEmpty()) { mPresShell->GetPresContext()->RefreshDriver()-> - RevokeAnimationFrameListeners(this); + RevokeFrameRequestCallbacks(this); } } static void SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) { SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry); @@ -8069,40 +8063,24 @@ nsIDocument::CreateStaticClone(nsISuppor } } } mCreatingStaticClone = false; return clonedDoc.forget(); } void -nsIDocument::ScheduleBeforePaintEvent(nsIAnimationFrameListener* aListener) -{ - if (aListener) { - bool alreadyRegistered = !mAnimationFrameListeners.IsEmpty(); - if (mAnimationFrameListeners.AppendElement(aListener) && - !alreadyRegistered && mPresShell && IsEventHandlingEnabled()) { - mPresShell->GetPresContext()->RefreshDriver()-> - ScheduleAnimationFrameListeners(this); - } - - return; - } - - if (!mHavePendingPaint) { - // We don't want to use GetShell() here, because we want to schedule the - // paint even if we're frozen. Either we'll get unfrozen and then the - // event will fire, or we'll quietly go away at some point. - mHavePendingPaint = - !mPresShell || - !IsEventHandlingEnabled() || - mPresShell->GetPresContext()->RefreshDriver()-> - ScheduleBeforePaintEvent(this); - } - +nsIDocument::ScheduleFrameRequestCallback(nsIFrameRequestCallback* aCallback) +{ + bool alreadyRegistered = !mFrameRequestCallbacks.IsEmpty(); + if (mFrameRequestCallbacks.AppendElement(aCallback) && + !alreadyRegistered && mPresShell && IsEventHandlingEnabled()) { + mPresShell->GetPresContext()->RefreshDriver()-> + ScheduleFrameRequestCallbacks(this); + } } nsresult nsDocument::GetStateObject(nsIVariant** aState) { // Get the document's current state object. This is the object backing both // history.state and popStateEvent.state. //
--- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -104,16 +104,17 @@ #include "nsGkAtoms.h" #include "nsContentUtils.h" #include "nsIJSContextStack.h" #include "nsIServiceManager.h" #include "nsIDOMEventListener.h" #include "nsIWebNavigation.h" #include "nsIBaseWindow.h" +#include "nsIWidget.h" #include "jsapi.h" #include "nsNodeInfoManager.h" #include "nsICategoryManager.h" #include "nsIDOMDocumentType.h" #include "nsIDOMUserDataHandler.h" #include "nsGenericHTMLElement.h" @@ -1092,27 +1093,51 @@ nsINode::AddEventListener(const nsAStrin nsEventListenerManager* listener_manager = GetListenerManager(true); NS_ENSURE_STATE(listener_manager); listener_manager->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted); return NS_OK; } NS_IMETHODIMP +nsINode::AddSystemEventListener(const nsAString& aType, + nsIDOMEventListener *aListener, + bool aUseCapture, + bool aWantsUntrusted, + PRUint8 aOptionalArgc) +{ + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, + "Won't check if this is chrome, you want to set " + "aWantsUntrusted to false or make the aWantsUntrusted " + "explicit by making aOptionalArgc non-zero."); + + if (!aWantsUntrusted && + (aOptionalArgc < 2 && + !nsContentUtils::IsChromeDoc(OwnerDoc()))) { + aWantsUntrusted = true; + } + + return NS_AddSystemEventListener(this, aType, aListener, aUseCapture, + aWantsUntrusted); +} + +NS_IMETHODIMP nsINode::RemoveEventListener(const nsAString& aType, nsIDOMEventListener* aListener, bool aUseCapture) { nsEventListenerManager* elm = GetListenerManager(false); if (elm) { elm->RemoveEventListener(aType, aListener, aUseCapture); } return NS_OK; } +NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsINode) + nsresult nsINode::PreHandleEvent(nsEventChainPreVisitor& aVisitor) { // This is only here so that we can use the NS_DECL_NSIDOMTARGET macro NS_ABORT(); return NS_ERROR_NOT_IMPLEMENTED; } @@ -1334,53 +1359,50 @@ nsIContent::GetFlattenedTreeParent() con doc->BindingManager()->GetNestedInsertionPoint(parent, this); if (insertionElement) { parent = insertionElement; } } return parent; } -PRUint32 +nsIContent::IMEState nsIContent::GetDesiredIMEState() { if (!IsEditableInternal()) { - return IME_STATUS_DISABLE; + return IMEState(IMEState::DISABLED); } // NOTE: The content for independent editors (e.g., input[type=text], // textarea) must override this method, so, we don't need to worry about // that here. nsIContent *editableAncestor = GetEditingHost(); // This is in another editable content, use the result of it. if (editableAncestor && editableAncestor != this) { return editableAncestor->GetDesiredIMEState(); } nsIDocument* doc = GetCurrentDoc(); if (!doc) { - return IME_STATUS_DISABLE; + return IMEState(IMEState::DISABLED); } nsIPresShell* ps = doc->GetShell(); if (!ps) { - return IME_STATUS_DISABLE; + return IMEState(IMEState::DISABLED); } nsPresContext* pc = ps->GetPresContext(); if (!pc) { - return IME_STATUS_DISABLE; + return IMEState(IMEState::DISABLED); } nsIEditor* editor = GetHTMLEditor(pc); nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor); if (!imeEditor) { - return IME_STATUS_DISABLE; - } - // Use "enable" for the default value because IME is disabled unexpectedly, - // it makes serious a11y problem. - PRUint32 state = IME_STATUS_ENABLE; - nsresult rv = imeEditor->GetPreferredIMEState(&state); - NS_ENSURE_SUCCESS(rv, IME_STATUS_ENABLE); + return IMEState(IMEState::DISABLED); + } + IMEState state; + imeEditor->GetPreferredIMEState(&state); return state; } bool nsIContent::HasIndependentSelection() { nsIFrame* frame = GetPrimaryFrame(); return (frame && frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION);
--- a/content/base/src/nsInProcessTabChildGlobal.cpp +++ b/content/base/src/nsInProcessTabChildGlobal.cpp @@ -306,17 +306,17 @@ nsInProcessTabChildGlobal::InitTabChildG mCx = cx; nsContentUtils::XPConnect()->SetSecurityManagerForJSContext(cx, nsContentUtils::GetSecurityManager(), 0); nsContentUtils::GetSecurityManager()->GetSystemPrincipal(getter_AddRefs(mPrincipal)); JS_SetNativeStackQuota(cx, 128 * sizeof(size_t) * 1024); - JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_JIT | JSOPTION_PRIVATE_IS_NSISUPPORTS); + JS_SetOptions(cx, JS_GetOptions(cx) | JSOPTION_PRIVATE_IS_NSISUPPORTS); JS_SetVersion(cx, JSVERSION_LATEST); JS_SetErrorReporter(cx, ContentScriptErrorReporter); xpc_LocalizeContext(cx); JSAutoRequest ar(cx); nsIXPConnect* xpc = nsContentUtils::XPConnect(); const PRUint32 flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES |
--- a/content/base/src/nsRange.cpp +++ b/content/base/src/nsRange.cpp @@ -2162,19 +2162,19 @@ static nsresult GetPartialTextRect(nsLay nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame); nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame); for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) { PRInt32 fstart = f->GetContentOffset(), fend = f->GetContentEnd(); if (fend <= aStartOffset || fstart >= aEndOffset) continue; // overlapping with the offset we want - f->EnsureTextRun(); - NS_ENSURE_TRUE(f->GetTextRun(), NS_ERROR_OUT_OF_MEMORY); - bool rtl = f->GetTextRun()->IsRightToLeft(); + f->EnsureTextRun(nsTextFrame::eInflated); + NS_ENSURE_TRUE(f->GetTextRun(nsTextFrame::eInflated), NS_ERROR_OUT_OF_MEMORY); + bool rtl = f->GetTextRun(nsTextFrame::eInflated)->IsRightToLeft(); nsRect r(f->GetOffsetTo(relativeTo), f->GetSize()); if (fstart < aStartOffset) { // aStartOffset is within this frame ExtractRectFromOffset(f, relativeTo, aStartOffset, &r, rtl); } if (fend > aEndOffset) { // aEndOffset is in the middle of this frame ExtractRectFromOffset(f, relativeTo, aEndOffset, &r, !rtl);
--- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -879,17 +879,17 @@ NS_IMETHODIMP nsXMLHttpRequest::GetRespo if (!(mState & (XML_HTTP_REQUEST_DONE | XML_HTTP_REQUEST_LOADING))) { return NS_OK; } // We only decode text lazily if we're also parsing to a doc. // Also, if we've decoded all current data already, then no need to decode // more. - if (IsWaitingForHTMLCharset() || !mResponseXML || + if (!mResponseXML || mResponseBodyDecodedPos == mResponseBody.Length()) { aResponseText = mResponseText; return NS_OK; } nsresult rv; nsCOMPtr<nsIDocument> document = do_QueryInterface(mResponseXML); @@ -1468,26 +1468,16 @@ nsXMLHttpRequest::GetCurrentHttpChannel( } bool nsXMLHttpRequest::IsSystemXHR() { return !!nsContentUtils::IsSystemPrincipal(mPrincipal); } -bool -nsXMLHttpRequest::IsWaitingForHTMLCharset() -{ - if (!mIsHtml || !mResponseXML) { - return false; - } - nsCOMPtr<nsIDocument> doc = do_QueryInterface(mResponseXML); - return doc->GetDocumentCharacterSetSource() < kCharsetFromDocTypeDefault; -} - nsresult nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel) { // First check if cross-site requests are enabled... if (IsSystemXHR()) { return NS_OK; } @@ -1923,17 +1913,23 @@ nsXMLHttpRequest::OnStartRequest(nsIRequ if (parseBody && NS_SUCCEEDED(status)) { // We can gain a huge performance win by not even trying to // parse non-XML data. This also protects us from the situation // where we have an XML document and sink, but HTML (or other) // parser, which can produce unreliable results. nsCAutoString type; channel->GetContentType(type); - if (type.EqualsLiteral("text/html")) { + if ((mResponseType == XML_HTTP_RESPONSE_TYPE_DOCUMENT) && + type.EqualsLiteral("text/html")) { + // HTML parsing is only supported for responseType == "document" to + // avoid running the parser and, worse, populating responseXML for + // legacy users of XHR who use responseType == "" for retrieving the + // responseText of text/html resources. This legacy case is so common + // that it's not useful to emit a warning about it. if (!(mState & XML_HTTP_REQUEST_ASYNC)) { // We don't make cool new features available in the bad synchronous // mode. The synchronous mode is for legacy only. mWarnAboutSyncHtml = true; mState &= ~XML_HTTP_REQUEST_PARSEBODY; } else if (mState & XML_HTTP_REQUEST_MULTIPART) { // HTML parsing is supported only for non-multipart responses. The // multipart implementation assumes that it's OK to start the next part @@ -3133,23 +3129,21 @@ nsXMLHttpRequest::MaybeDispatchProgressE mUploadTotal, mUploadProgress, mUploadProgressMax); } } else { if (aFinalProgress) { mLoadTotal = mLoadTransferred; mLoadLengthComputable = true; } - if (aFinalProgress || !IsWaitingForHTMLCharset()) { - mInLoadProgressEvent = true; - DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR), - true, mLoadLengthComputable, mLoadTransferred, - mLoadTotal, mLoadTransferred, mLoadTotal); - mInLoadProgressEvent = false; - } + mInLoadProgressEvent = true; + DispatchProgressEvent(this, NS_LITERAL_STRING(PROGRESS_STR), + true, mLoadLengthComputable, mLoadTransferred, + mLoadTotal, mLoadTransferred, mLoadTotal); + mInLoadProgressEvent = false; if (mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_TEXT || mResponseType == XML_HTTP_RESPONSE_TYPE_CHUNKED_ARRAYBUFFER) { mResponseBody.Truncate(); mResponseText.Truncate(); mResultArrayBuffer = nsnull; } }
--- a/content/base/src/nsXMLHttpRequest.h +++ b/content/base/src/nsXMLHttpRequest.h @@ -231,18 +231,16 @@ protected: nsresult GetInnerEventListener(nsRefPtr<nsDOMEventListenerWrapper>& aWrapper, nsIDOMEventListener** aListener); already_AddRefed<nsIHttpChannel> GetCurrentHttpChannel(); bool IsSystemXHR(); - bool IsWaitingForHTMLCharset(); - void ChangeStateToDone(); /** * Check if aChannel is ok for a cross-site request by making sure no * inappropriate headers are set, and no username/password is set. * * Also updates the XML_HTTP_REQUEST_USE_XSITE_AC bit. */
--- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -505,17 +505,16 @@ include $(topsrcdir)/config/rules.mk somedatas.resource \ somedatas.resource^headers^ \ delayedServerEvents.sjs \ test_html_in_xhr.html \ file_html_in_xhr.html \ file_html_in_xhr2.html \ file_html_in_xhr3.html \ file_html_in_xhr.sjs \ - file_html_in_xhr_slow.sjs \ test_bug664916.html \ test_bug666604.html \ test_bug675121.html \ file_bug675121.sjs \ test_bug675166.html \ test_bug682554.html \ test_bug682592.html \ bug682592-subframe.html \
deleted file mode 100644 --- a/content/base/test/file_html_in_xhr_slow.sjs +++ /dev/null @@ -1,24 +0,0 @@ -var timer; - -function handleRequest(request, response) -{ - var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Components.interfaces.nsIScriptableUnicodeConverter); - converter.charset = "windows-1251"; - var stream = converter.convertToInputStream("\u042E"); - var out = response.bodyOutputStream; - response.setHeader("Cache-Control", "no-cache", false); - response.setHeader("Content-Type", "text/html", false); - out.writeFrom(stream, 1); - var firstPart = "<meta charset='windows"; - out.write(firstPart, firstPart.length); - out.flush(); - response.processAsync(); - timer = Components.classes["@mozilla.org/timer;1"] - .createInstance(Components.interfaces.nsITimer); - timer.initWithCallback(function() { - response.write("-1251'>"); - response.finish(); - }, 500, Components.interfaces.nsITimer.TYPE_ONE_SHOT); -} -
--- a/content/base/test/test_html_in_xhr.html +++ b/content/base/test/test_html_in_xhr.html @@ -24,52 +24,51 @@ SimpleTest.waitForExplicitFinish(); var xhr = new XMLHttpRequest(); function runTest() { xhr.onreadystatechange = function() { if (this.readyState == 4) { ok(this.responseXML, "Should have gotten responseXML"); is(this.responseXML.characterSet, "windows-1251", "Wrong character encoding"); is(this.responseXML.documentElement.firstChild.data, " \u042E ", "Decoded using the wrong encoding."); - is(this.responseText.indexOf("\u042E"), 27, "Bad responseText"); + try { + this.responseText; + ok(false, "responseText access should have thrown."); + } catch (e) { + is(e.code, 11, "Should have thrown INVALID_STATE_ERR."); + } is(this.responseXML.getElementsByTagName("div").length, 1, "There should be one div."); ok(!this.responseXML.documentElement.hasAttribute("data-fail"), "Should not have a data-fail attribute."); var scripts = this.responseXML.getElementsByTagName("script"); is(scripts.length, 4, "Unexpected number of scripts."); while (scripts.length) { // These should not run when moved to another doc document.body.appendChild(scripts[0]); } var s = document.createElement("script"); s.src = "file_html_in_xhr.sjs?report=1"; document.body.appendChild(s); } } xhr.open("GET", "file_html_in_xhr.html", true); + xhr.responseType = "document"; xhr.send(); } function continueAfterReport() { - ok(!document.documentElement.hasAttribute("data-fail"), "Should not have a data-fail attribute on mochitest doc."); xhr = new XMLHttpRequest(); - xhr.onprogress = function() { - ok(this.responseText, "Got falsy responseText"); - if (this.responseText) { - ok(this.responseText.length, "Got zero-length responseText"); - if (this.responseText.length) { - is(this.responseText.charCodeAt(0), 0x042E, "Wrong character encoding for slow text"); - } - } - } xhr.onreadystatechange = function() { if (this.readyState == 4) { + is(this.responseText.indexOf("\u042E"), -1, "Honored meta in default mode."); + is(this.responseText.indexOf("\uFFFD"), 29, "Honored meta in default mode 2."); + is(this.responseXML, null, "responseXML should be null for HTML in the default mode"); testNonParsingText(); } } - xhr.open("GET", "file_html_in_xhr_slow.sjs"); + xhr.open("GET", "file_html_in_xhr2.html"); xhr.send(); } function testNonParsingText() { xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4) { is(this.responseText.indexOf("\u042E"), -1, "Honored meta in text mode.");
--- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -1082,19 +1082,20 @@ public: return mImageInfos.ElementAt(level * mFacesCount + face); } const ImageInfo& ImageInfoAt(size_t level, size_t face) const { return const_cast<WebGLTexture*>(this)->ImageInfoAt(level, face); } bool HasImageInfoAt(size_t level, size_t face) const { - return level <= mMaxLevelWithCustomImages && - face < mFacesCount && - ImageInfoAt(level, 0).mIsDefined; + CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face; + return checked_index.valid() && + checked_index.value() < mImageInfos.Length() && + ImageInfoAt(level, face).mIsDefined; } static size_t FaceForTarget(WebGLenum target) { return target == LOCAL_GL_TEXTURE_2D ? 0 : target - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X; } PRInt64 MemoryUsage() const { PRInt64 result = 0;
--- a/content/canvas/test/webgl/failing_tests_mac.txt +++ b/content/canvas/test/webgl/failing_tests_mac.txt @@ -1,13 +1,11 @@ conformance/context/premultiplyalpha-test.html conformance/glsl/misc/glsl-function-nodes.html conformance/glsl/misc/glsl-long-variable-names.html conformance/glsl/misc/shader-with-256-character-identifier.frag.html conformance/glsl/misc/shader-with-long-line.html -conformance/textures/texture-mips.html -conformance/textures/texture-npot.html conformance/more/conformance/quickCheckAPI-S_V.html conformance/more/functions/uniformfBadArgs.html conformance/more/functions/uniformiBadArgs.html conformance/glsl/misc/attrib-location-length-limits.html conformance/glsl/misc/uniform-location-length-limits.html conformance/renderbuffers/framebuffer-object-attachment.html
--- a/content/events/public/nsIPrivateDOMEvent.h +++ b/content/events/public/nsIPrivateDOMEvent.h @@ -139,9 +139,11 @@ NS_NewDOMAnimationEvent(nsIDOMEvent** aI nsresult NS_NewDOMCloseEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsEvent* aEvent); nsresult NS_NewDOMMozTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsMozTouchEvent* aEvent); nsresult NS_NewDOMTouchEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, class nsInputEvent *aEvent); nsresult NS_NewDOMCustomEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent); +nsresult +NS_NewDOMSmsEvent(nsIDOMEvent** aInstancePtrResult, nsPresContext* aPresContext, nsEvent* aEvent); #endif // nsIPrivateDOMEvent_h__
--- a/content/events/src/nsDOMEventTargetHelper.cpp +++ b/content/events/src/nsDOMEventTargetHelper.cpp @@ -98,16 +98,18 @@ nsDOMEventTargetHelper::RemoveEventListe nsEventListenerManager* elm = GetListenerManager(false); if (elm) { elm->RemoveEventListener(aType, aListener, aUseCapture); } return NS_OK; } +NS_IMPL_REMOVE_SYSTEM_EVENT_LISTENER(nsDOMEventTargetHelper) + NS_IMETHODIMP nsDOMEventTargetHelper::AddEventListener(const nsAString& aType, nsIDOMEventListener *aListener, bool aUseCapture, bool aWantsUntrusted, PRUint8 aOptionalArgc) { NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, @@ -126,16 +128,41 @@ nsDOMEventTargetHelper::AddEventListener nsEventListenerManager* elm = GetListenerManager(true); NS_ENSURE_STATE(elm); elm->AddEventListener(aType, aListener, aUseCapture, aWantsUntrusted); return NS_OK; } NS_IMETHODIMP +nsDOMEventTargetHelper::AddSystemEventListener(const nsAString& aType, + nsIDOMEventListener *aListener, + bool aUseCapture, + bool aWantsUntrusted, + PRUint8 aOptionalArgc) +{ + NS_ASSERTION(!aWantsUntrusted || aOptionalArgc > 1, + "Won't check if this is chrome, you want to set " + "aWantsUntrusted to false or make the aWantsUntrusted " + "explicit by making aOptionalArgc non-zero."); + + if (aOptionalArgc < 2) { + nsresult rv; + nsIScriptContext* context = GetContextForEventHandlers(&rv); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr<nsIDocument> doc = + nsContentUtils::GetDocumentFromScriptContext(context); + aWantsUntrusted = doc && !nsContentUtils::IsChromeDoc(doc); + } + + return NS_AddSystemEventListener(this, aType, aListener, aUseCapture, + aWantsUntrusted); +} + +NS_IMETHODIMP nsDOMEventTargetHelper::DispatchEvent(nsIDOMEvent* aEvent, bool* aRetVal) { nsEventStatus status = nsEventStatus_eIgnore; nsresult rv = nsEventDispatcher::DispatchDOMEvent(this, nsnull, aEvent, nsnull, &status); *aRetVal = (status != nsEventStatus_eConsumeNoDefault); return rv;
--- a/content/events/src/nsEventDispatcher.cpp +++ b/content/events/src/nsEventDispatcher.cpp @@ -899,11 +899,13 @@ nsEventDispatcher::CreateEvent(nsPresCon return NS_NewDOMCloseEvent(aDOMEvent, aPresContext, nsnull); if (aEventType.LowerCaseEqualsLiteral("touchevent") && nsDOMTouchEvent::PrefEnabled()) return NS_NewDOMTouchEvent(aDOMEvent, aPresContext, nsnull); if (aEventType.LowerCaseEqualsLiteral("hashchangeevent")) return NS_NewDOMHashChangeEvent(aDOMEvent, aPresContext, nsnull); if (aEventType.LowerCaseEqualsLiteral("customevent")) return NS_NewDOMCustomEvent(aDOMEvent, aPresContext, nsnull); + if (aEventType.LowerCaseEqualsLiteral("mozsmsevent")) + return NS_NewDOMSmsEvent(aDOMEvent, aPresContext, nsnull); return NS_ERROR_DOM_NOT_SUPPORTED_ERR; }
--- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -400,17 +400,17 @@ nsEventListenerManager::SetJSEventListen { nsresult rv = NS_OK; PRUint32 eventType = nsContentUtils::GetEventId(aName); nsListenerStruct* ls = FindJSEventListener(eventType, aName); if (!ls) { // If we didn't find a script listener or no listeners existed // create and add a new one. - nsCOMPtr<nsIDOMEventListener> scriptListener; + nsCOMPtr<nsIJSEventListener> scriptListener; rv = NS_NewJSEventListener(aContext, aScopeObject, mTarget, aName, aHandler, getter_AddRefs(scriptListener)); if (NS_SUCCEEDED(rv)) { AddEventListener(scriptListener, eventType, aName, NS_EVENT_FLAG_BUBBLE | NS_PRIV_EVENT_FLAG_SCRIPT); ls = FindJSEventListener(eventType, aName); } @@ -696,20 +696,18 @@ nsEventListenerManager::CompileEventHand NS_ENSURE_SUCCESS(result, result); } } if (handler) { // Bind it nsScriptObjectHolder boundHandler(context); context->BindCompiledEventHandler(mTarget, listener->GetEventScope(), - handler, boundHandler); - listener->SetHandler( - static_cast<JSObject*>( - static_cast<void*>(boundHandler))); + handler.getObject(), boundHandler); + listener->SetHandler(boundHandler.getObject()); } return result; } nsresult nsEventListenerManager::HandleEventSubType(nsListenerStruct* aListenerStruct, nsIDOMEventListener* aListener,
--- a/content/events/src/nsEventListenerManager.h +++ b/content/events/src/nsEventListenerManager.h @@ -58,28 +58,36 @@ class nsIWidget; struct nsPoint; struct EventTypeData; class nsEventTargetChainItem; class nsPIDOMWindow; class nsCxPusher; class nsIEventListenerInfo; class nsIDocument; -typedef struct { +struct nsListenerStruct +{ nsRefPtr<nsIDOMEventListener> mListener; PRUint32 mEventType; nsCOMPtr<nsIAtom> mTypeAtom; PRUint16 mFlags; bool mHandlerIsString; nsIJSEventListener* GetJSListener() const { return (mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) ? static_cast<nsIJSEventListener *>(mListener.get()) : nsnull; } -} nsListenerStruct; + + ~nsListenerStruct() + { + if ((mFlags & NS_PRIV_EVENT_FLAG_SCRIPT) && mListener) { + static_cast<nsIJSEventListener*>(mListener.get())->Disconnect(); + } + } +}; /* * Event listener manager */ class nsEventListenerManager { @@ -313,9 +321,31 @@ protected: static PRUint32 mInstanceCount; static jsid sAddListenerID; friend class nsEventTargetChainItem; static PRUint32 sCreatedCount; }; +/** + * NS_AddSystemEventListener() is a helper function for implementing + * nsIDOMEventTarget::AddSystemEventListener(). + */ +inline nsresult +NS_AddSystemEventListener(nsIDOMEventTarget* aTarget, + const nsAString& aType, + nsIDOMEventListener *aListener, + bool aUseCapture, + bool aWantsUntrusted) +{ + nsEventListenerManager* listenerManager = aTarget->GetListenerManager(true); + NS_ENSURE_STATE(listenerManager); + PRUint32 flags = NS_EVENT_FLAG_SYSTEM_EVENT; + flags |= aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE; + if (aWantsUntrusted) { + flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED; + } + listenerManager->AddEventListenerByType(aListener, aType, flags); + return NS_OK; +} + #endif // nsEventListenerManager_h__
--- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -2539,17 +2539,18 @@ GetScrollableLineHeight(nsIFrame* aTarge for (nsIFrame* f = aTargetFrame; f; f = GetParentFrameToScroll(f)) { nsIScrollableFrame* sf = f->GetScrollTargetFrame(); if (sf) return sf->GetLineScrollAmount().height; } // Fall back to the font height of the target frame. nsRefPtr<nsFontMetrics> fm; - nsLayoutUtils::GetFontMetricsForFrame(aTargetFrame, getter_AddRefs(fm)); + nsLayoutUtils::GetFontMetricsForFrame(aTargetFrame, getter_AddRefs(fm), + nsLayoutUtils::FontSizeInflationFor(aTargetFrame)); NS_ASSERTION(fm, "FontMetrics is null!"); if (fm) return fm->MaxHeight(); return 0; } void nsEventStateManager::SendLineScrollEvent(nsIFrame* aTargetFrame,
--- a/content/events/src/nsIMEStateManager.cpp +++ b/content/events/src/nsIMEStateManager.cpp @@ -35,27 +35,28 @@ * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsIMEStateManager.h" #include "nsCOMPtr.h" -#include "nsIWidget.h" #include "nsIViewManager.h" #include "nsIPresShell.h" #include "nsISupports.h" #include "nsPIDOMWindow.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIEditorDocShell.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsPresContext.h" #include "nsIDOMWindow.h" +#include "nsIDOMMouseEvent.h" +#include "nsIDOMNSEvent.h" #include "nsContentUtils.h" #include "nsINode.h" #include "nsIFrame.h" #include "nsRange.h" #include "nsIDOMRange.h" #include "nsISelection.h" #include "nsISelectionPrivate.h" #include "nsISelectionListener.h" @@ -63,16 +64,18 @@ #include "nsIMutationObserver.h" #include "nsContentEventHandler.h" #include "nsIObserverService.h" #include "mozilla/Services.h" #include "nsIFormControl.h" #include "nsIForm.h" #include "nsHTMLFormElement.h" +using namespace mozilla::widget; + /******************************************************************/ /* nsIMEStateManager */ /******************************************************************/ nsIContent* nsIMEStateManager::sContent = nsnull; nsPresContext* nsIMEStateManager::sPresContext = nsnull; bool nsIMEStateManager::sInstalledMenuKeyboardListener = false; bool nsIMEStateManager::sInSecureInputMode = false; @@ -82,18 +85,20 @@ nsTextStateManager* nsIMEStateManager::s nsresult nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext) { NS_ENSURE_ARG_POINTER(aPresContext); if (aPresContext != sPresContext) return NS_OK; nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext); if (widget) { - PRUint32 newState = GetNewIMEState(sPresContext, nsnull); - SetIMEState(newState, nsnull, widget, IMEContext::FOCUS_REMOVED); + IMEState newState = GetNewIMEState(sPresContext, nsnull); + InputContextAction action(InputContextAction::CAUSE_UNKNOWN, + InputContextAction::LOST_FOCUS); + SetIMEState(newState, nsnull, widget, action); } sContent = nsnull; sPresContext = nsnull; OnTextStateBlur(nsnull, nsnull); return NS_OK; } nsresult @@ -107,30 +112,41 @@ nsIMEStateManager::OnRemoveContent(nsPre return NS_OK; // Current IME transaction should commit nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext); if (widget) { nsresult rv = widget->CancelIMEComposition(); if (NS_FAILED(rv)) widget->ResetInputState(); - PRUint32 newState = GetNewIMEState(sPresContext, nsnull); - SetIMEState(newState, nsnull, widget, IMEContext::FOCUS_REMOVED); + IMEState newState = GetNewIMEState(sPresContext, nsnull); + InputContextAction action(InputContextAction::CAUSE_UNKNOWN, + InputContextAction::LOST_FOCUS); + SetIMEState(newState, nsnull, widget, action); } sContent = nsnull; sPresContext = nsnull; return NS_OK; } nsresult nsIMEStateManager::OnChangeFocus(nsPresContext* aPresContext, nsIContent* aContent, - PRUint32 aReason) + InputContextAction::Cause aCause) +{ + InputContextAction action(aCause); + return OnChangeFocusInternal(aPresContext, aContent, action); +} + +nsresult +nsIMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext, + nsIContent* aContent, + InputContextAction aAction) { NS_ENSURE_ARG_POINTER(aPresContext); nsCOMPtr<nsIWidget> widget = GetWidget(aPresContext); if (!widget) { return NS_OK; } @@ -152,121 +168,155 @@ nsIMEStateManager::OnChangeFocus(nsPresC } else { if (contentIsPassword) { if (NS_SUCCEEDED(widget->BeginSecureKeyboardInput())) { sInSecureInputMode = true; } } } - PRUint32 newState = GetNewIMEState(aPresContext, aContent); + IMEState newState = GetNewIMEState(aPresContext, aContent); if (aPresContext == sPresContext && aContent == sContent) { // actual focus isn't changing, but if IME enabled state is changing, // we should do it. - PRUint32 newEnabledState = newState & nsIContent::IME_STATUS_MASK_ENABLED; - if (newEnabledState == 0) { - // the enabled state isn't changing, we should do nothing. - return NS_OK; - } - IMEContext context; - if (!widget || NS_FAILED(widget->GetInputMode(context))) { - // this platform doesn't support IME controlling - return NS_OK; - } - if (context.mStatus == - nsContentUtils::GetWidgetStatusFromIMEStatus(newEnabledState)) { + InputContext context = widget->GetInputContext(); + if (context.mIMEState.mEnabled == newState.mEnabled) { // the enabled state isn't changing. return NS_OK; } + aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED; + } else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) { + // If aContent isn't null or aContent is null but editable, somebody gets + // focus. + bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED); + aAction.mFocusChange = + gotFocus ? InputContextAction::GOT_FOCUS : InputContextAction::LOST_FOCUS; } // Current IME transaction should commit if (sPresContext) { nsCOMPtr<nsIWidget> oldWidget; if (sPresContext == aPresContext) oldWidget = widget; else oldWidget = GetWidget(sPresContext); if (oldWidget) oldWidget->ResetInputState(); } - if (newState != nsIContent::IME_STATUS_NONE) { - // Update IME state for new focus widget - SetIMEState(newState, aContent, widget, aReason); - } + // Update IME state for new focus widget + SetIMEState(newState, aContent, widget, aAction); sPresContext = aPresContext; sContent = aContent; return NS_OK; } void nsIMEStateManager::OnInstalledMenuKeyboardListener(bool aInstalling) { sInstalledMenuKeyboardListener = aInstalling; - PRUint32 reason = aInstalling ? IMEContext::FOCUS_MOVED_TO_MENU - : IMEContext::FOCUS_MOVED_FROM_MENU; - OnChangeFocus(sPresContext, sContent, reason); + InputContextAction action(InputContextAction::CAUSE_UNKNOWN, + aInstalling ? InputContextAction::MENU_GOT_PSEUDO_FOCUS : + InputContextAction::MENU_LOST_PSEUDO_FOCUS); + OnChangeFocusInternal(sPresContext, sContent, action); } void -nsIMEStateManager::UpdateIMEState(PRUint32 aNewIMEState, nsIContent* aContent) +nsIMEStateManager::OnClickInEditor(nsPresContext* aPresContext, + nsIContent* aContent, + nsIDOMMouseEvent* aMouseEvent) +{ + if (sPresContext != aPresContext || sContent != aContent) { + return; + } + + nsCOMPtr<nsIWidget> widget = GetWidget(aPresContext); + NS_ENSURE_TRUE(widget, ); + + bool isTrusted; + nsCOMPtr<nsIDOMNSEvent> NSEvent = do_QueryInterface(aMouseEvent); + nsresult rv = NSEvent->GetIsTrusted(&isTrusted); + NS_ENSURE_SUCCESS(rv, ); + if (!isTrusted) { + return; // ignore untrusted event. + } + + PRUint16 button; + rv = aMouseEvent->GetButton(&button); + NS_ENSURE_SUCCESS(rv, ); + if (button != 0) { + return; // not a left click event. + } + + PRInt32 clickCount; + rv = aMouseEvent->GetDetail(&clickCount); + NS_ENSURE_SUCCESS(rv, ); + if (clickCount != 1) { + return; // should notify only first click event. + } + + InputContextAction action(InputContextAction::CAUSE_MOUSE, + InputContextAction::FOCUS_NOT_CHANGED); + IMEState newState = GetNewIMEState(aPresContext, aContent); + SetIMEState(newState, aContent, widget, action); +} + +void +nsIMEStateManager::UpdateIMEState(const IMEState &aNewIMEState, + nsIContent* aContent) { if (!sPresContext) { NS_WARNING("ISM doesn't know which editor has focus"); return; } - NS_PRECONDITION(aNewIMEState != 0, "aNewIMEState doesn't specify new state."); nsCOMPtr<nsIWidget> widget = GetWidget(sPresContext); if (!widget) { NS_WARNING("focused widget is not found"); return; } // Don't update IME state when enabled state isn't actually changed. - IMEContext context; - nsresult rv = widget->GetInputMode(context); - if (NS_FAILED(rv)) { - return; // This platform doesn't support controling the IME state. - } - PRUint32 newEnabledState = aNewIMEState & nsIContent::IME_STATUS_MASK_ENABLED; - if (context.mStatus == - nsContentUtils::GetWidgetStatusFromIMEStatus(newEnabledState)) { + InputContext context = widget->GetInputContext(); + if (context.mIMEState.mEnabled == aNewIMEState.mEnabled) { return; } // commit current composition widget->ResetInputState(); - SetIMEState(aNewIMEState, aContent, widget, IMEContext::EDITOR_STATE_MODIFIED); + InputContextAction action(InputContextAction::CAUSE_UNKNOWN, + InputContextAction::FOCUS_NOT_CHANGED); + SetIMEState(aNewIMEState, aContent, widget, action); } -PRUint32 +IMEState nsIMEStateManager::GetNewIMEState(nsPresContext* aPresContext, nsIContent* aContent) { // On Printing or Print Preview, we don't need IME. if (aPresContext->Type() == nsPresContext::eContext_PrintPreview || aPresContext->Type() == nsPresContext::eContext_Print) { - return nsIContent::IME_STATUS_DISABLE; + return IMEState(IMEState::DISABLED); } - if (sInstalledMenuKeyboardListener) - return nsIContent::IME_STATUS_DISABLE; + if (sInstalledMenuKeyboardListener) { + return IMEState(IMEState::DISABLED); + } if (!aContent) { // Even if there are no focused content, the focused document might be // editable, such case is design mode. nsIDocument* doc = aPresContext->Document(); - if (doc && doc->HasFlag(NODE_IS_EDITABLE)) - return nsIContent::IME_STATUS_ENABLE; - return nsIContent::IME_STATUS_DISABLE; + if (doc && doc->HasFlag(NODE_IS_EDITABLE)) { + return IMEState(IMEState::ENABLED); + } + return IMEState(IMEState::DISABLED); } return aContent->GetDesiredIMEState(); } // Helper class, used for IME enabled state change notification class IMEEnabledStateChangedEvent : public nsRunnable { public: @@ -285,75 +335,72 @@ public: return NS_OK; } private: PRUint32 mState; }; void -nsIMEStateManager::SetIMEState(PRUint32 aState, +nsIMEStateManager::SetIMEState(const IMEState &aState, nsIContent* aContent, nsIWidget* aWidget, - PRUint32 aReason) + InputContextAction aAction) { - if (aState & nsIContent::IME_STATUS_MASK_ENABLED) { - if (!aWidget) - return; + NS_ENSURE_TRUE(aWidget, ); + + InputContext oldContext = aWidget->GetInputContext(); - PRUint32 state = nsContentUtils::GetWidgetStatusFromIMEStatus(aState); - IMEContext context; - context.mStatus = state; - - if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML && - (aContent->Tag() == nsGkAtoms::input || - aContent->Tag() == nsGkAtoms::textarea)) { - aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, - context.mHTMLInputType); - aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint, - context.mActionHint); + InputContext context; + context.mIMEState = aState; + + if (aContent && aContent->GetNameSpaceID() == kNameSpaceID_XHTML && + (aContent->Tag() == nsGkAtoms::input || + aContent->Tag() == nsGkAtoms::textarea)) { + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, + context.mHTMLInputType); + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::moz_action_hint, + context.mActionHint); - // if we don't have an action hint and return won't submit the form use "next" - if (context.mActionHint.IsEmpty() && aContent->Tag() == nsGkAtoms::input) { - bool willSubmit = false; - nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent)); - mozilla::dom::Element* formElement = control->GetFormElement(); - nsCOMPtr<nsIForm> form; - if (control) { - // is this a form and does it have a default submit element? - if ((form = do_QueryInterface(formElement)) && form->GetDefaultSubmitElement()) { - willSubmit = true; - // is this an html form and does it only have a single text input element? - } else if (formElement && formElement->Tag() == nsGkAtoms::form && formElement->IsHTML() && - static_cast<nsHTMLFormElement*>(formElement)->HasSingleTextControl()) { - willSubmit = true; - } + // if we don't have an action hint and return won't submit the form use "next" + if (context.mActionHint.IsEmpty() && aContent->Tag() == nsGkAtoms::input) { + bool willSubmit = false; + nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent)); + mozilla::dom::Element* formElement = control->GetFormElement(); + nsCOMPtr<nsIForm> form; + if (control) { + // is this a form and does it have a default submit element? + if ((form = do_QueryInterface(formElement)) && form->GetDefaultSubmitElement()) { + willSubmit = true; + // is this an html form and does it only have a single text input element? + } else if (formElement && formElement->Tag() == nsGkAtoms::form && formElement->IsHTML() && + static_cast<nsHTMLFormElement*>(formElement)->HasSingleTextControl()) { + willSubmit = true; } - context.mActionHint.Assign(willSubmit ? control->GetType() == NS_FORM_INPUT_SEARCH - ? NS_LITERAL_STRING("search") - : NS_LITERAL_STRING("go") - : formElement - ? NS_LITERAL_STRING("next") - : EmptyString()); } + context.mActionHint.Assign(willSubmit ? control->GetType() == NS_FORM_INPUT_SEARCH + ? NS_LITERAL_STRING("search") + : NS_LITERAL_STRING("go") + : formElement + ? NS_LITERAL_STRING("next") + : EmptyString()); } + } - if (XRE_GetProcessType() == GeckoProcessType_Content) { - context.mReason = aReason | IMEContext::FOCUS_FROM_CONTENT_PROCESS; - } else { - context.mReason = aReason; - } + // XXX I think that we should use nsContentUtils::IsCallerChrome() instead + // of the process type. + if (aAction.mCause == InputContextAction::CAUSE_UNKNOWN && + XRE_GetProcessType() != GeckoProcessType_Content) { + aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME; + } - aWidget->SetInputMode(context); - - nsContentUtils::AddScriptRunner(new IMEEnabledStateChangedEvent(state)); - } - if (aState & nsIContent::IME_STATUS_MASK_OPENED) { - bool open = !!(aState & nsIContent::IME_STATUS_OPEN); - aWidget->SetIMEOpenState(open); + aWidget->SetInputContext(context, aAction); + if (oldContext.mIMEState.mEnabled != context.mIMEState.mEnabled) { + nsContentUtils::AddScriptRunner( + new IMEEnabledStateChangedEvent(context.mIMEState.mEnabled)); } } nsIWidget* nsIMEStateManager::GetWidget(nsPresContext* aPresContext) { nsIPresShell* shell = aPresContext->GetPresShell(); NS_ENSURE_TRUE(shell, nsnull);
--- a/content/events/src/nsIMEStateManager.h +++ b/content/events/src/nsIMEStateManager.h @@ -35,37 +35,48 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef nsIMEStateManager_h__ #define nsIMEStateManager_h__ #include "nscore.h" +#include "nsIWidget.h" class nsIContent; +class nsIDOMMouseEvent; class nsPIDOMWindow; class nsPresContext; -class nsIWidget; class nsTextStateManager; class nsISelection; /* * IME state manager */ class nsIMEStateManager { +protected: + typedef mozilla::widget::IMEState IMEState; + typedef mozilla::widget::InputContext InputContext; + typedef mozilla::widget::InputContextAction InputContextAction; + public: static nsresult OnDestroyPresContext(nsPresContext* aPresContext); static nsresult OnRemoveContent(nsPresContext* aPresContext, nsIContent* aContent); + /** + * OnChangeFocus() should be called when focused content is changed or + * IME enabled state is changed. If focus isn't actually changed and IME + * enabled state isn't changed, this will do nothing. + */ static nsresult OnChangeFocus(nsPresContext* aPresContext, nsIContent* aContent, - PRUint32 aReason); + InputContextAction::Cause aCause); static void OnInstalledMenuKeyboardListener(bool aInstalling); // These two methods manage focus and selection/text observers. // They are separate from OnChangeFocus above because this offers finer // control compared to having the two methods incorporated into OnChangeFocus // OnTextStateBlur should be called *before* NS_BLUR_CONTENT fires // aPresContext is the nsPresContext receiving focus (not lost focus) @@ -80,24 +91,37 @@ public: nsIContent* aContent); // Get the focused editor's selection and root static nsresult GetFocusSelectionAndRoot(nsISelection** aSel, nsIContent** aRoot); // This method updates the current IME state. However, if the enabled state // isn't changed by the new state, this method does nothing. // Note that this method changes the IME state of the active element in the // widget. So, the caller must have focus. - // aNewIMEState must have an enabled state of nsIContent::IME_STATUS_*. - // And optionally, it can have an open state of nsIContent::IME_STATUS_*. - static void UpdateIMEState(PRUint32 aNewIMEState, nsIContent* aContent); + static void UpdateIMEState(const IMEState &aNewIMEState, + nsIContent* aContent); + + // This method is called when user clicked in an editor. + // aContent must be: + // If the editor is for <input> or <textarea>, the element. + // If the editor is for contenteditable, the active editinghost. + // If the editor is for designMode, NULL. + static void OnClickInEditor(nsPresContext* aPresContext, + nsIContent* aContent, + nsIDOMMouseEvent* aMouseEvent); protected: - static void SetIMEState(PRUint32 aState, nsIContent* aContent, - nsIWidget* aWidget, PRUint32 aReason); - static PRUint32 GetNewIMEState(nsPresContext* aPresContext, + static nsresult OnChangeFocusInternal(nsPresContext* aPresContext, + nsIContent* aContent, + InputContextAction aAction); + static void SetIMEState(const IMEState &aState, + nsIContent* aContent, + nsIWidget* aWidget, + InputContextAction aAction); + static IMEState GetNewIMEState(nsPresContext* aPresContext, nsIContent* aContent); static nsIWidget* GetWidget(nsPresContext* aPresContext); static nsIContent* sContent; static nsPresContext* sPresContext; static bool sInstalledMenuKeyboardListener; static bool sInSecureInputMode;
--- a/content/html/content/public/nsHTMLMediaElement.h +++ b/content/html/content/public/nsHTMLMediaElement.h @@ -365,32 +365,49 @@ protected: * Create a decoder for the given aMIMEType. Returns null if we * were unable to create the decoder. */ already_AddRefed<nsMediaDecoder> CreateDecoder(const nsACString& aMIMEType); /** * Initialize a decoder as a clone of an existing decoder in another * element. + * mLoadingSrc must already be set. */ nsresult InitializeDecoderAsClone(nsMediaDecoder* aOriginal); /** * Initialize a decoder to load the given channel. The decoder's stream * listener is returned via aListener. + * mLoadingSrc must already be set. */ nsresult InitializeDecoderForChannel(nsIChannel *aChannel, nsIStreamListener **aListener); /** * Finish setting up the decoder after Load() has been called on it. + * Called by InitializeDecoderForChannel/InitializeDecoderAsClone. */ nsresult FinishDecoderSetup(nsMediaDecoder* aDecoder); /** + * Call this after setting up mLoadingSrc and mDecoder. + */ + void AddMediaElementToURITable(); + /** + * Call this before clearing mLoadingSrc. + */ + void RemoveMediaElementFromURITable(); + /** + * Call this to find a media element with the same NodePrincipal and mLoadingSrc + * set to aURI, and with a decoder on which Load() has been called. + */ + nsHTMLMediaElement* LookupMediaElementURITable(nsIURI* aURI); + + /** * Execute the initial steps of the load algorithm that ensure existing * loads are aborted, the element is emptied, and a new load ID is * created. */ void AbortExistingLoads(); /** * Create a URI for the given aURISpec string. @@ -426,17 +443,17 @@ protected: * Asynchronously awaits a stable state, and then causes SelectResource() * to be run on the main thread's event loop. */ void QueueSelectResourceTask(); /** * The resource-fetch algorithm step of the load algorithm. */ - nsresult LoadResource(nsIURI* aURI); + nsresult LoadResource(); /** * Selects the next <source> child from which to load a resource. Called * during the resource selection algorithm. Stores the return value in * mSourceLoadCandidate before returning. */ nsIContent* GetNextSource(); @@ -487,21 +504,21 @@ protected: PRELOAD_UNDEFINED = 0, // not determined - used only for initialization PRELOAD_NONE = 1, // do not preload PRELOAD_METADATA = 2, // preload only the metadata (and first frame) PRELOAD_ENOUGH = 3 // preload enough data to allow uninterrupted // playback }; /** - * Suspends the load of resource at aURI, so that it can be resumed later + * Suspends the load of mLoadingSrc, so that it can be resumed later * by ResumeLoad(). This is called when we have a media with a 'preload' * attribute value of 'none', during the resource selection algorithm. */ - void SuspendLoad(nsIURI* aURI); + void SuspendLoad(); /** * Resumes a previously suspended load (suspended by SuspendLoad(uri)). * Will continue running the resource selection algorithm. * Sets mPreloadAction to aAction. */ void ResumeLoad(PreloadAction aAction); @@ -530,16 +547,17 @@ protected: **/ void GetCurrentSpec(nsCString& aString); /** * Process any media fragment entries in the URI */ void ProcessMediaFragmentURI(); + // The current decoder. Load() has been called on this decoder. nsRefPtr<nsMediaDecoder> mDecoder; // A reference to the ImageContainer which contains the current frame // of video to display. nsRefPtr<ImageContainer> mImageContainer; // Holds a reference to the first channel we open to the media resource. // Once the decoder is created, control over the channel passes to the @@ -592,21 +610,21 @@ protected: double mVolume; // Current number of audio channels. PRUint32 mChannels; // Current audio sample rate. PRUint32 mRate; - // URI of the resource we're attempting to load. When the decoder is - // successfully initialized, we rely on it to record the URI we're playing, - // and clear mLoadingSrc. This stores the value we return in the currentSrc - // attribute until the decoder is initialized. Use GetCurrentSrc() to access - // the currentSrc attribute. + // URI of the resource we're attempting to load. This stores the value we + // return in the currentSrc attribute. Use GetCurrentSrc() to access the + // currentSrc attribute. + // This is always the original URL we're trying to load --- before + // redirects etc. nsCOMPtr<nsIURI> mLoadingSrc; // Stores the current preload action for this element. Initially set to // PRELOAD_UNDEFINED, its value is changed by calling // UpdatePreloadAction(). PreloadAction mPreloadAction; // Size of the media. Updated by the decoder on the main thread if
--- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -66,16 +66,17 @@ #include "nsIStyleRule.h" #include "nsIURL.h" #include "nsNetUtil.h" #include "nsEscape.h" #include "nsIFrame.h" #include "nsIScrollableFrame.h" #include "nsIView.h" #include "nsIViewManager.h" +#include "nsIWidget.h" #include "nsRange.h" #include "nsIPresShell.h" #include "nsPresContext.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" #include "nsINameSpaceManager.h" #include "nsDOMError.h" #include "nsScriptLoader.h" @@ -2647,27 +2648,27 @@ nsGenericHTMLFormElement::GetFormElement nsresult nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm) { NS_ENSURE_ARG_POINTER(aForm); NS_IF_ADDREF(*aForm = mForm); return NS_OK; } -PRUint32 +nsIContent::IMEState nsGenericHTMLFormElement::GetDesiredIMEState() { nsCOMPtr<nsIEditor> editor = nsnull; nsresult rv = GetEditorInternal(getter_AddRefs(editor)); if (NS_FAILED(rv) || !editor) return nsGenericHTMLElement::GetDesiredIMEState(); nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor); if (!imeEditor) return nsGenericHTMLElement::GetDesiredIMEState(); - PRUint32 state; + IMEState state; rv = imeEditor->GetPreferredIMEState(&state); if (NS_FAILED(rv)) return nsGenericHTMLElement::GetDesiredIMEState(); return state; } bool nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse,
--- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -879,17 +879,17 @@ public: } // nsIContent virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, bool aCompileEventHandlers); virtual void UnbindFromTree(bool aDeep = true, bool aNullParent = true); - virtual PRUint32 GetDesiredIMEState(); + virtual IMEState GetDesiredIMEState(); virtual nsEventStates IntrinsicState() const; virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor); virtual bool IsDisabled() const; /** * This callback is called by a fieldest on all its elements whenever its
--- a/content/html/content/src/nsHTMLCanvasElement.cpp +++ b/content/html/content/src/nsHTMLCanvasElement.cpp @@ -501,45 +501,47 @@ nsHTMLCanvasElement::GetContext(const ns contextProps = do_CreateInstance("@mozilla.org/hash-property-bag;1"); JSObject *opts = JSVAL_TO_OBJECT(aContextOptions); JSIdArray *props = JS_Enumerate(cx, opts); for (int i = 0; props && i < JS_IdArrayLength(cx, props); ++i) { jsid propid = JS_IdArrayGet(cx, props, i); jsval propname, propval; if (!JS_IdToValue(cx, propid, &propname) || - !JS_GetPropertyById(cx, opts, propid, &propval)) - { + !JS_GetPropertyById(cx, opts, propid, &propval)) { continue; } JSString *propnameString = JS_ValueToString(cx, propname); nsDependentJSString pstr; if (!propnameString || !pstr.init(cx, propnameString)) { + JS_DestroyIdArray(cx, props); mCurrentContext = nsnull; return NS_ERROR_FAILURE; } if (JSVAL_IS_BOOLEAN(propval)) { contextProps->SetPropertyAsBool(pstr, propval == JSVAL_TRUE ? true : false); } else if (JSVAL_IS_INT(propval)) { contextProps->SetPropertyAsInt32(pstr, JSVAL_TO_INT(propval)); } else if (JSVAL_IS_DOUBLE(propval)) { contextProps->SetPropertyAsDouble(pstr, JSVAL_TO_DOUBLE(propval)); } else if (JSVAL_IS_STRING(propval)) { JSString *propvalString = JS_ValueToString(cx, propval); nsDependentJSString vstr; if (!propvalString || !vstr.init(cx, propvalString)) { + JS_DestroyIdArray(cx, props); mCurrentContext = nsnull; return NS_ERROR_FAILURE; } contextProps->SetPropertyAsAString(pstr, vstr); } } + JS_DestroyIdArray(cx, props); } } rv = UpdateContext(contextProps); if (NS_FAILED(rv)) { if (!forceThebes) { // Try again with a Thebes context forceThebes = true;
--- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -84,16 +84,17 @@ #include "nsIDocShellTreeItem.h" #include "nsIAsyncVerifyRedirectCallback.h" #include "nsIAppShell.h" #include "nsWidgetsCID.h" #include "nsIPrivateDOMEvent.h" #include "nsIDOMNotifyAudioAvailableEvent.h" #include "nsMediaFragmentURIParser.h" +#include "nsURIHashKey.h" #ifdef MOZ_OGG #include "nsOggDecoder.h" #endif #ifdef MOZ_WAVE #include "nsWaveDecoder.h" #endif #ifdef MOZ_WEBM @@ -474,34 +475,38 @@ void nsHTMLMediaElement::AbortExistingLo // Abort any already-running instance of the resource selection algorithm. mLoadWaitStatus = NOT_WAITING; // Set a new load ID. This will cause events which were enqueued // with a different load ID to silently be cancelled. mCurrentLoadID++; bool fireTimeUpdate = false; + if (mDecoder) { + RemoveMediaElementFromURITable(); fireTimeUpdate = mDecoder->GetCurrentTime() != 0.0; mDecoder->Shutdown(); mDecoder = nsnull; } + mLoadingSrc = nsnull; if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING || mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE) { DispatchEvent(NS_LITERAL_STRING("abort")); } mError = nsnull; mLoadedFirstFrame = false; mAutoplaying = true; mIsLoadingFromSourceChildren = false; mSuspendedAfterFirstFrame = false; mAllowSuspendAfterFirstFrame = true; + mLoadIsSuspended = false; mSourcePointer = nsnull; // TODO: The playback rate must be set to the default playback rate. if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) { mNetworkState = nsIDOMHTMLMediaElement::NETWORK_EMPTY; ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING); mPaused = true; @@ -643,22 +648,22 @@ void nsHTMLMediaElement::SelectResource( if (NS_SUCCEEDED(rv)) { LOG(PR_LOG_DEBUG, ("%p Trying load from src=%s", this, NS_ConvertUTF16toUTF8(src).get())); NS_ASSERTION(!mIsLoadingFromSourceChildren, "Should think we're not loading from source children by default"); mLoadingSrc = uri; if (mPreloadAction == nsHTMLMediaElement::PRELOAD_NONE) { // preload:none media, suspend the load here before we make any // network requests. - SuspendLoad(uri); + SuspendLoad(); mIsRunningSelectResource = false; return; } - rv = LoadResource(uri); + rv = LoadResource(); if (NS_SUCCEEDED(rv)) { mIsRunningSelectResource = false; return; } } NoSupportedMediaSourceError(); } else { // Otherwise, the source elements will be used. @@ -745,55 +750,54 @@ void nsHTMLMediaElement::LoadFromSourceC mLoadingSrc = uri; NS_ASSERTION(mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING, "Network state should be loading"); if (mPreloadAction == nsHTMLMediaElement::PRELOAD_NONE) { // preload:none media, suspend the load here before we make any // network requests. - SuspendLoad(uri); + SuspendLoad(); return; } - if (NS_SUCCEEDED(LoadResource(uri))) { + if (NS_SUCCEEDED(LoadResource())) { return; } // If we fail to load, loop back and try loading the next resource. DispatchAsyncSourceError(child); } NS_NOTREACHED("Execution should not reach here!"); } -void nsHTMLMediaElement::SuspendLoad(nsIURI* aURI) +void nsHTMLMediaElement::SuspendLoad() { mLoadIsSuspended = true; mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE; DispatchAsyncEvent(NS_LITERAL_STRING("suspend")); ChangeDelayLoadStatus(false); } void nsHTMLMediaElement::ResumeLoad(PreloadAction aAction) { NS_ASSERTION(mLoadIsSuspended, "Can only resume preload if halted for one"); - nsCOMPtr<nsIURI> uri = mLoadingSrc; mLoadIsSuspended = false; mPreloadAction = aAction; ChangeDelayLoadStatus(true); mNetworkState = nsIDOMHTMLMediaElement::NETWORK_LOADING; if (!mIsLoadingFromSourceChildren) { // We were loading from the element's src attribute. - if (NS_FAILED(LoadResource(uri))) { + if (NS_FAILED(LoadResource())) { NoSupportedMediaSourceError(); } } else { // We were loading from a child <source> element. Try to resume the // load of that child, and if that fails, try the next child. - if (NS_FAILED(LoadResource(uri))) { + if (NS_FAILED(LoadResource())) { LoadFromSourceChildren(); } } } static bool IsAutoplayEnabled() { return Preferences::GetBool("media.autoplay.enabled"); @@ -868,36 +872,44 @@ void nsHTMLMediaElement::UpdatePreloadAc // value "none". The preload value has changed to preload:metadata, so // resume the load. We'll pause the load again after we've read the // metadata. ResumeLoad(PRELOAD_METADATA); } } } -nsresult nsHTMLMediaElement::LoadResource(nsIURI* aURI) +nsresult nsHTMLMediaElement::LoadResource() { NS_ASSERTION(mDelayingLoadEvent, "Should delay load event (if in document) during load"); // If a previous call to mozSetup() was made, kill that media stream // in order to use this new src instead. if (mAudioStream) { mAudioStream->Shutdown(); mAudioStream = nsnull; } if (mChannel) { mChannel->Cancel(NS_BINDING_ABORTED); mChannel = nsnull; } + nsHTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc); + if (other) { + // Clone it. + nsresult rv = InitializeDecoderAsClone(other->mDecoder); + if (NS_SUCCEEDED(rv)) + return rv; + } + PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; nsresult rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_MEDIA, - aURI, + mLoadingSrc, NodePrincipal(), static_cast<nsGenericElement*>(this), EmptyCString(), // mime type nsnull, // extra &shouldLoad, nsContentUtils::GetContentPolicy(), nsContentUtils::GetSecurityManager()); NS_ENSURE_SUCCESS(rv, rv); @@ -915,17 +927,17 @@ nsresult nsHTMLMediaElement::LoadResourc NS_ENSURE_SUCCESS(rv,rv); if (csp) { channelPolicy = do_CreateInstance("@mozilla.org/nschannelpolicy;1"); channelPolicy->SetContentSecurityPolicy(csp); channelPolicy->SetLoadType(nsIContentPolicy::TYPE_MEDIA); } nsCOMPtr<nsIChannel> channel; rv = NS_NewChannel(getter_AddRefs(channel), - aURI, + mLoadingSrc, nsnull, loadGroup, nsnull, nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY, channelPolicy); NS_ENSURE_SUCCESS(rv,rv); // The listener holds a strong reference to us. This creates a @@ -944,17 +956,17 @@ nsresult nsHTMLMediaElement::LoadResourc new nsCORSListenerProxy(loadListener, NodePrincipal(), channel, false, &rv); } else { rv = nsContentUtils::GetSecurityManager()-> CheckLoadURIWithPrincipal(NodePrincipal(), - aURI, + mLoadingSrc, nsIScriptSecurityManager::STANDARD); listener = loadListener; } NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIHttpChannel> hc = do_QueryInterface(channel); if (hc) { // Use a byte range request from the start of the resource. @@ -986,19 +998,21 @@ nsresult nsHTMLMediaElement::LoadWithCha { NS_ENSURE_ARG_POINTER(aChannel); NS_ENSURE_ARG_POINTER(aListener); *aListener = nsnull; AbortExistingLoads(); + nsresult rv = aChannel->GetOriginalURI(getter_AddRefs(mLoadingSrc)); + NS_ENSURE_SUCCESS(rv, rv); + ChangeDelayLoadStatus(true); - - nsresult rv = InitializeDecoderForChannel(aChannel, aListener); + rv = InitializeDecoderForChannel(aChannel, aListener); if (NS_FAILED(rv)) { ChangeDelayLoadStatus(false); return rv; } DispatchAsyncEvent(NS_LITERAL_STRING("loadstart")); return NS_OK; @@ -1012,16 +1026,17 @@ NS_IMETHODIMP nsHTMLMediaElement::MozLoa nsCOMPtr<nsIContent> content = do_QueryInterface(aOther); nsHTMLMediaElement* other = static_cast<nsHTMLMediaElement*>(content.get()); if (!other || !other->mDecoder) return NS_OK; ChangeDelayLoadStatus(true); + mLoadingSrc = other->mLoadingSrc; nsresult rv = InitializeDecoderAsClone(other->mDecoder); if (NS_FAILED(rv)) { ChangeDelayLoadStatus(false); return rv; } DispatchAsyncEvent(NS_LITERAL_STRING("loadstart")); @@ -1236,16 +1251,86 @@ NS_IMETHODIMP nsHTMLMediaElement::SetMut mAudioStream->SetVolume(mMuted ? 0.0 : mVolume); } DispatchAsyncEvent(NS_LITERAL_STRING("volumechange")); return NS_OK; } +class MediaElementSetForURI : public nsURIHashKey { +public: + MediaElementSetForURI(const nsIURI* aKey) : nsURIHashKey(aKey) {} + MediaElementSetForURI(const MediaElementSetForURI& toCopy) + : nsURIHashKey(toCopy), mElements(toCopy.mElements) {} + nsTArray<nsHTMLMediaElement*> mElements; +}; + +typedef nsTHashtable<MediaElementSetForURI> MediaElementURITable; +// Elements in this table must have non-null mDecoder and mLoadingSrc, and those +// can't change while the element is in the table. The table is keyed by +// the element's mLoadingSrc. Each entry has a list of all elements with the +// same mLoadingSrc. +static MediaElementURITable* gElementTable; + +void +nsHTMLMediaElement::AddMediaElementToURITable() +{ + NS_ASSERTION(mDecoder && mDecoder->GetStream(), "Call this only with decoder Load called"); + if (!gElementTable) { + gElementTable = new MediaElementURITable(); + gElementTable->Init(); + } + MediaElementSetForURI* entry = gElementTable->PutEntry(mLoadingSrc); + entry->mElements.AppendElement(this); +} + +void +nsHTMLMediaElement::RemoveMediaElementFromURITable() +{ + NS_ASSERTION(mDecoder, "Don't call this without decoder!"); + NS_ASSERTION(mLoadingSrc, "Can't have decoder without source!"); + if (!gElementTable) + return; + MediaElementSetForURI* entry = gElementTable->GetEntry(mLoadingSrc); + if (!entry) + return; + entry->mElements.RemoveElement(this); + if (entry->mElements.IsEmpty()) { + gElementTable->RemoveEntry(mLoadingSrc); + if (gElementTable->Count() == 0) { + delete gElementTable; + gElementTable = nsnull; + } + } +} + +nsHTMLMediaElement* +nsHTMLMediaElement::LookupMediaElementURITable(nsIURI* aURI) +{ + if (!gElementTable) + return nsnull; + MediaElementSetForURI* entry = gElementTable->GetEntry(aURI); + if (!entry) + return nsnull; + for (PRUint32 i = 0; i < entry->mElements.Length(); ++i) { + nsHTMLMediaElement* elem = entry->mElements[i]; + bool equal; + // Look for elements that have the same principal. + // XXX when we implement crossorigin for video, we'll also need to check + // for the same crossorigin mode here. Ditto for anything else that could + // cause us to send different headers. + if (NS_SUCCEEDED(elem->NodePrincipal()->Equals(NodePrincipal(), &equal)) && equal) { + NS_ASSERTION(elem->mDecoder && elem->mDecoder->GetStream(), "Decoder gone"); + return elem; + } + } + return nsnull; +} + nsHTMLMediaElement::nsHTMLMediaElement(already_AddRefed<nsINodeInfo> aNodeInfo) : nsGenericHTMLElement(aNodeInfo), mCurrentLoadID(0), mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY), mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING), mLoadWaitStatus(NOT_WAITING), mVolume(1.0), mChannels(0), @@ -1292,26 +1377,24 @@ nsHTMLMediaElement::nsHTMLMediaElement(a nsHTMLMediaElement::~nsHTMLMediaElement() { NS_ASSERTION(!mHasSelfReference, "How can we be destroyed if we're still holding a self reference?"); UnregisterFreezableElement(); if (mDecoder) { + RemoveMediaElementFromURITable(); mDecoder->Shutdown(); - mDecoder = nsnull; } if (mChannel) { mChannel->Cancel(NS_BINDING_ABORTED); - mChannel = nsnull; } if (mAudioStream) { mAudioStream->Shutdown(); - mAudioStream = nsnull; } } void nsHTMLMediaElement::StopSuspendingAfterFirstFrame() { mAllowSuspendAfterFirstFrame = false; if (!mSuspendedAfterFirstFrame) return; @@ -1342,19 +1425,23 @@ void nsHTMLMediaElement::SetPlayedOrSeek NS_IMETHODIMP nsHTMLMediaElement::Play() { StopSuspendingAfterFirstFrame(); SetPlayedOrSeeked(true); if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) { nsresult rv = Load(); NS_ENSURE_SUCCESS(rv, rv); - } else if (mLoadIsSuspended) { + } + if (mLoadIsSuspended) { ResumeLoad(PRELOAD_ENOUGH); - } else if (mDecoder) { + } + // Even if we just did Load() or ResumeLoad(), we could already have a decoder + // here if we managed to clone an existing decoder. + if (mDecoder) { if (mDecoder->IsEnded()) { SetCurrentTime(0); } if (!mPausedForInactiveDocument) { nsresult rv = mDecoder->Play(); NS_ENSURE_SUCCESS(rv, rv); } } @@ -1806,17 +1893,19 @@ nsHTMLMediaElement::CreateDecoder(const } } #endif return nsnull; } nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal) { - nsMediaStream* originalStream = aOriginal->GetCurrentStream(); + NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set"); + + nsMediaStream* originalStream = aOriginal->GetStream(); if (!originalStream) return NS_ERROR_FAILURE; nsRefPtr<nsMediaDecoder> decoder = aOriginal->Clone(); if (!decoder) return NS_ERROR_FAILURE; LOG(PR_LOG_DEBUG, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal)); @@ -1843,16 +1932,18 @@ nsresult nsHTMLMediaElement::InitializeD } return FinishDecoderSetup(decoder); } nsresult nsHTMLMediaElement::InitializeDecoderForChannel(nsIChannel *aChannel, nsIStreamListener **aListener) { + NS_ASSERTION(mLoadingSrc, "mLoadingSrc must already be set"); + nsCAutoString mimeType; aChannel->GetContentType(mimeType); nsRefPtr<nsMediaDecoder> decoder = CreateDecoder(mimeType); if (!decoder) { return NS_ERROR_FAILURE; } @@ -1873,20 +1964,20 @@ nsresult nsHTMLMediaElement::InitializeD // which owns the channel. mChannel = nsnull; return FinishDecoderSetup(decoder); } nsresult nsHTMLMediaElement::FinishDecoderSetup(nsMediaDecoder* aDecoder) { + NS_ASSERTION(mLoadingSrc, "mLoadingSrc set up"); + mDecoder = aDecoder; - - // Decoder has assumed ownership responsibility for remembering the URI. - mLoadingSrc = nsnull; + AddMediaElementToURITable(); // Force a same-origin check before allowing events for this media resource. mMediaSecurityVerified = false; // The new stream has not been suspended by us. mPausedForInactiveDocument = false; // But we may want to suspend it now. // This will also do an AddRemoveSelfReference. @@ -2014,19 +2105,21 @@ void nsHTMLMediaElement::ResourceLoaded( void nsHTMLMediaElement::NetworkError() { Error(nsIDOMMediaError::MEDIA_ERR_NETWORK); } void nsHTMLMediaElement::DecodeError() { if (mDecoder) { + RemoveMediaElementFromURITable(); mDecoder->Shutdown(); mDecoder = nsnull; } + mLoadingSrc = nsnull; if (mIsLoadingFromSourceChildren) { mError = nsnull; if (mSourceLoadCandidate) { DispatchAsyncSourceError(mSourceLoadCandidate); QueueLoadFromSourceTask(); } else { NS_WARNING("Should know the source we were loading from!"); } @@ -2664,23 +2757,20 @@ void nsHTMLMediaElement::FireTimeUpdate( mFragmentEnd = -1.0; mFragmentStart = -1.0; mDecoder->SetEndTime(mFragmentEnd); } } void nsHTMLMediaElement::GetCurrentSpec(nsCString& aString) { - if (mDecoder) { - nsMediaStream* stream = mDecoder->GetCurrentStream(); - if (stream) { - stream->URI()->GetSpec(aString); - } - } else if (mLoadingSrc) { + if (mLoadingSrc) { mLoadingSrc->GetSpec(aString); + } else { + aString.Truncate(); } } /* attribute double initialTime; */ NS_IMETHODIMP nsHTMLMediaElement::GetInitialTime(double *aTime) { // If there is no start fragment then the initalTime is zero. // Clamp to duration if it is greater than duration.
--- a/content/html/content/src/nsHTMLObjectElement.cpp +++ b/content/html/content/src/nsHTMLObjectElement.cpp @@ -47,16 +47,17 @@ #include "nsIDOMDocument.h" #include "nsIDOMSVGDocument.h" #include "nsIDOMGetSVGDocument.h" #include "nsIDOMHTMLObjectElement.h" #include "nsFormSubmission.h" #include "nsIObjectFrame.h" #include "nsNPAPIPluginInstance.h" #include "nsIConstraintValidation.h" +#include "nsIWidget.h" using namespace mozilla; using namespace mozilla::dom; class nsHTMLObjectElement : public nsGenericHTMLFormElement , public nsObjectLoadingContent , public nsIDOMHTMLObjectElement , public nsIConstraintValidation @@ -111,17 +112,17 @@ public: bool aNullParent = true); virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom *aName, nsIAtom *aPrefix, const nsAString &aValue, bool aNotify); virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, bool aNotify); virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex); - virtual PRUint32 GetDesiredIMEState(); + virtual IMEState GetDesiredIMEState(); // Overriden nsIFormControl methods NS_IMETHOD_(PRUint32) GetType() const { return NS_FORM_OBJECT; } NS_IMETHOD Reset(); @@ -371,21 +372,21 @@ nsHTMLObjectElement::IsHTMLFocusable(boo if (aTabIndex && *aIsFocusable) { *aTabIndex = attrVal->GetIntegerValue(); } return false; } -PRUint32 +nsIContent::IMEState nsHTMLObjectElement::GetDesiredIMEState() { if (Type() == eType_Plugin) { - return nsIContent::IME_STATUS_PLUGIN; + return IMEState(IMEState::PLUGIN); } return nsGenericHTMLFormElement::GetDesiredIMEState(); } NS_IMETHODIMP nsHTMLObjectElement::Reset() {
--- a/content/html/content/src/nsHTMLSharedObjectElement.cpp +++ b/content/html/content/src/nsHTMLSharedObjectElement.cpp @@ -45,16 +45,17 @@ #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsIDOMHTMLAppletElement.h" #include "nsIDOMHTMLEmbedElement.h" #include "nsThreadUtils.h" #include "nsIDOMGetSVGDocument.h" #include "nsIDOMSVGDocument.h" #include "nsIScriptError.h" +#include "nsIWidget.h" using namespace mozilla; using namespace mozilla::dom; class nsHTMLSharedObjectElement : public nsGenericHTMLElement , public nsObjectLoadingContent , public nsIDOMHTMLAppletElement , public nsIDOMHTMLEmbedElement @@ -114,17 +115,17 @@ public: bool aCompileEventHandlers); virtual void UnbindFromTree(bool aDeep = true, bool aNullParent = true); virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom *aName, nsIAtom *aPrefix, const nsAString &aValue, bool aNotify); virtual bool IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex); - virtual PRUint32 GetDesiredIMEState(); + virtual IMEState GetDesiredIMEState(); virtual void DoneAddingChildren(bool aHaveNotified); virtual bool IsDoneAddingChildren(); virtual bool ParseAttribute(PRInt32 aNamespaceID, nsIAtom *aAttribute, const nsAString &aValue, nsAttrValue &aResult); @@ -360,21 +361,21 @@ nsHTMLSharedObjectElement::IsHTMLFocusab // Let the plugin decide, so override. return true; } return nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex); } -PRUint32 +nsIContent::IMEState nsHTMLSharedObjectElement::GetDesiredIMEState() { if (Type() == eType_Plugin) { - return nsIContent::IME_STATUS_PLUGIN; + return IMEState(IMEState::PLUGIN); } return nsGenericHTMLElement::GetDesiredIMEState(); } NS_IMPL_STRING_ATTR(nsHTMLSharedObjectElement, Align, align) NS_IMPL_STRING_ATTR(nsHTMLSharedObjectElement, Alt, alt) NS_IMPL_STRING_ATTR(nsHTMLSharedObjectElement, Archive, archive)
--- a/content/media/VideoUtils.h +++ b/content/media/VideoUtils.h @@ -161,15 +161,9 @@ void ScaleDisplayByAspectRatio(nsIntSize // The amount of virtual memory reserved for thread stacks. #if defined(XP_WIN) || defined(XP_MACOSX) || defined(LINUX) #define MEDIA_THREAD_STACK_SIZE (128 * 1024) #else // All other platforms use their system defaults. #define MEDIA_THREAD_STACK_SIZE nsIThreadManager::DEFAULT_STACK_SIZE #endif -// Android's audio backend is not available in content processes, so audio must -// be remoted to the parent chrome process. -#if defined(ANDROID) -#define REMOTE_AUDIO 1 #endif - -#endif
--- a/content/media/nsAudioStream.cpp +++ b/content/media/nsAudioStream.cpp @@ -61,16 +61,22 @@ extern "C" { #include "mozilla/Preferences.h" using namespace mozilla; #if defined(XP_MACOSX) #define SA_PER_STREAM_VOLUME 1 #endif +// Android's audio backend is not available in content processes, so audio must +// be remoted to the parent chrome process. +#if defined(ANDROID) +#define REMOTE_AUDIO 1 +#endif + using mozilla::TimeStamp; #ifdef PR_LOGGING PRLogModuleInfo* gAudioStreamLog = nsnull; #endif static const PRUint32 FAKE_BUFFER_SIZE = 176400; @@ -110,16 +116,17 @@ class nsNativeAudioStream : public nsAud // True if this audio stream is paused. bool mPaused; // True if this stream has encountered an error. bool mInError; }; +#if defined(REMOTE_AUDIO) class nsRemotedAudioStream : public nsAudioStream { public: NS_DECL_ISUPPORTS nsRemotedAudioStream(); ~nsRemotedAudioStream(); @@ -302,16 +309,17 @@ class AudioShutdownEvent : public nsRunn { if (mAudioChild->IsIPCOpen()) mAudioChild->SendShutdown(); return NS_OK; } nsRefPtr<AudioChild> mAudioChild; }; +#endif static mozilla::Mutex* gVolumeScaleLock = nsnull; static double gVolumeScale = 1.0; static int VolumeScaleChanged(const char* aPref, void *aClosure) { nsAdoptingString value = Preferences::GetString("media.volume_scale"); mozilla::MutexAutoLock lock(*gVolumeScaleLock); @@ -603,16 +611,17 @@ PRInt32 nsNativeAudioStream::GetMinWrite if (r == SA_ERROR_NOT_SUPPORTED) return 1; else if (r != SA_SUCCESS || size > PR_INT32_MAX) return -1; return static_cast<PRInt32>(size / mChannels / sizeof(short)); } +#if defined(REMOTE_AUDIO) nsRemotedAudioStream::nsRemotedAudioStream() : mAudioChild(nsnull), mFormat(FORMAT_S16_LE), mRate(0), mChannels(0), mBytesPerFrame(0), mPaused(false) {} @@ -754,8 +763,10 @@ nsRemotedAudioStream::GetPositionInFrame return position + (mRate * dt / MS_PER_S); } bool nsRemotedAudioStream::IsPaused() { return mPaused; } +#endif +
--- a/content/media/nsBuiltinDecoder.cpp +++ b/content/media/nsBuiltinDecoder.cpp @@ -372,17 +372,17 @@ nsresult nsBuiltinDecoder::PlaybackRateC } double nsBuiltinDecoder::GetCurrentTime() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); return mCurrentTime; } -nsMediaStream* nsBuiltinDecoder::GetCurrentStream() +nsMediaStream* nsBuiltinDecoder::GetStream() { return mStream; } already_AddRefed<nsIPrincipal> nsBuiltinDecoder::GetCurrentPrincipal() { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); return mStream ? mStream->GetCurrentPrincipal() : nsnull;
--- a/content/media/nsBuiltinDecoder.h +++ b/content/media/nsBuiltinDecoder.h @@ -400,17 +400,17 @@ class nsBuiltinDecoder : public nsMediaD virtual void Pause(); virtual void SetVolume(double aVolume); virtual double GetDuration(); virtual void SetInfinite(bool aInfinite); virtual bool IsInfinite(); - virtual nsMediaStream* GetCurrentStream(); + virtual nsMediaStream* GetStream(); virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal(); virtual void NotifySuspendedStatusChanged(); virtual void NotifyBytesDownloaded(); virtual void NotifyDownloadEnded(nsresult aStatus); // Called by the decode thread to keep track of the number of bytes read // from the resource. void NotifyBytesConsumed(PRInt64 aBytes);
--- a/content/media/nsBuiltinDecoderStateMachine.cpp +++ b/content/media/nsBuiltinDecoderStateMachine.cpp @@ -762,39 +762,16 @@ void nsBuiltinDecoderStateMachine::Audio if (!FramesToUsecs(audioDuration, rate, playedUsecs)) { NS_WARNING("Int overflow calculating playedUsecs"); break; } if (!AddOverflow(audioStartTime, playedUsecs, mAudioEndTime)) { NS_WARNING("Int overflow calculating audio end time"); break; } - -// The remoted audio stream does not block writes when the other end's buffers -// are full, so this sleep is necessary to stop the audio thread spinning its -// wheels. When bug 695612 is fixed, this block of code can be removed. -#if defined(REMOTE_AUDIO) - PRInt64 audioAhead = mAudioEndTime - GetMediaTime(); - if (audioAhead > AMPLE_AUDIO_USECS && - framesWritten > minWriteFrames) - { - // We've pushed enough audio onto the hardware that we've queued up a - // significant amount ahead of the playback position. The decode - // thread will be going to sleep, so we won't get any new audio - // anyway, so sleep until we need to push to the hardware again. - Wait(AMPLE_AUDIO_USECS / 2); - // Kick the decode thread; since above we only do a NotifyAll when - // we pop an audio chunk of the queue, the decoder won't wake up if - // we've got no more decoded chunks to push to the hardware. We can - // hit this condition if the last frame in the stream doesn't have - // it's EOS flag set, and the decode thread sleeps just after decoding - // that packet, but before realising there's no more packets. - mon.NotifyAll(); - } -#endif } } if (mReader->mAudioQueue.AtEndOfStream() && mState != DECODER_STATE_SHUTDOWN && !mStopAudioThread) { // Last frame pushed to audio hardware, wait for the audio to finish, // before the audio thread terminates. @@ -1589,17 +1566,17 @@ private: nsRefPtr<nsBuiltinDecoder> mDecoder; nsCOMPtr<nsBuiltinDecoderStateMachine> mStateMachine; }; nsresult nsBuiltinDecoderStateMachine::RunStateMachine() { mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); - nsMediaStream* stream = mDecoder->GetCurrentStream(); + nsMediaStream* stream = mDecoder->GetStream(); NS_ENSURE_TRUE(stream, NS_ERROR_NULL_POINTER); switch (mState) { case DECODER_STATE_SHUTDOWN: { if (IsPlaying()) { StopPlayback(); } StopAudioThread(); @@ -1670,17 +1647,17 @@ nsresult nsBuiltinDecoderStateMachine::R TimeStamp now = TimeStamp::Now(); NS_ASSERTION(!mBufferingStart.IsNull(), "Must know buffering start time."); // We will remain in the buffering state if we've not decoded enough // data to begin playback, or if we've not downloaded a reasonable // amount of data inside our buffering time. TimeDuration elapsed = now - mBufferingStart; - bool isLiveStream = mDecoder->GetCurrentStream()->GetLength() == -1; + bool isLiveStream = mDecoder->GetStream()->GetLength() == -1; if ((isLiveStream || !mDecoder->CanPlayThrough()) && elapsed < TimeDuration::FromSeconds(mBufferingWait) && (mQuickBuffering ? HasLowDecodedData(QUICK_BUFFERING_LOW_DATA_USECS) : (GetUndecodedData() < mBufferingWait * USECS_PER_S / 1000)) && !stream->IsDataCachedToEndOfStream(mDecoder->mDecoderPosition) && !stream->IsSuspended()) { LOG(PR_LOG_DEBUG, @@ -1868,17 +1845,17 @@ void nsBuiltinDecoderStateMachine::Advan ? (DurationToUsecs(TimeStamp::Now() - mPlayStartTime) + mPlayDuration) : mPlayDuration; remainingTime = frame->mTime - mStartTime - now; } } // Check to see if we don't have enough data to play up to the next frame. // If we don't, switch to buffering mode. - nsMediaStream* stream = mDecoder->GetCurrentStream(); + nsMediaStream* stream = mDecoder->GetStream(); if (mState == DECODER_STATE_DECODING && mDecoder->GetState() == nsBuiltinDecoder::PLAY_STATE_PLAYING && HasLowDecodedData(remainingTime + EXHAUSTED_DATA_MARGIN_USECS) && !stream->IsDataCachedToEndOfStream(mDecoder->mDecoderPosition) && !stream->IsSuspended() && (JustExitedQuickBuffering() || HasLowUndecodedData())) { if (currentFrame) { @@ -2046,17 +2023,17 @@ void nsBuiltinDecoderStateMachine::Start nsMediaDecoder::Statistics stats = mDecoder->GetStatistics(); LOG(PR_LOG_DEBUG, ("%p Playback rate: %.1lfKB/s%s download rate: %.1lfKB/s%s", mDecoder.get(), stats.mPlaybackRate/1024, stats.mPlaybackRateReliable ? "" : " (unreliable)", stats.mDownloadRate/1024, stats.mDownloadRateReliable ? "" : " (unreliable)")); } nsresult nsBuiltinDecoderStateMachine::GetBuffered(nsTimeRanges* aBuffered) { - nsMediaStream* stream = mDecoder->GetCurrentStream(); + nsMediaStream* stream = mDecoder->GetStream(); NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE); stream->Pin(); nsresult res = mReader->GetBuffered(aBuffered, mStartTime); stream->Unpin(); return res; } bool nsBuiltinDecoderStateMachine::IsPausedAndDecoderWaiting() {
--- a/content/media/nsMediaCache.cpp +++ b/content/media/nsMediaCache.cpp @@ -1834,23 +1834,28 @@ nsMediaCacheStream::NotifyDataEnded(nsre memset(reinterpret_cast<char*>(mPartialBlockBuffer) + blockOffset, 0, BLOCK_SIZE - blockOffset); gMediaCache->AllocateAndWriteBlock(this, mPartialBlockBuffer, mMetadataInPartialBlockBuffer ? MODE_METADATA : MODE_PLAYBACK); // Wake up readers who may be waiting for this data mon.NotifyAll(); } - nsMediaCache::ResourceStreamIterator iter(mResourceID); - while (nsMediaCacheStream* stream = iter.Next()) { - if (NS_SUCCEEDED(aStatus)) { - // We read the whole stream, so remember the true length - stream->mStreamLength = mChannelOffset; + if (!mDidNotifyDataEnded) { + nsMediaCache::ResourceStreamIterator iter(mResourceID); + while (nsMediaCacheStream* stream = iter.Next()) { + if (NS_SUCCEEDED(aStatus)) { + // We read the whole stream, so remember the true length + stream->mStreamLength = mChannelOffset; + } + NS_ASSERTION(!stream->mDidNotifyDataEnded, "Stream already ended!"); + stream->mDidNotifyDataEnded = true; + stream->mNotifyDataEndedStatus = aStatus; + stream->mClient->CacheClientNotifyDataEnded(aStatus); } - stream->mClient->CacheClientNotifyDataEnded(aStatus); } } nsMediaCacheStream::~nsMediaCacheStream() { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); NS_ASSERTION(!mPinCount, "Unbalanced Pin"); @@ -2116,55 +2121,72 @@ nsMediaCacheStream::Read(char* aBuffer, break; } size = NS_MIN(size, PRInt32(bytesRemaining)); } PRInt32 bytes; PRUint32 channelBlock = PRUint32(mChannelOffset/BLOCK_SIZE); PRInt32 cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1; - if (channelBlock == streamBlock && mStreamOffset < mChannelOffset) { - // We can just use the data in mPartialBlockBuffer. In fact we should - // use it rather than waiting for the block to fill and land in - // the cache. - bytes = NS_MIN<PRInt64>(size, mChannelOffset - mStreamOffset); - memcpy(aBuffer + count, - reinterpret_cast<char*>(mPartialBlockBuffer) + offsetInStreamBlock, bytes); - if (mCurrentMode == MODE_METADATA) { - mMetadataInPartialBlockBuffer = true; + if (cacheBlock < 0) { + // We don't have a complete cached block here. + + if (count > 0) { + // Some data has been read, so return what we've got instead of + // blocking or trying to find a stream with a partial block. + break; } - gMediaCache->NoteBlockUsage(this, cacheBlock, mCurrentMode, TimeStamp::Now()); - } else { - if (cacheBlock < 0) { - if (count > 0) { - // Some data has been read, so return what we've got instead of - // blocking + + // See if the data is available in the partial cache block of any + // stream reading this resource. We need to do this in case there is + // another stream with this resource that has all the data to the end of + // the stream but the data doesn't end on a block boundary. + nsMediaCacheStream* streamWithPartialBlock = nsnull; + nsMediaCache::ResourceStreamIterator iter(mResourceID); + while (nsMediaCacheStream* stream = iter.Next()) { + if (PRUint32(stream->mChannelOffset/BLOCK_SIZE) == streamBlock && + mStreamOffset < stream->mChannelOffset) { + streamWithPartialBlock = stream; break; } - - // No data has been read yet, so block - mon.Wait(); - if (mClosed) { - // We may have successfully read some data, but let's just throw - // that out. - return NS_ERROR_FAILURE; + } + if (streamWithPartialBlock) { + // We can just use the data in mPartialBlockBuffer. In fact we should + // use it rather than waiting for the block to fill and land in + // the cache. + bytes = NS_MIN<PRInt64>(size, streamWithPartialBlock->mChannelOffset - mStreamOffset); + memcpy(aBuffer, + reinterpret_cast<char*>(streamWithPartialBlock->mPartialBlockBuffer) + offsetInStreamBlock, bytes); + if (mCurrentMode == MODE_METADATA) { + streamWithPartialBlock->mMetadataInPartialBlockBuffer = true; } - continue; + mStreamOffset += bytes; + count = bytes; + break; } - gMediaCache->NoteBlockUsage(this, cacheBlock, mCurrentMode, TimeStamp::Now()); + // No data has been read yet, so block + mon.Wait(); + if (mClosed) { + // We may have successfully read some data, but let's just throw + // that out. + return NS_ERROR_FAILURE; + } + continue; + } - PRInt64 offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock; - nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, size, &bytes); - if (NS_FAILED(rv)) { - if (count == 0) - return rv; - // If we did successfully read some data, may as well return it - break; - } + gMediaCache->NoteBlockUsage(this, cacheBlock, mCurrentMode, TimeStamp::Now()); + + PRInt64 offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock; + nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, size, &bytes); + if (NS_FAILED(rv)) { + if (count == 0) + return rv; + // If we did successfully read some data, may as well return it + break; } mStreamOffset += bytes; count += bytes; } if (count > 0) { // Some data was read, so queue an update since block priorities may // have changed @@ -2264,16 +2286,22 @@ nsMediaCacheStream::InitAsClone(nsMediaC mPrincipal = aOriginal->mPrincipal; mStreamLength = aOriginal->mStreamLength; mIsSeekable = aOriginal->mIsSeekable; // Cloned streams are initially suspended, since there is no channel open // initially for a clone. mCacheSuspended = true; + if (aOriginal->mDidNotifyDataEnded) { + mNotifyDataEndedStatus = aOriginal->mNotifyDataEndedStatus; + mDidNotifyDataEnded = true; + mClient->CacheClientNotifyDataEnded(mNotifyDataEndedStatus); + } + for (PRUint32 i = 0; i < aOriginal->mBlocks.Length(); ++i) { PRInt32 cacheBlockIndex = aOriginal->mBlocks[i]; if (cacheBlockIndex < 0) continue; while (i >= mBlocks.Length()) { mBlocks.AppendElement(-1); }
--- a/content/media/nsMediaCache.h +++ b/content/media/nsMediaCache.h @@ -223,16 +223,17 @@ public: MODE_PLAYBACK }; // aClient provides the underlying transport that cache will use to read // data for this stream. nsMediaCacheStream(nsMediaChannelStream* aClient) : mClient(aClient), mResourceID(0), mInitialized(false), mIsSeekable(false), mCacheSuspended(false), + mDidNotifyDataEnded(false), mUsingNullPrincipal(false), mChannelOffset(0), mStreamLength(-1), mStreamOffset(0), mPlaybackBytesPerSecond(10000), mPinCount(0), mCurrentMode(MODE_PLAYBACK), mMetadataInPartialBlockBuffer(false), mClosed(false) {} ~nsMediaCacheStream(); @@ -451,16 +452,18 @@ private: // only written on the main thread. // The last reported seekability state for the underlying channel bool mIsSeekable; // True if the cache has suspended our channel because the cache is // full and the priority of the data that would be received is lower // than the priority of the data already in the cache bool mCacheSuspended; + // True if CacheClientNotifyDataEnded has been called for this stream. + bool mDidNotifyDataEnded; // True if mPrincipal is a null principal because we saw data from // multiple origins bool mUsingNullPrincipal; // The offset where the next data from the channel will arrive PRInt64 mChannelOffset; // The reported or discovered length of the data, or -1 if nothing is // known PRInt64 mStreamLength; @@ -481,16 +484,18 @@ private: BlockList mMetadataBlocks; // The list of played-back blocks; the first block is the most recently used BlockList mPlayedBlocks; // The last reported estimate of the decoder's playback rate PRUint32 mPlaybackBytesPerSecond; // The number of times this stream has been Pinned without a // corresponding Unpin PRUint32 mPinCount; + // The status used when we did CacheClientNotifyDataEnded + nsresult mNotifyDataEndedStatus; // The last reported read mode ReadMode mCurrentMode; // True if some data in mPartialBlockBuffer has been read as metadata bool mMetadataInPartialBlockBuffer; // Set to true when the stream has been closed either explicitly or // due to an internal cache error bool mClosed;
--- a/content/media/nsMediaDecoder.cpp +++ b/content/media/nsMediaDecoder.cpp @@ -256,27 +256,27 @@ void nsMediaDecoder::SetVideoData(const double nsMediaDecoder::GetFrameDelay() { MutexAutoLock lock(mVideoUpdateLock); return mPaintDelay.ToSeconds(); } void nsMediaDecoder::PinForSeek() { - nsMediaStream* stream = GetCurrentStream(); + nsMediaStream* stream = GetStream(); if (!stream || mPinnedForSeek) { return; } mPinnedForSeek = true; stream->Pin(); } void nsMediaDecoder::UnpinForSeek() { - nsMediaStream* stream = GetCurrentStream(); + nsMediaStream* stream = GetStream(); if (!stream || !mPinnedForSeek) { return; } mPinnedForSeek = false; stream->Unpin(); } bool nsMediaDecoder::CanPlayThrough()
--- a/content/media/nsMediaDecoder.h +++ b/content/media/nsMediaDecoder.h @@ -86,18 +86,18 @@ public: virtual nsMediaDecoder* Clone() = 0; // Perform any initialization required for the decoder. // Return true on successful initialisation, false // on failure. virtual bool Init(nsHTMLMediaElement* aElement); // Get the current nsMediaStream being used. Its URI will be returned - // by currentSrc. - virtual nsMediaStream* GetCurrentStream() = 0; + // by currentSrc. Returns what was passed to Load(), if Load() has been called. + virtual nsMediaStream* GetStream() = 0; // Return the principal of the current URI being played or downloaded. virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal() = 0; // Return the time position in the video stream being // played measured in seconds. virtual double GetCurrentTime() = 0;
--- a/content/media/nsMediaStream.h +++ b/content/media/nsMediaStream.h @@ -164,17 +164,17 @@ class nsMediaStream public: virtual ~nsMediaStream() { MOZ_COUNT_DTOR(nsMediaStream); } // The following can be called on the main thread only: // Get the URI - nsIURI* URI() { return mURI; } + nsIURI* URI() const { return mURI; } // Close the stream, stop any listeners, channels, etc. // Cancels any currently blocking Read request and forces that request to // return an error. virtual nsresult Close() = 0; // Suspend any downloads that are in progress. // If aCloseImmediately is set, resources should be released immediately // since we don't expect to resume again any time soon. Otherwise we // may resume again soon so resources should be held for a little
--- a/content/media/ogg/nsOggReader.cpp +++ b/content/media/ogg/nsOggReader.cpp @@ -310,17 +310,17 @@ nsresult nsOggReader::ReadMetadata(nsVid LOG(PR_LOG_DEBUG, ("Got duration from Skeleton index %lld", duration)); } } } { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); - nsMediaStream* stream = mDecoder->GetCurrentStream(); + nsMediaStream* stream = mDecoder->GetStream(); if (mDecoder->GetStateMachine()->GetDuration() == -1 && mDecoder->GetStateMachine()->GetState() != nsDecoderStateMachine::DECODER_STATE_SHUTDOWN && stream->GetLength() >= 0 && mDecoder->GetStateMachine()->IsSeekable()) { // We didn't get a duration from the index or a Content-Duration header. // Seek to the end of file to find the end time. PRInt64 length = stream->GetLength(); @@ -547,17 +547,17 @@ PRInt64 nsOggReader::ReadOggPage(ogg_pag // with the given size. This buffer is stored // in the ogg synchronisation structure. char* buffer = ogg_sync_buffer(&mOggState, 4096); NS_ASSERTION(buffer, "ogg_sync_buffer failed"); // Read from the stream into the buffer PRUint32 bytesRead = 0; - nsresult rv = mDecoder->GetCurrentStream()->Read(buffer, 4096, &bytesRead); + nsresult rv = mDecoder->GetStream()->Read(buffer, 4096, &bytesRead);