diff --git a/accessible/src/html/nsHyperTextAccessible.cpp b/accessible/src/html/nsHyperTextAccessible.cpp index 1881230a7ab6..3bcce90b9b16 100644 --- a/accessible/src/html/nsHyperTextAccessible.cpp +++ b/accessible/src/html/nsHyperTextAccessible.cpp @@ -908,17 +908,9 @@ nsresult nsHyperTextAccessible::GetTextHelper(EGetTextType aType, nsAccessibleTe // or the start of a new line. Getting text at the line should provide the line with the visual caret, // otherwise screen readers will announce the wrong line as the user presses up or down arrow and land // at the end of a line. - nsCOMPtr domSel; - nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL, - nsnull, getter_AddRefs(domSel)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr privateSelection(do_QueryInterface(domSel)); - nsRefPtr frameSelection; - rv = privateSelection->GetFrameSelection(getter_AddRefs(frameSelection)); - NS_ENSURE_SUCCESS(rv, rv); - - if (frameSelection->GetHint() == nsFrameSelection::HINTLEFT) { + nsRefPtr frameSelection = FrameSelection(); + if (frameSelection && + frameSelection->GetHint() == nsFrameSelection::HINTLEFT) { -- aOffset; // We are at the start of a line } } @@ -1587,29 +1579,27 @@ nsHyperTextAccessible::SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos) // If range 0 was successfully set, clear any additional selection // ranges remaining from previous selection - nsCOMPtr domSel; - nsCOMPtr selCon; - GetSelections(nsISelectionController::SELECTION_NORMAL, - getter_AddRefs(selCon), getter_AddRefs(domSel)); - if (domSel) { - PRInt32 numRanges; - domSel->GetRangeCount(&numRanges); + nsRefPtr frameSelection = FrameSelection(); + NS_ENSURE_STATE(frameSelection); - for (PRInt32 count = 0; count < numRanges - 1; count ++) { - nsCOMPtr range; - domSel->GetRangeAt(1, getter_AddRefs(range)); - domSel->RemoveRange(range); - } - } - - if (selCon) { - // XXX I'm not sure this can do synchronous scrolling. If the last param is - // set to true, this calling might flush the pending reflow. See bug 418470. - selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, - nsISelectionController::SELECTION_FOCUS_REGION, 0); + nsCOMPtr domSel = + frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL); + NS_ENSURE_STATE(domSel); + + PRInt32 numRanges = 0; + domSel->GetRangeCount(&numRanges); + + for (PRInt32 count = 0; count < numRanges - 1; count ++) { + nsCOMPtr range; + domSel->GetRangeAt(1, getter_AddRefs(range)); + domSel->RemoveRange(range); } - return NS_OK; + // XXX I'm not sure this can do synchronous scrolling. If the last param is + // set to true, this calling might flush the pending reflow. See bug 418470. + return frameSelection->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, + nsISelectionController::SELECTION_FOCUS_REGION, + 0); } NS_IMETHODIMP @@ -1635,13 +1625,15 @@ nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset) // Turn the focus node and offset of the selection into caret hypretext // offset. - nsCOMPtr domSel; - nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL, - nsnull, getter_AddRefs(domSel)); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr frameSelection = FrameSelection(); + NS_ENSURE_STATE(frameSelection); + + nsISelection* domSel = + frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL); + NS_ENSURE_STATE(domSel); nsCOMPtr focusDOMNode; - rv = domSel->GetFocusNode(getter_AddRefs(focusDOMNode)); + nsresult rv = domSel->GetFocusNode(getter_AddRefs(focusDOMNode)); NS_ENSURE_SUCCESS(rv, rv); PRInt32 focusOffset; @@ -1665,18 +1657,19 @@ nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset) return NS_OK; } -PRInt32 nsHyperTextAccessible::GetCaretLineNumber() +PRInt32 +nsHyperTextAccessible::GetCaretLineNumber() { // Provide the line number for the caret, relative to the // currently focused node. Use a 1-based index - nsCOMPtr domSel; - GetSelections(nsISelectionController::SELECTION_NORMAL, nsnull, - getter_AddRefs(domSel)); - nsCOMPtr privateSelection(do_QueryInterface(domSel)); - NS_ENSURE_TRUE(privateSelection, -1); - nsRefPtr frameSelection; - privateSelection->GetFrameSelection(getter_AddRefs(frameSelection)); - NS_ENSURE_TRUE(frameSelection, -1); + nsRefPtr frameSelection = FrameSelection(); + if (!frameSelection) + return -1; + + nsISelection* domSel = + frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL); + if (!domSel) + return - 1; nsCOMPtr caretNode; domSel->GetFocusNode(getter_AddRefs(caretNode)); @@ -1731,104 +1724,70 @@ PRInt32 nsHyperTextAccessible::GetCaretLineNumber() return lineNumber; } -nsresult -nsHyperTextAccessible::GetSelections(PRInt16 aType, - nsISelectionController **aSelCon, - nsISelection **aDomSel, - nsCOMArray* aRanges) +already_AddRefed +nsHyperTextAccessible::FrameSelection() { - if (IsDefunct()) - return NS_ERROR_FAILURE; + nsIFrame* frame = GetFrame(); + return frame->GetFrameSelection(); +} - if (aSelCon) { - *aSelCon = nsnull; - } - if (aDomSel) { - *aDomSel = nsnull; - } - if (aRanges) { - aRanges->Clear(); - } - - nsCOMPtr domSel; - nsCOMPtr selCon; +void +nsHyperTextAccessible::GetSelectionDOMRanges(PRInt16 aType, + nsCOMArray* aRanges) +{ + nsRefPtr frameSelection = FrameSelection(); + if (!frameSelection) + return; + + nsISelection* domSel = frameSelection->GetSelection(aType); + if (!domSel) + return; + + nsCOMPtr startNode = GetNode(); nsCOMPtr editor; GetAssociatedEditor(getter_AddRefs(editor)); - nsCOMPtr peditor(do_QueryInterface(editor)); - if (peditor) { - // Case 1: plain text editor - // This is for form controls which have their own - // selection controller separate from the document, for example - // HTML:input, HTML:textarea, XUL:textbox, etc. - editor->GetSelectionController(getter_AddRefs(selCon)); - } - else { - // Case 2: rich content subtree (can be rich editor) - // This uses the selection controller from the entire document - nsIFrame *frame = GetFrame(); - NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE); - - // Get the selection and selection controller - frame->GetSelectionController(GetPresContext(), - getter_AddRefs(selCon)); - } - NS_ENSURE_TRUE(selCon, NS_ERROR_FAILURE); - - selCon->GetSelection(aType, getter_AddRefs(domSel)); - NS_ENSURE_TRUE(domSel, NS_ERROR_FAILURE); - - if (aSelCon) { - NS_ADDREF(*aSelCon = selCon); - } - if (aDomSel) { - NS_ADDREF(*aDomSel = domSel); + if (editor) { + nsCOMPtr editorRoot; + editor->GetRootElement(getter_AddRefs(editorRoot)); + startNode = do_QueryInterface(editorRoot); } - if (aRanges) { - nsCOMPtr privSel(do_QueryInterface(domSel)); + if (!startNode) + return; - nsCOMPtr startNode = GetNode(); - if (peditor) { - nsCOMPtr editorRoot; - editor->GetRootElement(getter_AddRefs(editorRoot)); - startNode = do_QueryInterface(editorRoot); - } - NS_ENSURE_STATE(startNode); + PRUint32 childCount = startNode->GetChildCount(); + nsCOMPtr startDOMNode(do_QueryInterface(startNode)); + nsCOMPtr privSel(do_QueryInterface(domSel)); + nsresult rv = privSel-> + GetRangesForIntervalCOMArray(startDOMNode, 0, startDOMNode, childCount, + true, aRanges); + NS_ENSURE_SUCCESS(rv,); - PRUint32 childCount = startNode->GetChildCount(); - nsCOMPtr startDOMNode(do_QueryInterface(startNode)); - nsresult rv = privSel-> - GetRangesForIntervalCOMArray(startDOMNode, 0, startDOMNode, childCount, - PR_TRUE, aRanges); - NS_ENSURE_SUCCESS(rv, rv); - // Remove collapsed ranges - PRInt32 numRanges = aRanges->Count(); - for (PRInt32 count = 0; count < numRanges; count ++) { - bool isCollapsed; - (*aRanges)[count]->GetCollapsed(&isCollapsed); - if (isCollapsed) { - aRanges->RemoveObjectAt(count); - -- numRanges; - -- count; - } + // Remove collapsed ranges + PRInt32 numRanges = aRanges->Count(); + for (PRInt32 count = 0; count < numRanges; count ++) { + bool isCollapsed = false; + (*aRanges)[count]->GetCollapsed(&isCollapsed); + if (isCollapsed) { + aRanges->RemoveObjectAt(count); + --numRanges; + --count; } } - - return NS_OK; } /* * Gets the number of selected regions. */ -NS_IMETHODIMP nsHyperTextAccessible::GetSelectionCount(PRInt32 *aSelectionCount) +NS_IMETHODIMP +nsHyperTextAccessible::GetSelectionCount(PRInt32* aSelectionCount) { - nsCOMPtr domSel; - nsCOMArray ranges; - nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL, - nsnull, nsnull, &ranges); - NS_ENSURE_SUCCESS(rv, rv); + NS_ENSURE_ARG_POINTER(aSelectionCount); + *aSelectionCount = 0; + nsCOMArray ranges; + GetSelectionDOMRanges(nsISelectionController::SELECTION_NORMAL, &ranges); *aSelectionCount = ranges.Count(); return NS_OK; @@ -1837,15 +1796,17 @@ NS_IMETHODIMP nsHyperTextAccessible::GetSelectionCount(PRInt32 *aSelectionCount) /* * Gets the start and end offset of the specified selection. */ -NS_IMETHODIMP nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, PRInt32 *aStartOffset, PRInt32 *aEndOffset) +NS_IMETHODIMP +nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, + PRInt32* aStartOffset, + PRInt32* aEndOffset) { + NS_ENSURE_ARG_POINTER(aStartOffset); + NS_ENSURE_ARG_POINTER(aEndOffset); *aStartOffset = *aEndOffset = 0; - nsCOMPtr domSel; nsCOMArray ranges; - nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL, - nsnull, getter_AddRefs(domSel), &ranges); - NS_ENSURE_SUCCESS(rv, rv); + GetSelectionDOMRanges(nsISelectionController::SELECTION_NORMAL, &ranges); PRInt32 rangeCount = ranges.Count(); if (aSelectionNum < 0 || aSelectionNum >= rangeCount) @@ -1857,18 +1818,19 @@ NS_IMETHODIMP nsHyperTextAccessible::GetSelectionBounds(PRInt32 aSelectionNum, P nsCOMPtr startDOMNode; range->GetStartContainer(getter_AddRefs(startDOMNode)); nsCOMPtr startNode(do_QueryInterface(startDOMNode)); - PRInt32 startOffset; + PRInt32 startOffset = 0; range->GetStartOffset(&startOffset); // Get end point nsCOMPtr endDOMNode; range->GetEndContainer(getter_AddRefs(endDOMNode)); nsCOMPtr endNode(do_QueryInterface(endDOMNode)); - PRInt32 endOffset; + PRInt32 endOffset = 0; range->GetEndOffset(&endOffset); - PRInt16 rangeCompareResult; - rv = range->CompareBoundaryPoints(nsIDOMRange::START_TO_END, range, &rangeCompareResult); + PRInt16 rangeCompareResult = 0; + nsresult rv = range->CompareBoundaryPoints(nsIDOMRange::START_TO_END, range, + &rangeCompareResult); NS_ENSURE_SUCCESS(rv, rv); if (rangeCompareResult < 0) { @@ -1898,15 +1860,17 @@ nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum, PRInt32 aStartOffset, PRInt32 aEndOffset) { - nsCOMPtr domSel; - nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL, - nsnull, getter_AddRefs(domSel)); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr frameSelection = FrameSelection(); + NS_ENSURE_STATE(frameSelection); + + nsCOMPtr domSel = + frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL); + NS_ENSURE_STATE(domSel); // Caret is a collapsed selection bool isOnlyCaret = (aStartOffset == aEndOffset); - PRInt32 rangeCount; + PRInt32 rangeCount = 0; domSel->GetRangeCount(&rangeCount); nsCOMPtr range; if (aSelectionNum == rangeCount) { // Add a range @@ -1921,12 +1885,12 @@ nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum, NS_ENSURE_TRUE(range, NS_ERROR_FAILURE); } - PRInt32 startOffset, endOffset; + PRInt32 startOffset = 0, endOffset = 0; nsCOMPtr startNode, endNode; - rv = HypertextOffsetsToDOMRange(aStartOffset, aEndOffset, - getter_AddRefs(startNode), &startOffset, - getter_AddRefs(endNode), &endOffset); + nsresult rv = HypertextOffsetsToDOMRange(aStartOffset, aEndOffset, + getter_AddRefs(startNode), &startOffset, + getter_AddRefs(endNode), &endOffset); NS_ENSURE_SUCCESS(rv, rv); rv = range->SetStart(startNode, startOffset); @@ -1936,23 +1900,30 @@ nsHyperTextAccessible::SetSelectionBounds(PRInt32 aSelectionNum, range->SetEnd(endNode, endOffset); NS_ENSURE_SUCCESS(rv, rv); - if (aSelectionNum == rangeCount) { // Add successfully created new range + // If new range was created then add it, otherwise notify selection listeners + // that existing selection range was changed. + if (aSelectionNum == rangeCount) return domSel->AddRange(range); - } + + domSel->RemoveRange(range); + domSel->AddRange(range); return NS_OK; } /* * Adds a selection bounded by the specified offsets. */ -NS_IMETHODIMP nsHyperTextAccessible::AddSelection(PRInt32 aStartOffset, PRInt32 aEndOffset) +NS_IMETHODIMP +nsHyperTextAccessible::AddSelection(PRInt32 aStartOffset, PRInt32 aEndOffset) { - nsCOMPtr domSel; - nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL, - nsnull, getter_AddRefs(domSel)); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr frameSelection = FrameSelection(); + NS_ENSURE_STATE(frameSelection); - PRInt32 rangeCount; + nsCOMPtr domSel = + frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL); + NS_ENSURE_STATE(domSel); + + PRInt32 rangeCount = 0; domSel->GetRangeCount(&rangeCount); return SetSelectionBounds(rangeCount, aStartOffset, aEndOffset); @@ -1961,12 +1932,15 @@ NS_IMETHODIMP nsHyperTextAccessible::AddSelection(PRInt32 aStartOffset, PRInt32 /* * Removes the specified selection. */ -NS_IMETHODIMP nsHyperTextAccessible::RemoveSelection(PRInt32 aSelectionNum) +NS_IMETHODIMP +nsHyperTextAccessible::RemoveSelection(PRInt32 aSelectionNum) { - nsCOMPtr domSel; - nsresult rv = GetSelections(nsISelectionController::SELECTION_NORMAL, - nsnull, getter_AddRefs(domSel)); - NS_ENSURE_SUCCESS(rv, rv); + nsRefPtr frameSelection = FrameSelection(); + NS_ENSURE_STATE(frameSelection); + + nsCOMPtr domSel = + frameSelection->GetSelection(nsISelectionController::SELECTION_NORMAL); + NS_ENSURE_STATE(domSel); PRInt32 rangeCount; domSel->GetRangeCount(&rangeCount); @@ -2348,9 +2322,7 @@ nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode, nsIPersistentProperties *aAttributes) { nsCOMArray ranges; - nsresult rv = GetSelections(nsISelectionController::SELECTION_SPELLCHECK, - nsnull, nsnull, &ranges); - NS_ENSURE_SUCCESS(rv, rv); + GetSelectionDOMRanges(nsISelectionController::SELECTION_SPELLCHECK, &ranges); PRInt32 rangeCount = ranges.Count(); if (!rangeCount) @@ -2362,7 +2334,7 @@ nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode, NS_ENSURE_STATE(nsrange); PRInt16 result; - rv = nsrange->ComparePoint(aNode, aNodeOffset, &result); + nsresult rv = nsrange->ComparePoint(aNode, aNodeOffset, &result); NS_ENSURE_SUCCESS(rv, rv); // ComparePoint checks boundary points, but we need to check that // text at aNodeOffset is inside the range. @@ -2381,8 +2353,8 @@ nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode, if (result == 1) { // range is before point PRInt32 startHTOffset = 0; - rv = DOMRangeBoundToHypertextOffset(range, PR_FALSE, PR_TRUE, - &startHTOffset); + nsresult rv = DOMRangeBoundToHypertextOffset(range, PR_FALSE, PR_TRUE, + &startHTOffset); NS_ENSURE_SUCCESS(rv, rv); if (startHTOffset > *aHTStartOffset) @@ -2390,8 +2362,8 @@ nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode, } else if (result == -1) { // range is after point PRInt32 endHTOffset = 0; - rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_FALSE, - &endHTOffset); + nsresult rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_FALSE, + &endHTOffset); NS_ENSURE_SUCCESS(rv, rv); if (endHTOffset < *aHTEndOffset) @@ -2399,8 +2371,8 @@ nsHyperTextAccessible::GetSpellTextAttribute(nsIDOMNode *aNode, } else { // point is in range PRInt32 startHTOffset = 0; - rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_TRUE, - &startHTOffset); + nsresult rv = DOMRangeBoundToHypertextOffset(range, PR_TRUE, PR_TRUE, + &startHTOffset); NS_ENSURE_SUCCESS(rv, rv); PRInt32 endHTOffset = 0; diff --git a/accessible/src/html/nsHyperTextAccessible.h b/accessible/src/html/nsHyperTextAccessible.h index 5b396b00407b..45ad50e890d2 100644 --- a/accessible/src/html/nsHyperTextAccessible.h +++ b/accessible/src/html/nsHyperTextAccessible.h @@ -351,22 +351,15 @@ protected: // Selection helpers - /** - * Get the relevant selection interfaces and ranges for the current hyper - * text. - * - * @param aType [in] the selection type - * @param aSelCon [out, optional] the selection controller for the current - * hyper text - * @param aDomSel [out, optional] the selection interface for the current - * hyper text - * @param aRanges [out, optional] the selected ranges within the current - * subtree + /** + * Return frame selection object for the accessible. */ - nsresult GetSelections(PRInt16 aType, - nsISelectionController **aSelCon, - nsISelection **aDomSel = nsnull, - nsCOMArray* aRanges = nsnull); + virtual already_AddRefed FrameSelection(); + + /** + * Return selection ranges within the accessible subtree. + */ + void GetSelectionDOMRanges(PRInt16 aType, nsCOMArray* aRanges); nsresult SetSelectionRange(PRInt32 aStartPos, PRInt32 aEndPos); diff --git a/accessible/src/xul/nsXULFormControlAccessible.cpp b/accessible/src/xul/nsXULFormControlAccessible.cpp index 28a041962160..ce460adf0fe2 100644 --- a/accessible/src/xul/nsXULFormControlAccessible.cpp +++ b/accessible/src/xul/nsXULFormControlAccessible.cpp @@ -882,6 +882,17 @@ nsXULTextFieldAccessible::CacheChildren() while ((child = walker.NextChild()) && AppendChild(child)); } +//////////////////////////////////////////////////////////////////////////////// +// nsXULTextFieldAccessible: nsHyperTextAccessible protected + +already_AddRefed +nsXULTextFieldAccessible::FrameSelection() +{ + nsCOMPtr inputContent(GetInputField()); + nsIFrame* frame = inputContent->GetPrimaryFrame(); + return frame->GetFrameSelection(); +} + //////////////////////////////////////////////////////////////////////////////// // nsXULTextFieldAccessible protected diff --git a/accessible/src/xul/nsXULFormControlAccessible.h b/accessible/src/xul/nsXULFormControlAccessible.h index 49ac22c6b11a..726a78993abb 100644 --- a/accessible/src/xul/nsXULFormControlAccessible.h +++ b/accessible/src/xul/nsXULFormControlAccessible.h @@ -276,6 +276,9 @@ protected: // nsAccessible virtual void CacheChildren(); + // nsHyperTextAccessible + virtual already_AddRefed FrameSelection(); + // nsXULTextFieldAccessible already_AddRefed GetInputField() const; }; diff --git a/accessible/tests/mochitest/Makefile.in b/accessible/tests/mochitest/Makefile.in index ac5954b8533c..b019906c397b 100644 --- a/accessible/tests/mochitest/Makefile.in +++ b/accessible/tests/mochitest/Makefile.in @@ -56,6 +56,7 @@ DIRS = \ states \ table \ text \ + textselection \ tree \ treeupdate \ value \ diff --git a/accessible/tests/mochitest/events.js b/accessible/tests/mochitest/events.js index 00fc7653c99f..789ebba89681 100644 --- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -23,6 +23,7 @@ const EVENT_TEXT_ATTRIBUTE_CHANGED = nsIAccessibleEvent.EVENT_TEXT_ATTRIBUTE_CHA const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED; const EVENT_TEXT_INSERTED = nsIAccessibleEvent.EVENT_TEXT_INSERTED; const EVENT_TEXT_REMOVED = nsIAccessibleEvent.EVENT_TEXT_REMOVED; +const EVENT_TEXT_SELECTION_CHANGED = nsIAccessibleEvent.EVENT_TEXT_SELECTION_CHANGED; const EVENT_VALUE_CHANGE = nsIAccessibleEvent.EVENT_VALUE_CHANGE; //////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/tests/mochitest/textselection/Makefile.in b/accessible/tests/mochitest/textselection/Makefile.in new file mode 100644 index 000000000000..d4a8eacef243 --- /dev/null +++ b/accessible/tests/mochitest/textselection/Makefile.in @@ -0,0 +1,53 @@ +# +# ***** 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): +# Alexander Surkov (original author) +# +# Alternatively, the contents of this file may be used under the terms of +# either of 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 ***** + +DEPTH = ../../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ +relativesrcdir = accessible/textselection + +include $(DEPTH)/config/autoconf.mk +include $(topsrcdir)/config/rules.mk + +_TEST_FILES = \ + test_general.html \ + $(NULL) + +libs:: $(_TEST_FILES) + $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir) diff --git a/accessible/tests/mochitest/textselection/test_general.html b/accessible/tests/mochitest/textselection/test_general.html new file mode 100644 index 000000000000..2cb1fb60676d --- /dev/null +++ b/accessible/tests/mochitest/textselection/test_general.html @@ -0,0 +1,170 @@ + + + + Text selection testing + + + + + + + + + + + + + + + Mozilla Bug 688126 + +

+ +
+  
+ +

hello

+ + + + + diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 0265e09c59db..dfe9f3ffec63 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -362,11 +362,6 @@ LIBS_DESC_SUFFIX = @LIBS_DESC_SUFFIX@ USE_N32 = @USE_N32@ HAVE_64BIT_OS = @HAVE_64BIT_OS@ -# Temp hack. It is not my intention to leave this crap in here for ever. -# Im talking to fur right now to solve the problem without introducing -# NS_USE_NATIVE to the build system -ramiro. -NS_USE_NATIVE = @NS_USE_NATIVE@ - CC = @CC@ CXX = @CXX@ diff --git a/configure.in b/configure.in index 6ce53031b210..c1b3a54d19fa 100644 --- a/configure.in +++ b/configure.in @@ -2488,7 +2488,6 @@ ia64*-hpux*) if test "$SOLARIS_SUNPRO_CC"; then LDFLAGS="$LDFLAGS -z ignore -R '\$\$ORIGIN:\$\$ORIGIN/..' -z lazyload -z combreloc -z muldefs" LIBS="-lCrun -lCstd -lc $LIBS" - NS_USE_NATIVE=1 AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" @@ -8209,7 +8208,6 @@ AC_SUBST(WINDRES) AC_SUBST(IMPLIB) AC_SUBST(FILTER) AC_SUBST(BIN_FLAGS) -AC_SUBST(NS_USE_NATIVE) AC_SUBST(MOZ_WIDGET_TOOLKIT) AC_SUBST(MOZ_UPDATE_XTERM) AC_SUBST(MOZ_PLATFORM_MAEMO) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index b6bd21c94bb7..91a97f5aa835 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1099,8 +1099,18 @@ nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI, nsIScriptSecurityManager::STANDARD); NS_ENSURE_SUCCESS(rv, rv); - rv = requestingPrincipal->CheckMayLoad(aURI, PR_TRUE); - NS_ENSURE_SUCCESS(rv, rv); + // Allow data URIs (let them skip the CheckMayLoad call), since we want + // to allow external resources from data URIs regardless of the difference + // in URI scheme. + bool doesInheritSecurityContext; + rv = + NS_URIChainHasFlags(aURI, + nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, + &doesInheritSecurityContext); + if (NS_FAILED(rv) || !doesInheritSecurityContext) { + rv = requestingPrincipal->CheckMayLoad(aURI, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); + } PRInt16 shouldLoad = nsIContentPolicy::ACCEPT; rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER, diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index f5210df21da5..da91aaaac0a6 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -105,6 +105,10 @@ static PRLogModuleInfo* gObjectLog = PR_NewLogModule("objlc"); #define LOG(args) PR_LOG(gObjectLog, PR_LOG_DEBUG, args) #define LOG_ENABLED() PR_LOG_TEST(gObjectLog, PR_LOG_DEBUG) +#ifdef ANDROID +#include "nsXULAppAPI.h" +#endif + class nsAsyncInstantiateEvent : public nsRunnable { public: // This stores both the content and the frame so that Instantiate calls can be @@ -200,6 +204,9 @@ nsPluginErrorEvent::Run() mContent.get())); nsString type; switch (mState) { + case ePluginClickToPlay: + type = NS_LITERAL_STRING("PluginClickToPlay"); + break; case ePluginUnsupported: type = NS_LITERAL_STRING("PluginNotFound"); break; @@ -1056,7 +1063,11 @@ nsObjectLoadingContent::ObjectState() const case eType_Image: return ImageState(); case eType_Plugin: - case eType_Document: +#ifdef ANDROID + if (XRE_GetProcessType() == GeckoProcessType_Content) + return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY; +#endif + case eType_Document: // These are OK. If documents start to load successfully, they display // something, and are thus not broken in this sense. The same goes for // plugins. @@ -1070,6 +1081,8 @@ nsObjectLoadingContent::ObjectState() const // Otherwise, broken nsEventStates state = NS_EVENT_STATE_BROKEN; switch (mFallbackReason) { + case ePluginClickToPlay: + return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY; case ePluginDisabled: state |= NS_EVENT_STATE_HANDLER_DISABLED; break; @@ -1949,6 +1962,10 @@ nsObjectLoadingContent::GetPluginSupportState(nsIContent* aContent, /* static */ PluginSupportState nsObjectLoadingContent::GetPluginDisabledState(const nsCString& aContentType) { +#ifdef ANDROID + if (XRE_GetProcessType() == GeckoProcessType_Content) + return ePluginClickToPlay; +#endif nsCOMPtr pluginHostCOM(do_GetService(MOZ_PLUGIN_HOST_CONTRACTID)); nsPluginHost *pluginHost = static_cast(pluginHostCOM.get()); if (!pluginHost) { diff --git a/content/base/src/nsObjectLoadingContent.h b/content/base/src/nsObjectLoadingContent.h index 003f4dd9e996..29be88848bb1 100644 --- a/content/base/src/nsObjectLoadingContent.h +++ b/content/base/src/nsObjectLoadingContent.h @@ -65,7 +65,8 @@ enum PluginSupportState { ePluginBlocklisted, // The plugin is blocklisted and disabled ePluginOutdated, // The plugin is considered outdated, but not disabled ePluginOtherState, // Something else (e.g. uninitialized or not a plugin) - ePluginCrashed + ePluginCrashed, + ePluginClickToPlay }; /** diff --git a/content/base/src/nsRange.cpp b/content/base/src/nsRange.cpp index 581f763d9abd..7eb76b070a39 100644 --- a/content/base/src/nsRange.cpp +++ b/content/base/src/nsRange.cpp @@ -357,7 +357,7 @@ nsRange::CharacterDataChanged(nsIDocument* aDocument, DoSetRange(newStartNode, newStartOffset, newEndNode, newEndOffset, newRoot ? newRoot : mRoot.get() #ifdef DEBUG - , !newEndNode->GetParent() + , !newEndNode->GetParent() || !newStartNode->GetParent() #endif ); } diff --git a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp index f943d9b249f0..58c26e54e60a 100644 --- a/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp +++ b/content/canvas/src/nsCanvasRenderingContext2DAzure.cpp @@ -3066,6 +3066,8 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP Point baselineOrigin = Point(point.x * devUnitsPerAppUnit, point.y * devUnitsPerAppUnit); + float advanceSum = 0; + for (PRUint32 c = 0; c < numRuns; c++) { gfxFont *font = runs[c].mFont; PRUint32 endRun = 0; @@ -3084,8 +3086,6 @@ struct NS_STACK_CLASS nsCanvasBidiProcessorAzure : public nsBidiPresUtils::BidiP std::vector glyphBuf; - float advanceSum = 0; - for (PRUint32 i = runs[c].mCharacterOffset; i < endRun; i++) { Glyph newGlyph; if (glyphs[i].IsSimpleGlyph()) { diff --git a/content/events/public/nsEventStates.h b/content/events/public/nsEventStates.h index 97078ce864a8..6f2fd4e2c483 100644 --- a/content/events/public/nsEventStates.h +++ b/content/events/public/nsEventStates.h @@ -264,6 +264,8 @@ private: // Content is the full screen element, or a frame containing the // current full-screen element. #define NS_EVENT_STATE_FULL_SCREEN NS_DEFINE_EVENT_STATE_MACRO(34) +// Handler for click to play plugin +#define NS_EVENT_STATE_TYPE_CLICK_TO_PLAY NS_DEFINE_EVENT_STATE_MACRO(35) /** * NOTE: do not go over 63 without updating nsEventStates::InternalType! diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 88c0c143774b..f41230b49b75 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -4888,14 +4888,7 @@ nsWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx, NS_ASSERTION(sgo, "nativeObj not a global object!"); nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj); - if (win->IsOuterWindow()) { - if (!win->EnsureInnerWindow()) { - return NS_ERROR_FAILURE; - } - - *parentObj = win->GetCurrentInnerWindowInternal()->FastGetGlobalJSObject(); - return NS_OK; - } + NS_ASSERTION(win->IsInnerWindow(), "Should be inner window."); JSObject *winObj = win->FastGetGlobalJSObject(); if (!winObj) { diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 8c4f00f26822..758f21f0bba7 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -299,6 +299,16 @@ public: // nsISupports NS_DECL_CYCLE_COLLECTING_ISUPPORTS + // nsWrapperCache + JSObject *WrapObject(JSContext *cx, XPCWrappedNativeScope *scope, + bool *triedToWrap) + { + NS_ASSERTION(IsOuterWindow(), + "Inner window supports nsWrapperCache, fix WrapObject!"); + *triedToWrap = true; + return EnsureInnerWindow() ? GetWrapper() : nsnull; + } + // nsIScriptGlobalObject virtual nsIScriptContext *GetContext(); virtual JSObject *GetGlobalJSObject(); diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index a1e9675d0c55..3921578b7dde 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -94,6 +94,7 @@ #include "nsXPCOMCID.h" #include "nsISupportsPrimitives.h" +#include "nsXULAppAPI.h" #include "nsIXULRuntime.h" // for the dialog @@ -2251,6 +2252,11 @@ nsresult nsPluginHost::ScanPluginsDirectoryList(nsISimpleEnumerator *dirEnum, nsresult nsPluginHost::LoadPlugins() { +#ifdef ANDROID + if (XRE_GetProcessType() == GeckoProcessType_Content) { + return NS_OK; + } +#endif // do not do anything if it is already done // use ReloadPlugins() to enforce loading if (mPluginsLoaded) diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c index 2f0cf031aca7..57548322a38c 100644 --- a/gfx/cairo/cairo/src/cairo-image-surface.c +++ b/gfx/cairo/cairo/src/cairo-image-surface.c @@ -326,7 +326,7 @@ _cairo_image_surface_create_with_pixman_format (unsigned char *data, return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); } - pixman_image = pixman_image_create_bits (pixman_format, width ? width : 1, height ? height : 1, + pixman_image = pixman_image_create_bits (pixman_format, width, height, (uint32_t *) data, stride ? stride : 4); if (unlikely (pixman_image == NULL)) diff --git a/gfx/layers/d3d10/ContainerLayerD3D10.cpp b/gfx/layers/d3d10/ContainerLayerD3D10.cpp index 9a39d1709fb1..bb2030334c97 100644 --- a/gfx/layers/d3d10/ContainerLayerD3D10.cpp +++ b/gfx/layers/d3d10/ContainerLayerD3D10.cpp @@ -201,9 +201,17 @@ ContainerLayerD3D10::RenderLayer() desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE; desc.SampleDesc.Count = 1; desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; - device()->CreateTexture2D(&desc, NULL, getter_AddRefs(renderTexture)); - - device()->CreateRenderTargetView(renderTexture, NULL, getter_AddRefs(rtView)); + HRESULT hr; + hr = device()->CreateTexture2D(&desc, NULL, getter_AddRefs(renderTexture)); + + if (FAILED(hr)) { + LayerManagerD3D10::ReportFailure(NS_LITERAL_CSTRING("Failed to create new texture for ContainerLayerD3D10!"), + hr); + return; + } + + hr = device()->CreateRenderTargetView(renderTexture, NULL, getter_AddRefs(rtView)); + NS_ASSERTION(SUCCEEDED(hr), "Failed to create render target view for ContainerLayerD3D10!"); effect()->GetVariableByName("vRenderTargetOffset")-> GetRawValue(previousRenderTargetOffset, 0, 8); diff --git a/ipc/chromium/src/base/dir_reader_fallback.h b/ipc/chromium/src/base/dir_reader_fallback.h new file mode 100644 index 000000000000..398f51b2557f --- /dev/null +++ b/ipc/chromium/src/base/dir_reader_fallback.h @@ -0,0 +1,31 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DIR_READER_FALLBACK_H_ +#define BASE_DIR_READER_FALLBACK_H_ +#pragma once + +namespace base { + +class DirReaderFallback { + public: + // Open a directory. If |IsValid| is true, then |Next| can be called to start + // the iteration at the beginning of the directory. + explicit DirReaderFallback(const char* directory_path) { } + // After construction, IsValid returns true iff the directory was + // successfully opened. + bool IsValid() const { return false; } + // Move to the next entry returning false if the iteration is complete. + bool Next() { return false; } + // Return the name of the current directory entry. + const char* name() { return 0;} + // Return the file descriptor which is being used. + int fd() const { return -1; } + // Returns true if this is a no-op fallback class (for testing). + static bool IsFallback() { return true; } +}; + +} // namespace base + +#endif // BASE_DIR_READER_FALLBACK_H_ diff --git a/ipc/chromium/src/base/dir_reader_linux.h b/ipc/chromium/src/base/dir_reader_linux.h new file mode 100644 index 000000000000..f1ec4b7144f1 --- /dev/null +++ b/ipc/chromium/src/base/dir_reader_linux.h @@ -0,0 +1,99 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DIR_READER_LINUX_H_ +#define BASE_DIR_READER_LINUX_H_ +#pragma once + +#include +#include +#include +#include +#include + +#include "base/logging.h" +#include "base/eintr_wrapper.h" + +// See the comments in dir_reader_posix.h about this. + +namespace base { + +struct linux_dirent { + uint64_t d_ino; + int64_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[0]; +}; + +class DirReaderLinux { + public: + explicit DirReaderLinux(const char* directory_path) + : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)), + offset_(0), + size_(0) { + memset(buf_, 0, sizeof(buf_)); + } + + ~DirReaderLinux() { + if (fd_ >= 0) { + if (HANDLE_EINTR(close(fd_))) + DLOG(ERROR) << "Failed to close directory handle"; + } + } + + bool IsValid() const { + return fd_ >= 0; + } + + // Move to the next entry returning false if the iteration is complete. + bool Next() { + if (size_) { + linux_dirent* dirent = reinterpret_cast(&buf_[offset_]); + offset_ += dirent->d_reclen; + } + + if (offset_ != size_) + return true; + + const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_)); + if (r == 0) + return false; + if (r == -1) { + DLOG(ERROR) << "getdents64 returned an error: " << errno; + return false; + } + size_ = r; + offset_ = 0; + return true; + } + + const char* name() const { + if (!size_) + return NULL; + + const linux_dirent* dirent = + reinterpret_cast(&buf_[offset_]); + return dirent->d_name; + } + + int fd() const { + return fd_; + } + + static bool IsFallback() { + return false; + } + + private: + const int fd_; + unsigned char buf_[512]; + size_t offset_, size_; + + DISALLOW_COPY_AND_ASSIGN(DirReaderLinux); +}; + +} // namespace base + +#endif // BASE_DIR_READER_LINUX_H_ diff --git a/ipc/chromium/src/base/dir_reader_posix.h b/ipc/chromium/src/base/dir_reader_posix.h new file mode 100644 index 000000000000..f591ae05783b --- /dev/null +++ b/ipc/chromium/src/base/dir_reader_posix.h @@ -0,0 +1,37 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DIR_READER_POSIX_H_ +#define BASE_DIR_READER_POSIX_H_ +#pragma once + +#include "build/build_config.h" + +// This header provides a class, DirReaderPosix, which allows one to open and +// read from directories without allocating memory. For the interface, see +// the generic fallback in dir_reader_fallback.h. + +// Mac note: OS X has getdirentries, but it only works if we restrict Chrome to +// 32-bit inodes. There is a getdirentries64 syscall in 10.6, but it's not +// wrapped and the direct syscall interface is unstable. Using an unstable API +// seems worse than falling back to enumerating all file descriptors so we will +// probably never implement this on the Mac. + +#if defined(OS_LINUX) +#include "base/dir_reader_linux.h" +#else +#include "base/dir_reader_fallback.h" +#endif + +namespace base { + +#if defined(OS_LINUX) +typedef DirReaderLinux DirReaderPosix; +#else +typedef DirReaderFallback DirReaderPosix; +#endif + +} // namespace base + +#endif // BASE_DIR_READER_POSIX_H_ diff --git a/ipc/chromium/src/base/file_descriptor_shuffle.cc b/ipc/chromium/src/base/file_descriptor_shuffle.cc index 28447c950be5..5cce963fa99d 100644 --- a/ipc/chromium/src/base/file_descriptor_shuffle.cc +++ b/ipc/chromium/src/base/file_descriptor_shuffle.cc @@ -12,26 +12,36 @@ namespace base { -bool PerformInjectiveMultimap(const InjectiveMultimap& m_in, - InjectionDelegate* delegate) { - InjectiveMultimap m(m_in); - std::vector extra_fds; +bool PerformInjectiveMultimapDestructive( + InjectiveMultimap* m, InjectionDelegate* delegate) { + static const size_t kMaxExtraFDs = 16; + int extra_fds[kMaxExtraFDs]; + unsigned next_extra_fd = 0; - for (InjectiveMultimap::iterator i = m.begin(); i != m.end(); ++i) { + // DANGER: this function may not allocate. + + for (InjectiveMultimap::iterator i = m->begin(); i != m->end(); ++i) { int temp_fd = -1; // We DCHECK the injectiveness of the mapping. - for (InjectiveMultimap::iterator j = i + 1; j != m.end(); ++j) - DCHECK(i->dest != j->dest); + for (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) { + DCHECK(i->dest != j->dest) << "Both fd " << i->source + << " and " << j->source << " map to " << i->dest; + } const bool is_identity = i->source == i->dest; - for (InjectiveMultimap::iterator j = i + 1; j != m.end(); ++j) { + for (InjectiveMultimap::iterator j = i + 1; j != m->end(); ++j) { if (!is_identity && i->dest == j->source) { if (temp_fd == -1) { if (!delegate->Duplicate(&temp_fd, i->dest)) return false; - extra_fds.push_back(temp_fd); + if (next_extra_fd < kMaxExtraFDs) { + extra_fds[next_extra_fd++] = temp_fd; + } else { + DLOG(ERROR) << "PerformInjectiveMultimapDestructive overflowed " + << "extra_fds. Leaking file descriptors!"; + } } j->source = temp_fd; @@ -56,14 +66,18 @@ bool PerformInjectiveMultimap(const InjectiveMultimap& m_in, delegate->Close(i->source); } - for (std::vector::const_iterator - i = extra_fds.begin(); i != extra_fds.end(); ++i) { - delegate->Close(*i); - } + for (unsigned i = 0; i < next_extra_fd; i++) + delegate->Close(extra_fds[i]); return true; } +bool PerformInjectiveMultimap(const InjectiveMultimap& m_in, + InjectionDelegate* delegate) { + InjectiveMultimap m(m_in); + return PerformInjectiveMultimapDestructive(&m, delegate); +} + bool FileDescriptorTableInjection::Duplicate(int* result, int fd) { *result = HANDLE_EINTR(dup(fd)); return *result >= 0; diff --git a/ipc/chromium/src/base/file_descriptor_shuffle.h b/ipc/chromium/src/base/file_descriptor_shuffle.h index 8ee774097e8f..a28866ca95bc 100644 --- a/ipc/chromium/src/base/file_descriptor_shuffle.h +++ b/ipc/chromium/src/base/file_descriptor_shuffle.h @@ -65,10 +65,13 @@ typedef std::vector InjectiveMultimap; bool PerformInjectiveMultimap(const InjectiveMultimap& map, InjectionDelegate* delegate); +bool PerformInjectiveMultimapDestructive(InjectiveMultimap* map, + InjectionDelegate* delegate); -static inline bool ShuffleFileDescriptors(const InjectiveMultimap& map) { +// This function will not call malloc but will mutate |map| +static inline bool ShuffleFileDescriptors(InjectiveMultimap *map) { FileDescriptorTableInjection delegate; - return PerformInjectiveMultimap(map, &delegate); + return PerformInjectiveMultimapDestructive(map, &delegate); } } // namespace base diff --git a/ipc/chromium/src/base/process_util_linux.cc b/ipc/chromium/src/base/process_util_linux.cc index 3a0d59195349..858e3c54f6da 100644 --- a/ipc/chromium/src/base/process_util_linux.cc +++ b/ipc/chromium/src/base/process_util_linux.cc @@ -48,39 +48,34 @@ bool LaunchApp(const std::vector& argv, const environment_map& env_vars_to_set, bool wait, ProcessHandle* process_handle, ProcessArchitecture arch) { -#ifdef MOZ_MEMORY_ANDROID - /* We specifically don't call pthread_atfork in jemalloc because it is not - available in bionic until 2.3. However without it, jemalloc could - potentially deadlock, when stl allocates memory through jemalloc, after - fork and before execvp. Therefore, we must manually inform jemalloc here */ - ::_malloc_prefork(); -#endif + scoped_array argv_cstr(new char*[argv.size() + 1]); + // Illegal to allocate memory after fork and before execvp + InjectiveMultimap fd_shuffle1, fd_shuffle2; + fd_shuffle1.reserve(fds_to_remap.size()); + fd_shuffle2.reserve(fds_to_remap.size()); + pid_t pid = fork(); -#ifdef MOZ_MEMORY_ANDROID - ::_malloc_postfork(); -#endif if (pid < 0) return false; if (pid == 0) { - InjectiveMultimap fd_shuffle; for (file_handle_mapping_vector::const_iterator it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) { - fd_shuffle.push_back(InjectionArc(it->first, it->second, false)); + fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); + fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); } - if (!ShuffleFileDescriptors(fd_shuffle)) - exit(127); + if (!ShuffleFileDescriptors(&fd_shuffle1)) + _exit(127); - CloseSuperfluousFds(fd_shuffle); + CloseSuperfluousFds(fd_shuffle2); for (environment_map::const_iterator it = env_vars_to_set.begin(); it != env_vars_to_set.end(); ++it) { if (setenv(it->first.c_str(), it->second.c_str(), 1/*overwrite*/)) - exit(127); + _exit(127); } - scoped_array argv_cstr(new char*[argv.size() + 1]); for (size_t i = 0; i < argv.size(); i++) argv_cstr[i] = const_cast(argv[i].c_str()); argv_cstr[argv.size()] = NULL; diff --git a/ipc/chromium/src/base/process_util_posix.cc b/ipc/chromium/src/base/process_util_posix.cc index 7d83431635e3..b7411bc81e32 100644 --- a/ipc/chromium/src/base/process_util_posix.cc +++ b/ipc/chromium/src/base/process_util_posix.cc @@ -1,3 +1,4 @@ +//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -25,6 +26,7 @@ #include "base/sys_info.h" #include "base/time.h" #include "base/waitable_event.h" +#include "base/dir_reader_posix.h" const int kMicrosecondsPerSecond = 1000000; @@ -86,6 +88,10 @@ bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { return result; } +#ifdef ANDROID +typedef unsigned long int rlim_t; +#endif + // A class to handle auto-closing of DIR*'s. class ScopedDIRClose { public: @@ -97,19 +103,20 @@ class ScopedDIRClose { }; typedef scoped_ptr_malloc ScopedDIR; -#ifdef ANDROID -typedef unsigned long int rlim_t; -#endif void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { -#if defined(OS_LINUX) + // DANGER: no calls to malloc are allowed from now on: + // http://crbug.com/36678 +#if defined(ANDROID) + static const rlim_t kSystemDefaultMaxFds = 1024; + static const char kFDDir[] = "/proc/self/fd"; +#elif defined(OS_LINUX) static const rlim_t kSystemDefaultMaxFds = 8192; - static const char fd_dir[] = "/proc/self/fd"; + static const char kFDDir[] = "/proc/self/fd"; #elif defined(OS_MACOSX) static const rlim_t kSystemDefaultMaxFds = 256; - static const char fd_dir[] = "/dev/fd"; + static const char kFDDir[] = "/dev/fd"; #endif - std::set saved_fds; // Get the maximum number of FDs possible. struct rlimit nofile; @@ -125,52 +132,63 @@ void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { if (max_fds > INT_MAX) max_fds = INT_MAX; - // Don't close stdin, stdout and stderr - saved_fds.insert(STDIN_FILENO); - saved_fds.insert(STDOUT_FILENO); - saved_fds.insert(STDERR_FILENO); - - for (base::InjectiveMultimap::const_iterator - i = saved_mapping.begin(); i != saved_mapping.end(); ++i) { - saved_fds.insert(i->dest); - } - - ScopedDIR dir_closer(opendir(fd_dir)); - DIR *dir = dir_closer.get(); - if (NULL == dir) { - DLOG(ERROR) << "Unable to open " << fd_dir; + DirReaderPosix fd_dir(kFDDir); + if (!fd_dir.IsValid()) { // Fallback case: Try every possible fd. for (rlim_t i = 0; i < max_fds; ++i) { const int fd = static_cast(i); - if (saved_fds.find(fd) != saved_fds.end()) + if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) + continue; + InjectiveMultimap::const_iterator j; + for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) { + if (fd == j->dest) + break; + } + if (j != saved_mapping.end()) continue; + // Since we're just trying to close anything we can find, + // ignore any error return values of close(). HANDLE_EINTR(close(fd)); } return; } - struct dirent *ent; - while ((ent = readdir(dir))) { + const int dir_fd = fd_dir.fd(); + + for ( ; fd_dir.Next(); ) { // Skip . and .. entries. - if (ent->d_name[0] == '.') + if (fd_dir.name()[0] == '.') continue; char *endptr; errno = 0; - const long int fd = strtol(ent->d_name, &endptr, 10); - if (ent->d_name[0] == 0 || *endptr || fd < 0 || errno) + const long int fd = strtol(fd_dir.name(), &endptr, 10); + if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) continue; - if (saved_fds.find(fd) != saved_fds.end()) + if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) + continue; + InjectiveMultimap::const_iterator i; + for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) { + if (fd == i->dest) + break; + } + if (i != saved_mapping.end()) + continue; + if (fd == dir_fd) continue; // When running under Valgrind, Valgrind opens several FDs for its // own use and will complain if we try to close them. All of // these FDs are >= |max_fds|, so we can check against that here // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 - if (fd < static_cast(max_fds)) - HANDLE_EINTR(close(fd)); + if (fd < static_cast(max_fds)) { + int ret = HANDLE_EINTR(close(fd)); + if (ret != 0) { + DLOG(ERROR) << "Problem closing fd"; + } + } } } @@ -419,6 +437,13 @@ bool GetAppOutput(const CommandLine& cl, std::string* output) { int pipe_fd[2]; pid_t pid; + // Illegal to allocate memory after fork and before execvp + InjectiveMultimap fd_shuffle1, fd_shuffle2; + fd_shuffle1.reserve(3); + fd_shuffle2.reserve(3); + const std::vector& argv = cl.argv(); + scoped_array argv_cstr(new char*[argv.size() + 1]); + if (pipe(pipe_fd) < 0) return false; @@ -429,27 +454,35 @@ bool GetAppOutput(const CommandLine& cl, std::string* output) { return false; case 0: // child { + // Obscure fork() rule: in the child, if you don't end up doing exec*(), + // you call _exit() instead of exit(). This is because _exit() does not + // call any previously-registered (in the parent) exit handlers, which + // might do things like block waiting for threads that don't even exist + // in the child. int dev_null = open("/dev/null", O_WRONLY); if (dev_null < 0) - exit(127); + _exit(127); - InjectiveMultimap fd_shuffle; - fd_shuffle.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); - fd_shuffle.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); - fd_shuffle.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); + fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); + fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); + fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); + // Adding another element here? Remeber to increase the argument to + // reserve(), above. - if (!ShuffleFileDescriptors(fd_shuffle)) - exit(127); + std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), + std::back_inserter(fd_shuffle2)); - CloseSuperfluousFds(fd_shuffle); + // fd_shuffle1 is mutated by this call because it cannot malloc. + if (!ShuffleFileDescriptors(&fd_shuffle1)) + _exit(127); + + CloseSuperfluousFds(fd_shuffle2); - const std::vector argv = cl.argv(); - scoped_array argv_cstr(new char*[argv.size() + 1]); for (size_t i = 0; i < argv.size(); i++) argv_cstr[i] = const_cast(argv[i].c_str()); argv_cstr[argv.size()] = NULL; execvp(argv_cstr[0], argv_cstr.get()); - exit(127); + _exit(127); } default: // parent { diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index c85943550b6f..2b494011ea14 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -310,7 +310,7 @@ DEFINE_STATIC_SETTER(static_input_setter, DEFINE_STATIC_SETTER(static_multiline_setter, if (!JSVAL_IS_BOOLEAN(*vp) && !JS_ConvertValue(cx, *vp, JSTYPE_BOOLEAN, vp)) return false; - res->setMultiline(!!JSVAL_TO_BOOLEAN(*vp))) + res->setMultiline(cx, !!JSVAL_TO_BOOLEAN(*vp))) const uint8 REGEXP_STATIC_PROP_ATTRS = JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE; const uint8 RO_REGEXP_STATIC_PROP_ATTRS = REGEXP_STATIC_PROP_ATTRS | JSPROP_READONLY; diff --git a/js/src/config/autoconf.mk.in b/js/src/config/autoconf.mk.in index a3c7fbe31931..8d8b4a542016 100644 --- a/js/src/config/autoconf.mk.in +++ b/js/src/config/autoconf.mk.in @@ -191,11 +191,6 @@ LIBS_DESC_SUFFIX = @LIBS_DESC_SUFFIX@ USE_N32 = @USE_N32@ HAVE_64BIT_OS = @HAVE_64BIT_OS@ -# Temp hack. It is not my intention to leave this crap in here for ever. -# Im talking to fur right now to solve the problem without introducing -# NS_USE_NATIVE to the build system -ramiro. -NS_USE_NATIVE = @NS_USE_NATIVE@ - CC = @CC@ CXX = @CXX@ diff --git a/js/src/configure.in b/js/src/configure.in index ba3b72a567b9..0bf21eabccf0 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -2334,7 +2334,6 @@ ia64*-hpux*) if test "$SOLARIS_SUNPRO_CC"; then LDFLAGS="$LDFLAGS -z ignore -R '\$\$ORIGIN:\$\$ORIGIN/..' -z lazyload -z combreloc -z muldefs" LIBS="-lCrun -lCstd -lc $LIBS" - NS_USE_NATIVE=1 AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" @@ -5079,7 +5078,6 @@ AC_SUBST(WINDRES) AC_SUBST(IMPLIB) AC_SUBST(FILTER) AC_SUBST(BIN_FLAGS) -AC_SUBST(NS_USE_NATIVE) AC_SUBST(MOZ_JS_LIBS) AC_SUBST(MOZ_PSM) AC_SUBST(MOZ_DEBUG) diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index 0fa9388a4585..31ed88b2e663 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -92,19 +92,18 @@ class BumpChunk JS_ASSERT(bump == AlignPtr(bump)); } - void clobberUnused() { -#ifdef DEBUG - memset(bump, 0xcd, limit - bump); -#endif - } - void setBump(void *ptr) { JS_ASSERT(bumpBase() <= ptr); JS_ASSERT(ptr <= limit); DebugOnly prevBump = bump; bump = static_cast(ptr); - if (prevBump < bump) - clobberUnused(); +#ifdef DEBUG + JS_ASSERT(contains(prevBump)); + + /* Clobber the now-free space. */ + if (prevBump > bump) + memset(bump, 0xcd, prevBump - bump); +#endif } public: diff --git a/js/src/jit-test/tests/basic/bug649939.js b/js/src/jit-test/tests/basic/bug649939.js index 9c2cd6141db9..2f1b054730bd 100644 --- a/js/src/jit-test/tests/basic/bug649939.js +++ b/js/src/jit-test/tests/basic/bug649939.js @@ -20,7 +20,7 @@ function assertRaises(exc, callback) { try { callback(); } catch (e) { - assertEq(e instanceof InternalError, true); + assertEq(e instanceof StopIteration, true); caught = true; } assertEq(caught, true); diff --git a/js/src/jit-test/tests/basic/regexp-multiline.js b/js/src/jit-test/tests/basic/regexp-multiline.js new file mode 100644 index 000000000000..7455b4e89ef8 --- /dev/null +++ b/js/src/jit-test/tests/basic/regexp-multiline.js @@ -0,0 +1,12 @@ +// visibility of updates to RegExp.multiline + +function foo(value) { + for (var i = 0; i < 50; i++) { + var re = /erwe/; + assertEq(re.multiline, value); + } +} + +foo(false); +RegExp.multiline = true; +foo(true); diff --git a/js/src/jit-test/tests/basic/testStackIter.js b/js/src/jit-test/tests/basic/testStackIter.js index 9bd1aa8af3dd..ad3741e5c30b 100644 --- a/js/src/jit-test/tests/basic/testStackIter.js +++ b/js/src/jit-test/tests/basic/testStackIter.js @@ -45,7 +45,6 @@ eval("assertStackIs(['eval-code', 'global-code'])"); this['eval']("assertStackIs(['eval-code', eval, 'global-code'])"); eval.bind(null, "assertStackIs(['eval-code', eval, 'bound(eval)', 'global-code'])")(); (function f() { assertStackIs([f, Function.prototype.call, 'global-code']) }).call(null); -(function f() { assertStackIs([f, Function.prototype.apply, 'global-code']) }).apply(null, {}); (function f() { (function g(x,y,z) { assertStackIs([g,f,'global-code']); })() })(1); /***********/ @@ -135,10 +134,9 @@ new proxy(); /***********/ for (var i = 0; i < 10; ++i) { + eval("'no imacros please'"); + /* No loss for scripts. */ - (function f() { - assertStackIs([f, Function.prototype.apply, 'global-code']); - }).apply(null, {}); (function f() { assertStackIs([f, Function.prototype.call, 'global-code']); }).call(null); @@ -155,26 +153,4 @@ for (var i = 0; i < 10; ++i) { assertEq(stack[1], Function.prototype.call); } }).bind().call(null); - (function f() { - var stack = dumpStack(); - assertEq(stack[0], f); - if (stack.length === 4) { - assertEq(stack[1].name, 'f'); - assertEq(stack[2], Function.prototype.apply); - } else { - assertEq(stack.length, 3); - assertEq(stack[1], Function.prototype.apply); - } - }).bind().apply(null, {}); - (function f() { - var stack = dumpStack(); - assertEq(stack[0], f); - if (stack.length === 4) { - assertEq(stack[1].name, 'f'); - assertEq(stack[2], Function.prototype.apply); - } else { - assertEq(stack.length, 3); - assertEq(stack[1], Function.prototype.apply); - } - }).bind().apply(null, [1,2,3,4,5]); } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 71c403ae4e56..2a4d1934cc6f 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5944,7 +5944,7 @@ JS_SetRegExpInput(JSContext *cx, JSObject *obj, JSString *input, JSBool multilin CHECK_REQUEST(cx); assertSameCompartment(cx, input); - obj->asGlobal()->getRegExpStatics()->reset(input, !!multiline); + obj->asGlobal()->getRegExpStatics()->reset(cx, input, !!multiline); } JS_PUBLIC_API(void) diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 399e21abd919..f213efc948f0 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -301,37 +301,40 @@ enum { * Some objects are not dense arrays, or are dense arrays whose length * property does not fit in an int32. */ - OBJECT_FLAG_NON_DENSE_ARRAY = 0x0010000, + OBJECT_FLAG_NON_DENSE_ARRAY = 0x00010000, /* Whether any objects this represents are not packed arrays. */ - OBJECT_FLAG_NON_PACKED_ARRAY = 0x0020000, + OBJECT_FLAG_NON_PACKED_ARRAY = 0x00020000, /* Whether any objects this represents are not typed arrays. */ - OBJECT_FLAG_NON_TYPED_ARRAY = 0x0040000, + OBJECT_FLAG_NON_TYPED_ARRAY = 0x00040000, /* Whether any represented script has had arguments objects created. */ - OBJECT_FLAG_CREATED_ARGUMENTS = 0x0080000, + OBJECT_FLAG_CREATED_ARGUMENTS = 0x00080000, /* Whether any represented script is considered uninlineable. */ - OBJECT_FLAG_UNINLINEABLE = 0x0100000, + OBJECT_FLAG_UNINLINEABLE = 0x00100000, /* Whether any objects have an equality hook. */ - OBJECT_FLAG_SPECIAL_EQUALITY = 0x0200000, + OBJECT_FLAG_SPECIAL_EQUALITY = 0x00200000, /* Whether any objects have been iterated over. */ - OBJECT_FLAG_ITERATED = 0x0400000, + OBJECT_FLAG_ITERATED = 0x00400000, /* Outer function which has been marked reentrant. */ - OBJECT_FLAG_REENTRANT_FUNCTION = 0x0800000, + OBJECT_FLAG_REENTRANT_FUNCTION = 0x00800000, + + /* For a global object, whether flags were set on the RegExpStatics. */ + OBJECT_FLAG_REGEXP_FLAGS_SET = 0x01000000, /* Flags which indicate dynamic properties of represented objects. */ - OBJECT_FLAG_DYNAMIC_MASK = 0x0ff0000, + OBJECT_FLAG_DYNAMIC_MASK = 0x01ff0000, /* * Whether all properties of this object are considered unknown. * If set, all flags in DYNAMIC_MASK will also be set. */ - OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x1000000, + OBJECT_FLAG_UNKNOWN_PROPERTIES = 0x80000000, /* Mask for objects created with unknown properties. */ OBJECT_FLAG_UNKNOWN_MASK = diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 5ed5f1027785..e656f5bff157 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -574,8 +574,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp) if (obj) { /* Enumerate Iterator.prototype directly. */ - JSIteratorOp op = obj->getClass()->ext.iteratorObject; - if (op && (obj->getClass() != &IteratorClass || obj->getNativeIterator())) { + if (JSIteratorOp op = obj->getClass()->ext.iteratorObject) { JSObject *iterobj = op(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) return false; @@ -973,12 +972,10 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval) if (iterobj->isIterator()) { /* Key iterators are handled by fast-paths. */ ni = iterobj->getNativeIterator(); - if (ni) { - bool more = ni->props_cursor < ni->props_end; - if (ni->isKeyIter() || !more) { - rval->setBoolean(more); - return true; - } + bool more = ni->props_cursor < ni->props_end; + if (ni->isKeyIter() || !more) { + rval->setBoolean(more); + return true; } } @@ -1033,7 +1030,7 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) * read-only and permanent. */ NativeIterator *ni = iterobj->getNativeIterator(); - if (ni && ni->isKeyIter()) { + if (ni->isKeyIter()) { JS_ASSERT(ni->props_cursor < ni->props_end); *rval = IdToValue(*ni->current()); ni->incCursor(); @@ -1459,6 +1456,14 @@ InitIteratorClass(JSContext *cx, GlobalObject *global) if (!iteratorProto) return false; + AutoIdVector blank(cx); + NativeIterator *ni = NativeIterator::allocateIterator(cx, 0, blank); + if (!ni) + return false; + ni->init(NULL, 0 /* flags */, 0, 0); + + iteratorProto->setNativeIterator(ni); + JSFunction *ctor = global->createConstructor(cx, Iterator, &IteratorClass, CLASS_ATOM(cx, Iterator), 2); if (!ctor) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index ef1f354ffa97..16573c452cfd 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -1539,8 +1539,8 @@ MatchCallback(JSContext *cx, RegExpStatics *res, size_t count, void *p) return res->createLastMatch(cx, &v) && arrayobj->defineElement(cx, count, v); } -static JSBool -str_match(JSContext *cx, uintN argc, Value *vp) +JSBool +js::str_match(JSContext *cx, uintN argc, Value *vp) { JSString *str = ThisToStringForStringProto(cx, vp); if (!str) @@ -1572,8 +1572,8 @@ str_match(JSContext *cx, uintN argc, Value *vp) return true; } -static JSBool -str_search(JSContext *cx, uintN argc, Value *vp) +JSBool +js::str_search(JSContext *cx, uintN argc, Value *vp) { JSString *str = ThisToStringForStringProto(cx, vp); if (!str) @@ -2436,8 +2436,8 @@ class SplitStringMatcher { }; /* ES5 15.5.4.14 */ -static JSBool -str_split(JSContext *cx, uintN argc, Value *vp) +JSBool +js::str_split(JSContext *cx, uintN argc, Value *vp) { /* Steps 1-2. */ JSString *str = ThisToStringForStringProto(cx, vp); diff --git a/js/src/jsstr.h b/js/src/jsstr.h index be76219c0bb4..5dc596556db4 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -337,6 +337,15 @@ FileEscapedString(FILE *fp, JSLinearString *str, uint32 quote) return PutEscapedStringImpl(NULL, 0, fp, str, quote) != size_t(-1); } +JSBool +str_match(JSContext *cx, uintN argc, Value *vp); + +JSBool +str_search(JSContext *cx, uintN argc, Value *vp); + +JSBool +str_split(JSContext *cx, uintN argc, Value *vp); + } /* namespace js */ extern JSBool diff --git a/js/src/methodjit/BaseAssembler.h b/js/src/methodjit/BaseAssembler.h index 248a6c1bb589..98b0095eb152 100644 --- a/js/src/methodjit/BaseAssembler.h +++ b/js/src/methodjit/BaseAssembler.h @@ -1305,10 +1305,15 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist storePtr(ImmPtr((void *) templateObject->capacity), Address(result, offsetof(JSObject, capacity))); storePtr(ImmPtr(templateObject->type()), Address(result, JSObject::offsetOfType())); - /* Fixed slots of non-array objects are required to be initialized. */ + /* + * Fixed slots of non-array objects are required to be initialized; + * Use the values currently in the template object. + */ if (!templateObject->isDenseArray()) { - for (unsigned i = 0; i < templateObject->numFixedSlots(); i++) - storeValue(UndefinedValue(), Address(result, JSObject::getFixedSlotOffset(i))); + for (unsigned i = 0; i < templateObject->numFixedSlots(); i++) { + storeValue(templateObject->getFixedSlot(i), + Address(result, JSObject::getFixedSlotOffset(i))); + } } return jump; diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 5edc2247567a..3a22e0d402e6 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -61,9 +61,15 @@ #include "jsopcodeinlines.h" #include "jshotloop.h" +#include "builtin/RegExp.h" +#include "vm/RegExpStatics.h" +#include "vm/RegExpObject.h" + #include "jsautooplen.h" #include "jstypedarrayinlines.h" +#include "vm/RegExpObject-inl.h" + using namespace js; using namespace js::mjit; #if defined(JS_POLYIC) || defined(JS_MONOIC) @@ -2719,14 +2725,7 @@ mjit::Compiler::generateMethod() END_CASE(JSOP_SETGNAME) BEGIN_CASE(JSOP_REGEXP) - { - JSObject *regex = script->getRegExp(fullAtomIndex(PC)); - prepareStubCall(Uses(0)); - masm.move(ImmPtr(regex), Registers::ArgReg1); - INLINE_STUBCALL(stubs::RegExp, REJOIN_PUSH_OBJECT); - frame.takeReg(Registers::ReturnReg); - frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg); - } + jsop_regexp(); END_CASE(JSOP_REGEXP) BEGIN_CASE(JSOP_OBJECT) @@ -6576,6 +6575,87 @@ mjit::Compiler::jsop_newinit() return true; } +void +mjit::Compiler::jsop_regexp() +{ + JSObject *obj = script->getRegExp(fullAtomIndex(PC)); + RegExpStatics *res = globalObj ? globalObj->getRegExpStatics() : NULL; + + if (!globalObj || + !cx->typeInferenceEnabled() || + analysis->localsAliasStack() || + types::TypeSet::HasObjectFlags(cx, globalObj->getType(cx), + types::OBJECT_FLAG_REGEXP_FLAGS_SET)) { + prepareStubCall(Uses(0)); + masm.move(ImmPtr(obj), Registers::ArgReg1); + INLINE_STUBCALL(stubs::RegExp, REJOIN_FALLTHROUGH); + frame.pushSynced(JSVAL_TYPE_OBJECT); + return; + } + + RegExpPrivate *regexp = static_cast(obj)->getPrivate(); + + DebugOnly origFlags = regexp->getFlags(); + DebugOnly staticsFlags = res->getFlags(); + JS_ASSERT((origFlags & staticsFlags) == staticsFlags); + + /* + * JS semantics require regular expression literals to create different + * objects every time they execute. We only need to do this cloning if the + * script could actually observe the effect of such cloning, by getting + * or setting properties on it. Particular RegExp and String natives take + * regular expressions as 'this' or an argument, and do not let that + * expression escape and be accessed by the script, so avoid cloning in + * these cases. + */ + analyze::SSAUseChain *uses = + analysis->useChain(analyze::SSAValue::PushedValue(PC - script->code, 0)); + if (uses && uses->popped && !uses->next) { + jsbytecode *use = script->code + uses->offset; + uint32 which = uses->u.which; + if (JSOp(*use) == JSOP_CALLPROP) { + JSObject *callee = analysis->pushedTypes(use, 0)->getSingleton(cx); + if (callee && callee->isFunction()) { + Native native = callee->getFunctionPrivate()->maybeNative(); + if (native == js::regexp_exec || native == js::regexp_test) { + frame.push(ObjectValue(*obj)); + return; + } + } + } else if (JSOp(*use) == JSOP_CALL && which == 0) { + uint32 argc = GET_ARGC(use); + JSObject *callee = analysis->poppedTypes(use, argc + 1)->getSingleton(cx); + if (callee && callee->isFunction() && argc >= 1 && which == argc - 1) { + Native native = callee->getFunctionPrivate()->maybeNative(); + if (native == js::str_match || + native == js::str_search || + native == js::str_replace || + native == js::str_split) { + frame.push(ObjectValue(*obj)); + return; + } + } + } + } + + RegisterID result = frame.allocReg(); + Jump emptyFreeList = masm.getNewObject(cx, result, obj); + + stubcc.linkExit(emptyFreeList, Uses(0)); + stubcc.leave(); + + stubcc.masm.move(ImmPtr(obj), Registers::ArgReg1); + OOL_STUBCALL(stubs::RegExp, REJOIN_FALLTHROUGH); + + /* Bump the refcount on the wrapped RegExp. */ + size_t *refcount = regexp->addressOfRefCount(); + masm.add32(Imm32(1), AbsoluteAddress(refcount)); + + frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result); + + stubcc.rejoin(Changes(1)); +} + bool mjit::Compiler::startLoop(jsbytecode *head, Jump entry, jsbytecode *entryTarget) { diff --git a/js/src/methodjit/Compiler.h b/js/src/methodjit/Compiler.h index 373337087afc..bd4dd9be91c3 100644 --- a/js/src/methodjit/Compiler.h +++ b/js/src/methodjit/Compiler.h @@ -711,6 +711,7 @@ private: bool jsop_arginc(JSOp op, uint32 slot); bool jsop_localinc(JSOp op, uint32 slot); bool jsop_newinit(); + void jsop_regexp(); void jsop_initmethod(); void jsop_initprop(); void jsop_initelem(); diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index f9d9f1e02281..2aa0cd218a49 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -1430,7 +1430,7 @@ stubs::DefLocalFun_FC(VMFrame &f, JSFunction *fun) return obj; } -JSObject * JS_FASTCALL +void JS_FASTCALL stubs::RegExp(VMFrame &f, JSObject *regex) { /* @@ -1443,12 +1443,12 @@ stubs::RegExp(VMFrame &f, JSObject *regex) */ JSObject *proto; if (!js_GetClassPrototype(f.cx, &f.fp()->scopeChain(), JSProto_RegExp, &proto)) - THROWV(NULL); + THROW(); JS_ASSERT(proto); JSObject *obj = js_CloneRegExpObject(f.cx, regex, proto); if (!obj) - THROWV(NULL); - return obj; + THROW(); + f.regs.sp[0].setObject(*obj); } JSObject * JS_FASTCALL diff --git a/js/src/methodjit/StubCalls.h b/js/src/methodjit/StubCalls.h index 41c712a24b7e..86e92a5773ae 100644 --- a/js/src/methodjit/StubCalls.h +++ b/js/src/methodjit/StubCalls.h @@ -152,7 +152,7 @@ void JS_FASTCALL SetConst(VMFrame &f, JSAtom *atom); template void JS_FASTCALL DefFun(VMFrame &f, JSFunction *fun); JSObject * JS_FASTCALL DefLocalFun(VMFrame &f, JSFunction *fun); JSObject * JS_FASTCALL DefLocalFun_FC(VMFrame &f, JSFunction *fun); -JSObject * JS_FASTCALL RegExp(VMFrame &f, JSObject *regex); +void JS_FASTCALL RegExp(VMFrame &f, JSObject *regex); JSObject * JS_FASTCALL Lambda(VMFrame &f, JSFunction *fun); JSObject * JS_FASTCALL LambdaJoinableForInit(VMFrame &f, JSFunction *fun); JSObject * JS_FASTCALL LambdaJoinableForSet(VMFrame &f, JSFunction *fun); diff --git a/js/src/vm/RegExpObject-inl.h b/js/src/vm/RegExpObject-inl.h index c57f84000933..1ed596a234ba 100644 --- a/js/src/vm/RegExpObject-inl.h +++ b/js/src/vm/RegExpObject-inl.h @@ -46,6 +46,7 @@ #include "jsobjinlines.h" #include "jsstrinlines.h" +#include "RegExpStatics-inl.h" inline js::RegExpObject * JSObject::asRegExp() diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index 74b6b2fa304c..1449d5625567 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -284,6 +284,9 @@ class RegExpPrivate void incref(JSContext *cx); void decref(JSContext *cx); + /* For JIT access. */ + size_t *addressOfRefCount() { return &refCount; } + /* Accessors */ JSLinearString *getSource() const { return source; } diff --git a/js/src/vm/RegExpStatics-inl.h b/js/src/vm/RegExpStatics-inl.h index 722055ac966a..c0c25f177e6f 100644 --- a/js/src/vm/RegExpStatics-inl.h +++ b/js/src/vm/RegExpStatics-inl.h @@ -181,6 +181,45 @@ RegExpStatics::getRightContext(JSSubString *out) const out->length = matchPairsInput->length() - get(0, 1); } +inline void +RegExpStatics::setMultiline(JSContext *cx, bool enabled) +{ + aboutToWrite(); + if (enabled) { + flags = RegExpFlag(flags | MultilineFlag); + markFlagsSet(cx); + } else { + flags = RegExpFlag(flags & ~MultilineFlag); + } +} + +inline void +RegExpStatics::markFlagsSet(JSContext *cx) +{ + /* + * Flags set on the RegExp function get propagated to constructed RegExp + * objects, which interferes with optimizations that inline RegExp cloning + * or avoid cloning entirely. Scripts making this assumption listen to + * type changes on RegExp.prototype, so mark a state change to trigger + * recompilation of all such code (when recompiling, a stub call will + * always be performed). + */ + GlobalObject *global = GetGlobalForScopeChain(cx); + JS_ASSERT(this == global->getRegExpStatics()); + + types::MarkTypeObjectFlags(cx, global, types::OBJECT_FLAG_REGEXP_FLAGS_SET); +} + +inline void +RegExpStatics::reset(JSContext *cx, JSString *newInput, bool newMultiline) +{ + aboutToWrite(); + clear(); + pendingInput = newInput; + setMultiline(cx, newMultiline); + checkInvariants(); +} + } /* namespace js */ #endif diff --git a/js/src/vm/RegExpStatics.h b/js/src/vm/RegExpStatics.h index a9d89bc593c1..e383f137bb34 100644 --- a/js/src/vm/RegExpStatics.h +++ b/js/src/vm/RegExpStatics.h @@ -148,6 +148,8 @@ class RegExpStatics */ bool makeMatch(JSContext *cx, size_t checkValidIndex, size_t pairNum, Value *out) const; + void markFlagsSet(JSContext *cx); + struct InitBuffer {}; explicit RegExpStatics(InitBuffer) : bufferLink(NULL), copied(false) {} @@ -157,7 +159,6 @@ class RegExpStatics RegExpStatics() : bufferLink(NULL), copied(false) { clear(); } static JSObject *create(JSContext *cx, GlobalObject *parent); - static RegExpStatics *extractFrom(GlobalObject *globalObj); /* Mutators. */ @@ -177,13 +178,7 @@ class RegExpStatics return true; } - void setMultiline(bool enabled) { - aboutToWrite(); - if (enabled) - flags = RegExpFlag(flags | MultilineFlag); - else - flags = RegExpFlag(flags & ~MultilineFlag); - } + inline void setMultiline(JSContext *cx, bool enabled); void clear() { aboutToWrite(); @@ -194,13 +189,7 @@ class RegExpStatics } /* Corresponds to JSAPI functionality to set the pending RegExp input. */ - void reset(JSString *newInput, bool newMultiline) { - aboutToWrite(); - clear(); - pendingInput = newInput; - setMultiline(newMultiline); - checkInvariants(); - } + inline void reset(JSContext *cx, JSString *newInput, bool newMultiline); void setPendingInput(JSString *newInput) { aboutToWrite(); diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 50503e6268af..ffc2b86d6769 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1028,19 +1028,20 @@ StackIter::settleOnNewState() * * regs.sp == vp + 2 + argc * - * The mjit Function.prototype.apply optimization breaks this - * invariant (see ic::SplatApplyArgs). Thus, for JSOP_FUNAPPLY we - * need to (slowly) reconstruct the depth. - * - * Additionally, the Function.prototype.{call,apply} optimizations - * leave no record when 'this' is a native function. Thus, if the - * following expression runs and breaks in the debugger, the call - * to 'replace' will not appear on the callstack. + * The Function.prototype.call optimization leaves no record when + * 'this' is a native function. Thus, if the following expression + * runs and breaks in the debugger, the call to 'replace' will not + * appear on the callstack. * * (String.prototype.replace).call('a',/a/,function(){debugger}); * * Function.prototype.call will however appear, hence the debugger * can, by inspecting 'args.thisv', give some useful information. + * + * For Function.prototype.apply, the situation is even worse: since + * a dynamic number of arguments have been pushed onto the stack + * (see SplatApplyArgs), there is no efficient way to know how to + * find the callee. Thus, calls to apply are lost completely. */ JSOp op = js_GetOpcode(cx_, fp_->script(), pc_); if (op == JSOP_CALL || op == JSOP_FUNCALL) { @@ -1056,30 +1057,12 @@ StackIter::settleOnNewState() args_ = CallArgsFromVp(argc, vp); return; } - } else if (op == JSOP_FUNAPPLY) { - JS_ASSERT(!fp_->hasImacropc()); - uintN argc = GET_ARGC(pc_); - uintN spoff = js_ReconstructStackDepth(cx_, fp_->script(), pc_); - Value *sp = fp_->base() + spoff; - Value *vp = sp - (2 + argc); - - CrashIfInvalidSlot(fp_, vp); - if (IsNativeFunction(*vp)) { - if (sp_ != sp) { - JS_ASSERT(argc == 2); - JS_ASSERT(vp[0].toObject().getFunctionPrivate()->native() == js_fun_apply); - JS_ASSERT(sp_ >= vp + 3); - argc = sp_ - (vp + 2); - } - state_ = IMPLICIT_NATIVE; - args_ = CallArgsFromVp(argc, vp); - return; - } } state_ = SCRIPTED; - JS_ASSERT(sp_ >= fp_->base() && sp_ <= fp_->slots() + fp_->script()->nslots); DebugOnly script = fp_->script(); + JS_ASSERT_IF(op != JSOP_FUNAPPLY, + sp_ >= fp_->base() && sp_ <= fp_->slots() + script->nslots); JS_ASSERT_IF(!fp_->hasImacropc(), pc_ >= script->code && pc_ < script->code + script->length); return; diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index b8c4dbf3a928..a53a6df4e5b2 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -1175,9 +1175,6 @@ XPCConvert::NativeInterface2JSObject(XPCLazyCallContext& lccx, &triedToWrap); if(!flat && triedToWrap) return JS_FALSE; - if (!flat) { - flat = ConstructProxyObject(ccx, aHelper, xpcscope); - } } if(flat) { diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index f58ecc4b63c0..bfdd0e8f1ad3 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -2370,10 +2370,6 @@ private: }; class xpcObjectHelper; -JSObject * -ConstructProxyObject(XPCCallContext &ccx, - xpcObjectHelper &aHelper, - XPCWrappedNativeScope *xpcscope); extern JSBool ConstructSlimWrapper(XPCCallContext &ccx, xpcObjectHelper &aHelper, XPCWrappedNativeScope* xpcScope, diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index b0c8b0302ec8..5598ef7ea460 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -3923,34 +3923,6 @@ MorphSlimWrapper(JSContext *cx, JSObject *obj) static PRUint32 sSlimWrappers; #endif -JSObject * -ConstructProxyObject(XPCCallContext &ccx, - xpcObjectHelper &aHelper, - XPCWrappedNativeScope *xpcscope) -{ - nsISupports *identityObj = aHelper.GetCanonical(); - nsXPCClassInfo *classInfoHelper = aHelper.GetXPCClassInfo(); - -#ifdef DEBUG - { - JSUint32 flagsInt; - nsresult debug_rv = classInfoHelper->GetScriptableFlags(&flagsInt); - XPCNativeScriptableFlags flags(flagsInt); - NS_ASSERTION(NS_SUCCEEDED(debug_rv) && flags.WantPreCreate(), - "bad flags, cache->IsProxy() implies WantPreCreate()"); - } -#endif - - // We re-use the PreCreate hook to create the actual proxy object. - JSObject* parent = xpcscope->GetGlobalJSObject(); - nsresult rv = classInfoHelper->PreCreate(identityObj, ccx, parent, &parent); - NS_ENSURE_SUCCESS(rv, nsnull); - - nsWrapperCache *cache = aHelper.GetWrapperCache(); - JSObject *flat = cache->GetWrapper(); - return flat; -} - JSBool ConstructSlimWrapper(XPCCallContext &ccx, xpcObjectHelper &aHelper, diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index 79cfa84eed52..2e230010a845 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -277,11 +277,11 @@ TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder, scroll->GetScrollbarStyles().mHorizontal != NS_STYLE_OVERFLOW_HIDDEN; textOverflow->mContentArea.MoveBy(scroll->GetScrollPosition()); } - textOverflow->mBlockIsRTL = - aBlockFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; + PRUint8 direction = aBlockFrame->GetStyleVisibility()->mDirection; + textOverflow->mBlockIsRTL = direction == NS_STYLE_DIRECTION_RTL; const nsStyleTextReset* style = aBlockFrame->GetStyleTextReset(); - textOverflow->mLeft.Init(style->mTextOverflow.mLeft); - textOverflow->mRight.Init(style->mTextOverflow.mRight); + textOverflow->mLeft.Init(style->mTextOverflow.GetLeft(direction)); + textOverflow->mRight.Init(style->mTextOverflow.GetRight(direction)); // The left/right marker string is setup in ExamineLineFrames when a line // has overflow on that side. @@ -402,31 +402,44 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine, FrameHashtable* aFramesToHide, AlignmentEdges* aAlignmentEdges) { + // No ellipsing for 'clip' style. + bool suppressLeft = mLeft.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP; + bool suppressRight = mRight.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP; + if (mCanHaveHorizontalScrollbar) { + nsIScrollableFrame* scroll = nsLayoutUtils::GetScrollableFrameFor(mBlock); + nsPoint pos = scroll->GetScrollPosition(); + nsRect scrollRange = scroll->GetScrollRange(); + // No ellipsing when nothing to scroll to on that side (this includes + // overflow:auto that doesn't trigger a horizontal scrollbar). + if (pos.x <= scrollRange.x) { + suppressLeft = true; + } + if (pos.x >= scrollRange.XMost()) { + suppressRight = true; + } + } + // Scrolling to the end position can leave some text still overflowing due to // pixel snapping behaviour in our scrolling code so we move the edges 1px // outward to avoid triggering a text-overflow marker for such overflow. nsRect contentArea = mContentArea; const nscoord scrollAdjust = mCanHaveHorizontalScrollbar ? mBlock->PresContext()->AppUnitsPerDevPixel() : 0; - InflateLeft(&contentArea, - mLeft.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP, - scrollAdjust); - InflateRight(&contentArea, - mRight.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP, - scrollAdjust); + InflateLeft(&contentArea, suppressLeft, scrollAdjust); + InflateRight(&contentArea, suppressRight, scrollAdjust); nsRect lineRect = aLine->GetScrollableOverflowArea(); - const bool leftOverflow = lineRect.x < contentArea.x; - const bool rightOverflow = lineRect.XMost() > contentArea.XMost(); + const bool leftOverflow = + !suppressLeft && lineRect.x < contentArea.x; + const bool rightOverflow = + !suppressRight && lineRect.XMost() > contentArea.XMost(); if (!leftOverflow && !rightOverflow) { - // The line does not overflow - no need to traverse the frame tree. + // The line does not overflow on a side we should ellipsize. return; } PRUint32 pass = 0; - bool guessLeft = - mLeft.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP && leftOverflow; - bool guessRight = - mRight.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP && rightOverflow; + bool guessLeft = leftOverflow; + bool guessRight = rightOverflow; do { // Setup marker strings as needed. if (guessLeft) { diff --git a/layout/generic/crashtests/688996-1.html b/layout/generic/crashtests/688996-1.html new file mode 100644 index 000000000000..f2a32802d29c --- /dev/null +++ b/layout/generic/crashtests/688996-1.html @@ -0,0 +1,18 @@ + +
b
+ diff --git a/layout/generic/crashtests/688996-2.html b/layout/generic/crashtests/688996-2.html new file mode 100644 index 000000000000..d4132d91fbe9 --- /dev/null +++ b/layout/generic/crashtests/688996-2.html @@ -0,0 +1,15 @@ + +
b
+ diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index 54ccc19a632d..7be438ed9341 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -379,3 +379,5 @@ asserts(14) asserts-if(Android,8) load 673770.html # bug 569193 and bug 459597 load 679933-1.html load 682649-1.html load 683702-1.xhtml +load 688996-1.html +load 688996-2.html diff --git a/layout/reftests/canvas/693610-1-notref.html b/layout/reftests/canvas/693610-1-notref.html new file mode 100644 index 000000000000..6f2642da1e13 --- /dev/null +++ b/layout/reftests/canvas/693610-1-notref.html @@ -0,0 +1,18 @@ + + + + + + +

+ + + diff --git a/layout/reftests/canvas/693610-1.html b/layout/reftests/canvas/693610-1.html new file mode 100644 index 000000000000..77745ae5f587 --- /dev/null +++ b/layout/reftests/canvas/693610-1.html @@ -0,0 +1,16 @@ + + + + + + +

+ + + diff --git a/layout/reftests/canvas/reftest.list b/layout/reftests/canvas/reftest.list index 9298988b6d41..6c44daf407fc 100644 --- a/layout/reftests/canvas/reftest.list +++ b/layout/reftests/canvas/reftest.list @@ -67,3 +67,6 @@ fails == ctm-singular-sanity.html data:text/html,Pass # Bug 612033 fails-if(cocoaWidget) == 672646-alpha-radial-gradient.html 672646-alpha-radial-gradient-ref.html # Bug 673333 == 674003-alpha-radial-gradient-superlum.html 674003-alpha-radial-gradient-superlum-ref.html + +!= 693610-1.html 693610-1-notref.html # bug 693610: multiple glyph runs should not be overprinted + diff --git a/layout/reftests/selection/splitText-normalize.js b/layout/reftests/selection/splitText-normalize.js index c0b1e976e339..820c2bd2112d 100644 --- a/layout/reftests/selection/splitText-normalize.js +++ b/layout/reftests/selection/splitText-normalize.js @@ -16,6 +16,7 @@ var tests = [ [ {endNode:1}, [0,4], "012345678", "" ], [ {endNode:1}, [0,4], "01234567", "8" ], [ {endNode:1}, [1,4], "0", "12345678" ], + [ {startOffset:1,endNode:1}, [0,0], "0", "12345678" ], [ {endNode:2}, [1,4], "0", "12345", "678" ], ] diff --git a/layout/reftests/svg/filter-extref-differentOrigin-01.svg b/layout/reftests/svg/filter-extref-differentOrigin-01.svg new file mode 100644 index 000000000000..c10d5b89fdde --- /dev/null +++ b/layout/reftests/svg/filter-extref-differentOrigin-01.svg @@ -0,0 +1,12 @@ + + + + + + + diff --git a/layout/reftests/svg/mask-extref-dataURI-01.svg b/layout/reftests/svg/mask-extref-dataURI-01.svg new file mode 100644 index 000000000000..b79258fb1763 --- /dev/null +++ b/layout/reftests/svg/mask-extref-dataURI-01.svg @@ -0,0 +1,38 @@ + + + +]> + + + Testcase for bug 686013: CSS mask targeting a fragment in a data URI + + + + + + + + + + + + + + + + + + + diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index ce2ec1c6a2e7..51d2bf6e7159 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -105,6 +105,7 @@ random == dynamic-use-nested-01.svg dynamic-use-nested-01-ref.svg # bug 467498 == use-01.svg pass.svg == use-01-extref.svg pass.svg == use-02-extref.svg use-02-extref-ref.svg +== use-extref-dataURI-01.svg pass.svg == use-children.svg pass.svg == fallback-color-01a.svg pass.svg == fallback-color-01b.svg pass.svg @@ -116,6 +117,7 @@ random == dynamic-use-nested-01.svg dynamic-use-nested-01-ref.svg # bug 467498 == filter-basic-03.svg pass.svg == filter-bounds-01.svg pass.svg == filter-bounds-02.svg pass.svg +== filter-extref-differentOrigin-01.svg pass.svg == filter-foreignObject-01.svg pass.svg == filter-invalidation-01.svg pass.svg == filter-scaled-01.svg pass.svg @@ -146,6 +148,7 @@ fails == inline-in-xul-basic-01.xul pass.svg == marker-viewBox-01.svg marker-viewBox-01-ref.svg == mask-basic-01.svg pass.svg == mask-basic-02.svg mask-basic-02-ref.svg +== mask-extref-dataURI-01.svg pass.svg == mask-containing-masked-content-01.svg pass.svg == mask-transformed-01.svg mask-transformed-01-ref.svg == nested-viewBox-01.svg pass.svg diff --git a/layout/reftests/svg/use-extref-dataURI-01.svg b/layout/reftests/svg/use-extref-dataURI-01.svg new file mode 100644 index 000000000000..3274a21264c4 --- /dev/null +++ b/layout/reftests/svg/use-extref-dataURI-01.svg @@ -0,0 +1,12 @@ + + + + Testcase for bug 686013: <use> targeting a fragment in a data URI + + + + diff --git a/layout/reftests/text-overflow/bidi-simple-scrolled.html b/layout/reftests/text-overflow/bidi-simple-scrolled.html index 5036958687c8..489535ab83f3 100644 --- a/layout/reftests/text-overflow/bidi-simple-scrolled.html +++ b/layout/reftests/text-overflow/bidi-simple-scrolled.html @@ -17,7 +17,7 @@ html,body { } .test { overflow:auto; - text-overflow:ellipsis; + text-overflow:ellipsis ellipsis; white-space:nowrap; width: 4.4em; margin-bottom:1em; diff --git a/layout/reftests/text-overflow/ellipsis-font-fallback.html b/layout/reftests/text-overflow/ellipsis-font-fallback.html index 4e4c32e4864c..f02d569d0a6c 100644 --- a/layout/reftests/text-overflow/ellipsis-font-fallback.html +++ b/layout/reftests/text-overflow/ellipsis-font-fallback.html @@ -31,7 +31,7 @@ html,body { } .o { - text-overflow: ellipsis; + text-overflow: ellipsis ellipsis; color:blue; } .o span { diff --git a/layout/reftests/text-overflow/false-marker-overlap.html b/layout/reftests/text-overflow/false-marker-overlap.html index 55ead4533cf7..28720226c093 100644 --- a/layout/reftests/text-overflow/false-marker-overlap.html +++ b/layout/reftests/text-overflow/false-marker-overlap.html @@ -19,7 +19,7 @@ html,body { .test { overflow: hidden; white-space: nowrap; - text-overflow: ellipsis; + text-overflow: ellipsis ellipsis; color: black; height: 6em; width: 32.5em; diff --git a/layout/reftests/text-overflow/marker-basic-ref.html b/layout/reftests/text-overflow/marker-basic-ref.html index 42736eee178e..6f10b17a6323 100644 --- a/layout/reftests/text-overflow/marker-basic-ref.html +++ b/layout/reftests/text-overflow/marker-basic-ref.html @@ -134,6 +134,8 @@ x1 m { position:absolute; right:0; font-size:16px; } #test9b { top:320px; left:100px; position:absolute; border:1px solid black; } #test9c { top:320px; left:200px; position:absolute; border:1px solid black; } #test9d { top:320px; left:300px; position:absolute; border:1px solid black; } +#test10a { top:360px; left:0; position:absolute; } +#test10b { top:360px; left:100px; position:absolute; } @@ -299,6 +301,9 @@ x1 m { position:absolute; right:0; font-size:16px; }
    
    
+ +
||||||
+
||||||
diff --git a/layout/reftests/text-overflow/marker-basic.html b/layout/reftests/text-overflow/marker-basic.html index 9f67d0260852..4f4afb667cf0 100644 --- a/layout/reftests/text-overflow/marker-basic.html +++ b/layout/reftests/text-overflow/marker-basic.html @@ -30,7 +30,7 @@ html,body { } .o { - text-overflow: ellipsis; + text-overflow: ellipsis ellipsis; } .rel { @@ -50,6 +50,9 @@ html,body { white-space:nowrap; font-size:16px; } +.auto { + overflow: auto; +} .r { text-align:right; } @@ -131,6 +134,8 @@ i { #test9b { top:320px; left:100px; position:absolute; border:1px solid black; } #test9c { top:320px; left:200px; position:absolute; border:1px solid black; } #test9d { top:320px; left:300px; position:absolute; border:1px solid black; } +#test10a { top:360px; left:0; position:absolute; } +#test10b { top:360px; left:100px; position:absolute; } @@ -191,7 +196,10 @@ i {
    |||
    |||
- + +
||||||
+
||||||
+ diff --git a/layout/reftests/text-overflow/marker-string.html b/layout/reftests/text-overflow/marker-string.html index 3cfee6e7fda9..356ae14c2f2f 100644 --- a/layout/reftests/text-overflow/marker-string.html +++ b/layout/reftests/text-overflow/marker-string.html @@ -44,9 +44,9 @@ s { direction:ltr; } -.t1 { text-overflow:""; } -.t2 { text-overflow:"Hello World"; } -.t3 { text-overflow:"X"; } +.t1 { text-overflow:"" ""; } +.t2 { text-overflow:"Hello World" "Hello World"; } +.t3 { text-overflow:"X" "X"; } diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list index 1b72f667f5e9..bc2573f54f06 100644 --- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -19,3 +19,4 @@ skip-if(Android) == clipped-elements.html clipped-elements-ref.html == theme-overflow.html theme-overflow-ref.html HTTP(..) == table-cell.html table-cell-ref.html HTTP(..) == two-value-syntax.html two-value-syntax-ref.html +HTTP(..) == single-value.html single-value-ref.html diff --git a/layout/reftests/text-overflow/selection.html b/layout/reftests/text-overflow/selection.html index 4115e31f4a3c..7cba2c6652fb 100644 --- a/layout/reftests/text-overflow/selection.html +++ b/layout/reftests/text-overflow/selection.html @@ -23,7 +23,7 @@ html,body { .test { overflow:auto; - text-overflow:ellipsis; + text-overflow:ellipsis ellipsis; white-space:nowrap; width: 5em; position:relative; diff --git a/layout/reftests/text-overflow/single-value-ref.html b/layout/reftests/text-overflow/single-value-ref.html new file mode 100644 index 000000000000..85a751741121 --- /dev/null +++ b/layout/reftests/text-overflow/single-value-ref.html @@ -0,0 +1,105 @@ + + + +text-overflow: <single value>, scrolled and non-scrolled tests, (bug 684266) + + + + + + + +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ + +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ + +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+
+ + + + diff --git a/layout/reftests/text-overflow/single-value.html b/layout/reftests/text-overflow/single-value.html new file mode 100644 index 000000000000..d2e35baccb52 --- /dev/null +++ b/layout/reftests/text-overflow/single-value.html @@ -0,0 +1,98 @@ + + + +text-overflow: <single value>, scrolled and non-scrolled tests, (bug 684266) + + + + + + + +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ + +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ + +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+ +
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:auto)
+
A long line that does not break (overflow:scroll)
+
+ + + + diff --git a/layout/reftests/text-overflow/theme-overflow.html b/layout/reftests/text-overflow/theme-overflow.html index 80dcb3abbd9c..77f9019f5907 100644 --- a/layout/reftests/text-overflow/theme-overflow.html +++ b/layout/reftests/text-overflow/theme-overflow.html @@ -7,7 +7,7 @@ + + +
+The spaces should not have shadows! +
+ + diff --git a/layout/reftests/text-shadow/text-shadow-on-space-1.html b/layout/reftests/text-shadow/text-shadow-on-space-1.html new file mode 100644 index 000000000000..7433dad35ee6 --- /dev/null +++ b/layout/reftests/text-shadow/text-shadow-on-space-1.html @@ -0,0 +1,17 @@ + + + + + + +
+The spaces should not have shadows! +       +
+ + diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index f79729cedd78..b56d5442db63 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -8186,8 +8186,9 @@ CSSParserImpl::ParseTextOverflow(nsCSSValue& aValue) if (ParseVariant(right, VARIANT_KEYWORD | VARIANT_STRING, nsCSSProps::kTextOverflowKTable)) aValue.SetPairValue(left, right); - else - aValue.SetPairValue(left, left); + else { + aValue = left; + } return PR_TRUE; } diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index dbd9197247ad..9e7c29b53787 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -156,6 +156,8 @@ CSS_STATE_PSEUDO_CLASS(mozSuppressed, ":-moz-suppressed", CSS_STATE_PSEUDO_CLASS(mozLoading, ":-moz-loading", NS_EVENT_STATE_LOADING) CSS_STATE_PSEUDO_CLASS(mozTypeUnsupported, ":-moz-type-unsupported", NS_EVENT_STATE_TYPE_UNSUPPORTED) +CSS_STATE_PSEUDO_CLASS(mozHandlerClickToPlay, ":-moz-handler-clicktoplay", + NS_EVENT_STATE_TYPE_CLICK_TO_PLAY) CSS_STATE_PSEUDO_CLASS(mozHandlerDisabled, ":-moz-handler-disabled", NS_EVENT_STATE_HANDLER_DISABLED) CSS_STATE_PSEUDO_CLASS(mozHandlerBlocked, ":-moz-handler-blocked", diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index adbcb4dec80e..bd959b94b842 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -2486,33 +2486,35 @@ nsIDOMCSSValue* nsComputedDOMStyle::DoGetTextOverflow() { const nsStyleTextReset *style = GetStyleTextReset(); - nsROCSSPrimitiveValue *left = GetROCSSPrimitiveValue(); - if (style->mTextOverflow.mLeft.mType == NS_STYLE_TEXT_OVERFLOW_STRING) { + nsROCSSPrimitiveValue *first = GetROCSSPrimitiveValue(); + const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue(); + if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) { nsString str; - nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mLeft.mString, str); - left->SetString(str); + nsStyleUtil::AppendEscapedCSSString(side->mString, str); + first->SetString(str); } else { - left->SetIdent( - nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mLeft.mType, + first->SetIdent( + nsCSSProps::ValueToKeywordEnum(side->mType, nsCSSProps::kTextOverflowKTable)); } - if (style->mTextOverflow.mLeft == style->mTextOverflow.mRight) { - return left; + side = style->mTextOverflow.GetSecondValue(); + if (!side) { + return first; } - nsROCSSPrimitiveValue *right = GetROCSSPrimitiveValue(); - if (style->mTextOverflow.mRight.mType == NS_STYLE_TEXT_OVERFLOW_STRING) { + nsROCSSPrimitiveValue *second = GetROCSSPrimitiveValue(); + if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) { nsString str; - nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mRight.mString, str); - right->SetString(str); + nsStyleUtil::AppendEscapedCSSString(side->mString, str); + second->SetString(str); } else { - right->SetIdent( - nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mRight.mType, + second->SetIdent( + nsCSSProps::ValueToKeywordEnum(side->mType, nsCSSProps::kTextOverflowKTable)); } nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE); - valueList->AppendCSSValue(left); - valueList->AppendCSSValue(right); + valueList->AppendCSSValue(first); + valueList->AppendCSSValue(second); return valueList; } diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 1b4a89758379..5c9fbfee409a 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -3494,7 +3494,7 @@ nsRuleNode::ComputeTextResetData(void* aStartStruct, text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID); } - // text-overflow: pair(enum|string), inherit, initial + // text-overflow: enum, string, pair(enum|string), inherit, initial const nsCSSValue* textOverflowValue = aRuleData->ValueForTextOverflow(); if (eCSSUnit_Initial == textOverflowValue->GetUnit()) { @@ -3502,7 +3502,26 @@ nsRuleNode::ComputeTextResetData(void* aStartStruct, } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) { canStoreInRuleTree = PR_FALSE; text->mTextOverflow = parentText->mTextOverflow; + } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) { + // A single enumerated value. + SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType, + canStoreInRuleTree, + SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType, + NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0); + text->mTextOverflow.mRight.mString.Truncate(); + text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP; + text->mTextOverflow.mLeft.mString.Truncate(); + text->mTextOverflow.mLogicalDirections = true; + } else if (eCSSUnit_String == textOverflowValue->GetUnit()) { + // A single string value. + text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING; + textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString); + text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP; + text->mTextOverflow.mLeft.mString.Truncate(); + text->mTextOverflow.mLogicalDirections = true; } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) { + // Two values were specified. + text->mTextOverflow.mLogicalDirections = false; const nsCSSValuePair& textOverflowValue = aRuleData->ValueForTextOverflow()->GetPairValue(); diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 69d25716e1d0..928ca3bc79b5 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1148,6 +1148,7 @@ struct nsStyleTextOverflowSide { }; struct nsStyleTextOverflow { + nsStyleTextOverflow() : mLogicalDirections(true) {} bool operator==(const nsStyleTextOverflow& aOther) const { return mLeft == aOther.mLeft && mRight == aOther.mRight; } @@ -1155,8 +1156,35 @@ struct nsStyleTextOverflow { return !(*this == aOther); } - nsStyleTextOverflowSide mLeft; - nsStyleTextOverflowSide mRight; + // Returns the value to apply on the left side. + const nsStyleTextOverflowSide& GetLeft(PRUint8 aDirection) const { + NS_ASSERTION(aDirection == NS_STYLE_DIRECTION_LTR || + aDirection == NS_STYLE_DIRECTION_RTL, "bad direction"); + return !mLogicalDirections || aDirection == NS_STYLE_DIRECTION_LTR ? + mLeft : mRight; + } + + // Returns the value to apply on the right side. + const nsStyleTextOverflowSide& GetRight(PRUint8 aDirection) const { + NS_ASSERTION(aDirection == NS_STYLE_DIRECTION_LTR || + aDirection == NS_STYLE_DIRECTION_RTL, "bad direction"); + return !mLogicalDirections || aDirection == NS_STYLE_DIRECTION_LTR ? + mRight : mLeft; + } + + // Returns the first value that was specified. + const nsStyleTextOverflowSide* GetFirstValue() const { + return mLogicalDirections ? &mRight : &mLeft; + } + + // Returns the second value, or null if there was only one value specified. + const nsStyleTextOverflowSide* GetSecondValue() const { + return mLogicalDirections ? nsnull : &mRight; + } + + nsStyleTextOverflowSide mLeft; // start side when mLogicalDirections is true + nsStyleTextOverflowSide mRight; // end side when mLogicalDirections is true + bool mLogicalDirections; // true when only one value was specified }; struct nsStyleTextReset { diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 509806fcbc6b..b9123bb60af1 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -2568,8 +2568,8 @@ var gCSSProperties = { domProp: "textOverflow", inherited: false, type: CSS_TYPE_LONGHAND, - initial_values: [ "clip", "clip clip" ], - other_values: [ "ellipsis", '""', "''", '"hello"', 'clip ellipsis', 'clip ""', '"hello" ""', '"" ellipsis' ], + initial_values: [ "clip" ], + other_values: [ "ellipsis", '""', "''", '"hello"', 'clip clip', 'ellipsis ellipsis', 'clip ellipsis', 'clip ""', '"hello" ""', '"" ellipsis' ], invalid_values: [ "none", "auto", '"hello" inherit', 'inherit "hello"', 'clip initial', 'initial clip', 'initial inherit', 'inherit initial', 'inherit none'] }, "text-shadow": { diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index e18eaf0def51..3a86e2738324 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1074,7 +1074,7 @@ nsTableFrame::GetChildLists(nsTArray* aLists) const nsRect nsDisplayTableItem::GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } bool diff --git a/memory/mozalloc/mozalloc.h b/memory/mozalloc/mozalloc.h index dfd79ad11a7a..b59b25db17cd 100644 --- a/memory/mozalloc/mozalloc.h +++ b/memory/mozalloc/mozalloc.h @@ -53,6 +53,7 @@ #include "xpcom-config.h" #define MOZALLOC_HAVE_XMALLOC +#define MOZALLOC_HAVE_MALLOC_USABLE_SIZE #if defined(MOZALLOC_EXPORT) /* do nothing: it's been defined to __declspec(dllexport) by diff --git a/mfbt/Util.h b/mfbt/Util.h index 5f7d8d27a66d..b50cafc16d73 100644 --- a/mfbt/Util.h +++ b/mfbt/Util.h @@ -177,15 +177,12 @@ struct DebugOnly T& operator->() { return value; } - bool operator<(const T& other) { return value < other; } - #else DebugOnly() {} DebugOnly(const T&) {} DebugOnly& operator=(const T&) { return *this; } void operator++(int) {} void operator--(int) {} - bool operator<(const T&) { return false; } #endif /* diff --git a/mobile/app/mobile.js b/mobile/app/mobile.js index 9260eb17fd07..a0c06c704702 100644 --- a/mobile/app/mobile.js +++ b/mobile/app/mobile.js @@ -437,10 +437,14 @@ pref("browser.ui.touch.weight.visited", 120); // percentage // plugins #if MOZ_PLATFORM_MAEMO == 6 pref("plugin.disable", false); +pref("dom.ipc.plugins.enabled", true); +#elifdef ANDROID +pref("plugin.disable", false); +pref("dom.ipc.plugins.enabled", false); #else pref("plugin.disable", true); -#endif pref("dom.ipc.plugins.enabled", true); +#endif // process priority // higher values give content process less CPU time diff --git a/mobile/chrome/content/bindings.xml b/mobile/chrome/content/bindings.xml index f46175255223..056994032f27 100644 --- a/mobile/chrome/content/bindings.xml +++ b/mobile/chrome/content/bindings.xml @@ -1384,28 +1384,57 @@ + + + + + + + + + + + @@ -1417,22 +1446,23 @@ let engine = this._getWeaveEngine(); - // Only load items if the tabs engine is ready. In case - // sync fails, WeaveGlue will show an error dialog. If sync - // succeeds but has no data to display, a message is presented - // in the panel (see "message" attribute). - if (engine) { - let items = this._getRemoteTabs(engine); + // Only load items if the tabs engine is ready + if (!engine) + return false; - if (items.length) { - children.setItems(items.map(this.createItem)); - } else { - let bundle = Services.strings.createBundle("chrome://browser/locale/sync.properties"); - this.setAttribute("message", bundle.GetStringFromName("sync.message.notabs")); - } + // In case sync fails, WeaveGlue will show an error dialog + let items = this._getRemoteTabs(engine); + + // If sync succeeds but has no data to display, a message + // is presented in the panel (see "message" attribute). + if (items.length) { + children.setItems(items.map(this.createItem)); + } else { + let bundle = Services.strings.createBundle("chrome://browser/locale/sync.properties"); + this.setAttribute("message", bundle.GetStringFromName("sync.message.notabs")); } - this.removeAttribute("loading"); + return true; ]]> @@ -1447,7 +1477,7 @@ // Return null if the Weave isn't ready if (document.getElementById("cmd_remoteTabs").getAttribute("disabled") == "true") return null; - if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) + if (!Services.prefs.prefHasUserValue("services.sync.username")) { return null; return Weave.Engines.get("tabs"); diff --git a/mobile/chrome/content/bindings/arrowbox.xml b/mobile/chrome/content/bindings/arrowbox.xml index b3c63954f8f4..24582601e8c8 100644 --- a/mobile/chrome/content/bindings/arrowbox.xml +++ b/mobile/chrome/content/bindings/arrowbox.xml @@ -166,6 +166,7 @@ } this.anchorNode = aAnchorNode; + this.position = aPosition; let anchorRect = aAnchorNode.getBoundingClientRect(); let popupRect = new Rect(0,0,0,0); @@ -299,7 +300,7 @@ let arrowbox = document.getAnonymousElementByAttribute(self, "anonid", "arrowbox"); arrowbox.style.marginLeft = "0px"; arrowbox.style.marginTop = "0px"; - self.anchorTo(self.anchorNode); + self.anchorTo(self.anchorNode, self.position); break; } } diff --git a/mobile/chrome/content/browser-ui.js b/mobile/chrome/content/browser-ui.js index f8c833845990..16c6423ee3ae 100644 --- a/mobile/chrome/content/browser-ui.js +++ b/mobile/chrome/content/browser-ui.js @@ -1230,7 +1230,7 @@ var BrowserUI = { AwesomeScreen.activePanel = HistoryList; break; case "cmd_remoteTabs": - if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) { + if (!Services.prefs.prefHasUserValue("services.sync.username")) { // We have to set activePanel before showing sync's dialog // to make the sure the dialog stacking is correct. AwesomeScreen.activePanel = RemoteTabsList; diff --git a/mobile/chrome/content/browser.js b/mobile/chrome/content/browser.js index 2b77c7cbe9f8..b4958b17bc7f 100644 --- a/mobile/chrome/content/browser.js +++ b/mobile/chrome/content/browser.js @@ -400,6 +400,7 @@ var Browser = { messageManager.addMessageListener("Browser:CertException", this); messageManager.addMessageListener("Browser:BlockedSite", this); messageManager.addMessageListener("Browser:ErrorPage", this); + messageManager.addMessageListener("Browser:PluginClickToPlayClicked", this); // Broadcast a UIReady message so add-ons know we are finished with startup let event = document.createEvent("Events"); @@ -498,6 +499,7 @@ var Browser = { messageManager.removeMessageListener("Browser:CertException", this); messageManager.removeMessageListener("Browser:BlockedSite", this); messageManager.removeMessageListener("Browser:ErrorPage", this); + messageManager.removeMessageListener("Browser:PluginClickToPlayClicked", this); var os = Services.obs; os.removeObserver(XPInstallObserver, "addon-install-blocked"); @@ -1275,6 +1277,31 @@ var Browser = { case "Browser:ErrorPage": this._handleErrorPage(aMessage); break; + case "Browser:PluginClickToPlayClicked": { + // Save off session history + let parent = browser.parentNode; + let data = browser.__SS_data; + if (data.entries.length == 0) + return; + + // Remove the browser from the DOM, effectively killing it's content + parent.removeChild(browser); + + // Re-create the browser as non-remote, so plugins work + browser.setAttribute("remote", "false"); + parent.appendChild(browser); + + // Reload the content using session history + browser.__SS_data = data; + let json = { + uri: data.entries[data.index - 1].url, + flags: null, + entries: data.entries, + index: data.index + }; + browser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", json); + break; + } } } }; diff --git a/mobile/chrome/content/content.js b/mobile/chrome/content/content.js index 53d986ad0f25..b894f5c0fe60 100644 --- a/mobile/chrome/content/content.js +++ b/mobile/chrome/content/content.js @@ -1570,3 +1570,53 @@ var SelectionHandler = { }; SelectionHandler.init(); + + +var PluginHandler = { + init: function() { + addEventListener("PluginClickToPlay", this, false); + }, + + addLinkClickCallback: function (linkNode, callbackName /*callbackArgs...*/) { + // XXX just doing (callback)(arg) was giving a same-origin error. bug? + let self = this; + let callbackArgs = Array.prototype.slice.call(arguments).slice(2); + linkNode.addEventListener("click", + function(evt) { + if (!evt.isTrusted) + return; + evt.preventDefault(); + if (callbackArgs.length == 0) + callbackArgs = [ evt ]; + (self[callbackName]).apply(self, callbackArgs); + }, + true); + + linkNode.addEventListener("keydown", + function(evt) { + if (!evt.isTrusted) + return; + if (evt.keyCode == evt.DOM_VK_RETURN) { + evt.preventDefault(); + if (callbackArgs.length == 0) + callbackArgs = [ evt ]; + evt.preventDefault(); + (self[callbackName]).apply(self, callbackArgs); + } + }, + true); + }, + + handleEvent : function(event) { + if (event.type != "PluginClickToPlay") + return; + let plugin = event.target; + PluginHandler.addLinkClickCallback(plugin, "reloadToEnablePlugin"); + }, + + reloadToEnablePlugin: function() { + sendAsyncMessage("Browser:PluginClickToPlayClicked", { }); + } +}; + +PluginHandler.init(); diff --git a/mobile/chrome/content/sanitize.js b/mobile/chrome/content/sanitize.js index 82f6284e6350..e3201b37db86 100644 --- a/mobile/chrome/content/sanitize.js +++ b/mobile/chrome/content/sanitize.js @@ -101,7 +101,7 @@ Sanitizer.prototype = { get canClear() { - return (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED); + return (Services.prefs.prefHasUserValue("services.sync.username")); } }, diff --git a/mobile/chrome/content/sync.js b/mobile/chrome/content/sync.js index d71fb9d0fb4e..8a124407bfdf 100644 --- a/mobile/chrome/content/sync.js +++ b/mobile/chrome/content/sync.js @@ -53,7 +53,7 @@ let WeaveGlue = { this.setupData = { account: "", password: "" , synckey: "", serverURL: "" }; // Generating keypairs is expensive on mobile, so disable it - if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) { + if (Services.prefs.prefHasUserValue("services.sync.username")) { // Put the settings UI into a state of "connecting..." if we are going to auto-connect this._elements.connect.firstChild.disabled = true; this._elements.connect.setAttribute("title", this._bundle.GetStringFromName("connecting.label")); @@ -259,17 +259,11 @@ let WeaveGlue = { tryConnect: function login() { // If Sync is not configured, simply show the setup dialog - if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) { + if (!Services.prefs.prefHasUserValue("services.sync.username")) { this.open(); return; } - // If user is already logged-in, try to connect straight away - if (Weave.Service.isLoggedIn) { - this.connect(); - return; - } - // No setup data, do nothing if (!this.setupData) return; @@ -403,12 +397,12 @@ let WeaveGlue = { let disconnect = this._elements.disconnect; let sync = this._elements.sync; - let loggedIn = Weave.Service.isLoggedIn; + let isConfigured = Services.prefs.prefHasUserValue("services.sync.username"); - connect.collapsed = loggedIn; - connected.collapsed = !loggedIn; + connect.collapsed = isConfigured; + connected.collapsed = !isConfigured; - if (!loggedIn) { + if (!isConfigured) { connect.setAttribute("title", this._bundle.GetStringFromName("notconnected.label")); connect.firstChild.disabled = false; details.checked = false; @@ -449,7 +443,7 @@ let WeaveGlue = { // Show what went wrong with login if necessary if (aTopic == "weave:service:login:error") { - if (Weave.Status.login == "service.master_password_locked") + if (Weave.Status.login == Weave.MASTER_PASSWORD_LOCKED) Weave.Service.logout(); else connect.setAttribute("desc", Weave.Utils.getErrorString(Weave.Status.login)); diff --git a/mobile/themes/core/honeycomb/browser.css b/mobile/themes/core/honeycomb/browser.css index 0fbf0af68c37..0a61eace65a0 100644 --- a/mobile/themes/core/honeycomb/browser.css +++ b/mobile/themes/core/honeycomb/browser.css @@ -813,8 +813,14 @@ placeitem[ui="manage"] > .bookmark-manage textbox[anonid="uri"]:-moz-locale-dir( #awesome-header .panel-row-button { -moz-padding-end: 0px; - padding: @padding_normal@ !important; - border: none !important; + padding: @padding_large@ !important; + height: @touch_row@; + margin: 0px; + border: 0px; +} + +#awesome-header .panel-row-button .toolbarbutton-text { + font-size: @font_xxtiny@ !important; } #awesome-header { @@ -1294,9 +1300,21 @@ pageaction > vbox { /* Override richlistbox and richlistitem styles */ #context-header { - background-color: transparent; - border-bottom: @border_width_xlarge@ solid @color_divider_border@; - margin: @margin_large@ @margin_large@ 0px; + margin: 0px; + padding: 0px @padding_xlarge@; + min-height: @touch_row@ +} + +#context-header > label { + border-bottom: @border_width_xxlarge@ solid @color_divider_border@; + padding: @padding_xlarge@ @padding_large@; + color: @color_text_default@; + font-size: @font_snormal@; + margin: 0px; +} + +#context-header > label[value=""] { + visibility: collapse; } #context-commands > scrollbox { @@ -1306,18 +1324,21 @@ pageaction > vbox { .action-button, .context-command { -moz-box-align: center; - padding: 0px @padding_large@; + padding: 0px @padding_xlarge@; border: none; border-top: @border_width_tiny@ solid transparent; + font-size: @font_snormal@; } .action-button > label, .context-command > label { min-height: @touch_row@; + padding: 0px @padding_large@; padding-top: -moz-calc(@touch_row@ / 2 - 0.75em); -moz-box-align: center; border-bottom: @border_width_tiny@ solid @color_button_border@; -moz-box-flex: 1; + margin: 0px; margin-bottom: -@border_width_tiny@; } @@ -1406,17 +1427,12 @@ pageaction:not([image]) > hbox >.pageaction-image { } #share-title, -#bookmark-popup-title, -#context-hint { +#bookmark-popup-title { color: @color_text_default@; font-size: @font_small@; padding: @padding_small@; } -#context-hint[value=""] { - visibility: collapse; -} - #search-engines-list > .action-button > .button-box > .button-icon { width: 32px; height: 32px; @@ -1699,6 +1715,7 @@ setting[type="bool"]:hover:active .setting-input > checkbox[checked="true"] > .c border-top: @border_width_tiny@ solid @color_button_border@; border-bottom: none; background-color: transparent; + font-size: @font_snormal@ !important; } #appmenu-popup-sitecommands { @@ -1708,7 +1725,7 @@ setting[type="bool"]:hover:active .setting-input > checkbox[checked="true"] > .c } #appmenu-popup-sitecommands > .appmenu-pageaction { - font-size: @font_tiny@; + font-size: @font_xxtiny@; display: inline-block; min-height: -moz-calc(1.5 * @touch_button_xlarge@) !important; min-width: -moz-calc(1.5 * @touch_button_xlarge@) !important; diff --git a/mobile/themes/core/honeycomb/platform.css b/mobile/themes/core/honeycomb/platform.css index 106bfadfb478..b81b653164cd 100644 --- a/mobile/themes/core/honeycomb/platform.css +++ b/mobile/themes/core/honeycomb/platform.css @@ -623,17 +623,20 @@ dialog { .prompt-message { -moz-box-pack: center; font-size: @font_snormal@; - padding-bottom: @padding_normal@; - min-height: 4em; + padding: @padding_normal@ @padding_large@; + min-height: @touch_row@; } .prompt-header { border-bottom: @border_width_tiny@ solid @color_button_border@; - margin: @margin_normal@ @margin_large@ 0px !important; + margin: 0px @margin_large@ !important; } .prompt-title { font-size: @font_snormal@; + min-height: @touch_row@; + padding: @padding_xlarge@ @padding_large@; + margin: 0px; } /* Authentication dialogs do not have a title */ @@ -644,8 +647,8 @@ dialog { .prompt-line { background-color: transparent; - border-bottom: @border_width_xlarge@ solid @color_divider_border@; - height: @padding_normal@ !important; + border-bottom: @border_width_xxlarge@ solid @color_divider_border@; + height: @border_width_xxlarge@ !important; } .prompt-buttons { diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index 2e51260ffc30..45e311567baa 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -85,8 +85,6 @@ using namespace mozilla; // ShortIdleTimeoutSeconds of idle time. Smaller pools use LongIdleTimeoutSeconds for a // timeout period. -#define MAX_NON_PRIORITY_REQUESTS 150 - #define HighThreadThreshold MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY #define LongIdleTimeoutSeconds 300 // for threads 1 -> HighThreadThreshold #define ShortIdleTimeoutSeconds 60 // for threads HighThreadThreshold+1 -> MAX_RESOLVER_THREADS diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h index 6cf9587d3377..b9e83ad55371 100644 --- a/netwerk/dns/nsHostResolver.h +++ b/netwerk/dns/nsHostResolver.h @@ -71,8 +71,20 @@ class nsResolveHostCallback; return n; \ } +#ifdef ANDROID +// See bug 687367 - pre gingerbread android has race conditions involving stdio. +// stdio is used as part of the getaddrinfo() implementation. In order to reduce +// that race window limit ourselves to 1 lookup at a time on android. + +#define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 0 +#define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 1 +#define MAX_NON_PRIORITY_REQUESTS 0 +#else #define MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY 3 #define MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY 5 +#define MAX_NON_PRIORITY_REQUESTS 150 +#endif + #define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \ MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY) diff --git a/netwerk/test/unit/test_MIME_params.js b/netwerk/test/unit/test_MIME_params.js index a75b23b89723..b444d58f2282 100644 --- a/netwerk/test/unit/test_MIME_params.js +++ b/netwerk/test/unit/test_MIME_params.js @@ -1,152 +1,256 @@ /** - * Test for bug 588781: ensure that for a MIME parameter with both "filename" - * and "filename*" we pick the RFC2231/5987 encoded form + * Tests for parsing header fields using the syntax used in + * Content-Disposition and Content-Type * - * Note: RFC 5987 drops support for continuations (foo*0, foo*1*, etc.). - * - * See also + * See also https://bugzilla.mozilla.org/show_bug.cgi?id=609667 */ const Cr = Components.results; +var BS = '\\'; +var DQUOTE = '"'; + // Test array: -// - element 0: "Content-Disposition" header to test for 'filename' parameter -// - element 1: correct value returned under RFC 2231 (email) -// - element 2: correct value returned under RFC 5987 (HTTP) +// - element 0: "Content-Disposition" header to test +// under RFC 2231 (email): +// - element 1: correct value returned for disposition-type (empty param name) +// - element 2: correct value for filename returned +// under RFC 5987 (HTTP): +// (note: 5987-mode not yet in use, see bug 601933) +// - element 3: correct value returned for disposition-type (empty param name) +// - element 4: correct value for filename returned +// +// 3 and 4 may be left out if they are identical var tests = [ // No filename parameter: return nothing - ["attachment;", - Cr.NS_ERROR_INVALID_ARG, Cr.NS_ERROR_INVALID_ARG], + ["attachment;", + "attachment", Cr.NS_ERROR_INVALID_ARG], // basic ["attachment; filename=basic", - "basic", "basic"], + "attachment", "basic"], // extended ["attachment; filename*=UTF-8''extended", - "extended", "extended"], + "attachment", "extended"], - // prefer extended to basic + // prefer extended to basic (bug 588781) ["attachment; filename=basic; filename*=UTF-8''extended", - "extended", "extended"], + "attachment", "extended"], - // prefer extended to basic + // prefer extended to basic (bug 588781) ["attachment; filename*=UTF-8''extended; filename=basic", - "extended", "extended"], + "attachment", "extended"], - // use first basic value + // use first basic value (invalid; error recovery) ["attachment; filename=first; filename=wrong", - "first", "first"], + "attachment", "first"], // old school bad HTTP servers: missing 'attachment' or 'inline' + // (invalid; error recovery) ["filename=old", - "old", "old"], + "filename=old", "old"], ["attachment; filename*=UTF-8''extended", - "extended", "extended"], + "attachment", "extended"], + // continuations not part of RFC 5987 (bug 610054) ["attachment; filename*0=foo; filename*1=bar", - "foobar", Cr.NS_ERROR_INVALID_ARG], + "attachment", "foobar", + "attachment", Cr.NS_ERROR_INVALID_ARG], - // Return first continuation + // Return first continuation (invalid; error recovery) ["attachment; filename*0=first; filename*0=wrong; filename=basic", - "first", "basic"], + "attachment", "first", + "attachment", "basic"], - // Only use correctly ordered continuations + // Only use correctly ordered continuations (invalid; error recovery) ["attachment; filename*0=first; filename*1=second; filename*0=wrong", - "firstsecond", Cr.NS_ERROR_INVALID_ARG], + "attachment", "firstsecond", + "attachment", Cr.NS_ERROR_INVALID_ARG], // prefer continuation to basic (unless RFC 5987) ["attachment; filename=basic; filename*0=foo; filename*1=bar", - "foobar", "basic"], + "attachment", "foobar", + "attachment", "basic"], // Prefer extended to basic and/or (broken or not) continuation + // (invalid; error recovery) ["attachment; filename=basic; filename*0=first; filename*0=wrong; filename*=UTF-8''extended", - "extended", "extended"], + "attachment", "extended"], // RFC 2231 not clear on correct outcome: we prefer non-continued extended + // (invalid; error recovery) ["attachment; filename=basic; filename*=UTF-8''extended; filename*0=foo; filename*1=bar", - "extended", "extended"], + "attachment", "extended"], // Gaps should result in returning only value until gap hit + // (invalid; error recovery) ["attachment; filename*0=foo; filename*2=bar", - "foo", Cr.NS_ERROR_INVALID_ARG], + "attachment", "foo", + "attachment", Cr.NS_ERROR_INVALID_ARG], - // Don't allow leading 0's (*01) + // Don't allow leading 0's (*01) (invalid; error recovery) ["attachment; filename*0=foo; filename*01=bar", - "foo", Cr.NS_ERROR_INVALID_ARG], + "attachment", "foo", + "attachment", Cr.NS_ERROR_INVALID_ARG], // continuations should prevail over non-extended (unless RFC 5987) ["attachment; filename=basic; filename*0*=UTF-8''multi\r\n" + " filename*1=line\r\n" + " filename*2*=%20extended", - "multiline extended", "basic"], + "attachment", "multiline extended", + "attachment", "basic"], // Gaps should result in returning only value until gap hit + // (invalid; error recovery) ["attachment; filename=basic; filename*0*=UTF-8''multi\r\n" + " filename*1=line\r\n" + " filename*3*=%20extended", - "multiline", "basic"], + "attachment", "multiline", + "attachment", "basic"], // First series, only please, and don't slurp up higher elements (*2 in this - // case) from later series into earlier one + // case) from later series into earlier one (invalid; error recovery) ["attachment; filename=basic; filename*0*=UTF-8''multi\r\n" + " filename*1=line\r\n" + " filename*0*=UTF-8''wrong\r\n" + " filename*1=bad\r\n" + " filename*2=evil", - "multiline", "basic"], + "attachment", "multiline", + "attachment", "basic"], // RFC 2231 not clear on correct outcome: we prefer non-continued extended + // (invalid; error recovery) ["attachment; filename=basic; filename*0=UTF-8''multi\r\n" + " filename*=UTF-8''extended\r\n" + " filename*1=line\r\n" + " filename*2*=%20extended", - "extended", "extended"], + "attachment", "extended"], // sneaky: if unescaped, make sure we leave UTF-8'' in value ["attachment; filename*0=UTF-8''unescaped\r\n" + " filename*1*=%20so%20includes%20UTF-8''%20in%20value", - "UTF-8''unescaped so includes UTF-8'' in value", Cr.NS_ERROR_INVALID_ARG], + "attachment", "UTF-8''unescaped so includes UTF-8'' in value", + "attachment", Cr.NS_ERROR_INVALID_ARG], // sneaky: if unescaped, make sure we leave UTF-8'' in value ["attachment; filename=basic; filename*0=UTF-8''unescaped\r\n" + " filename*1*=%20so%20includes%20UTF-8''%20in%20value", - "UTF-8''unescaped so includes UTF-8'' in value", "basic"], + "attachment", "UTF-8''unescaped so includes UTF-8'' in value", + "attachment", "basic"], // Prefer basic over invalid continuation + // (invalid; error recovery) ["attachment; filename=basic; filename*1=multi\r\n" + " filename*2=line\r\n" + " filename*3*=%20extended", - "basic", "basic"], + "attachment", "basic"], // support digits over 10 ["attachment; filename=basic; filename*0*=UTF-8''0\r\n" + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5\r\n" + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a\r\n" + " filename*11=b; filename*12=c;filename*13=d;filename*14=e;filename*15=f\r\n", - "0123456789abcdef", "basic"], + "attachment", "0123456789abcdef", + "attachment", "basic"], // support digits over 10 (check ordering) ["attachment; filename=basic; filename*0*=UTF-8''0\r\n" + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5\r\n" + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a\r\n" + " filename*11=b; filename*12=c;filename*13=d;filename*15=f;filename*14=e\r\n", - "0123456789abcd" /* should see the 'f', see bug 588414 */, "basic"], + "attachment", "0123456789abcd" /* should see the 'f', see bug 588414 */, + "attachment", "basic"], // support digits over 10 (detect gaps) ["attachment; filename=basic; filename*0*=UTF-8''0\r\n" + " filename*1=1; filename*2=2;filename*3=3;filename*4=4;filename*5=5\r\n" + " filename*6=6; filename*7=7;filename*8=8;filename*9=9;filename*10=a\r\n" + " filename*11=b; filename*12=c;filename*14=e\r\n", - "0123456789abc", "basic"], + "attachment", "0123456789abc", + "attachment", "basic"], // return nothing: invalid + // (invalid; error recovery) ["attachment; filename*1=multi\r\n" + " filename*2=line\r\n" + " filename*3*=%20extended", - Cr.NS_ERROR_INVALID_ARG, Cr.NS_ERROR_INVALID_ARG], + "attachment", Cr.NS_ERROR_INVALID_ARG], + + // Bug 272541: Empty disposition type treated as "attachment" + // sanity check + ["attachment; filename=foo.html", + "attachment", "foo.html", + "attachment", "foo.html"], + + // the actual bug + ["; filename=foo.html", + Cr.NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY, "foo.html", + Cr.NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY, "foo.html"], + + // regression check, but see bug 671204 + ["filename=foo.html", + "filename=foo.html", "foo.html", + "filename=foo.html", "foo.html"], + + // Bug 419157: ensure that a MIME parameter with no charset information + // fallbacks to Latin-1 + + ["attachment;filename=IT839\x04\xB5(m8)2.pdf;", + "attachment", "IT839\u0004\u00b5(m8)2.pdf"], + + // Bug 588389: unescaping backslashes in quoted string parameters + + // '\"', should be parsed as '"' + ["attachment; filename=" + DQUOTE + (BS + DQUOTE) + DQUOTE, + "attachment", DQUOTE], + + // 'a\"b', should be parsed as 'a"b' + ["attachment; filename=" + DQUOTE + 'a' + (BS + DQUOTE) + 'b' + DQUOTE, + "attachment", "a" + DQUOTE + "b"], + + // '\x', should be parsed as 'x' + ["attachment; filename=" + DQUOTE + (BS + "x") + DQUOTE, + "attachment", "x"], + + // test empty param (quoted-string) + ["attachment; filename=" + DQUOTE + DQUOTE, + "attachment", ""], + + // test empty param + ["attachment; filename=", + "attachment", ""], + + // Bug 651185: double quotes around 2231/5987 encoded param + + // sanity check + ["attachment; filename*=utf-8''%41", + "attachment", "A"], + + // the actual bug + ["attachment; filename*=" + DQUOTE + "utf-8''%41" + DQUOTE, + "attachment", Cr.NS_ERROR_INVALID_ARG], + + // Bug 670333: Content-Disposition parser does not require presence of "=" + // in params + + // sanity check + ["attachment; filename*=UTF-8''foo-%41.html", + "attachment", "foo-A.html"], + + // the actual bug + ["attachment; filename *=UTF-8''foo-%41.html", + "attachment", Cr.NS_ERROR_INVALID_ARG], + + // the actual bug, without 2231/5987 encoding + ["attachment; filename X", + "attachment", Cr.NS_ERROR_INVALID_ARG], + + // sanity check with WS on both sides + ["attachment; filename = foo-A.html", + "attachment", "foo-A.html"], ]; function do_tests(whichRFC) @@ -157,21 +261,51 @@ function do_tests(whichRFC) var unused = { value : null }; for (var i = 0; i < tests.length; ++i) { - dump("Testing " + tests[i] + "\n"); + dump("Testing #" + i + ": " + tests[i] + "\n"); + + // check disposition type + var expectedDt = tests[i].length == 3 || whichRFC == 0 ? tests[i][1] : tests[i][3]; + try { var result; - if (whichRFC == 1) - result = mhp.getParameter(tests[i][0], "filename", "UTF-8", true, unused); + + if (whichRFC == 0) + result = mhp.getParameter(tests[i][0], "", "UTF-8", true, unused); else - result = mhp.getParameter5987(tests[i][0], "filename", "UTF-8", true, unused); - do_check_eq(result, tests[i][whichRFC]); + result = mhp.getParameter5987(tests[i][0], "", "UTF-8", true, unused); + + do_check_eq(result, expectedDt); } catch (e) { // Tests can also succeed by expecting to fail with given error code if (e.result) { // Allow following tests to run by catching exception from do_check_eq() try { - do_check_eq(e.result, tests[i][whichRFC]); + do_check_eq(e.result, expectedDt); + } catch(e) {} + } + continue; + } + + // check filename parameter + var expectedFn = tests[i].length == 3 || whichRFC == 0 ? tests[i][2] : tests[i][4]; + + try { + var result; + + if (whichRFC == 0) + result = mhp.getParameter(tests[i][0], "filename", "UTF-8", true, unused); + else + result = mhp.getParameter5987(tests[i][0], "filename", "UTF-8", true, unused); + + do_check_eq(result, expectedFn); + } + catch (e) { + // Tests can also succeed by expecting to fail with given error code + if (e.result) { + // Allow following tests to run by catching exception from do_check_eq() + try { + do_check_eq(e.result, expectedFn); } catch(e) {} } continue; @@ -182,9 +316,9 @@ function do_tests(whichRFC) function run_test() { // Test RFC 2231 - do_tests(1); + do_tests(0); // Test RFC 5987 - do_tests(2); + do_tests(1); } diff --git a/netwerk/test/unit/test_bug272541.js b/netwerk/test/unit/test_bug272541.js deleted file mode 100644 index 666f81ed5cdb..000000000000 --- a/netwerk/test/unit/test_bug272541.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Test for bug 272541: - Empty disposition type treated as "attachment" - */ - -const Cr = Components.results - -var tests = [ - [ /* the actual bug */ - "; filename=foo.html", - Cr.NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY], - [ /* regression check, but see bug 671204 */ - "filename=foo.html", - "filename=foo.html"], - [ /* sanity check */ - "attachment; filename=foo.html", - "attachment"], - ]; - -function run_test() { - - var mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"] - .getService(Components.interfaces.nsIMIMEHeaderParam); - - var unused = { value : null }; - - for (var i = 0; i < tests.length; ++i) { - dump("Testing " + tests[i] + "\n"); - try { - do_check_eq(mhp.getParameter(tests[i][0], "", "UTF-8", true, unused), - tests[i][1]); - } - catch (e) { - do_check_eq(e.result, tests[i][1]); - } - } -} - diff --git a/netwerk/test/unit/test_bug419157.js b/netwerk/test/unit/test_bug419157.js deleted file mode 100644 index a68bd7422a4f..000000000000 --- a/netwerk/test/unit/test_bug419157.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Test for bug 419157: ensure that a MIME parameter with no charset information - * fallbacks to Latin-1 - */ -const Cc = Components.classes; -const Ci = Components.interfaces; - -const header = "Content-Disposition: attachment;filename=IT839\x04\xB5(m8)2.pdf;"; -const expected = "IT839\u0004\u00b5(m8)2.pdf"; - -function run_test() -{ - var mhp = Cc["@mozilla.org/network/mime-hdrparam;1"]. - getService(Ci.nsIMIMEHeaderParam); - - var unused = { value : null }; - var result = null; - - try { - result = mhp.getParameter(header, "filename", "UTF-8", true, unused); - } catch (e) {} - - do_check_eq(result, expected); -} diff --git a/netwerk/test/unit/test_bug588389.js b/netwerk/test/unit/test_bug588389.js deleted file mode 100644 index 58f6cfefffc8..000000000000 --- a/netwerk/test/unit/test_bug588389.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Test for bug 588389: unescaping backslashes in quoted string parameters - */ - -var BS = '\\'; -var DQUOTE = '"'; - -var reference = [ - [ // '\"', should be parsed as '"' - "Content-Disposition: attachment; foobar=" + DQUOTE + (BS + DQUOTE) + DQUOTE, - DQUOTE], - [ // 'a\"b', should be parsed as 'a"b' - "Content-Disposition: attachment; foobar=" + DQUOTE + 'a' + (BS + DQUOTE) + 'b' + DQUOTE, - 'a' + DQUOTE + 'b'], - [ // '\x', should be parsed as 'x' - "Content-Disposition: attachment; foobar=" + DQUOTE + (BS + "x") + DQUOTE, - "x"], - [ // test empty param (quoted-string) - "Content-Disposition: attachment; foobar=" + DQUOTE + DQUOTE, - ""], - [ // test empty param - "Content-Disposition: attachment; foobar=", - ""], - ]; - -function run_test() { - - var mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"] - .getService(Components.interfaces.nsIMIMEHeaderParam); - - var unused = { value : null }; - - for (var i = 0; i < reference.length; ++i) { - dump("Testing " + reference[i] + "\n"); - do_check_eq(mhp.getParameter(reference[i][0], "foobar", "UTF-8", true, unused), - reference[i][1]); - } -} - diff --git a/netwerk/test/unit/test_bug651185.js b/netwerk/test/unit/test_bug651185.js deleted file mode 100644 index 960d01a3a86f..000000000000 --- a/netwerk/test/unit/test_bug651185.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Test for bug 651185: double quotes around 2231/5987 encoded param - */ - -const Cr = Components.results - -var BS = '\\'; -var DQUOTE = '"'; - -var tests = [ - [ /* sanity check */ - "Content-Disposition: attachment; filename*=utf-8''%41", - "A"], - [ /* the actual bug */ - "Content-Disposition: attachment; filename*=" + DQUOTE + "utf-8''%41" + DQUOTE, - Cr.NS_ERROR_INVALID_ARG], - ]; - -function run_test() { - - var mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"] - .getService(Components.interfaces.nsIMIMEHeaderParam); - - var unused = { value : null }; - - for (var i = 0; i < tests.length; ++i) { - dump("Testing " + tests[i] + "\n"); - try { - do_check_eq(mhp.getParameter(tests[i][0], "filename", "UTF-8", true, unused), - tests[i][1]); - } - catch (e) { - do_check_eq(e.result, tests[i][1]); - } - } -} - diff --git a/netwerk/test/unit/test_bug670333.js b/netwerk/test/unit/test_bug670333.js deleted file mode 100644 index aabcd4d03f13..000000000000 --- a/netwerk/test/unit/test_bug670333.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Test for bug 670333: Content-Disposition parser does not require presence of "=" in params - */ - -const Cr = Components.results - -var BS = '\\'; -var DQUOTE = '"'; - -var tests = [ - [ /* sanity check */ - "Content-Disposition: attachment; filename*=UTF-8''foo-%41.html", - "foo-A.html"], - [ /* the actual bug */ - "Content-Disposition: attachment; filename *=UTF-8''foo-%41.html", - Cr.NS_ERROR_INVALID_ARG], - [ /* the actual bug, without 2231/5987 encoding */ - "Content-Disposition: attachment; filename X", - Cr.NS_ERROR_INVALID_ARG], - [ /* sanity check with WS on both sides */ - "Content-Disposition: attachment; filename = foo-A.html", - "foo-A.html"], - ]; - -function run_test() { - - var mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"] - .getService(Components.interfaces.nsIMIMEHeaderParam); - - var unused = { value : null }; - - for (var i = 0; i < tests.length; ++i) { - dump("Testing " + tests[i] + "\n"); - try { - do_check_eq(mhp.getParameter(tests[i][0], "filename", "UTF-8", true, unused), - tests[i][1]); - } - catch (e) { - do_check_eq(e.result, tests[i][1]); - } - } -} - diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index ddc4742cbabd..ea5020bf1344 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -16,7 +16,6 @@ skip-if = os == "android" [test_bug248970_cookie.js] [test_bug261425.js] [test_bug263127.js] -[test_bug272541.js] [test_bug321706.js] [test_bug331825.js] [test_bug336501.js] @@ -35,7 +34,6 @@ skip-if = os == "android" [test_bug411952.js] [test_bug412945.js] [test_bug414122.js] -[test_bug419157.js] [test_bug427957.js] [test_bug429347.js] [test_bug455311.js] @@ -63,7 +61,6 @@ skip-if = os == "android" [test_bug561276.js] [test_bug580508.js] [test_bug586908.js] -[test_bug588389.js] [test_bug596443.js] [test_bug618835.js] [test_bug633743.js] @@ -83,9 +80,7 @@ fail-if = os == "android" fail-if = os == "android" [test_bug659569.js] [test_bug660066.js] -[test_bug651185.js] [test_bug667907.js] -[test_bug670333.js] [test_bug667818.js] [test_cacheflags.js] [test_channel_close.js] diff --git a/parser/htmlparser/src/nsScannerString.cpp b/parser/htmlparser/src/nsScannerString.cpp index c35850f1cc76..ce583049532f 100644 --- a/parser/htmlparser/src/nsScannerString.cpp +++ b/parser/htmlparser/src/nsScannerString.cpp @@ -44,11 +44,17 @@ * nsScannerBufferList */ +#define MAX_CAPACITY ((PR_UINT32_MAX / sizeof(PRUnichar)) - \ + (sizeof(Buffer) + sizeof(PRUnichar))) + nsScannerBufferList::Buffer* nsScannerBufferList::AllocBufferFromString( const nsAString& aString ) { PRUint32 len = aString.Length(); + if (len > MAX_CAPACITY) + return nsnull; + Buffer* buf = (Buffer*) malloc(sizeof(Buffer) + (len + 1) * sizeof(PRUnichar)); if (buf) { @@ -71,6 +77,9 @@ nsScannerBufferList::AllocBufferFromString( const nsAString& aString ) nsScannerBufferList::Buffer* nsScannerBufferList::AllocBuffer( PRUint32 capacity ) { + if (capacity > MAX_CAPACITY) + return nsnull; + Buffer* buf = (Buffer*) malloc(sizeof(Buffer) + (capacity + 1) * sizeof(PRUnichar)); if (buf) { diff --git a/security/manager/Makefile.in b/security/manager/Makefile.in index 9efe0c8a655d..1c16ad7b23f7 100644 --- a/security/manager/Makefile.in +++ b/security/manager/Makefile.in @@ -191,9 +191,9 @@ ifndef MOZ_DEBUG DEFAULT_GMAKE_FLAGS += BUILD_OPT=1 OPT_CODE_SIZE=1 endif ifdef GNU_CC -DEFAULT_GMAKE_FLAGS += NS_USE_GCC=1 NS_USE_NATIVE= +DEFAULT_GMAKE_FLAGS += NS_USE_GCC=1 else -DEFAULT_GMAKE_FLAGS += NS_USE_GCC= NS_USE_NATIVE=1 +DEFAULT_GMAKE_FLAGS += NS_USE_GCC= endif ifdef USE_N32 # It is not really necessary to specify USE_PTHREADS=1. USE_PTHREADS diff --git a/services/sync/modules/service.js b/services/sync/modules/service.js index b99f41e82498..e1c11577b828 100644 --- a/services/sync/modules/service.js +++ b/services/sync/modules/service.js @@ -759,10 +759,9 @@ WeaveSvc.prototype = { // Go ahead and do remote setup, so that we can determine // conclusively that our passphrase is correct. if (this._remoteSetup()) { - // Username/password verified. - Status.login = LOGIN_SUCCEEDED; - return true; + Status.login = LOGIN_SUCCEEDED; + return true; } this._log.warn("Remote setup failed."); diff --git a/toolkit/components/places/History.cpp b/toolkit/components/places/History.cpp index 35f229fd8bac..7625b2211e82 100644 --- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -59,6 +59,7 @@ #include "mozilla/unused.h" #include "mozilla/Util.h" #include "nsContentUtils.h" +#include "nsIMemoryReporter.h" // Initial size for the cache holding visited status observers. #define VISIT_OBSERVERS_INITIAL_CACHE_SIZE 128 @@ -1284,6 +1285,22 @@ StoreAndNotifyEmbedVisit(VisitData& aPlace, (void)NS_DispatchToMainThread(event); } +PRInt64 GetHistoryObserversSize() +{ + History* history = History::GetService(); + if (!history) + return 0; + return sizeof(*history) + history->SizeOf(); +} + +NS_MEMORY_REPORTER_IMPLEMENT(HistoryService, + "explicit/history-links-hashtable", + KIND_HEAP, + UNITS_BYTES, + GetHistoryObserversSize, + "Memory used by the hashtable of observers Places uses to notify objects of " + "changes to links' visited state.") + } // anonymous namespace //////////////////////////////////////////////////////////////////////////////// @@ -1303,6 +1320,8 @@ History::History() if (os) { (void)os->AddObserver(this, TOPIC_PLACES_SHUTDOWN, PR_FALSE); } + + NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(HistoryService)); } History::~History() @@ -1550,6 +1569,27 @@ History::FetchPageInfo(VisitData& _place) return true; } +PLDHashOperator +History::SizeOfEnumerator(KeyClass* aEntry, void* aArg) +{ + PRInt64 *size = reinterpret_cast(aArg); + + // Don't add in sizeof(*aEntry); that's already accounted for in + // mObservers.SizeOf(). + *size += aEntry->array.SizeOf(); + return PL_DHASH_NEXT; +} + +PRInt64 +History::SizeOf() +{ + PRInt64 size = mObservers.SizeOf(); + if (mObservers.IsInitialized()) { + mObservers.EnumerateEntries(SizeOfEnumerator, &size); + } + return size; +} + /* static */ History* History::GetService() diff --git a/toolkit/components/places/History.h b/toolkit/components/places/History.h index 0de0f5d78a8e..7784de6f4829 100644 --- a/toolkit/components/places/History.h +++ b/toolkit/components/places/History.h @@ -110,6 +110,12 @@ public: */ bool FetchPageInfo(VisitData& _place); + /** + * Get the number of bytes of memory this History object is using (not + * counting sizeof(*this)). + */ + PRInt64 SizeOf(); + /** * Obtains a pointer to this service. */ @@ -184,6 +190,11 @@ private: ObserverArray array; }; + /** + * Helper function for nsTHashtable::EnumerateEntries call in SizeOf(). + */ + static PLDHashOperator SizeOfEnumerator(KeyClass* aEntry, void* aArg); + nsTHashtable mObservers; }; diff --git a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd index 5290fe815709..8673940c5f20 100644 --- a/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd +++ b/toolkit/locales/en-US/chrome/mozapps/plugins/plugins.dtd @@ -21,6 +21,7 @@ + diff --git a/toolkit/mozapps/plugins/content/pluginProblem.xml b/toolkit/mozapps/plugins/content/pluginProblem.xml index c54f895a8ced..c3507d86cc96 100644 --- a/toolkit/mozapps/plugins/content/pluginProblem.xml +++ b/toolkit/mozapps/plugins/content/pluginProblem.xml @@ -58,6 +58,7 @@ &missingPlugin; + &clickToPlayPlugin; &disabledPlugin; &blockedPlugin.label; diff --git a/toolkit/mozapps/plugins/content/pluginProblemBinding.css b/toolkit/mozapps/plugins/content/pluginProblemBinding.css index fc1472195199..580f4628cdcf 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemBinding.css +++ b/toolkit/mozapps/plugins/content/pluginProblemBinding.css @@ -41,12 +41,15 @@ embed:-moz-handler-disabled, embed:-moz-handler-blocked, embed:-moz-handler-crashed, +embed:-moz-handler-clicktoplay, applet:-moz-handler-disabled, applet:-moz-handler-blocked, applet:-moz-handler-crashed, +applet:-moz-handler-clicktoplay, object:-moz-has-handlerref:-moz-handler-disabled, object:-moz-has-handlerref:-moz-handler-blocked, -object:-moz-handler-crashed { +object:-moz-handler-crashed, +object:-moz-handler-clicktoplay { display: inline-block; overflow: hidden; -moz-binding: url('chrome://mozapps/content/plugins/pluginProblem.xml#pluginProblem') !important; diff --git a/toolkit/mozapps/plugins/content/pluginProblemContent.css b/toolkit/mozapps/plugins/content/pluginProblemContent.css index 66d1cfb6e69f..3039718671ed 100644 --- a/toolkit/mozapps/plugins/content/pluginProblemContent.css +++ b/toolkit/mozapps/plugins/content/pluginProblemContent.css @@ -13,11 +13,13 @@ html|applet:not([height]), html|applet[height=""] { } :-moz-type-unsupported .mainBox, +:-moz-handler-clicktoplay .mainBox, :-moz-handler-disabled .mainBox, :-moz-handler-blocked .mainBox { -moz-user-focus: normal; } :-moz-type-unsupported .mainBox:focus, +:-moz-handler-clicktoplay .mainBox:focus, :-moz-handler-disabled .mainBox:focus, :-moz-handler-blocked .mainBox:focus { outline: 1px dotted; @@ -40,6 +42,7 @@ html|applet:not([height]), html|applet[height=""] { } :-moz-type-unsupported .msgUnsupported, +:-moz-handler-clicktoplay .msgClickToPlay, :-moz-handler-disabled .msgDisabled, :-moz-handler-disabled .msgManagePlugins, :-moz-handler-blocked .msgBlocked, diff --git a/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css b/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css index 4b3855d2fd35..0924145e8699 100644 --- a/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css +++ b/toolkit/themes/pinstripe/mozapps/plugins/pluginProblem.css @@ -34,6 +34,9 @@ html|a { :-moz-type-unsupported .icon[status="ready"] { background-image: url(chrome://mozapps/skin/plugins/contentPluginDownload.png); } +:-moz-handler-clicktoplay .icon { + background-image: url(chrome://mozapps/skin/plugins/contentPluginMissing.png); +} :-moz-handler-disabled .icon { background-image: url(chrome://mozapps/skin/plugins/contentPluginDisabled.png); } diff --git a/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css b/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css index 4b3855d2fd35..0924145e8699 100644 --- a/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css +++ b/toolkit/themes/winstripe/mozapps/plugins/pluginProblem.css @@ -34,6 +34,9 @@ html|a { :-moz-type-unsupported .icon[status="ready"] { background-image: url(chrome://mozapps/skin/plugins/contentPluginDownload.png); } +:-moz-handler-clicktoplay .icon { + background-image: url(chrome://mozapps/skin/plugins/contentPluginMissing.png); +} :-moz-handler-disabled .icon { background-image: url(chrome://mozapps/skin/plugins/contentPluginDisabled.png); } diff --git a/widget/src/xpwidgets/GfxInfoX11.cpp b/widget/src/xpwidgets/GfxInfoX11.cpp index 900e03da1475..42431a19f4a1 100644 --- a/widget/src/xpwidgets/GfxInfoX11.cpp +++ b/widget/src/xpwidgets/GfxInfoX11.cpp @@ -253,6 +253,12 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aFeature, PRInt32 *aStatus, nsAString & aS *aStatus = nsIGfxInfo::FEATURE_NO_INFO; aSuggestedDriverVersion.SetIsVoid(PR_TRUE); + if (aDriverInfo) { + // We don't implement the downloaded blacklist yet. Don't evaluate + // anything. + return NS_OK; + } + #ifdef MOZ_PLATFORM_MAEMO // on Maemo, the glxtest probe doesn't build, and we don't really need GfxInfo anyway return NS_OK; diff --git a/xpcom/ds/TimeStamp_darwin.cpp b/xpcom/ds/TimeStamp_darwin.cpp index fc800f9f3699..8176b40ce20d 100644 --- a/xpcom/ds/TimeStamp_darwin.cpp +++ b/xpcom/ds/TimeStamp_darwin.cpp @@ -63,6 +63,7 @@ static const PRUint64 kNsPerSec = 1000000000; static const double kNsPerMsd = 1000000.0; static const double kNsPerSecd = 1000000000.0; +static bool gInitialized = false; static double sNsPerTick; static PRUint64 @@ -111,12 +112,14 @@ namespace mozilla { double TimeDuration::ToSeconds() const { + NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early"); return (mValue * sNsPerTick) / kNsPerSecd; } double TimeDuration::ToSecondsSigDigits() const { + NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early"); // don't report a value < mResolution ... PRInt64 valueSigDigs = sResolution * (mValue / sResolution); // and chop off insignificant digits @@ -127,12 +130,14 @@ TimeDuration::ToSecondsSigDigits() const TimeDuration TimeDuration::FromMilliseconds(double aMilliseconds) { + NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early"); return TimeDuration::FromTicks(PRInt64((aMilliseconds * kNsPerMsd) / sNsPerTick)); } TimeDuration TimeDuration::Resolution() { + NS_ABORT_IF_FALSE(gInitialized, "calling TimeDuration too early"); return TimeDuration::FromTicks(PRInt64(sResolution)); } @@ -147,7 +152,6 @@ struct TimeStampInitialization }; static TimeStampInitialization initOnce; -static bool gInitialized = false; nsresult TimeStamp::Startup() diff --git a/xpcom/glue/nsTHashtable.h b/xpcom/glue/nsTHashtable.h index 135966ff4239..777d1afd02c8 100644 --- a/xpcom/glue/nsTHashtable.h +++ b/xpcom/glue/nsTHashtable.h @@ -251,6 +251,14 @@ public: PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull); } + PRUint64 SizeOf() + { + if (IsInitialized()) { + return PL_DHashTableSizeOf(&mTable); + } + return 0; + } + protected: PLDHashTable mTable; diff --git a/xpcom/glue/nsTObserverArray.h b/xpcom/glue/nsTObserverArray.h index 03c3e281a383..67c968f48f13 100644 --- a/xpcom/glue/nsTObserverArray.h +++ b/xpcom/glue/nsTObserverArray.h @@ -243,6 +243,12 @@ class nsAutoTObserverArray : protected nsTObserverArray_base { ClearIterators(); } + // Returns the number of bytes on the heap taken up by this object, not + // including sizeof(*this). + PRUint64 SizeOf() { + return mArray.SizeOf(); + } + // // Iterators // diff --git a/xpcom/glue/pldhash.cpp b/xpcom/glue/pldhash.cpp index 32339b41fb30..ddb58715eb0e 100644 --- a/xpcom/glue/pldhash.cpp +++ b/xpcom/glue/pldhash.cpp @@ -40,7 +40,8 @@ /* * Double hashing implementation. - * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + * + * Try to keep this file in sync with js/src/jsdhash.cpp. */ #include #include @@ -794,6 +795,24 @@ PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg) return i; } +PRUint64 +PL_DHashTableSizeOf(PLDHashTable *table) +{ + PRUint64 size = 0; + +#ifdef MOZALLOC_HAVE_MALLOC_USABLE_SIZE + // Even when moz_malloc_usable_size is defined, it might always return 0, if + // the allocator in use doesn't support malloc_usable_size. + size = moz_malloc_usable_size(table->entryStore); +#endif + + if (size == 0) { + size = PL_DHASH_TABLE_SIZE(table) * table->entrySize; + } + + return size; +} + #ifdef DEBUG void PL_DHashMarkTableImmutable(PLDHashTable *table) diff --git a/xpcom/glue/pldhash.h b/xpcom/glue/pldhash.h index df8a926c22f4..3f0fcde5191b 100644 --- a/xpcom/glue/pldhash.h +++ b/xpcom/glue/pldhash.h @@ -40,7 +40,8 @@ #define pldhash_h___ /* * Double hashing, a la Knuth 6. - * GENERATED BY js/src/plify_jsdhash.sed -- DO NOT EDIT!!! + * + * Try to keep this file in sync with js/src/jsdhash.h. */ #include "nscore.h" @@ -577,6 +578,15 @@ typedef PLDHashOperator NS_COM_GLUE PRUint32 PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg); +/** + * Get the hashtable's "shallow heap size" in bytes. The size returned here + * includes all the heap memory allocated by the hashtable itself. It does not + * include sizeof(*this) or heap memory allocated by the objects in the hash + * table. + */ +NS_COM_GLUE PRUint64 +PL_DHashTableSizeOf(PLDHashTable *table); + #ifdef DEBUG /** * Mark a table as immutable for the remainder of its lifetime. This