merge the last green changeset on fx-team to m-c

This commit is contained in:
Tim Taubert 2011-08-10 01:30:21 +02:00
commit b6faf8adf8
79 changed files with 1543 additions and 615 deletions

View File

@ -170,6 +170,18 @@ nsApplicationAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY,
return nsnull;
}
nsAccessible*
nsApplicationAccessible::FocusedChild()
{
if (gLastFocusedNode) {
nsAccessible* focusedChild =
GetAccService()->GetAccessible(gLastFocusedNode);
if (focusedChild && focusedChild->Parent() == this)
return focusedChild;
}
return nsnull;
}
NS_IMETHODIMP
nsApplicationAccessible::GetRelationByType(PRUint32 aRelationType,
nsIAccessibleRelation **aRelation)

View File

@ -122,8 +122,10 @@ public:
virtual PRUint32 NativeRole();
virtual PRUint64 State();
virtual PRUint64 NativeState();
virtual nsAccessible* ChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
virtual nsAccessible* FocusedChild();
virtual void InvalidateChildren();

View File

@ -211,10 +211,10 @@ nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
nsDocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
#ifdef DEBUG_NOTIFICATIONS
nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSelection));
nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
PRInt16 type = 0;
sel2->GetType(&type);
privSel->GetType(&type);
if (type == nsISelectionController::SELECTION_NORMAL ||
type == nsISelectionController::SELECTION_SPELLCHECK) {
@ -245,10 +245,10 @@ nsCaretAccessible::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
void
nsCaretAccessible::ProcessSelectionChanged(nsISelection* aSelection)
{
nsCOMPtr<nsISelection2> sel2(do_QueryInterface(aSelection));
nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
PRInt16 type = 0;
sel2->GetType(&type);
privSel->GetType(&type);
if (type == nsISelectionController::SELECTION_NORMAL)
NormalSelectionChanged(aSelection);

View File

@ -42,7 +42,6 @@
#include "nsHyperTextAccessible.h"
#include "nsISelectionListener.h"
#include "nsISelection2.h"
class nsRootAccessible;

View File

@ -56,7 +56,7 @@
#include "nsPresContext.h"
#include "nsIScrollableFrame.h"
#include "nsEventStateManager.h"
#include "nsISelection2.h"
#include "nsISelectionPrivate.h"
#include "nsISelectionController.h"
#include "nsPIDOMWindow.h"
#include "nsGUIEvent.h"
@ -331,20 +331,18 @@ nsCoreUtils::ScrollSubstringTo(nsIFrame *aFrame,
scrollToRange->SetStart(aStartNode, aStartIndex);
scrollToRange->SetEnd(aEndNode, aEndIndex);
nsCOMPtr<nsISelection> selection1;
nsCOMPtr<nsISelection> selection;
selCon->GetSelection(nsISelectionController::SELECTION_ACCESSIBILITY,
getter_AddRefs(selection1));
getter_AddRefs(selection));
nsCOMPtr<nsISelection2> selection(do_QueryInterface(selection1));
if (selection) {
selection->RemoveAllRanges();
selection->AddRange(scrollToRange);
nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(selection));
selection->RemoveAllRanges();
selection->AddRange(scrollToRange);
selection->ScrollIntoView(nsISelectionController::SELECTION_ANCHOR_REGION,
PR_TRUE, aVPercent, aHPercent);
privSel->ScrollIntoView(nsISelectionController::SELECTION_ANCHOR_REGION,
PR_TRUE, aVPercent, aHPercent);
selection->CollapseToStart();
}
selection->CollapseToStart();
return NS_OK;
}

View File

@ -50,7 +50,6 @@
#include "nsIDOMElement.h"
#include "nsIDOMDocument.h"
#include "nsIDOMRange.h"
#include "nsISelection2.h"
#include "nsISelectionPrivate.h"
#include "nsINameSpaceManager.h"
#include "nsIDOMHTMLCollection.h"

View File

@ -60,7 +60,6 @@
#include "nsIInterfaceRequestorUtils.h"
#include "nsIPlaintextEditor.h"
#include "nsIScrollableFrame.h"
#include "nsISelection2.h"
#include "nsISelectionPrivate.h"
#include "nsIServiceManager.h"
#include "nsTextFragment.h"
@ -1791,8 +1790,7 @@ nsHyperTextAccessible::GetSelections(PRInt16 aType,
}
if (aRanges) {
nsCOMPtr<nsISelection2> selection2(do_QueryInterface(domSel));
NS_ENSURE_TRUE(selection2, NS_ERROR_FAILURE);
nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(domSel));
nsCOMPtr<nsINode> startNode = GetNode();
if (peditor) {
@ -1804,7 +1802,7 @@ nsHyperTextAccessible::GetSelections(PRInt16 aType,
PRUint32 childCount = startNode->GetChildCount();
nsCOMPtr<nsIDOMNode> startDOMNode(do_QueryInterface(startNode));
nsresult rv = selection2->
nsresult rv = privSel->
GetRangesForIntervalCOMArray(startDOMNode, 0, startDOMNode, childCount,
PR_TRUE, aRanges);
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -47,6 +47,7 @@ DIRS = \
attributes \
editabletext \
events \
focus \
hyperlink \
hypertext \
name \
@ -103,7 +104,6 @@ _TEST_FILES =\
test_nsIAccessNode_utils.html \
test_nsOuterDocAccessible.html \
test_role_nsHyperTextAcc.html \
test_takeFocus.html \
test_text_caret.html \
test_textboxes.html \
test_textboxes.xul \

View File

@ -0,0 +1,54 @@
#
# ***** 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 <surkov.alexander@gmail.com> (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/focus
include $(DEPTH)/config/autoconf.mk
include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
test_focusedChild.html \
test_takeFocus.html \
$(NULL)
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/a11y/$(relativesrcdir)

View File

@ -0,0 +1,85 @@
<html>
<head>
<title>nsIAccessible::focusedChild testing</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../states.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
function openWnd()
{
this.eventSeq = [ new invokerChecker(EVENT_FOCUS,
getDialogAccessible,
this) ];
this.invoke = function openWnd_invoke()
{
this.dialog = window.openDialog("about:mozilla",
"AboutMozilla",
"chrome,width=600,height=600");
}
this.finalCheck = function openWnd_finalCheck()
{
var app = getApplicationAccessible();
is(app.focusedChild, getDialogAccessible(this),
"Wrong focused child");
this.dialog.close();
}
this.getID = function openWnd_getID()
{
return "focusedChild for application accessible";
}
function getDialogAccessible(aInvoker)
{
return getAccessible(aInvoker.dialog.document);
}
}
//gA11yEventDumpToConsole = true;
var gQueue = null;
function doTest()
{
gQueue = new eventQueue();
gQueue.push(new openWnd());
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=677467"
title="focusedChild crashes on application accessible">
Mozilla Bug 677467
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -10,12 +10,13 @@
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="common.js"></script>
src="../common.js"></script>
<script type="application/javascript"
src="states.js"></script>
src="../states.js"></script>
<script type="application/javascript"
src="events.js"></script>
src="../events.js"></script>
<script type="application/javascript">
////////////////////////////////////////////////////////////////////////////

View File

@ -74,7 +74,7 @@
};
registerA11yEventListener(EVENT_REORDER, handler);
tabBrowser.loadTabs(["about:", "about:mozilla"], false, true);
tabBrowser.loadTabs(docURIs, false, true);
}
function testRelations()

View File

@ -75,7 +75,9 @@ CSRCS := \
libs:: $(CSRCS:.c=.$(OBJ_SUFFIX))
ifndef CROSS_COMPILE
WRAP_MALLOC_CFLAGS=
WRAP_MALLOC_LIB=
test$(DLL_SUFFIX): test.$(OBJ_SUFFIX) elfhack $(CSRCS:.c=.$(OBJ_SUFFIX))
$(MKSHLIB) $(LDFLAGS) $<
@echo ===
@ -92,6 +94,13 @@ test$(DLL_SUFFIX): test.$(OBJ_SUFFIX) elfhack $(CSRCS:.c=.$(OBJ_SUFFIX))
.PRECIOUS: test$(DLL_SUFFIX)
CSRCS += test.c
GARBAGE += test$(DLL_SUFFIX) test$(DLL_SUFFIX).bak
libs:: test$(DLL_SUFFIX)
ifndef CROSS_COMPILE
dummy: dummy.$(OBJ_SUFFIX) test$(DLL_SUFFIX)
$(CC) -o $@ $^ $(LDFLAGS)
@ -99,9 +108,9 @@ libs:: dummy
# Will either crash or return exit code 1 if elfhack is broken
LD_LIBRARY_PATH=$(CURDIR) $(CURDIR)/dummy
CSRCS += test.c dummy.c
CSRCS += dummy.c
GARBAGE += dummy test$(DLL_SUFFIX) test$(DLL_SUFFIX).bak
GARBAGE += dummy
endif
inject:

View File

@ -45,9 +45,9 @@
#
# Define an include-at-most-once flag
#ifdef INCLUDED_CONFIG_MK
#$(error Don't include config.mk twice!)
#endif
ifdef INCLUDED_CONFIG_MK
$(error Don't include config.mk twice!)
endif
INCLUDED_CONFIG_MK = 1
EXIT_ON_ERROR = set -e; # Shell loops continue past errors without this.

View File

@ -343,7 +343,7 @@ case "$target" in
CPPFLAGS="-I$android_platform/usr/include $STLPORT_CPPFLAGS $CPPFLAGS"
CFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CFLAGS"
CXXFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CXXFLAGS"
LIBS="$LIBS $STLPORT_LIBS -static-libstdc++"
LIBS="$LIBS $STLPORT_LIBS"
dnl Add -llog by default, since we use it all over the place.
dnl Add --allow-shlib-undefined, because libGLESv2 links to an
@ -366,8 +366,8 @@ case "$target" in
fi
ANDROID_NDK="${android_ndk}"
ANDROID_TOOLCHAIN="{android_toolchain}"
ANDROID_PLATFORM="{android_platform}"
ANDROID_TOOLCHAIN="${android_toolchain}"
ANDROID_PLATFORM="${android_platform}"
ANDROID_SDK="${android_sdk}"
ANDROID_PLATFORM_TOOLS="${android_platform_tools}"
ANDROID_VERSION="${android_version}"
@ -7267,6 +7267,38 @@ if test -n "$MOZ_DEBUG" -o -n "$MOZ_DEBUG_SYMBOLS"; then
export MOZ_DEBUG_SYMBOLS
fi
dnl ========================================================
dnl = Identical Code Folding
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(icf,
[ --disable-icf Disable Identical Code Folding],
MOZ_DISABLE_ICF=1,
MOZ_DISABLE_ICF= )
if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -z "$MOZ_DISABLE_ICF"; then
AC_CACHE_CHECK([whether the linker supports Identical Code Folding],
LD_SUPPORTS_ICF,
[echo 'int foo() {return 42;}' \
'int bar() {return 42;}' \
'int main() {return foo() - bar();}' > conftest.${ac_ext}
# If the linker supports ICF, foo and bar symbols will have
# the same address
if AC_TRY_COMMAND([${CC-cc} -o conftest${ac_exeext} $LDFLAGS -Wl,--icf=safe -ffunction-sections conftest.${ac_ext} $LIBS 1>&2]) &&
test -s conftest${ac_exeext} &&
objdump -t conftest${ac_exeext} | awk '{a[[$6]] = $1} END {if (a[["foo"]] && (a[["foo"]] != a[["bar"]])) { exit 1 }}'; then
LD_SUPPORTS_ICF=yes
else
LD_SUPPORTS_ICF=no
fi
rm -rf conftest*])
if test "$LD_SUPPORTS_ICF" = yes; then
LDFLAGS="$LDFLAGS -Wl,--icf=safe"
CFLAGS="$CFLAGS -ffunction-sections"
CXXFLAGS="$CXXFLAGS -ffunction-sections"
fi
fi
dnl ========================================================
dnl = Automatically remove dead symbols
dnl ========================================================
@ -7294,8 +7326,16 @@ if test "$GNU_CC" -a "$GCC_USE_GNU_LD" -a -n "$MOZ_DEBUG_FLAGS"; then
rm -rf conftest*])
if test "$GC_SECTIONS_BREAKS_DEBUG_RANGES" = no; then
DSO_LDOPTS="$DSO_LDOPTS -Wl,--gc-sections"
CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
case "$CFLAGS" in
*-ffunction-sections*)
CFLAGS="$CFLAGS -fdata-sections"
CXXFLAGS="$CXXFLAGS -fdata-sections"
;;
*)
CFLAGS="$CFLAGS -ffunction-sections -fdata-sections"
CXXFLAGS="$CXXFLAGS -ffunction-sections -fdata-sections"
;;
esac
fi
fi
@ -7859,7 +7899,7 @@ dnl done during packaging with omnijar.
if test "$MOZ_CHROME_FILE_FORMAT" = "omni"; then
MOZ_OMNIJAR=1
AC_DEFINE(MOZ_OMNIJAR)
if test "$OS_ARCH" = "WINNT"; then
if test "$OS_ARCH" = "WINNT" -o "$OS_ARCH" = "OS2"; then
MOZ_CHROME_FILE_FORMAT=flat
else
MOZ_CHROME_FILE_FORMAT=symlink

View File

@ -108,8 +108,6 @@ XPIDLSRCS = \
nsIDOMFormData.idl \
nsIDOMParser.idl \
nsIDOMSerializer.idl \
nsISelection2.idl \
nsISelection3.idl \
nsISelectionController.idl \
nsISelectionDisplay.idl \
nsISelectionListener.idl \

View File

@ -49,7 +49,7 @@ interface nsIDOMRange;
* @version 1.0
*/
[scriptable, uuid(B2C7ED59-8634-4352-9E37-5484C8B6E4E1)]
[scriptable, uuid(5ac0cd5d-3c08-4c4c-8e70-230c433f5d5c)]
interface nsISelection : nsISupports
{
/**
@ -165,4 +165,25 @@ interface nsISelection : nsISupports
* Returns the whole selection into a plain text string.
*/
wstring toString();
/**
* Modifies the selection. Note that the parameters are case-insensitive.
*
* @param alter can be one of { "move", "extend" }
* - "move" collapses the selection to the end of the selection and
* applies the movement direction/granularity to the collapsed
* selection.
* - "extend" leaves the start of the selection unchanged, and applies
* movement direction/granularity to the end of the selection.
* @param direction can be one of { "forward", "backward", "left", "right" }
* @param granularity can be one of { "character", "word",
* "line", "lineboundary" }
*
* @returns NS_ERROR_NOT_IMPLEMENTED if the granularity is "sentence",
* "sentenceboundary", "paragraph", "paragraphboundary", or
* "documentboundary". Returns NS_ERROR_INVALID_ARG if alter, direction,
* or granularity has an unrecognized value.
*/
void modify(in DOMString alter, in DOMString direction,
in DOMString granularity);
};

View File

@ -1,111 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 Selection code.
*
* The Initial Developer of the Original Code is
* Google Inc.
* Portions created by the Initial Developer are Copyright (C) 2006
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brett Wilson <brettw@gmail.com>
* Alexander Surkov <surkov.alexander@gmail.com>
*
* 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 ***** */
#include "nsISelection.idl"
interface nsIDOMNode;
interface nsIDOMRange;
%{C++
#include "nsCOMArray.h"
%}
[ptr] native RangeArray(nsCOMArray<nsIDOMRange>);
[scriptable, uuid(5d21d5fe-3691-4716-a334-4691eea54d29)]
interface nsISelection2 : nsISelection
{
/**
* Returns the type of the selection (see nsISelectionController for
* available constants).
*/
readonly attribute short type;
/**
* Return array of ranges intersecting with the given DOM interval.
*/
void GetRangesForInterval(
in nsIDOMNode beginNode, in PRInt32 beginOffset,
in nsIDOMNode endNode, in PRInt32 endOffset,
in boolean allowAdjacent,
out PRUint32 resultCount,
[retval, array, size_is(resultCount)] out nsIDOMRange results);
[noscript] void GetRangesForIntervalCOMArray(
in nsIDOMNode beginNode, in PRInt32 beginOffset,
in nsIDOMNode endNode, in PRInt32 endOffset,
in boolean allowAdjacent,
in RangeArray results);
/**
* Scrolls a region of the selection, so that it is visible in
* the scrolled view.
*
* @param aRegion - the region inside the selection to scroll into view
* (see selection region constants defined in
* nsISelectionController).
* @param aIsSynchronous - when true, scrolls the selection into view
* before returning. If false, posts a request which
* is processed at some point after the method returns.
* @param aVPercent - how to align the frame vertically. A value of 0
* means the frame's upper edge is aligned with the top edge
* of the visible area. A value of 100 means the frame's
* bottom edge is aligned with the bottom edge of
* the visible area. For values in between, the point
* "aVPercent" down the frame is placed at the point
* "aVPercent" down the visible area. A value of 50 centers
* the frame vertically. A value of -1 means move
* the frame the minimum amount necessary in order for
* the entire frame to be visible vertically (if possible).
* @param aHPercent - how to align the frame horizontally. A value of 0
* means the frame's left edge is aligned with the left
* edge of the visible area. A value of 100 means the
* frame's right edge is aligned with the right edge of
* the visible area. For values in between, the point
* "aHPercent" across the frame is placed at the point
* "aHPercent" across the visible area. A value of 50
* centers the frame horizontally . A value of -1 means
* move the frame the minimum amount necessary in order
* for the entire frame to be visible horizontally
* (if possible).
*/
void scrollIntoView(in short aRegion, in boolean aIsSynchronous,
in short aVPercent, in short aHPercent);
};

View File

@ -1,65 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** 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 Selection code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Justin Lebar <justin.lebar@gmail.com>
*
* 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 ***** */
#include "nsISupports.idl"
[scriptable, uuid(94ac0cb4-95b4-11df-8e13-0026b9792740)]
interface nsISelection3 : nsISupports
{
/**
* Modifies the selection. Note that the parameters are case-insensitive.
*
* @param alter can be one of { "move", "extend" }
* - "move" collapses the selection to the end of the selection and
* applies the movement direction/granularity to the collapsed
* selection.
* - "extend" leaves the start of the selection unchanged, and applies
* movement direction/granularity to the end of the selection.
* @param direction can be one of { "forward", "backward", "left", "right" }
* @param granularity can be one of { "character", "word",
* "line", "lineboundary" }
*
* @returns NS_ERROR_NOT_IMPLEMENTED if the granularity is "sentence",
* "sentenceboundary", "paragraph", "paragraphboundary", or
* "documentboundary". Returns NS_ERROR_INVALID_ARG if alter, direction,
* or granularity has an unrecognized value.
*/
void modify(in DOMString alter, in DOMString direction,
in DOMString granularity);
};

View File

@ -38,8 +38,10 @@
#include "nsISupports.idl"
#include "nsISelectionListener.idl"
#include "nsIEnumerator.idl"
#include "nsISelection.idl"
interface nsIDOMRange;
interface nsIDOMNode;
interface nsISelectionListener;
interface nsIContent;
@ -50,17 +52,19 @@ class nsIPresShell;
struct nsTextRangeStyle;
struct nsPoint;
#include "nsIFrame.h"
#include "nsCOMArray.h"
%}
[ptr] native nsFrameSelection(nsFrameSelection);
[ptr] native nsIFrame(nsIFrame);
[ptr] native nsIPresShell(nsIPresShell);
[ptr] native RangeArray(nsCOMArray<nsIDOMRange>);
[ref] native constTextRangeStyleRef(const nsTextRangeStyle);
[ref] native nsPointRef(nsPoint);
native nsDirection(nsDirection);
[scriptable, uuid(98552206-ad7a-4d2d-8ce3-b6fa2389298b)]
interface nsISelectionPrivate : nsISupports
[scriptable, uuid(1820a940-6203-4e27-bc94-fa81131722a4)]
interface nsISelectionPrivate : nsISelection
{
const short ENDOFPRECEDINGLINE=0;
const short STARTOFNEXTLINE=1;
@ -136,5 +140,62 @@ interface nsISelectionPrivate : nsISupports
*/
[noscript, notxpcom] nsDirection getSelectionDirection();
[noscript, notxpcom] void setSelectionDirection(in nsDirection aDirection);
/**
* Returns the type of the selection (see nsISelectionController for
* available constants).
*/
readonly attribute short type;
/**
* Return array of ranges intersecting with the given DOM interval.
*/
void GetRangesForInterval(
in nsIDOMNode beginNode, in PRInt32 beginOffset,
in nsIDOMNode endNode, in PRInt32 endOffset,
in PRBool allowAdjacent,
out PRUint32 resultCount,
[retval, array, size_is(resultCount)] out nsIDOMRange results);
[noscript] void GetRangesForIntervalCOMArray(
in nsIDOMNode beginNode, in PRInt32 beginOffset,
in nsIDOMNode endNode, in PRInt32 endOffset,
in PRBool allowAdjacent,
in RangeArray results);
/**
* Scrolls a region of the selection, so that it is visible in
* the scrolled view.
*
* @param aRegion - the region inside the selection to scroll into view
* (see selection region constants defined in
* nsISelectionController).
* @param aIsSynchronous - when true, scrolls the selection into view
* before returning. If false, posts a request which
* is processed at some point after the method returns.
* @param aVPercent - how to align the frame vertically. A value of 0
* means the frame's upper edge is aligned with the top edge
* of the visible area. A value of 100 means the frame's
* bottom edge is aligned with the bottom edge of
* the visible area. For values in between, the point
* "aVPercent" down the frame is placed at the point
* "aVPercent" down the visible area. A value of 50 centers
* the frame vertically. A value of -1 means move
* the frame the minimum amount necessary in order for
* the entire frame to be visible vertically (if possible).
* @param aHPercent - how to align the frame horizontally. A value of 0
* means the frame's left edge is aligned with the left
* edge of the visible area. A value of 100 means the
* frame's right edge is aligned with the right edge of
* the visible area. For values in between, the point
* "aHPercent" across the frame is placed at the point
* "aHPercent" across the visible area. A value of 50
* centers the frame horizontally . A value of -1 means
* move the frame the minimum amount necessary in order
* for the entire frame to be visible horizontally
* (if possible).
*/
void scrollIntoView(in short aRegion, in boolean aIsSynchronous,
in short aVPercent, in short aHPercent);
};

View File

@ -59,7 +59,6 @@
#include "nsISelectionPrivate.h"
#include "nsContentUtils.h"
#include "nsLayoutUtils.h"
#include "nsISelection2.h"
#include "nsIMEStateManager.h"
#include "nsIObjectFrame.h"
@ -1071,8 +1070,7 @@ nsContentEventHandler::OnSelectionEvent(nsSelectionEvent* aEvent)
nsCOMPtr<nsIDOMNode> endDomNode(do_QueryInterface(endNode));
NS_ENSURE_TRUE(startDomNode && endDomNode, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsISelectionPrivate> selPrivate = do_QueryInterface(mSelection);
NS_ENSURE_TRUE(selPrivate, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
selPrivate->StartBatchChanges();
// Clear selection first before setting
@ -1096,7 +1094,7 @@ nsContentEventHandler::OnSelectionEvent(nsSelectionEvent* aEvent)
selPrivate->EndBatchChanges();
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISelection2>(do_QueryInterface(mSelection))->ScrollIntoView(
selPrivate->ScrollIntoView(
nsISelectionController::SELECTION_FOCUS_REGION, PR_FALSE, -1, -1);
aEvent->mSucceeded = PR_TRUE;
return NS_OK;

View File

@ -1134,6 +1134,19 @@ NS_IMETHODIMP nsHTMLMediaElement::GetDuration(double *aDuration)
return NS_OK;
}
/* readonly attribute nsIDOMHTMLTimeRanges seekable; */
NS_IMETHODIMP nsHTMLMediaElement::GetSeekable(nsIDOMTimeRanges** aSeekable)
{
nsTimeRanges* ranges = new nsTimeRanges();
NS_ADDREF(*aSeekable = ranges);
if (mDecoder && mReadyState > nsIDOMHTMLMediaElement::HAVE_NOTHING) {
mDecoder->GetSeekable(ranges);
}
return NS_OK;
}
/* readonly attribute boolean paused; */
NS_IMETHODIMP nsHTMLMediaElement::GetPaused(PRBool *aPaused)
{
@ -1825,7 +1838,7 @@ nsresult nsHTMLMediaElement::InitializeDecoderAsClone(nsMediaDecoder* aOriginal)
double duration = aOriginal->GetDuration();
if (duration >= 0) {
decoder->SetDuration(duration);
decoder->SetSeekable(aOriginal->GetSeekable());
decoder->SetSeekable(aOriginal->IsSeekable());
}
nsMediaStream* stream = originalStream->CloneData(decoder);

View File

@ -47,6 +47,7 @@
#include "VideoUtils.h"
#include "nsBuiltinDecoder.h"
#include "nsBuiltinDecoderStateMachine.h"
#include "nsTimeRanges.h"
using namespace mozilla;
@ -267,13 +268,82 @@ nsresult nsBuiltinDecoder::Play()
return NS_OK;
}
/**
* Returns PR_TRUE if aValue is inside a range of aRanges, and put the range
* index in aIntervalIndex if it is not null.
* If aValue is not inside a range, PR_FALSE is returned, and aIntervalIndex, if
* not null, is set to the index of the range which ends immediatly before aValue
* (and can be -1 if aValue is before aRanges.Start(0)).
*/
static PRBool IsInRanges(nsTimeRanges& aRanges, double aValue, PRInt32& aIntervalIndex) {
PRUint32 length;
aRanges.GetLength(&length);
for (PRUint32 i = 0; i < length; i++) {
double start, end;
aRanges.Start(i, &start);
if (start > aValue) {
aIntervalIndex = i - 1;
return PR_FALSE;
}
aRanges.End(i, &end);
if (aValue <= end) {
aIntervalIndex = i;
return PR_TRUE;
}
}
aIntervalIndex = length - 1;
return PR_FALSE;
}
nsresult nsBuiltinDecoder::Seek(double aTime)
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (aTime < 0.0)
return NS_ERROR_FAILURE;
NS_ABORT_IF_FALSE(aTime >= 0.0, "Cannot seek to a negative value.");
nsTimeRanges seekable;
nsresult res;
PRUint32 length = 0;
res = GetSeekable(&seekable);
NS_ENSURE_SUCCESS(res, NS_OK);
seekable.GetLength(&length);
if (!length) {
return NS_OK;
}
// If the position we want to seek to is not in a seekable range, we seek
// to the closest position in the seekable ranges instead . If two positions
// are equaly close, we seek to the closest position from the currentTime.
// See seeking spec, point 7 :
// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#seeking
PRInt32 range = 0;
if (!IsInRanges(seekable, aTime, range)) {
if (range != -1) {
double leftBound, rightBound;
res = seekable.End(range, &leftBound);
NS_ENSURE_SUCCESS(res, NS_OK);
double distanceLeft = NS_ABS(leftBound - aTime);
double distanceRight = -1;
if (range + 1 < length) {
res = seekable.Start(range+1, &rightBound);
NS_ENSURE_SUCCESS(res, NS_OK);
distanceRight = NS_ABS(rightBound - aTime);
}
if (distanceLeft == distanceRight) {
distanceLeft = NS_ABS(leftBound - mCurrentTime);
distanceRight = NS_ABS(rightBound - mCurrentTime);
}
aTime = (distanceLeft < distanceRight) ? leftBound : rightBound;
} else {
// aTime is before the first range in |seekable|, the closest point we can
// seek to is the start of the first range.
seekable.Start(0, &aTime);
}
}
mRequestedSeekTime = aTime;
mCurrentTime = aTime;
@ -847,12 +917,27 @@ void nsBuiltinDecoder::SetSeekable(PRBool aSeekable)
}
}
PRBool nsBuiltinDecoder::GetSeekable()
PRBool nsBuiltinDecoder::IsSeekable()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
return mSeekable;
}
nsresult nsBuiltinDecoder::GetSeekable(nsTimeRanges* aSeekable)
{
//TODO : change 0.0 to GetInitialTime() when available
double initialTime = 0.0;
if (IsSeekable()) {
double end = IsInfinite() ? std::numeric_limits<double>::infinity()
: initialTime + GetDuration();
aSeekable->Add(initialTime, end);
return NS_OK;
}
return GetBuffered(aSeekable);
}
void nsBuiltinDecoder::Suspend()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");

View File

@ -316,7 +316,7 @@ public:
// Returns PR_TRUE if the media resource can seek into unbuffered ranges,
// as set by SetSeekable(). The decoder monitor must be obtained before
// calling this.
virtual PRBool GetSeekable() = 0;
virtual PRBool IsSeekable() = 0;
// Update the playback position. This can result in a timeupdate event
// and an invalidate of the frame being dispatched asynchronously if
@ -433,7 +433,9 @@ class nsBuiltinDecoder : public nsMediaDecoder
virtual void SetSeekable(PRBool aSeekable);
// Return PR_TRUE if seeking is supported.
virtual PRBool GetSeekable();
virtual PRBool IsSeekable();
virtual nsresult GetSeekable(nsTimeRanges* aSeekable);
virtual Statistics GetStatistics();

View File

@ -252,7 +252,7 @@ public:
return mEndTime;
}
PRBool GetSeekable() {
PRBool IsSeekable() {
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
return mSeekable;
}

View File

@ -291,7 +291,10 @@ public:
virtual void SetSeekable(PRBool aSeekable) = 0;
// Return PR_TRUE if seeking is supported.
virtual PRBool GetSeekable() = 0;
virtual PRBool IsSeekable() = 0;
// Return the time ranges that can be seeked into.
virtual nsresult GetSeekable(nsTimeRanges* aSeekable) = 0;
// Invalidate the frame.
virtual void Invalidate();

View File

@ -326,7 +326,7 @@ nsresult nsOggReader::ReadMetadata(nsVideoInfo* aInfo)
if (mDecoder->GetStateMachine()->GetDuration() == -1 &&
mDecoder->GetStateMachine()->GetState() != nsDecoderStateMachine::DECODER_STATE_SHUTDOWN &&
stream->GetLength() >= 0 &&
mDecoder->GetStateMachine()->GetSeekable())
mDecoder->GetStateMachine()->IsSeekable())
{
// We didn't get a duration from the index or a Content-Duration header.
// Seek to the end of file to find the end time.

View File

@ -128,6 +128,7 @@ _TEST_FILES = \
test_play_events_2.html \
test_playback.html \
test_playback_errors.html \
test_seekable1.html \
test_preload_actions.html \
test_preload_attribute.html \
test_progress.html \
@ -259,6 +260,9 @@ _TEST_FILES += \
contentDuration5.sjs \
contentDuration6.sjs \
contentDuration7.sjs \
noContentLength.sjs \
test_seekable2.html \
test_seekable3.html \
test_a4_tone.html \
file_audio_event_adopt_iframe.html \
test_audio_event_adopt.html \

View File

@ -146,6 +146,19 @@ function fileUriToSrc(path, mustExist) {
return f.path;
}
// Returns true if two nsTimeRanges are equal, false otherwise
function range_equals(r1, r2) {
if (r1.length != r2.length) {
return false;
}
for (var i = 0; i < r1.length; i++) {
if (r1.start(i) != r2.start(i) || r1.end(i) != r2.end(i)) {
return false;
}
}
return true;
}
// These are URIs to files that we use to check that we don't leak any state
// or other information such that script can determine stuff about a user's
// environment. Used by test_info_leak.

View File

@ -0,0 +1,23 @@
// Serve a media file without using content-range header
function handleRequest(request, response)
{
var file = Components.classes["@mozilla.org/file/directory_service;1"].
getService(Components.interfaces.nsIProperties).
get("CurWorkD", Components.interfaces.nsILocalFile);
var fis = Components.classes['@mozilla.org/network/file-input-stream;1'].
createInstance(Components.interfaces.nsIFileInputStream);
var bis = Components.classes["@mozilla.org/binaryinputstream;1"].
createInstance(Components.interfaces.nsIBinaryInputStream);
var paths = "tests/content/media/test/320x240.ogv";
var split = paths.split("/");
for(var i = 0; i < split.length; ++i) {
file.append(split[i]);
}
fis.init(file, -1, -1, false);
bis.setInputStream(fis);
var bytes = bis.readBytes(bis.available());
response.setStatusLine(request.httpVersion, 200, "Content Follows");
response.setHeader("Content-Type", "video/ogg", false);
response.write(bytes, bytes.length);
bis.close();
}

View File

@ -0,0 +1,66 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test seekable member for media elements</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id='test'>
<script class="testbody" type='application/javascript;version=1.8'>
let manager = new MediaTestManager;
function finish_test(element) {
if (element.parentNode)
element.parentNode.removeChild(element);
element.src="";
manager.finished(element.token);
}
var tests = [
// Test using a finite media stream, and a server supporting range requests
{
setup : function(element) {
is(element.seekable.length, 0, "seekable.length should be initialy 0.");
element.addEventListener("loadedmetadata", function() {
is(element.seekable.length, 1, "seekable.length should be 1 for a server supporting range requests.");
//TODO : change this by using element.initialTime
is(element.seekable.start(0), 0.0, "The start of the first range should be the initialTime.");
is(element.seekable.end(0), element.duration, "The end of the first range should be the duration.")
finish_test(element);
}, false);
}
}
];
function createTestArray() {
var A = [];
for (var k=0; k < gProgressTests.length; k++) {
var t = new Object();
t.setup = tests[0].setup;
t.name = gProgressTests[k].name;
t.type = gProgressTests[k].type;
A.push(t);
}
return A;
}
function startTest(test, token) {
var elemType = /^audio/.test(test.type) ? "audio" : "video";
var element = document.createElement(elemType);
element.src = test.name;
element.token = token;
test.setup(element);
manager.started(token);
}
manager.runTests(createTestArray(), startTest);
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media test: seek test 3</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="manifest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onunload="mediaTestCleanup();">
<pre id="test">
<script class="testbody" type="text/javascript">
function on_metadataloaded() {
var v = document.getElementById('v');
ok(range_equals(v.seekable, v.buffered), "seekable.length should be initialy empty, or equal to buffered");
v.addEventListener("playing", function() {
ok(v.seekable.length > 0, "seekable.length should not be empty while playing.");
}, false);
v.addEventListener("ended", function() {
is(v.seekable.length, 1, "seekable.length should be 1 at end of playback.");
is(v.seekable.start(0), 0.0, "start of first range should 0.0");
is(v.seekable.end(0), v.duration, "end of first range should be equal to duration");
SimpleTest.finish();
}, false);
v.play();
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<video id='v'
src='contentDuration6.sjs'
onloadedmetadata='on_metadataloaded();'></video>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media test: seek test 3</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="manifest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onunload="mediaTestCleanup();">
<pre id="test">
<script class="testbody" type="text/javascript">
function on_metadataloaded() {
var v = document.getElementById('v');
ok(range_equals(v.seekable, v.buffered), "seekable.length should be initialy empty");
v.addEventListener("playing", function() {
ok(v.seekable.length > 0, "seekable.length should not empty while playing.");
}, false);
v.addEventListener("ended", function() {
is(v.seekable.length, 1, "seekable.length should be 1 at end of playback.");
is(v.seekable.start(0), 0.0, "start of first range should 0.0");
is(v.seekable.end(0), v.duration, "end of first range should be equal to duration");
SimpleTest.finish();
}, false);
v.play();
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<video id='v'
src='noContentLength.sjs'
onloadedmetadata='on_metadataloaded();'></video>
</body>
</html>

View File

@ -342,7 +342,6 @@
#include "nsIDOMCRMFObject.h"
#include "nsIControllers.h"
#include "nsISelection.h"
#include "nsISelection3.h"
#include "nsIBoxObject.h"
#ifdef MOZ_XUL
#include "nsITreeSelection.h"
@ -2919,7 +2918,6 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_MAP_BEGIN(Selection, nsISelection)
DOM_CLASSINFO_MAP_ENTRY(nsISelection)
DOM_CLASSINFO_MAP_ENTRY(nsISelection3)
DOM_CLASSINFO_MAP_END
#ifdef MOZ_XUL

View File

@ -57,7 +57,7 @@
#endif
%}
[scriptable, uuid(d8213322-46d8-47ca-a15c-2abae47ddfde)]
[scriptable, uuid(9441effd-fbe1-4f48-aa90-1741c1e390a1)]
interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
{
// error state
@ -89,6 +89,7 @@ interface nsIDOMHTMLMediaElement : nsIDOMHTMLElement
attribute double currentTime;
readonly attribute double duration;
readonly attribute boolean paused;
readonly attribute nsIDOMTimeRanges seekable;
readonly attribute boolean ended;
readonly attribute boolean mozAutoplayEnabled;
attribute boolean autoplay;

View File

@ -46,6 +46,8 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES = \
green.png \
test_bug290026.html \
test_bug291780.html \
test_bug332636.html \
test_bug332636.html^headers^ \
test_bug366682.html \

View File

@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=290026
-->
<head>
<title>Test for Bug 290026</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=290026">Mozilla Bug 290026</a>
<p id="display"></p>
<div id="editor" contenteditable></div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 290026 **/
SimpleTest.waitForExplicitFinish();
var editor = document.getElementById("editor");
editor.innerHTML = '<p></p><ul><li>Item 1</li><li>Item 2</li></ul><p></p>';
editor.focus();
addLoadEvent(function() {
var sel = window.getSelection();
sel.removeAllRanges();
var lis = document.getElementsByTagName("li");
var range = document.createRange();
range.setStart(lis[0], 0);
range.setEnd(lis[1], lis[1].childNodes.length);
sel.addRange(range);
document.execCommand("indent", false, false);
var oneindent = '<p></p><ul style="margin-left: 40px;"><li>Item 1</li><li>Item 2</li></ul><p></p>';
is(editor.innerHTML, oneindent, "a once indented bulleted list");
document.execCommand("indent", false, false);
var twoindent = '<p></p><ul style="margin-left: 80px;"><li>Item 1</li><li>Item 2</li></ul><p></p>';
is(editor.innerHTML, twoindent, "a twice indented bulleted list");
document.execCommand("outdent", false, false);
todo_is(editor.innerHTML, oneindent, "outdenting a twice indented bulleted list");
// done
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,51 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=291780
-->
<head>
<title>Test for Bug 291780</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=291780">Mozilla Bug 291780</a>
<p id="display"></p>
<div id="editor" contenteditable></div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 291780 **/
SimpleTest.waitForExplicitFinish();
var original = '<ul style="margin-left: 40px;"><li>Item 1</li><li>Item 2</li><li>Item 3</li><li>Item 4</li></ul>';
var editor = document.getElementById("editor");
editor.innerHTML = original;
editor.focus();
addLoadEvent(function() {
var sel = window.getSelection();
sel.removeAllRanges();
var lis = document.getElementsByTagName("li");
var range = document.createRange();
range.setStart(lis[1], 0);
range.setEnd(lis[2], lis[2].childNodes.length);
sel.addRange(range);
document.execCommand("indent", false, false);
var expected = '<ul style="margin-left: 40px;"><li>Item 1</li><ul><li>Item 2</li><li>Item 3</li></ul><li>Item 4</li></ul>';
is(editor.innerHTML, expected, "indenting part of an already indented bulleted list");
document.execCommand("outdent", false, false);
todo_is(editor.innerHTML, original, "outdenting the partially indented part of an already indented bulleted list");
// done
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -85,7 +85,7 @@
#include "nsIPrefService.h"
#include "nsIRunnable.h"
#include "nsISelection.h"
#include "nsISelection2.h"
#include "nsISelectionPrivate.h"
#include "nsISelectionController.h"
#include "nsIServiceManager.h"
#include "nsITextServicesFilter.h"
@ -1281,8 +1281,7 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
if (iscollapsed)
return NS_OK;
nsCOMPtr<nsISelection2> sel2 = do_QueryInterface(aSpellCheckSelection, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISelectionPrivate> privSel = do_QueryInterface(aSpellCheckSelection);
// see if the selection has any ranges, if not, then we can optimize checking
// range inclusion later (we have no ranges when we are initially checking or
@ -1347,9 +1346,9 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
createdRange->IsPointInRange(beginNode, beginOffset, &inCreatedRange);
if (! inCreatedRange) {
nsCOMArray<nsIDOMRange> ranges;
rv = sel2->GetRangesForIntervalCOMArray(beginNode, beginOffset,
endNode, endOffset,
PR_TRUE, &ranges);
rv = privSel->GetRangesForIntervalCOMArray(beginNode, beginOffset,
endNode, endOffset,
PR_TRUE, &ranges);
NS_ENSURE_SUCCESS(rv, rv);
for (PRInt32 i = 0; i < ranges.Count(); i ++)
RemoveRange(aSpellCheckSelection, ranges[i]);
@ -1478,13 +1477,11 @@ mozInlineSpellChecker::IsPointInSelection(nsISelection *aSelection,
{
*aRange = nsnull;
nsresult rv;
nsCOMPtr<nsISelection2> sel2 = do_QueryInterface(aSelection, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
nsCOMArray<nsIDOMRange> ranges;
rv = sel2->GetRangesForIntervalCOMArray(aNode, aOffset, aNode, aOffset,
PR_TRUE, &ranges);
nsresult rv = privSel->GetRangesForIntervalCOMArray(aNode, aOffset, aNode, aOffset,
PR_TRUE, &ranges);
NS_ENSURE_SUCCESS(rv, rv);
if (ranges.Count() == 0)

View File

@ -651,12 +651,15 @@ void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
void
gfxFontFamily::FindFontForChar(FontSearch *aMatchData)
{
if (!mHasStyles)
if (!mHasStyles) {
FindStyleVariations();
}
// xxx - optimization point - keep a bit vector with the union of supported unicode ranges
// by all fonts for this family and bail immediately if the character is not in any of
// this family's cmaps
if (!TestCharacterMap(aMatchData->mCh)) {
// none of the faces in the family support the required char,
// so bail out immediately
return;
}
// iterate over fonts
PRUint32 numFonts = mAvailableFonts.Length();
@ -2610,6 +2613,22 @@ gfxFontGroup::FindFontForChar(PRUint32 aCh, PRUint32 aPrevCh,
*aMatchType = gfxTextRange::kFontGroup;
return font.forget();
}
// check other faces of the family
gfxFontFamily *family = font->GetFontEntry()->Family();
if (family && family->TestCharacterMap(aCh)) {
FontSearch matchData(aCh, font);
family->FindFontForChar(&matchData);
gfxFontEntry *fe = matchData.mBestMatch;
if (fe) {
PRBool needsBold =
font->GetStyle()->weight >= 600 && !fe->IsBold();
selectedFont =
fe->FindOrMakeFont(font->GetStyle(), needsBold);
if (selectedFont) {
return selectedFont.forget();
}
}
}
}
// if character is in Private Use Area, don't do matching against pref or system fonts

View File

@ -482,7 +482,8 @@ public:
mFaceNamesInitialized(PR_FALSE),
mHasStyles(PR_FALSE),
mIsSimpleFamily(PR_FALSE),
mIsBadUnderlineFamily(PR_FALSE)
mIsBadUnderlineFamily(PR_FALSE),
mCharacterMapInitialized(PR_FALSE)
{ }
virtual ~gfxFontFamily() { }
@ -544,10 +545,28 @@ public:
// read in cmaps for all the faces
void ReadCMAP() {
PRUint32 i, numFonts = mAvailableFonts.Length();
// called from RunLoader BEFORE CheckForSimpleFamily so that there cannot
// be any NULL entries in mAvailableFonts
for (i = 0; i < numFonts; i++)
mAvailableFonts[i]->ReadCMAP();
for (i = 0; i < numFonts; i++) {
gfxFontEntry *fe = mAvailableFonts[i];
if (!fe) {
continue;
}
fe->ReadCMAP();
mCharacterMap.Union(fe->mCharacterMap);
}
mCharacterMap.Compact();
mCharacterMapInitialized = PR_TRUE;
}
PRBool TestCharacterMap(PRUint32 aCh) {
if (!mCharacterMapInitialized) {
ReadCMAP();
}
return mCharacterMap.test(aCh);
}
void ResetCharacterMap() {
mCharacterMap.reset();
mCharacterMapInitialized = PR_FALSE;
}
// mark this family as being in the "bad" underline offset blacklist
@ -590,12 +609,14 @@ protected:
nsString mName;
nsTArray<nsRefPtr<gfxFontEntry> > mAvailableFonts;
gfxSparseBitSet mCharacterMap;
PRPackedBool mOtherFamilyNamesInitialized;
PRPackedBool mHasOtherFamilyNames;
PRPackedBool mFaceNamesInitialized;
PRPackedBool mHasStyles;
PRPackedBool mIsSimpleFamily;
PRPackedBool mIsBadUnderlineFamily;
PRPackedBool mCharacterMapInitialized;
enum {
// for "simple" families, the faces are stored in mAvailableFonts

View File

@ -313,7 +313,7 @@ gfxFontUtils::ReadCMAPTableFormat12(const PRUint8 *aBuf, PRUint32 aLength,
prevEndCharCode = endCharCode;
}
aCharacterMap.mBlocks.Compact();
aCharacterMap.Compact();
return NS_OK;
}
@ -391,7 +391,7 @@ gfxFontUtils::ReadCMAPTableFormat4(const PRUint8 *aBuf, PRUint32 aLength,
}
}
aCharacterMap.mBlocks.Compact();
aCharacterMap.Compact();
return NS_OK;
}

View File

@ -165,8 +165,6 @@ public:
Block *block = mBlocks[blockIndex];
if (!block) {
block = new Block;
if (NS_UNLIKELY(!block)) // OOM
return;
mBlocks[blockIndex] = block;
}
block->mBits[(aIndex>>3) & (BLOCK_SIZE - 1)] |= 1 << (aIndex & 0x7);
@ -201,9 +199,6 @@ public:
fullBlock = PR_TRUE;
block = new Block(fullBlock ? 0xFF : 0);
if (NS_UNLIKELY(!block)) // OOM
return;
mBlocks[i] = block;
if (fullBlock)
@ -279,7 +274,44 @@ public:
for (i = 0; i < mBlocks.Length(); i++)
mBlocks[i] = nsnull;
}
// set this bitset to the union of its current contents and another
void Union(const gfxSparseBitSet& aBitset) {
// ensure mBlocks is large enough
PRUint32 blockCount = aBitset.mBlocks.Length();
if (blockCount > mBlocks.Length()) {
PRUint32 needed = blockCount - mBlocks.Length();
nsAutoPtr<Block> *blocks = mBlocks.AppendElements(needed);
if (NS_UNLIKELY(!blocks)) { // OOM
return;
}
}
// for each block that may be present in aBitset...
for (PRUint32 i = 0; i < blockCount; ++i) {
// if it is missing (implicitly empty), just skip
if (!aBitset.mBlocks[i]) {
continue;
}
// if the block is missing in this set, just copy the other
if (!mBlocks[i]) {
mBlocks[i] = new Block(*aBitset.mBlocks[i]);
continue;
}
// else set existing block to the union of both
PRUint32 *dst = reinterpret_cast<PRUint32*>(mBlocks[i]->mBits);
const PRUint32 *src =
reinterpret_cast<const PRUint32*>(aBitset.mBlocks[i]->mBits);
for (PRUint32 j = 0; j < BLOCK_SIZE / 4; ++j) {
dst[j] |= src[j];
}
}
}
void Compact() {
mBlocks.Compact();
}
private:
nsTArray< nsAutoPtr<Block> > mBlocks;
};

View File

@ -106,10 +106,12 @@ public:
virtual ~gfxMixedFontFamily() { }
void AddFontEntry(gfxFontEntry *aFontEntry) {
void AddFontEntry(gfxFontEntry *aFontEntry)
{
nsRefPtr<gfxFontEntry> fe = aFontEntry;
mAvailableFonts.AppendElement(fe);
aFontEntry->SetFamily(this);
ResetCharacterMap();
}
void ReplaceFontEntry(gfxFontEntry *aOldFontEntry, gfxFontEntry *aNewFontEntry)
@ -123,9 +125,10 @@ public:
// other reference to it except from its family
mAvailableFonts[i] = aNewFontEntry;
aNewFontEntry->SetFamily(this);
return;
break;
}
}
ResetCharacterMap();
}
void RemoveFontEntry(gfxFontEntry *aFontEntry)
@ -136,9 +139,10 @@ public:
if (fe == aFontEntry) {
aFontEntry->SetFamily(nsnull);
mAvailableFonts.RemoveElementAt(i);
return;
break;
}
}
ResetCharacterMap();
}
// temp method to determine if all proxies are loaded

View File

@ -45,9 +45,9 @@
#
# Define an include-at-most-once flag
#ifdef INCLUDED_CONFIG_MK
#$(error Don't include config.mk twice!)
#endif
ifdef INCLUDED_CONFIG_MK
$(error Don't include config.mk twice!)
endif
INCLUDED_CONFIG_MK = 1
EXIT_ON_ERROR = set -e; # Shell loops continue past errors without this.

View File

@ -334,7 +334,7 @@ case "$target" in
CPPFLAGS="-I$android_platform/usr/include $STLPORT_CPPFLAGS $CPPFLAGS"
CFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CFLAGS"
CXXFLAGS="-mandroid -I$android_platform/usr/include -fno-short-enums -fno-exceptions $CXXFLAGS"
LIBS="$LIBS $STLPORT_LIBS -static-libstdc++"
LIBS="$LIBS $STLPORT_LIBS"
dnl Add -llog by default, since we use it all over the place.
dnl Add --allow-shlib-undefined, because libGLESv2 links to an
@ -357,8 +357,8 @@ case "$target" in
fi
ANDROID_NDK="${android_ndk}"
ANDROID_TOOLCHAIN="{android_toolchain}"
ANDROID_PLATFORM="{android_platform}"
ANDROID_TOOLCHAIN="${android_toolchain}"
ANDROID_PLATFORM="${android_platform}"
ANDROID_SDK="${android_sdk}"
ANDROID_PLATFORM_TOOLS="${android_platform_tools}"
ANDROID_VERSION="${android_version}"

View File

@ -50,7 +50,7 @@ var FOCUS = 1;
function testCollapsed(id, vPercent, startAt, expected) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var selection = window.getSelection().QueryInterface(Components.interfaces.nsISelection2);
var selection = window.getSelection().QueryInterface(Components.interfaces.nsISelectionPrivate);
var c = document.getElementById("c" + id);
var target = document.getElementById("target" + id);

View File

@ -48,9 +48,6 @@
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsFrameSelection.h"
#include "nsISelection.h"
#include "nsISelection2.h"
#include "nsISelection3.h"
#include "nsISelectionPrivate.h"
#include "nsISelectionListener.h"
#include "nsIComponentManager.h"
@ -181,9 +178,7 @@ static RangeData sEmptyData(nsnull);
// This ensures that nsFrameSelection is never deleted before its
// nsTypedSelections.
class nsTypedSelection : public nsISelection2,
public nsISelection3,
public nsISelectionPrivate,
class nsTypedSelection : public nsISelectionPrivate,
public nsSupportsWeakReference
{
public:
@ -192,10 +187,8 @@ public:
virtual ~nsTypedSelection();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTypedSelection, nsISelection)
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsTypedSelection, nsISelectionPrivate)
NS_DECL_NSISELECTION
NS_DECL_NSISELECTION2
NS_DECL_NSISELECTION3
NS_DECL_NSISELECTIONPRIVATE
// utility methods for scrolling the selection into view
@ -3451,8 +3444,6 @@ DOMCI_DATA(Selection, nsTypedSelection)
// QueryInterface implementation for nsTypedSelection
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsTypedSelection)
NS_INTERFACE_MAP_ENTRY(nsISelection)
NS_INTERFACE_MAP_ENTRY(nsISelection2)
NS_INTERFACE_MAP_ENTRY(nsISelection3)
NS_INTERFACE_MAP_ENTRY(nsISelectionPrivate)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelection)

View File

@ -332,11 +332,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
selection.addRange(range8);
intervalChecker.reset();
intervalChecker.addExpected(testNode, 8, 10);
var sel2 = selection.QueryInterface(Components.interfaces.nsISelection2);
ok(sel2, "Test 17 - QIed to instance of nsISelection2 interface");
var privSel = selection.QueryInterface(Components.interfaces.nsISelectionPrivate);
ok(privSel, "Test 17 - QIed to instance of nsISelection2 interface");
var numResults = {};
var results = sel2.GetRangesForInterval(testNode, 8, testNode, 10,
false, numResults);
var results = privSel.GetRangesForInterval(testNode, 8, testNode, 10,
false, numResults);
intervalChecker.check(17, results);
// Test 18. Check GetRangesForInterval returns correct results.
@ -344,16 +344,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.addExpected(testNode, 6, 8);
intervalChecker.addExpected(testNode, 10, 12);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 8, testNode, 10,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 8, testNode, 10,
true, numResults);
intervalChecker.check(18, results);
// Test 19. Check GetRangesForInterval returns correct results.
// Part 3 - Test interval not selected.
intervalChecker.reset();
numResults = {};
results = sel2.GetRangesForInterval(testNode, 14, testNode, 16,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 14, testNode, 16,
true, numResults);
intervalChecker.check(19, results);
// Test 20. Check GetRangesForInterval returns correct results.
@ -364,8 +364,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.reset();
intervalChecker.addExpected(testNode, 0, 10);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 5, testNode, 7,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 5, testNode, 7,
true, numResults);
intervalChecker.check(20, results);
// Test 21. Check GetRangesForInterval returns correct results.
@ -376,8 +376,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.reset();
intervalChecker.addExpected(testNode, 6, 8);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 5, testNode, 9,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 5, testNode, 9,
true, numResults);
intervalChecker.check(21, results);
// Test 22. Check GetRangesForInterval returns correct results.
@ -388,8 +388,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.reset();
intervalChecker.addExpected(testNode, 8, 10);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 6, testNode, 8,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 6, testNode, 8,
true, numResults);
intervalChecker.check(22, results);
// Test 23. Check GetRangesForInterval returns correct results.
@ -397,8 +397,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
// the range array, and adjacencies not permitted.
intervalChecker.reset();
numResults = {};
results = sel2.GetRangesForInterval(testNode, 6, testNode, 8,
false, numResults);
results = privSel.GetRangesForInterval(testNode, 6, testNode, 8,
false, numResults);
intervalChecker.check(23, results);
// Test 24. Check GetRangesForInterval returns correct results.
@ -406,8 +406,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
// and adjacencies permitted.
intervalChecker.addExpected(testNode, 8, 10);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 10, testNode, 12,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 10, testNode, 12,
true, numResults);
intervalChecker.check(24, results);
// Test 25. Check GetRangesForInterval returns correct results.
@ -415,8 +415,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
// and adjacencies not permitted.
intervalChecker.reset();
numResults = {};
results = sel2.GetRangesForInterval(testNode, 10, testNode, 12,
false, numResults);
results = privSel.GetRangesForInterval(testNode, 10, testNode, 12,
false, numResults);
intervalChecker.check(25, results);
// Test 26. Check GetRangesForInterval returns correct results.
@ -426,16 +426,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
selection.addRange(range4);
intervalChecker.addExpected(testNode, 11, 11);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 11, testNode, 11,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
true, numResults);
intervalChecker.check(26, results);
// Test 27. Check GetRangesForInterval returns correct results.
// Part 11 - Test interval is equal to a collapsed range at position 0
// in the range array, and adjacencies not permitted.
numResults = {};
results = sel2.GetRangesForInterval(testNode, 11, testNode, 11,
false, numResults);
results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
false, numResults);
intervalChecker.check(27, results);
// Test 28. Check GetRangesForInterval returns correct results.
@ -445,16 +445,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
selection.addRange(range2);
selection.addRange(range4);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 11, testNode, 11,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
true, numResults);
intervalChecker.check(28, results);
// Test 29. Check GetRangesForInterval returns correct results.
// Part 13 - Test interval is equal to a collapsed range at end of the
// range array, and adjacencies not permitted.
numResults = {};
results = sel2.GetRangesForInterval(testNode, 11, testNode, 11,
false, numResults);
results = privSel.GetRangesForInterval(testNode, 11, testNode, 11,
false, numResults);
intervalChecker.check(29, results);
// Test 30. Check GetRangesForInterval returns correct results.
@ -465,8 +465,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.reset();
intervalChecker.addExpected(testNode, 6, 8);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 7, testNode, 7,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 7, testNode, 7,
true, numResults);
intervalChecker.check(30, results);
// Test 31. Check GetRangesForInterval returns correct results.
@ -481,8 +481,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.reset();
intervalChecker.addExpected(testNode, 8, 8);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 8, testNode, 8,
false, numResults);
results = privSel.GetRangesForInterval(testNode, 8, testNode, 8,
false, numResults);
intervalChecker.check(31, results);
// Test 32. Check GetRangesForInterval returns correct results.
@ -490,16 +490,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
// at either endpoint of the selection's range array,
// adjacencies allowed.
numResults = {};
results = sel2.GetRangesForInterval(testNode, 8, testNode, 8,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 8, testNode, 8,
true, numResults);
intervalChecker.check(32, results);
// Test 33. Check GetRangesForInterval returns correct results.
// Part 17 - Test interval contains a collapsed range which is not
// stored at either endpoint of the selection's range array.
numResults = {};
results = sel2.GetRangesForInterval(testNode, 7, testNode, 9,
false, numResults);
results = privSel.GetRangesForInterval(testNode, 7, testNode, 9,
false, numResults);
intervalChecker.check(33, results);
// Test 34. Check GetRangesForInterval returns correct results.
@ -507,8 +507,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.reset();
intervalChecker.addExpected(testNode, 5, 7);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 2, testNode, 6,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 2, testNode, 6,
true, numResults);
intervalChecker.check(34, results);
// Test 35. Check GetRangesForInterval returns correct results.
@ -518,8 +518,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=348681
intervalChecker.reset();
intervalChecker.addExpected(testNode, 10, 12);
numResults = {};
results = sel2.GetRangesForInterval(testNode, 11, testNode, 13,
true, numResults);
results = privSel.GetRangesForInterval(testNode, 11, testNode, 13,
true, numResults);
intervalChecker.check(35, results);
SimpleTest.finish();

View File

@ -540,9 +540,10 @@ nsMathMLmtableOuterFrame::GetRowFrameAt(nsPresContext* aPresContext,
// Negative indices mean to find upwards from the end.
if (aRowIndex < 0) {
aRowIndex = rowCount + aRowIndex;
} else {
// aRowIndex is 1-based, so convert it to a 0-based index
--aRowIndex;
}
// aRowIndex is 1-based, so convert it to a 0-based index
--aRowIndex;
// if our inner table says that the index is valid, find the row now
if (0 <= aRowIndex && aRowIndex <= rowCount) {

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<head>
<title>mtable align attribute: negative rownumber</title>
</head>
<body>
<div>
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mrow>
<mtable align="axis 3"><mtr><mtd><mi>a</mi></mtd> <mtd><mi>b</mi></mtd> <mtd><mi>c</mi></mtd></mtr> <mtr><mtd><mi>d</mi></mtd> <mtd><mi>e</mi></mtd> <mtd><mi>f</mi></mtd></mtr> <mtr><mtd><mi>g</mi></mtd> <mtd><mi>h</mi></mtd> <mtd><mi>i</mi></mtd></mtr></mtable><mo>=</mo>
<mtable align="axis 1"><mtr><mtd><mi>a</mi></mtd> <mtd><mi>b</mi></mtd> <mtd><mi>c</mi></mtd></mtr> <mtr><mtd><mi>d</mi></mtd> <mtd><mi>e</mi></mtd> <mtd><mi>f</mi></mtd></mtr> <mtr><mtd><mi>g</mi></mtd> <mtd><mi>h</mi></mtd> <mtd><mi>i</mi></mtd></mtr></mtable></mrow></math>
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<head>
<title>mtable align attribute: negative rownumber</title>
</head>
<body>
<div>
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><mrow>
<mtable align="axis -1"><mtr><mtd><mi>a</mi></mtd> <mtd><mi>b</mi></mtd> <mtd><mi>c</mi></mtd></mtr> <mtr><mtd><mi>d</mi></mtd> <mtd><mi>e</mi></mtd> <mtd><mi>f</mi></mtd></mtr> <mtr><mtd><mi>g</mi></mtd> <mtd><mi>h</mi></mtd> <mtd><mi>i</mi></mtd></mtr></mtable><mo>=</mo>
<mtable align="axis 1"><mtr><mtd><mi>a</mi></mtd> <mtd><mi>b</mi></mtd> <mtd><mi>c</mi></mtd></mtr> <mtr><mtd><mi>d</mi></mtd> <mtd><mi>e</mi></mtd> <mtd><mi>f</mi></mtd></mtr> <mtr><mtd><mi>g</mi></mtd> <mtd><mi>h</mi></mtd> <mtd><mi>i</mi></mtd></mtr></mtable></mrow></math>
</div>
</body>
</html>

View File

@ -26,6 +26,7 @@ fails-if(winWidget) == mfenced-10.html mfenced-10-ref.html
== table-width-1.xhtml table-width-1-ref.xhtml
== underbar-width-1.xhtml underbar-width-1-ref.xhtml
== mathml-type-supported.xhtml mathml-type-supported-ref.xml
== mtable-align-negative-rownumber.html mtable-align-negative-rownumber-ref.html
!= embellished-op-1-1.html embellished-op-1-1-ref.html
!= embellished-op-1-2.html embellished-op-1-2-ref.html
!= embellished-op-1-3.html embellished-op-1-3-ref.html

View File

@ -92,6 +92,7 @@ nsFontFaceLoader::nsFontFaceLoader(gfxProxyFontEntry *aProxy, nsIURI *aFontURI,
: mFontEntry(aProxy), mFontURI(aFontURI), mFontSet(aFontSet),
mChannel(aChannel)
{
mFontFamily = aProxy->Family();
}
nsFontFaceLoader::~nsFontFaceLoader()

View File

@ -145,6 +145,7 @@ public:
private:
nsRefPtr<gfxProxyFontEntry> mFontEntry;
nsRefPtr<gfxFontFamily> mFontFamily;
nsCOMPtr<nsIURI> mFontURI;
nsRefPtr<nsUserFontSet> mFontSet;
nsCOMPtr<nsIChannel> mChannel;

View File

@ -573,7 +573,7 @@ WebSocketChannel::WebSocketChannel() :
mStopOnClose(NS_OK),
mServerCloseCode(CLOSE_ABNORMAL),
mScriptCloseCode(0),
mFragmentOpcode(0),
mFragmentOpcode(kContinuation),
mFragmentAccumulator(0),
mBuffered(0),
mBufferSize(16384),
@ -863,7 +863,7 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count)
// Only the first frame has a non zero op code: Make sure we don't see a
// first frame while some old fragments are open
if ((mFragmentAccumulator != 0) && (opcode != kContinuation)) {
LOG(("WebSocketHeandler:: nested fragments\n"));
LOG(("WebSocketChannel:: nested fragments\n"));
AbortSession(NS_ERROR_ILLEGAL_VALUE);
return NS_ERROR_ILLEGAL_VALUE;
}
@ -871,6 +871,14 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count)
LOG(("WebSocketChannel:: Accumulating Fragment %lld\n", payloadLength));
if (opcode == kContinuation) {
// Make sure this continuation fragment isn't the first fragment
if (mFragmentOpcode == kContinuation) {
LOG(("WebSocketHeandler:: continuation code in first fragment\n"));
AbortSession(NS_ERROR_ILLEGAL_VALUE);
return NS_ERROR_ILLEGAL_VALUE;
}
// For frag > 1 move the data body back on top of the headers
// so we have contiguous stream of data
NS_ABORT_IF_FALSE(mFramePtr + framingLength == payload,
@ -890,6 +898,8 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count)
avail += mFragmentAccumulator;
mFragmentAccumulator = 0;
opcode = mFragmentOpcode;
// reset to detect if next message illegally starts with continuation
mFragmentOpcode = kContinuation;
} else {
opcode = kContinuation;
mFragmentAccumulator += payloadLength;

View File

@ -257,11 +257,11 @@ DEFAULT_GMAKE_FLAGS += \
CPU_ARCH="$(TARGET_CPU)" \
$(NULL)
# Android has pthreads integrated into -lc, so OS_LIBS is set to nothing
# Android has pthreads integrated into -lc, so OS_PTHREAD is set to nothing
ifeq ($(OS_TARGET), Android)
DEFAULT_GMAKE_FLAGS += \
OS_RELEASE="2.6" \
OS_LIBS= \
OS_PTHREAD= \
STANDARDS_CFLAGS="-std=gnu89" \
DSO_CFLAGS="$(CFLAGS) -DCHECK_FORK_GETPID -DRTLD_NOLOAD=0 -DANDROID_VERSION=$(ANDROID_VERSION) -include $(ABS_topsrcdir)/security/manager/android_stub.h" \
DSO_LDOPTS="-shared $(LDFLAGS) $(WRAP_MALLOC_CFLAGS) $(WRAP_MALLOC_LIB) " \

View File

@ -1294,7 +1294,7 @@ BookmarksTracker.prototype = {
this._log.debug("Restore succeeded: wiping server and other clients.");
Weave.Service.resetClient([this.name]);
Weave.Service.wipeServer([this.name]);
Weave.Service.prepCommand("wipeEngine", [this.name]);
Clients.sendCommand("wipeEngine", [this.name]);
break;
case "bookmarks-restore-failed":
this._log.debug("Tracking all items on failed import.");

View File

@ -48,6 +48,7 @@ Cu.import("resource://services-sync/ext/StringBundle.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/resource.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://services-sync/main.js");
const CLIENTS_TTL = 1814400; // 21 days
const CLIENTS_TTL_REFRESH = 604800; // 7 days
@ -107,41 +108,6 @@ ClientEngine.prototype = {
return stats;
},
// Remove any commands for the local client and mark it for upload
clearCommands: function clearCommands() {
delete this.localCommands;
this._tracker.addChangedID(this.localID);
},
// Send a command+args pair to each remote client
sendCommand: function sendCommand(command, args) {
// Helper to determine if the client already has this command
let notDupe = function(other) other.command != command ||
JSON.stringify(other.args) != JSON.stringify(args);
// Package the command/args pair into an object
let action = {
command: command,
args: args,
};
// Send the command to each remote client
for (let [id, client] in Iterator(this._store._remoteClients)) {
// Set the action to be a new commands array if none exists
if (client.commands == null)
client.commands = [action];
// Add the new action if there are no duplicates
else if (client.commands.every(notDupe))
client.commands.push(action);
// Must have been a dupe.. skip!
else
continue;
this._log.trace("Client " + id + " got a new action: " + [command, args]);
this._tracker.addChangedID(id);
}
},
get localID() {
// Generate a random GUID id we don't have one
let localID = Svc.Prefs.get("client.GUID", "");
@ -221,6 +187,149 @@ ClientEngine.prototype = {
// Neither try again nor error; we're going to delete it.
return SyncEngine.kRecoveryStrategy.ignore;
},
/**
* A hash of valid commands that the client knows about. The key is a command
* and the value is a hash containing information about the command such as
* number of arguments and description.
*/
_commands: {
resetAll: { args: 0, desc: "Clear temporary local data for all engines" },
resetEngine: { args: 1, desc: "Clear temporary local data for engine" },
wipeAll: { args: 0, desc: "Delete all client data for all engines" },
wipeEngine: { args: 1, desc: "Delete all client data for engine" },
logout: { args: 0, desc: "Log out client" }
},
/**
* Remove any commands for the local client and mark it for upload.
*/
clearCommands: function clearCommands() {
delete this.localCommands;
this._tracker.addChangedID(this.localID);
},
/**
* Sends a command+args pair to a specific client.
*
* @param command Command string
* @param args Array of arguments/data for command
* @param clientId Client to send command to
*/
_sendCommandToClient: function sendCommandToClient(command, args, clientId) {
this._log.trace("Sending " + command + " to " + clientId);
let client = this._store._remoteClients[clientId];
if (!client) {
throw new Error("Unknown remote client ID: '" + clientId + "'.");
}
// notDupe compares two commands and returns if they are not equal.
let notDupe = function(other) {
return other.command != command || !Utils.deepEquals(other.args, args);
};
let action = {
command: command,
args: args,
};
if (!client.commands) {
client.commands = [action];
}
// Add the new action if there are no duplicates.
else if (client.commands.every(notDupe)) {
client.commands.push(action);
}
// It must be a dupe. Skip.
else {
return;
}
this._log.trace("Client " + clientId + " got a new action: " + [command, args]);
this._tracker.addChangedID(clientId);
},
/**
* Check if the local client has any remote commands and perform them.
*
* @return false to abort sync
*/
processIncomingCommands: function processIncomingCommands() {
return this._notify("clients:process-commands", "", function() {
let commands = this.localCommands;
// Immediately clear out the commands as we've got them locally.
this.clearCommands();
// Process each command in order.
for each ({command: command, args: args} in commands) {
this._log.debug("Processing command: " + command + "(" + args + ")");
let engines = [args[0]];
switch (command) {
case "resetAll":
engines = null;
// Fallthrough
case "resetEngine":
Weave.Service.resetClient(engines);
break;
case "wipeAll":
engines = null;
// Fallthrough
case "wipeEngine":
Weave.Service.wipeClient(engines);
break;
case "logout":
Weave.Service.logout();
return false;
default:
this._log.debug("Received an unknown command: " + command);
break;
}
}
return true;
})();
},
/**
* Validates and sends a command to a client or all clients.
*
* Calling this does not actually sync the command data to the server. If the
* client already has the command/args pair, it won't receive a duplicate
* command.
*
* @param command
* Command to invoke on remote clients
* @param args
* Array of arguments to give to the command
* @param clientId
* Client ID to send command to. If undefined, send to all remote
* clients.
*/
sendCommand: function sendCommand(command, args, clientId) {
let commandData = this._commands[command];
// Don't send commands that we don't know about.
if (!commandData) {
this._log.error("Unknown command to send: " + command);
return;
}
// Don't send a command with the wrong number of arguments.
else if (!args || args.length != commandData.args) {
this._log.error("Expected " + commandData.args + " args for '" +
command + "', but got " + args);
return;
}
if (clientId) {
this._sendCommandToClient(command, args, clientId);
} else {
for (let id in this._store._remoteClients) {
this._sendCommandToClient(command, args, id);
}
}
}
};

View File

@ -22,6 +22,7 @@
* Dan Mills <thunder@mozilla.com>
* Philipp von Weitershausen <philipp@weitershausen.de>
* Richard Newman <rnewman@mozilla.com>
* Allison Naaktgeboren <ally@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -253,8 +254,8 @@ HistoryStore.prototype = {
}
let cb = Async.makeSyncCallback();
let onPlace = function onPlace(result, placeInfo) {
if (!Components.isSuccessCode(result)) {
let updatePlacesCallback = {
handleError: function handleError(resultCode, placeInfo) {
failed.push(placeInfo.guid);
}
};
@ -263,7 +264,7 @@ HistoryStore.prototype = {
cb();
};
Svc.Obs.add(TOPIC_UPDATEPLACES_COMPLETE, onComplete);
this._asyncHistory.updatePlaces(records, onPlace);
this._asyncHistory.updatePlaces(records, updatePlacesCallback);
Async.waitForSyncCallback(cb);
return failed;
},

View File

@ -1461,10 +1461,9 @@ WeaveSvc.prototype = {
break;
}
// Process the incoming commands if we have any
if (Clients.localCommands) {
try {
if (!(this.processCommands())) {
if (!(Clients.processIncomingCommands())) {
Status.sync = ABORT_SYNC_COMMAND;
throw "aborting sync, process commands said so";
}
@ -1817,20 +1816,22 @@ WeaveSvc.prototype = {
*/
wipeRemote: function WeaveSvc_wipeRemote(engines)
this._catch(this._notify("wipe-remote", "", function() {
// Make sure stuff gets uploaded
// Make sure stuff gets uploaded.
this.resetClient(engines);
// Clear out any server data
// Clear out any server data.
this.wipeServer(engines);
// Only wipe the engines provided
if (engines)
engines.forEach(function(e) this.prepCommand("wipeEngine", [e]), this);
// Tell the remote machines to wipe themselves
else
this.prepCommand("wipeAll", []);
// Only wipe the engines provided.
if (engines) {
engines.forEach(function(e) Clients.sendCommand("wipeEngine", [e]), this);
}
// Tell the remote machines to wipe themselves.
else {
Clients.sendCommand("wipeAll", []);
}
// Make sure the changed clients get updated
// Make sure the changed clients get updated.
Clients.sync();
}))(),
@ -1871,104 +1872,16 @@ WeaveSvc.prototype = {
engine.resetClient();
}))(),
/**
* A hash of valid commands that the client knows about. The key is a command
* and the value is a hash containing information about the command such as
* number of arguments and description.
*/
_commands: [
["resetAll", 0, "Clear temporary local data for all engines"],
["resetEngine", 1, "Clear temporary local data for engine"],
["wipeAll", 0, "Delete all client data for all engines"],
["wipeEngine", 1, "Delete all client data for engine"],
["logout", 0, "Log out client"],
].reduce(function WeaveSvc__commands(commands, entry) {
commands[entry[0]] = {};
for (let [i, attr] in Iterator(["args", "desc"]))
commands[entry[0]][attr] = entry[i + 1];
return commands;
}, {}),
/**
* Check if the local client has any remote commands and perform them.
*
* @return False to abort sync
*/
processCommands: function WeaveSvc_processCommands()
this._notify("process-commands", "", function() {
// Immediately clear out the commands as we've got them locally
let commands = Clients.localCommands;
Clients.clearCommands();
// Process each command in order
for each ({command: command, args: args} in commands) {
this._log.debug("Processing command: " + command + "(" + args + ")");
let engines = [args[0]];
switch (command) {
case "resetAll":
engines = null;
// Fallthrough
case "resetEngine":
this.resetClient(engines);
break;
case "wipeAll":
engines = null;
// Fallthrough
case "wipeEngine":
this.wipeClient(engines);
break;
case "logout":
this.logout();
return false;
default:
this._log.debug("Received an unknown command: " + command);
break;
}
}
return true;
})(),
/**
* Prepare to send a command to each remote client. Calling this doesn't
* actually sync the command data to the server. If the client already has
* the command/args pair, it won't get a duplicate action.
*
* @param command
* Command to invoke on remote clients
* @param args
* Array of arguments to give to the command
*/
prepCommand: function WeaveSvc_prepCommand(command, args) {
let commandData = this._commands[command];
// Don't send commands that we don't know about
if (commandData == null) {
this._log.error("Unknown command to send: " + command);
return;
}
// Don't send a command with the wrong number of arguments
else if (args == null || args.length != commandData.args) {
this._log.error("Expected " + commandData.args + " args for '" +
command + "', but got " + args);
return;
}
// Send the command to all remote clients
this._log.debug("Sending clients: " + [command, args, commandData.desc]);
Clients.sendCommand(command, args);
},
/**
* Fetch storage info from the server.
*
*
* @param type
* String specifying what info to fetch from the server. Must be one
* of the INFO_* values. See Sync Storage Server API spec for details.
* @param callback
* Callback function with signature (error, data) where `data' is
* the return value from the server already parsed as JSON.
*
*
* @return RESTRequest instance representing the request, allowing callers
* to cancel the request.
*/

View File

@ -239,6 +239,216 @@ add_test(function test_client_name_change() {
run_next_test();
});
add_test(function test_send_command() {
_("Verifies _sendCommandToClient puts commands in the outbound queue.");
let store = Clients._store;
let tracker = Clients._tracker;
let remoteId = Utils.makeGUID();
let rec = new ClientsRec("clients", remoteId);
store.create(rec);
let remoteRecord = store.createRecord(remoteId, "clients");
let action = "testCommand";
let args = ["foo", "bar"];
Clients._sendCommandToClient(action, args, remoteId);
let newRecord = store._remoteClients[remoteId];
do_check_neq(newRecord, undefined);
do_check_eq(newRecord.commands.length, 1);
let command = newRecord.commands[0];
do_check_eq(command.command, action);
do_check_eq(command.args.length, 2);
do_check_eq(command.args, args);
do_check_neq(tracker.changedIDs[remoteId], undefined);
run_next_test();
});
add_test(function test_command_validation() {
_("Verifies that command validation works properly.");
let store = Clients._store;
let testCommands = [
["resetAll", [], true ],
["resetAll", ["foo"], false],
["resetEngine", ["tabs"], true ],
["resetEngine", [], false],
["wipeAll", [], true ],
["wipeAll", ["foo"], false],
["wipeEngine", ["tabs"], true ],
["wipeEngine", [], false],
["logout", [], true ],
["logout", ["foo"], false],
["__UNKNOWN__", [], false]
];
for each (let [action, args, expectedResult] in testCommands) {
let remoteId = Utils.makeGUID();
let rec = new ClientsRec("clients", remoteId);
store.create(rec);
store.createRecord(remoteId, "clients");
Clients.sendCommand(action, args, remoteId);
let newRecord = store._remoteClients[remoteId];
do_check_neq(newRecord, undefined);
if (expectedResult) {
_("Ensuring command is sent: " + action);
do_check_eq(newRecord.commands.length, 1);
let command = newRecord.commands[0];
do_check_eq(command.command, action);
do_check_eq(command.args, args);
do_check_neq(Clients._tracker, undefined);
do_check_neq(Clients._tracker.changedIDs[remoteId], undefined);
} else {
_("Ensuring command is scrubbed: " + action);
do_check_eq(newRecord.commands, undefined);
if (store._tracker) {
do_check_eq(Clients._tracker[remoteId], undefined);
}
}
}
run_next_test();
});
add_test(function test_command_duplication() {
_("Ensures duplicate commands are detected and not added");
let store = Clients._store;
let remoteId = Utils.makeGUID();
let rec = new ClientsRec("clients", remoteId);
store.create(rec);
store.createRecord(remoteId, "clients");
let action = "resetAll";
let args = [];
Clients.sendCommand(action, args, remoteId);
Clients.sendCommand(action, args, remoteId);
let newRecord = store._remoteClients[remoteId];
do_check_eq(newRecord.commands.length, 1);
_("Check variant args length");
newRecord.commands = [];
action = "resetEngine";
Clients.sendCommand(action, [{ x: "foo" }], remoteId);
Clients.sendCommand(action, [{ x: "bar" }], remoteId);
_("Make sure we spot a real dupe argument.");
Clients.sendCommand(action, [{ x: "bar" }], remoteId);
do_check_eq(newRecord.commands.length, 2);
run_next_test();
});
add_test(function test_command_invalid_client() {
_("Ensures invalid client IDs are caught");
let id = Utils.makeGUID();
let error;
try {
Clients.sendCommand("wipeAll", [], id);
} catch (ex) {
error = ex;
}
do_check_eq(error.message.indexOf("Unknown remote client ID: "), 0);
run_next_test();
});
add_test(function test_process_incoming_commands() {
_("Ensures local commands are executed");
Clients.localCommands = [{ command: "logout", args: [] }];
let ev = "weave:service:logout:finish";
var handler = function() {
Svc.Obs.remove(ev, handler);
run_next_test();
};
Svc.Obs.add(ev, handler);
// logout command causes processIncomingCommands to return explicit false.
do_check_false(Clients.processIncomingCommands());
});
add_test(function test_command_sync() {
_("Ensure that commands are synced across clients.");
Svc.Prefs.set("clusterURL", "http://localhost:8080/");
Svc.Prefs.set("username", "foo");
generateNewKeys();
let global = new ServerWBO('global',
{engines: {clients: {version: Clients.version,
syncID: Clients.syncID}}});
let coll = new ServerCollection();
let clientwbo = coll.wbos[Clients.localID] = new ServerWBO(Clients.localID);
let server = httpd_setup({
"/1.1/foo/storage/meta/global": global.handler(),
"/1.1/foo/storage/clients": coll.handler()
});
let remoteId = Utils.makeGUID();
let remotewbo = coll.wbos[remoteId] = new ServerWBO(remoteId);
server.registerPathHandler(
"/1.1/foo/storage/clients/" + Clients.localID, clientwbo.handler());
server.registerPathHandler(
"/1.1/foo/storage/clients/" + remoteId, remotewbo.handler());
_("Create remote client record");
let rec = new ClientsRec("clients", remoteId);
Clients._store.create(rec);
let remoteRecord = Clients._store.createRecord(remoteId, "clients");
Clients.sendCommand("wipeAll", []);
let clientRecord = Clients._store._remoteClients[remoteId];
do_check_neq(clientRecord, undefined);
do_check_eq(clientRecord.commands.length, 1);
try {
Clients.sync();
do_check_neq(clientwbo.payload, undefined);
do_check_true(Clients.lastRecordUpload > 0);
do_check_neq(remotewbo.payload, undefined);
Svc.Prefs.set("client.GUID", remoteId);
Clients._resetClient();
do_check_eq(Clients.localID, remoteId);
Clients.sync();
do_check_neq(Clients.localCommands, undefined);
do_check_eq(Clients.localCommands.length, 1);
let command = Clients.localCommands[0];
do_check_eq(command.command, "wipeAll");
do_check_eq(command.args.length, 0);
} finally {
Svc.Prefs.resetBranch("");
Records.clearCache();
server.stop(run_next_test);
}
});
function run_test() {
initTestLogging("Trace");
Log4Moz.repository.getLogger("Sync.Engine.Clients").level = Log4Moz.Level.Trace;

21
testing/tps/INSTALL.sh Normal file → Executable file
View File

@ -55,13 +55,27 @@ fi
# install TPS
cd ${CWD}
python setup.py develop
python setup.py install
if [ "$?" -gt 0 ]
then
exit 1
fi
CONFIG="`find ${VIRTUAL_ENV} -name config.json.in`"
NEWCONFIG=${CONFIG:0:${#CONFIG}-3}
cd "../../services/sync/tests/tps"
TESTDIR="`pwd`"
cd "../../tps"
EXTDIR="`pwd`"
sed 's|__TESTDIR__|'"${TESTDIR}"'|' "${CONFIG}" | sed 's|__EXTENSIONDIR__|'"${EXTDIR}"'|' > "${NEWCONFIG}"
rm ${CONFIG}
echo
echo "***********************************************************************"
echo
echo "To run TPS, activate the virtualenv using:"
echo " source ${TARGET}/${BIN_NAME}"
@ -69,3 +83,8 @@ echo "then execute tps using:"
echo " runtps --binary=/path/to/firefox"
echo
echo "See runtps --help for all options"
echo
echo "To change your TPS config, please edit the file: "
echo "${NEWCONFIG}"
echo
echo "***********************************************************************"

View File

@ -0,0 +1,7 @@
To edit the TPS configuration, do not edit config.json.in in the tree.
Instead, edit config.json inside your virtualenv; it will be located at
something like:
(linux): /path/to/virtualenv/lib/python2.6/site-packages/tps-0.2.40-py2.6.egg/tps/config.json
(win): /path/to/virtualenv/Lib/site-packages/tps-0.2.40-py2.6.egg/tps/config.json

View File

@ -18,6 +18,8 @@
},
"platform": "win32",
"os": "win7",
"es": "localhost:9200"
"es": "localhost:9200",
"testdir": "__TESTDIR__",
"extensiondir": "__EXTENSIONDIR__"
}

View File

@ -58,7 +58,7 @@ setup(name='tps',
keywords='',
author='Jonathan Griffin',
author_email='jgriffin@mozilla.com',
url='http://hg.mozilla.org/services/tps',
url='http://hg.mozilla.org/services/services-central',
license='MPL',
dependency_links = [
"http://people.mozilla.org/~jgriffin/packages/"
@ -72,4 +72,7 @@ setup(name='tps',
[console_scripts]
runtps = tps.cli:main
""",
data_files=[
('tps', ['config/config.json.in']),
],
)

View File

@ -38,6 +38,7 @@
import json
import optparse
import os
import sys
import logging
from threading import RLock
@ -76,7 +77,7 @@ def main():
"will be searched;")
parser.add_option("--configfile",
action = "store", type = "string", dest = "configfile",
default = "config.json",
default = None,
help = "path to the config file to use "
"[default: %default]")
parser.add_option("--pulsefile",
@ -86,15 +87,33 @@ def main():
"json format that you want to inject into the monitor")
(options, args) = parser.parse_args()
configfile = options.configfile
if configfile is None:
if os.environ.get('VIRTUAL_ENV'):
configfile = os.path.join(os.path.dirname(__file__), 'config.json')
else:
raise Exception("Unable to find config.json in a VIRTUAL_ENV; you must "
"specify a config file using the --configfile option")
# load the config file
f = open(options.configfile, 'r')
f = open(configfile, 'r')
configcontent = f.read()
f.close()
config = json.loads(configcontent)
rlock = RLock()
extensionDir = os.path.join(os.getcwd(), "..", "..", "services", "sync", "tps")
extensionDir = config.get("extensiondir")
if not extensionDir or extensionDir == '__EXTENSIONDIR__':
extensionDir = os.path.join(os.getcwd(), "..", "..", "services", "sync", "tps")
else:
if sys.platform == 'win32':
# replace msys-style paths with proper Windows paths
import re
m = re.match('^\/\w\/', extensionDir)
if m:
extensionDir = "%s:/%s" % (m.group(0)[1:2], extensionDir[3:])
extensionDir = extensionDir.replace("/", "\\")
if options.binary is None:
# If no binary is specified, start the pulse build monitor, and wait

View File

@ -53,7 +53,7 @@
#include "nsIServiceManager.h"
#include "nsIDOMWindow.h"
#include "nsIWindowWatcher.h"
#include "nsDependentString.h"
#include "nsPromiseFlatString.h"
#include "nsWidgetsCID.h"
#include "nsILookAndFeel.h"
#include "nsToolkitCompsCID.h"
@ -85,7 +85,7 @@ NS_IMETHODIMP nsAlertsService::ShowAlertNotification(const nsAString & aImageUrl
ContentChild* cpc = ContentChild::GetSingleton();
if (aAlertListener)
cpc->AddRemoteAlertObserver(nsDependentString(aAlertCookie), aAlertListener);
cpc->AddRemoteAlertObserver(PromiseFlatString(aAlertCookie), aAlertListener);
cpc->SendShowAlertNotification(nsAutoString(aImageUrl),
nsAutoString(aAlertTitle),

View File

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Allison Naaktgeboren <ally@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -566,8 +567,13 @@ public:
nsCOMPtr<mozIPlaceInfo> place =
new PlaceInfo(mPlace.placeId, mPlace.guid, uri.forget(), mPlace.title,
-1, visits);
if (NS_SUCCEEDED(mResult)) {
(void)mCallback->HandleResult(place);
}
else {
(void)mCallback->HandleError(mResult, place);
}
(void)mCallback->OnComplete(mResult, place);
return NS_OK;
}

View File

@ -122,20 +122,31 @@ interface mozIPlaceInfo : nsISupports
/**
* @status EXPERIMENTAL
*/
[scriptable,function, uuid(3b97ca3c-5ea8-424f-b429-797477c52302)]
[scriptable, uuid(eb0b406f-8f57-4f2b-b0da-8883684b138a)]
interface mozIVisitInfoCallback : nsISupports
{
/**
* Called for each visit added, title change, or guid change when passed to
* mozIAsyncHistory::updatePlaces.
* Called when the given mozIPlaceInfo object could not be processed.
*
* @param aResultCode
* nsresult of the change indicating success or failure reason.
* nsresult indicating the failure reason.
* @param aPlaceInfo
* The information that was being entered into the database.
*/
void onComplete(in nsresult aResultCode,
in mozIPlaceInfo aPlaceInfo);
void handleError(in nsresult aResultCode,
in mozIPlaceInfo aPlaceInfo);
/**
* Called for each visit added, title change, or guid change when passed to
* mozIAsyncHistory::updatePlaces. If more than one operation is done for
* a given visit, only one callback will be given (i.e. title change and
* add visit).
*
* @param aPlaceInfo
* The information that was being entered into the database.
*/
void handleResult(in mozIPlaceInfo aPlaceInfo);
};
/**
@ -152,9 +163,8 @@ interface mozIAsyncHistory : nsISupports
* The mozIPlaceInfo object[s] containing the information to store or
* update. This can be a single object, or an array of objects.
* @param [optional] aCallback
* Callback to be notified for each visit addition, title change, or
* guid change. If more than one operation is done for a given visit,
* only one callback will be given (i.e. title change and add visit).
* A mozIVisitInfoCallback object which consists of callbacks to be
* notified for successful and/or failed changes.
*
* @throws NS_ERROR_INVALID_ARG
* - Passing in NULL for aPlaceInfo.

View File

@ -159,6 +159,38 @@ function do_check_title_for_uri(aURI,
stmt.finalize();
}
/**
* Default callback handler throws when success is unexpected.
*
* @param handleErrorFunc
* The error handling function
*/
function expectHandleError(handleErrorFunc)
{
return {
handleError: handleErrorFunc,
handleResult: function handleResult(aPlaceInfo) {
do_throw("Unexpected success.");
}
};
}
/**
* Default callback handler throws when failure is unexpected.
*
* @param handleResultFunc
* The success handling function
*/
function expectHandleResult(handleResultFunc)
{
return {
handleError: function handleError(aResultCode, aPlacesInfo) {
do_throw("Unexpected error: " + aResultCode);
},
handleResult: handleResultFunc
};
}
////////////////////////////////////////////////////////////////////////////////
//// Test Functions
@ -422,7 +454,7 @@ function test_non_addable_uri_errors()
});
let callbackCount = 0;
gHistory.updatePlaces(places, function(aResultCode, aPlaceInfo) {
gHistory.updatePlaces(places, expectHandleError(function(aResultCode, aPlaceInfo) {
do_log_info("Checking '" + aPlaceInfo.uri.spec + "'");
do_check_eq(aResultCode, Cr.NS_ERROR_INVALID_ARG);
do_check_false(gGlobalHistory.isVisited(aPlaceInfo.uri));
@ -431,7 +463,7 @@ function test_non_addable_uri_errors()
if (++callbackCount == places.length) {
waitForAsyncUpdates(run_next_test);
}
});
}));
}
function test_duplicate_guid_errors()
@ -446,8 +478,7 @@ function test_duplicate_guid_errors()
};
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_true(gGlobalHistory.isVisited(place.uri));
let badPlace = {
@ -459,13 +490,13 @@ function test_duplicate_guid_errors()
};
do_check_false(gGlobalHistory.isVisited(badPlace.uri));
gHistory.updatePlaces(badPlace, function(aResultCode, aPlaceInfo) {
gHistory.updatePlaces(badPlace, expectHandleError(function(aResultCode, aPlaceInfo) {
do_check_eq(aResultCode, Cr.NS_ERROR_STORAGE_CONSTRAINT);
do_check_false(gGlobalHistory.isVisited(badPlace.uri));
waitForAsyncUpdates(run_next_test);
});
});
}));
}));
}
function test_invalid_referrerURI_ignored()
@ -481,8 +512,7 @@ function test_invalid_referrerURI_ignored()
do_check_false(gGlobalHistory.isVisited(place.uri));
do_check_false(gGlobalHistory.isVisited(place.visits[0].referrerURI));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
@ -501,7 +531,7 @@ function test_invalid_referrerURI_ignored()
stmt.finalize();
waitForAsyncUpdates(run_next_test);
});
}));
}
function test_nonnsIURI_referrerURI_ignored()
@ -516,8 +546,7 @@ function test_nonnsIURI_referrerURI_ignored()
place.visits[0].referrerURI = place.uri.spec + "_nonnsIURI";
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
@ -533,7 +562,7 @@ function test_nonnsIURI_referrerURI_ignored()
stmt.finalize();
waitForAsyncUpdates(run_next_test);
});
}));
}
function test_invalid_sessionId_ignored()
@ -548,8 +577,7 @@ function test_invalid_sessionId_ignored()
place.visits[0].sessionId = -1;
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
@ -569,7 +597,7 @@ function test_invalid_sessionId_ignored()
stmt.finalize();
waitForAsyncUpdates(run_next_test);
});
}));
}
function test_unstored_sessionId_ignored()
@ -595,8 +623,7 @@ function test_unstored_sessionId_ignored()
place.visits[0].sessionId = maxSessionId + 10;
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
@ -618,7 +645,7 @@ function test_unstored_sessionId_ignored()
stmt.finalize();
waitForAsyncUpdates(run_next_test);
});
}));
}
@ -638,11 +665,10 @@ function test_old_referrer_ignored()
// First we must add our referrer to the history so that it is not ignored
// as being invalid.
do_check_false(gGlobalHistory.isVisited(referrerPlace.uri));
gHistory.updatePlaces(referrerPlace, function(aResultCode, aPlaceInfo) {
gHistory.updatePlaces(referrerPlace, expectHandleResult(function(aPlaceInfo) {
// Now that the referrer is added, we can add a page with a valid
// referrer to determine if the recency of the referrer is taken into
// account.
do_check_true(Components.isSuccessCode(aResultCode));
do_check_true(gGlobalHistory.isVisited(referrerPlace.uri));
let visitInfo = new VisitInfo();
@ -655,8 +681,7 @@ function test_old_referrer_ignored()
};
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult (function(aPlaceInfo) {
do_check_true(gGlobalHistory.isVisited(place.uri));
// Though the visit will not contain the referrer, we must examine the
@ -674,8 +699,8 @@ function test_old_referrer_ignored()
stmt.finalize();
waitForAsyncUpdates(run_next_test);
});
});
}));
}));
}
function test_place_id_ignored()
@ -688,8 +713,7 @@ function test_place_id_ignored()
};
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_true(gGlobalHistory.isVisited(place.uri));
let placeId = aPlaceInfo.placeId;
@ -704,15 +728,18 @@ function test_place_id_ignored()
};
do_check_false(gGlobalHistory.isVisited(badPlace.uri));
gHistory.updatePlaces(badPlace, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(badPlace, {
handleResult: function handleResult(aPlaceInfo) {
do_check_neq(aPlaceInfo.placeId, placeId);
do_check_true(gGlobalHistory.isVisited(badPlace.uri));
do_check_neq(aPlaceInfo.placeId, placeId);
do_check_true(gGlobalHistory.isVisited(badPlace.uri));
waitForAsyncUpdates(run_next_test);
waitForAsyncUpdates(run_next_test);
},
handleError: function handleError(aResultCode) {
do_throw("Unexpected error: " + aResultCode);
}
});
});
}));
}
function test_observer_topic_dispatched_when_complete()
@ -737,21 +764,28 @@ function test_observer_topic_dispatched_when_complete()
do_check_false(gGlobalHistory.isVisited(places[0].uri));
do_check_false(gGlobalHistory.isVisited(places[1].uri));
const EXPECTED_COUNT = 3;
let callbackCount = 0;
const EXPECTED_COUNT_SUCCESS = 2;
const EXPECTED_COUNT_FAILURE = 1;
let callbackCountSuccess = 0;
let callbackCountFailure = 0;
gHistory.updatePlaces(places, function(aResultCode, aPlaceInfo) {
let checker = PlacesUtils.history.canAddURI(aPlaceInfo.uri) ?
do_check_true : do_check_false;
checker(Components.isSuccessCode(aResultCode));
callbackCount++;
gHistory.updatePlaces(places, {
handleResult: function handleResult(aPlaceInfo) {
let checker = PlacesUtils.history.canAddURI(aPlaceInfo.uri) ?
do_check_true : do_check_false;
callbackCountSuccess++;
},
handleError: function handleError(aResultCode, aPlaceInfo) {
callbackCountFailure++;
}
});
let observer = {
observe: function(aSubject, aTopic, aData)
{
do_check_eq(aTopic, TOPIC_UPDATEPLACES_COMPLETE);
do_check_eq(callbackCount, EXPECTED_COUNT);
do_check_eq(callbackCountSuccess, EXPECTED_COUNT_SUCCESS);
do_check_eq(callbackCountFailure, EXPECTED_COUNT_FAILURE);
Services.obs.removeObserver(observer, TOPIC_UPDATEPLACES_COMPLETE);
waitForAsyncUpdates(run_next_test);
},
@ -775,8 +809,7 @@ function test_add_visit()
do_check_false(gGlobalHistory.isVisited(place.uri));
let callbackCount = 0;
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_true(gGlobalHistory.isVisited(place.uri));
// Check mozIPlaceInfo properties.
@ -790,14 +823,14 @@ function test_add_visit()
let visit = visits[0];
do_check_eq(visit.visitDate, VISIT_TIME);
do_check_true(visit.transitionType >= TRANSITION_LINK &&
visit.transitionType <= TRANSITION_FRAMED_LINK);
visit.transitionType <= TRANSITION_FRAMED_LINK);
do_check_true(visit.referrerURI === null);
// For TRANSITION_EMBED visits, many properties will always be zero or
// undefined.
if (visit.transitionType == TRANSITION_EMBED) {
// Check mozIPlaceInfo properties.
do_check_eq(aPlaceInfo.placeId, 0);
do_check_eq(aPlaceInfo.placeId, 0, '//');
do_check_eq(aPlaceInfo.guid, null);
// Check mozIVisitInfo properties.
@ -819,7 +852,7 @@ function test_add_visit()
if (++callbackCount == place.visits.length) {
waitForAsyncUpdates(run_next_test);
}
});
}));
}
function test_properties_saved()
@ -842,8 +875,7 @@ function test_properties_saved()
}
let callbackCount = 0;
gHistory.updatePlaces(places, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(places, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
let visit = aPlaceInfo.visits[0];
@ -915,7 +947,7 @@ function test_properties_saved()
if (++callbackCount == places.length) {
waitForAsyncUpdates(run_next_test);
}
});
}));
}
function test_guid_saved()
@ -930,15 +962,13 @@ function test_guid_saved()
do_check_valid_places_guid(place.guid);
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
do_check_eq(aPlaceInfo.guid, place.guid);
do_check_guid_for_uri(uri, place.guid);
waitForAsyncUpdates(run_next_test);
});
}));
}
function test_referrer_saved()
@ -961,8 +991,7 @@ function test_referrer_saved()
let callbackCount = 0;
let referrerSessionId;
gHistory.updatePlaces(places, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(places, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
let visit = aPlaceInfo.visits[0];
@ -993,7 +1022,7 @@ function test_referrer_saved()
stmt.finalize();
waitForAsyncUpdates(run_next_test);
});
}));
}
function test_sessionId_saved()
@ -1007,8 +1036,7 @@ function test_sessionId_saved()
place.visits[0].sessionId = 3;
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
let uri = aPlaceInfo.uri;
do_check_true(gGlobalHistory.isVisited(uri));
@ -1028,7 +1056,7 @@ function test_sessionId_saved()
stmt.finalize();
waitForAsyncUpdates(run_next_test);
});
}));
}
function test_guid_change_saved()
@ -1042,19 +1070,17 @@ function test_guid_change_saved()
};
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
// Then, change the guid with visits.
place.guid = "_GUIDCHANGE_";
place.visits = [new VisitInfo()];
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_guid_for_uri(place.uri, place.guid);
waitForAsyncUpdates(run_next_test);
});
});
}));
}));
}
function test_title_change_saved()
@ -1069,35 +1095,31 @@ function test_title_change_saved()
};
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
// Now, make sure the empty string clears the title.
place.title = "";
place.visits = [new VisitInfo()];
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_title_for_uri(place.uri, null);
// Then, change the title with visits.
place.title = "title change";
place.visits = [new VisitInfo()];
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_title_for_uri(place.uri, place.title);
// Lastly, check that the title is cleared if we set it to null.
place.title = null;
place.visits = [new VisitInfo()];
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_title_for_uri(place.uri, place.title);
waitForAsyncUpdates(run_next_test);
});
});
});
});
}));
}));
}));
}));
}
function test_no_title_does_not_clear_title()
@ -1113,19 +1135,16 @@ function test_no_title_does_not_clear_title()
};
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
// Now, make sure that not specifying a title does not clear it.
delete place.title;
place.visits = [new VisitInfo()];
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_title_for_uri(place.uri, TITLE);
waitForAsyncUpdates(run_next_test);
});
});
}));
}));
}
function test_title_change_notifies()
@ -1229,8 +1248,7 @@ function test_referrer_sessionId_persists()
// First we add the referrer visit, and then the main visit with referrer
// attached. We ensure that the sessionId is maintained across the updates.
do_check_false(gGlobalHistory.isVisited(referrerPlace.uri));
gHistory.updatePlaces(referrerPlace, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(referrerPlace, expectHandleResult(function(aPlaceInfo) {
do_check_true(gGlobalHistory.isVisited(referrerPlace.uri));
let sessionId = aPlaceInfo.visits[0].sessionId;
@ -1245,15 +1263,52 @@ function test_referrer_sessionId_persists()
place.visits[0].referrerURI = referrerPlace.uri;
do_check_false(gGlobalHistory.isVisited(place.uri));
gHistory.updatePlaces(place, function(aResultCode, aPlaceInfo) {
do_check_true(Components.isSuccessCode(aResultCode));
gHistory.updatePlaces(place, expectHandleResult(function(aPlaceInfo) {
do_check_true(gGlobalHistory.isVisited(place.uri));
do_check_eq(aPlaceInfo.visits[0].sessionId, sessionId);
waitForAsyncUpdates(run_next_test);
});
}));
}));
}
// test with empty mozIVisitInfoCallback object
function test_callbacks_not_supplied()
{
const URLS = [
"imap://cyrus.andrew.cmu.edu/archive.imap", // bad URI
"http://mozilla.org/" // valid URI
];
let places = [];
URLS.forEach(function(url) {
try {
let place = {
uri: NetUtil.newURI(url),
title: "test for " + url,
visits: [
new VisitInfo(),
],
};
places.push(place);
}
catch (e if e.result === Cr.NS_ERROR_FAILURE) {
// NetUtil.newURI() can throw if e.g. our app knows about imap://
// but the account is not set up and so the URL is invalid for us.
// Note this in the log but ignore as it's not the subject of this test.
do_log_info("Could not construct URI for '" + url + "'; ignoring");
}
});
gHistory.updatePlaces(places, {} );
let observer = {
observe: function(aSubject, aTopic, aData)
{
Services.obs.removeObserver(observer, TOPIC_UPDATEPLACES_COMPLETE);
waitForAsyncUpdates(run_next_test);
},
};
Services.obs.addObserver(observer, TOPIC_UPDATEPLACES_COMPLETE, false);
}
////////////////////////////////////////////////////////////////////////////////
@ -1290,6 +1345,7 @@ function test_referrer_sessionId_persists()
test_title_change_notifies,
test_visit_notifies,
test_referrer_sessionId_persists,
test_callbacks_not_supplied,
].forEach(add_test);
function run_test()

View File

@ -58,7 +58,6 @@ FORCE_USE_PIC = 1
include $(topsrcdir)/config/rules.mk
ifeq ($(OS_ARCH),Linux)
include $(topsrcdir)/config/config.mk
# need this to suppress errors when compiling common/linux/eintr_wrapper.h
OS_CXXFLAGS := $(filter-out -pedantic,$(OS_CXXFLAGS))
endif

View File

@ -342,7 +342,7 @@ nsGtkIMModule::OnFocusWindow(nsWindow* aWindow)
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): OnFocusWindow, aWindow=%p, mLastFocusedWindow=%p",
this, aWindow));
this, aWindow, mLastFocusedWindow));
mLastFocusedWindow = aWindow;
Focus();
}
@ -550,7 +550,8 @@ nsGtkIMModule::SetInputMode(nsWindow* aCaller, const IMEContext* aContext)
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): SetInputMode, aCaller=%p, aState=%s mHTMLInputType=%s",
this, aCaller, GetEnabledStateName(aContext->mStatus), aContext->mHTMLInputType.get()));
this, aCaller, GetEnabledStateName(aContext->mStatus),
NS_ConvertUTF16toUTF8(aContext->mHTMLInputType).get()));
if (aCaller != mLastFocusedWindow) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
@ -726,8 +727,7 @@ nsGtkIMModule::Focus()
GtkIMContext *im = GetContext();
if (!im) {
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" FAILED, there are no context",
this));
(" FAILED, there are no context"));
return;
}
@ -1119,7 +1119,7 @@ nsGtkIMModule::DispatchCompositionStart()
}
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" mCompositionStart=%lu", mCompositionStart));
(" mCompositionStart=%u", mCompositionStart));
mIsComposing = PR_TRUE;
nsCompositionEvent compEvent(PR_TRUE, NS_COMPOSITION_START,
mLastFocusedWindow);
@ -1329,7 +1329,7 @@ nsGtkIMModule::SetTextRangeList(nsTArray<nsTextRange> &aTextRangeList)
aTextRangeList.AppendElement(range);
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" mStartOffset=%lu, mEndOffset=%lu, mRangeType=%s",
(" mStartOffset=%u, mEndOffset=%u, mRangeType=%s",
range.mStartOffset, range.mEndOffset,
GetRangeTypeName(range.mRangeType)));
} while (pango_attr_iterator_next(iter));
@ -1347,7 +1347,7 @@ nsGtkIMModule::SetTextRangeList(nsTArray<nsTextRange> &aTextRangeList)
aTextRangeList.AppendElement(range);
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
(" mStartOffset=%lu, mEndOffset=%lu, mRangeType=%s",
(" mStartOffset=%u, mEndOffset=%u, mRangeType=%s",
range.mStartOffset, range.mEndOffset,
GetRangeTypeName(range.mRangeType)));
@ -1360,7 +1360,7 @@ void
nsGtkIMModule::SetCursorPosition(PRUint32 aTargetOffset)
{
PR_LOG(gGtkIMLog, PR_LOG_ALWAYS,
("GtkIMModule(%p): SetCursorPosition, aTargetOffset=%lu",
("GtkIMModule(%p): SetCursorPosition, aTargetOffset=%u",
this, aTargetOffset));
if (aTargetOffset == PR_UINT32_MAX) {

View File

@ -55,10 +55,6 @@ EXPORT_LIBRARY = 1
GRE_MODULE = 1
MOZILLA_INTERNAL_API = 1
CSRCS = \
$(XPCOM_GLUE_SRC_LCSRCS) \
$(NULL)
CPPSRCS = \
$(XPCOM_GLUE_SRC_LCPPSRCS) \
$(XPCOM_GLUENS_SRC_LCPPSRCS) \
@ -128,7 +124,7 @@ EXPORTS_mozilla = \
# Force use of PIC
FORCE_USE_PIC = 1
GARBAGE += $(XPCOM_GLUE_SRC_LCSRCS) $(XPCOM_GLUE_SRC_LCPPSRCS) $(XPCOM_GLUENS_SRC_LCPPSRCS) $(wildcard *.$(OBJ_SUFFIX))
GARBAGE += $(XPCOM_GLUE_SRC_LCPPSRCS) $(XPCOM_GLUENS_SRC_LCPPSRCS) $(wildcard *.$(OBJ_SUFFIX))
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
@ -148,5 +144,5 @@ ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
CXXFLAGS += $(TK_CFLAGS)
endif
export:: $(XPCOM_GLUE_SRC_CSRCS) $(XPCOM_GLUE_SRC_CPPSRCS) $(XPCOM_GLUENS_SRC_CPPSRCS)
export:: $(XPCOM_GLUE_SRC_CPPSRCS) $(XPCOM_GLUENS_SRC_CPPSRCS)
$(INSTALL) $^ .

View File

@ -55,10 +55,6 @@ LOCAL_INCLUDES = \
-I$(srcdir)/../build \
$(NULL)
CSRCS = \
$(XPCOM_GLUE_SRC_LCSRCS) \
$(NULL)
CPPSRCS = \
$(XPCOM_GLUE_SRC_LCPPSRCS) \
$(XPCOM_GLUENS_SRC_LCPPSRCS) \

View File

@ -54,10 +54,6 @@ LOCAL_INCLUDES = \
-I$(srcdir)/../../build \
$(NULL)
CSRCS = \
$(XPCOM_GLUE_SRC_LCSRCS) \
$(NULL)
CPPSRCS = \
$(XPCOM_GLUE_SRC_LCPPSRCS) \
$(XPCOM_GLUENS_SRC_LCPPSRCS) \
@ -69,7 +65,7 @@ SDK_LIBRARY = \
$(LIB_PREFIX)xpcomglue_s_nomozalloc.$(LIB_SUFFIX) \
$(NULL)
GARBAGE += $(CSRCS) $(CPPSRCS) DeadlockDetector.h SSE.h arm.h
GARBAGE += $(CPPSRCS) DeadlockDetector.h SSE.h arm.h
# we don't want the shared lib, but we want to force the creation of a static lib.
FORCE_STATIC_LIB = 1
@ -94,7 +90,7 @@ OS_COMPILE_CFLAGS += -Zl
DEFINES += -D_USE_ANSI_CPP
endif
export:: $(XPCOM_GLUE_SRC_CSRCS) $(XPCOM_GLUE_SRC_CPPSRCS) $(XPCOM_GLUENS_SRC_CPPSRCS) $(topsrcdir)/xpcom/glue/nsStringAPI.cpp $(topsrcdir)/xpcom/glue/GenericModule.cpp $(topsrcdir)/xpcom/glue/DeadlockDetector.h $(topsrcdir)/xpcom/glue/SSE.h $(topsrcdir)/xpcom/glue/arm.h
export:: $(XPCOM_GLUE_SRC_CPPSRCS) $(XPCOM_GLUENS_SRC_CPPSRCS) $(topsrcdir)/xpcom/glue/nsStringAPI.cpp $(topsrcdir)/xpcom/glue/GenericModule.cpp $(topsrcdir)/xpcom/glue/DeadlockDetector.h $(topsrcdir)/xpcom/glue/SSE.h $(topsrcdir)/xpcom/glue/arm.h
$(INSTALL) $^ .
ifdef TARGET_XPCOM_ABI

View File

@ -34,12 +34,6 @@
#
# ***** END LICENSE BLOCK *****
XPCOM_GLUE_SRC_LCSRCS = \
pldhash.c \
$(NULL)
XPCOM_GLUE_SRC_CSRCS = $(addprefix $(topsrcdir)/xpcom/glue/, $(XPCOM_GLUE_SRC_LCSRCS))
XPCOM_GLUE_SRC_LCPPSRCS = \
nsArrayEnumerator.cpp \
nsArrayUtils.cpp \
@ -66,6 +60,7 @@ XPCOM_GLUE_SRC_LCPPSRCS = \
nsCycleCollectionParticipant.cpp \
nsCycleCollectorUtils.cpp \
nsDeque.cpp \
pldhash.cpp \
$(NULL)
XPCOM_GLUE_SRC_CPPSRCS = $(addprefix $(topsrcdir)/xpcom/glue/, $(XPCOM_GLUE_SRC_LCPPSRCS))

View File

@ -71,10 +71,6 @@ LINKSRC = nsGlueLinkingNull.cpp
$(warning TinderboxPrint:<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=298044">Error: XPCOM Glue</a>)
endif
CSRCS = \
$(XPCOM_GLUE_SRC_LCSRCS) \
$(NULL)
CPPSRCS = \
$(XPCOM_GLUE_SRC_LCPPSRCS) \
nsStringAPI.cpp \
@ -104,7 +100,7 @@ USE_STATIC_LIBS = 1
# Don't use STL wrappers here (i.e. wrapped <new>); they require mozalloc
STL_FLAGS =
GARBAGE += $(XPCOM_GLUE_SRC_LCSRCS) $(XPCOM_GLUE_SRC_LCPPSRCS) $(wildcard *.$(OBJ_SUFFIX))
GARBAGE += $(XPCOM_GLUE_SRC_LCPPSRCS) $(wildcard *.$(OBJ_SUFFIX))
SRCS_IN_OBJDIR = 1
@ -117,7 +113,7 @@ OS_COMPILE_CFLAGS += -Zl
DEFINES += -D_USE_ANSI_CPP
endif
export:: $(XPCOM_GLUE_SRC_CSRCS) $(XPCOM_GLUE_SRC_CPPSRCS) $(topsrcdir)/xpcom/glue/nsStringAPI.cpp
export:: $(XPCOM_GLUE_SRC_CPPSRCS) $(topsrcdir)/xpcom/glue/nsStringAPI.cpp
$(INSTALL) $^ .
GARBAGE += nsStringAPI.cpp