Merge mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2011-10-22 13:58:26 +01:00
Родитель 09677add76 89844136bb
Коммит 0a636f7669
66 изменённых файлов: 1769 добавлений и 1346 удалений

Просмотреть файл

@ -1920,9 +1920,7 @@ SessionStoreService.prototype = {
catch (ex) { debug(ex); } catch (ex) { debug(ex); }
} }
if (aEntry.docIdentifier) { entry.docIdentifier = aEntry.BFCacheEntry.ID;
entry.docIdentifier = aEntry.docIdentifier;
}
if (aEntry.stateData != null) { if (aEntry.stateData != null) {
entry.structuredCloneState = aEntry.stateData.getDataAsBase64(); entry.structuredCloneState = aEntry.stateData.getDataAsBase64();
@ -3024,16 +3022,11 @@ SessionStoreService.prototype = {
browser.webNavigation.setCurrentURI(this._getURIFromString("about:blank")); browser.webNavigation.setCurrentURI(this._getURIFromString("about:blank"));
// Attach data that will be restored on "load" event, after tab is restored. // Attach data that will be restored on "load" event, after tab is restored.
if (activeIndex > -1) { if (activeIndex > -1) {
let curSHEntry = browser.webNavigation.sessionHistory.
getEntryAtIndex(activeIndex, false).
QueryInterface(Ci.nsISHEntry);
// restore those aspects of the currently active documents which are not // restore those aspects of the currently active documents which are not
// preserved in the plain history entries (mainly scroll state and text data) // preserved in the plain history entries (mainly scroll state and text data)
browser.__SS_restore_data = tabData.entries[activeIndex] || {}; browser.__SS_restore_data = tabData.entries[activeIndex] || {};
browser.__SS_restore_pageStyle = tabData.pageStyle || ""; browser.__SS_restore_pageStyle = tabData.pageStyle || "";
browser.__SS_restore_tab = aTab; browser.__SS_restore_tab = aTab;
browser.__SS_restore_docIdentifier = curSHEntry.docIdentifier;
didStartLoad = true; didStartLoad = true;
try { try {
// In order to work around certain issues in session history, we need to // In order to work around certain issues in session history, we need to
@ -3188,24 +3181,16 @@ SessionStoreService.prototype = {
} }
if (aEntry.docIdentifier) { if (aEntry.docIdentifier) {
// Get a new document identifier for this entry to ensure that history // If we have a serialized document identifier, try to find an SHEntry
// entries after a session restore are considered to have different // which matches that doc identifier and adopt that SHEntry's
// documents from the history entries before the session restore. // BFCacheEntry. If we don't find a match, insert shEntry as the match
// Document identifiers are 64-bit ints, so JS will loose precision and // for the document identifier.
// start assigning all entries the same doc identifier if these ever get let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
// large enough. if (!matchingEntry) {
// aDocIdentMap[aEntry.docIdentifier] = shEntry;
// It's a potential security issue if document identifiers aren't
// globally unique, but shEntry.setUniqueDocIdentifier() below guarantees
// that we won't re-use a doc identifier within a given instance of the
// application.
let ident = aDocIdentMap[aEntry.docIdentifier];
if (!ident) {
shEntry.setUniqueDocIdentifier();
aDocIdentMap[aEntry.docIdentifier] = shEntry.docIdentifier;
} }
else { else {
shEntry.docIdentifier = ident; shEntry.adoptBFCacheEntry(matchingEntry);
} }
} }
@ -3341,19 +3326,12 @@ SessionStoreService.prototype = {
aBrowser.markupDocumentViewer.authorStyleDisabled = selectedPageStyle == "_nostyle"; aBrowser.markupDocumentViewer.authorStyleDisabled = selectedPageStyle == "_nostyle";
} }
if (aBrowser.__SS_restore_docIdentifier) {
let sh = aBrowser.webNavigation.sessionHistory;
sh.getEntryAtIndex(sh.index, false).QueryInterface(Ci.nsISHEntry).
docIdentifier = aBrowser.__SS_restore_docIdentifier;
}
// notify the tabbrowser that this document has been completely restored // notify the tabbrowser that this document has been completely restored
this._sendTabRestoredNotification(aBrowser.__SS_restore_tab); this._sendTabRestoredNotification(aBrowser.__SS_restore_tab);
delete aBrowser.__SS_restore_data; delete aBrowser.__SS_restore_data;
delete aBrowser.__SS_restore_pageStyle; delete aBrowser.__SS_restore_pageStyle;
delete aBrowser.__SS_restore_tab; delete aBrowser.__SS_restore_tab;
delete aBrowser.__SS_restore_docIdentifier;
}, },
/** /**

Просмотреть файл

@ -116,13 +116,13 @@ function test() {
// After these push/replaceState calls, the window should have three // After these push/replaceState calls, the window should have three
// history entries: // history entries:
// testURL (state object: null) <-- oldest // testURL (state object: null) <-- oldest
// testURL (state object: {obj1:1}) // testURL (state object: {obj1:1})
// page2 (state object: {obj3:/^a$/}) <-- newest // testURL?page2 (state object: {obj3:/^a$/}) <-- newest
let contentWindow = tab.linkedBrowser.contentWindow; let contentWindow = tab.linkedBrowser.contentWindow;
let history = contentWindow.history; let history = contentWindow.history;
history.pushState({obj1:1}, "title-obj1"); history.pushState({obj1:1}, "title-obj1");
history.pushState({obj2:2}, "title-obj2", "page2"); history.pushState({obj2:2}, "title-obj2", "?page2");
history.replaceState({obj3:/^a$/}, "title-obj3"); history.replaceState({obj3:/^a$/}, "title-obj3");
let state = ss.getTabState(tab); let state = ss.getTabState(tab);

Просмотреть файл

@ -2,7 +2,6 @@
%filter substitution %filter substitution
%define toolbarHighlight rgba(255,255,255,.5) %define toolbarHighlight rgba(255,255,255,.5)
%define navbarTextboxCustomBorder border-color: rgba(0,0,0,.32);
%define customToolbarColor hsl(214,44%,87%) %define customToolbarColor hsl(214,44%,87%)
#placesView { #placesView {
@ -71,21 +70,10 @@
#searchFilter { #searchFilter {
-moz-appearance: none; -moz-appearance: none;
background-color: rgba(255,255,255,.725);
color: black;
padding: 2px; padding: 2px;
-moz-padding-start: 4px; -moz-padding-start: 4px;
background-clip: padding-box; background-clip: padding-box;
border: 1px solid ThreeDDarkShadow; border: 1px solid rgba(0,0,0,.32);
border-radius: 2.5px; border-radius: 2.5px;
@navbarTextboxCustomBorder@
}
#searchFilter:hover {
background-color: rgba(255,255,255,.898);
}
#searchFilter[focused] {
background-color: white;
} }
} }

Просмотреть файл

@ -312,7 +312,6 @@ MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@
MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@ MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@
MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@ MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@
MOZ_EXCEPTIONS_FLAGS_ON = @_MOZ_EXCEPTIONS_FLAGS_ON@
PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@ PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@
PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@ PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@

Просмотреть файл

@ -362,9 +362,6 @@ endif
endif # !GNU_CC endif # !GNU_CC
ifdef ENABLE_CXX_EXCEPTIONS
CXXFLAGS += $(MOZ_EXCEPTIONS_FLAGS_ON) -DMOZ_CPP_EXCEPTIONS=1
endif # ENABLE_CXX_EXCEPTIONS
endif # WINNT endif # WINNT
ifeq ($(SOLARIS_SUNPRO_CXX),1) ifeq ($(SOLARIS_SUNPRO_CXX),1)

Просмотреть файл

@ -755,8 +755,6 @@ case "$target" in
_MOZ_RTTI_FLAGS_ON='-GR' _MOZ_RTTI_FLAGS_ON='-GR'
_MOZ_RTTI_FLAGS_OFF='-GR-' _MOZ_RTTI_FLAGS_OFF='-GR-'
_MOZ_EXCEPTIONS_FLAGS_ON='-EHsc'
_MOZ_EXCEPTIONS_FLAGS_OFF=''
AC_DEFINE(HAVE_SEH_EXCEPTIONS) AC_DEFINE(HAVE_SEH_EXCEPTIONS)
if test -n "$WIN32_REDIST_DIR"; then if test -n "$WIN32_REDIST_DIR"; then
@ -1545,8 +1543,6 @@ if test "$GNU_CC"; then
ASFLAGS="$ASFLAGS -fPIC" ASFLAGS="$ASFLAGS -fPIC"
_MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti _MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti
_MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti _MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti
_MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions'
_MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions'
# Turn on GNU specific features # Turn on GNU specific features
# -Wall - turn on all warnings # -Wall - turn on all warnings
@ -1604,7 +1600,7 @@ fi
if test "$GNU_CXX"; then if test "$GNU_CXX"; then
# FIXME: Let us build with strict aliasing. bug 414641. # FIXME: Let us build with strict aliasing. bug 414641.
CXXFLAGS="$CXXFLAGS -fno-strict-aliasing" CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-strict-aliasing"
# Turn on GNU specific features # Turn on GNU specific features
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor" _WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor"
if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
@ -2490,9 +2486,7 @@ ia64*-hpux*)
LIBS="-lCrun -lCstd -lc $LIBS" LIBS="-lCrun -lCstd -lc $LIBS"
AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES)
CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__"
CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions,no%except -norunpath -D__FUNCTION__=__func__ -template=no%extdef"
_MOZ_EXCEPTIONS_FLAGS_ON='-features=except'
_MOZ_EXCEPTIONS_FLAGS_OFF='-features=no%except'
LDFLAGS="-xildoff $LDFLAGS" LDFLAGS="-xildoff $LDFLAGS"
if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then
_SAVE_LDFLAGS=$LDFLAGS _SAVE_LDFLAGS=$LDFLAGS
@ -7747,24 +7741,6 @@ if test "$ac_nscap_nonconst_opeq_bug" = "yes" ; then
fi fi
fi # ! SKIP_COMPILER_CHECKS fi # ! SKIP_COMPILER_CHECKS
dnl ========================================================
dnl C++ exceptions (g++/VC/Sun only - for now)
dnl Should be smarter and check that the compiler does indeed have exceptions
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(cpp-exceptions,
[ --enable-cpp-exceptions Enable C++ exceptions ],
[ _MOZ_CPP_EXCEPTIONS=1 ],
[ _MOZ_CPP_EXCEPTIONS= ])
if test "$_MOZ_CPP_EXCEPTIONS"; then
_MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_ON
AC_DEFINE(MOZ_CPP_EXCEPTIONS)
else
_MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_OFF
fi
AC_SUBST(_MOZ_EXCEPTIONS_FLAGS_ON)
AC_DEFINE(CPP_THROW_NEW, [throw()]) AC_DEFINE(CPP_THROW_NEW, [throw()])
AC_LANG_C AC_LANG_C
@ -8421,7 +8397,6 @@ CFLAGS=`echo \
CXXFLAGS=`echo \ CXXFLAGS=`echo \
$_MOZ_RTTI_FLAGS \ $_MOZ_RTTI_FLAGS \
$_MOZ_EXCEPTIONS_FLAGS \
$_WARNINGS_CXXFLAGS \ $_WARNINGS_CXXFLAGS \
$CXXFLAGS` $CXXFLAGS`

Просмотреть файл

@ -69,6 +69,7 @@
#include "nsIAnimationFrameListener.h" #include "nsIAnimationFrameListener.h"
#include "nsEventStates.h" #include "nsEventStates.h"
#include "nsIStructuredCloneContainer.h" #include "nsIStructuredCloneContainer.h"
#include "nsIBFCacheEntry.h"
#include "nsDOMMemoryReporter.h" #include "nsDOMMemoryReporter.h"
class nsIContent; class nsIContent;
@ -125,8 +126,8 @@ class Element;
} // namespace mozilla } // namespace mozilla
#define NS_IDOCUMENT_IID \ #define NS_IDOCUMENT_IID \
{ 0x4114a7c7, 0xb2f4, 0x4dea, \ { 0x448c396a, 0x013c, 0x47b8, \
{ 0xac, 0x78, 0x20, 0xab, 0xda, 0x6f, 0xb2, 0xaf } } { 0x95, 0xf4, 0x56, 0x68, 0x0f, 0x5f, 0x12, 0xf8 } }
// Flag for AddStyleSheet(). // Flag for AddStyleSheet().
#define NS_STYLESHEET_FROM_CATALOG (1 << 0) #define NS_STYLESHEET_FROM_CATALOG (1 << 0)
@ -479,11 +480,15 @@ public:
return GetBFCacheEntry() ? nsnull : mPresShell; return GetBFCacheEntry() ? nsnull : mPresShell;
} }
void SetBFCacheEntry(nsISHEntry* aSHEntry) { void SetBFCacheEntry(nsIBFCacheEntry* aEntry)
mSHEntry = aSHEntry; {
mBFCacheEntry = aEntry;
} }
nsISHEntry* GetBFCacheEntry() const { return mSHEntry; } nsIBFCacheEntry* GetBFCacheEntry() const
{
return mBFCacheEntry;
}
/** /**
* Return the parent document of this document. Will return null * Return the parent document of this document. Will return null
@ -1786,9 +1791,9 @@ protected:
AnimationListenerList mAnimationFrameListeners; AnimationListenerList mAnimationFrameListeners;
// The session history entry in which we're currently bf-cached. Non-null // This object allows us to evict ourself from the back/forward cache. The
// if and only if we're currently in the bfcache. // pointer is non-null iff we're currently in the bfcache.
nsISHEntry* mSHEntry; nsIBFCacheEntry *mBFCacheEntry;
// Our base target. // Our base target.
nsString mBaseTarget; nsString mBaseTarget;

Просмотреть файл

@ -4126,10 +4126,10 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
mFailedLoadType = mLoadType; mFailedLoadType = mLoadType;
if (mLSHE) { if (mLSHE) {
// If we don't give mLSHE a new doc identifier here, when we go back or // Abandon mLSHE's BFCache entry and create a new one. This way, if
// forward to another SHEntry with the same doc identifier, the error // we go back or forward to another SHEntry with the same doc
// page will persist. // identifier, the error page won't persist.
mLSHE->SetUniqueDocIdentifier(); mLSHE->AbandonBFCacheEntry();
} }
nsCAutoString url; nsCAutoString url;
@ -4402,10 +4402,10 @@ nsDocShell::LoadPage(nsISupports *aPageDescriptor, PRUint32 aDisplayType)
nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry)); nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Give our cloned shEntry a new document identifier so this load is // Give our cloned shEntry a new bfcache entry so this load is independent
// independent of all other loads. (This is important, in particular, // of all other loads. (This is important, in particular, for bugs 582795
// for bugs 582795 and 585298.) // and 585298.)
rv = shEntry->SetUniqueDocIdentifier(); rv = shEntry->AbandonBFCacheEntry();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// //
@ -8280,17 +8280,15 @@ nsDocShell::InternalLoad(nsIURI * aURI,
NS_SUCCEEDED(splitRv2) && NS_SUCCEEDED(splitRv2) &&
curBeforeHash.Equals(newBeforeHash); curBeforeHash.Equals(newBeforeHash);
bool sameDocIdent = false; // XXX rename
bool sameDocument = false;
if (mOSHE && aSHEntry) { if (mOSHE && aSHEntry) {
// We're doing a history load. // We're doing a history load.
PRUint64 ourDocIdent, otherDocIdent; mOSHE->SharesDocumentWith(aSHEntry, &sameDocument);
mOSHE->GetDocIdentifier(&ourDocIdent);
aSHEntry->GetDocIdentifier(&otherDocIdent);
sameDocIdent = (ourDocIdent == otherDocIdent);
#ifdef DEBUG #ifdef DEBUG
if (sameDocIdent) { if (sameDocument) {
nsCOMPtr<nsIInputStream> currentPostData; nsCOMPtr<nsIInputStream> currentPostData;
mOSHE->GetPostData(getter_AddRefs(currentPostData)); mOSHE->GetPostData(getter_AddRefs(currentPostData));
NS_ASSERTION(currentPostData == aPostData, NS_ASSERTION(currentPostData == aPostData,
@ -8313,7 +8311,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// The restriction tha the SHEntries in (a) must be different ensures // The restriction tha the SHEntries in (a) must be different ensures
// that history.go(0) and the like trigger full refreshes, rather than // that history.go(0) and the like trigger full refreshes, rather than
// short-circuited loads. // short-circuited loads.
bool doShortCircuitedLoad = (sameDocIdent && mOSHE != aSHEntry) || bool doShortCircuitedLoad = (sameDocument && mOSHE != aSHEntry) ||
(!aSHEntry && aPostData == nsnull && (!aSHEntry && aPostData == nsnull &&
sameExceptHashes && !newHash.IsEmpty()); sameExceptHashes && !newHash.IsEmpty());
@ -8364,7 +8362,6 @@ nsDocShell::InternalLoad(nsIURI * aURI,
OnNewURI(aURI, nsnull, owner, mLoadType, true, true, true); OnNewURI(aURI, nsnull, owner, mLoadType, true, true, true);
nsCOMPtr<nsIInputStream> postData; nsCOMPtr<nsIInputStream> postData;
PRUint64 docIdent = PRUint64(-1);
nsCOMPtr<nsISupports> cacheKey; nsCOMPtr<nsISupports> cacheKey;
if (mOSHE) { if (mOSHE) {
@ -8378,8 +8375,13 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// wouldn't want here. // wouldn't want here.
if (aLoadType & LOAD_CMD_NORMAL) { if (aLoadType & LOAD_CMD_NORMAL) {
mOSHE->GetPostData(getter_AddRefs(postData)); mOSHE->GetPostData(getter_AddRefs(postData));
mOSHE->GetDocIdentifier(&docIdent);
mOSHE->GetCacheKey(getter_AddRefs(cacheKey)); mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
// Link our new SHEntry to the old SHEntry's back/forward
// cache data, since the two SHEntries correspond to the
// same document.
if (mLSHE)
mLSHE->AdoptBFCacheEntry(mOSHE);
} }
} }
@ -8399,11 +8401,6 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// cache first // cache first
if (cacheKey) if (cacheKey)
mOSHE->SetCacheKey(cacheKey); mOSHE->SetCacheKey(cacheKey);
// Propagate our document identifier to the new mOSHE so that
// we'll know it's related by an anchor navigation or pushState.
if (docIdent != PRUint64(-1))
mOSHE->SetDocIdentifier(docIdent);
} }
/* restore previous position of scroller(s), if we're moving /* restore previous position of scroller(s), if we're moving
@ -8447,7 +8444,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
} }
} }
if (sameDocIdent) { if (sameDocument) {
// Set the doc's URI according to the new history entry's URI // Set the doc's URI according to the new history entry's URI
nsCOMPtr<nsIURI> newURI; nsCOMPtr<nsIURI> newURI;
mOSHE->GetURI(getter_AddRefs(newURI)); mOSHE->GetURI(getter_AddRefs(newURI));
@ -8464,10 +8461,10 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// Dispatch the popstate and hashchange events, as appropriate. // Dispatch the popstate and hashchange events, as appropriate.
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal); nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal);
if (window) { if (window) {
// Need the doHashchange check here since sameDocIdent is // Need the doHashchange check here since sameDocument is
// false if we're navigating to a new shentry (i.e. a aSHEntry // false if we're navigating to a new shentry (i.e. a aSHEntry
// is null), such as when clicking a <a href="#foo">. // is null), such as when clicking a <a href="#foo">.
if (sameDocIdent || doHashchange) { if (sameDocument || doHashchange) {
window->DispatchSyncPopState(); window->DispatchSyncPopState();
} }
@ -9250,11 +9247,11 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
} }
// If the response status indicates an error, unlink this session // If the response status indicates an error, unlink this session
// history entry from any entries sharing its doc ident. // history entry from any entries sharing its document.
PRUint32 responseStatus; PRUint32 responseStatus;
nsresult rv = httpChannel->GetResponseStatus(&responseStatus); nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) { if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
mLSHE->SetUniqueDocIdentifier(); mLSHE->AbandonBFCacheEntry();
} }
} }
} }
@ -9483,9 +9480,9 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
// It's important that this function not run arbitrary scripts after step 1 // It's important that this function not run arbitrary scripts after step 1
// and before completing step 5. For example, if a script called // and before completing step 5. For example, if a script called
// history.back() before we completed step 5, bfcache might destroy an // history.back() before we completed step 5, bfcache might destroy an
// active content viewer. Since EvictContentViewers at the end of step 5 // active content viewer. Since EvictOutOfRangeContentViewers at the end of
// might run script, we can't just put a script blocker around the critical // step 5 might run script, we can't just put a script blocker around the
// section. // critical section.
// //
// Note that we completely ignore the aTitle parameter. // Note that we completely ignore the aTitle parameter.
@ -9665,11 +9662,9 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE); NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
// Set the new SHEntry's document identifier, if we can. // Link the new SHEntry to the old SHEntry's BFCache entry, since the
PRUint64 ourDocIdent; // two entries correspond to the same document.
NS_ENSURE_SUCCESS(oldOSHE->GetDocIdentifier(&ourDocIdent), NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(newSHEntry->SetDocIdentifier(ourDocIdent),
NS_ERROR_FAILURE); NS_ERROR_FAILURE);
// Set the new SHEntry's title (bug 655273). // Set the new SHEntry's title (bug 655273).
@ -9715,7 +9710,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
PRInt32 curIndex = -1; PRInt32 curIndex = -1;
rv = rootSH->GetIndex(&curIndex); rv = rootSH->GetIndex(&curIndex);
if (NS_SUCCEEDED(rv) && curIndex > -1) { if (NS_SUCCEEDED(rv) && curIndex > -1) {
internalSH->EvictContentViewers(curIndex - 1, curIndex); internalSH->EvictOutOfRangeContentViewers(curIndex);
} }
} }

Просмотреть файл

@ -66,6 +66,7 @@
// session history // session history
#include "nsSHEntry.h" #include "nsSHEntry.h"
#include "nsSHEntryShared.h"
#include "nsSHistory.h" #include "nsSHistory.h"
#include "nsSHTransaction.h" #include "nsSHTransaction.h"
@ -87,15 +88,15 @@ Initialize()
nsresult rv = nsSHistory::Startup(); nsresult rv = nsSHistory::Startup();
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
rv = nsSHEntry::Startup(); nsSHEntryShared::Startup();
return rv; return NS_OK;
} }
static void static void
Shutdown() Shutdown()
{ {
nsSHistory::Shutdown(); nsSHistory::Shutdown();
nsSHEntry::Shutdown(); nsSHEntryShared::Shutdown();
gInitialized = false; gInitialized = false;
} }

Просмотреть файл

@ -56,6 +56,7 @@ XPIDLSRCS = \
nsISHContainer.idl \ nsISHContainer.idl \
nsISHTransaction.idl \ nsISHTransaction.idl \
nsISHistoryInternal.idl \ nsISHistoryInternal.idl \
nsIBFCacheEntry.idl \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,47 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* 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"
/**
* This interface lets you evict a document from the back/forward cache.
*/
[scriptable, uuid(a576060e-c7df-4d81-aa8c-5b52bd6ad25d)]
interface nsIBFCacheEntry : nsISupports
{
void RemoveFromBFCacheSync();
void RemoveFromBFCacheAsync();
readonly attribute unsigned long long ID;
};

Просмотреть файл

@ -51,15 +51,18 @@ interface nsIInputStream;
interface nsIDocShellTreeItem; interface nsIDocShellTreeItem;
interface nsISupportsArray; interface nsISupportsArray;
interface nsIStructuredCloneContainer; interface nsIStructuredCloneContainer;
interface nsIBFCacheEntry;
%{C++ %{C++
struct nsIntRect; struct nsIntRect;
class nsDocShellEditorData; class nsDocShellEditorData;
class nsSHEntryShared;
%} %}
[ref] native nsIntRect(nsIntRect); [ref] native nsIntRect(nsIntRect);
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData); [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
[ptr] native nsSHEntryShared(nsSHEntryShared);
[scriptable, uuid(6443FD72-A50F-4B8B-BB82-BB1FA04CB15D)]
[scriptable, uuid(b92d403e-f5ec-4b81-b0e3-6e6c241cef2d)]
interface nsISHEntry : nsIHistoryEntry interface nsISHEntry : nsIHistoryEntry
{ {
/** URI for the document */ /** URI for the document */
@ -140,21 +143,6 @@ interface nsISHEntry : nsIHistoryEntry
*/ */
attribute unsigned long ID; attribute unsigned long ID;
/**
* docIdentifier is an integer that should be the same for two entries
* attached to the same docshell if and only if the two entries are entries
* for the same document. In practice, two entries A and B will have the
* same docIdentifier if we arrived at B by clicking an anchor link in A or
* if B was created by A's calling history.pushState().
*/
attribute unsigned long long docIdentifier;
/**
* Changes this entry's doc identifier to a new value which is unique
* among those of all other entries.
*/
void setUniqueDocIdentifier();
/** attribute to set and get the cache key for the entry */ /** attribute to set and get the cache key for the entry */
attribute nsISupports cacheKey; attribute nsISupports cacheKey;
@ -252,6 +240,36 @@ interface nsISHEntry : nsIHistoryEntry
* The history ID of the docshell. * The history ID of the docshell.
*/ */
attribute unsigned long long docshellID; attribute unsigned long long docshellID;
readonly attribute nsIBFCacheEntry BFCacheEntry;
/**
* Does this SHEntry point to the given BFCache entry? If so, evicting
* the BFCache entry will evict the SHEntry, since the two entries
* correspond to the same document.
*/
[notxpcom, noscript]
boolean hasBFCacheEntry(in nsIBFCacheEntry aEntry);
/**
* Adopt aEntry's BFCacheEntry, so now both this and aEntry point to
* aEntry's BFCacheEntry.
*/
void adoptBFCacheEntry(in nsISHEntry aEntry);
/**
* Create a new BFCache entry and drop our reference to our old one. This
* call unlinks this SHEntry from any other SHEntries for its document.
*/
void abandonBFCacheEntry();
/**
* Does this SHEntry correspond to the same document as aEntry? This is
* true iff the two SHEntries have the same BFCacheEntry. So in
* particular, sharesDocumentWith(aEntry) is guaranteed to return true if
* it's preceeded by a call to adoptBFCacheEntry(aEntry).
*/
boolean sharesDocumentWith(in nsISHEntry aEntry);
}; };
[scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)] [scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)]
@ -264,6 +282,17 @@ interface nsISHEntryInternal : nsISupports
* A number that is assigned by the sHistory when the entry is activated * A number that is assigned by the sHistory when the entry is activated
*/ */
attribute unsigned long lastTouched; attribute unsigned long lastTouched;
/**
* Some state, particularly that related to the back/forward cache, is
* shared between SHEntries which correspond to the same document. This
* method gets a pointer to that shared state.
*
* This shared state is the SHEntry's BFCacheEntry. So
* hasBFCacheEntry(getSharedState()) is guaranteed to return true.
*/
[noscript, notxpcom]
nsSHEntryShared getSharedState();
}; };
%{ C++ %{ C++

Просмотреть файл

@ -57,7 +57,7 @@ struct nsTArrayDefaultAllocator;
[ref] native nsDocshellIDArray(nsTArray<PRUint64, nsTArrayDefaultAllocator>); [ref] native nsDocshellIDArray(nsTArray<PRUint64, nsTArrayDefaultAllocator>);
[scriptable, uuid(2dede933-25e1-47a3-8f61-0127c785ea01)] [scriptable, uuid(e27cf38e-c19f-4294-bd31-d7e0916e7fa2)]
interface nsISHistoryInternal: nsISupports interface nsISHistoryInternal: nsISupports
{ {
/** /**
@ -96,20 +96,25 @@ interface nsISHistoryInternal: nsISupports
*/ */
readonly attribute nsISHistoryListener listener; readonly attribute nsISHistoryListener listener;
/** /**
* Evict content viewers until the number of content viewers per tab * Evict content viewers which don't lie in the "safe" range around aIndex.
* is no more than gHistoryMaxViewers. Also, count * In practice, this should leave us with no more than gHistoryMaxViewers
* total number of content viewers globally and evict one if we are over * viewers associated with this SHistory object.
* our total max. This is always called in Show(), after we destroy *
* the previous viewer. * Also make sure that the total number of content viewers in all windows is
*/ * not greater than our global max; if it is, evict viewers as appropriate.
void evictContentViewers(in long previousIndex, in long index); *
* @param aIndex - The index around which the "safe" range is centered. In
* general, if you just navigated the history, aIndex should be the index
* history was navigated to.
*/
void evictOutOfRangeContentViewers(in long aIndex);
/** /**
* Evict the content viewer associated with a session history entry * Evict the content viewer associated with a bfcache entry
* that has timed out. * that has timed out.
*/ */
void evictExpiredContentViewerForEntry(in nsISHEntry aEntry); void evictExpiredContentViewerForEntry(in nsIBFCacheEntry aEntry);
/** /**
* Evict all the content viewers in this session history * Evict all the content viewers in this session history

Просмотреть файл

@ -48,10 +48,13 @@ LIBRARY_NAME = shistory_s
FORCE_STATIC_LIB = 1 FORCE_STATIC_LIB = 1
LIBXUL_LIBRARY = 1 LIBXUL_LIBRARY = 1
EXPORTS = nsSHEntryShared.h \
$(NULL)
CPPSRCS = nsSHEntry.cpp \ CPPSRCS = nsSHEntry.cpp \
nsSHTransaction.cpp \ nsSHTransaction.cpp \
nsSHistory.cpp \ nsSHistory.cpp \
nsSHEntryShared.cpp \
$(NULL) $(NULL)
include $(topsrcdir)/config/rules.mk include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -36,10 +36,6 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#ifdef DEBUG_bryner
#define DEBUG_PAGE_CACHE
#endif
// Local Includes // Local Includes
#include "nsSHEntry.h" #include "nsSHEntry.h"
#include "nsXPIDLString.h" #include "nsXPIDLString.h"
@ -48,103 +44,44 @@
#include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeItem.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsIDOMDocument.h" #include "nsIDOMDocument.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "nsIWebNavigation.h"
#include "nsISHistory.h" #include "nsISHistory.h"
#include "nsISHistoryInternal.h" #include "nsISHistoryInternal.h"
#include "nsDocShellEditorData.h" #include "nsDocShellEditorData.h"
#include "nsIDocShell.h" #include "nsSHEntryShared.h"
#include "nsILayoutHistoryState.h"
#include "nsIContentViewer.h"
#include "nsISupportsArray.h"
namespace dom = mozilla::dom; namespace dom = mozilla::dom;
// Hardcode this to time out unused content viewers after 30 minutes
#define CONTENT_VIEWER_TIMEOUT_SECONDS 30*60
typedef nsExpirationTracker<nsSHEntry,3> HistoryTrackerBase;
class HistoryTracker : public HistoryTrackerBase {
public:
// Expire cached contentviewers after 20-30 minutes in the cache.
HistoryTracker() : HistoryTrackerBase((CONTENT_VIEWER_TIMEOUT_SECONDS/2)*1000) {}
protected:
virtual void NotifyExpired(nsSHEntry* aObj) {
RemoveObject(aObj);
aObj->Expire();
}
};
static HistoryTracker *gHistoryTracker = nsnull;
static PRUint32 gEntryID = 0; static PRUint32 gEntryID = 0;
static PRUint64 gEntryDocIdentifier = 0;
nsresult nsSHEntry::Startup()
{
gHistoryTracker = new HistoryTracker();
return gHistoryTracker ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
void nsSHEntry::Shutdown()
{
delete gHistoryTracker;
gHistoryTracker = nsnull;
}
static void StopTrackingEntry(nsSHEntry *aEntry)
{
if (aEntry->GetExpirationState()->IsTracked()) {
gHistoryTracker->RemoveObject(aEntry);
}
}
//***************************************************************************** //*****************************************************************************
//*** nsSHEntry: Object Management //*** nsSHEntry: Object Management
//***************************************************************************** //*****************************************************************************
nsSHEntry::nsSHEntry() nsSHEntry::nsSHEntry()
: mLoadType(0) : mLoadType(0)
, mID(gEntryID++) , mID(gEntryID++)
, mDocIdentifier(gEntryDocIdentifier++)
, mScrollPositionX(0) , mScrollPositionX(0)
, mScrollPositionY(0) , mScrollPositionY(0)
, mURIWasModified(false) , mURIWasModified(false)
, mIsFrameNavigation(false)
, mSaveLayoutState(true)
, mExpired(false)
, mSticky(true)
, mDynamicallyCreated(false)
, mParent(nsnull)
, mViewerBounds(0, 0, 0, 0)
, mDocShellID(0)
, mLastTouched(0)
{ {
mShared = new nsSHEntryShared();
} }
nsSHEntry::nsSHEntry(const nsSHEntry &other) nsSHEntry::nsSHEntry(const nsSHEntry &other)
: mURI(other.mURI) : mShared(other.mShared)
, mURI(other.mURI)
, mReferrerURI(other.mReferrerURI) , mReferrerURI(other.mReferrerURI)
// XXX why not copy mDocument?
, mTitle(other.mTitle) , mTitle(other.mTitle)
, mPostData(other.mPostData) , mPostData(other.mPostData)
, mLayoutHistoryState(other.mLayoutHistoryState)
, mLoadType(0) // XXX why not copy? , mLoadType(0) // XXX why not copy?
, mID(other.mID) , mID(other.mID)
, mDocIdentifier(other.mDocIdentifier)
, mScrollPositionX(0) // XXX why not copy? , mScrollPositionX(0) // XXX why not copy?
, mScrollPositionY(0) // XXX why not copy? , mScrollPositionY(0) // XXX why not copy?
, mURIWasModified(other.mURIWasModified) , mURIWasModified(other.mURIWasModified)
, mIsFrameNavigation(other.mIsFrameNavigation)
, mSaveLayoutState(other.mSaveLayoutState)
, mExpired(other.mExpired)
, mSticky(true)
, mDynamicallyCreated(other.mDynamicallyCreated)
// XXX why not copy mContentType?
, mCacheKey(other.mCacheKey)
, mParent(other.mParent)
, mViewerBounds(0, 0, 0, 0)
, mOwner(other.mOwner)
, mDocShellID(other.mDocShellID)
, mStateData(other.mStateData) , mStateData(other.mStateData)
{ {
} }
@ -160,37 +97,16 @@ ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
nsSHEntry::~nsSHEntry() nsSHEntry::~nsSHEntry()
{ {
StopTrackingEntry(this); // Null out the mParent pointers on all our kids.
// Since we never really remove kids from SHEntrys, we need to null
// out the mParent pointers on all our kids.
mChildren.EnumerateForwards(ClearParentPtr, nsnull); mChildren.EnumerateForwards(ClearParentPtr, nsnull);
mChildren.Clear();
if (mContentViewer) {
// RemoveFromBFCacheSync is virtual, so call the nsSHEntry version
// explicitly
nsSHEntry::RemoveFromBFCacheSync();
}
mEditorData = nsnull;
#ifdef DEBUG
// This is not happening as far as I can tell from breakpad as of early November 2007
nsExpirationTracker<nsSHEntry,3>::Iterator iterator(gHistoryTracker);
nsSHEntry* elem;
while ((elem = iterator.Next()) != nsnull) {
NS_ASSERTION(elem != this, "Found dead entry still in the tracker!");
}
#endif
} }
//***************************************************************************** //*****************************************************************************
// nsSHEntry: nsISupports // nsSHEntry: nsISupports
//***************************************************************************** //*****************************************************************************
NS_IMPL_ISUPPORTS5(nsSHEntry, nsISHContainer, nsISHEntry, nsIHistoryEntry, NS_IMPL_ISUPPORTS4(nsSHEntry, nsISHContainer, nsISHEntry, nsIHistoryEntry,
nsIMutationObserver, nsISHEntryInternal) nsISHEntryInternal)
//***************************************************************************** //*****************************************************************************
// nsSHEntry: nsISHEntry // nsSHEntry: nsISHEntry
@ -251,35 +167,13 @@ NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetContentViewer(nsIContentViewer *aViewer) nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
{ {
NS_PRECONDITION(!aViewer || !mContentViewer, "SHEntry already contains viewer"); return mShared->SetContentViewer(aViewer);
if (mContentViewer || !aViewer) {
DropPresentationState();
}
mContentViewer = aViewer;
if (mContentViewer) {
gHistoryTracker->AddObject(this);
nsCOMPtr<nsIDOMDocument> domDoc;
mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
// Store observed document in strong pointer in case it is removed from
// the contentviewer
mDocument = do_QueryInterface(domDoc);
if (mDocument) {
mDocument->SetBFCacheEntry(this);
mDocument->AddMutationObserver(this);
}
}
return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetContentViewer(nsIContentViewer **aResult) nsSHEntry::GetContentViewer(nsIContentViewer **aResult)
{ {
*aResult = mContentViewer; *aResult = mShared->mContentViewer;
NS_IF_ADDREF(*aResult); NS_IF_ADDREF(*aResult);
return NS_OK; return NS_OK;
} }
@ -319,14 +213,14 @@ nsSHEntry::GetAnyContentViewer(nsISHEntry **aOwnerEntry,
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetSticky(bool aSticky) nsSHEntry::SetSticky(bool aSticky)
{ {
mSticky = aSticky; mShared->mSticky = aSticky;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetSticky(bool *aSticky) nsSHEntry::GetSticky(bool *aSticky)
{ {
*aSticky = mSticky; *aSticky = mShared->mSticky;
return NS_OK; return NS_OK;
} }
@ -365,16 +259,18 @@ NS_IMETHODIMP nsSHEntry::SetPostData(nsIInputStream* aPostData)
NS_IMETHODIMP nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult) NS_IMETHODIMP nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult)
{ {
*aResult = mLayoutHistoryState; *aResult = mShared->mLayoutHistoryState;
NS_IF_ADDREF(*aResult); NS_IF_ADDREF(*aResult);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState) NS_IMETHODIMP nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState)
{ {
mLayoutHistoryState = aState; mShared->mLayoutHistoryState = aState;
if (mLayoutHistoryState) if (mShared->mLayoutHistoryState) {
mLayoutHistoryState->SetScrollPositionOnly(!mSaveLayoutState); mShared->mLayoutHistoryState->
SetScrollPositionOnly(!mShared->mSaveLayoutState);
}
return NS_OK; return NS_OK;
} }
@ -403,91 +299,73 @@ NS_IMETHODIMP nsSHEntry::SetID(PRUint32 aID)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::GetDocIdentifier(PRUint64 * aResult) nsSHEntryShared* nsSHEntry::GetSharedState()
{ {
*aResult = mDocIdentifier; return mShared;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::SetDocIdentifier(PRUint64 aDocIdentifier)
{
// This ensures that after a session restore, gEntryDocIdentifier is greater
// than all SHEntries' docIdentifiers, which ensures that we'll never repeat
// a doc identifier.
if (aDocIdentifier >= gEntryDocIdentifier)
gEntryDocIdentifier = aDocIdentifier + 1;
mDocIdentifier = aDocIdentifier;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::SetUniqueDocIdentifier()
{
mDocIdentifier = gEntryDocIdentifier++;
return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::GetIsSubFrame(bool * aFlag) NS_IMETHODIMP nsSHEntry::GetIsSubFrame(bool * aFlag)
{ {
*aFlag = mIsFrameNavigation; *aFlag = mShared->mIsFrameNavigation;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetIsSubFrame(bool aFlag) NS_IMETHODIMP nsSHEntry::SetIsSubFrame(bool aFlag)
{ {
mIsFrameNavigation = aFlag; mShared->mIsFrameNavigation = aFlag;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::GetCacheKey(nsISupports** aResult) NS_IMETHODIMP nsSHEntry::GetCacheKey(nsISupports** aResult)
{ {
*aResult = mCacheKey; *aResult = mShared->mCacheKey;
NS_IF_ADDREF(*aResult); NS_IF_ADDREF(*aResult);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey) NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey)
{ {
mCacheKey = aCacheKey; mShared->mCacheKey = aCacheKey;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(bool * aFlag) NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(bool * aFlag)
{ {
*aFlag = mSaveLayoutState; *aFlag = mShared->mSaveLayoutState;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(bool aFlag) NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(bool aFlag)
{ {
mSaveLayoutState = aFlag; mShared->mSaveLayoutState = aFlag;
if (mLayoutHistoryState) if (mShared->mLayoutHistoryState) {
mLayoutHistoryState->SetScrollPositionOnly(!aFlag); mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag);
}
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::GetExpirationStatus(bool * aFlag) NS_IMETHODIMP nsSHEntry::GetExpirationStatus(bool * aFlag)
{ {
*aFlag = mExpired; *aFlag = mShared->mExpired;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetExpirationStatus(bool aFlag) NS_IMETHODIMP nsSHEntry::SetExpirationStatus(bool aFlag)
{ {
mExpired = aFlag; mShared->mExpired = aFlag;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::GetContentType(nsACString& aContentType) NS_IMETHODIMP nsSHEntry::GetContentType(nsACString& aContentType)
{ {
aContentType = mContentType; aContentType = mShared->mContentType;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType) NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType)
{ {
mContentType = aContentType; mShared->mContentType = aContentType;
return NS_OK; return NS_OK;
} }
@ -502,26 +380,27 @@ nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle,
mURI = aURI; mURI = aURI;
mTitle = aTitle; mTitle = aTitle;
mPostData = aInputStream; mPostData = aInputStream;
mCacheKey = aCacheKey;
mContentType = aContentType;
mOwner = aOwner;
mDocShellID = aDocShellID;
mDynamicallyCreated = aDynamicCreation;
// Set the LoadType by default to loadHistory during creation // Set the LoadType by default to loadHistory during creation
mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory; mLoadType = (PRUint32) nsIDocShellLoadInfo::loadHistory;
mShared->mCacheKey = aCacheKey;
mShared->mContentType = aContentType;
mShared->mOwner = aOwner;
mShared->mDocShellID = aDocShellID;
mShared->mDynamicallyCreated = aDynamicCreation;
// By default all entries are set false for subframe flag. // By default all entries are set false for subframe flag.
// nsDocShell::CloneAndReplace() which creates entries for // nsDocShell::CloneAndReplace() which creates entries for
// all subframe navigations, sets the flag to true. // all subframe navigations, sets the flag to true.
mIsFrameNavigation = false; mShared->mIsFrameNavigation = false;
// By default we save LayoutHistoryState // By default we save LayoutHistoryState
mSaveLayoutState = true; mShared->mSaveLayoutState = true;
mLayoutHistoryState = aLayoutHistoryState; mShared->mLayoutHistoryState = aLayoutHistoryState;
//By default the page is not expired //By default the page is not expired
mExpired = false; mShared->mExpired = false;
return NS_OK; return NS_OK;
} }
@ -530,8 +409,6 @@ NS_IMETHODIMP
nsSHEntry::Clone(nsISHEntry ** aResult) nsSHEntry::Clone(nsISHEntry ** aResult)
{ {
*aResult = new nsSHEntry(*this); *aResult = new nsSHEntry(*this);
if (!*aResult)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aResult); NS_ADDREF(*aResult);
return NS_OK; return NS_OK;
} }
@ -540,7 +417,7 @@ NS_IMETHODIMP
nsSHEntry::GetParent(nsISHEntry ** aResult) nsSHEntry::GetParent(nsISHEntry ** aResult)
{ {
NS_ENSURE_ARG_POINTER(aResult); NS_ENSURE_ARG_POINTER(aResult);
*aResult = mParent; *aResult = mShared->mParent;
NS_IF_ADDREF(*aResult); NS_IF_ADDREF(*aResult);
return NS_OK; return NS_OK;
} }
@ -553,49 +430,95 @@ nsSHEntry::SetParent(nsISHEntry * aParent)
* *
* XXX this method should not be scriptable if this is the case!! * XXX this method should not be scriptable if this is the case!!
*/ */
mParent = aParent; mShared->mParent = aParent;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetWindowState(nsISupports *aState) nsSHEntry::SetWindowState(nsISupports *aState)
{ {
mWindowState = aState; mShared->mWindowState = aState;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetWindowState(nsISupports **aState) nsSHEntry::GetWindowState(nsISupports **aState)
{ {
NS_IF_ADDREF(*aState = mWindowState); NS_IF_ADDREF(*aState = mShared->mWindowState);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetViewerBounds(const nsIntRect &aBounds) nsSHEntry::SetViewerBounds(const nsIntRect &aBounds)
{ {
mViewerBounds = aBounds; mShared->mViewerBounds = aBounds;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetViewerBounds(nsIntRect &aBounds) nsSHEntry::GetViewerBounds(nsIntRect &aBounds)
{ {
aBounds = mViewerBounds; aBounds = mShared->mViewerBounds;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetOwner(nsISupports **aOwner) nsSHEntry::GetOwner(nsISupports **aOwner)
{ {
NS_IF_ADDREF(*aOwner = mOwner); NS_IF_ADDREF(*aOwner = mShared->mOwner);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetOwner(nsISupports *aOwner) nsSHEntry::SetOwner(nsISupports *aOwner)
{ {
mOwner = aOwner; mShared->mOwner = aOwner;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry **aEntry)
{
NS_ENSURE_ARG_POINTER(aEntry);
NS_IF_ADDREF(*aEntry = mShared);
return NS_OK;
}
bool
nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry *aEntry)
{
return static_cast<nsIBFCacheEntry*>(mShared) == aEntry;
}
NS_IMETHODIMP
nsSHEntry::AdoptBFCacheEntry(nsISHEntry *aEntry)
{
nsCOMPtr<nsISHEntryInternal> shEntry = do_QueryInterface(aEntry);
NS_ENSURE_STATE(shEntry);
nsSHEntryShared *shared = shEntry->GetSharedState();
NS_ENSURE_STATE(shared);
mShared = shared;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SharesDocumentWith(nsISHEntry *aEntry, bool *aOut)
{
NS_ENSURE_ARG_POINTER(aOut);
nsCOMPtr<nsISHEntryInternal> internal = do_QueryInterface(aEntry);
NS_ENSURE_STATE(internal);
*aOut = mShared == internal->GetSharedState();
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::AbandonBFCacheEntry()
{
mShared = nsSHEntryShared::Duplicate(mShared);
return NS_OK; return NS_OK;
} }
@ -753,256 +676,77 @@ NS_IMETHODIMP
nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell) nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell)
{ {
NS_ASSERTION(aShell, "Null child shell added to history entry"); NS_ASSERTION(aShell, "Null child shell added to history entry");
mChildShells.AppendObject(aShell); mShared->mChildShells.AppendObject(aShell);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::ChildShellAt(PRInt32 aIndex, nsIDocShellTreeItem **aShell) nsSHEntry::ChildShellAt(PRInt32 aIndex, nsIDocShellTreeItem **aShell)
{ {
NS_IF_ADDREF(*aShell = mChildShells.SafeObjectAt(aIndex)); NS_IF_ADDREF(*aShell = mShared->mChildShells.SafeObjectAt(aIndex));
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::ClearChildShells() nsSHEntry::ClearChildShells()
{ {
mChildShells.Clear(); mShared->mChildShells.Clear();
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetRefreshURIList(nsISupportsArray **aList) nsSHEntry::GetRefreshURIList(nsISupportsArray **aList)
{ {
NS_IF_ADDREF(*aList = mRefreshURIList); NS_IF_ADDREF(*aList = mShared->mRefreshURIList);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetRefreshURIList(nsISupportsArray *aList) nsSHEntry::SetRefreshURIList(nsISupportsArray *aList)
{ {
mRefreshURIList = aList; mShared->mRefreshURIList = aList;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SyncPresentationState() nsSHEntry::SyncPresentationState()
{ {
if (mContentViewer && mWindowState) { return mShared->SyncPresentationState();
// If we have a content viewer and a window state, we should be ok.
return NS_OK;
}
DropPresentationState();
return NS_OK;
} }
void
nsSHEntry::DropPresentationState()
{
nsRefPtr<nsSHEntry> kungFuDeathGrip = this;
if (mDocument) {
mDocument->SetBFCacheEntry(nsnull);
mDocument->RemoveMutationObserver(this);
mDocument = nsnull;
}
if (mContentViewer)
mContentViewer->ClearHistoryEntry();
StopTrackingEntry(this);
mContentViewer = nsnull;
mSticky = true;
mWindowState = nsnull;
mViewerBounds.SetRect(0, 0, 0, 0);
mChildShells.Clear();
mRefreshURIList = nsnull;
mEditorData = nsnull;
}
void
nsSHEntry::Expire()
{
// This entry has timed out. If we still have a content viewer, we need to
// get it evicted.
if (!mContentViewer)
return;
nsCOMPtr<nsISupports> container;
mContentViewer->GetContainer(getter_AddRefs(container));
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
if (!treeItem)
return;
// We need to find the root DocShell since only that object has an
// SHistory and we need the SHistory to evict content viewers
nsCOMPtr<nsIDocShellTreeItem> root;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
nsCOMPtr<nsISHistory> history;
webNav->GetSessionHistory(getter_AddRefs(history));
nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
if (!historyInt)
return;
historyInt->EvictExpiredContentViewerForEntry(this);
}
//*****************************************************************************
// nsSHEntry: nsIMutationObserver
//*****************************************************************************
void
nsSHEntry::NodeWillBeDestroyed(const nsINode* aNode)
{
NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
}
void
nsSHEntry::CharacterDataWillChange(nsIDocument* aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
}
void
nsSHEntry::CharacterDataChanged(nsIDocument* aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntry::AttributeWillChange(nsIDocument* aDocument,
dom::Element* aContent,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType)
{
}
void
nsSHEntry::AttributeChanged(nsIDocument* aDocument,
dom::Element* aElement,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntry::ContentAppended(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aFirstNewContent,
PRInt32 /* unused */)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntry::ContentInserted(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 /* unused */)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntry::ContentRemoved(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer,
nsIContent* aPreviousSibling)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntry::ParentChainChanged(nsIContent *aContent)
{
}
class DestroyViewerEvent : public nsRunnable
{
public:
DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument)
: mViewer(aViewer),
mDocument(aDocument)
{}
NS_IMETHOD Run()
{
if (mViewer)
mViewer->Destroy();
return NS_OK;
}
nsCOMPtr<nsIContentViewer> mViewer;
nsCOMPtr<nsIDocument> mDocument;
};
void void
nsSHEntry::RemoveFromBFCacheSync() nsSHEntry::RemoveFromBFCacheSync()
{ {
NS_ASSERTION(mContentViewer && mDocument, mShared->RemoveFromBFCacheSync();
"we're not in the bfcache!");
nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
DropPresentationState();
// Warning! The call to DropPresentationState could have dropped the last
// reference to this nsSHEntry, so no accessing members beyond here.
if (viewer) {
viewer->Destroy();
}
} }
void void
nsSHEntry::RemoveFromBFCacheAsync() nsSHEntry::RemoveFromBFCacheAsync()
{ {
NS_ASSERTION(mContentViewer && mDocument, mShared->RemoveFromBFCacheAsync();
"we're not in the bfcache!");
// Release the reference to the contentviewer asynchronously so that the
// document doesn't get nuked mid-mutation.
nsCOMPtr<nsIRunnable> evt =
new DestroyViewerEvent(mContentViewer, mDocument);
nsresult rv = NS_DispatchToCurrentThread(evt);
if (NS_FAILED(rv)) {
NS_WARNING("failed to dispatch DestroyViewerEvent");
}
else {
// Drop presentation. Also ensures that we don't post more then one
// PLEvent. Only do this if we succeeded in posting the event since
// otherwise the document could be torn down mid mutation causing crashes.
DropPresentationState();
}
// Warning! The call to DropPresentationState could have dropped the last
// reference to this nsSHEntry, so no accessing members beyond here.
} }
nsDocShellEditorData* nsDocShellEditorData*
nsSHEntry::ForgetEditorData() nsSHEntry::ForgetEditorData()
{ {
return mEditorData.forget(); // XXX jlebar Check how this is used.
return mShared->mEditorData.forget();
} }
void void
nsSHEntry::SetEditorData(nsDocShellEditorData* aData) nsSHEntry::SetEditorData(nsDocShellEditorData* aData)
{ {
NS_ASSERTION(!(aData && mEditorData), NS_ASSERTION(!(aData && mShared->mEditorData),
"We're going to overwrite an owning ref!"); "We're going to overwrite an owning ref!");
if (mEditorData != aData) if (mShared->mEditorData != aData) {
mEditorData = aData; mShared->mEditorData = aData;
}
} }
bool bool
nsSHEntry::HasDetachedEditor() nsSHEntry::HasDetachedEditor()
{ {
return mEditorData != nsnull; return mShared->mEditorData != nsnull;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -1023,7 +767,7 @@ nsSHEntry::SetStateData(nsIStructuredCloneContainer *aContainer)
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::IsDynamicallyAdded(bool* aAdded) nsSHEntry::IsDynamicallyAdded(bool* aAdded)
{ {
*aAdded = mDynamicallyCreated; *aAdded = mShared->mDynamicallyCreated;
return NS_OK; return NS_OK;
} }
@ -1046,14 +790,14 @@ nsSHEntry::HasDynamicallyAddedChild(bool* aAdded)
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetDocshellID(PRUint64* aID) nsSHEntry::GetDocshellID(PRUint64* aID)
{ {
*aID = mDocShellID; *aID = mShared->mDocShellID;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetDocshellID(PRUint64 aID) nsSHEntry::SetDocshellID(PRUint64 aID)
{ {
mDocShellID = aID; mShared->mDocShellID = aID;
return NS_OK; return NS_OK;
} }
@ -1061,14 +805,13 @@ nsSHEntry::SetDocshellID(PRUint64 aID)
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::GetLastTouched(PRUint32 *aLastTouched) nsSHEntry::GetLastTouched(PRUint32 *aLastTouched)
{ {
*aLastTouched = mLastTouched; *aLastTouched = mShared->mLastTouched;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::SetLastTouched(PRUint32 aLastTouched) nsSHEntry::SetLastTouched(PRUint32 aLastTouched)
{ {
mLastTouched = aLastTouched; mShared->mLastTouched = aLastTouched;
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -42,28 +42,21 @@
// Helper Classes // Helper Classes
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsCOMArray.h" #include "nsCOMArray.h"
#include "nsString.h" #include "nsString.h"
#include "nsAutoPtr.h"
// Interfaces needed // Interfaces needed
#include "nsIContentViewer.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsILayoutHistoryState.h"
#include "nsISHEntry.h" #include "nsISHEntry.h"
#include "nsISHContainer.h" #include "nsISHContainer.h"
#include "nsIURI.h" #include "nsIURI.h"
#include "nsIEnumerator.h"
#include "nsIHistoryEntry.h" #include "nsIHistoryEntry.h"
#include "nsRect.h"
#include "nsISupportsArray.h" class nsSHEntryShared;
#include "nsIMutationObserver.h"
#include "nsExpirationTracker.h"
#include "nsDocShellEditorData.h"
class nsSHEntry : public nsISHEntry, class nsSHEntry : public nsISHEntry,
public nsISHContainer, public nsISHContainer,
public nsIMutationObserver,
public nsISHEntryInternal public nsISHEntryInternal
{ {
public: public:
@ -75,51 +68,30 @@ public:
NS_DECL_NSISHENTRY NS_DECL_NSISHENTRY
NS_DECL_NSISHENTRYINTERNAL NS_DECL_NSISHENTRYINTERNAL
NS_DECL_NSISHCONTAINER NS_DECL_NSISHCONTAINER
NS_DECL_NSIMUTATIONOBSERVER
void DropPresentationState(); void DropPresentationState();
void Expire();
nsExpirationState *GetExpirationState() { return &mExpirationState; }
static nsresult Startup(); static nsresult Startup();
static void Shutdown(); static void Shutdown();
private: private:
~nsSHEntry(); ~nsSHEntry();
nsCOMPtr<nsIURI> mURI; // We share the state in here with other SHEntries which correspond to the
nsCOMPtr<nsIURI> mReferrerURI; // same document.
nsCOMPtr<nsIContentViewer> mContentViewer; nsRefPtr<nsSHEntryShared> mShared;
nsCOMPtr<nsIDocument> mDocument; // document currently being observed
nsString mTitle; // See nsSHEntry.idl for comments on these members.
nsCOMPtr<nsIInputStream> mPostData; nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState; nsCOMPtr<nsIURI> mReferrerURI;
nsCOMArray<nsISHEntry> mChildren; nsString mTitle;
PRUint32 mLoadType; nsCOMPtr<nsIInputStream> mPostData;
PRUint32 mID; PRUint32 mLoadType;
PRInt64 mDocIdentifier; PRUint32 mID;
PRInt32 mScrollPositionX; PRInt32 mScrollPositionX;
PRInt32 mScrollPositionY; PRInt32 mScrollPositionY;
PRPackedBool mURIWasModified; nsCOMArray<nsISHEntry> mChildren;
PRPackedBool mIsFrameNavigation; bool mURIWasModified;
PRPackedBool mSaveLayoutState;
PRPackedBool mExpired;
PRPackedBool mSticky;
PRPackedBool mDynamicallyCreated;
nsCString mContentType;
nsCOMPtr<nsISupports> mCacheKey;
nsISHEntry * mParent; // weak reference
nsCOMPtr<nsISupports> mWindowState;
nsIntRect mViewerBounds;
nsCOMArray<nsIDocShellTreeItem> mChildShells;
nsCOMPtr<nsISupportsArray> mRefreshURIList;
nsCOMPtr<nsISupports> mOwner;
nsExpirationState mExpirationState;
nsAutoPtr<nsDocShellEditorData> mEditorData;
PRUint64 mDocShellID;
PRUint32 mLastTouched;
nsCOMPtr<nsIStructuredCloneContainer> mStateData; nsCOMPtr<nsIStructuredCloneContainer> mStateData;
}; };

Просмотреть файл

@ -0,0 +1,400 @@
/* ***** 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 the Mozilla Foundation.
*
* Portions created by the Initial Developer are Copyright (C) 2011
* 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 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 "nsSHEntryShared.h"
#include "nsISHistory.h"
#include "nsISHistoryInternal.h"
#include "nsIDocument.h"
#include "nsIWebNavigation.h"
#include "nsIContentViewer.h"
#include "nsIDocShellTreeItem.h"
#include "nsISupportsArray.h"
#include "nsDocShellEditorData.h"
#include "nsThreadUtils.h"
#include "nsILayoutHistoryState.h"
#include "prprf.h"
namespace dom = mozilla::dom;
namespace {
PRUint64 gSHEntrySharedID = 0;
} // anonymous namespace
// Hardcode this to time out unused content viewers after 30 minutes
// XXX jlebar shouldn't this be a pref?
#define CONTENT_VIEWER_TIMEOUT_SECONDS (30*60)
typedef nsExpirationTracker<nsSHEntryShared, 3> HistoryTrackerBase;
class HistoryTracker : public HistoryTrackerBase {
public:
// Expire cached contentviewers after 20-30 minutes in the cache.
HistoryTracker()
: HistoryTrackerBase(1000 * CONTENT_VIEWER_TIMEOUT_SECONDS / 2)
{
}
protected:
virtual void NotifyExpired(nsSHEntryShared *aObj) {
RemoveObject(aObj);
aObj->Expire();
}
};
static HistoryTracker *gHistoryTracker = nsnull;
void
nsSHEntryShared::Startup()
{
gHistoryTracker = new HistoryTracker();
}
void
nsSHEntryShared::Shutdown()
{
delete gHistoryTracker;
gHistoryTracker = nsnull;
}
nsSHEntryShared::nsSHEntryShared()
: mDocShellID(0)
, mParent(nsnull)
, mIsFrameNavigation(false)
, mSaveLayoutState(true)
, mSticky(true)
, mDynamicallyCreated(false)
, mLastTouched(0)
, mID(gSHEntrySharedID++)
, mExpired(false)
, mViewerBounds(0, 0, 0, 0)
{
}
nsSHEntryShared::~nsSHEntryShared()
{
RemoveFromExpirationTracker();
#ifdef DEBUG
// Check that we're not still on track to expire. We shouldn't be, because
// we just removed ourselves!
nsExpirationTracker<nsSHEntryShared, 3>::Iterator
iterator(gHistoryTracker);
nsSHEntryShared *elem;
while ((elem = iterator.Next()) != nsnull) {
NS_ASSERTION(elem != this, "Found dead entry still in the tracker!");
}
#endif
if (mContentViewer) {
RemoveFromBFCacheSync();
}
}
NS_IMPL_ISUPPORTS2(nsSHEntryShared, nsIBFCacheEntry, nsIMutationObserver)
already_AddRefed<nsSHEntryShared>
nsSHEntryShared::Duplicate(nsSHEntryShared *aEntry)
{
nsRefPtr<nsSHEntryShared> newEntry = new nsSHEntryShared();
newEntry->mDocShellID = aEntry->mDocShellID;
newEntry->mChildShells.AppendObjects(aEntry->mChildShells);
newEntry->mOwner = aEntry->mOwner;
newEntry->mParent = aEntry->mParent;
newEntry->mContentType.Assign(aEntry->mContentType);
newEntry->mIsFrameNavigation = aEntry->mIsFrameNavigation;
newEntry->mSaveLayoutState = aEntry->mSaveLayoutState;
newEntry->mSticky = aEntry->mSticky;
newEntry->mDynamicallyCreated = aEntry->mDynamicallyCreated;
newEntry->mCacheKey = aEntry->mCacheKey;
newEntry->mLastTouched = aEntry->mLastTouched;
return newEntry.forget();
}
void nsSHEntryShared::RemoveFromExpirationTracker()
{
if (GetExpirationState()->IsTracked()) {
gHistoryTracker->RemoveObject(this);
}
}
nsresult
nsSHEntryShared::SyncPresentationState()
{
if (mContentViewer && mWindowState) {
// If we have a content viewer and a window state, we should be ok.
return NS_OK;
}
DropPresentationState();
return NS_OK;
}
void
nsSHEntryShared::DropPresentationState()
{
nsRefPtr<nsSHEntryShared> kungFuDeathGrip = this;
if (mDocument) {
mDocument->SetBFCacheEntry(nsnull);
mDocument->RemoveMutationObserver(this);
mDocument = nsnull;
}
if (mContentViewer) {
mContentViewer->ClearHistoryEntry();
}
RemoveFromExpirationTracker();
mContentViewer = nsnull;
mSticky = true;
mWindowState = nsnull;
mViewerBounds.SetRect(0, 0, 0, 0);
mChildShells.Clear();
mRefreshURIList = nsnull;
mEditorData = nsnull;
}
void
nsSHEntryShared::Expire()
{
// This entry has timed out. If we still have a content viewer, we need to
// evict it.
if (!mContentViewer) {
return;
}
nsCOMPtr<nsISupports> container;
mContentViewer->GetContainer(getter_AddRefs(container));
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
if (!treeItem) {
return;
}
// We need to find the root DocShell since only that object has an
// SHistory and we need the SHistory to evict content viewers
nsCOMPtr<nsIDocShellTreeItem> root;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
nsCOMPtr<nsISHistory> history;
webNav->GetSessionHistory(getter_AddRefs(history));
nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
if (!historyInt) {
return;
}
historyInt->EvictExpiredContentViewerForEntry(this);
}
nsresult
nsSHEntryShared::SetContentViewer(nsIContentViewer *aViewer)
{
NS_PRECONDITION(!aViewer || !mContentViewer,
"SHEntryShared already contains viewer");
if (mContentViewer || !aViewer) {
DropPresentationState();
}
mContentViewer = aViewer;
if (mContentViewer) {
gHistoryTracker->AddObject(this);
nsCOMPtr<nsIDOMDocument> domDoc;
mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
// Store observed document in strong pointer in case it is removed from
// the contentviewer
mDocument = do_QueryInterface(domDoc);
if (mDocument) {
mDocument->SetBFCacheEntry(this);
mDocument->AddMutationObserver(this);
}
}
return NS_OK;
}
nsresult
nsSHEntryShared::RemoveFromBFCacheSync()
{
NS_ASSERTION(mContentViewer && mDocument,
"we're not in the bfcache!");
nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
DropPresentationState();
// Warning! The call to DropPresentationState could have dropped the last
// reference to this object, so don't access members beyond here.
if (viewer) {
viewer->Destroy();
}
return NS_OK;
}
class DestroyViewerEvent : public nsRunnable
{
public:
DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument)
: mViewer(aViewer),
mDocument(aDocument)
{}
NS_IMETHOD Run()
{
if (mViewer) {
mViewer->Destroy();
}
return NS_OK;
}
nsCOMPtr<nsIContentViewer> mViewer;
nsCOMPtr<nsIDocument> mDocument;
};
nsresult
nsSHEntryShared::RemoveFromBFCacheAsync()
{
NS_ASSERTION(mContentViewer && mDocument,
"we're not in the bfcache!");
// Release the reference to the contentviewer asynchronously so that the
// document doesn't get nuked mid-mutation.
nsCOMPtr<nsIRunnable> evt =
new DestroyViewerEvent(mContentViewer, mDocument);
nsresult rv = NS_DispatchToCurrentThread(evt);
if (NS_FAILED(rv)) {
NS_WARNING("failed to dispatch DestroyViewerEvent");
} else {
// Drop presentation. Only do this if we succeeded in posting the event
// since otherwise the document could be torn down mid-mutation, causing
// crashes.
DropPresentationState();
}
// Careful! The call to DropPresentationState could have dropped the last
// reference to this nsSHEntryShared, so don't access members beyond here.
return NS_OK;
}
nsresult
nsSHEntryShared::GetID(PRUint64 *aID)
{
*aID = mID;
return NS_OK;
}
//*****************************************************************************
// nsSHEntryShared: nsIMutationObserver
//*****************************************************************************
void
nsSHEntryShared::NodeWillBeDestroyed(const nsINode* aNode)
{
NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
}
void
nsSHEntryShared::CharacterDataWillChange(nsIDocument* aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
}
void
nsSHEntryShared::CharacterDataChanged(nsIDocument* aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntryShared::AttributeWillChange(nsIDocument* aDocument,
dom::Element* aContent,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType)
{
}
void
nsSHEntryShared::AttributeChanged(nsIDocument* aDocument,
dom::Element* aElement,
PRInt32 aNameSpaceID,
nsIAtom* aAttribute,
PRInt32 aModType)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntryShared::ContentAppended(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aFirstNewContent,
PRInt32 /* unused */)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntryShared::ContentInserted(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 /* unused */)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntryShared::ContentRemoved(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
PRInt32 aIndexInContainer,
nsIContent* aPreviousSibling)
{
RemoveFromBFCacheAsync();
}
void
nsSHEntryShared::ParentChainChanged(nsIContent *aContent)
{
}

Просмотреть файл

@ -0,0 +1,124 @@
/* ***** 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 the Mozilla Foundation.
*
* Portions created by the Initial Developer are Copyright (C) 2011
* 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 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 ***** */
#ifndef nsSHEntryShared_h__
#define nsSHEntryShared_h__
#include "nsCOMPtr.h"
#include "nsAutoPtr.h"
#include "nsCOMArray.h"
#include "nsIBFCacheEntry.h"
#include "nsIMutationObserver.h"
#include "nsExpirationTracker.h"
#include "nsRect.h"
class nsSHEntry;
class nsISHEntry;
class nsIDocument;
class nsIContentViewer;
class nsIDocShellTreeItem;
class nsILayoutHistoryState;
class nsISupportsArray;
class nsDocShellEditorData;
// A document may have multiple SHEntries, either due to hash navigations or
// calls to history.pushState. SHEntries corresponding to the same document
// share many members; in particular, they share state related to the
// back/forward cache.
//
// nsSHEntryShared is the vehicle for this sharing.
class nsSHEntryShared : public nsIBFCacheEntry,
public nsIMutationObserver
{
public:
static void Startup();
static void Shutdown();
nsSHEntryShared();
~nsSHEntryShared();
NS_DECL_ISUPPORTS
NS_DECL_NSIMUTATIONOBSERVER
NS_DECL_NSIBFCACHEENTRY
private:
friend class nsSHEntry;
friend class HistoryTracker;
friend class nsExpirationTracker<nsSHEntryShared, 3>;
nsExpirationState *GetExpirationState() { return &mExpirationState; }
static already_AddRefed<nsSHEntryShared> Duplicate(nsSHEntryShared *aEntry);
void RemoveFromExpirationTracker();
void Expire();
nsresult SyncPresentationState();
void DropPresentationState();
nsresult SetContentViewer(nsIContentViewer *aViewer);
// See nsISHEntry.idl for an explanation of these members.
// These members are copied by nsSHEntryShared::Duplicate(). If you add a
// member here, be sure to update the Duplicate() implementation.
PRUint64 mDocShellID;
nsCOMArray<nsIDocShellTreeItem> mChildShells;
nsCOMPtr<nsISupports> mOwner;
nsISHEntry* mParent;
nsCString mContentType;
bool mIsFrameNavigation;
bool mSaveLayoutState;
bool mSticky;
bool mDynamicallyCreated;
nsCOMPtr<nsISupports> mCacheKey;
PRUint32 mLastTouched;
// These members aren't copied by nsSHEntryShared::Duplicate() because
// they're specific to a particular content viewer.
PRUint64 mID;
nsCOMPtr<nsIContentViewer> mContentViewer;
nsCOMPtr<nsIDocument> mDocument;
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
bool mExpired;
nsCOMPtr<nsISupports> mWindowState;
nsIntRect mViewerBounds;
nsCOMPtr<nsISupportsArray> mRefreshURIList;
nsExpirationState mExpirationState;
nsAutoPtr<nsDocShellEditorData> mEditorData;
};
#endif

Просмотреть файл

@ -72,12 +72,10 @@ using namespace mozilla;
#define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries" #define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
#define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers" #define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers"
#define PREF_SHISTORY_OPTIMIZE_EVICTION "browser.sessionhistory.optimize_eviction"
static const char* kObservedPrefs[] = { static const char* kObservedPrefs[] = {
PREF_SHISTORY_SIZE, PREF_SHISTORY_SIZE,
PREF_SHISTORY_MAX_TOTAL_VIEWERS, PREF_SHISTORY_MAX_TOTAL_VIEWERS,
PREF_SHISTORY_OPTIMIZE_EVICTION,
nsnull nsnull
}; };
@ -90,16 +88,46 @@ static PRCList gSHistoryList;
// means we will calculate how many viewers to cache based on total memory // means we will calculate how many viewers to cache based on total memory
PRInt32 nsSHistory::sHistoryMaxTotalViewers = -1; PRInt32 nsSHistory::sHistoryMaxTotalViewers = -1;
// Whether we should optimize the search for which entry to evict,
// by evicting older entries first. See entryLastTouched in
// nsSHistory::EvictGlobalContentViewer().
// NB: After 4.0, we should remove this option and the corresponding
// pref - optimization should always be used
static bool gOptimizeEviction = false;
// A counter that is used to be able to know the order in which // A counter that is used to be able to know the order in which
// entries were touched, so that we can evict older entries first. // entries were touched, so that we can evict older entries first.
static PRUint32 gTouchCounter = 0; static PRUint32 gTouchCounter = 0;
static PRLogModuleInfo* gLogModule = PR_LOG_DEFINE("nsSHistory");
#define LOG(format) PR_LOG(gLogModule, PR_LOG_DEBUG, format)
// This macro makes it easier to print a log message which includes a URI's
// spec. Example use:
//
// nsIURI *uri = [...];
// LOG_SPEC(("The URI is %s.", _spec), uri);
//
#define LOG_SPEC(format, uri) \
PR_BEGIN_MACRO \
if (PR_LOG_TEST(gLogModule, PR_LOG_DEBUG)) { \
nsCAutoString _specStr(NS_LITERAL_CSTRING("(null)"));\
if (uri) { \
uri->GetSpec(_specStr); \
} \
const char* _spec = _specStr.get(); \
LOG(format); \
} \
PR_END_MACRO
// This macro makes it easy to log a message including an SHEntry's URI.
// For example:
//
// nsCOMPtr<nsISHEntry> shentry = [...];
// LOG_SHENTRY_SPEC(("shentry %p has uri %s.", shentry.get(), _spec), shentry);
//
#define LOG_SHENTRY_SPEC(format, shentry) \
PR_BEGIN_MACRO \
if (PR_LOG_TEST(gLogModule, PR_LOG_DEBUG)) { \
nsCOMPtr<nsIURI> uri; \
shentry->GetURI(getter_AddRefs(uri)); \
LOG_SPEC(format, uri); \
} \
PR_END_MACRO
enum HistCmd{ enum HistCmd{
HIST_CMD_BACK, HIST_CMD_BACK,
HIST_CMD_FORWARD, HIST_CMD_FORWARD,
@ -134,15 +162,60 @@ nsSHistoryObserver::Observe(nsISupports *aSubject, const char *aTopic,
{ {
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
nsSHistory::UpdatePrefs(); nsSHistory::UpdatePrefs();
nsSHistory::EvictGlobalContentViewer(); nsSHistory::GloballyEvictContentViewers();
} else if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID) || } else if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID) ||
!strcmp(aTopic, "memory-pressure")) { !strcmp(aTopic, "memory-pressure")) {
nsSHistory::EvictAllContentViewersGlobally(); nsSHistory::GloballyEvictAllContentViewers();
} }
return NS_OK; return NS_OK;
} }
namespace {
already_AddRefed<nsIContentViewer>
GetContentViewerForTransaction(nsISHTransaction *aTrans)
{
nsCOMPtr<nsISHEntry> entry;
aTrans->GetSHEntry(getter_AddRefs(entry));
if (!entry) {
return nsnull;
}
nsCOMPtr<nsISHEntry> ownerEntry;
nsCOMPtr<nsIContentViewer> viewer;
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
getter_AddRefs(viewer));
return viewer.forget();
}
void
EvictContentViewerForTransaction(nsISHTransaction *aTrans)
{
nsCOMPtr<nsISHEntry> entry;
aTrans->GetSHEntry(getter_AddRefs(entry));
nsCOMPtr<nsIContentViewer> viewer;
nsCOMPtr<nsISHEntry> ownerEntry;
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
getter_AddRefs(viewer));
if (viewer) {
NS_ASSERTION(ownerEntry,
"Content viewer exists but its SHEntry is null");
LOG_SHENTRY_SPEC(("Evicting content viewer 0x%p for "
"owning SHEntry 0x%p at %s.",
viewer.get(), ownerEntry.get(), _spec), ownerEntry);
// Drop the presentation state before destroying the viewer, so that
// document teardown is able to correctly persist the state.
ownerEntry->SetContentViewer(nsnull);
ownerEntry->SyncPresentationState();
viewer->Destroy();
}
}
} // anonymous namespace
//***************************************************************************** //*****************************************************************************
//*** nsSHistory: Object Management //*** nsSHistory: Object Management
//***************************************************************************** //*****************************************************************************
@ -240,7 +313,6 @@ nsSHistory::UpdatePrefs()
Preferences::GetInt(PREF_SHISTORY_SIZE, &gHistoryMaxSize); Preferences::GetInt(PREF_SHISTORY_SIZE, &gHistoryMaxSize);
Preferences::GetInt(PREF_SHISTORY_MAX_TOTAL_VIEWERS, Preferences::GetInt(PREF_SHISTORY_MAX_TOTAL_VIEWERS,
&sHistoryMaxTotalViewers); &sHistoryMaxTotalViewers);
Preferences::GetBool(PREF_SHISTORY_OPTIMIZE_EVICTION, &gOptimizeEviction);
// If the pref is negative, that means we calculate how many viewers // If the pref is negative, that means we calculate how many viewers
// we think we should cache, based on total memory // we think we should cache, based on total memory
if (sHistoryMaxTotalViewers < 0) { if (sHistoryMaxTotalViewers < 0) {
@ -689,12 +761,12 @@ nsSHistory::GetListener(nsISHistoryListener ** aListener)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHistory::EvictContentViewers(PRInt32 aPreviousIndex, PRInt32 aIndex) nsSHistory::EvictOutOfRangeContentViewers(PRInt32 aIndex)
{ {
// Check our per SHistory object limit in the currently navigated SHistory // Check our per SHistory object limit in the currently navigated SHistory
EvictWindowContentViewers(aPreviousIndex, aIndex); EvictOutOfRangeWindowContentViewers(aIndex);
// Check our total limit across all SHistory objects // Check our total limit across all SHistory objects
EvictGlobalContentViewer(); GloballyEvictContentViewers();
return NS_OK; return NS_OK;
} }
@ -703,7 +775,14 @@ nsSHistory::EvictAllContentViewers()
{ {
// XXXbz we don't actually do a good job of evicting things as we should, so // XXXbz we don't actually do a good job of evicting things as we should, so
// we might have viewers quite far from mIndex. So just evict everything. // we might have viewers quite far from mIndex. So just evict everything.
EvictContentViewersInRange(0, mLength); nsCOMPtr<nsISHTransaction> trans = mListRoot;
while (trans) {
EvictContentViewerForTransaction(trans);
nsISHTransaction *temp = trans;
temp->GetNext(getter_AddRefs(trans));
}
return NS_OK; return NS_OK;
} }
@ -835,103 +914,78 @@ nsSHistory::ReloadCurrentEntry()
} }
void void
nsSHistory::EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex) nsSHistory::EvictOutOfRangeWindowContentViewers(PRInt32 aIndex)
{ {
// To enforce the per SHistory object limit on cached content viewers, we // XXX rename method to EvictContentViewersExceptAroundIndex, or something.
// need to release all of the content viewers that are no longer in the
// "window" that now ends/begins at aToIndex. Existing content viewers // We need to release all content viewers that are no longer in the range
// should be in the window from
// aFromIndex - gHistoryMaxViewers to aFromIndex + gHistoryMaxViewers
// //
// We make the assumption that entries outside this range have no viewers so // aIndex - gHistoryMaxViewers to aIndex + gHistoryMaxViewers
// that we don't have to walk the whole entire session history checking for //
// content viewers. // to ensure that this SHistory object isn't responsible for more than
// gHistoryMaxViewers content viewers. But our job is complicated by the
// fact that two transactions which are related by either hash navigations or
// history.pushState will have the same content viewer.
//
// To illustrate the issue, suppose gHistoryMaxViewers = 3 and we have four
// linked transactions in our history. Suppose we then add a new content
// viewer and call into this function. So the history looks like:
//
// A A A A B
// + *
//
// where the letters are content viewers and + and * denote the beginning and
// end of the range aIndex +/- gHistoryMaxViewers.
//
// Although one copy of the content viewer A exists outside the range, we
// don't want to evict A, because it has other copies in range!
//
// We therefore adjust our eviction strategy to read:
//
// Evict each content viewer outside the range aIndex -/+
// gHistoryMaxViewers, unless that content viewer also appears within the
// range.
//
// (Note that it's entirely legal to have two copies of one content viewer
// separated by a different content viewer -- call pushState twice, go back
// once, and refresh -- so we can't rely on identical viewers only appearing
// adjacent to one another.)
// This can happen on the first load of a page in a particular window if (aIndex < 0) {
if (aFromIndex < 0 || aToIndex < 0) {
return; return;
} }
NS_ASSERTION(aFromIndex < mLength, "aFromIndex is out of range"); NS_ASSERTION(aIndex < mLength, "aIndex is out of range");
NS_ASSERTION(aToIndex < mLength, "aToIndex is out of range"); if (aIndex >= mLength) {
if (aFromIndex >= mLength || aToIndex >= mLength) {
return; return;
} }
// These indices give the range of SHEntries whose content viewers will be // Calculate the range that's safe from eviction.
// evicted PRInt32 startSafeIndex = PR_MAX(0, aIndex - gHistoryMaxViewers);
PRInt32 startIndex, endIndex; PRInt32 endSafeIndex = PR_MIN(mLength, aIndex + gHistoryMaxViewers);
if (aToIndex > aFromIndex) { // going forward
endIndex = aToIndex - gHistoryMaxViewers;
if (endIndex <= 0) {
return;
}
startIndex = NS_MAX(0, aFromIndex - gHistoryMaxViewers);
} else { // going backward
startIndex = aToIndex + gHistoryMaxViewers + 1;
if (startIndex >= mLength) {
return;
}
endIndex = NS_MIN(mLength, aFromIndex + gHistoryMaxViewers + 1);
}
#ifdef DEBUG LOG(("EvictOutOfRangeWindowContentViewers(index=%d), "
"mLength=%d. Safe range [%d, %d]",
aIndex, mLength, startSafeIndex, endSafeIndex));
// The content viewers in range aIndex -/+ gHistoryMaxViewers will not be
// evicted. Collect a set of them so we don't accidentally evict one of them
// if it appears outside this range.
nsCOMArray<nsIContentViewer> safeViewers;
nsCOMPtr<nsISHTransaction> trans; nsCOMPtr<nsISHTransaction> trans;
GetTransactionAtIndex(startSafeIndex, getter_AddRefs(trans));
for (PRUint32 i = startSafeIndex; trans && i <= endSafeIndex; i++) {
nsCOMPtr<nsIContentViewer> viewer = GetContentViewerForTransaction(trans);
safeViewers.AppendObject(viewer);
nsISHTransaction *temp = trans;
temp->GetNext(getter_AddRefs(trans));
}
// Walk the SHistory list and evict any content viewers that aren't safe.
GetTransactionAtIndex(0, getter_AddRefs(trans)); GetTransactionAtIndex(0, getter_AddRefs(trans));
while (trans) {
// Walk the full session history and check that entries outside the window nsCOMPtr<nsIContentViewer> viewer = GetContentViewerForTransaction(trans);
// around aFromIndex have no content viewers if (safeViewers.IndexOf(viewer) == -1) {
for (PRInt32 i = 0; trans && i < mLength; ++i) { EvictContentViewerForTransaction(trans);
if (i < aFromIndex - gHistoryMaxViewers ||
i > aFromIndex + gHistoryMaxViewers) {
nsCOMPtr<nsISHEntry> entry;
trans->GetSHEntry(getter_AddRefs(entry));
nsCOMPtr<nsIContentViewer> viewer;
nsCOMPtr<nsISHEntry> ownerEntry;
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
getter_AddRefs(viewer));
NS_WARN_IF_FALSE(!viewer,
"ContentViewer exists outside gHistoryMaxViewer range");
}
nsISHTransaction *temp = trans;
temp->GetNext(getter_AddRefs(trans));
}
#endif
EvictContentViewersInRange(startIndex, endIndex);
}
void
nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd)
{
nsCOMPtr<nsISHTransaction> trans;
GetTransactionAtIndex(aStart, getter_AddRefs(trans));
for (PRInt32 i = aStart; trans && i < aEnd; ++i) {
nsCOMPtr<nsISHEntry> entry;
trans->GetSHEntry(getter_AddRefs(entry));
nsCOMPtr<nsIContentViewer> viewer;
nsCOMPtr<nsISHEntry> ownerEntry;
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
getter_AddRefs(viewer));
if (viewer) {
NS_ASSERTION(ownerEntry,
"ContentViewer exists but its SHEntry is null");
#ifdef DEBUG_PAGE_CACHE
nsCOMPtr<nsIURI> uri;
ownerEntry->GetURI(getter_AddRefs(uri));
nsCAutoString spec;
if (uri)
uri->GetSpec(spec);
printf("per SHistory limit: evicting content viewer: %s\n", spec.get());
#endif
// Drop the presentation state before destroying the viewer, so that
// document teardown is able to correctly persist the state.
ownerEntry->SetContentViewer(nsnull);
ownerEntry->SyncPresentationState();
viewer->Destroy();
} }
nsISHTransaction *temp = trans; nsISHTransaction *temp = trans;
@ -939,138 +993,153 @@ nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd)
} }
} }
// static namespace {
void
nsSHistory::EvictGlobalContentViewer() class TransactionAndDistance
{ {
// true until the total number of content viewers is <= total max public:
// The usual case is that we only need to evict one content viewer. TransactionAndDistance(nsISHTransaction *aTrans, PRUint32 aDist)
// However, if somebody resets the pref value, we might occasionally : mTransaction(aTrans)
// need to evict more than one. , mDistance(aDist)
bool shouldTryEviction = true; {
while (shouldTryEviction) { mViewer = GetContentViewerForTransaction(aTrans);
// Walk through our list of SHistory objects, looking for content NS_ASSERTION(mViewer, "Transaction should have a content viewer");
// viewers in the possible active window of all of the SHEntry objects.
// Keep track of the SHEntry object that has a ContentViewer and is
// farthest from the current focus in any SHistory object. The
// ContentViewer associated with that SHEntry will be evicted
PRInt32 distanceFromFocus = 0;
PRUint32 candidateLastTouched = 0;
nsCOMPtr<nsISHEntry> evictFromSHE;
nsCOMPtr<nsIContentViewer> evictViewer;
PRInt32 totalContentViewers = 0;
nsSHistory* shist = static_cast<nsSHistory*>
(PR_LIST_HEAD(&gSHistoryList));
while (shist != &gSHistoryList) {
// Calculate the window of SHEntries that could possibly have a content
// viewer. There could be up to gHistoryMaxViewers content viewers,
// but we don't know whether they are before or after the mIndex position
// in the SHEntry list. Just check both sides, to be safe.
PRInt32 startIndex = NS_MAX(0, shist->mIndex - gHistoryMaxViewers);
PRInt32 endIndex = NS_MIN(shist->mLength - 1,
shist->mIndex + gHistoryMaxViewers);
nsCOMPtr<nsISHTransaction> trans;
shist->GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
for (PRInt32 i = startIndex; trans && i <= endIndex; ++i) { nsCOMPtr<nsISHEntry> shentry;
nsCOMPtr<nsISHEntry> entry; mTransaction->GetSHEntry(getter_AddRefs(shentry));
trans->GetSHEntry(getter_AddRefs(entry));
nsCOMPtr<nsIContentViewer> viewer;
nsCOMPtr<nsISHEntry> ownerEntry;
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
getter_AddRefs(viewer));
PRUint32 entryLastTouched = 0; nsCOMPtr<nsISHEntryInternal> shentryInternal = do_QueryInterface(shentry);
if (gOptimizeEviction) { if (shentryInternal) {
nsCOMPtr<nsISHEntryInternal> entryInternal = do_QueryInterface(entry); shentryInternal->GetLastTouched(&mLastTouched);
if (entryInternal) {
// Find when this entry was last activated
entryInternal->GetLastTouched(&entryLastTouched);
}
}
#ifdef DEBUG_PAGE_CACHE
nsCOMPtr<nsIURI> uri;
if (ownerEntry) {
ownerEntry->GetURI(getter_AddRefs(uri));
} else {
entry->GetURI(getter_AddRefs(uri));
}
nsCAutoString spec;
if (uri) {
uri->GetSpec(spec);
printf("Considering for eviction: %s\n", spec.get());
}
#endif
// This SHEntry has a ContentViewer, so check how far away it is from
// the currently used SHEntry within this SHistory object
if (viewer) {
PRInt32 distance = NS_ABS(shist->mIndex - i);
#ifdef DEBUG_PAGE_CACHE
printf("Has a cached content viewer: %s\n", spec.get());
printf("mIndex: %d i: %d\n", shist->mIndex, i);
#endif
totalContentViewers++;
// If this entry is further away from focus than any previously found
// or at the same distance but it is longer time since it was activated
// then take this entry as the new candiate for eviction
if (distance > distanceFromFocus || (distance == distanceFromFocus && candidateLastTouched > entryLastTouched)) {
#ifdef DEBUG_PAGE_CACHE
printf("Choosing as new eviction candidate: %s\n", spec.get());
#endif
candidateLastTouched = entryLastTouched;
distanceFromFocus = distance;
evictFromSHE = ownerEntry;
evictViewer = viewer;
}
}
nsISHTransaction* temp = trans;
temp->GetNext(getter_AddRefs(trans));
}
shist = static_cast<nsSHistory*>(PR_NEXT_LINK(shist));
}
#ifdef DEBUG_PAGE_CACHE
printf("Distance from focus: %d\n", distanceFromFocus);
printf("Total max viewers: %d\n", sHistoryMaxTotalViewers);
printf("Total number of viewers: %d\n", totalContentViewers);
#endif
if (totalContentViewers > sHistoryMaxTotalViewers && evictViewer) {
#ifdef DEBUG_PAGE_CACHE
nsCOMPtr<nsIURI> uri;
evictFromSHE->GetURI(getter_AddRefs(uri));
nsCAutoString spec;
if (uri) {
uri->GetSpec(spec);
printf("Evicting content viewer: %s\n", spec.get());
}
#endif
// Drop the presentation state before destroying the viewer, so that
// document teardown is able to correctly persist the state.
evictFromSHE->SetContentViewer(nsnull);
evictFromSHE->SyncPresentationState();
evictViewer->Destroy();
// If we only needed to evict one content viewer, then we are done.
// Otherwise, continue evicting until we reach the max total limit.
if (totalContentViewers - sHistoryMaxTotalViewers == 1) {
shouldTryEviction = false;
}
} else { } else {
// couldn't find a content viewer to evict, so we are done NS_WARNING("Can't cast to nsISHEntryInternal?");
shouldTryEviction = false; mLastTouched = 0;
} }
} // while shouldTryEviction }
bool operator<(const TransactionAndDistance &aOther) const
{
// Compare distances first, and fall back to last-accessed times.
if (aOther.mDistance != this->mDistance) {
return this->mDistance < aOther.mDistance;
}
return this->mLastTouched < aOther.mLastTouched;
}
bool operator==(const TransactionAndDistance &aOther) const
{
// This is a little silly; we need == so the default comaprator can be
// instantiated, but this function is never actually called when we sort
// the list of TransactionAndDistance objects.
return aOther.mDistance == this->mDistance &&
aOther.mLastTouched == this->mLastTouched;
}
nsCOMPtr<nsISHTransaction> mTransaction;
nsCOMPtr<nsIContentViewer> mViewer;
PRUint32 mLastTouched;
PRInt32 mDistance;
};
} // anonymous namespace
//static
void
nsSHistory::GloballyEvictContentViewers()
{
// First, collect from each SHistory object the transactions which have a
// cached content viewer. Associate with each transaction its distance from
// its SHistory's current index.
nsTArray<TransactionAndDistance> transactions;
nsSHistory *shist = static_cast<nsSHistory*>(PR_LIST_HEAD(&gSHistoryList));
while (shist != &gSHistoryList) {
// Maintain a list of the transactions which have viewers and belong to
// this particular shist object. We'll add this list to the global list,
// |transactions|, eventually.
nsTArray<TransactionAndDistance> shTransactions;
// Content viewers are likely to exist only within shist->mIndex -/+
// gHistoryMaxViewers, so only search within that range.
//
// A content viewer might exist outside that range due to either:
//
// * history.pushState or hash navigations, in which case a copy of the
// content viewer should exist within the range, or
//
// * bugs which cause us not to call nsSHistory::EvictContentViewers()
// often enough. Once we do call EvictContentViewers() for the
// SHistory object in question, we'll do a full search of its history
// and evict the out-of-range content viewers, so we don't bother here.
//
PRInt32 startIndex = NS_MAX(0, shist->mIndex - gHistoryMaxViewers);
PRInt32 endIndex = NS_MIN(shist->mLength - 1,
shist->mIndex + gHistoryMaxViewers);
nsCOMPtr<nsISHTransaction> trans;
shist->GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
for (PRInt32 i = startIndex; trans && i <= endIndex; i++) {
nsCOMPtr<nsIContentViewer> contentViewer =
GetContentViewerForTransaction(trans);
if (contentViewer) {
// Because one content viewer might belong to multiple SHEntries, we
// have to search through shTransactions to see if we already know
// about this content viewer. If we find the viewer, update its
// distance from the SHistory's index and continue.
bool found = false;
for (PRUint32 j = 0; j < shTransactions.Length(); j++) {
TransactionAndDistance &container = shTransactions[j];
if (container.mViewer == contentViewer) {
container.mDistance = PR_MIN(container.mDistance,
PR_ABS(i - shist->mIndex));
found = true;
break;
}
}
// If we didn't find a TransactionAndDistance for this content viewer, make a new
// one.
if (!found) {
TransactionAndDistance container(trans, PR_ABS(i - shist->mIndex));
shTransactions.AppendElement(container);
}
}
nsISHTransaction *temp = trans;
temp->GetNext(getter_AddRefs(trans));
}
// We've found all the transactions belonging to shist which have viewers.
// Add those transactions to our global list and move on.
transactions.AppendElements(shTransactions);
shist = static_cast<nsSHistory*>(PR_NEXT_LINK(shist));
}
// We now have collected all cached content viewers. First check that we
// have enough that we actually need to evict some.
if ((PRInt32)transactions.Length() <= sHistoryMaxTotalViewers) {
return;
}
// If we need to evict, sort our list of transactions and evict the largest
// ones. (We could of course get better algorithmic complexity here by using
// a heap or something more clever. But sHistoryMaxTotalViewers isn't large,
// so let's not worry about it.)
transactions.Sort();
for (PRInt32 i = transactions.Length() - 1;
i >= sHistoryMaxTotalViewers; --i) {
EvictContentViewerForTransaction(transactions[i].mTransaction);
}
} }
NS_IMETHODIMP nsresult
nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry) nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry *aEntry)
{ {
PRInt32 startIndex = NS_MAX(0, mIndex - gHistoryMaxViewers); PRInt32 startIndex = NS_MAX(0, mIndex - gHistoryMaxViewers);
PRInt32 endIndex = NS_MIN(mLength - 1, PRInt32 endIndex = NS_MIN(mLength - 1,
@ -1082,8 +1151,11 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry)
for (i = startIndex; trans && i <= endIndex; ++i) { for (i = startIndex; trans && i <= endIndex; ++i) {
nsCOMPtr<nsISHEntry> entry; nsCOMPtr<nsISHEntry> entry;
trans->GetSHEntry(getter_AddRefs(entry)); trans->GetSHEntry(getter_AddRefs(entry));
if (entry == aEntry)
// Does entry have the same BFCacheEntry as the argument to this method?
if (entry->HasBFCacheEntry(aEntry)) {
break; break;
}
nsISHTransaction *temp = trans; nsISHTransaction *temp = trans;
temp->GetNext(getter_AddRefs(trans)); temp->GetNext(getter_AddRefs(trans));
@ -1091,21 +1163,13 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry)
if (i > endIndex) if (i > endIndex)
return NS_OK; return NS_OK;
NS_ASSERTION(i != mIndex, "How did the current session entry expire?"); if (i == mIndex) {
if (i == mIndex) NS_WARNING("How did the current SHEntry expire?");
return NS_OK; return NS_OK;
// We evict content viewers for the expired entry and any other entries that
// we would have to go through the expired entry to get to (i.e. the entries
// that have the expired entry between them and the current entry). Those
// other entries should have timed out already, actually, but this is just
// to be on the safe side.
if (i < mIndex) {
EvictContentViewersInRange(startIndex, i + 1);
} else {
EvictContentViewersInRange(i, endIndex + 1);
} }
EvictContentViewerForTransaction(trans);
return NS_OK; return NS_OK;
} }
@ -1116,11 +1180,11 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry)
//static //static
void void
nsSHistory::EvictAllContentViewersGlobally() nsSHistory::GloballyEvictAllContentViewers()
{ {
PRInt32 maxViewers = sHistoryMaxTotalViewers; PRInt32 maxViewers = sHistoryMaxTotalViewers;
sHistoryMaxTotalViewers = 0; sHistoryMaxTotalViewers = 0;
EvictGlobalContentViewer(); GloballyEvictContentViewers();
sHistoryMaxTotalViewers = maxViewers; sHistoryMaxTotalViewers = maxViewers;
} }

Просмотреть файл

@ -101,12 +101,11 @@ protected:
nsresult PrintHistory(); nsresult PrintHistory();
#endif #endif
// Evict the viewers at indices between aStartIndex and aEndIndex, // Evict content viewers in this window which don't lie in the "safe" range
// including aStartIndex but not aEndIndex. // around aIndex.
void EvictContentViewersInRange(PRInt32 aStartIndex, PRInt32 aEndIndex); void EvictOutOfRangeWindowContentViewers(PRInt32 aIndex);
void EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex); static void GloballyEvictContentViewers();
static void EvictGlobalContentViewer(); static void GloballyEvictAllContentViewers();
static void EvictAllContentViewersGlobally();
// Calculates a max number of total // Calculates a max number of total
// content viewers to cache, based on amount of total memory // content viewers to cache, based on amount of total memory

Просмотреть файл

@ -119,6 +119,7 @@ _TEST_FILES = \
test_bug669671.html \ test_bug669671.html \
file_bug669671.sjs \ file_bug669671.sjs \
test_bug675587.html \ test_bug675587.html \
test_bfcache_plus_hash.html \
test_bug680257.html \ test_bug680257.html \
file_bug680257.html \ file_bug680257.html \
$(NULL) $(NULL)

Просмотреть файл

@ -50,6 +50,9 @@
const LISTEN_EVENTS = ["pageshow"]; const LISTEN_EVENTS = ["pageshow"];
const Cc = Components.classes;
const Ci = Components.interfaces;
var gBrowser; var gBrowser;
var gTestCount = 0; var gTestCount = 0;
var gTestsIterator; var gTestsIterator;
@ -96,6 +99,23 @@
QueryInterface(Components.interfaces.nsISHEntry); QueryInterface(Components.interfaces.nsISHEntry);
is(!!shEntry.contentViewer, gExpected[i], "content viewer "+i+", test "+gTestCount); is(!!shEntry.contentViewer, gExpected[i], "content viewer "+i+", test "+gTestCount);
} }
// Make sure none of the SHEntries share bfcache entries with one
// another.
for (var i = 0; i < history.count; i++) {
for (var j = 0; j < history.count; j++) {
if (j == i)
continue;
let shentry1 = history.getEntryAtIndex(i, false)
.QueryInterface(Ci.nsISHEntry);
let shentry2 = history.getEntryAtIndex(j, false)
.QueryInterface(Ci.nsISHEntry);
ok(!shentry1.sharesDocumentWith(shentry2),
'Test ' + gTestCount + ': shentry[' + i + "] shouldn't " +
"share document with shentry[" + j + ']');
}
}
} }
else { else {
is(history.count, gExpected.length, "Wrong history length in test "+gTestCount); is(history.count, gExpected.length, "Wrong history length in test "+gTestCount);

Просмотреть файл

@ -0,0 +1,120 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=646641
-->
<head>
<title>Test for Bug 646641</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.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=646641">Mozilla Bug 646641</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
/** Test for Bug 646641 **/
/*
* In a popup (because navigating the main frame confuses Mochitest), do the
* following:
*
* * Call history.pushState().
* * Navigate to a new page.
* * Go back two history entries.
*
* Check that we go back, we retrieve the document from bfcache.
*/
SimpleTest.waitForExplicitFinish();
function debug(msg) {
// Wrap dump so we can turn debug messages on and off easily.
dump(msg + '\n');
}
var expectedLoadNum = -1;
function childLoad(n) {
if (n == expectedLoadNum) {
debug('Got load ' + n);
expectedLoadNum = -1;
// Spin the event loop before calling gGen.next() so the generator runs
// outside the onload handler. This prevents us from encountering all
// sorts of docshell quirks.
//
// (I don't know why I need to wrap gGen.next() in a function, but it
// throws an error otherwise.)
setTimeout(function() { gGen.next() }, 0);
}
else {
debug('Got unexpected load ' + n);
ok(false, 'Got unexpected load ' + n);
}
}
var expectedPageshowNum = -1;
function childPageshow(n) {
if (n == expectedPageshowNum) {
debug('Got expected pageshow ' + n);
expectedPageshowNum = -1;
ok(true, 'Got expected pageshow ' + n);
setTimeout(function() { gGen.next() }, 0);
}
else {
debug('Got pageshow ' + n);
}
// Since a pageshow comes along with an onload, don't fail the test if we get
// an unexpected pageshow.
}
function waitForLoad(n) {
debug('Waiting for load ' + n);
expectedLoadNum = n;
}
function waitForShow(n) {
debug('Waiting for show ' + n);
expectedPageshowNum = n;
}
function test() {
var popup = window.open('data:text/html,' +
'<html><body onload="opener.childLoad(1)" ' +
'onpageshow="opener.childPageshow(1)">' +
'Popup 1' +
'</body></html>');
waitForLoad(1);
yield;
popup.history.pushState('', '', '');
popup.location = 'data:text/html,<html><body onload="opener.childLoad(2)">Popup 2</body></html>';
waitForLoad(2);
yield;
// Now go back 2. The first page should be retrieved from bfcache.
popup.history.go(-2);
waitForShow(1);
yield;
popup.close();
SimpleTest.finish();
// Yield once more so we don't throw a StopIteration exception.
yield;
}
var gGen = test();
gGen.next();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -228,12 +228,9 @@ public:
// First check if the document the IDBDatabase is part of is bfcached // First check if the document the IDBDatabase is part of is bfcached
nsCOMPtr<nsIDocument> ownerDoc = database->GetOwnerDocument(); nsCOMPtr<nsIDocument> ownerDoc = database->GetOwnerDocument();
nsISHEntry* shEntry; nsIBFCacheEntry* bfCacheEntry;
if (ownerDoc && (shEntry = ownerDoc->GetBFCacheEntry())) { if (ownerDoc && (bfCacheEntry = ownerDoc->GetBFCacheEntry())) {
nsCOMPtr<nsISHEntryInternal> sheInternal = do_QueryInterface(shEntry); bfCacheEntry->RemoveFromBFCacheSync();
if (sheInternal) {
sheInternal->RemoveFromBFCacheSync();
}
NS_ASSERTION(database->IsClosed(), NS_ASSERTION(database->IsClosed(),
"Kicking doc out of bfcache should have closed database"); "Kicking doc out of bfcache should have closed database");
continue; continue;

Просмотреть файл

@ -63,6 +63,7 @@ using nsMouseScrollEvent;
using nsKeyEvent; using nsKeyEvent;
using RemoteDOMEvent; using RemoteDOMEvent;
using mozilla::WindowsHandle; using mozilla::WindowsHandle;
using nscolor;
namespace mozilla { namespace mozilla {
namespace dom { namespace dom {
@ -190,6 +191,7 @@ parent:
sync GetWidgetNativeData() returns (WindowsHandle value); sync GetWidgetNativeData() returns (WindowsHandle value);
SetCursor(PRUint32 value); SetCursor(PRUint32 value);
SetBackgroundColor(nscolor color);
PContentPermissionRequest(nsCString aType, URI uri); PContentPermissionRequest(nsCString aType, URI uri);

Просмотреть файл

@ -123,6 +123,7 @@ TabChild::TabChild(PRUint32 aChromeFlags)
, mTabChildGlobal(nsnull) , mTabChildGlobal(nsnull)
, mChromeFlags(aChromeFlags) , mChromeFlags(aChromeFlags)
, mOuterRect(0, 0, 0, 0) , mOuterRect(0, 0, 0, 0)
, mLastBackgroundColor(NS_RGB(255, 255, 255))
{ {
printf("creating %d!\n", NS_IsMainThread()); printf("creating %d!\n", NS_IsMainThread());
} }
@ -1000,6 +1001,15 @@ TabChild::InitWidget(const nsIntSize& size)
return true; return true;
} }
void
TabChild::SetBackgroundColor(const nscolor& aColor)
{
if (mLastBackgroundColor != aColor) {
mLastBackgroundColor = aColor;
SendSetBackgroundColor(mLastBackgroundColor);
}
}
static bool static bool
SendSyncMessageToParent(void* aCallbackData, SendSyncMessageToParent(void* aCallbackData,
const nsAString& aMessage, const nsAString& aMessage,
@ -1121,4 +1131,3 @@ TabChildGlobal::GetPrincipal()
return nsnull; return nsnull;
return mTabChild->GetPrincipal(); return mTabChild->GetPrincipal();
} }

Просмотреть файл

@ -255,6 +255,7 @@ public:
nsIPrincipal* GetPrincipal() { return mPrincipal; } nsIPrincipal* GetPrincipal() { return mPrincipal; }
void SetBackgroundColor(const nscolor& aColor);
protected: protected:
NS_OVERRIDE NS_OVERRIDE
virtual PRenderFrameChild* AllocPRenderFrame(); virtual PRenderFrameChild* AllocPRenderFrame();
@ -278,6 +279,7 @@ private:
nsRefPtr<TabChildGlobal> mTabChildGlobal; nsRefPtr<TabChildGlobal> mTabChildGlobal;
PRUint32 mChromeFlags; PRUint32 mChromeFlags;
nsIntRect mOuterRect; nsIntRect mOuterRect;
nscolor mLastBackgroundColor;
DISALLOW_EVIL_CONSTRUCTORS(TabChild); DISALLOW_EVIL_CONSTRUCTORS(TabChild);
}; };

Просмотреть файл

@ -341,6 +341,17 @@ TabParent::RecvSetCursor(const PRUint32& aCursor)
return true; return true;
} }
bool
TabParent::RecvSetBackgroundColor(const nscolor& aColor)
{
if (nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader()) {
if (RenderFrameParent* frame = frameLoader->GetCurrentRemoteFrame()) {
frame->SetBackgroundColor(aColor);
}
}
return true;
}
bool bool
TabParent::RecvNotifyIMEFocus(const bool& aFocus, TabParent::RecvNotifyIMEFocus(const bool& aFocus,
nsIMEUpdatePreference* aPreference, nsIMEUpdatePreference* aPreference,

Просмотреть файл

@ -108,6 +108,7 @@ public:
virtual bool RecvGetIMEOpenState(bool* aValue); virtual bool RecvGetIMEOpenState(bool* aValue);
virtual bool RecvSetIMEOpenState(const bool& aValue); virtual bool RecvSetIMEOpenState(const bool& aValue);
virtual bool RecvSetCursor(const PRUint32& aValue); virtual bool RecvSetCursor(const PRUint32& aValue);
virtual bool RecvSetBackgroundColor(const nscolor& aValue);
virtual bool RecvGetDPI(float* aValue); virtual bool RecvGetDPI(float* aValue);
virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue); virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType, virtual PContentDialogParent* AllocPContentDialog(const PRUint32& aType,

Просмотреть файл

@ -37,6 +37,8 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "mozilla/Util.h"
#include "Events.h" #include "Events.h"
#include "jsapi.h" #include "jsapi.h"
@ -57,6 +59,7 @@
#define CONSTANT_FLAGS \ #define CONSTANT_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY
using namespace mozilla;
USING_WORKERS_NAMESPACE USING_WORKERS_NAMESPACE
namespace { namespace {
@ -1126,7 +1129,7 @@ DispatchEventToTarget(JSContext* aCx, JSObject* aTarget, JSObject* aEvent,
if (hasProperty) { if (hasProperty) {
jsval argv[] = { OBJECT_TO_JSVAL(aEvent) }; jsval argv[] = { OBJECT_TO_JSVAL(aEvent) };
jsval rval = JSVAL_VOID; jsval rval = JSVAL_VOID;
if (!JS_CallFunctionName(aCx, aTarget, kFunctionName, JS_ARRAY_LENGTH(argv), if (!JS_CallFunctionName(aCx, aTarget, kFunctionName, ArrayLength(argv),
argv, &rval) || argv, &rval) ||
!JS_ValueToBoolean(aCx, rval, &preventDefaultCalled)) { !JS_ValueToBoolean(aCx, rval, &preventDefaultCalled)) {
return false; return false;

Просмотреть файл

@ -37,6 +37,8 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "mozilla/Util.h"
#include "Exceptions.h" #include "Exceptions.h"
#include "jsapi.h" #include "jsapi.h"
@ -54,6 +56,7 @@
#define CONSTANT_FLAGS \ #define CONSTANT_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY
using namespace mozilla;
USING_WORKERS_NAMESPACE USING_WORKERS_NAMESPACE
namespace { namespace {
@ -247,9 +250,7 @@ DOMException::Create(JSContext* aCx, intN aCode)
} }
size_t foundIndex = size_t(-1); size_t foundIndex = size_t(-1);
for (size_t index = 0; for (size_t index = 0; index < ArrayLength(sStaticProperties) - 1; index++) {
index < JS_ARRAY_LENGTH(sStaticProperties) - 1;
index++) {
if (sStaticProperties[index].tinyid == aCode) { if (sStaticProperties[index].tinyid == aCode) {
foundIndex = index; foundIndex = index;
break; break;
@ -397,9 +398,7 @@ FileException::Create(JSContext* aCx, intN aCode)
} }
size_t foundIndex = size_t(-1); size_t foundIndex = size_t(-1);
for (size_t index = 0; for (size_t index = 0; index < ArrayLength(sStaticProperties) - 1; index++) {
index < JS_ARRAY_LENGTH(sStaticProperties) - 1;
index++) {
if (sStaticProperties[index].tinyid == aCode) { if (sStaticProperties[index].tinyid == aCode) {
foundIndex = index; foundIndex = index;
break; break;

Просмотреть файл

@ -36,6 +36,8 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "mozilla/Util.h"
#include "ListenerManager.h" #include "ListenerManager.h"
#include "jsapi.h" #include "jsapi.h"
@ -44,7 +46,8 @@
#include "Events.h" #include "Events.h"
using mozilla::dom::workers::events::ListenerManager; using namespace mozilla;
using dom::workers::events::ListenerManager;
namespace { namespace {
@ -426,7 +429,7 @@ ListenerManager::DispatchEvent(JSContext* aCx, JSObject* aTarget,
jsval argv[] = { OBJECT_TO_JSVAL(aEvent) }; jsval argv[] = { OBJECT_TO_JSVAL(aEvent) };
jsval rval = JSVAL_VOID; jsval rval = JSVAL_VOID;
if (!JS_CallFunctionValue(aCx, aTarget, listenerVal, JS_ARRAY_LENGTH(argv), if (!JS_CallFunctionValue(aCx, aTarget, listenerVal, ArrayLength(argv),
argv, &rval)) { argv, &rval)) {
if (!JS_ReportPendingException(aCx)) { if (!JS_ReportPendingException(aCx)) {
return false; return false;

Просмотреть файл

@ -37,6 +37,8 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "mozilla/Util.h"
#include "WorkerScope.h" #include "WorkerScope.h"
#include "jsapi.h" #include "jsapi.h"
@ -68,6 +70,7 @@
#define FUNCTION_FLAGS \ #define FUNCTION_FLAGS \
JSPROP_ENUMERATE JSPROP_ENUMERATE
using namespace mozilla;
USING_WORKERS_NAMESPACE USING_WORKERS_NAMESPACE
namespace { namespace {
@ -287,7 +290,7 @@ private:
jsval rval = JSVAL_VOID; jsval rval = JSVAL_VOID;
if (!JS_CallFunctionValue(aCx, JSVAL_TO_OBJECT(scope), listener, if (!JS_CallFunctionValue(aCx, JSVAL_TO_OBJECT(scope), listener,
JS_ARRAY_LENGTH(argv), argv, &rval)) { ArrayLength(argv), argv, &rval)) {
JS_ReportPendingException(aCx); JS_ReportPendingException(aCx);
return false; return false;
} }

Просмотреть файл

@ -150,7 +150,6 @@ MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@
MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@ MOZ_OPTIMIZE_SIZE_TWEAK = @MOZ_OPTIMIZE_SIZE_TWEAK@
MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@ MOZ_RTTI_FLAGS_ON = @_MOZ_RTTI_FLAGS_ON@
MOZ_EXCEPTIONS_FLAGS_ON = @_MOZ_EXCEPTIONS_FLAGS_ON@
PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@ PROFILE_GEN_CFLAGS = @PROFILE_GEN_CFLAGS@
PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@ PROFILE_GEN_LDFLAGS = @PROFILE_GEN_LDFLAGS@

Просмотреть файл

@ -362,9 +362,6 @@ endif
endif # !GNU_CC endif # !GNU_CC
ifdef ENABLE_CXX_EXCEPTIONS
CXXFLAGS += $(MOZ_EXCEPTIONS_FLAGS_ON) -DMOZ_CPP_EXCEPTIONS=1
endif # ENABLE_CXX_EXCEPTIONS
endif # WINNT endif # WINNT
ifeq ($(SOLARIS_SUNPRO_CXX),1) ifeq ($(SOLARIS_SUNPRO_CXX),1)

Просмотреть файл

@ -752,8 +752,6 @@ case "$target" in
_MOZ_RTTI_FLAGS_ON='-GR' _MOZ_RTTI_FLAGS_ON='-GR'
_MOZ_RTTI_FLAGS_OFF='-GR-' _MOZ_RTTI_FLAGS_OFF='-GR-'
_MOZ_EXCEPTIONS_FLAGS_ON='-EHsc'
_MOZ_EXCEPTIONS_FLAGS_OFF=''
dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool', dnl Ensure that mt.exe is 'Microsoft (R) Manifest Tool',
dnl not something else like "magnetic tape manipulation utility". dnl not something else like "magnetic tape manipulation utility".
@ -1491,8 +1489,6 @@ if test "$GNU_CC"; then
ASFLAGS="$ASFLAGS -fPIC" ASFLAGS="$ASFLAGS -fPIC"
_MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti _MOZ_RTTI_FLAGS_ON=${_COMPILER_PREFIX}-frtti
_MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti _MOZ_RTTI_FLAGS_OFF=${_COMPILER_PREFIX}-fno-rtti
_MOZ_EXCEPTIONS_FLAGS_ON='-fexceptions'
_MOZ_EXCEPTIONS_FLAGS_OFF='-fno-exceptions'
# Turn on GNU specific features # Turn on GNU specific features
# -Wall - turn on all warnings # -Wall - turn on all warnings
@ -2336,9 +2332,7 @@ ia64*-hpux*)
LIBS="-lCrun -lCstd -lc $LIBS" LIBS="-lCrun -lCstd -lc $LIBS"
AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES) AC_DEFINE(NSCAP_DISABLE_DEBUG_PTR_TYPES)
CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__" CFLAGS="$CFLAGS -xlibmieee -xstrconst -xbuiltin=%all -D__FUNCTION__=__func__"
CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions -norunpath -D__FUNCTION__=__func__ -template=no%extdef" CXXFLAGS="$CXXFLAGS -xlibmieee -xbuiltin=%all -features=tmplife,tmplrefstatic,extensions,no%except -norunpath -D__FUNCTION__=__func__ -template=no%extdef"
_MOZ_EXCEPTIONS_FLAGS_ON='-features=except'
_MOZ_EXCEPTIONS_FLAGS_OFF='-features=no%except'
LDFLAGS="-xildoff $LDFLAGS" LDFLAGS="-xildoff $LDFLAGS"
if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then if test -z "$CROSS_COMPILE" -a -f /usr/lib/ld/map.noexstk; then
_SAVE_LDFLAGS=$LDFLAGS _SAVE_LDFLAGS=$LDFLAGS
@ -4856,24 +4850,6 @@ fi
AC_SUBST(_MOZ_RTTI_FLAGS_ON) AC_SUBST(_MOZ_RTTI_FLAGS_ON)
dnl ========================================================
dnl C++ exceptions (g++/VC/Sun only - for now)
dnl Should be smarter and check that the compiler does indeed have exceptions
dnl ========================================================
MOZ_ARG_ENABLE_BOOL(cpp-exceptions,
[ --enable-cpp-exceptions Enable C++ exceptions ],
[ _MOZ_CPP_EXCEPTIONS=1 ],
[ _MOZ_CPP_EXCEPTIONS= ])
if test "$_MOZ_CPP_EXCEPTIONS"; then
_MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_ON
AC_DEFINE(MOZ_CPP_EXCEPTIONS)
else
_MOZ_EXCEPTIONS_FLAGS=$_MOZ_EXCEPTIONS_FLAGS_OFF
fi
AC_SUBST(_MOZ_EXCEPTIONS_FLAGS_ON)
AC_DEFINE(CPP_THROW_NEW, [throw()]) AC_DEFINE(CPP_THROW_NEW, [throw()])
AC_LANG_C AC_LANG_C
@ -5138,7 +5114,6 @@ CFLAGS=`echo \
CXXFLAGS=`echo \ CXXFLAGS=`echo \
$_MOZ_RTTI_FLAGS \ $_MOZ_RTTI_FLAGS \
$_MOZ_EXCEPTIONS_FLAGS \
$_WARNINGS_CXXFLAGS \ $_WARNINGS_CXXFLAGS \
$CXXFLAGS` $CXXFLAGS`

Просмотреть файл

@ -425,7 +425,7 @@ BytecodeCompiler::compileFunctionBody(JSContext *cx, JSFunction *fun, JSPrincipa
if (nargs) { if (nargs) {
/* /*
* NB: do not use AutoLocalNameArray because it will release space * NB: do not use AutoLocalNameArray because it will release space
* allocated from cx->tempPool by DefineArg. * allocated from cx->tempLifoAlloc by DefineArg.
*/ */
Vector<JSAtom *> names(cx); Vector<JSAtom *> names(cx);
if (!funcg.bindings.getLocalNameArray(cx, &names)) { if (!funcg.bindings.getLocalNameArray(cx, &names)) {

Просмотреть файл

@ -5556,13 +5556,301 @@ EmitWith(JSContext *cx, CodeGenerator *cg, ParseNode *pn, JSBool &ok)
return true; return true;
} }
static bool
EmitForIn(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top)
{
StmtInfo stmtInfo;
PushStatement(cg, &stmtInfo, STMT_FOR_IN_LOOP, top);
ParseNode *forHead = pn->pn_left;
ParseNode *forBody = pn->pn_right;
/*
* If the left part is 'var x', emit code to define x if necessary
* using a prolog opcode, but do not emit a pop. If the left part
* was originally 'var x = i', the parser will have rewritten it;
* see Parser::forStatement. 'for (let x = i in o)' is mercifully
* banned.
*/
bool forLet = false;
if (ParseNode *decl = forHead->pn_kid1) {
JS_ASSERT(TokenKindIsDecl(decl->getKind()));
forLet = decl->isKind(TOK_LET);
cg->flags |= TCF_IN_FOR_INIT;
if (!EmitTree(cx, cg, decl))
return false;
cg->flags &= ~TCF_IN_FOR_INIT;
}
/* Compile the object expression to the right of 'in'. */
{
TempPopScope tps;
if (forLet && !tps.popBlock(cx, cg))
return false;
if (!EmitTree(cx, cg, forHead->pn_kid3))
return false;
if (forLet && !tps.repushBlock(cx, cg))
return false;
}
/*
* Emit a bytecode to convert top of stack value to the iterator
* object depending on the loop variant (for-in, for-each-in, or
* destructuring for-in).
*/
JS_ASSERT(pn->isOp(JSOP_ITER));
if (Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
return false;
/* Annotate so the decompiler can find the loop-closing jump. */
intN noteIndex = NewSrcNote(cx, cg, SRC_FOR_IN);
if (noteIndex < 0)
return false;
/*
* Jump down to the loop condition to minimize overhead assuming at
* least one iteration, as the other loop forms do.
*/
ptrdiff_t jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
if (jmp < 0)
return false;
intN noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
if (noteIndex2 < 0)
return false;
top = CG_OFFSET(cg);
SET_STATEMENT_TOP(&stmtInfo, top);
if (EmitTraceOp(cx, cg, NULL) < 0)
return false;
#ifdef DEBUG
intN loopDepth = cg->stackDepth;
#endif
/*
* Emit code to get the next enumeration value and assign it to the
* left hand side. The JSOP_POP after this assignment is annotated
* so that the decompiler can distinguish 'for (x in y)' from
* 'for (var x in y)'.
*/
if (!EmitAssignment(cx, cg, forHead->pn_kid2, JSOP_NOP, NULL))
return false;
ptrdiff_t tmp2 = CG_OFFSET(cg);
if (forHead->pn_kid1 && NewSrcNote2(cx, cg, SRC_DECL,
(forHead->pn_kid1->isOp(JSOP_DEFVAR))
? SRC_DECL_VAR
: SRC_DECL_LET) < 0) {
return false;
}
if (Emit1(cx, cg, JSOP_POP) < 0)
return false;
/* The stack should be balanced around the assignment opcode sequence. */
JS_ASSERT(cg->stackDepth == loopDepth);
/* Emit code for the loop body. */
if (!EmitTree(cx, cg, forBody))
return false;
/* Set loop and enclosing "update" offsets, for continue. */
StmtInfo *stmt = &stmtInfo;
do {
stmt->update = CG_OFFSET(cg);
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
/*
* Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
*/
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
if (Emit1(cx, cg, JSOP_MOREITER) < 0)
return false;
ptrdiff_t beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
if (beq < 0)
return false;
/*
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
* note gets bigger.
*/
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top))
return false;
/* Set the first srcnote offset so we can find the start of the loop body. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp))
return false;
/* Set the second srcnote offset so we can find the closing jump. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp))
return false;
/* Now fixup all breaks and continues (before the JSOP_ENDITER). */
if (!PopStatementCG(cx, cg))
return false;
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)))
return false;
return Emit1(cx, cg, JSOP_ENDITER) >= 0;
}
static bool
EmitNormalFor(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top)
{
StmtInfo stmtInfo;
PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
ParseNode *forHead = pn->pn_left;
ParseNode *forBody = pn->pn_right;
/* C-style for (init; cond; update) ... loop. */
JSOp op = JSOP_POP;
ParseNode *pn3 = forHead->pn_kid1;
if (!pn3) {
/* No initializer: emit an annotated nop for the decompiler. */
op = JSOP_NOP;
} else {
cg->flags |= TCF_IN_FOR_INIT;
#if JS_HAS_DESTRUCTURING
if (pn3->isKind(TOK_ASSIGN) &&
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
return false;
}
#endif
if (op == JSOP_POP) {
if (!EmitTree(cx, cg, pn3))
return false;
if (TokenKindIsDecl(pn3->getKind())) {
/*
* Check whether a destructuring-initialized var decl
* was optimized to a group assignment. If so, we do
* not need to emit a pop below, so switch to a nop,
* just for the decompiler.
*/
JS_ASSERT(pn3->isArity(PN_LIST));
if (pn3->pn_xflags & PNX_GROUPINIT)
op = JSOP_NOP;
}
}
cg->flags &= ~TCF_IN_FOR_INIT;
}
/*
* NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
* Use tmp to hold the biased srcnote "top" offset, which differs
* from the top local variable by the length of the JSOP_GOTO{,X}
* emitted in between tmp and top if this loop has a condition.
*/
intN noteIndex = NewSrcNote(cx, cg, SRC_FOR);
if (noteIndex < 0 || Emit1(cx, cg, op) < 0)
return false;
ptrdiff_t tmp = CG_OFFSET(cg);
ptrdiff_t jmp = -1;
if (forHead->pn_kid2) {
/* Goto the loop condition, which branches back to iterate. */
jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
if (jmp < 0)
return false;
}
top = CG_OFFSET(cg);
SET_STATEMENT_TOP(&stmtInfo, top);
intN noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
if (noteIndex2 < 0)
return false;
/* Emit code for the loop body. */
if (EmitTraceOp(cx, cg, forBody) < 0)
return false;
if (!EmitTree(cx, cg, forBody))
return false;
/* Set the second note offset so we can find the update part. */
JS_ASSERT(noteIndex != -1);
ptrdiff_t tmp2 = CG_OFFSET(cg);
/* Set loop and enclosing "update" offsets, for continue. */
StmtInfo *stmt = &stmtInfo;
do {
stmt->update = CG_OFFSET(cg);
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
/* Check for update code to do before the condition (if any). */
pn3 = forHead->pn_kid3;
if (pn3) {
op = JSOP_POP;
#if JS_HAS_DESTRUCTURING
if (pn3->isKind(TOK_ASSIGN) &&
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
return false;
}
#endif
if (op == JSOP_POP && !EmitTree(cx, cg, pn3))
return false;
/* Always emit the POP or NOP, to help the decompiler. */
if (Emit1(cx, cg, op) < 0)
return false;
/* Restore the absolute line number for source note readers. */
ptrdiff_t lineno = pn->pn_pos.end.lineno;
if (CG_CURRENT_LINE(cg) != (uintN) lineno) {
if (NewSrcNote2(cx, cg, SRC_SETLINE, lineno) < 0)
return false;
CG_CURRENT_LINE(cg) = (uintN) lineno;
}
}
ptrdiff_t tmp3 = CG_OFFSET(cg);
if (forHead->pn_kid2) {
/* Fix up the goto from top to target the loop condition. */
JS_ASSERT(jmp >= 0);
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
if (!EmitTree(cx, cg, forHead->pn_kid2))
return false;
}
/*
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
* note gets bigger.
*/
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, CG_OFFSET(cg) - top))
return false;
/* Set the first note offset so we can find the loop condition. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp3 - tmp))
return false;
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, tmp2 - tmp))
return false;
/* The third note offset helps us find the loop-closing jump. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, CG_OFFSET(cg) - tmp))
return false;
/* If no loop condition, just emit a loop-closing jump. */
op = forHead->pn_kid2 ? JSOP_IFNE : JSOP_GOTO;
if (EmitJump(cx, cg, op, top - CG_OFFSET(cg)) < 0)
return false;
/* Now fixup all breaks and continues. */
return PopStatementCG(cx, cg);
}
static inline bool
EmitFor(JSContext *cx, CodeGenerator *cg, ParseNode *pn, ptrdiff_t top)
{
return pn->pn_left->isKind(TOK_IN)
? EmitForIn(cx, cg, pn, top)
: EmitNormalFor(cx, cg, pn, top);
}
JSBool JSBool
EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn) EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
{ {
JSBool useful, wantval; JSBool useful, wantval;
StmtInfo stmtInfo; StmtInfo stmtInfo;
StmtInfo *stmt; StmtInfo *stmt;
ptrdiff_t top, off, tmp, beq, jmp, tmp2, tmp3; ptrdiff_t top, off, tmp, beq, jmp;
ParseNode *pn2, *pn3; ParseNode *pn2, *pn3;
JSAtom *atom; JSAtom *atom;
jsatomid atomIndex; jsatomid atomIndex;
@ -5860,280 +6148,7 @@ EmitTree(JSContext *cx, CodeGenerator *cg, ParseNode *pn)
break; break;
case TOK_FOR: case TOK_FOR:
beq = 0; /* suppress gcc warnings */ ok = EmitFor(cx, cg, pn, top);
jmp = -1;
pn2 = pn->pn_left;
PushStatement(cg, &stmtInfo, STMT_FOR_LOOP, top);
if (pn2->isKind(TOK_IN)) {
/* Set stmtInfo type for later testing. */
stmtInfo.type = STMT_FOR_IN_LOOP;
/*
* If the left part is 'var x', emit code to define x if necessary
* using a prolog opcode, but do not emit a pop. If the left part
* was originally 'var x = i', the parser will have rewritten it;
* see Parser::forStatement. 'for (let x = i in o)' is mercifully
* banned.
*/
bool forLet = false;
if (ParseNode *decl = pn2->pn_kid1) {
JS_ASSERT(TokenKindIsDecl(decl->getKind()));
forLet = decl->isKind(TOK_LET);
cg->flags |= TCF_IN_FOR_INIT;
if (!EmitTree(cx, cg, decl))
return JS_FALSE;
cg->flags &= ~TCF_IN_FOR_INIT;
}
/* Compile the object expression to the right of 'in'. */
{
TempPopScope tps;
if (forLet && !tps.popBlock(cx, cg))
return JS_FALSE;
if (!EmitTree(cx, cg, pn2->pn_kid3))
return JS_FALSE;
if (forLet && !tps.repushBlock(cx, cg))
return JS_FALSE;
}
/*
* Emit a bytecode to convert top of stack value to the iterator
* object depending on the loop variant (for-in, for-each-in, or
* destructuring for-in).
*/
JS_ASSERT(pn->isOp(JSOP_ITER));
if (Emit2(cx, cg, JSOP_ITER, (uint8) pn->pn_iflags) < 0)
return JS_FALSE;
/* Annotate so the decompiler can find the loop-closing jump. */
noteIndex = NewSrcNote(cx, cg, SRC_FOR_IN);
if (noteIndex < 0)
return JS_FALSE;
/*
* Jump down to the loop condition to minimize overhead assuming at
* least one iteration, as the other loop forms do.
*/
jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
if (jmp < 0)
return JS_FALSE;
noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
if (noteIndex2 < 0)
return JS_FALSE;
top = CG_OFFSET(cg);
SET_STATEMENT_TOP(&stmtInfo, top);
if (EmitTraceOp(cx, cg, NULL) < 0)
return JS_FALSE;
#ifdef DEBUG
intN loopDepth = cg->stackDepth;
#endif
/*
* Emit code to get the next enumeration value and assign it to the
* left hand side. The JSOP_POP after this assignment is annotated
* so that the decompiler can distinguish 'for (x in y)' from
* 'for (var x in y)'.
*/
if (!EmitAssignment(cx, cg, pn2->pn_kid2, JSOP_NOP, NULL))
return false;
tmp2 = CG_OFFSET(cg);
if (pn2->pn_kid1 && NewSrcNote2(cx, cg, SRC_DECL, (pn2->pn_kid1->isOp(JSOP_DEFVAR))
? SRC_DECL_VAR
: SRC_DECL_LET) < 0)
{
return false;
}
if (Emit1(cx, cg, JSOP_POP) < 0)
return false;
/* The stack should be balanced around the assignment opcode sequence. */
JS_ASSERT(cg->stackDepth == loopDepth);
/* Emit code for the loop body. */
if (!EmitTree(cx, cg, pn->pn_right))
return JS_FALSE;
/* Set loop and enclosing "update" offsets, for continue. */
stmt = &stmtInfo;
do {
stmt->update = CG_OFFSET(cg);
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
/*
* Fixup the goto that starts the loop to jump down to JSOP_MOREITER.
*/
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
if (Emit1(cx, cg, JSOP_MOREITER) < 0)
return JS_FALSE;
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
if (beq < 0)
return JS_FALSE;
/*
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
* note gets bigger.
*/
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, beq - top))
return JS_FALSE;
/* Set the first srcnote offset so we can find the start of the loop body. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp2 - jmp))
return JS_FALSE;
/* Set the second srcnote offset so we can find the closing jump. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, beq - jmp))
return JS_FALSE;
} else {
/* C-style for (init; cond; update) ... loop. */
op = JSOP_POP;
pn3 = pn2->pn_kid1;
if (!pn3) {
/* No initializer: emit an annotated nop for the decompiler. */
op = JSOP_NOP;
} else {
cg->flags |= TCF_IN_FOR_INIT;
#if JS_HAS_DESTRUCTURING
if (pn3->isKind(TOK_ASSIGN) &&
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
return JS_FALSE;
}
#endif
if (op == JSOP_POP) {
if (!EmitTree(cx, cg, pn3))
return JS_FALSE;
if (TokenKindIsDecl(pn3->getKind())) {
/*
* Check whether a destructuring-initialized var decl
* was optimized to a group assignment. If so, we do
* not need to emit a pop below, so switch to a nop,
* just for the decompiler.
*/
JS_ASSERT(pn3->isArity(PN_LIST));
if (pn3->pn_xflags & PNX_GROUPINIT)
op = JSOP_NOP;
}
}
cg->flags &= ~TCF_IN_FOR_INIT;
}
/*
* NB: the SRC_FOR note has offsetBias 1 (JSOP_{NOP,POP}_LENGTH).
* Use tmp to hold the biased srcnote "top" offset, which differs
* from the top local variable by the length of the JSOP_GOTO{,X}
* emitted in between tmp and top if this loop has a condition.
*/
noteIndex = NewSrcNote(cx, cg, SRC_FOR);
if (noteIndex < 0 || Emit1(cx, cg, op) < 0)
return JS_FALSE;
tmp = CG_OFFSET(cg);
if (pn2->pn_kid2) {
/* Goto the loop condition, which branches back to iterate. */
jmp = EmitJump(cx, cg, JSOP_GOTO, 0);
if (jmp < 0)
return JS_FALSE;
}
top = CG_OFFSET(cg);
SET_STATEMENT_TOP(&stmtInfo, top);
noteIndex2 = NewSrcNote(cx, cg, SRC_TRACE);
if (noteIndex2 < 0)
return JS_FALSE;
/* Emit code for the loop body. */
if (EmitTraceOp(cx, cg, pn->pn_right) < 0)
return JS_FALSE;
if (!EmitTree(cx, cg, pn->pn_right))
return JS_FALSE;
/* Set the second note offset so we can find the update part. */
JS_ASSERT(noteIndex != -1);
tmp2 = CG_OFFSET(cg);
/* Set loop and enclosing "update" offsets, for continue. */
stmt = &stmtInfo;
do {
stmt->update = CG_OFFSET(cg);
} while ((stmt = stmt->down) != NULL && stmt->type == STMT_LABEL);
/* Check for update code to do before the condition (if any). */
pn3 = pn2->pn_kid3;
if (pn3) {
op = JSOP_POP;
#if JS_HAS_DESTRUCTURING
if (pn3->isKind(TOK_ASSIGN) &&
!MaybeEmitGroupAssignment(cx, cg, op, pn3, &op)) {
return JS_FALSE;
}
#endif
if (op == JSOP_POP && !EmitTree(cx, cg, pn3))
return JS_FALSE;
/* Always emit the POP or NOP, to help the decompiler. */
if (Emit1(cx, cg, op) < 0)
return JS_FALSE;
/* Restore the absolute line number for source note readers. */
off = (ptrdiff_t) pn->pn_pos.end.lineno;
if (CG_CURRENT_LINE(cg) != (uintN) off) {
if (NewSrcNote2(cx, cg, SRC_SETLINE, off) < 0)
return JS_FALSE;
CG_CURRENT_LINE(cg) = (uintN) off;
}
}
tmp3 = CG_OFFSET(cg);
if (pn2->pn_kid2) {
/* Fix up the goto from top to target the loop condition. */
JS_ASSERT(jmp >= 0);
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp);
if (!EmitTree(cx, cg, pn2->pn_kid2))
return JS_FALSE;
}
/*
* Be careful: We must set noteIndex2 before noteIndex in case the noteIndex
* note gets bigger.
*/
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex2, 0, CG_OFFSET(cg) - top))
return JS_FALSE;
/* Set the first note offset so we can find the loop condition. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 0, tmp3 - tmp))
return JS_FALSE;
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 1, tmp2 - tmp))
return JS_FALSE;
/* The third note offset helps us find the loop-closing jump. */
if (!SetSrcNoteOffset(cx, cg, (uintN)noteIndex, 2, CG_OFFSET(cg) - tmp))
return JS_FALSE;
if (pn2->pn_kid2) {
beq = EmitJump(cx, cg, JSOP_IFNE, top - CG_OFFSET(cg));
if (beq < 0)
return JS_FALSE;
} else {
/* No loop condition -- emit the loop-closing jump. */
jmp = EmitJump(cx, cg, JSOP_GOTO, top - CG_OFFSET(cg));
if (jmp < 0)
return JS_FALSE;
}
}
/* Now fixup all breaks and continues (before for/in's JSOP_ENDITER). */
if (!PopStatementCG(cx, cg))
return JS_FALSE;
if (pn2->isKind(TOK_IN)) {
if (!NewTryNote(cx, cg, JSTRY_ITER, cg->stackDepth, top, CG_OFFSET(cg)) ||
Emit1(cx, cg, JSOP_ENDITER) < 0)
{
return JS_FALSE;
}
}
break; break;
case TOK_BREAK: { case TOK_BREAK: {

Просмотреть файл

@ -678,9 +678,10 @@ struct CodeGenerator : public TreeContext
} }
/* /*
* Note that cgs are magic: they own the arena "top-of-stack" space above * Note that cgs are magic: they own the arena "top-of-stack" space
* their tempMark points. This means that you cannot alloc from tempPool * above their tempMark points. This means that you cannot alloc from
* and save the pointer beyond the next CodeGenerator destructor call. * tempLifoAlloc and save the pointer beyond the next CodeGenerator
* destructor call.
*/ */
~CodeGenerator(); ~CodeGenerator();

Просмотреть файл

@ -176,10 +176,11 @@ Parser::newObjectBox(JSObject *obj)
JS_ASSERT(obj); JS_ASSERT(obj);
/* /*
* We use JSContext.tempPool to allocate parsed objects and place them on * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
* a list in this Parser to ensure GC safety. Thus the tempPool arenas * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
* containing the entries must be alive until we are done with scanning, * arenas containing the entries must be alive until we are done with
* parsing and code generation for the whole script or top-level function. * scanning, parsing and code generation for the whole script or top-level
* function.
*/ */
ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>(); ObjectBox *objbox = context->tempLifoAlloc().new_<ObjectBox>();
if (!objbox) { if (!objbox) {
@ -201,10 +202,11 @@ Parser::newFunctionBox(JSObject *obj, ParseNode *fn, TreeContext *tc)
JS_ASSERT(obj->isFunction()); JS_ASSERT(obj->isFunction());
/* /*
* We use JSContext.tempPool to allocate parsed objects and place them on * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
* a list in this Parser to ensure GC safety. Thus the tempPool arenas * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
* containing the entries must be alive until we are done with scanning, * arenas containing the entries must be alive until we are done with
* parsing and code generation for the whole script or top-level function. * scanning, parsing and code generation for the whole script or top-level
* function.
*/ */
FunctionBox *funbox = context->tempLifoAlloc().newPod<FunctionBox>(); FunctionBox *funbox = context->tempLifoAlloc().newPod<FunctionBox>();
if (!funbox) { if (!funbox) {

Просмотреть файл

@ -102,7 +102,7 @@ struct Parser : private AutoGCRooter
JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */ JSContext *const context; /* FIXME Bug 551291: use AutoGCRooter::context? */
void *tempFreeList[NUM_TEMP_FREELISTS]; void *tempFreeList[NUM_TEMP_FREELISTS];
TokenStream tokenStream; TokenStream tokenStream;
void *tempPoolMark; /* initial JSContext.tempPool mark */ void *tempPoolMark; /* initial JSContext.tempLifoAlloc mark */
JSPrincipals *principals; /* principals associated with source */ JSPrincipals *principals; /* principals associated with source */
StackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */ StackFrame *const callerFrame; /* scripted caller frame for eval and dbgapi */
JSObject *const callerVarObj; /* callerFrame's varObj */ JSObject *const callerVarObj; /* callerFrame's varObj */
@ -125,10 +125,11 @@ struct Parser : private AutoGCRooter
friend struct BytecodeCompiler; friend struct BytecodeCompiler;
/* /*
* Initialize a parser. Parameters are passed on to init tokenStream. * Initialize a parser. Parameters are passed on to init tokenStream. The
* The compiler owns the arena pool "tops-of-stack" space above the current * compiler owns the arena pool "tops-of-stack" space above the current
* JSContext.tempPool mark. This means you cannot allocate from tempPool * JSContext.tempLifoAlloc mark. This means you cannot allocate from
* and save the pointer beyond the next Parser destructor invocation. * tempLifoAlloc and save the pointer beyond the next Parser destructor
* invocation.
*/ */
bool init(const jschar *base, size_t length, const char *filename, uintN lineno, bool init(const jschar *base, size_t length, const char *filename, uintN lineno,
JSVersion version); JSVersion version);
@ -150,7 +151,8 @@ struct Parser : private AutoGCRooter
#endif #endif
/* /*
* Allocate a new parsed object or function container from cx->tempPool. * Allocate a new parsed object or function container from
* cx->tempLifoAlloc.
*/ */
ObjectBox *newObjectBox(JSObject *obj); ObjectBox *newObjectBox(JSObject *obj);

Просмотреть файл

@ -384,7 +384,7 @@ class TokenStream
* first call |close| then call the destructor. If |init| fails, do not call * first call |close| then call the destructor. If |init| fails, do not call
* |close|. * |close|.
* *
* This class uses JSContext.tempPool to allocate internal buffers. The * This class uses JSContext.tempLifoAlloc to allocate internal buffers. The
* caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE * caller should JS_ARENA_MARK before calling |init| and JS_ARENA_RELEASE
* after calling |close|. * after calling |close|.
*/ */

Просмотреть файл

@ -2181,8 +2181,8 @@ Function(JSContext *cx, uintN argc, Value *vp)
/* /*
* Allocate a string to hold the concatenated arguments, including room * Allocate a string to hold the concatenated arguments, including room
* for a terminating 0. Mark cx->tempPool for later release, to free * for a terminating 0. Mark cx->tempLifeAlloc for later release, to
* collected_args and its tokenstream in one swoop. * free collected_args and its tokenstream in one swoop.
*/ */
LifoAllocScope las(&cx->tempLifoAlloc()); LifoAllocScope las(&cx->tempLifoAlloc());
jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1); jschar *cp = cx->tempLifoAlloc().newArray<jschar>(args_length + 1);

Просмотреть файл

@ -4067,10 +4067,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
LOAD_FUNCTION(0); LOAD_FUNCTION(0);
/* /*
* All allocation when decompiling is LIFO, using malloc * All allocation when decompiling is LIFO, using malloc or,
* or, more commonly, arena-allocating from cx->tempPool. * more commonly, arena-allocating from cx->tempLifoAlloc
* Therefore after InitSprintStack succeeds, we must * Therefore after InitSprintStack succeeds, we must release
* release to mark before returning. * to mark before returning.
*/ */
LifoAllocScope las(&cx->tempLifoAlloc()); LifoAllocScope las(&cx->tempLifoAlloc());
if (fun->script()->bindings.hasLocalNames()) { if (fun->script()->bindings.hasLocalNames()) {
@ -4179,9 +4179,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
} }
/* /*
* Alas, we have to malloc a copy of the result left on * Alas, we have to malloc a copy of the result left on the
* the top of ss2 because both ss and ss2 arena-allocate * top of ss2 because both ss and ss2 arena-allocate from
* from cx's tempPool. * cx's tempLifoAlloc
*/ */
rval = JS_strdup(cx, PopStr(&ss2, op)); rval = JS_strdup(cx, PopStr(&ss2, op));
las.releaseEarly(); las.releaseEarly();

Просмотреть файл

@ -648,8 +648,9 @@ js_XDRAtom(JSXDRState *xdr, JSAtom **atomp)
chars = stackChars; chars = stackChars;
} else { } else {
/* /*
* This is very uncommon. Don't use the tempPool arena for this as * This is very uncommon. Don't use the tempLifoAlloc arena for this as
* most allocations here will be bigger than tempPool's arenasize. * most allocations here will be bigger than tempLifoAlloc's default
* chunk size.
*/ */
chars = (jschar *) cx->malloc_(nchars * sizeof(jschar)); chars = (jschar *) cx->malloc_(nchars * sizeof(jschar));
if (!chars) if (!chars)

Просмотреть файл

@ -1959,7 +1959,7 @@ DocumentViewerImpl::Show(void)
printf("About to evict content viewers: prev=%d, loaded=%d\n", printf("About to evict content viewers: prev=%d, loaded=%d\n",
prevIndex, loadedIndex); prevIndex, loadedIndex);
#endif #endif
historyInt->EvictContentViewers(prevIndex, loadedIndex); historyInt->EvictOutOfRangeContentViewers(loadedIndex);
} }
} }
} }

Просмотреть файл

@ -56,6 +56,8 @@
/* a presentation of a document, part 2 */ /* a presentation of a document, part 2 */
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/TabChild.h"
#include "mozilla/Util.h" #include "mozilla/Util.h"
#include "nsPresShell.h" #include "nsPresShell.h"
@ -5092,6 +5094,11 @@ void PresShell::UpdateCanvasBackground()
if (!FrameConstructor()->GetRootElementFrame()) { if (!FrameConstructor()->GetRootElementFrame()) {
mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw(); mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw();
} }
if (XRE_GetProcessType() == GeckoProcessType_Content) {
if (TabChild* tabChild = GetTabChildFrom(this)) {
tabChild->SetBackgroundColor(mCanvasBackgroundColor);
}
}
} }
nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot) nscolor PresShell::ComputeBackstopColor(nsIView* aDisplayRoot)

Просмотреть файл

@ -114,7 +114,7 @@ private:
nsRect nsRect
nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) { nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) {
return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
} }
void void

Просмотреть файл

@ -153,7 +153,7 @@ public:
// override bounds because the list item focus ring may extend outside // override bounds because the list item focus ring may extend outside
// the nsSelectsAreaFrame // the nsSelectsAreaFrame
nsListControlFrame* listFrame = GetEnclosingListFrame(GetUnderlyingFrame()); nsListControlFrame* listFrame = GetEnclosingListFrame(GetUnderlyingFrame());
return listFrame->GetVisualOverflowRect() + return listFrame->GetVisualOverflowRectRelativeToSelf() +
aBuilder->ToReferenceFrame(listFrame); aBuilder->ToReferenceFrame(listFrame);
} }
virtual void Paint(nsDisplayListBuilder* aBuilder, virtual void Paint(nsDisplayListBuilder* aBuilder,

Просмотреть файл

@ -226,7 +226,7 @@ public:
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
{ {
return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
} }
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) { HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {

Просмотреть файл

@ -163,11 +163,15 @@ nsHTMLReflowState::nsHTMLReflowState(nsPresContext* aPresContext,
mLineLayout = aParentReflowState.mLineLayout; mLineLayout = aParentReflowState.mLineLayout;
else else
mLineLayout = nsnull; mLineLayout = nsnull;
mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage;
// Note: mFlags was initialized as a copy of aParentReflowState.mFlags up in
// this constructor's init list, so the only flags that we need to explicitly
// initialize here are those that may need a value other than our parent's.
mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched && mFlags.mNextInFlowUntouched = aParentReflowState.mFlags.mNextInFlowUntouched &&
CheckNextInFlowParenthood(aFrame, aParentReflowState.frame); CheckNextInFlowParenthood(aFrame, aParentReflowState.frame);
mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false; mFlags.mAssumingHScrollbar = mFlags.mAssumingVScrollbar = false;
mFlags.mHasClearance = false; mFlags.mHasClearance = false;
mDiscoveredClearance = nsnull; mDiscoveredClearance = nsnull;
mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver &&
aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this))

Просмотреть файл

@ -4137,7 +4137,7 @@ public:
#endif #endif
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
} }
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) { HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {

Просмотреть файл

@ -62,28 +62,6 @@ namespace layout {
typedef FrameMetrics::ViewID ViewID; typedef FrameMetrics::ViewID ViewID;
typedef RenderFrameParent::ViewMap ViewMap; typedef RenderFrameParent::ViewMap ViewMap;
nsRefPtr<ImageContainer> sCheckerboard = nsnull;
class CheckerBoardPatternDeleter : public nsIObserver
{
public:
NS_DECL_NSIOBSERVER
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS1(CheckerBoardPatternDeleter, nsIObserver)
NS_IMETHODIMP
CheckerBoardPatternDeleter::Observe(nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
if (!strcmp(aTopic, "xpcom-shutdown")) {
sCheckerboard = nsnull;
}
return NS_OK;
}
// Represents (affine) transforms that are calculated from a content view. // Represents (affine) transforms that are calculated from a content view.
struct ViewTransform { struct ViewTransform {
ViewTransform(nsIntPoint aTranslation = nsIntPoint(0, 0), float aXScale = 1, float aYScale = 1) ViewTransform(nsIntPoint aTranslation = nsIntPoint(0, 0), float aXScale = 1, float aYScale = 1)
@ -424,61 +402,14 @@ BuildViewMap(ViewMap& oldContentViews, ViewMap& newContentViews,
} }
} }
#define BOARDSIZE 32
#define CHECKERSIZE 16
already_AddRefed<gfxASurface>
GetBackgroundImage()
{
static unsigned int data[BOARDSIZE * BOARDSIZE];
static bool initialized = false;
if (!initialized) {
initialized = true;
for (unsigned int y = 0; y < BOARDSIZE; y++) {
for (unsigned int x = 0; x < BOARDSIZE; x++) {
bool col_odd = (x / CHECKERSIZE) & 1;
bool row_odd = (y / CHECKERSIZE) & 1;
if (col_odd ^ row_odd) { // xor
data[y * BOARDSIZE + x] = 0xFFFFFFFF;
}
else {
data[y * BOARDSIZE + x] = 0xFFDDDDDD;
}
}
}
}
nsRefPtr<gfxASurface> s =
new gfxImageSurface((unsigned char*) data,
gfxIntSize(BOARDSIZE, BOARDSIZE),
BOARDSIZE * sizeof(unsigned int),
gfxASurface::ImageFormatARGB32);
return s.forget();
}
static void static void
BuildBackgroundPatternFor(ContainerLayer* aContainer, BuildBackgroundPatternFor(ContainerLayer* aContainer,
ContainerLayer* aShadowRoot, ContainerLayer* aShadowRoot,
const FrameMetrics& aMetrics,
const ViewConfig& aConfig, const ViewConfig& aConfig,
const gfxRGBA& aColor,
LayerManager* aManager, LayerManager* aManager,
nsIFrame* aFrame, nsIFrame* aFrame)
nsDisplayListBuilder* aBuilder)
{ {
// We tile a visible region that is the frame's area \setminus the
// rect in our frame onto which valid pixels from remote content
// will be drawn. It's just a waste of CPU cycles to draw a
// checkerboard behind that content.
//
// We want to give the background the illusion of moving while the
// user pans, so we nudge the tiling area a bit based on the
// "desired" scroll offset.
//
// The background-image layer is added to the layer tree "behind"
// the shadow tree. It doesn't matter in theory which is behind/in
// front, except that having the background in front of content
// means we have to be more careful about snapping boundaries,
// whereas having it behind allows us to trade off simplicity for
// "wasted" drawing of a few extra pixels.
ShadowLayer* shadowRoot = aShadowRoot->AsShadowLayer(); ShadowLayer* shadowRoot = aShadowRoot->AsShadowLayer();
gfxMatrix t; gfxMatrix t;
if (!shadowRoot->GetShadowTransform().Is2D(&t)) { if (!shadowRoot->GetShadowTransform().Is2D(&t)) {
@ -505,57 +436,14 @@ BuildBackgroundPatternFor(ContainerLayer* aContainer,
if (localIntContentVis.Contains(frameRect)) { if (localIntContentVis.Contains(frameRect)) {
return; return;
} }
nsRefPtr<ColorLayer> layer = aManager->CreateColorLayer();
nsRefPtr<gfxASurface> bgImage = GetBackgroundImage(); layer->SetColor(aColor);
gfxIntSize bgImageSize = bgImage->GetSize();
// Set up goop needed to get a cairo image into its own layer
if (!sCheckerboard) {
sCheckerboard = aManager->CreateImageContainer().get();
const Image::Format fmts[] = { Image::CAIRO_SURFACE };
nsRefPtr<Image> img = sCheckerboard->CreateImage(fmts, 1);
CairoImage::Data data = { bgImage.get(), bgImageSize };
static_cast<CairoImage*>(img.get())->SetData(data);
sCheckerboard->SetCurrentImage(img);
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService();
if (!observerService) {
return;
}
nsresult rv = observerService->AddObserver(new CheckerBoardPatternDeleter, "xpcom-shutdown", false);
if (NS_FAILED(rv)) {
return;
}
}
nsRefPtr<ImageLayer> layer = aManager->CreateImageLayer();
layer->SetContainer(sCheckerboard);
// The tile source is the entire background image
nsIntRect tileSource(0, 0, bgImageSize.width, bgImageSize.height);
layer->SetTileSourceRect(&tileSource);
// The origin of the tiling plane, top-left of the tile source rect,
// is at layer-space point <0,0>. Set up a translation from that
// origin to the frame top-left, with the little nudge included.
nsIntPoint translation = frameRect.TopLeft();
nsIntPoint panNudge = aConfig.mScrollOffset.ToNearestPixels(auPerDevPixel);
// This offset must be positive to ensure that the tiling rect
// contains the frame's visible rect. The "desired" scroll offset
// is allowed to be negative, however, so we fix that up here.
panNudge.x = (panNudge.x % bgImageSize.width);
if (panNudge.x < 0) panNudge.x += bgImageSize.width;
panNudge.y = (panNudge.y % bgImageSize.height);
if (panNudge.y < 0) panNudge.y += bgImageSize.height;
translation -= panNudge;
layer->SetTransform(gfx3DMatrix::Translation(translation.x, translation.y, 0));
// The visible area of the background is the frame's area minus the // The visible area of the background is the frame's area minus the
// content area // content area
nsIntRegion bgRgn(frameRect); nsIntRegion bgRgn(frameRect);
bgRgn.Sub(bgRgn, localIntContentVis); bgRgn.Sub(bgRgn, localIntContentVis);
bgRgn.MoveBy(-translation); bgRgn.MoveBy(-frameRect.TopLeft());
layer->SetVisibleRegion(bgRgn); layer->SetVisibleRegion(bgRgn);
aContainer->InsertAfter(layer, nsnull); aContainer->InsertAfter(layer, nsnull);
@ -564,6 +452,7 @@ BuildBackgroundPatternFor(ContainerLayer* aContainer,
RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader) RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader)
: mFrameLoader(aFrameLoader) : mFrameLoader(aFrameLoader)
, mFrameLoaderDestroyed(false) , mFrameLoaderDestroyed(false)
, mBackgroundColor(gfxRGBA(1, 1, 1))
{ {
if (aFrameLoader) { if (aFrameLoader) {
mContentViews[FrameMetrics::ROOT_SCROLL_ID] = mContentViews[FrameMetrics::ROOT_SCROLL_ID] =
@ -691,9 +580,9 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
const nsContentView* view = GetContentView(FrameMetrics::ROOT_SCROLL_ID); const nsContentView* view = GetContentView(FrameMetrics::ROOT_SCROLL_ID);
BuildBackgroundPatternFor(mContainer, BuildBackgroundPatternFor(mContainer,
shadowRoot, shadowRoot,
shadowRoot->GetFrameMetrics(),
view->GetViewConfig(), view->GetViewConfig(),
aManager, aFrame, aBuilder); mBackgroundColor,
aManager, aFrame);
} }
mContainer->SetVisibleRegion(aVisibleRect); mContainer->SetVisibleRegion(aVisibleRect);

Просмотреть файл

@ -98,6 +98,8 @@ public:
void OwnerContentChanged(nsIContent* aContent); void OwnerContentChanged(nsIContent* aContent);
void SetBackgroundColor(nscolor aColor) { mBackgroundColor = gfxRGBA(aColor); };
protected: protected:
NS_OVERRIDE void ActorDestroy(ActorDestroyReason why); NS_OVERRIDE void ActorDestroy(ActorDestroyReason why);
@ -133,6 +135,8 @@ private:
// It's possible for mFrameLoader==null and // It's possible for mFrameLoader==null and
// mFrameLoaderDestroyed==false. // mFrameLoaderDestroyed==false.
bool mFrameLoaderDestroyed; bool mFrameLoaderDestroyed;
// this is gfxRGBA because that's what ColorLayer wants.
gfxRGBA mBackgroundColor;
}; };
} // namespace layout } // namespace layout

Просмотреть файл

@ -91,6 +91,7 @@ fails-if(!browserIsRemote) == test-displayport.html test-displayport-ref.html #
skip-if(!browserIsRemote) != test-displayport-2.html test-displayport-ref.html # bug 593168 skip-if(!browserIsRemote) != test-displayport-2.html test-displayport-ref.html # bug 593168
skip-if(!browserIsRemote) == 647192-1.html 647192-1-ref.html skip-if(!browserIsRemote) == 647192-1.html 647192-1-ref.html
skip-if(!browserIsRemote) == 656041-1.html 656041-1-ref.html skip-if(!browserIsRemote) == 656041-1.html 656041-1-ref.html
skip-if(!browserIsRemote) == test-displayport-bg.html test-displayport-ref.html # bug 694706
# IPC Position-fixed frames/layers test # IPC Position-fixed frames/layers test
# Fixed layers are temporarily disabled (bug 656167). # Fixed layers are temporarily disabled (bug 656167).

Просмотреть файл

@ -0,0 +1,7 @@
<!DOCTYPE HTML>
<html reftest-viewport-w="100" reftest-viewport-h="100"
reftest-displayport-w="400" reftest-displayport-h="500"
reftest-async-scroll=true>
<body bgcolor=green style="position: absolute; left:0px; top:0px;width:800px; height:1000px;"></body>
</html>

Просмотреть файл

@ -49,7 +49,7 @@ const CSS_TYPE_SHORTHAND_AND_LONGHAND = 2;
// Each property has the following fields: // Each property has the following fields:
// domProp: The name of the relevant member of nsIDOM[NS]CSS2Properties // domProp: The name of the relevant member of nsIDOM[NS]CSS2Properties
// inherited: Whether the property is inherited by default (stated as // inherited: Whether the property is inherited by default (stated as
// yes or no in the property header in all CSS specs) // yes or no in the property header in all CSS specs)
// type: see above // type: see above
// get_computed: if present, the property's computed value shows up on // get_computed: if present, the property's computed value shows up on
@ -1833,7 +1833,7 @@ var gCSSProperties = {
inherited: true, inherited: true,
type: CSS_TYPE_LONGHAND, type: CSS_TYPE_LONGHAND,
initial_values: [ "show" ], initial_values: [ "show" ],
other_values: [ "hide" ], other_values: [ "hide", "-moz-show-background" ],
invalid_values: [] invalid_values: []
}, },
"float": { "float": {
@ -1874,7 +1874,7 @@ var gCSSProperties = {
inherited: true, inherited: true,
type: CSS_TYPE_LONGHAND, type: CSS_TYPE_LONGHAND,
initial_values: [ "normal" ], initial_values: [ "normal" ],
other_values: [ "'TRK'", "\"TRK\"", "'N\\'Ko'" ], other_values: [ "'ENG'", "'TRK'", "\"TRK\"", "'N\\'Ko'" ],
invalid_values: [ "TRK" ] invalid_values: [ "TRK" ]
}, },
"font-size": { "font-size": {
@ -1935,7 +1935,7 @@ var gCSSProperties = {
type: CSS_TYPE_LONGHAND, type: CSS_TYPE_LONGHAND,
initial_values: [ "normal", "400" ], initial_values: [ "normal", "400" ],
other_values: [ "bold", "100", "200", "300", "500", "600", "700", "800", "900", "bolder", "lighter" ], other_values: [ "bold", "100", "200", "300", "500", "600", "700", "800", "900", "bolder", "lighter" ],
invalid_values: [ "107", "399", "401", "699", "710" ] invalid_values: [ "0", "100.0", "107", "399", "401", "699", "710", "1000" ]
}, },
"height": { "height": {
domProp: "height", domProp: "height",

Просмотреть файл

@ -257,6 +257,10 @@ function setupDisplayport(contentRootElement) {
LogInfo("Setting displayport to <x="+ dpx +", y="+ dpy +", w="+ dpw +", h="+ dph +">"); LogInfo("Setting displayport to <x="+ dpx +", y="+ dpy +", w="+ dpw +", h="+ dph +">");
windowUtils().setDisplayPortForElement(dpx, dpy, dpw, dph, content.document.documentElement); windowUtils().setDisplayPortForElement(dpx, dpy, dpw, dph, content.document.documentElement);
} }
var asyncScroll = attrOrDefault("reftest-async-scroll", false);
if (asyncScroll) {
SendEnableAsyncScroll();
}
// XXX support resolution when needed // XXX support resolution when needed
@ -751,6 +755,11 @@ function SendFailedLoad(why)
sendAsyncMessage("reftest:FailedLoad", { why: why }); sendAsyncMessage("reftest:FailedLoad", { why: why });
} }
function SendEnableAsyncScroll()
{
sendAsyncMessage("reftest:EnableAsyncScroll");
}
// Return true if a snapshot was taken. // Return true if a snapshot was taken.
function SendInitCanvasWithSnapshot() function SendInitCanvasWithSnapshot()
{ {

Просмотреть файл

@ -1346,6 +1346,7 @@ function FinishTestItem()
gDumpLog("REFTEST INFO | Loading a blank page\n"); gDumpLog("REFTEST INFO | Loading a blank page\n");
// After clearing, content will notify us of the assertion count // After clearing, content will notify us of the assertion count
// and tests will continue. // and tests will continue.
SetAsyncScroll(false);
SendClear(); SendClear();
} }
@ -1442,10 +1443,21 @@ function RegisterMessageListenersAndLoadContentScript()
"reftest:ExpectProcessCrash", "reftest:ExpectProcessCrash",
function (m) { RecvExpectProcessCrash(); } function (m) { RecvExpectProcessCrash(); }
); );
gBrowserMessageManager.addMessageListener(
"reftest:EnableAsyncScroll",
function (m) { SetAsyncScroll(true); }
);
gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true); gBrowserMessageManager.loadFrameScript("chrome://reftest/content/reftest-content.js", true);
} }
function SetAsyncScroll(enabled)
{
gBrowser.QueryInterface(CI.nsIFrameLoaderOwner).frameLoader.renderMode =
enabled ? CI.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL :
CI.nsIFrameLoader.RENDER_MODE_DEFAULT;
}
function RecvAssertionCount(count) function RecvAssertionCount(count)
{ {
DoAssertionCheck(count); DoAssertionCheck(count);

Просмотреть файл

@ -379,7 +379,7 @@ nsDisplayXULTextBox::PaintTextToContext(nsRenderingContext* aCtx,
nsRect nsRect
nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) { nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) {
return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame();
} }
nsRect nsRect

Просмотреть файл

@ -140,7 +140,6 @@ pref("browser.display.remotetabs.timeout", 10);
/* session history */ /* session history */
pref("browser.sessionhistory.max_total_viewers", 1); pref("browser.sessionhistory.max_total_viewers", 1);
pref("browser.sessionhistory.max_entries", 50); pref("browser.sessionhistory.max_entries", 50);
pref("browser.sessionhistory.optimize_eviction", true);
/* session store */ /* session store */
pref("browser.sessionstore.resume_session_once", false); pref("browser.sessionstore.resume_session_once", false);

Просмотреть файл

@ -268,8 +268,13 @@ let WebNavigation = {
if (aEntry.docshellID) if (aEntry.docshellID)
shEntry.docshellID = aEntry.docshellID; shEntry.docshellID = aEntry.docshellID;
if (aEntry.stateData) if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) {
shEntry.stateData = aEntry.stateData; shEntry.stateData =
Cc["@mozilla.org/docshell/structured-clone-container;1"].
createInstance(Ci.nsIStructuredCloneContainer);
shEntry.stateData.initFromBase64(aEntry.structuredCloneState, aEntry.structuredCloneVersion);
}
if (aEntry.scroll) { if (aEntry.scroll) {
let scrollPos = aEntry.scroll.split(","); let scrollPos = aEntry.scroll.split(",");
@ -278,23 +283,15 @@ let WebNavigation = {
} }
if (aEntry.docIdentifier) { if (aEntry.docIdentifier) {
// Get a new document identifier for this entry to ensure that history // If we have a serialized document identifier, try to find an SHEntry
// entries after a session restore are considered to have different // which matches that doc identifier and adopt that SHEntry's
// documents from the history entries before the session restore. // BFCacheEntry. If we don't find a match, insert shEntry as the match
// Document identifiers are 64-bit ints, so JS will loose precision and // for the document identifier.
// start assigning all entries the same doc identifier if these ever get let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
// large enough. if (!matchingEntry) {
// aDocIdentMap[aEntry.docIdentifier] = shEntry;
// It's a potential security issue if document identifiers aren't
// globally unique, but shEntry.setUniqueDocIdentifier() below guarantees
// that we won't re-use a doc identifier within a given instance of the
// application.
let ident = aDocIdentMap[aEntry.docIdentifier];
if (!ident) {
shEntry.setUniqueDocIdentifier();
aDocIdentMap[aEntry.docIdentifier] = shEntry.docIdentifier;
} else { } else {
shEntry.docIdentifier = ident; shEntry.adoptBFCacheEntry(matchingEntry);
} }
} }
@ -379,11 +376,12 @@ let WebNavigation = {
} catch (e) { dump(e); } } catch (e) { dump(e); }
} }
if (aEntry.docIdentifier) entry.docIdentifier = aEntry.BFCacheEntry.ID;
entry.docIdentifier = aEntry.docIdentifier;
if (aEntry.stateData) if (aEntry.stateData != null) {
entry.stateData = aEntry.stateData; entry.structuredCloneState = aEntry.stateData.getDataAsBase64();
entry.structuredCloneVersion = aEntry.stateData.formatVersion;
}
if (!(aEntry instanceof Ci.nsISHContainer)) if (!(aEntry instanceof Ci.nsISHContainer))
return entry; return entry;

Просмотреть файл

@ -109,8 +109,6 @@ pref("dom.enable_performance", true);
// of content viewers to cache based on the amount of available memory. // of content viewers to cache based on the amount of available memory.
pref("browser.sessionhistory.max_total_viewers", -1); pref("browser.sessionhistory.max_total_viewers", -1);
pref("browser.sessionhistory.optimize_eviction", true);
pref("ui.use_native_colors", true); pref("ui.use_native_colors", true);
pref("ui.click_hold_context_menus", false); pref("ui.click_hold_context_menus", false);
pref("browser.display.use_document_fonts", 1); // 0 = never, 1 = quick, 2 = always pref("browser.display.use_document_fonts", 1); // 0 = never, 1 = quick, 2 = always

Просмотреть файл

@ -52,15 +52,13 @@
#define NM_DBUS_SERVICE "org.freedesktop.NetworkManager" #define NM_DBUS_SERVICE "org.freedesktop.NetworkManager"
#define NM_DBUS_PATH "/org/freedesktop/NetworkManager" #define NM_DBUS_PATH "/org/freedesktop/NetworkManager"
#define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager" #define NM_DBUS_INTERFACE "org.freedesktop.NetworkManager"
#define NM_DBUS_SIGNAL_STATE_CHANGE "StateChange" #define NM_DBUS_SIGNAL_STATE_CHANGE "StateChange" /* Deprecated in 0.7.x */
typedef enum NMState #define NM_DBUS_SIGNAL_STATE_CHANGED "StateChanged"
{
NM_STATE_UNKNOWN = 0, #define NM_STATE_CONNECTED_OLD 3 /* Before NM 0.9.0 */
NM_STATE_ASLEEP, #define NM_STATE_CONNECTED_LOCAL 50
NM_STATE_CONNECTING, #define NM_STATE_CONNECTED_SITE 60
NM_STATE_CONNECTED, #define NM_STATE_CONNECTED_GLOBAL 70
NM_STATE_DISCONNECTED
} NMState;
nsNetworkManagerListener::nsNetworkManagerListener() : nsNetworkManagerListener::nsNetworkManagerListener() :
mLinkUp(true), mNetworkManagerActive(false), mLinkUp(true), mNetworkManagerActive(false),
@ -185,7 +183,9 @@ nsNetworkManagerListener::UnregisterWithConnection(DBusConnection* connection) {
bool bool
nsNetworkManagerListener::HandleMessage(DBusMessage* message) { nsNetworkManagerListener::HandleMessage(DBusMessage* message) {
if (dbus_message_is_signal(message, NM_DBUS_INTERFACE, if (dbus_message_is_signal(message, NM_DBUS_INTERFACE,
NM_DBUS_SIGNAL_STATE_CHANGE)) { NM_DBUS_SIGNAL_STATE_CHANGE) ||
dbus_message_is_signal(message, NM_DBUS_INTERFACE,
NM_DBUS_SIGNAL_STATE_CHANGED)) {
UpdateNetworkStatus(message); UpdateNetworkStatus(message);
return true; return true;
} }
@ -202,7 +202,10 @@ nsNetworkManagerListener::UpdateNetworkStatus(DBusMessage* msg) {
mNetworkManagerActive = true; mNetworkManagerActive = true;
bool wasUp = mLinkUp; bool wasUp = mLinkUp;
mLinkUp = result == NM_STATE_CONNECTED; mLinkUp = result == NM_STATE_CONNECTED_OLD ||
result == NM_STATE_CONNECTED_LOCAL ||
result == NM_STATE_CONNECTED_SITE ||
result == NM_STATE_CONNECTED_GLOBAL;
if (wasUp == mLinkUp) if (wasUp == mLinkUp)
return; return;

Просмотреть файл

@ -2817,7 +2817,7 @@ nsLocalFile::RevealUsingShell()
} }
const ITEMIDLIST* selection[] = { dir }; const ITEMIDLIST* selection[] = { dir };
UINT count = PR_ARRAY_SIZE(selection); UINT count = ArrayLength(selection);
//Perform the open of the directory. //Perform the open of the directory.
hr = sSHOpenFolderAndSelectItems(dir, count, selection, 0); hr = sSHOpenFolderAndSelectItems(dir, count, selection, 0);
@ -2846,7 +2846,7 @@ nsLocalFile::RevealUsingShell()
} }
const ITEMIDLIST* selection[] = { item }; const ITEMIDLIST* selection[] = { item };
UINT count = PR_ARRAY_SIZE(selection); UINT count = ArrayLength(selection);
//Perform the selection of the file. //Perform the selection of the file.
hr = sSHOpenFolderAndSelectItems(dir, count, selection, 0); hr = sSHOpenFolderAndSelectItems(dir, count, selection, 0);

Просмотреть файл

@ -38,6 +38,8 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#include "mozilla/Util.h"
#include "jscntxt.h" #include "jscntxt.h"
#include "nscore.h" #include "nscore.h"
#include "plstr.h" #include "plstr.h"
@ -52,6 +54,8 @@
#include "nsICryptoHash.h" #include "nsICryptoHash.h"
#include "nsIX509Cert.h" #include "nsIX509Cert.h"
using namespace mozilla;
// //
// nsXPITriggerItem // nsXPITriggerItem
// //
@ -246,7 +250,7 @@ XPITriggerEvent::Run()
// Build arguments into rooted jsval array // Build arguments into rooted jsval array
jsval args[2] = { JSVAL_NULL, JSVAL_NULL }; jsval args[2] = { JSVAL_NULL, JSVAL_NULL };
js::AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(args), args); js::AutoArrayRooter tvr(cx, ArrayLength(args), args);
// args[0] is the URL // args[0] is the URL
JSString *str = JS_NewUCStringCopyZ(cx, reinterpret_cast<const jschar*>(URL.get())); JSString *str = JS_NewUCStringCopyZ(cx, reinterpret_cast<const jschar*>(URL.get()));