author | Ryan VanderMeulen <ryanvm@gmail.com> |
Thu, 02 Aug 2012 22:00:53 -0400 | |
changeset 101276 | 89dcadd42ec4b68b6e39b71061f04cd8d1aefc25 |
parent 101275 | 030feb4315fc1d8401477dd14a2cc57704eeb9dc (current diff) |
parent 101266 | 38b216220e608d9d1613765d3dbde93d1119a33f (diff) |
child 101277 | 6a82b0462271dadc79f584028abb290237e48344 |
child 101303 | 73b3b3f828b095d5b260728310f1b160f72b94fc |
child 101350 | 369f4847191837ca58a8dd4af0ae01c2cccd782c |
push id | 12935 |
push user | ryanvm@gmail.com |
push date | Fri, 03 Aug 2012 02:01:42 +0000 |
treeherder | mozilla-inbound@6a82b0462271 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 17.0a1 |
first release with | nightly linux32
89dcadd42ec4
/
17.0a1
/
20120803030521
/
files
nightly linux64
89dcadd42ec4
/
17.0a1
/
20120803030521
/
files
nightly mac
89dcadd42ec4
/
17.0a1
/
20120803030521
/
files
nightly win32
89dcadd42ec4
/
17.0a1
/
20120803030521
/
files
nightly win64
89dcadd42ec4
/
17.0a1
/
20120803030521
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
17.0a1
/
20120803030521
/
pushlog to previous
nightly linux64
17.0a1
/
20120803030521
/
pushlog to previous
nightly mac
17.0a1
/
20120803030521
/
pushlog to previous
nightly win32
17.0a1
/
20120803030521
/
pushlog to previous
nightly win64
17.0a1
/
20120803030521
/
pushlog to previous
|
toolkit/components/maintenanceservice/prefetch.cpp | file | annotate | diff | comparison | revisions | |
toolkit/components/maintenanceservice/prefetch.h | file | annotate | diff | comparison | revisions |
--- a/accessible/src/atk/ApplicationAccessibleWrap.cpp +++ b/accessible/src/atk/ApplicationAccessibleWrap.cpp @@ -567,17 +567,17 @@ toplevel_event_watcher(GSignalInvocation } } } return TRUE; } -bool +void ApplicationAccessibleWrap::Init() { if (ShouldA11yBeEnabled()) { // load and initialize gail library nsresult rv = LoadGtkModule(sGail); if (NS_SUCCEEDED(rv)) { (*sGail.init)(); } @@ -610,17 +610,17 @@ ApplicationAccessibleWrap::Init() reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_SHOW), NULL); sToplevel_hide_hook = g_signal_add_emission_hook(g_signal_lookup("hide", GTK_TYPE_WINDOW), 0, toplevel_event_watcher, reinterpret_cast<gpointer>(nsIAccessibleEvent::EVENT_HIDE), NULL); } } - return ApplicationAccessible::Init(); + ApplicationAccessible::Init(); } void ApplicationAccessibleWrap::Unload() { if (sToplevel_event_hook_added) { sToplevel_event_hook_added = false; g_signal_remove_emission_hook(g_signal_lookup("show", GTK_TYPE_WINDOW),
--- a/accessible/src/atk/ApplicationAccessibleWrap.h +++ b/accessible/src/atk/ApplicationAccessibleWrap.h @@ -18,17 +18,17 @@ public: static void Unload(); static void PreCreate(); public: ApplicationAccessibleWrap(); virtual ~ApplicationAccessibleWrap(); // nsAccessNode - virtual bool Init(); + virtual void Init(); // Accessible virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual bool AppendChild(Accessible* aChild); virtual bool RemoveChild(Accessible* aChild); /** * Return the atk object for app root accessible.
--- a/accessible/src/base/nsAccDocManager.cpp +++ b/accessible/src/base/nsAccDocManager.cpp @@ -383,20 +383,17 @@ nsAccDocManager::CreateDocOrRootAccessib nsRefPtr<DocAccessible> docAcc = isRootDoc ? new RootAccessibleWrap(aDocument, rootElm, presShell) : new DocAccessibleWrap(aDocument, rootElm, presShell); // Cache the document accessible into document cache. mDocAccessibleCache.Put(aDocument, docAcc); // Initialize the document accessible. - if (!docAcc->Init()) { - docAcc->Shutdown(); - return nullptr; - } + docAcc->Init(); docAcc->SetRoleMapEntry(aria::GetRoleMap(aDocument)); // Bind the document to the tree. if (isRootDoc) { Accessible* appAcc = nsAccessNode::GetApplicationAccessible(); if (!appAcc->AppendChild(docAcc)) { docAcc->Shutdown(); return nullptr;
--- a/accessible/src/base/nsAccessNode.cpp +++ b/accessible/src/base/nsAccessNode.cpp @@ -91,22 +91,17 @@ nsAccessNode::GetApplicationAccessible() if (!gApplicationAccessible) { ApplicationAccessibleWrap::PreCreate(); gApplicationAccessible = new ApplicationAccessibleWrap(); // Addref on create. Will Release in ShutdownXPAccessibility() NS_ADDREF(gApplicationAccessible); - nsresult rv = gApplicationAccessible->Init(); - if (NS_FAILED(rv)) { - gApplicationAccessible->Shutdown(); - NS_RELEASE(gApplicationAccessible); - return nullptr; - } + gApplicationAccessible->Init(); } return gApplicationAccessible; } void nsAccessNode::ShutdownXPAccessibility() { // Called by nsAccessibilityService::Shutdown()
--- a/accessible/src/base/nsTextEquivUtils.cpp +++ b/accessible/src/base/nsTextEquivUtils.cpp @@ -6,16 +6,17 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsTextEquivUtils.h" #include "Accessible-inl.h" #include "AccIterator.h" #include "nsAccessibilityService.h" #include "nsAccUtils.h" +#include "nsStyleStructInlines.h" #include "nsIDOMXULLabeledControlEl.h" #include "nsArrayUtils.h" using namespace mozilla::a11y; #define NS_OK_NO_NAME_CLAUSE_HANDLED \ @@ -121,17 +122,17 @@ nsTextEquivUtils::AppendTextEquivFromTex nsIContent *parentContent = aContent->GetParent(); if (parentContent) { nsIFrame *frame = parentContent->GetPrimaryFrame(); if (frame) { // If this text is inside a block level frame (as opposed to span // level), we need to add spaces around that block's text, so we don't // get words jammed together in final name. const nsStyleDisplay* display = frame->GetStyleDisplay(); - if (display->IsBlockOutside() || + if (display->IsBlockOutsideStyle() || display->mDisplay == NS_STYLE_DISPLAY_TABLE_CELL) { isHTMLBlock = true; if (!aString->IsEmpty()) { aString->Append(PRUnichar(' ')); } } } }
--- a/accessible/src/generic/Accessible.cpp +++ b/accessible/src/generic/Accessible.cpp @@ -190,20 +190,19 @@ Accessible::~Accessible() } void Accessible::SetRoleMapEntry(nsRoleMapEntry* aRoleMapEntry) { mRoleMapEntry = aRoleMapEntry; } -bool +void Accessible::Init() { - return true; } NS_IMETHODIMP Accessible::GetDocument(nsIAccessibleDocument** aDocument) { NS_ENSURE_ARG_POINTER(aDocument); NS_IF_ADDREF(*aDocument = Document());
--- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -124,17 +124,17 @@ public: virtual void Shutdown(); ////////////////////////////////////////////////////////////////////////////// // Public methods /** * Initialize the accessible. */ - virtual bool Init(); + virtual void Init(); /** * Get the description of this accessible. */ virtual void Description(nsString& aDescription); /** * Get the value of this accessible.
--- a/accessible/src/generic/ApplicationAccessible.cpp +++ b/accessible/src/generic/ApplicationAccessible.cpp @@ -263,21 +263,20 @@ ApplicationAccessible::GetPlatformVersio AppendUTF8toUTF16(cversion, aVersion); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// // nsAccessNode public methods -bool +void ApplicationAccessible::Init() { mAppInfo = do_GetService("@mozilla.org/xre/app-info;1"); - return true; } void ApplicationAccessible::Shutdown() { mAppInfo = nullptr; }
--- a/accessible/src/generic/ApplicationAccessible.h +++ b/accessible/src/generic/ApplicationAccessible.h @@ -56,17 +56,17 @@ public: NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString &aName); NS_IMETHOD GetActionDescription(PRUint8 aIndex, nsAString &aDescription); NS_IMETHOD DoAction(PRUint8 aIndex); // nsIAccessibleApplication NS_DECL_NSIACCESSIBLEAPPLICATION // nsAccessNode - virtual bool Init(); + virtual void Init(); virtual void Shutdown(); virtual bool IsPrimaryForNode() const; // Accessible virtual GroupPos GroupPosition(); virtual ENameValueFlag Name(nsString& aName); virtual void ApplyARIAState(PRUint64* aState) const; virtual void Description(nsString& aDescription);
--- a/accessible/src/generic/DocAccessible.cpp +++ b/accessible/src/generic/DocAccessible.cpp @@ -599,37 +599,34 @@ DocAccessible::GetAccessible(nsINode* aN #endif return accessible; } //////////////////////////////////////////////////////////////////////////////// // nsAccessNode -bool +void DocAccessible::Init() { #ifdef DEBUG if (logging::IsEnabled(logging::eDocCreate)) logging::DocCreate("document initialize", mDocument, this); #endif // Initialize notification controller. mNotificationController = new NotificationController(this, mPresShell); - if (!mNotificationController) - return false; // Mark the document accessible as loaded if its DOM document was loaded at // this point (this can happen because a11y is started late or DOM document // having no container was loaded. if (mDocument->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) mLoadState |= eDOMLoaded; AddEventListeners(); - return true; } void DocAccessible::Shutdown() { if (!mPresShell) // already shutdown return; @@ -1392,22 +1389,17 @@ DocAccessible::BindToDocument(Accessible // Put into DOM node cache. if (aAccessible->IsPrimaryForNode()) mNodeToAccessibleMap.Put(aAccessible->GetNode(), aAccessible); // Put into unique ID cache. mAccessibleCache.Put(aAccessible->UniqueID(), aAccessible); // Initialize the accessible. - if (!aAccessible->Init()) { - NS_ERROR("Failed to initialize an accessible!"); - - UnbindFromDocument(aAccessible); - return false; - } + aAccessible->Init(); aAccessible->SetRoleMapEntry(aRoleMapEntry); if (aAccessible->IsElement()) AddDependentIDsFor(aAccessible); return true; }
--- a/accessible/src/generic/DocAccessible.h +++ b/accessible/src/generic/DocAccessible.h @@ -66,17 +66,17 @@ public: // nsIScrollPositionListener virtual void ScrollPositionWillChange(nscoord aX, nscoord aY) {} virtual void ScrollPositionDidChange(nscoord aX, nscoord aY); // nsIDocumentObserver NS_DECL_NSIDOCUMENTOBSERVER // nsAccessNode - virtual bool Init(); + virtual void Init(); virtual void Shutdown(); virtual nsIFrame* GetFrame() const; virtual nsINode* GetNode() const { return mDocument; } virtual nsIDocument* GetDocumentNode() const { return mDocument; } // Accessible virtual mozilla::a11y::ENameValueFlag Name(nsString& aName); virtual void Description(nsString& aDescription);
--- a/accessible/src/xul/XULTreeAccessible.cpp +++ b/accessible/src/xul/XULTreeAccessible.cpp @@ -1145,24 +1145,21 @@ XULTreeItemAccessible::Name(nsString& aN GetCellName(mColumn, aName); return eNameOK; } //////////////////////////////////////////////////////////////////////////////// // XULTreeItemAccessible: nsAccessNode implementation -bool +void XULTreeItemAccessible::Init() { - if (!XULTreeItemAccessibleBase::Init()) - return false; - + XULTreeItemAccessibleBase::Init(); Name(mCachedName); - return true; } void XULTreeItemAccessible::Shutdown() { mColumn = nullptr; XULTreeItemAccessibleBase::Shutdown(); }
--- a/accessible/src/xul/XULTreeAccessible.h +++ b/accessible/src/xul/XULTreeAccessible.h @@ -230,17 +230,17 @@ public: nsITreeView* aTreeView, PRInt32 aRow); // nsISupports and cycle collection NS_DECL_ISUPPORTS_INHERITED NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(XULTreeItemAccessible, XULTreeItemAccessibleBase) // nsAccessNode - virtual bool Init(); + virtual void Init(); virtual void Shutdown(); // Accessible virtual ENameValueFlag Name(nsString& aName); virtual a11y::role NativeRole(); // XULTreeItemAccessibleBase virtual void RowInvalidated(PRInt32 aStartColIdx, PRInt32 aEndColIdx);
--- a/accessible/src/xul/XULTreeGridAccessible.cpp +++ b/accessible/src/xul/XULTreeGridAccessible.cpp @@ -774,30 +774,29 @@ XULTreeGridCellAccessible::IsSelected(bo NS_ENSURE_SUCCESS(rv, rv); return selection->IsSelected(mRow, aIsSelected); } //////////////////////////////////////////////////////////////////////////////// // XULTreeGridCellAccessible: nsAccessNode implementation -bool +void XULTreeGridCellAccessible::Init() { - if (!LeafAccessible::Init() || !mTreeView) - return false; + LeafAccessible::Init(); + + NS_ASSERTION(mTreeView, "mTreeView is null"); PRInt16 type; mColumn->GetType(&type); if (type == nsITreeColumn::TYPE_CHECKBOX) mTreeView->GetCellValue(mRow, mColumn, mCachedTextEquiv); else mTreeView->GetCellText(mRow, mColumn, mCachedTextEquiv); - - return true; } bool XULTreeGridCellAccessible::IsPrimaryForNode() const { return false; }
--- a/accessible/src/xul/XULTreeGridAccessible.h +++ b/accessible/src/xul/XULTreeGridAccessible.h @@ -145,17 +145,17 @@ public: NS_IMETHOD GetActionName(PRUint8 aIndex, nsAString& aName); NS_IMETHOD DoAction(PRUint8 aIndex); // nsIAccessibleTableCell NS_DECL_OR_FORWARD_NSIACCESSIBLETABLECELL_WITH_XPCACCESSIBLETABLECELL // nsAccessNode - virtual bool Init(); + virtual void Init(); virtual bool IsPrimaryForNode() const; // Accessible virtual void Shutdown(); virtual ENameValueFlag Name(nsString& aName); virtual Accessible* FocusedChild(); virtual nsresult GetAttributesInternal(nsIPersistentProperties* aAttributes); virtual PRInt32 IndexInParent() const;
--- a/b2g/app/nsBrowserApp.cpp +++ b/b2g/app/nsBrowserApp.cpp @@ -169,29 +169,22 @@ int main(int argc, char* argv[]) strcpy(++lastSlash, XPCOM_DLL); int gotCounters; #if defined(XP_UNIX) struct rusage initialRUsage; gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); #elif defined(XP_WIN) - // GetProcessIoCounters().ReadOperationCount seems to have little to - // do with actual read operations. It reports 0 or 1 at this stage - // in the program. Luckily 1 coincides with when prefetch is - // enabled. If Windows prefetch didn't happen we can do our own - // faster dll preloading. IO_COUNTERS ioCounters; gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); - if (gotCounters && !ioCounters.ReadOperationCount) #endif - { - XPCOMGlueEnablePreload(); - } + // We do this because of data in bug 771745 + XPCOMGlueEnablePreload(); rv = XPCOMGlueStartup(exePath); if (NS_FAILED(rv)) { Output("Couldn't load XPCOM.\n"); return 255; } // Reset exePath so that it is the directory name and not the xpcom dll name *lastSlash = 0;
--- a/browser/app/nsBrowserApp.cpp +++ b/browser/app/nsBrowserApp.cpp @@ -169,48 +169,16 @@ static int do_main(int argc, char* argv[ int result = XRE_main(argc, argv, appData, 0); XRE_FreeAppData(appData); return result; } return XRE_main(argc, argv, &sAppData, 0); } -#ifdef XP_WIN -/** - * Determines if the registry is disabled via the service or not. - * - * @return true if prefetch is disabled - * false if prefetch is not disabled or an error occurred. -*/ -bool IsPrefetchDisabledViaService() -{ - // We don't need to return false when we don't have MOZ_MAINTENANCE_SERVICE - // defined. The reason is because another product installed that has it - // defined may have cleared our prefetch for us. There is no known way - // to figure out which prefetch files are associated with which apps - // because of the prefetch hash. So we disable all of them that start - // with FIREFOX. - HKEY baseKey; - LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Mozilla\\MaintenanceService", 0, - KEY_READ | KEY_WOW64_64KEY, &baseKey); - if (retCode != ERROR_SUCCESS) { - return false; - } - DWORD disabledValue = 0; - DWORD disabledValueSize = sizeof(DWORD); - RegQueryValueExW(baseKey, L"FFPrefetchDisabled", 0, NULL, - reinterpret_cast<LPBYTE>(&disabledValue), - &disabledValueSize); - RegCloseKey(baseKey); - return disabledValue == 1; -} -#endif - /* Local implementation of PR_Now, since the executable can't depend on NSPR */ static PRTime _PR_Now() { #ifdef XP_WIN MOZ_STATIC_ASSERT(sizeof(PRTime) == sizeof(FILETIME), "PRTime must have the same size as FILETIME"); FILETIME ft; GetSystemTimeAsFileTime(&ft); PRTime now; @@ -253,19 +221,18 @@ int main(int argc, char* argv[]) #if defined(XP_UNIX) struct rusage initialRUsage; gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); #elif defined(XP_WIN) IO_COUNTERS ioCounters; gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); #endif -#if !defined(XP_WIN) + // We do this because of data in bug 771745 XPCOMGlueEnablePreload(); -#endif rv = XPCOMGlueStartup(exePath); if (NS_FAILED(rv)) { Output("Couldn't load XPCOM.\n"); return 255; } // Reset exePath so that it is the directory name and not the xpcom dll name *lastSlash = 0;
--- a/browser/components/shell/src/nsWindowsShellService.cpp +++ b/browser/components/shell/src/nsWindowsShellService.cpp @@ -47,21 +47,16 @@ #define REG_SUCCEEDED(val) \ (val == ERROR_SUCCESS) #define REG_FAILED(val) \ (val != ERROR_SUCCESS) #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1" -// We clear the prefetch files one time after the browser is started after -// 3 minutes. After this is done once we set a pref so this will never happen -// again except in updater code. -#define CLEAR_PREFETCH_TIMEOUT_MS 180000 - NS_IMPL_ISUPPORTS2(nsWindowsShellService, nsIWindowsShellService, nsIShellService) static nsresult OpenKeyForReading(HKEY aKeyRoot, const nsAString& aKeyName, HKEY* aKey) { const nsString &flatName = PromiseFlatString(aKeyName); DWORD res = ::RegOpenKeyExW(aKeyRoot, flatName.get(), 0, KEY_READ, aKey); @@ -189,27 +184,16 @@ static SETTING gDDESettings[] = { { MAKE_KEY_NAME1("Software\\Classes\\FirefoxURL", SOD) }, // Protocol Handlers { MAKE_KEY_NAME1("Software\\Classes\\FTP", SOD) }, { MAKE_KEY_NAME1("Software\\Classes\\HTTP", SOD) }, { MAKE_KEY_NAME1("Software\\Classes\\HTTPS", SOD) } }; -#if defined(MOZ_MAINTENANCE_SERVICE) - -#define ONLY_SERVICE_LAUNCHING -#include "updatehelper.h" -#include "updatehelper.cpp" - -static const char *kPrefetchClearedPref = - "app.update.service.lastVersionPrefetchCleared"; -static nsCOMPtr<nsIThread> sThread; -#endif - nsresult GetHelperPath(nsAutoString& aPath) { nsresult rv; nsCOMPtr<nsIProperties> directoryService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); @@ -996,133 +980,22 @@ nsWindowsShellService::SetDesktopBackgro NS_ENSURE_SUCCESS(rv, rv); return regKey->Close(); } nsWindowsShellService::nsWindowsShellService() : mCheckedThisSession(false) { -#if defined(MOZ_MAINTENANCE_SERVICE) - - // Check to make sure the service is installed - PRUint32 installed = 0; - nsCOMPtr<nsIWindowsRegKey> regKey = - do_CreateInstance("@mozilla.org/windows-registry-key;1"); - if (!regKey || - NS_FAILED(regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, - NS_LITERAL_STRING( - "SOFTWARE\\Mozilla\\MaintenanceService"), - nsIWindowsRegKey::ACCESS_READ | - nsIWindowsRegKey::WOW64_64)) || - NS_FAILED(regKey->ReadIntValue(NS_LITERAL_STRING("Installed"), - &installed)) || - !installed) { - return; - } - - // check to see if we have attempted to do the one time operation of clearing - // the prefetch. We do it once per version upgrade. - nsCString lastClearedVer; - nsCOMPtr<nsIPrefBranch> prefBranch; - nsCOMPtr<nsIPrefService> prefs = - do_GetService(NS_PREFSERVICE_CONTRACTID); - if (!prefs || - NS_FAILED(prefs->GetBranch(nullptr, getter_AddRefs(prefBranch))) || - (NS_SUCCEEDED(prefBranch->GetCharPref(kPrefetchClearedPref, - getter_Copies(lastClearedVer))))) { - // If the versions are the same, then bail out early. We only want to clear - // once per version. - if (!strcmp(MOZ_APP_VERSION, lastClearedVer.get())) { - return; - } - } - - // In a minute after startup is definitely complete, launch the - // service command. - mTimer = do_CreateInstance(NS_TIMER_CONTRACTID); - if (mTimer) { - mTimer->InitWithFuncCallback( - nsWindowsShellService::LaunchPrefetchClearCommand, - nullptr, CLEAR_PREFETCH_TIMEOUT_MS, nsITimer::TYPE_ONE_SHOT); - } -#endif } nsWindowsShellService::~nsWindowsShellService() { -#if defined(MOZ_MAINTENANCE_SERVICE) - if (mTimer) { - mTimer->Cancel(); - mTimer = nullptr; - } - if (sThread) { - sThread->Shutdown(); - sThread = nullptr; - } -#endif } -#if defined(MOZ_MAINTENANCE_SERVICE) - -class ClearPrefetchEvent : public nsRunnable { -public: - ClearPrefetchEvent() - { - } - - NS_IMETHOD Run() - { - // Start the service command - LPCWSTR updaterServiceArgv[2]; - updaterServiceArgv[0] = L"MozillaMaintenance"; - updaterServiceArgv[1] = L"clear-prefetch"; - // If this command fails, it is not critical as prefetch will be cleared - // on the next software update. - StartServiceCommand(NS_ARRAY_LENGTH(updaterServiceArgv), - updaterServiceArgv); - return NS_OK; - } -}; -#endif - -/** - * For faster startup we attempt to clear the prefetch if the maintenance - * service is installed. Please see the definition of ClearPrefetch() - * in toolkit/components/maintenanceservice/prefetch.cpp for more info. - * For now the only application that gets prefetch cleaned is Firefox - * since we have not done performance checking for other applications. - * This is done on every update but also there is a one time operation done - * from within the program for first time installs. - */ -#if defined(MOZ_MAINTENANCE_SERVICE) -void -nsWindowsShellService::LaunchPrefetchClearCommand(nsITimer *aTimer, void*) -{ - // Make sure we don't call this again from the application, it will be - // called on each application update instead. - nsCOMPtr<nsIPrefBranch> prefBranch; - nsCOMPtr<nsIPrefService> prefs = - do_GetService(NS_PREFSERVICE_CONTRACTID); - if (prefs) { - if (NS_SUCCEEDED(prefs->GetBranch(nullptr, getter_AddRefs(prefBranch)))) { - prefBranch->SetCharPref(kPrefetchClearedPref, MOZ_APP_VERSION); - } - } - - // Starting the sevice can take a bit of time and we don't want to block the - // main thread, so start an event on another thread to handle the operation - NS_NewThread(getter_AddRefs(sThread)); - if (sThread) { - nsCOMPtr<nsIRunnable> prefetchEvent = new ClearPrefetchEvent(); - sThread->Dispatch(prefetchEvent, NS_DISPATCH_NORMAL); - } -} -#endif - NS_IMETHODIMP nsWindowsShellService::OpenApplicationWithURI(nsIFile* aApplication, const nsACString& aURI) { nsresult rv; nsCOMPtr<nsIProcess> process = do_CreateInstance("@mozilla.org/process/util;1", &rv); if (NS_FAILED(rv))
--- a/browser/components/shell/src/nsWindowsShellService.h +++ b/browser/components/shell/src/nsWindowsShellService.h @@ -24,16 +24,12 @@ public: NS_DECL_NSISHELLSERVICE NS_DECL_NSIWINDOWSSHELLSERVICE protected: static nsresult IsDefaultBrowser(bool* aIsDefaultBrowser); static bool IsDefaultBrowserVista(bool* aIsDefaultBrowser); private: -#if defined(MOZ_MAINTENANCE_SERVICE) - static void LaunchPrefetchClearCommand(nsITimer *aTimer, void*); - nsCOMPtr<nsITimer> mTimer; -#endif bool mCheckedThisSession; }; #endif // nswindowsshellservice_h____
--- a/build/automationutils.py +++ b/build/automationutils.py @@ -421,17 +421,17 @@ def wrapCommand(cmd): return cmd class ShutdownLeakLogger(object): """ Parses the mochitest run log when running a debug build, assigns all leaked DOM windows (that are still around after test suite shutdown, despite running the GC) to the tests that created them and prints leak statistics. """ - MAX_LEAK_COUNT = 4 + MAX_LEAK_COUNT = 5 def __init__(self, logger): self.logger = logger self.tests = [] self.leakedWindows = {} self.leakedDocShells = set() self.currentTest = None self.seenShutdown = False
--- a/build/mobile/devicemanager.py +++ b/build/mobile/devicemanager.py @@ -432,16 +432,18 @@ class DeviceManager: @abstractmethod def getInfo(self, directive=None): """ Returns information about the device: Directive indicates the information you want to get, your choices are: os - name of the os id - unique id of the device uptime - uptime of the device + uptimemillis - uptime of the device in milliseconds (NOT supported on all + platforms) systime - system time of the device screen - screen resolution memory - memory stats process - list of running processes (same as ps) disk - total, free, available bytes on disk power - power status (charge, battery temp) all - all of them - or call it with no parameters to get all the information returns:
--- a/build/mobile/devicemanagerADB.py +++ b/build/mobile/devicemanagerADB.py @@ -658,16 +658,18 @@ class DeviceManagerADB(DeviceManager): # uptime - uptime of the device # systime - system time of the device # screen - screen resolution # memory - memory stats # process - list of running processes (same as ps) # disk - total, free, available bytes on disk # power - power status (charge, battery temp) # all - all of them - or call it with no parameters to get all the information + ### Note that uptimemillis is NOT supported, as there is no way to get this + ### data from the shell. # returns: # success: dict of info strings by directive name # failure: {} def getInfo(self, directive="all"): ret = {} if (directive == "id" or directive == "all"): ret["id"] = self.runCmd(["get-serialno"]).stdout.read() if (directive == "os" or directive == "all"):
--- a/build/mobile/devicemanagerSUT.py +++ b/build/mobile/devicemanagerSUT.py @@ -912,34 +912,35 @@ class DeviceManagerSUT(DeviceManager): if (self.debug > 3): print "INFO: rebt- got status back: " + str(status) return status # Returns information about the device: # Directive indicates the information you want to get, your choices are: # os - name of the os # id - unique id of the device # uptime - uptime of the device + # uptimemillis - uptime of the device in milliseconds # systime - system time of the device # screen - screen resolution # rotation - rotation of the device (in degrees) # memory - memory stats # process - list of running processes (same as ps) # disk - total, free, available bytes on disk # power - power status (charge, battery temp) # all - all of them - or call it with no parameters to get all the information # returns: # success: dict of info strings by directive name # failure: {} def getInfo(self, directive=None): data = None result = {} collapseSpaces = re.compile(' +') - directives = ['os','id','uptime','systime','screen','rotation','memory','process', - 'disk','power'] + directives = ['os','id','uptime','uptimemillis','systime','screen', + 'rotation','memory','process','disk','power'] if (directive in directives): directives = [directive] for d in directives: data = self.runCmds([{ 'cmd': 'info ' + d }]) if (data is None): continue data = collapseSpaces.sub(' ', data)
--- a/build/mobile/sutagent/android/watcher/WatcherService.java +++ b/build/mobile/sutagent/android/watcher/WatcherService.java @@ -45,17 +45,17 @@ import android.widget.Toast; public class WatcherService extends Service { String sErrorPrefix = "##Installer Error## "; String currentDir = "/"; String sPingTarget = ""; long lDelay = 60000; long lPeriod = 300000; - int nMaxStrikes = 3; // maximum number of tries before we consider network unreachable + int nMaxStrikes = 0; // maximum number of tries before we consider network unreachable (0 means don't check) boolean bStartSUTAgent = true; Process pProc; Context myContext = null; Timer myTimer = null; private PowerManager.WakeLock pwl = null; public static final int NOTIFICATION_ID = 1964; boolean bInstalling = false; @@ -106,17 +106,17 @@ public class WatcherService extends Serv String sHold = ""; Log.i("Watcher", String.format("Loading settings from %s", sIniFile)); this.sPingTarget = GetIniData("watcher", "PingTarget", sIniFile, "www.mozilla.org"); sHold = GetIniData("watcher", "delay", sIniFile, "60000"); this.lDelay = Long.parseLong(sHold.trim()); sHold = GetIniData("watcher", "period", sIniFile,"300000"); this.lPeriod = Long.parseLong(sHold.trim()); - sHold = GetIniData("watcher", "strikes", sIniFile,"3"); + sHold = GetIniData("watcher", "strikes", sIniFile,"0"); this.nMaxStrikes = Integer.parseInt(sHold.trim()); Log.i("Watcher", String.format("Pinging %s after a delay of %s sec, period of %s sec, max number of failed attempts is %s (if max # of failed attempts is 0, then no checking)", this.sPingTarget, this.lDelay / 1000.0, this.lPeriod / 1000.0, nMaxStrikes)); sHold = GetIniData("watcher", "StartSUTAgent", sIniFile, "true"); this.bStartSUTAgent = Boolean.parseBoolean(sHold.trim()); sHold = GetIniData("watcher", "stayon", sIniFile,"0");
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -8434,18 +8434,17 @@ nsDocument::CreateTouch(nsIDOMWindow* aV aForce)); return NS_OK; } NS_IMETHODIMP nsDocument::CreateTouchList(nsIVariant* aPoints, nsIDOMTouchList** aRetVal) { - nsRefPtr<nsDOMTouchList> retval = - new nsDOMTouchList(static_cast<nsIDocument*>(this)); + nsRefPtr<nsDOMTouchList> retval = new nsDOMTouchList(); if (aPoints) { PRUint16 type; aPoints->GetDataType(&type); if (type == nsIDataType::VTYPE_INTERFACE || type == nsIDataType::VTYPE_INTERFACE_IS) { nsCOMPtr<nsISupports> data; aPoints->GetAsISupports(getter_AddRefs(data)); nsCOMPtr<nsIDOMTouch> point = do_QueryInterface(data);
--- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -146,32 +146,34 @@ WebGLContext::WebGLContext() mGLMaxTextureUnits = 0; mGLMaxTextureSize = 0; mGLMaxCubeMapTextureSize = 0; mGLMaxTextureImageUnits = 0; mGLMaxVertexTextureImageUnits = 0; mGLMaxVaryingVectors = 0; mGLMaxFragmentUniformVectors = 0; mGLMaxVertexUniformVectors = 0; - + // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13 mPixelStorePackAlignment = 4; mPixelStoreUnpackAlignment = 4; WebGLMemoryMultiReporterWrapper::AddWebGLContext(this); mAllowRestore = true; mContextLossTimerRunning = false; mDrawSinceContextLossTimerSet = false; mContextRestorer = do_CreateInstance("@mozilla.org/timer;1"); mContextStatus = ContextStable; mContextLostErrorSet = false; mAlreadyGeneratedWarnings = 0; mAlreadyWarnedAboutFakeVertexAttrib0 = false; + + mLastUseIndex = 0; } WebGLContext::~WebGLContext() { DestroyResourcesAndContext(); WebGLMemoryMultiReporterWrapper::RemoveWebGLContext(this); TerminateContextLossTimer(); mContextRestorer = nullptr; @@ -330,17 +332,17 @@ WebGLContext::SetContextOptions(nsIPrope mOptions = newOpts; return NS_OK; } NS_IMETHODIMP WebGLContext::SetDimensions(PRInt32 width, PRInt32 height) { /*** early success return cases ***/ - + if (mCanvasElement) { mCanvasElement->InvalidateCanvas(); } if (gl && mWidth == width && mHeight == height) return NS_OK; // Zero-sized surfaces can cause problems. @@ -361,21 +363,27 @@ WebGLContext::SetDimensions(PRInt32 widt mHeight = gl->OffscreenActualSize().height; mResetLayer = true; gl->ClearSafely(); return NS_OK; } - /*** end of early success return cases ***/ + /*** End of early success return cases. + *** At this point we know that we're not just resizing an existing context, + *** we are initializing a new context. + ***/ - // At this point we know that the old context is not going to survive, even though we still don't - // know if creating the new context will succeed. - DestroyResourcesAndContext(); + // if we exceeded either the global or the per-principal limit for WebGL contexts, + // lose the oldest-used context now to free resources. Note that we can't do that + // in the WebGLContext constructor as we don't have a canvas element yet there. + // Here is the right place to do so, as we are about to create the OpenGL context + // and that is what can fail if we already have too many. + LoseOldestWebGLContextIfLimitExceeded(); // Get some prefs for some preferred/overriden things NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE); bool forceOSMesa = Preferences::GetBool("webgl.force_osmesa", false); #ifdef XP_WIN bool preferEGL = @@ -624,16 +632,101 @@ WebGLContext::Render(gfxContext *ctx, gf ctx->NewPath(); ctx->PixelSnappedRectangleAndSetPattern(gfxRect(0, 0, mWidth, mHeight), pat); ctx->Fill(); return NS_OK; } +void WebGLContext::LoseOldestWebGLContextIfLimitExceeded() +{ +#ifdef MOZ_GFX_OPTIMIZE_MOBILE + // some mobile devices can't have more than 8 GL contexts overall + const size_t kMaxWebGLContextsPerPrincipal = 2; + const size_t kMaxWebGLContexts = 4; +#else + const size_t kMaxWebGLContextsPerPrincipal = 8; + const size_t kMaxWebGLContexts = 16; +#endif + MOZ_ASSERT(kMaxWebGLContextsPerPrincipal < kMaxWebGLContexts); + + // it's important to update the index on a new context before losing old contexts, + // otherwise new unused contexts would all have index 0 and we couldn't distinguish older ones + // when choosing which one to lose first. + UpdateLastUseIndex(); + + WebGLMemoryMultiReporterWrapper::ContextsArrayType &contexts + = WebGLMemoryMultiReporterWrapper::Contexts(); + + // quick exit path, should cover a majority of cases + if (contexts.Length() <= kMaxWebGLContextsPerPrincipal) { + return; + } + + // note that here by "context" we mean "non-lost context". See the check for + // IsContextLost() below. Indeed, the point of this function is to maybe lose + // some currently non-lost context. + + uint64_t oldestIndex = UINT64_MAX; + uint64_t oldestIndexThisPrincipal = UINT64_MAX; + const WebGLContext *oldestContext = nsnull; + const WebGLContext *oldestContextThisPrincipal = nsnull; + size_t numContexts = 0; + size_t numContextsThisPrincipal = 0; + + for(size_t i = 0; i < contexts.Length(); ++i) { + + // don't want to lose ourselves. + if (contexts[i] == this) + continue; + + if (contexts[i]->IsContextLost()) + continue; + + if (!contexts[i]->GetCanvas()) { + // Zombie context: the canvas is already destroyed, but something else + // (typically the compositor) is still holding on to the context. + // Killing zombies is a no-brainer. + const_cast<WebGLContext*>(contexts[i])->LoseContext(); + continue; + } + + numContexts++; + if (contexts[i]->mLastUseIndex < oldestIndex) { + oldestIndex = contexts[i]->mLastUseIndex; + oldestContext = contexts[i]; + } + + nsIPrincipal *ourPrincipal = GetCanvas()->NodePrincipal(); + nsIPrincipal *theirPrincipal = contexts[i]->GetCanvas()->NodePrincipal(); + bool samePrincipal; + nsresult rv = ourPrincipal->Equals(theirPrincipal, &samePrincipal); + if (NS_SUCCEEDED(rv) && samePrincipal) { + numContextsThisPrincipal++; + if (contexts[i]->mLastUseIndex < oldestIndexThisPrincipal) { + oldestIndexThisPrincipal = contexts[i]->mLastUseIndex; + oldestContextThisPrincipal = contexts[i]; + } + } + } + + if (numContextsThisPrincipal > kMaxWebGLContextsPerPrincipal) { + GenerateWarning("Exceeded %d live WebGL contexts for this principal, losing the " + "least recently used one.", kMaxWebGLContextsPerPrincipal); + MOZ_ASSERT(oldestContextThisPrincipal); // if we reach this point, this can't be null + const_cast<WebGLContext*>(oldestContextThisPrincipal)->LoseContext(); + } else if (numContexts > kMaxWebGLContexts) { + GenerateWarning("Exceeded %d live WebGL contexts, losing the least recently used one.", + kMaxWebGLContexts); + MOZ_ASSERT(oldestContext); // if we reach this point, this can't be null + const_cast<WebGLContext*>(oldestContext)->LoseContext(); + } +} + NS_IMETHODIMP WebGLContext::GetInputStream(const char* aMimeType, const PRUnichar* aEncoderOptions, nsIInputStream **aStream) { NS_ASSERTION(gl, "GetInputStream on invalid context?"); if (!gl) return NS_ERROR_FAILURE; @@ -686,16 +779,31 @@ WebGLContext::GetInputStream(const char* } NS_IMETHODIMP WebGLContext::GetThebesSurface(gfxASurface **surface) { return NS_ERROR_NOT_AVAILABLE; } +void WebGLContext::UpdateLastUseIndex() +{ + static CheckedInt<uint64_t> sIndex = 0; + + sIndex++; + + // should never happen with 64-bit; trying to handle this would be riskier than + // not handling it as the handler code would never get exercised. + if (!sIndex.isValid()) { + NS_RUNTIMEABORT("Can't believe it's been 2^64 transactions already!"); + } + + mLastUseIndex = sIndex.value(); +} + static PRUint8 gWebGLLayerUserData; namespace mozilla { class WebGLContextUserData : public LayerUserData { public: WebGLContextUserData(nsHTMLCanvasElement *aContent) : mContent(aContent) {} @@ -706,16 +814,18 @@ public: static void DidTransactionCallback(void* aData) { WebGLContextUserData *userdata = static_cast<WebGLContextUserData*>(aData); nsHTMLCanvasElement *canvas = userdata->mContent; WebGLContext *context = static_cast<WebGLContext*>(canvas->GetContextAtIndex(0)); context->mBackbufferClearingStatus = BackbufferClearingStatus::NotClearedSinceLastPresented; canvas->MarkContextClean(); + + context->UpdateLastUseIndex(); } private: nsRefPtr<nsHTMLCanvasElement> mContent; }; } // end namespace mozilla
--- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -1356,16 +1356,21 @@ protected: int mAlreadyGeneratedWarnings; bool mAlreadyWarnedAboutFakeVertexAttrib0; bool ShouldGenerateWarnings() const { return mAlreadyGeneratedWarnings < 32; } + uint64_t mLastUseIndex; + + void LoseOldestWebGLContextIfLimitExceeded(); + void UpdateLastUseIndex(); + #ifdef XP_MACOSX // see bug 713305. This RAII helper guarantees that we're on the discrete GPU, during its lifetime // Debouncing note: we don't want to switch GPUs too frequently, so try to not create and destroy // these objects at high frequency. Having WebGLContext's hold one such object seems fine, // because WebGLContext objects only go away during GC, which shouldn't happen too frequently. // If in the future GC becomes much more frequent, we may have to revisit then (maybe use a timer). ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper; #endif @@ -3169,23 +3174,25 @@ class WebGLMemoryMultiReporterWrapper ~WebGLMemoryMultiReporterWrapper(); static WebGLMemoryMultiReporterWrapper* sUniqueInstance; // here we store plain pointers, not RefPtrs: we don't want the // WebGLMemoryMultiReporterWrapper unique instance to keep alive all // WebGLContexts ever created. typedef nsTArray<const WebGLContext*> ContextsArrayType; ContextsArrayType mContexts; - + nsCOMPtr<nsIMemoryMultiReporter> mReporter; static WebGLMemoryMultiReporterWrapper* UniqueInstance(); static ContextsArrayType & Contexts() { return UniqueInstance()->mContexts; } + friend class WebGLContext; + public: static void AddWebGLContext(const WebGLContext* c) { Contexts().AppendElement(c); } static void RemoveWebGLContext(const WebGLContext* c) { ContextsArrayType & contexts = Contexts();
--- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -4499,16 +4499,17 @@ WebGLContext::name##_base(WebGLUniformLo " (since this uniform is not an array uniform)," \ " got an array of length %d", \ #name, \ expectedElemSize, \ arrayLength); \ } \ \ uint32_t numElementsToUpload = NS_MIN(info.arraySize, arrayLength/expectedElemSize); \ + MakeContextCurrent(); \ gl->f##name(location, numElementsToUpload, data); \ } #define SIMPLE_MATRIX_METHOD_UNIFORM(name, dim) \ NS_IMETHODIMP \ WebGLContext::name(nsIWebGLUniformLocation* aLocation, bool aTranspose, \ const JS::Value& aValue, JSContext* aCx) \ { \
--- a/content/events/src/nsDOMTouchEvent.cpp +++ b/content/events/src/nsDOMTouchEvent.cpp @@ -123,56 +123,52 @@ nsDOMTouch::Equals(nsIDOMTouch* aTouch) aTouch->GetRadiusY(&radiusY); return mRefPoint != aTouch->mRefPoint || (mForce != force) || (mRotationAngle != orientation) || (mRadius.x != radiusX) || (mRadius.y != radiusY); } // TouchList +nsDOMTouchList::nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches) +{ + mPoints.AppendElements(aTouches); +} DOMCI_DATA(TouchList, nsDOMTouchList) NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMTouchList) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMTouchList) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_ENTRY(nsIDOMTouchList) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(TouchList) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMTouchList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSTARRAY_OF_NSCOMPTR(mPoints) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParent) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMTouchList) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER -NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMTouchList) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mPoints) - NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParent) - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMTouchList) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTouchList) NS_IMETHODIMP nsDOMTouchList::GetLength(PRUint32* aLength) { *aLength = mPoints.Length(); return NS_OK; } NS_IMETHODIMP nsDOMTouchList::Item(PRUint32 aIndex, nsIDOMTouch** aRetVal) { - NS_IF_ADDREF(*aRetVal = nsDOMTouchList::GetItemAt(aIndex)); + NS_IF_ADDREF(*aRetVal = mPoints.SafeElementAt(aIndex, nsnull)); return NS_OK; } NS_IMETHODIMP nsDOMTouchList::IdentifiedTouch(PRInt32 aIdentifier, nsIDOMTouch** aRetVal) { *aRetVal = nullptr; for (PRUint32 i = 0; i < mPoints.Length(); ++i) { @@ -182,22 +178,16 @@ nsDOMTouchList::IdentifiedTouch(PRInt32 aIdentifier == identifier) { point.swap(*aRetVal); break; } } return NS_OK; } -nsIDOMTouch* -nsDOMTouchList::GetItemAt(PRUint32 aIndex) -{ - return mPoints.SafeElementAt(aIndex, nullptr); -} - // TouchEvent nsDOMTouchEvent::nsDOMTouchEvent(nsPresContext* aPresContext, nsTouchEvent* aEvent) : nsDOMUIEvent(aPresContext, aEvent ? aEvent : new nsTouchEvent(false, 0, nullptr)) { if (aEvent) { @@ -292,21 +282,19 @@ nsDOMTouchEvent::GetTouches(nsIDOMTouchL // for touchend events, remove any changed touches from the touches array nsTArray<nsCOMPtr<nsIDOMTouch> > unchangedTouches; nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches; for (PRUint32 i = 0; i < touches.Length(); ++i) { if (!touches[i]->mChanged) { unchangedTouches.AppendElement(touches[i]); } } - t = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this), - unchangedTouches); + t = new nsDOMTouchList(unchangedTouches); } else { - t = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this), - touchEvent->touches); + t = new nsDOMTouchList(touchEvent->touches); } mTouches = t; return CallQueryInterface(mTouches, aTouches); } NS_IMETHODIMP nsDOMTouchEvent::GetTargetTouches(nsIDOMTouchList** aTargetTouches) { @@ -326,18 +314,17 @@ nsDOMTouchEvent::GetTargetTouches(nsIDOM if ((mEvent->message != NS_TOUCH_END && mEvent->message != NS_TOUCH_CANCEL) || !touches[i]->mChanged) { nsIDOMEventTarget* targetPtr = touches[i]->GetTarget(); if (targetPtr == mEvent->target) { targetTouches.AppendElement(touches[i]); } } } - mTargetTouches = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this), - targetTouches); + mTargetTouches = new nsDOMTouchList(targetTouches); return CallQueryInterface(mTargetTouches, aTargetTouches); } NS_IMETHODIMP nsDOMTouchEvent::GetChangedTouches(nsIDOMTouchList** aChangedTouches) { NS_ENSURE_ARG_POINTER(aChangedTouches); NS_ENSURE_STATE(mEvent); @@ -349,18 +336,17 @@ nsDOMTouchEvent::GetChangedTouches(nsIDO nsTArray<nsCOMPtr<nsIDOMTouch> > changedTouches; nsTouchEvent* touchEvent = static_cast<nsTouchEvent*>(mEvent); nsTArray<nsCOMPtr<nsIDOMTouch> > touches = touchEvent->touches; for (PRUint32 i = 0; i < touches.Length(); ++i) { if (touches[i]->mChanged) { changedTouches.AppendElement(touches[i]); } } - mChangedTouches = new nsDOMTouchList(static_cast<nsIDOMTouchEvent*>(this), - changedTouches); + mChangedTouches = new nsDOMTouchList(changedTouches); return CallQueryInterface(mChangedTouches, aChangedTouches); } NS_IMETHODIMP nsDOMTouchEvent::GetAltKey(bool* aAltKey) { *aAltKey = static_cast<nsInputEvent*>(mEvent)->IsAlt(); return NS_OK;
--- a/content/events/src/nsDOMTouchEvent.h +++ b/content/events/src/nsDOMTouchEvent.h @@ -4,18 +4,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsDOMTouchEvent_h_ #define nsDOMTouchEvent_h_ #include "nsDOMUIEvent.h" #include "nsIDOMTouchEvent.h" #include "nsString.h" #include "nsTArray.h" -#include "nsIDocument.h" -#include "dombindings.h" #include "mozilla/Attributes.h" class nsDOMTouch MOZ_FINAL : public nsIDOMTouch { public: nsDOMTouch(nsIDOMEventTarget* aTarget, PRInt32 aIdentifier, PRInt32 aPageX, @@ -94,56 +92,38 @@ public: nsIntPoint mScreenPoint; nsIntPoint mRadius; float mRotationAngle; float mForce; protected: bool mPointsInitialized; }; -class nsDOMTouchList MOZ_FINAL : public nsIDOMTouchList, - public nsWrapperCache +class nsDOMTouchList : public nsIDOMTouchList { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMTouchList) + NS_DECL_CYCLE_COLLECTION_CLASS(nsDOMTouchList) NS_DECL_NSIDOMTOUCHLIST - nsDOMTouchList(nsISupports *aParent) : mParent(aParent) - { - SetIsDOMBinding(); - } - nsDOMTouchList(nsISupports *aParent, - nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches) - : mPoints(aTouches), - mParent(aParent) - { - SetIsDOMBinding(); - } - - virtual JSObject* WrapObject(JSContext *cx, JSObject *scope, - bool *triedToWrap) - { - return mozilla::dom::binding::TouchList::create(cx, scope, this, - triedToWrap); - } - - nsISupports *GetParentObject() - { - return mParent; - } + nsDOMTouchList() { } + nsDOMTouchList(nsTArray<nsCOMPtr<nsIDOMTouch> > &aTouches); void Append(nsIDOMTouch* aPoint) { mPoints.AppendElement(aPoint); } + nsIDOMTouch* GetItemAt(PRUint32 aIndex) + { + return mPoints.SafeElementAt(aIndex, nsnull); + } + protected: nsTArray<nsCOMPtr<nsIDOMTouch> > mPoints; - nsCOMPtr<nsISupports> mParent; }; class nsDOMTouchEvent : public nsDOMUIEvent, public nsIDOMTouchEvent { public: nsDOMTouchEvent(nsPresContext* aPresContext, nsTouchEvent* aEvent); virtual ~nsDOMTouchEvent();
--- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -483,26 +483,25 @@ nsGenericHTMLElement::GetOffsetRect(nsRe Element* docElement = GetCurrentDoc()->GetRootElement(); nsIContent* content = frame->GetContent(); if (content && (content->IsHTML(nsGkAtoms::body) || content == docElement)) { parent = frame; } else { - const bool isPositioned = frame->GetStyleDisplay()->IsPositioned(); - const bool isAbsolutelyPositioned = - frame->GetStyleDisplay()->IsAbsolutelyPositioned(); + const bool isPositioned = frame->IsPositioned(); + const bool isAbsolutelyPositioned = frame->IsAbsolutelyPositioned(); origin += frame->GetPositionIgnoringScrolling(); for ( ; parent ; parent = parent->GetParent()) { content = parent->GetContent(); // Stop at the first ancestor that is positioned. - if (parent->GetStyleDisplay()->IsPositioned()) { + if (parent->IsPositioned()) { *aOffsetParent = content; NS_IF_ADDREF(*aOffsetParent); break; } // Add the parent's origin to our own to get to the // right coordinate system. const bool isOffsetParent = !isPositioned && IsOffsetParent(parent);
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -11376,17 +11376,17 @@ nsDocShell::GetIsContent(bool *aIsConten NS_IMETHODIMP nsDocShell::GetExtendedOrigin(nsIURI *aUri, nsACString &aResult) { bool isInBrowserElement; GetIsInBrowserElement(&isInBrowserElement); nsCOMPtr<nsIScriptSecurityManager> ssmgr = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); - NS_ENSURE_TRUE(ssmgr, false); + NS_ENSURE_TRUE(ssmgr, NS_ERROR_FAILURE); return ssmgr->GetExtendedOrigin(aUri, mAppId, isInBrowserElement, aResult); } bool nsDocShell::IsOKToLoadURI(nsIURI* aURI) {
--- a/dom/alarm/AlarmDB.jsm +++ b/dom/alarm/AlarmDB.jsm @@ -74,52 +74,81 @@ AlarmDB.prototype = { aSuccessCb, aErrorCb ); }, /** * @param aId * The ID of record to be removed. + * @param aManifestURL + * The manifest URL of the app that alarm belongs to. + * If null, directly remove the ID record; otherwise, + * need to check if the alarm belongs to this app. * @param aSuccessCb * Callback function to invoke with result. * @param aErrorCb [optional] * Callback function to invoke when there was an error. */ - remove: function remove(aId, aSuccessCb, aErrorCb) { + remove: function remove(aId, aManifestURL, aSuccessCb, aErrorCb) { debug("remove()"); this.newTxn( "readwrite", function txnCb(aTxn, aStore) { debug("Going to remove " + aId); - aStore.delete(aId); + + // Look up the existing record and compare the manifestURL + // to see if the alarm to be removed belongs to this app. + aStore.get(aId).onsuccess = function doRemove(aEvent) { + let alarm = aEvent.target.result; + + if (!alarm) { + debug("Alarm doesn't exist. No need to remove it."); + return; + } + + if (aManifestURL && aManifestURL != alarm.manifestURL) { + debug("Cannot remove the alarm added by other apps."); + return; + } + + aStore.delete(aId); + }; }, aSuccessCb, aErrorCb ); }, /** + * @param aManifestURL + * The manifest URL of the app that alarms belong to. + * If null, directly return all alarms; otherwise, + * only return the alarms that belong to this app. * @param aSuccessCb * Callback function to invoke with result array. * @param aErrorCb [optional] * Callback function to invoke when there was an error. */ - getAll: function getAll(aSuccessCb, aErrorCb) { + getAll: function getAll(aManifestURL, aSuccessCb, aErrorCb) { debug("getAll()"); this.newTxn( "readonly", function txnCb(aTxn, aStore) { if (!aTxn.result) - aTxn.result = {}; + aTxn.result = []; aStore.mozGetAll().onsuccess = function setTxnResult(aEvent) { - aTxn.result = aEvent.target.result; + aEvent.target.result.forEach(function addAlarm(aAlarm) { + if (!aManifestURL || aManifestURL == aAlarm.manifestURL) + aTxn.result.push(aAlarm); + }); + debug("Request successful. Record count: " + aTxn.result.length); }; }, aSuccessCb, aErrorCb ); } };
--- a/dom/alarm/AlarmService.jsm +++ b/dom/alarm/AlarmService.jsm @@ -75,16 +75,17 @@ let AlarmService = { receiveMessage: function receiveMessage(aMessage) { debug("receiveMessage(): " + aMessage.name); let mm = aMessage.target.QueryInterface(Ci.nsIFrameMessageManager); let json = aMessage.json; switch (aMessage.name) { case "AlarmsManager:GetAll": this._db.getAll( + json.manifestURL, function getAllSuccessCb(aAlarms) { debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms)); this._sendAsyncMessage(mm, "GetAll", true, json.requestId, aAlarms); }.bind(this), function getAllErrorCb(aErrorMsg) { this._sendAsyncMessage(mm, "GetAll", false, json.requestId, aErrorMsg); }.bind(this) ); @@ -145,30 +146,34 @@ let AlarmService = { this._sendAsyncMessage(mm, "Add", false, json.requestId, aErrorMsg); }.bind(this) ); break; case "AlarmsManager:Remove": this._removeAlarmFromDb( json.id, + json.manifestURL, function removeSuccessCb() { debug("Callback after removing alarm from database."); // if there is no alarm being set if (!this._currentAlarm) { this._debugCurrentAlarm(); return; } // check if the alarm to be removed is in the queue + // by ID and whether it belongs to the requesting app let alarmQueue = this._alarmQueue; - if (this._currentAlarm.id != json.id) { + if (this._currentAlarm.id != json.id || + this._currentAlarm.manifestURL != json.manifestURL) { for (let i = 0; i < alarmQueue.length; i++) { - if (alarmQueue[i].id == json.id) { + if (alarmQueue[i].id == json.id && + alarmQueue[i].manifestURL == json.manifestURL) { alarmQueue.splice(i, 1); break; } } this._debugCurrentAlarm(); return; } @@ -219,29 +224,30 @@ let AlarmService = { default: throw Components.results.NS_ERROR_NOT_IMPLEMENTED; break; } aMessageManager.sendAsyncMessage("AlarmsManager:" + aMessageName + ":Return:" + (aSuccess ? "OK" : "KO"), json); }, - _removeAlarmFromDb: function _removeAlarmFromDb(aId, aRemoveSuccessCb) { + _removeAlarmFromDb: function _removeAlarmFromDb(aId, aManifestURL, aRemoveSuccessCb) { debug("_removeAlarmFromDb()"); // If the aRemoveSuccessCb is undefined or null, set a // dummy callback for it which is needed for _db.remove() if (!aRemoveSuccessCb) { aRemoveSuccessCb = function removeSuccessCb() { debug("Remove alarm from DB successfully."); }; } this._db.remove( aId, + aManifestURL, aRemoveSuccessCb, function removeErrorCb(aErrorMsg) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; } ); }, _fireSystemMessage: function _fireSystemMessage(aAlarm) { @@ -250,31 +256,31 @@ let AlarmService = { messenger.sendMessage("alarm", aAlarm, manifestURI); }, _onAlarmFired: function _onAlarmFired() { debug("_onAlarmFired()"); if (this._currentAlarm) { this._fireSystemMessage(this._currentAlarm); - this._removeAlarmFromDb(this._currentAlarm.id); + this._removeAlarmFromDb(this._currentAlarm.id, null); this._currentAlarm = null; } // Reset the next alarm from the queue. let alarmQueue = this._alarmQueue; while (alarmQueue.length > 0) { let nextAlarm = alarmQueue.shift(); let nextAlarmTime = this._getAlarmTime(nextAlarm); // If the next alarm has been expired, directly // fire system message for it instead of setting it. if (nextAlarmTime <= Date.now()) { this._fireSystemMessage(nextAlarm); - this._removeAlarmFromDb(nextAlarm.id); + this._removeAlarmFromDb(nextAlarm.id, null); } else { this._currentAlarm = nextAlarm; break; } } this._debugCurrentAlarm(); }, @@ -284,16 +290,17 @@ let AlarmService = { this._currentTimezoneOffset = aTimezoneOffset; this._restoreAlarmsFromDb(); }, _restoreAlarmsFromDb: function _restoreAlarmsFromDb() { debug("_restoreAlarmsFromDb()"); this._db.getAll( + null, function getAllSuccessCb(aAlarms) { debug("Callback after getting alarms from database: " + JSON.stringify(aAlarms)); // clear any alarms set or queued in the cache let alarmQueue = this._alarmQueue; alarmQueue.length = 0; this._currentAlarm = null;
--- a/dom/alarm/AlarmsManager.js +++ b/dom/alarm/AlarmsManager.js @@ -73,27 +73,27 @@ AlarmsManager.prototype = { return request; }, remove: function remove(aId) { debug("remove()"); return this._cpmm.sendSyncMessage( "AlarmsManager:Remove", - { id: aId } + { id: aId, manifestURL: this._manifestURL } ); }, getAll: function getAll() { debug("getAll()"); let request = this.createRequest(); this._cpmm.sendAsyncMessage( "AlarmsManager:GetAll", - { requestId: this.getRequestId(request) } + { requestId: this.getRequestId(request), manifestURL: this._manifestURL } ); return request; }, receiveMessage: function receiveMessage(aMessage) { debug("receiveMessage(): " + aMessage.name); let json = aMessage.json;
--- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -415,17 +415,16 @@ #include "nsIImageDocument.h" // Storage includes #include "nsDOMStorage.h" // Device Storage #include "nsIDOMDeviceStorage.h" -#include "nsIDOMDeviceStorageChangeEvent.h" #include "nsIDOMDeviceStorageCursor.h" // Drag and drop #include "nsIDOMDataTransfer.h" // Geolocation #include "nsIDOMGeoGeolocation.h" #include "nsIDOMGeoPosition.h" @@ -1435,19 +1434,16 @@ static nsDOMClassInfoData sClassInfoData DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(MessageEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(DeviceStorage, nsEventTargetSH, EVENTTARGET_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(DeviceStorageChangeEvent, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(DeviceStorageCursor, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(GeoGeolocation, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(GeoPosition, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -1628,18 +1624,18 @@ static nsDOMClassInfoData sClassInfoData DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, IDBEventTargetSH, IDBEVENTTARGET_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(Touch, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) - NS_DEFINE_CLASSINFO_DATA(TouchList, nsDOMGenericSH, - DOM_DEFAULT_SCRIPTABLE_FLAGS) + NS_DEFINE_CLASSINFO_DATA(TouchList, nsDOMTouchListSH, + ARRAY_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(TouchEvent, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframeRule, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) NS_DEFINE_CLASSINFO_DATA(MozCSSKeyframesRule, nsDOMGenericSH, DOM_DEFAULT_SCRIPTABLE_FLAGS) @@ -4038,21 +4034,16 @@ nsDOMClassInfo::Init() DOM_CLASSINFO_EVENT_MAP_ENTRIES DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(DeviceStorage, nsIDOMDeviceStorage) DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorage) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(DeviceStorageChangeEvent, nsIDOMDeviceStorageChangeEvent) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent) - DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent) - DOM_CLASSINFO_MAP_END - DOM_CLASSINFO_MAP_BEGIN(DeviceStorageCursor, nsIDOMDeviceStorageCursor) DOM_CLASSINFO_MAP_ENTRY(nsIDOMDeviceStorageCursor) DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest) DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget) DOM_CLASSINFO_MAP_END DOM_CLASSINFO_MAP_BEGIN(GeoGeolocation, nsIDOMGeoGeolocation) DOM_CLASSINFO_MAP_ENTRY(nsIDOMGeoGeolocation) @@ -4882,16 +4873,24 @@ nsDOMClassInfo::NewResolve(nsIXPConnectW { if (id == sConstructor_id && !(flags & JSRESOLVE_ASSIGNING)) { return ResolveConstructor(cx, obj, objp); } return NS_OK; } +nsISupports* +nsDOMTouchListSH::GetItemAt(nsISupports *aNative, PRUint32 aIndex, + nsWrapperCache **aCache, nsresult *aResult) +{ + nsDOMTouchList* list = static_cast<nsDOMTouchList*>(aNative); + return list->GetItemAt(aIndex); +} + NS_IMETHODIMP nsDOMClassInfo::Convert(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 type, jsval *vp, bool *_retval) { NS_WARNING("nsDOMClassInfo::Convert Don't call me!"); return NS_ERROR_UNEXPECTED;
--- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -1211,16 +1211,37 @@ protected: public: static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { return new nsCSSRuleListSH(aData); } }; +class nsDOMTouchListSH : public nsArraySH +{ + protected: + nsDOMTouchListSH(nsDOMClassInfoData* aData) : nsArraySH(aData) + { + } + + virtual ~nsDOMTouchListSH() + { + } + + virtual nsISupports* GetItemAt(nsISupports *aNative, PRUint32 aIndex, + nsWrapperCache **aCache, nsresult *aResult); + + public: + static nsIClassInfo* doCreate(nsDOMClassInfoData* aData) + { + return new nsDOMTouchListSH(aData); + } +}; + #ifdef MOZ_XUL // TreeColumns helper class nsTreeColumnsSH : public nsNamedArraySH { protected: nsTreeColumnsSH(nsDOMClassInfoData* aData) : nsNamedArraySH(aData) {
--- a/dom/base/nsDOMClassInfoClasses.h +++ b/dom/base/nsDOMClassInfoClasses.h @@ -380,17 +380,16 @@ DOMCI_CLASS(ModalContentWindow) // Data Events DOMCI_CLASS(DataContainerEvent) // event used for cross-domain message-passing and for server-sent events in // HTML5 DOMCI_CLASS(MessageEvent) DOMCI_CLASS(DeviceStorage) -DOMCI_CLASS(DeviceStorageChangeEvent) DOMCI_CLASS(DeviceStorageCursor) // Geolocation DOMCI_CLASS(GeoGeolocation) DOMCI_CLASS(GeoPosition) DOMCI_CLASS(GeoPositionCoords) DOMCI_CLASS(GeoPositionError)
--- a/dom/base/nsHistory.cpp +++ b/dom/base/nsHistory.cpp @@ -234,18 +234,18 @@ nsHistory::Go(PRInt32 aDelta) NS_ENSURE_TRUE(session_history, NS_ERROR_FAILURE); // QI SHistory to nsIWebNavigation nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(session_history)); NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE); PRInt32 curIndex=-1; PRInt32 len = 0; - nsresult rv = session_history->GetIndex(&curIndex); - rv = session_history->GetCount(&len); + session_history->GetIndex(&curIndex); + session_history->GetCount(&len); PRInt32 index = curIndex + aDelta; if (index > -1 && index < len) webnav->GotoIndex(index); // We always want to return a NS_OK, since returning errors // from GotoIndex() can lead to exceptions and a possible leak // of history length
--- a/dom/browser-element/BrowserElementParent.js +++ b/dom/browser-element/BrowserElementParent.js @@ -129,16 +129,17 @@ BrowserElementParentFactory.prototype = }; function BrowserElementParent(frameLoader, hasRemoteFrame) { debug("Creating new BrowserElementParent object for " + frameLoader); this._domRequestCounter = 0; this._pendingDOMRequests = {}; this._hasRemoteFrame = hasRemoteFrame; + this._frameLoader = frameLoader; this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement; if (!this._frameElement) { debug("No frame element?"); return; } this._mm = frameLoader.messageManager; @@ -173,16 +174,17 @@ function BrowserElementParent(frameLoade addMessageListener('got-can-go-back', this._gotDOMRequestResult); addMessageListener('got-can-go-forward', this._gotDOMRequestResult); addMessageListener('fullscreen-origin-change', this._remoteFullscreenOriginChange); addMessageListener('rollback-fullscreen', this._remoteFrameFullscreenReverted); addMessageListener('exit-fullscreen', this._exitFullscreen); let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); os.addObserver(this, 'ask-children-to-exit-fullscreen', /* ownsWeak = */ true); + os.addObserver(this, 'oop-frameloader-crashed', /* ownsWeak = */ true); function defineMethod(name, fn) { XPCNativeWrapper.unwrap(self._frameElement)[name] = function() { if (self._isAlive()) { return fn.apply(self, arguments); } }; } @@ -469,18 +471,36 @@ BrowserElementParent.prototype = { let origin = data.json; this._windowUtils.remoteFrameFullscreenChanged(this._frameElement, origin); }, _remoteFrameFullscreenReverted: function(data) { this._windowUtils.remoteFrameFullscreenReverted(); }, + _fireFatalError: function() { + let evt = this._createEvent('error', {type: 'fatal'}, + /* cancelable = */ false); + this._frameElement.dispatchEvent(evt); + }, + observe: function(subject, topic, data) { - if (topic == 'ask-children-to-exit-fullscreen' && - this._isAlive() && - this._frameElement.ownerDocument == subject && - this._hasRemoteFrame) - this._sendAsyncMsg('exit-fullscreen'); + switch(topic) { + case 'oop-frameloader-crashed': + if (this._isAlive() && subject == this._frameLoader) { + this._fireFatalError(); + } + break; + case 'ask-children-to-exit-fullscreen': + if (this._isAlive() && + this._frameElement.ownerDocument == subject && + this._hasRemoteFrame) { + this._sendAsyncMsg('exit-fullscreen'); + } + break; + default: + debug('Unknown topic: ' + topic); + break; + }; }, }; var NSGetFactory = XPCOMUtils.generateNSGetFactory([BrowserElementParentFactory]);
--- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -28,16 +28,17 @@ #include "nsContentUtils.h" #include "nsXULAppAPI.h" #include "TabChild.h" #include "DeviceStorageRequestChild.h" #include "nsIDOMDeviceStorageChangeEvent.h" #include "nsCRT.h" #include "mozilla/Services.h" #include "nsIObserverService.h" +#include "GeneratedEvents.h" // Microsoft's API Name hackery sucks #undef CreateEvent #ifdef MOZ_WIDGET_GONK #include "nsIVolumeService.h" #endif @@ -433,102 +434,16 @@ jsval StringToJsval(nsPIDOMWindow* aWind jsval result = JSVAL_NULL; if (!xpc::StringToJsval(cx, aString, &result)) { return JSVAL_NULL; } return result; } -class nsDOMDeviceStorageChangeEvent : public nsDOMEvent, public nsIDOMDeviceStorageChangeEvent -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_FORWARD_NSIDOMEVENT(nsDOMEvent::) - NS_DECL_NSIDOMDEVICESTORAGECHANGEEVENT - - nsDOMDeviceStorageChangeEvent(); - - virtual nsresult InitFromCtor(const nsAString& aType, - JSContext* aCx, - jsval* aVal); - - NS_IMETHOD Init(const nsAString & aEventTypeArg, - bool aCanBubbleArg, - bool aCancelableArg, - nsAString& aPath, - nsAString& aReason); - -private: - ~nsDOMDeviceStorageChangeEvent(); - -protected: - nsString mPath; - nsString mReason; -}; - -DOMCI_DATA(DeviceStorageChangeEvent, nsDOMDeviceStorageChangeEvent) - -NS_INTERFACE_MAP_BEGIN(nsDOMDeviceStorageChangeEvent) - NS_INTERFACE_MAP_ENTRY(nsIDOMDeviceStorageChangeEvent) - NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DeviceStorageChangeEvent) -NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent) - -NS_IMPL_ADDREF_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent) -NS_IMPL_RELEASE_INHERITED(nsDOMDeviceStorageChangeEvent, nsDOMEvent) - -nsDOMDeviceStorageChangeEvent::nsDOMDeviceStorageChangeEvent() - : nsDOMEvent(nullptr, nullptr) -{ -} - -nsDOMDeviceStorageChangeEvent::~nsDOMDeviceStorageChangeEvent() -{ -} - -NS_IMETHODIMP -nsDOMDeviceStorageChangeEvent::Init(const nsAString & aEventTypeArg, - bool aCanBubbleArg, - bool aCancelableArg, - nsAString& aPath, - nsAString& aReason) -{ - nsresult rv = nsDOMEvent::InitEvent(aEventTypeArg, aCanBubbleArg, aCancelableArg); - NS_ENSURE_SUCCESS(rv, rv); - - mPath = aPath; - mReason = aReason; - return NS_OK; -} - -nsresult -nsDOMDeviceStorageChangeEvent::InitFromCtor(const nsAString& aType, - JSContext* aCx, - jsval* aVal) -{ - mozilla::dom::DeviceStorageChangeEventInit d; - nsresult rv = d.Init(aCx, aVal); - NS_ENSURE_SUCCESS(rv, rv); - return Init(aType, d.bubbles, d.cancelable, d.path, d.reason); -} - -NS_IMETHODIMP -nsDOMDeviceStorageChangeEvent::GetPath(nsAString & aPath) -{ - aPath = mPath; - return NS_OK; -} - -NS_IMETHODIMP -nsDOMDeviceStorageChangeEvent::GetReason(nsAString & aReason) -{ - aReason = mReason; - return NS_OK; -} - class DeviceStorageCursorRequest MOZ_FINAL : public nsIContentPermissionRequest , public PCOMContentPermissionRequestChild { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(DeviceStorageCursorRequest, nsIContentPermissionRequest) @@ -1663,26 +1578,28 @@ nsDOMDeviceStorage::Update(const char* a if (!StringBeginsWith(fullpath, rootpath)) { NS_WARNING("Observing a path outside of our root!"); return NS_OK; } nsAString::size_type len = rootpath.Length() + 1; // +1 for the trailing / nsDependentSubstring newPath (fullpath, len, fullpath.Length() - len); - nsRefPtr<nsDOMDeviceStorageChangeEvent> event = new nsDOMDeviceStorageChangeEvent(); + nsCOMPtr<nsIDOMEvent> event; + NS_NewDOMDeviceStorageChangeEvent(getter_AddRefs(event), nullptr, nullptr); + + nsCOMPtr<nsIDOMDeviceStorageChangeEvent> ce = do_QueryInterface(event); + nsString reason; reason.AssignWithConversion(aReason); - rv = event->Init(NS_LITERAL_STRING("change"), true, false, newPath, reason); + rv = ce->InitDeviceStorageChangeEvent(NS_LITERAL_STRING("change"), true, false, newPath, reason); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr<nsIDOMDeviceStorageChangeEvent> e = event.get(); - bool ignore; - DispatchEvent(e, &ignore); + DispatchEvent(ce, &ignore); return NS_OK; } NS_IMETHODIMP nsDOMDeviceStorage::AddEventListener(const nsAString & aType, nsIDOMEventListener *aListener, bool aUseCapture, bool aWantsUntrusted,
--- a/dom/interfaces/devicestorage/nsIDOMDeviceStorageChangeEvent.idl +++ b/dom/interfaces/devicestorage/nsIDOMDeviceStorageChangeEvent.idl @@ -3,16 +3,23 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "domstubs.idl" #include "nsIDOMEvent.idl" [scriptable, uuid(468304d6-aab6-4e1e-8ab2-569d9e703431), builtinclass] interface nsIDOMDeviceStorageChangeEvent : nsIDOMEvent { + + [noscript] void initDeviceStorageChangeEvent(in DOMString eventTypeArg, + in boolean canBubbleArg, + in boolean cancelableArg, + in DOMString path, + in DOMString reason); + readonly attribute DOMString path; readonly attribute DOMString reason; }; dictionary DeviceStorageChangeEventInit : EventInit { DOMString path; DOMString reason;
--- a/dom/interfaces/events/nsIDOMTouchEvent.idl +++ b/dom/interfaces/events/nsIDOMTouchEvent.idl @@ -36,18 +36,17 @@ interface nsIDOMTouch : nsISupports { bool mChanged; PRUint32 mMessage; %} }; [scriptable, uuid(60706eb7-d50d-4379-b01c-e78e6af84213)] interface nsIDOMTouchList : nsISupports { readonly attribute unsigned long length; - [getter,forward(getItemAt)] nsIDOMTouch item(in unsigned long index); - [noscript,notxpcom,nostdcall] nsIDOMTouch getItemAt(in unsigned long index); + nsIDOMTouch item(in unsigned long index); nsIDOMTouch identifiedTouch(in long identifier); }; [scriptable, builtinclass, uuid(57809468-7c03-4e8a-b080-4e30f157db21)] interface nsIDOMTouchEvent : nsIDOMUIEvent { readonly attribute nsIDOMTouchList touches; readonly attribute nsIDOMTouchList targetTouches; readonly attribute nsIDOMTouchList changedTouches;
--- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -668,24 +668,27 @@ TabChild::RecvUpdateFrame(const nsIntRec data += nsPrintfCString(", \"resolution\" : %f", aResolution.width); data += nsPrintfCString(" }"); data += nsPrintfCString(", \"screenSize\" : "); data += nsPrintfCString("{ \"width\" : %d", aScreenSize.width); data += nsPrintfCString(", \"height\" : %d", aScreenSize.height); data += nsPrintfCString(" }"); data += nsPrintfCString(" }"); + JSAutoRequest ar(mCx); jsval json = JSVAL_NULL; StructuredCloneData cloneData; JSAutoStructuredCloneBuffer buffer; if (JS_ParseJSON(mCx, static_cast<const jschar*>(NS_ConvertUTF8toUTF16(data).get()), data.Length(), &json)) { WriteStructuredClone(mCx, json, buffer, cloneData.mClosure); + cloneData.mData = buffer.data(); + cloneData.mDataLength = buffer.nbytes(); } nsFrameScriptCx cx(static_cast<nsIWebBrowserChrome*>(this), this); // Let the BrowserElementScrolling helper (if it exists) for this // content manipulate the frame state. nsRefPtr<nsFrameMessageManager> mm = static_cast<nsFrameMessageManager*>(mTabChildGlobal->mMessageManager.get()); mm->ReceiveMessage(static_cast<nsIDOMEventTarget*>(mTabChildGlobal),
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -115,16 +115,24 @@ TabParent::Recv__delete__() void TabParent::ActorDestroy(ActorDestroyReason why) { if (mIMETabParent == this) mIMETabParent = nullptr; nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(); if (frameLoader) { frameLoader->DestroyChild(); + + if (why == AbnormalShutdown) { + nsCOMPtr<nsIObserverService> os = services::GetObserverService(); + if (os) { + os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader), + "oop-frameloader-crashed", nullptr); + } + } } } bool TabParent::RecvMoveFocus(const bool& aForward) { nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID); if (fm) {
--- a/dom/plugins/test/mochitest/Makefile.in +++ b/dom/plugins/test/mochitest/Makefile.in @@ -51,19 +51,16 @@ MOCHITEST_FILES = \ test_npn_timers.html \ test_npn_asynccall.html \ test_bug532208.html \ large-pic.jpg \ test_twostreams.html \ test_streamatclose.html \ neverending.sjs \ test_newstreamondestroy.html \ - test_crashing.html \ - $(warning test_crashing2.html disabled due to random orange; see bug 566049) \ - test_hanging.html \ crashing_subpage.html \ test_GCrace.html \ test_propertyAndMethod.html \ test_bug539565-1.html \ test_bug539565-2.html \ test_bug771202.html \ file_bug771202.html \ test_bug777098.html \ @@ -116,16 +113,22 @@ MOCHITEST_CHROME_FILES += \ test_xulbrowser_plugin_visibility.xul \ xulbrowser_plugin_visibility.xul \ plugin_visibility_loader.html \ $(NULL) endif endif ifdef MOZ_CRASHREPORTER +MOCHITEST_FILES += \ + test_crashing.html \ + $(warning test_crashing2.html disabled due to random orange; see bug 566049) \ + test_hanging.html \ + $(NULL) + MOCHITEST_CHROME_FILES += \ test_crash_notify.xul \ test_crash_notify_no_report.xul \ test_crash_submit.xul \ $(NULL) ifeq ($(OS_ARCH),WINNT) MOCHITEST_CHROME_FILES += \ test_idle_hang.xul \
--- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -940,17 +940,17 @@ GLContextEGL::CreateSharedHandle(Texture } return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast<nsSurfaceTexture*>(aBuffer)); #endif case SharedTextureBufferType::TextureID: { if (!mShareWithEGLImage) return 0; - GLuint texture = (GLuint)aBuffer; + GLuint texture = (uintptr_t)aBuffer; EGLTextureWrapper* tex = new EGLTextureWrapper(); if (!tex->CreateEGLImage(this, texture)) { NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); delete tex; return 0; } return (SharedTextureHandle)tex;
--- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -646,19 +646,19 @@ class OrderedHashSet } // namespace js /*** HashableValue *******************************************************************************/ bool HashableValue::setValue(JSContext *cx, const Value &v) { - if (v.isString() && v.toString()->isRope()) { - // Flatten this rope so that equals() is infallible. - JSString *str = v.toString()->ensureLinear(cx); + if (v.isString()) { + // Atomize so that hash() and equals() are fast and infallible. + JSString *str = js_AtomizeString(cx, v.toString(), DoNotInternAtom); if (!str) return false; value = StringValue(str); } else if (v.isDouble()) { double d = v.toDouble(); int32_t i; if (MOZ_DOUBLE_IS_INT32(d, &i)) { // Normalize int32-valued doubles to int32 for faster hashing and testing. @@ -678,38 +678,25 @@ HashableValue::setValue(JSContext *cx, c return true; } HashNumber HashableValue::hash() const { // HashableValue::setValue normalizes values so that the SameValue relation // on HashableValues is the same as the == relationship on - // value.data.asBits, except for strings. - if (value.isString()) { - JSLinearString &s = value.toString()->asLinear(); - return HashChars(s.chars(), s.length()); - } - - // Having dispensed with strings, we can just hash asBits. - uint64_t u = value.asRawBits(); - return HashNumber((u >> 3) ^ - (u >> (HashNumberSizeBits + 3)) ^ - (u << (HashNumberSizeBits - 3))); + // value.data.asBits. + return value.asRawBits(); } bool HashableValue::equals(const HashableValue &other) const { - // Two HashableValues are equal if they have equal bits or they're equal strings. - bool b = (value.asRawBits() == other.value.asRawBits()) || - (value.isString() && - other.value.isString() && - EqualStrings(&value.toString()->asLinear(), - &other.value.toString()->asLinear())); + // Two HashableValues are equal if they have equal bits. + bool b = (value.asRawBits() == other.value.asRawBits()); #ifdef DEBUG bool same; JS_ASSERT(SameValue(NULL, value, other.value, &same)); JS_ASSERT(same == b); #endif return b; }
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/basic/expression-autopsy.js @@ -0,0 +1,96 @@ +function check_one(expected, f, err) { + var failed = true; + try { + f(); + failed = false; + } catch (ex) { + var s = ex.toString(); + assertEq(s.slice(0, 11), "TypeError: "); + assertEq(s.slice(-err.length), err); + assertEq(s.slice(11, -err.length), expected); + } + if (!failed) + throw new Error("didn't fail"); +} +ieval = eval; +function check(expr, expected=expr) { + var end, err; + for ([end, err] of [[".random_prop", " is undefined"], ["()", " is not a function"]]) { + var statement = "o = {};" + expr + end, f; + var cases = [ + // Global scope + function () { + ieval("var o, undef;\n" + statement); + }, + // Function scope + Function("o", "undef", statement), + // Function scope with variables + Function("var o, undef;\n" + statement), + // Function scope with some different arugments + Function("arg1", "arg2", "var o, undef;\n" + statement), + // Deoptimized function scope + Function("o", "undef", "with (Object) {}\n" + statement), + // Inside with + Function("with (Object) { " + statement + " }"), + // Closure + Function("o", "undef", "function myfunc() { return o + undef; }\n" + statement), + // Let definitions in a block + Function("{ let o, undef;\n" + statement + "}"), + // Let block + Function("let (o, undef) { " + statement + " }"), + // Let block with some other variables + Function("var v1, v2; let (o, undef) { " + statement + " }"), + // Shadowed let block + Function("o", "undef", "let (o, undef) { " + statement + " }"), + // Let in a switch + Function("var x = 4; switch (x) { case 4: let o, undef;" + statement + "\ncase 6: break;}"), + // Let in for-in + Function("var undef, o; for (let z in [1, 2]) { " + statement + " }"), + // The more lets the merrier + Function("let (x=4, y=5) { x + y; }\nlet (a, b, c) { a + b - c; }\nlet (o, undef) {" + statement + " }"), + // Let destructuring + Function("o", "undef", "let ([] = 4) {} let (o, undef) { " + statement + " }"), + // Try-catch blocks + Function("o", "undef", "try { let q = 4; try { let p = 4; } catch (e) {} } catch (e) {} let (o, undef) { " + statement + " }") + ]; + for (var f of cases) { + check_one(expected, f, err); + } + } +} + +check("undef"); +check("o.b"); +check("o.length"); +check("o[true]"); +check("o[false]"); +check("o[null]"); +check("o[0]"); +check("o[1]"); +check("o[3]"); +check("o[256]"); +check("o[65536]"); +check("o[268435455]"); +check("o['1.1']"); +check("o[4 + 'h']", "o['4h']"); +check("this.x"); +check("ieval(undef)", "ieval(...)"); +check("ieval.call()", "ieval.call(...)"); + +for (let tok of ["|", "^", "&", "==", "!==", "===", "!==", "<", "<=", ">", ">=", + ">>", "<<", ">>>", "+", "-", "*", "/", "%"]) { + check("o[(undef " + tok + " 4)]"); +} + +check("o[!(o)]"); +check("o[~(o)]"); +check("o[+ (o)]"); +check("o[- (o)]"); + +// A few one off tests +check_one("6", (function () { 6() }), " is not a function"); +check_one("Array.prototype.reverse.call(...)", (function () { Array.prototype.reverse.call('123'); }), " is read-only"); +check_one("null", function () { var [{ x }] = [null, {}]; }, " has no properties"); + +// Check fallback behavior +check_one("undefined", (function () { for (let x of undefined) {} }), " has no properties");
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/basic/function-tosource-bug779694.js @@ -0,0 +1,6 @@ +var x = ""; +for (var i=0; i<400; ++i) { + x += String.fromCharCode(i * 289); +} +var s = "'" + x + "'"; +assertEq(Function("evt", s).toString(), "function anonymous(evt) {\n" + s + "\n}");
--- a/js/src/jit-test/tests/basic/testBug566556.js +++ b/js/src/jit-test/tests/basic/testBug566556.js @@ -1,9 +1,9 @@ var msg = ""; try { this.__defineSetter__('x', Object.create); this.watch('x', function() {}); x = 3; } catch (e) { msg = e.toString(); } -assertEq(msg, "TypeError: (void 0) is not an object or null"); +assertEq(msg, "TypeError: undefined is not an object or null");
--- a/js/src/jit-test/tests/basic/testBug579647.js +++ b/js/src/jit-test/tests/basic/testBug579647.js @@ -1,13 +1,13 @@ expected = "TypeError: NaN is not a function"; actual = ""; try { a = "" for each(x in [0, 0, 0, 0]) { a %= x - } ( - a)() + } ( let (a=-a) a)() } catch (e) { actual = '' + e; } assertEq(expected, actual);
--- a/js/src/jit-test/tests/basic/testInitSingletons.js +++ b/js/src/jit-test/tests/basic/testInitSingletons.js @@ -23,17 +23,17 @@ foo(); var q = {0x4fffffff: 0, 0x7fffffff: 1, 0xffffffff: 2}; assertEq(q[1342177279], 0); assertEq(q[2147483647], 1); assertEq(q[4294967295], 2); try { [1,2,3,{a:0,b:1}].foo.bar; -} catch (e) { assertEq(e.message, "[1, 2, 3, {a:0, b:1}].foo is undefined"); } +} catch (e) { assertEq(e.message.search("\.foo is undefined") != -1, true); } var a = [1 + 1, 3 * 2, 6 - 5, 14 % 6, 15 / 5, 1 << 3, 8 >> 2, 5 | 2, 5 ^ 3, ~3, -3,"a" + "b", !true, !false]; assertEq(String(a), "2,6,1,2,3,8,2,7,6,-4,-3,ab,false,true"); assertEq(a.length, 14); var b = { a: 1 + 1,
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -540,21 +540,18 @@ JS_ValueToSource(JSContext *cx, jsval v) CHECK_REQUEST(cx); assertSameCompartment(cx, v); return js_ValueToSource(cx, v); } JS_PUBLIC_API(JSBool) JS_ValueToNumber(JSContext *cx, jsval v, double *dp) { - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, v); - - return ToNumber(cx, v, dp); + RootedValue value(cx, v); + return JS::ToNumber(cx, value, dp); } JS_PUBLIC_API(JSBool) JS_DoubleIsInt32(double d, int32_t *ip) { return MOZ_DOUBLE_IS_INT32(d, ip); } @@ -568,32 +565,25 @@ JS_PUBLIC_API(uint32_t) JS_DoubleToUint32(double d) { return ToUint32(d); } JS_PUBLIC_API(JSBool) JS_ValueToECMAInt32(JSContext *cx, jsval v, int32_t *ip) { - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, v); - RootedValue value(cx, v); - return ToInt32(cx, value, ip); + return JS::ToInt32(cx, value, ip); } JS_PUBLIC_API(JSBool) JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32_t *ip) { - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, v); - - return ToUint32(cx, v, (uint32_t *)ip); + RootedValue value(cx, v); + return JS::ToUint32(cx, value, ip); } JS_PUBLIC_API(JSBool) JS_ValueToInt32(JSContext *cx, jsval v, int32_t *ip) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, v); @@ -618,21 +608,17 @@ JS_ValueToInt32(JSContext *cx, jsval v, *ip = (int32_t) floor(d + 0.5); /* Round to nearest */ return true; } JS_PUBLIC_API(JSBool) JS_ValueToUint16(JSContext *cx, jsval v, uint16_t *ip) { - AssertHeapIsIdle(cx); - CHECK_REQUEST(cx); - assertSameCompartment(cx, v); - - return ValueToUint16(cx, v, (uint16_t *)ip); + return ToUint16(cx, v, ip); } JS_PUBLIC_API(JSBool) JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, v);
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -993,18 +993,21 @@ class JS_PUBLIC_API(AutoCheckRequestDept #else # define CHECK_REQUEST(cx) \ ((void) 0) #endif /* JS_THREADSAFE && DEBUG */ #ifdef DEBUG -/* Assert that we're not doing GC on cx, that we're in a request as - needed, and that the compartments for cx and v are correct. */ +/* + * Assert that we're not doing GC on cx, that we're in a request as + * needed, and that the compartments for cx and v are correct. + * Also check that GC would be safe at this point. + */ JS_PUBLIC_API(void) AssertArgumentsAreSane(JSContext *cx, const Value &v); #else inline void AssertArgumentsAreSane(JSContext *cx, const Value &v) { /* Do nothing */ } #endif /* DEBUG */ @@ -2695,20 +2698,23 @@ ToBooleanSlow(const JS::Value &v); namespace JS { /* ES5 9.3 ToNumber. */ JS_ALWAYS_INLINE bool ToNumber(JSContext *cx, const Value &v, double *out) { AssertArgumentsAreSane(cx, v); + { + JS::SkipRoot root(cx, &v); + MaybeCheckStackRoots(cx); + } if (v.isNumber()) { *out = v.toNumber(); - MaybeCheckStackRoots(cx); return true; } return js::ToNumberSlow(cx, v, out); } JS_ALWAYS_INLINE bool ToBoolean(const Value &v) { @@ -2745,36 +2751,79 @@ JS_DoubleToUint32(double d); * Convert a value to a number, then to an int32_t, according to the ECMA rules * for ToInt32. */ extern JS_PUBLIC_API(JSBool) JS_ValueToECMAInt32(JSContext *cx, jsval v, int32_t *ip); #ifdef __cplusplus namespace js { -/* - * DO NOT CALL THIS. Use JS::ToInt32 - */ +/* DO NOT CALL THIS. Use JS::ToInt16. */ +extern JS_PUBLIC_API(bool) +ToUint16Slow(JSContext *cx, const JS::Value &v, uint16_t *out); + +/* DO NOT CALL THIS. Use JS::ToInt32. */ extern JS_PUBLIC_API(bool) ToInt32Slow(JSContext *cx, const JS::Value &v, int32_t *out); + +/* DO NOT CALL THIS. Use JS::ToUint32. */ +extern JS_PUBLIC_API(bool) +ToUint32Slow(JSContext *cx, const JS::Value &v, uint32_t *out); } /* namespace js */ namespace JS { JS_ALWAYS_INLINE bool +ToUint16(JSContext *cx, const js::Value &v, uint16_t *out) +{ + AssertArgumentsAreSane(cx, v); + { + SkipRoot skip(cx, &v); + MaybeCheckStackRoots(cx); + } + + if (v.isInt32()) { + *out = uint16_t(v.toInt32()); + return true; + } + return js::ToUint16Slow(cx, v, out); +} + +JS_ALWAYS_INLINE bool ToInt32(JSContext *cx, const js::Value &v, int32_t *out) { AssertArgumentsAreSane(cx, v); + { + JS::SkipRoot root(cx, &v); + MaybeCheckStackRoots(cx); + } + if (v.isInt32()) { *out = v.toInt32(); return true; } return js::ToInt32Slow(cx, v, out); } +JS_ALWAYS_INLINE bool +ToUint32(JSContext *cx, const js::Value &v, uint32_t *out) +{ + AssertArgumentsAreSane(cx, v); + { + JS::SkipRoot root(cx, &v); + MaybeCheckStackRoots(cx); + } + + if (v.isInt32()) { + *out = uint32_t(v.toInt32()); + return true; + } + return js::ToUint32Slow(cx, v, out); +} + } /* namespace JS */ #endif /* __cplusplus */ /* * Convert a value to a number, then to a uint32_t, according to the ECMA rules * for ToUint32. */ extern JS_PUBLIC_API(JSBool) @@ -4958,17 +5007,17 @@ JS_CompileUCFunctionForPrincipalsVersion JSVersion version); #ifdef __cplusplus JS_END_EXTERN_C namespace JS { /* Options for JavaScript compilation. */ -struct CompileOptions { +struct JS_PUBLIC_API(CompileOptions) { JSPrincipals *principals; JSPrincipals *originPrincipals; JSVersion version; bool versionSet; bool utf8; const char *filename; unsigned lineno; bool compileAndGo;
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3874,32 +3874,36 @@ IncrementalCollectSlice(JSRuntime *rt, AutoCopyFreeListToArenas copy(rt); AutoGCSlice slice(rt); gc::State initialState = rt->gcIncrementalState; SliceBudget sliceBudget(budget); int zeal = 0; #ifdef JS_GC_ZEAL - if (reason == gcreason::DEBUG_GC) { + if (reason == gcreason::DEBUG_GC && budget != SliceBudget::Unlimited) { /* - * Do the collection type specified by zeal mode only if the collection - * was triggered by RunDebugGC(). + * Do the incremental collection type specified by zeal mode if the + * collection was triggered by RunDebugGC() and incremental GC has not + * been cancelled by ResetIncrementalGC. */ zeal = rt->gcZeal(); - JS_ASSERT_IF(zeal == ZealIncrementalMarkAllThenFinish || - zeal == ZealIncrementalRootsThenFinish, - budget == SliceBudget::Unlimited); } #endif bool isIncremental = rt->gcIncrementalState != NO_INCREMENTAL || - budget != SliceBudget::Unlimited || - zeal == ZealIncrementalRootsThenFinish || - zeal == ZealIncrementalMarkAllThenFinish; + budget != SliceBudget::Unlimited; + + if (zeal == ZealIncrementalRootsThenFinish || zeal == ZealIncrementalMarkAllThenFinish) { + /* + * Yields between slices occurs at predetermined points in these + * modes. sliceBudget is not used. + */ + sliceBudget.reset(); + } if (rt->gcIncrementalState == NO_INCREMENTAL) { rt->gcIncrementalState = MARK_ROOTS; rt->gcLastMarkSlice = false; } switch (rt->gcIncrementalState) { @@ -4499,17 +4503,18 @@ RunDebugGC(JSContext *cx) * completion. */ if (initialState == NO_INCREMENTAL) rt->gcIncrementalLimit = rt->gcZealFrequency / 2; else rt->gcIncrementalLimit *= 2; budget = SliceBudget::WorkBudget(rt->gcIncrementalLimit); } else { - budget = SliceBudget::Unlimited; + // This triggers incremental GC but is actually ignored by IncrementalMarkSlice. + budget = SliceBudget::WorkBudget(1); } Collect(rt, true, budget, GC_NORMAL, gcreason::DEBUG_GC); /* * For multi-slice zeal, reset the slice size when we get to the sweep * phase. */
--- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -1410,33 +1410,33 @@ ToInt32Slow(JSContext *cx, const Value & } else { if (!ToNumberSlow(cx, v, &d)) return false; } *out = ToInt32(d); return true; } -bool +JS_PUBLIC_API(bool) ToUint32Slow(JSContext *cx, const Value &v, uint32_t *out) { JS_ASSERT(!v.isInt32()); double d; if (v.isDouble()) { d = v.toDouble(); } else { if (!ToNumberSlow(cx, v, &d)) return false; } *out = ToUint32(d); return true; } -bool -ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out) +JS_PUBLIC_API(bool) +ToUint16Slow(JSContext *cx, const Value &v, uint16_t *out) { JS_ASSERT(!v.isInt32()); double d; if (v.isDouble()) { d = v.toDouble(); } else if (!ToNumberSlow(cx, v, &d)) { return false; }
--- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -139,63 +139,16 @@ ToNumber(JSContext *cx, Value *vp) extern bool ToNumberSlow(JSContext *cx, js::Value v, double *dp); if (!ToNumberSlow(cx, *vp, &d)) return false; vp->setNumber(d); return true; } -/* - * Convert a value to a uint32_t, according to the ECMA rules for - * ToUint32. Return converted value in *out on success, !ok on - * failure. - */ - -JS_ALWAYS_INLINE bool -ToUint32(JSContext *cx, const js::Value &v, uint32_t *out) -{ -#ifdef DEBUG - { - SkipRoot skip(cx, &v); - MaybeCheckStackRoots(cx); - } -#endif - - if (v.isInt32()) { - *out = (uint32_t)v.toInt32(); - return true; - } - extern bool ToUint32Slow(JSContext *cx, const js::Value &v, uint32_t *ip); - return ToUint32Slow(cx, v, out); -} - -/* - * Convert a value to a number, then to a uint16_t according to the ECMA rules - * for ToUint16. Return converted value on success, !ok on failure. v must be a - * copy of a rooted value. - */ -JS_ALWAYS_INLINE bool -ValueToUint16(JSContext *cx, const js::Value &v, uint16_t *out) -{ -#ifdef DEBUG - { - SkipRoot skip(cx, &v); - MaybeCheckStackRoots(cx); - } -#endif - - if (v.isInt32()) { - *out = uint16_t(v.toInt32()); - return true; - } - extern bool ValueToUint16Slow(JSContext *cx, const js::Value &v, uint16_t *out); - return ValueToUint16Slow(cx, v, out); -} - JSBool num_parseInt(JSContext *cx, unsigned argc, Value *vp); } /* namespace js */ /* * Similar to strtod except that it replaces overflows with infinities of the * correct sign, and underflows with zeros of the correct sign. Guaranteed to
--- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1326,17 +1326,17 @@ CopyDecompiledTextForDecomposedOp(JSPrin * * This function cannot raise an exception or error. However, due to a risk of * potential bugs when modeling the stack, the function returns -1 if it * detects an inconsistency in the model. Such an inconsistency triggers an * assert in a debug build. */ static int ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *pc, - jsbytecode **pcstack, jsbytecode **lastDecomposedPC); + jsbytecode **pcstack); #define FAILED_EXPRESSION_DECOMPILER ((char *) 1) /* * Decompile a part of expression up to the given pc. The function returns * NULL on out-of-memory, or the FAILED_EXPRESSION_DECOMPILER sentinel when * the decompiler fails due to a bug and/or unimplemented feature, or the * decompiled string on success. @@ -5729,115 +5729,503 @@ js_DecompileFunction(JSPrinter *jp) } if (!jp->pretty && !jp->grouped && (fun->flags & JSFUN_LAMBDA)) js_puts(jp, ")"); return JS_TRUE; } +static JSObject * +GetBlockChainAtPC(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + jsbytecode *start = script->main(); + + JS_ASSERT(pc >= start && pc < script->code + script->length); + + JSObject *blockChain = NULL; + for (jsbytecode *p = start; p < pc; p += GetBytecodeLength(p)) { + JSOp op = JSOp(*p); + + switch (op) { + case JSOP_ENTERBLOCK: + case JSOP_ENTERLET0: + case JSOP_ENTERLET1: { + JSObject *child = script->getObject(p); + JS_ASSERT_IF(blockChain, child->asBlock().stackDepth() >= blockChain->asBlock().stackDepth()); + blockChain = child; + break; + } + case JSOP_LEAVEBLOCK: + case JSOP_LEAVEBLOCKEXPR: + case JSOP_LEAVEFORLETIN: { + // Some LEAVEBLOCK instructions are due to early exits via + // return/break/etc. from block-scoped loops and functions. We + // should ignore these instructions, since they don't really signal + // the end of the block. + jssrcnote *sn = js_GetSrcNote(script, p); + if (!(sn && SN_TYPE(sn) == SRC_HIDDEN)) { + JS_ASSERT(blockChain); + blockChain = blockChain->asStaticBlock().enclosingBlock(); + JS_ASSERT_IF(blockChain, blockChain->isBlock()); + } + break; + } + default: + break; + } + } + + return blockChain; +} + +class PCStack +{ + JSContext *cx; + jsbytecode **stack; + int depth_; + + public: + explicit PCStack(JSContext *cx) + : cx(cx), + stack(NULL), + depth_(0) + {} + ~PCStack(); + bool init(JSContext *cx, JSScript *script, jsbytecode *pc); + int depth() const { return depth_; } + jsbytecode *operator[](int i) const; +}; + +PCStack::~PCStack() +{ + cx->free_(stack); +} + +bool +PCStack::init(JSContext *cx, JSScript *script, jsbytecode *pc) +{ + stack = static_cast<jsbytecode **>(cx->malloc_(StackDepth(script) * sizeof(*stack))); + if (!stack) + return false; + depth_ = ReconstructPCStack(cx, script, pc, stack); + JS_ASSERT(depth_ >= 0); + return true; +} + +/* Indexes the pcstack. */ +jsbytecode * +PCStack::operator[](int i) const +{ + if (i < 0) { + i += depth_; + JS_ASSERT(i >= 0); + } + JS_ASSERT(i < depth_); + return stack[i]; +} + +/* + * The expression decompiler is invoked by error handling code to produce a + * string representation of the erroring expression. As it's only a debugging + * tool, it only supports basic expressions. For anything complicated, it simply + * puts "(intermediate value)" into the error result. + * + * Here's the basic algorithm: + * + * 1. Find the stack location of the value whose expression we wish to + * decompile. The error handler can explicitly pass this as an + * argument. Otherwise, we search backwards down the stack for the offending + * value. + * + * 2. Call ReconstructPCStack with the current frame's pc. This creates a stack + * of pcs parallel to the interpreter stack; given an interpreter stack + * location, the corresponding pc stack location contains the opcode that pushed + * the value in the interpreter. Now, with the result of step 1, we have the + * opcode responsible for pushing the value we want to decompile. + * + * 3. Pass the opcode to decompilePC. decompilePC is the main decompiler + * routine, responsible for a string representation of the expression that + * generated a certain stack location. decompilePC looks at one opcode and + * returns the JS source equivalent of that opcode. + * + * 4. Expressions can, of course, contain subexpressions. For example, the + * literals "4" and "5" are subexpressions of the addition operator in "4 + + * 5". If we need to decompile a subexpression, we call decompilePC (step 2) + * recursively on the operands' pcs. The result is a depth-first traversal of + * the expression tree. + * + */ +struct ExpressionDecompiler +{ + JSContext *cx; + StackFrame *fp; + RootedScript script; + RootedFunction fun; + BindingVector *localNames; + Sprinter sprinter; + + ExpressionDecompiler(JSContext *cx, JSScript *script, JSFunction *fun) + : cx(cx), + script(cx, script), + fun(cx, fun), + localNames(NULL), + sprinter(cx) + {} + ~ExpressionDecompiler(); + bool init(); + bool decompilePC(jsbytecode *pc); + JSAtom *getVar(unsigned slot); + JSAtom *getArg(unsigned slot); + JSAtom *findLetVar(jsbytecode *pc, unsigned depth); + JSAtom *loadAtom(jsbytecode *pc); + bool quote(JSString *s, uint32_t quote); + bool write(const char *s); + bool write(JSString *s); + bool getOutput(char **out); +}; + +bool +ExpressionDecompiler::decompilePC(jsbytecode *pc) +{ + JS_ASSERT(script->code <= pc && pc < script->code + script->length); + + PCStack pcstack(cx); + if (!pcstack.init(cx, script, pc)) + return NULL; + + JSOp op = (JSOp)*pc; + + // None of these stack-writing ops generates novel values. + JS_ASSERT(op != JSOP_CASE && op != JSOP_DUP && op != JSOP_DUP2); + + if (const char *token = CodeToken[op]) { + // Handle simple cases of binary and unary operators. + switch (js_CodeSpec[op].nuses) { + case 2: { + jssrcnote *sn = js_GetSrcNote(script, pc); + if (!sn || SN_TYPE(sn) != SRC_ASSIGNOP) + return write("(") && + decompilePC(pcstack[-2]) && + write(" ") && + write(token) && + write(" ") && + decompilePC(pcstack[-1]) && + write(")"); + break; + } + case 1: + return write(token) && + write("(") && + decompilePC(pcstack[-1]) && + write(")"); + default: + break; + } + } + + switch (op) { + case JSOP_GETGNAME: + case JSOP_CALLGNAME: + case JSOP_NAME: + case JSOP_CALLNAME: + return write(loadAtom(pc)); + case JSOP_GETARG: + case JSOP_CALLARG: { + unsigned slot = GET_ARGNO(pc); + JSAtom *atom = getArg(slot); + if (!atom) + break; // Destructuring + return write(atom); + } + case JSOP_GETLOCAL: + case JSOP_CALLLOCAL: { + unsigned i = GET_SLOTNO(pc); + JSAtom *atom; + if (i >= script->nfixed) { + i -= script->nfixed; + JS_ASSERT(i < unsigned(pcstack.depth())); + atom = findLetVar(pc, i); + if (!atom) + return decompilePC(pcstack[i]); // Destructing temporary + } else { + atom = getVar(i); + } + JS_ASSERT(atom); + return write(atom); + } + case JSOP_CALLALIASEDVAR: + case JSOP_GETALIASEDVAR: { + JSAtom *atom = ScopeCoordinateName(cx->runtime, script, pc); + JS_ASSERT(atom); + return write(atom); + } + case JSOP_LENGTH: + case JSOP_GETPROP: + case JSOP_CALLPROP: { + JSAtom *prop = (op == JSOP_LENGTH) ? cx->runtime->atomState.lengthAtom : loadAtom(pc); + if (!decompilePC(pcstack[-1])) + return false; + if (IsIdentifier(prop)) + return write(".") && + quote(prop, '\0'); + else + return write("[") && + quote(prop, '\'') && + write("]") >= 0; + return true; + } + case JSOP_GETELEM: + case JSOP_CALLELEM: + return decompilePC(pcstack[-2]) && + write("[") && + decompilePC(pcstack[-1]) && + write("]"); + case JSOP_NULL: + return write(js_null_str); + case JSOP_TRUE: + return write(js_true_str); + case JSOP_FALSE: + return write(js_false_str); + case JSOP_ZERO: + case JSOP_ONE: + case JSOP_INT8: + case JSOP_UINT16: + case JSOP_UINT24: + case JSOP_INT32: { + int32_t i; + switch (op) { + case JSOP_ZERO: + i = 0; + break; + case JSOP_ONE: + i = 1; + break; + case JSOP_INT8: + i = GET_INT8(pc); + break; + case JSOP_UINT16: + i = GET_UINT16(pc); + break; + case JSOP_UINT24: + i = GET_UINT24(pc); + break; + case JSOP_INT32: + i = GET_INT32(pc); + break; + default: + JS_NOT_REACHED("wat?"); + } + return sprinter.printf("%d", i) >= 0; + } + case JSOP_STRING: + return quote(loadAtom(pc), '"'); + case JSOP_UNDEFINED: + return write(js_undefined_str); + case JSOP_THIS: + // |this| could convert to a very long object initialiser, so cite it by + // its keyword name. + return write(js_this_str); + case JSOP_CALL: + case JSOP_FUNCALL: + return decompilePC(pcstack[-(GET_ARGC(pc) + 2)]) && + write("(...)"); + default: + break; + } + return write("(intermediate value)"); +} + +ExpressionDecompiler::~ExpressionDecompiler() +{ + cx->delete_<BindingVector>(localNames); +} + +bool +ExpressionDecompiler::init() +{ + if (!sprinter.init()) + return false; + + localNames = cx->new_<BindingVector>(cx); + if (!localNames) + return false; + if (!GetOrderedBindings(cx, script->bindings, localNames)) + return false; + + return true; +} + +bool +ExpressionDecompiler::write(const char *s) +{ + return sprinter.put(s) >= 0; +} + +bool +ExpressionDecompiler::write(JSString *s) +{ + return sprinter.putString(s) >= 0; +} + +bool +ExpressionDecompiler::quote(JSString *s, uint32_t quote) +{ + return QuoteString(&sprinter, s, quote) >= 0; +} + +JSAtom * +ExpressionDecompiler::loadAtom(jsbytecode *pc) +{ + return script->getAtom(GET_UINT32_INDEX(pc)); +} + +JSAtom * +ExpressionDecompiler::findLetVar(jsbytecode *pc, unsigned depth) +{ + if (script->hasObjects()) { + JSObject *chain = GetBlockChainAtPC(cx, script, pc); + if (!chain) + return NULL; + JS_ASSERT(chain->isBlock()); + do { + BlockObject &block = chain->asBlock(); + uint32_t blockDepth = block.stackDepth(); + uint32_t blockCount = block.slotCount(); + if (uint32_t(depth - blockDepth) < uint32_t(blockCount)) { + for (Shape::Range r(block.lastProperty()); !r.empty(); r.popFront()) { + const Shape &shape = r.front(); + if (shape.shortid() == int(depth - blockDepth)) { + // !JSID_IS_ATOM(shape.propid()) happens for empty + // destructuring variables in lets. They can be safely + // ignored. + if (JSID_IS_ATOM(shape.propid())) + return JSID_TO_ATOM(shape.propid()); + } + } + } + chain = chain->enclosingScope(); + } while (chain->isBlock()); + } + return NULL; +} + +JSAtom * +ExpressionDecompiler::getArg(unsigned slot) +{ + JS_ASSERT(fun); + JS_ASSERT(slot < script->bindings.count()); + return (*localNames)[slot].maybeName; +} + +JSAtom * +ExpressionDecompiler::getVar(unsigned slot) +{ + JS_ASSERT(fun); + slot += fun->nargs; + JS_ASSERT(slot < script->bindings.count()); + return (*localNames)[slot].maybeName; +} + +bool +ExpressionDecompiler::getOutput(char **res) +{ + ptrdiff_t len = sprinter.stringEnd() - sprinter.stringAt(0); + *res = static_cast<char *>(cx->malloc_(len + 1)); + if (!*res) + return false; + js_memcpy(*res, sprinter.stringAt(0), len); + (*res)[len] = 0; + return true; +} + +static bool +FindStartPC(JSContext *cx, JSScript *script, int spindex, Value v, jsbytecode **valuepc) +{ + jsbytecode *current = *valuepc; + + if (spindex == JSDVG_IGNORE_STACK) + return true; + + *valuepc = NULL; + + PCStack pcstack(cx); + if (!pcstack.init(cx, script, current)) + return false; + + if (spindex == JSDVG_SEARCH_STACK) { + // We search from fp->sp to base to find the most recently calculated + // value matching v under assumption that it is it that caused + // exception. + Value *stackBase = cx->regs().spForStackDepth(0); + Value *sp = cx->regs().sp; + do { + if (sp == stackBase) + return true; + } while (*--sp != v); + if (sp < stackBase + pcstack.depth()) + *valuepc = pcstack[sp - stackBase]; + } else { + *valuepc = pcstack[spindex]; + } + return true; +} + +static bool +DecompileExpressionFromStack(JSContext *cx, int spindex, Value v, char **res) +{ + JS_ASSERT(spindex < 0 || + spindex == JSDVG_IGNORE_STACK || + spindex == JSDVG_SEARCH_STACK); + + *res = NULL; + + if (!cx->hasfp() || !cx->fp()->isScriptFrame()) + return true; + StackFrame *fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL); + JSScript *script = fp->script(); + jsbytecode *valuepc = cx->regs().pc; + JSFunction *fun = fp->maybeFun(); + JS_ASSERT(script->code <= valuepc && valuepc < script->code + script->length); + + // Give up if in prologue. + if (valuepc < script->main()) + return true; + + if (!FindStartPC(cx, script, spindex, v, &valuepc)) + return false; + if (!valuepc) + return true; + + ExpressionDecompiler ea(cx, script, fun); + if (!ea.init()) + return false; + if (!ea.decompilePC(valuepc)) + return false; + + return ea.getOutput(res); +} + char * js_DecompileValueGenerator(JSContext *cx, int spindex, jsval v, JSString *fallback) { - StackFrame *fp; - JSScript *script; - jsbytecode *pc; - - JS_ASSERT(spindex < 0 || - spindex == JSDVG_IGNORE_STACK || - spindex == JSDVG_SEARCH_STACK); - - if (!cx->hasfp() || !cx->fp()->isScriptFrame()) - goto do_fallback; - - fp = js_GetTopStackFrame(cx, FRAME_EXPAND_ALL); - script = fp->script(); - pc = cx->regs().pc; - JS_ASSERT(script->code <= pc && pc < script->code + script->length); - - if (pc < script->main()) - goto do_fallback; - - if (spindex != JSDVG_IGNORE_STACK) { - jsbytecode **pcstack; - - /* - * Prepare computing pcstack containing pointers to opcodes that - * populated interpreter's stack with its current content. - */ - pcstack = (jsbytecode **) - cx->malloc_(StackDepth(script) * sizeof *pcstack); - if (!pcstack) + { + char *result; + if (!DecompileExpressionFromStack(cx, spindex, v, &result)) return NULL; - jsbytecode *lastDecomposedPC = NULL; - int pcdepth = ReconstructPCStack(cx, script, pc, pcstack, &lastDecomposedPC); - if (pcdepth < 0) - goto release_pcstack; - - if (spindex != JSDVG_SEARCH_STACK) { - JS_ASSERT(spindex < 0); - pcdepth += spindex; - if (pcdepth < 0) - goto release_pcstack; - pc = pcstack[pcdepth]; - } else { - /* - * We search from fp->sp to base to find the most recently - * calculated value matching v under assumption that it is - * it that caused exception, see bug 328664. - */ - Value *stackBase = cx->regs().spForStackDepth(0); - Value *sp = cx->regs().sp; - do { - if (sp == stackBase) { - pcdepth = -1; - goto release_pcstack; - } - } while (*--sp != v); - - /* - * The value may have come from beyond stackBase + pcdepth, meaning - * that it came from a temporary slot pushed by the interpreter or - * arguments pushed for an Invoke call. Only update pc if beneath - * stackBase + pcdepth. If above, the value may or may not be - * produced by the current pc. Since it takes a fairly contrived - * combination of calls to produce a situation where this is not - * what we want, we just use the current pc. - * - * If we are in the middle of a decomposed opcode, use the outer - * 'fat' opcode itself. Any source notes for the operation which - * are needed during decompilation will be associated with the - * outer opcode. - */ - if (sp < stackBase + pcdepth) { - pc = pcstack[sp - stackBase]; - if (lastDecomposedPC) { - size_t len = GetDecomposeLength(lastDecomposedPC, - js_CodeSpec[*lastDecomposedPC].length); - if (unsigned(pc - lastDecomposedPC) < len) - pc = lastDecomposedPC; - } - } + if (result) { + if (strcmp(result, "(intermediate value)")) + return result; + cx->free_(result); } - - release_pcstack: - cx->free_(pcstack); - if (pcdepth < 0) - goto do_fallback; } - - { - char *name = DecompileExpression(cx, script, fp->maybeFun(), pc); - if (name != FAILED_EXPRESSION_DECOMPILER) - return name; - } - - do_fallback: if (!fallback) { + if (v.isUndefined()) + return JS_strdup(cx, js_undefined_str); // Prevent users from seeing "(void 0)" fallback = js_ValueToSource(cx, v); if (!fallback) return NULL; } size_t length = fallback->length(); const jschar *chars = fallback->getChars(cx); if (!chars) return NULL; @@ -5922,17 +6310,17 @@ DecompileExpression(JSContext *cx, JSScr Foreground::free_(pcstack); } } g; g.pcstack = (jsbytecode **)OffTheBooks::malloc_(StackDepth(script) * sizeof *g.pcstack); if (!g.pcstack) return NULL; - int pcdepth = ReconstructPCStack(cx, script, begin, g.pcstack, NULL); + int pcdepth = ReconstructPCStack(cx, script, begin, g.pcstack); if (pcdepth < 0) return FAILED_EXPRESSION_DECOMPILER; g.printer = js_NewPrinter(cx, "js_DecompileValueGenerator", fun, 0, false, false, false); if (!g.printer) return NULL; g.printer->dvgfence = end; @@ -5941,17 +6329,17 @@ DecompileExpression(JSContext *cx, JSScr return NULL; return JS_strdup(cx, g.printer->sprinter.string()); } unsigned js_ReconstructStackDepth(JSContext *cx, JSScript *script, jsbytecode *pc) { - return ReconstructPCStack(cx, script, pc, NULL, NULL); + return ReconstructPCStack(cx, script, pc, NULL); } #define LOCAL_ASSERT(expr) LOCAL_ASSERT_RV(expr, -1); static int SimulateOp(JSContext *cx, JSScript *script, JSOp op, const JSCodeSpec *cs, jsbytecode *pc, jsbytecode **pcstack, unsigned &pcdepth) { @@ -6003,42 +6391,37 @@ SimulateOp(JSContext *cx, JSScript *scri break; } pcdepth += ndefs; return pcdepth; } static int ReconstructPCStack(JSContext *cx, JSScript *script, jsbytecode *target, - jsbytecode **pcstack, jsbytecode **lastDecomposedPC) + jsbytecode **pcstack) { /* * Walk forward from script->main and compute the stack depth and stack of * operand-generating opcode PCs in pcstack. * * FIXME: Code to compute oplen copied from js_Disassemble1 and reduced. * FIXME: Optimize to use last empty-stack sequence point. */ LOCAL_ASSERT(script->code <= target && target < script->code + script->length); jsbytecode *pc = script->code; unsigned pcdepth = 0; ptrdiff_t oplen; for (; pc < target; pc += oplen) { JSOp op = JSOp(*pc); const JSCodeSpec *cs = &js_CodeSpec[op]; - oplen = cs->length; - if (oplen < 0) - oplen = js_GetVariableBytecodeLength(pc); - - if (cs->format & JOF_DECOMPOSE) { - if (lastDecomposedPC) - *lastDecomposedPC = pc; + oplen = GetBytecodeLength(pc); + + if (cs->format & JOF_DECOMPOSE) continue; - } /* * A (C ? T : E) expression requires skipping either T (if target is in * E) or both T and E (if target is after the whole expression) before * adjusting pcdepth based on the JSOP_IFEQ at pc that tests condition * C. We know that the stack depth can't change from what it was with * C on top of stack. */
--- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3027,30 +3027,30 @@ js_String(JSContext *cx, unsigned argc, JSBool js::str_fromCharCode(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); JS_ASSERT(args.length() <= StackSpace::ARGS_LENGTH_MAX); if (args.length() == 1) { uint16_t code; - if (!ValueToUint16(cx, args[0], &code)) + if (!ToUint16(cx, args[0], &code)) return JS_FALSE; if (StaticStrings::hasUnit(code)) { args.rval().setString(cx->runtime->staticStrings.getUnit(code)); return JS_TRUE; } args[0].setInt32(code); } jschar *chars = (jschar *) cx->malloc_((args.length() + 1) * sizeof(jschar)); if (!chars) return JS_FALSE; for (unsigned i = 0; i < args.length(); i++) { uint16_t code; - if (!ValueToUint16(cx, args[i], &code)) { + if (!ToUint16(cx, args[i], &code)) { cx->free_(chars); return JS_FALSE; } chars[i] = (jschar)code; } chars[args.length()] = 0; JSString *str = js_NewString(cx, chars, args.length()); if (!str) {
--- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -62,17 +62,21 @@ Compressor::compressMore() { uInt left = inplen - (zs.next_in - inp); bool done = left <= CHUNKSIZE; if (done) zs.avail_in = left; else if (zs.avail_in == 0) zs.avail_in = CHUNKSIZE; int ret = deflate(&zs, done ? Z_FINISH : Z_NO_FLUSH); - if (ret == Z_BUF_ERROR) { + if (ret == Z_MEM_ERROR) { + zs.avail_out = 0; + return false; + } + if (ret == Z_BUF_ERROR || (done && ret == Z_OK)) { JS_ASSERT(zs.avail_out == 0); return false; } JS_ASSERT_IF(!done, ret == Z_OK); JS_ASSERT_IF(done, ret == Z_STREAM_END); return !done; }
--- a/js/src/tests/e4x/Regress/regress-355478.js +++ b/js/src/tests/e4x/Regress/regress-355478.js @@ -9,17 +9,17 @@ var BUGNUMBER = 355478; var summary = 'Do not crash with hasOwnProperty'; var actual = ''; var expect = ''; printBugNumber(BUGNUMBER); START(summary); -expect = 'TypeError: <x/>.hasOwnProperty is not a constructor'; +expect = 'TypeError: (intermediate value).hasOwnProperty is not a constructor'; actual = ''; try { new <x/>.hasOwnProperty("y"); } catch(ex) {
--- a/js/src/tests/ecma_3/Object/8.6.1-01.js +++ b/js/src/tests/ecma_3/Object/8.6.1-01.js @@ -10,17 +10,17 @@ var summary = 'In strict mode, setting a printBugNumber(BUGNUMBER); printStatus (summary); enterFunc (String (BUGNUMBER)); // should throw an error in strict mode var actual = ''; -var expect = 's.length is read-only'; +var expect = '"length" is read-only'; var status = summary + ': Throw if STRICT and WERROR is enabled'; if (!options().match(/strict/)) { options('strict'); } if (!options().match(/werror/)) {
--- a/js/src/tests/js1_5/Regress/regress-372364.js +++ b/js/src/tests/js1_5/Regress/regress-372364.js @@ -16,28 +16,28 @@ test(); function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); print('See Also bug 365891'); - expect = /TypeError: a\(1\) (has no properties|is null)/; + expect = /TypeError: a\(.+\) (has no properties|is null)/; try { function a(){return null;} a(1)[0]; } catch(ex) { actual = ex + ''; } reportMatch(expect, actual, summary); - expect = /TypeError: \/a\/\.exec\("b"\) (has no properties|is null)/; + expect = /TypeError: \(intermediate value\).exec\(.+\) (has no properties|is null)/; try { /a/.exec("b")[0]; } catch(ex) { actual = ex + ''; }
--- a/js/src/tests/js1_5/extensions/regress-50447-1.js +++ b/js/src/tests/js1_5/extensions/regress-50447-1.js @@ -94,24 +94,19 @@ function test2() { /* generate an error with only msg property */ enterFunc ("test2"); /* note this test incorporates the path to the test file and assumes the path to the test case is a subdirectory of the directory containing jsDriver.pl */ - var expectedLine = 114; + var expectedLine = 109; var expectedFileName = 'js1_5/extensions/regress-50447-1.js'; - if (typeof document == "undefined") - { - expectedFileName = './' + expectedFileName; - } - else - { + if (typeof document != "undefined") { expectedFileName = document.location.href. replace(/[^\/]*(\?.*)$/, '') + expectedFileName; } var e = new InternalError ("msg"); reportCompare ("(new InternalError(\"msg\", \"" + expectedFileName + "\", " + expectedLine + "))", normalize(e.toSource()), @@ -132,22 +127,17 @@ function test3() /* note this test incorporates the path to the test file and assumes the path to the test case is a subdirectory of the directory containing jsDriver.pl */ enterFunc ("test3"); var expectedFileName = 'js1_5/extensions/regress-50447-1.js'; - if (typeof document == "undefined") - { - expectedFileName = './' + expectedFileName; - } - else - { + if (typeof document != "undefined") { expectedFileName = document.location.href. replace(/[^\/]*(\?.*)$/, '') + expectedFileName; } var e = new InternalError ("msg"); e.lineNumber = 10; reportCompare ("(new InternalError(\"msg\", \"" + @@ -163,17 +153,17 @@ function test3() } function test4() { /* generate an error with only msg and filename properties */ enterFunc ("test4"); - var expectedLine = 173; + var expectedLine = 163; var e = new InternalError ("msg", "file"); reportCompare ("(new InternalError(\"msg\", \"file\", " + expectedLine + "))", e.toSource(), "toSource() returned unexpected result."); reportCompare ("file", e.fileName, "fileName property returned unexpected value."); reportCompare (expectedLine, e.lineNumber,
--- a/js/src/tests/js1_6/Array/regress-304828.js +++ b/js/src/tests/js1_6/Array/regress-304828.js @@ -24,30 +24,30 @@ try catch(e) { actual = e + ''; } reportCompare(expect, actual, summary + ': join'); // reverse value = '123'; -expect = 'TypeError: Array.prototype.reverse.call(value) is read-only'; +expect = 'TypeError: Array.prototype.reverse.call(...) is read-only'; try { actual = Array.prototype.reverse.call(value) + ''; } catch(e) { actual = e + ''; } reportCompare(expect, actual, summary + ': reverse'); // sort value = 'cba'; -expect = 'TypeError: Array.prototype.sort.call(value) is read-only'; +expect = 'TypeError: Array.prototype.sort.call(...) is read-only'; try { actual = Array.prototype.sort.call(value) + ''; } catch(e) { actual = e + ''; } @@ -64,59 +64,59 @@ catch(e) { actual = e + ''; } reportCompare(expect, actual, summary + ': push'); reportCompare('abc', value, summary + ': push'); // pop value = 'abc'; -expect = "TypeError: property Array.prototype.pop.call(value) is non-configurable and can't be deleted"; +expect = "TypeError: property Array.prototype.pop.call(...) is non-configurable and can't be deleted"; try { actual = Array.prototype.pop.call(value); } catch(e) { actual = e + ''; } reportCompare(expect, actual, summary + ': pop'); reportCompare('abc', value, summary + ': pop'); // unshift value = 'def'; -expect = 'TypeError: Array.prototype.unshift.call(value, "a", "b", "c") is read-only'; +expect = 'TypeError: Array.prototype.unshift.call(...) is read-only'; try { actual = Array.prototype.unshift.call(value, 'a', 'b', 'c'); } catch(e) { actual = e + ''; } reportCompare(expect, actual, summary + ': unshift'); reportCompare('def', value, summary + ': unshift'); // shift value = 'abc'; -expect = 'TypeError: Array.prototype.shift.call(value) is read-only'; +expect = 'TypeError: Array.prototype.shift.call(...) is read-only'; try { actual = Array.prototype.shift.call(value); } catch(e) { actual = e + ''; } reportCompare(expect, actual, summary + ': shift'); reportCompare('abc', value, summary + ': shift'); // splice value = 'abc'; -expect = 'TypeError: Array.prototype.splice.call(value, 1, 1) is read-only'; +expect = 'TypeError: Array.prototype.splice.call(...) is read-only'; try { actual = Array.prototype.splice.call(value, 1, 1) + ''; } catch(e) { actual = e + ''; }
--- a/js/src/tests/js1_6/Regress/regress-350417.js +++ b/js/src/tests/js1_6/Regress/regress-350417.js @@ -15,17 +15,17 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = 'TypeError: y.a = [2 for each (p in [])] is not a function'; + expect = 'TypeError: [] is not a function'; try { eval('y = {}; (y.a = [2 for each (p in [])])();'); } catch(ex) { actual = ex + ''; }
--- a/js/src/tests/js1_7/block/regress-352616.js +++ b/js/src/tests/js1_7/block/regress-352616.js @@ -14,43 +14,43 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: (\(let \(b = 1\) 2\).c is not a function|Cannot find function c.)/; + expect = /TypeError: (.+\.c is not a function|Cannot find function c.)/; actual = 'No Error'; try { for(a in (let (b=1) 2).c(3)) { }; } catch(ex) { actual = ex + ''; } reportMatch(expect, actual, summary + ': 1'); - expect = /TypeError: (\(let \(b = 1, d = 2\) 2\).c is not a function|Cannot find function c.)/; + expect = /TypeError: (.+\.c is not a function|Cannot find function c.)/; actual = 'No Error'; try { for(a in (let (b=1,d=2) 2).c(3)) { }; } catch(ex) { actual = ex + ''; } reportMatch(expect, actual, summary + ': 2'); - expect = /TypeError: (\(let \(b = 1, d = 2\) 2\).c is not a function|Cannot find function c.)/; + expect = /TypeError: (.+\.c is not a function|Cannot find function c.)/; actual = 'No Error'; try { for(a in (let (b=1,d=2) 2).c(3)) { }; } catch(ex) { actual = ex + '';
--- a/js/src/tests/js1_7/extensions/regress-355052-01.js +++ b/js/src/tests/js1_7/extensions/regress-355052-01.js @@ -15,17 +15,17 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: NaN is not a function/; + expect = /TypeError: .+ is not a function/; actual = 'No Error'; try { ( {valueOf: gc} - [function(){}].__iterator__ )(); } catch(ex) { actual = ex + '';
--- a/js/src/tests/js1_7/extensions/regress-355052-02.js +++ b/js/src/tests/js1_7/extensions/regress-355052-02.js @@ -15,17 +15,17 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: NaN is not a function/; + expect = /TypeError: .+ is not a function/; actual = 'No Error'; try { ( {valueOf: gc} - [].a )(); } catch(ex) { actual = ex + '';
--- a/js/src/tests/js1_7/extensions/regress-355052-03.js +++ b/js/src/tests/js1_7/extensions/regress-355052-03.js @@ -15,17 +15,17 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: NaN is not a function/; + expect = /TypeError: .+ is not a function/; actual = 'No Error'; try { var obj = {valueOf: gc }; function f() { ( obj * [].a )(); }
--- a/js/src/tests/js1_7/regress/regress-352870-02.js +++ b/js/src/tests/js1_7/regress/regress-352870-02.js @@ -16,17 +16,17 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: \[1, 2, 3, 4\].g (has no properties|is undefined)/; + expect = /TypeError: .+\.g (has no properties|is undefined)/; actual = ''; try { switch(4) { case [(let (y = [].j(5)) ({})) for (p in ([1,2,3,4].g).v({},((w).y(z, <x/>))))]: } } catch(ex) { actual = ex + '';
--- a/js/src/tests/js1_8/extensions/regress-469625.js +++ b/js/src/tests/js1_8/extensions/regress-469625.js @@ -17,17 +17,17 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = 'TypeError: [].__proto__ is not a function'; + expect = 'TypeError: (intermediate value).__proto__ is not a function'; jit(true); Array.prototype.__proto__ = function () 3; try { [].__proto__();
--- a/js/src/tests/js1_8_1/regress/regress-420399.js +++ b/js/src/tests/js1_8_1/regress/regress-420399.js @@ -15,22 +15,22 @@ test(); //----------------------------------------------------------------------------- function test() { enterFunc ('test'); printBugNumber(BUGNUMBER); printStatus (summary); - expect = /TypeError: let \(a = undefined\) a (is undefined|has no properties)/; + expect = "TypeError: undefined has no properties"; try { (let (a=undefined) a).b = 3; } catch(ex) { actual = ex + ''; } - reportMatch(expect, actual, summary); + reportCompare(expect, actual, summary); exitFunc ('test'); }
--- a/js/src/tests/js1_8_5/regress/regress-469758.js +++ b/js/src/tests/js1_8_5/regress/regress-469758.js @@ -4,11 +4,11 @@ var err; try { {let i=1} {let j=1; [][j][2]} } catch (e) { err = e; } assertEq(err instanceof TypeError, true); -assertEq(err.message, "[][j] is undefined"); +assertEq(err.message, "(intermediate value)[j] is undefined"); reportCompare(0, 0, 'ok');
--- a/js/src/tests/lib/tests.py +++ b/js/src/tests/lib/tests.py @@ -81,18 +81,17 @@ class Test(object): def get_command(self, js_cmd_prefix): dirname, filename = os.path.split(self.path) cmd = js_cmd_prefix if self.allowXml: cmd = cmd + [ '-e', 'options("allow_xml")' ] cmd = cmd + Test.prefix_command(dirname) if self.debugMode: cmd += [ '-d' ] - # There is a test that requires the path to start with './'. - cmd += [ '-f', './' + self.path ] + cmd += [ '-f', self.path ] return cmd def run(self, js_cmd_prefix, timeout=30.0): cmd = self.get_command(js_cmd_prefix) out, err, rc, dt, timed_out = run_cmd(cmd, timeout) return TestOutput(self, cmd, out, err, rc, dt, timed_out) class TestCase(Test):
--- a/js/xpconnect/src/dictionary_helper_gen.conf +++ b/js/xpconnect/src/dictionary_helper_gen.conf @@ -12,17 +12,16 @@ dictionaries = [ [ 'BlobPropertyBag', 'nsIDOMFile.idl' ], [ 'MutationObserverInit', 'nsIDOMMutationObserver.idl' ], [ 'WifiConnectionInfoEventInit', 'nsIWifiEventInits.idl' ], [ 'WifiStatusChangeEventInit', 'nsIWifiEventInits.idl' ], [ 'GeoPositionOptions', 'nsIDOMGeoGeolocation.idl' ], [ 'DOMFileMetadataParameters', 'nsIDOMLockedFile.idl' ], [ 'XMLHttpRequestParameters', 'nsIXMLHttpRequest.idl' ], [ 'DeviceStorageEnumerationParameters', 'nsIDOMDeviceStorage.idl' ], - [ 'DeviceStorageChangeEventInit', 'nsIDOMDeviceStorageChangeEvent.idl' ], [ 'CameraSize', 'nsIDOMCameraManager.idl' ], [ 'CameraRegion', 'nsIDOMCameraManager.idl' ], [ 'CameraPosition', 'nsIDOMCameraManager.idl' ], [ 'CameraSelector', 'nsIDOMCameraManager.idl' ], [ 'CameraPictureOptions', 'nsIDOMCameraManager.idl' ] ] # include file names
--- a/js/xpconnect/src/dom_quickstubs.qsconf +++ b/js/xpconnect/src/dom_quickstubs.qsconf @@ -181,16 +181,17 @@ members = [ 'nsIDOMUIEvent.which', 'nsIDOMUIEvent.rangeParent', 'nsIDOMUIEvent.rangeOffset', 'nsIDOMUIEvent.pageX', 'nsIDOMUIEvent.pageY', 'nsIDOMUIEvent.isChar', 'nsIDOMTouch.*', + 'nsIDOMTouchList.*', 'nsIDOMTouchEvent.*', # dom/interfaces/geolocation - None. # dom/interfaces/html 'nsIDOMHTMLAnchorElement.href', 'nsIDOMHTMLAnchorElement.rel', 'nsIDOMHTMLAnchorElement.target',
--- a/js/xpconnect/src/dombindings.conf +++ b/js/xpconnect/src/dombindings.conf @@ -36,20 +36,16 @@ list_classes = [ 'name': 'ClientRectList', 'nativeClass': 'nsClientRectList' }, { 'name': 'PaintRequestList', 'nativeClass': 'nsPaintRequestList' }, { - 'name': 'TouchList', - 'nativeClass': 'nsDOMTouchList' - }, - { 'name': 'FileList', 'nativeClass': 'nsDOMFileList' }, { 'name': 'SVGLengthList', 'nativeClass': 'mozilla::DOMSVGLengthList' }, { @@ -73,19 +69,16 @@ list_classes = [ prefableClasses = { } irregularFilenames = { 'nsHTMLOptionCollection': 'nsHTMLSelectElement', 'mozilla::dom::PropertyNodeList': 'HTMLPropertiesCollection', 'nsClientRectList': 'nsClientRect', 'nsPaintRequestList': 'nsPaintRequest', - 'nsIDOMTouch': 'nsIDOMTouchEvent', - 'nsIDOMTouchList': 'nsIDOMTouchEvent', - 'nsDOMTouchList': 'nsDOMTouchEvent', 'nsDOMFileList': 'nsDOMFile', } customInheritance = { 'nsIDOMPropertyNodeList': 'nsIDOMNodeList', 'nsIDOMHTMLOptionsCollection': 'nsIDOMHTMLCollection', 'nsIDOMHTMLPropertiesCollection': 'nsIDOMHTMLCollection', }
--- a/js/xpconnect/src/event_impl_gen.conf.in +++ b/js/xpconnect/src/event_impl_gen.conf.in @@ -15,17 +15,18 @@ simple_events = [ 'CustomEvent', 'PageTransitionEvent', 'PopStateEvent', 'HashChangeEvent', 'CloseEvent', 'MozContactChangeEvent', 'DeviceOrientationEvent', 'DeviceLightEvent', - 'MozApplicationEvent' + 'MozApplicationEvent', + 'DeviceStorageChangeEvent' ] """ include file names """ special_includes = [ 'DictionaryHelpers.h', 'nsContentUtils.h', 'nsIDOMApplicationRegistry.h' ]
--- a/layout/base/nsBidiPresUtils.cpp +++ b/layout/base/nsBidiPresUtils.cpp @@ -15,16 +15,17 @@ #include "nsBidiUtils.h" #include "nsCSSFrameConstructor.h" #include "nsContainerFrame.h" #include "nsInlineFrame.h" #include "nsPlaceholderFrame.h" #include "nsFirstLetterFrame.h" #include "nsUnicodeProperties.h" #include "nsTextFrame.h" +#include "nsStyleStructInlines.h" #undef NOISY_BIDI #undef REALLY_NOISY_BIDI using namespace mozilla; static const PRUnichar kSpace = 0x0020; static const PRUnichar kZWSP = 0x200B; @@ -512,17 +513,17 @@ CreateContinuation(nsIFrame* aFrame, NS_ASSERTION(parent, "Couldn't get frame parent in nsBidiPresUtils::CreateContinuation"); nsresult rv = NS_OK; // Have to special case floating first letter frames because the continuation // doesn't go in the first letter frame. The continuation goes with the rest // of the text that the first letter frame was made out of. if (parent->GetType() == nsGkAtoms::letterFrame && - parent->GetStyleDisplay()->IsFloating()) { + parent->IsFloating()) { nsFirstLetterFrame* letterFrame = do_QueryFrame(parent); rv = letterFrame->CreateContinuationForFloatingParent(presContext, aFrame, aNewFrame, aIsFluid); return rv; } rv = presShell->FrameConstructor()-> CreateContinuingFrame(presContext, aFrame, parent, aNewFrame, aIsFluid); @@ -1087,17 +1088,17 @@ nsBidiPresUtils::TraverseFrames(nsBlockF } else { // other frame type -- see the Unicode Bidi Algorithm: // "...inline objects (such as graphics) are treated as if they are ... // U+FFFC" // <wbr>, however, is treated as U+200B ZERO WIDTH SPACE. See // http://dev.w3.org/html5/spec/Overview.html#phrasing-content-1 aBpd->AppendUnichar(content->IsHTML(nsGkAtoms::wbr) ? kZWSP : kObjectSubstitute); - if (!frame->GetStyleContext()->GetStyleDisplay()->IsInlineOutside()) { + if (!frame->IsInlineOutside()) { // if it is not inline, end the paragraph ResolveParagraphWithinBlock(aBlockFrame, aBpd); } } } else { // For a non-leaf frame, recurse into TraverseFrames nsIFrame* kid = frame->GetFirstPrincipalChild(); nsIFrame* overflowKid = frame->GetFirstChild(nsIFrame::kOverflowList);
--- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -83,16 +83,17 @@ #include "nsBox.h" #include "nsTArray.h" #include "nsGenericDOMDataNode.h" #include "mozilla/dom/Element.h" #include "FrameLayerBuilder.h" #include "nsAutoLayoutPhase.h" #include "nsCSSRenderingBorders.h" #include "nsRenderingContext.h" +#include "nsStyleStructInlines.h" #ifdef MOZ_XUL #include "nsIRootBox.h" #include "nsIDOMXULCommandDispatcher.h" #include "nsIDOMXULDocument.h" #include "nsIXULDocument.h" #endif #ifdef MOZ_FLEXBOX @@ -355,22 +356,16 @@ GetFieldSetBlockFrame(nsIFrame* aFieldse #define FCDATA_DECL(_flags, _func) \ { _flags, { (FrameCreationFunc)_func }, nullptr, nullptr } #define FCDATA_WITH_WRAPPING_BLOCK(_flags, _func, _anon_box) \ { _flags | FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS, \ { (FrameCreationFunc)_func }, nullptr, &_anon_box } //---------------------------------------------------------------------- -static bool -IsInlineOutside(nsIFrame* aFrame) -{ - return aFrame->GetStyleDisplay()->IsInlineOutside(); -} - /** * True if aFrame is an actual inline frame in the sense of non-replaced * display:inline CSS boxes. In other words, it can be affected by {ib} * splitting and can contain first-letter frames. Basically, this is either an * inline frame (positioned or otherwise) or an line frame (this last because * it can contain first-letter and because inserting blocks in the middle of it * needs to terminate it). */ @@ -469,17 +464,17 @@ static nsIFrame* GetSpecialPrevSibling(n static nsIFrame* GetLastSpecialSibling(nsIFrame* aFrame, bool aReturnEmptyTrailingInline) { for (nsIFrame *frame = aFrame, *next; ; frame = next) { next = GetSpecialSibling(frame); if (!next || (!aReturnEmptyTrailingInline && !next->GetFirstPrincipalChild() && !GetSpecialSibling(next))) { - NS_ASSERTION(!next || !IsInlineOutside(frame), + NS_ASSERTION(!next || !frame->IsInlineOutside(), "Should have a block here!"); return frame; } } NS_NOTREACHED("unreachable code"); return nullptr; } @@ -556,31 +551,31 @@ GetIBContainingBlockFor(nsIFrame* aFrame // After this function returns, aLink is pointing to the first link at or // after its starting position for which the next frame is a block. If there // is no such link, it points to the end of the list. static void FindFirstBlock(nsFrameList::FrameLinkEnumerator& aLink) { for ( ; !aLink.AtEnd(); aLink.Next()) { - if (!IsInlineOutside(aLink.NextFrame())) { + if (!aLink.NextFrame()->IsInlineOutside()) { return; } } } // This function returns a frame link enumerator pointing to the first link in // the list for which the next frame is not block. If there is no such link, // it points to the end of the list. static nsFrameList::FrameLinkEnumerator FindFirstNonBlock(const nsFrameList& aList) { nsFrameList::FrameLinkEnumerator link(aList); for (; !link.AtEnd(); link.Next()) { - if (IsInlineOutside(link.NextFrame())) { + if (link.NextFrame()->IsInlineOutside()) { break; } } return link; } inline void SetInitialSingleChild(nsIFrame* aParent, nsIFrame* aFrame) @@ -1063,18 +1058,22 @@ nsFrameConstructorState::GetGeometricPar // elements. (1) has the usual problems when multiple frames share the same // content (notice all the special cases in this file dealing with inner // tables and outer tables which share the same content). (2) requires some // work and possible factoring. // // XXXbz couldn't we just force position to "static" on roots and // float to "none"? That's OK per CSS 2.1, as far as I can tell. - if (aStyleDisplay->IsFloating() && mFloatedItems.containingBlock) { - NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositioned(), + if (aContentParentFrame && aContentParentFrame->IsSVGText()) { + return aContentParentFrame; + } + + if (aStyleDisplay->IsFloatingStyle() && mFloatedItems.containingBlock) { + NS_ASSERTION(!aStyleDisplay->IsAbsolutelyPositionedStyle(), "Absolutely positioned _and_ floating?"); return mFloatedItems.containingBlock; } if (aStyleDisplay->mPosition == NS_STYLE_POSITION_ABSOLUTE && mAbsoluteItems.containingBlock) { return mAbsoluteItems.containingBlock; } @@ -1115,17 +1114,17 @@ nsFrameConstructorState::AddChild(nsIFra "Popup whose parent is not the popup containing block?"); NS_ASSERTION(mPopupItems.containingBlock, "Must have a popup set frame!"); needPlaceholder = true; frameItems = &mPopupItems; placeholderType = PLACEHOLDER_FOR_POPUP; } else #endif // MOZ_XUL - if (aCanBeFloated && disp->IsFloating() && + if (aCanBeFloated && aNewFrame->IsFloating() && mFloatedItems.containingBlock) { NS_ASSERTION(aNewFrame->GetParent() == mFloatedItems.containingBlock, "Float whose parent is not the float containing block?"); needPlaceholder = true; frameItems = &mFloatedItems; placeholderType = PLACEHOLDER_FOR_FLOAT; } else if (aCanBePositioned) { @@ -1924,17 +1923,17 @@ nsCSSFrameConstructor::ConstructTable(ns nsFrameItems childItems; // Process children nsFrameConstructorSaveState absoluteSaveState; const nsStyleDisplay* display = outerStyleContext->GetStyleDisplay(); // Mark the table frame as an absolute container if needed - if (display->IsPositioned()) { + if (display->IsPositioned(aParentFrame)) { aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState); } if (aItem.mFCData->mBits & FCDATA_USE_CHILD_ITEMS) { rv = ConstructFramesFromItemList(aState, aItem.mChildItems, innerFrame, childItems); } else { rv = ProcessChildren(aState, content, styleContext, innerFrame, true, childItems, false, aItem.mPendingBinding); @@ -2469,18 +2468,18 @@ nsCSSFrameConstructor::ConstructDocEleme if (!contentFrame) return NS_ERROR_OUT_OF_MEMORY; nsFrameItems frameItems; // Use a null PendingBinding, since our binding is not in fact pending. rv = ConstructBlock(state, display, aDocElement, state.GetGeometricParent(display, mDocElementContainingBlock), mDocElementContainingBlock, styleContext, - &contentFrame, frameItems, display->IsPositioned(), - nullptr); + &contentFrame, frameItems, + display->IsPositioned(contentFrame), nullptr); if (NS_FAILED(rv) || frameItems.IsEmpty()) return rv; *aNewFrame = frameItems.FirstChild(); NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames"); } } // set the primary frame @@ -2968,19 +2967,19 @@ nsCSSFrameConstructor::ConstructSelectFr // Notify the listbox that it is being used as a dropdown list. nsIListControlFrame * listControlFrame = do_QueryFrame(listFrame); if (listControlFrame) { listControlFrame->SetComboboxFrame(comboboxFrame); } // Notify combobox that it should use the listbox as it's popup comboBox->SetDropDown(listFrame); - NS_ASSERTION(!listStyle->GetStyleDisplay()->IsPositioned(), + NS_ASSERTION(!listFrame->IsPositioned(), "Ended up with positioned dropdown list somehow."); - NS_ASSERTION(!listStyle->GetStyleDisplay()->IsFloating(), + NS_ASSERTION(!listFrame->IsFloating(), "Ended up with floating dropdown list somehow."); // Initialize the scroll frame positioned. Note that it is NOT // initialized as absolutely positioned. nsIFrame* scrolledFrame = NS_NewSelectsAreaFrame(mPresShell, styleContext, flags); InitializeSelectFrame(aState, listFrame, scrolledFrame, content, comboboxFrame, listStyle, true, @@ -3132,17 +3131,17 @@ nsCSSFrameConstructor::ConstructFieldSet if (NS_FAILED(rv)) { return rv; } // Process children nsFrameConstructorSaveState absoluteSaveState; nsFrameItems childItems; - if (aStyleDisplay->IsPositioned()) { + if (newFrame->IsPositioned()) { aState.PushAbsoluteContainingBlock(newFrame, absoluteSaveState); } ProcessChildren(aState, content, styleContext, blockFrame, true, childItems, true, aItem.mPendingBinding); nsFrameItems fieldsetKids; fieldsetKids.AddChild(blockFrame); @@ -3351,18 +3350,18 @@ nsCSSFrameConstructor::FindHTMLData(Elem "Unexpected parent for fieldset content anon box"); if (aTag == nsGkAtoms::legend && (!aParentFrame || (aParentFrame->GetType() != nsGkAtoms::fieldSetFrame && aParentFrame->GetStyleContext()->GetPseudo() != nsCSSAnonBoxes::fieldsetContent) || !aElement->GetParent() || !aElement->GetParent()->IsHTML(nsGkAtoms::fieldset) || - aStyleContext->GetStyleDisplay()->IsFloating() || - aStyleContext->GetStyleDisplay()->IsAbsolutelyPositioned())) { + aStyleContext->GetStyleDisplay()->IsFloatingStyle() || + aStyleContext->GetStyleDisplay()->IsAbsolutelyPositionedStyle())) { // <legend> is only special inside fieldset, check both the frame tree // parent and content tree parent due to XBL issues. For floated or // absolutely positioned legends we want to construct by display type and // not do special legend stuff. // XXXbz it would be nice if we could just decide this based on the parent // tag, and hence just use a SIMPLE_TAG_CHAIN for legend below, but the // fact that with XBL we could end up with this legend element in some // totally weird insertion point makes that chancy, I think. @@ -3674,17 +3673,17 @@ nsCSSFrameConstructor::ConstructFrameFro } SetInitialSingleChild(newFrame, blockFrame); // Now figure out whether newFrame or blockFrame should be the // absolute container. It should be the latter if it's // positioned, otherwise the former. const nsStyleDisplay* blockDisplay = blockContext->GetStyleDisplay(); - if (blockDisplay->IsPositioned()) { + if (blockDisplay->IsPositioned(blockFrame)) { maybeAbsoluteContainingBlockDisplay = blockDisplay; maybeAbsoluteContainingBlock = blockFrame; } // Our kids should go into the blockFrame newFrame = blockFrame; } @@ -3709,17 +3708,18 @@ nsCSSFrameConstructor::ConstructFrameFro // Process the child content if requested nsFrameItems childItems; nsFrameConstructorSaveState absoluteSaveState; if (bits & FCDATA_FORCE_NULL_ABSPOS_CONTAINER) { aState.PushAbsoluteContainingBlock(nullptr, absoluteSaveState); } else if (!(bits & FCDATA_SKIP_ABSPOS_PUSH) && - maybeAbsoluteContainingBlockDisplay->IsPositioned()) { + maybeAbsoluteContainingBlockDisplay->IsPositioned + (maybeAbsoluteContainingBlock)) { aState.PushAbsoluteContainingBlock(maybeAbsoluteContainingBlock, absoluteSaveState); } if (bits & FCDATA_USE_CHILD_ITEMS) { NS_ASSERTION(!ShouldSuppressFloatingOfDescendants(newFrame), "uh oh -- this frame is supposed to _suppress_ floats, but " "we're about to push it as a float containing block..."); @@ -4303,25 +4303,26 @@ nsCSSFrameConstructor::BuildScrollFrame( FinishBuildingScrollFrame(aNewFrame, aScrolledFrame); return NS_OK; } const nsCSSFrameConstructor::FrameConstructionData* nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay, Element* aElement, + nsIFrame* aParentFrame, nsStyleContext* aStyleContext) { PR_STATIC_ASSERT(eParentTypeCount < (1 << (32 - FCDATA_PARENT_TYPE_OFFSET))); // The style system ensures that floated and positioned frames are // block-level. - NS_ASSERTION(!(aDisplay->IsFloating() || - aDisplay->IsAbsolutelyPositioned()) || - aDisplay->IsBlockOutside(), + NS_ASSERTION(!(aDisplay->IsFloatingStyle() || + aDisplay->IsAbsolutelyPositionedStyle()) || + aDisplay->IsBlockOutsideStyle(), "Style system did not apply CSS2.1 section 9.7 fixups"); // If this is "body", try propagating its scroll style to the viewport // Note that we need to do this even if the body is NOT scrollable; // it might have dynamically changed from scrollable to not scrollable, // and that might need to be propagated. // XXXbz is this the right place to do this? If this code moves, // make this function static. @@ -4335,38 +4336,40 @@ nsCSSFrameConstructor::FindDisplayData(c !mPresShell->GetPresContext()->IsPaginated(), "Shouldn't propagate scroll in paginated contexts"); // If the frame is a block-level frame and is scrollable, then wrap it in a // scroll frame. // XXX Ignore tables for the time being // XXXbz it would be nice to combine this with the other block // case... Think about how do do this? - if (aDisplay->IsBlockInside() && + if ((aParentFrame ? aDisplay->IsBlockInside(aParentFrame) : + aDisplay->IsBlockInsideStyle()) && aDisplay->IsScrollableOverflow() && !propagatedScrollToViewport) { // Except we don't want to do that for paginated contexts for // frames that are block-outside and aren't frames for native // anonymous stuff. if (mPresShell->GetPresContext()->IsPaginated() && - aDisplay->IsBlockOutside() && + aDisplay->IsBlockOutsideStyle() && !aElement->IsInNativeAnonymousSubtree()) { static const FrameConstructionData sForcedNonScrollableBlockData = FULL_CTOR_FCDATA(FCDATA_FORCED_NON_SCROLLABLE_BLOCK, &nsCSSFrameConstructor::ConstructNonScrollableBlock); return &sForcedNonScrollableBlockData; } static const FrameConstructionData sScrollableBlockData = FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructScrollableBlock); return &sScrollableBlockData; } // Handle various non-scrollable blocks - if (aDisplay->IsBlockInside()) { + if ((aParentFrame ? aDisplay->IsBlockInside(aParentFrame) : + aDisplay->IsBlockInsideStyle())) { static const FrameConstructionData sNonScrollableBlockData = FULL_CTOR_FCDATA(0, &nsCSSFrameConstructor::ConstructNonScrollableBlock); return &sNonScrollableBlockData; } static const FrameConstructionDataByInt sDisplayData[] = { // To keep the hash table small don't add inline frames (they're // typically things like FONT and B), because we can quickly @@ -4419,18 +4422,20 @@ nsCSSFrameConstructor::FindDisplayData(c FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRowGroup), &nsCSSFrameConstructor::ConstructTableRow) }, { NS_STYLE_DISPLAY_TABLE_CELL, FULL_CTOR_FCDATA(FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeRow), &nsCSSFrameConstructor::ConstructTableCell) } }; - return FindDataByInt(aDisplay->mDisplay, aElement, aStyleContext, - sDisplayData, ArrayLength(sDisplayData)); + return FindDataByInt((aParentFrame ? aDisplay->GetDisplay(aParentFrame) : + aDisplay->mDisplay), + aElement, aStyleContext, sDisplayData, + ArrayLength(sDisplayData)); } nsresult nsCSSFrameConstructor::ConstructScrollableBlock(nsFrameConstructorState& aState, FrameConstructionItem& aItem, nsIFrame* aParentFrame, const nsStyleDisplay* aDisplay, nsFrameItems& aFrameItems, @@ -4450,17 +4455,18 @@ nsCSSFrameConstructor::ConstructScrollab // pass a temporary stylecontext, the correct one will be set later nsIFrame* scrolledFrame = NS_NewBlockFormattingContext(mPresShell, styleContext); nsFrameItems blockItem; nsresult rv = ConstructBlock(aState, scrolledContentStyle->GetStyleDisplay(), content, *aNewFrame, *aNewFrame, scrolledContentStyle, - &scrolledFrame, blockItem, aDisplay->IsPositioned(), + &scrolledFrame, blockItem, + aDisplay->IsPositioned(scrolledFrame), aItem.mPendingBinding); if (NS_UNLIKELY(NS_FAILED(rv))) { // XXXbz any cleanup needed here? return rv; } NS_ASSERTION(blockItem.FirstChild() == scrolledFrame, "Scrollframe's frameItems should be exactly the scrolled frame"); @@ -4482,32 +4488,33 @@ nsCSSFrameConstructor::ConstructNonScrol nsStyleContext* const styleContext = aItem.mStyleContext; // We want a block formatting context root in paginated contexts for // every block that would be scrollable in a non-paginated context. // We mark our blocks with a bit here if this condition is true, so // we can check it later in nsFrame::ApplyPaginatedOverflowClipping. bool clipPaginatedOverflow = (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0; - if (aDisplay->IsAbsolutelyPositioned() || - aDisplay->IsFloating() || - NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay || - clipPaginatedOverflow) { + if ((aDisplay->IsAbsolutelyPositionedStyle() || + aDisplay->IsFloatingStyle() || + NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay->mDisplay || + clipPaginatedOverflow) && + !aParentFrame->IsSVGText()) { *aNewFrame = NS_NewBlockFormattingContext(mPresShell, styleContext); if (clipPaginatedOverflow) { (*aNewFrame)->AddStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW); } } else { *aNewFrame = NS_NewBlockFrame(mPresShell, styleContext); } return ConstructBlock(aState, aDisplay, aItem.mContent, aState.GetGeometricParent(aDisplay, aParentFrame), aParentFrame, styleContext, aNewFrame, - aFrameItems, aDisplay->IsPositioned(), + aFrameItems, aDisplay->IsPositioned(*aNewFrame), aItem.mPendingBinding); } nsresult nsCSSFrameConstructor::InitAndRestoreFrame(const nsFrameConstructorState& aState, nsIContent* aContent, nsIFrame* aParentFrame, @@ -4654,17 +4661,17 @@ nsCSSFrameConstructor::FindMathMLData(El if (aNameSpaceID != kNameSpaceID_MathML) return nullptr; // Handle <math> specially, because it sometimes produces inlines if (aTag == nsGkAtoms::math) { // This needs to match the test in EnsureBlockDisplay in // nsRuleNode.cpp. Though the behavior here for the display:table // case is pretty weird... - if (aStyleContext->GetStyleDisplay()->IsBlockOutside()) { + if (aStyleContext->GetStyleDisplay()->IsBlockOutsideStyle()) { static const FrameConstructionData sBlockMathData = FCDATA_DECL(FCDATA_FORCE_NULL_ABSPOS_CONTAINER | FCDATA_WRAP_KIDS_IN_BLOCKS, NS_CreateNewMathMLmathBlockFrame); return &sBlockMathData; } static const FrameConstructionData sInlineMathData = @@ -5249,17 +5256,17 @@ nsCSSFrameConstructor::AddFrameConstruct // Now check for XUL display types if (!data) { data = FindXULDisplayData(display, element, styleContext); } // And general display types if (!data) { - data = FindDisplayData(display, element, styleContext); + data = FindDisplayData(display, element, aParentFrame, styleContext); } NS_ASSERTION(data, "Should have frame construction data now"); if (data->mBits & FCDATA_SUPPRESS_FRAME) { SetAsUndisplayedContent(aItems, element, styleContext, isGeneratedContent); return; } @@ -5289,18 +5296,19 @@ nsCSSFrameConstructor::AddFrameConstruct display->mDisplay != NS_STYLE_DISPLAY_TABLE_COLUMN)) { SetAsUndisplayedContent(aItems, aContent, styleContext, isGeneratedContent); return; } bool canHavePageBreak = (aFlags & ITEM_ALLOW_PAGE_BREAK) && aState.mPresContext->IsPaginated() && - !display->IsAbsolutelyPositioned() && - !(bits & FCDATA_IS_TABLE_PART); + !display->IsAbsolutelyPositionedStyle() && + !(bits & FCDATA_IS_TABLE_PART) && + !(bits & FCDATA_IS_SVG_TEXT); if (canHavePageBreak && display->mBreakBefore) { AddPageBreakItem(aContent, aStyleContext, aItems); } FrameConstructionItem* item = aItems.AppendItem(data, aContent, aTag, aNameSpaceID, pendingBinding, styleContext.forget(), @@ -5341,17 +5349,18 @@ nsCSSFrameConstructor::AddFrameConstruct bool isInline = // Table-internal things are inline-outside if and only if they're kids of // inlines, since they'll trigger construction of inline-table // pseudos. ((bits & FCDATA_IS_TABLE_PART) && (!aParentFrame || // No aParentFrame means inline aParentFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_INLINE)) || // Things that are inline-outside but aren't inline frames are inline - display->IsInlineOutside() || + (aParentFrame ? display->IsInlineOutside(aParentFrame) : + display->IsInlineOutsideStyle()) || // Popups that are certainly out of flow. isPopup; // Set mIsAllInline conservatively. It just might be that even an inline // that has mIsAllInline false doesn't need an {ib} split. So this is just // an optimization to keep from doing too much work in cases when we can // show that mIsAllInline is true.. item->mIsAllInline = item->mHasInlineEnds = isInline || @@ -5371,18 +5380,20 @@ nsCSSFrameConstructor::AddFrameConstruct (!(bits & FCDATA_DISALLOW_OUT_OF_FLOW) && aState.GetGeometricParent(display, nullptr)); // Set mIsBlock conservatively. It's OK to set it false for some real // blocks, but not OK to set it true for things that aren't blocks. Since // isOutOfFlow might be false even in cases when the frame will end up // out-of-flow, we can't use it here. But we _can_ say that the frame will // for sure end up in-flow if it's not floated or absolutely positioned. - item->mIsBlock = - !isInline && !display->IsAbsolutelyPositioned() && !display->IsFloating(); + item->mIsBlock = !isInline && + !display->IsAbsolutelyPositionedStyle() && + !display->IsFloatingStyle() && + !(bits & FCDATA_IS_SVG_TEXT); } if (item->mIsAllInline) { aItems.InlineItemAdded(); } else if (item->mIsBlock) { aItems.BlockItemAdded(); } @@ -5591,18 +5602,17 @@ nsCSSFrameConstructor::GetAbsoluteContai } // If the frame is positioned, we will probably return it as the containing // block (see the exceptions below). Otherwise, we'll start looking at the // parent frame, unless we're dealing with a scrollframe. // Scrollframes are special since they're not positioned, but their // scrolledframe might be. So, we need to check this special case to return // the correct containing block (the scrolledframe) in that case. - const nsStyleDisplay* disp = frame->GetStyleDisplay(); - if (!disp->IsPositioned()) { + if (!frame->IsPositioned()) { continue; } nsIFrame* absPosCBCandidate = nullptr; if (frame->GetType() == nsGkAtoms::scrollFrame) { nsIScrollableFrame* scrollFrame = do_QueryFrame(frame); absPosCBCandidate = scrollFrame->GetScrolledFrame(); } else { // Only first continuations can be containing blocks. @@ -5768,17 +5778,17 @@ nsCSSFrameConstructor::AppendFramesToPar if (!nextSibling && IsFrameSpecial(aParentFrame)) { // When we get here, our frame list might start with a block. If it does // so, and aParentFrame is an inline, and it and all its previous // continuations have no siblings, then put the initial blocks from the // frame list into the previous block of the {ib} split. Note that we // didn't want to stop at the block part of the split when figuring out // initial parent, because that could screw up float parenting; it's easier // to do this little fixup here instead. - if (aFrameList.NotEmpty() && !IsInlineOutside(aFrameList.FirstChild())) { + if (aFrameList.NotEmpty() && !aFrameList.FirstChild()->IsInlineOutside()) { // See whether our trailing inline is empty nsIFrame* firstContinuation = aParentFrame->GetFirstContinuation(); if (firstContinuation->PrincipalChildList().IsEmpty()) { // Our trailing inline is empty. Collect our starting blocks from // aFrameList, get the right parent frame for them, and put them in. nsFrameList::FrameLinkEnumerator firstNonBlockEnumerator = FindFirstNonBlock(aFrameList); nsFrameList blockKids = aFrameList.ExtractHead(firstNonBlockEnumerator); @@ -5799,18 +5809,19 @@ nsCSSFrameConstructor::AppendFramesToPar nsFrameList inlineKids = aFrameList.ExtractHead(firstBlockEnumerator); if (!inlineKids.IsEmpty()) { AppendFrames(aParentFrame, kPrincipalList, inlineKids); } if (!aFrameList.IsEmpty()) { const nsStyleDisplay* parentDisplay = aParentFrame->GetStyleDisplay(); bool positioned = - parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE || - parentDisplay->HasTransform(); + (parentDisplay->mPosition == NS_STYLE_POSITION_RELATIVE || + parentDisplay->HasTransform()) && + !aParentFrame->IsSVGText(); nsFrameItems ibSiblings; CreateIBSiblings(aState, aParentFrame, positioned, aFrameList, ibSiblings); // Make sure to trigger reflow of the inline that used to be our // last one and now isn't anymore, since its GetSkipSides() has // changed. mPresShell->FrameNeedsReflow(aParentFrame, @@ -5846,18 +5857,18 @@ nsCSSFrameConstructor::IsValidSibling(ns nsIAtom* grandparentType = nullptr; if (parentFrame) { parentType = parentFrame->GetType(); nsIFrame* grandparentFrame = parentFrame->GetParent(); if (grandparentFrame) { grandparentType = grandparentFrame->GetType(); } } - - PRUint8 siblingDisplay = aSibling->GetStyleDisplay()->mDisplay; + + PRUint8 siblingDisplay = aSibling->GetDisplay(); if ((NS_STYLE_DISPLAY_TABLE_COLUMN_GROUP == siblingDisplay) || (NS_STYLE_DISPLAY_TABLE_COLUMN == siblingDisplay) || (NS_STYLE_DISPLAY_TABLE_CAPTION == siblingDisplay) || (NS_STYLE_DISPLAY_TABLE_HEADER_GROUP == siblingDisplay) || (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == siblingDisplay) || (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == siblingDisplay) || nsGkAtoms::menuFrame == parentType) { // if we haven't already, construct a style context to find the display type of aContent @@ -6676,21 +6687,21 @@ nsCSSFrameConstructor::ContentAppended(n LAYOUT_PHASE_TEMP_REENTER(); // If the parent is a block frame, and we're not in a special case // where frames can be moved around, determine if the list is for the // start or end of the block. if (nsLayoutUtils::GetAsBlock(parentFrame) && !haveFirstLetterStyle && !haveFirstLineStyle && !parentSpecial) { items.SetLineBoundaryAtStart(!prevSibling || - !prevSibling->GetStyleDisplay()->IsInlineOutside() || + !prevSibling->IsInlineOutside() || prevSibling->GetType() == nsGkAtoms::brFrame); // :after content can't be <br> so no need to check it items.SetLineBoundaryAtEnd(!parentAfterFrame || - !parentAfterFrame->GetStyleDisplay()->IsInlineOutside()); + !parentAfterFrame->IsInlineOutside()); } // To suppress whitespace-only text frames, we have to verify that // our container's DOM child list matches its flattened tree child list. // This is guaranteed to be true if GetXBLChildNodesFor() returns null. items.SetParentHasNoXBLChildren(haveNoXBLChildren); nsFrameItems frameItems; ConstructFramesFromItemList(state, items, parentFrame, frameItems); @@ -7056,25 +7067,25 @@ nsCSSFrameConstructor::ContentRangeInser nsIFrame* containingBlock = state.mFloatedItems.containingBlock; bool haveFirstLetterStyle = false; bool haveFirstLineStyle = false; // In order to shave off some cycles, we only dig up the // containing block haveFirst* flags if the parent frame where // the insertion/append is occurring is an inline or block // container. For other types of containers this isn't relevant. - const nsStyleDisplay* parentDisplay = parentFrame->GetStyleDisplay(); + PRUint8 parentDisplay = parentFrame->GetDisplay(); // Examine the parentFrame where the insertion is taking // place. If it's a certain kind of container then some special // processing is done. - if ((NS_STYLE_DISPLAY_BLOCK == parentDisplay->mDisplay) || - (NS_STYLE_DISPLAY_LIST_ITEM == parentDisplay->mDisplay) || - (NS_STYLE_DISPLAY_INLINE == parentDisplay->mDisplay) || - (NS_STYLE_DISPLAY_INLINE_BLOCK == parentDisplay->mDisplay)) { + if ((NS_STYLE_DISPLAY_BLOCK == parentDisplay) || + (NS_STYLE_DISPLAY_LIST_ITEM == parentDisplay) || + (NS_STYLE_DISPLAY_INLINE == parentDisplay) || + (NS_STYLE_DISPLAY_INLINE_BLOCK == parentDisplay)) { // Recover the special style flags for the containing block if (containingBlock) { haveFirstLetterStyle = HasFirstLetterStyle(containingBlock); haveFirstLineStyle = ShouldHaveFirstLineStyle(containingBlock->GetContent(), containingBlock->GetStyleContext()); } @@ -9700,17 +9711,17 @@ nsCSSFrameConstructor::CreateNeededTable true); // Here we're cheating a tad... technically, table-internal items should be // inline if aParentFrame is inline, but they'll get wrapped in an // inline-table in the end, so it'll all work out. In any case, arguably // we don't need to maintain this state at this point... but it's better // to, I guess. newItem->mIsAllInline = newItem->mHasInlineEnds = - newItem->mStyleContext->GetStyleDisplay()->IsInlineOutside(); + newItem->mStyleContext->GetStyleDisplay()->IsInlineOutsideStyle(); // Table pseudo frames always induce line boundaries around their // contents. newItem->mChildItems.SetLineBoundaryAtStart(true); newItem->mChildItems.SetLineBoundaryAtEnd(true); // The parent of the items in aItems is also the parent of the items // in mChildItems newItem->mChildItems.SetParentHasNoXBLChildren( @@ -9985,17 +9996,17 @@ nsCSSFrameConstructor::WrapFramesInFirst nsIFrame* aBlockFrame, nsIFrame* aLineFrame, nsFrameItems& aFrameItems) { nsresult rv = NS_OK; // Find the part of aFrameItems that we want to put in the first-line nsFrameList::FrameLinkEnumerator link(aFrameItems); - while (!link.AtEnd() && IsInlineOutside(link.NextFrame())) { + while (!link.AtEnd() && link.NextFrame()->IsInlineOutside()) { link.Next(); } nsFrameList firstLineChildren = aFrameItems.ExtractHead(link); if (firstLineChildren.IsEmpty()) { // Nothing is supposed to go into the first-line; nothing to do return NS_OK; @@ -10422,17 +10433,17 @@ nsCSSFrameConstructor::CreateLetterFrame NS_ASSERTION(aBlockContinuation == GetFloatContainingBlock(aParentFrame), "Containing block is confused"); nsFrameConstructorState state(mPresShell, mFixedContainingBlock, GetAbsoluteContainingBlock(aParentFrame), aBlockContinuation); // Create the right type of first-letter frame const nsStyleDisplay* display = sc->GetStyleDisplay(); - if (display->IsFloating()) { + if (display->IsFloating(aParentFrame)) { // Make a floating first-letter frame CreateFloatingLetterFrame(state, aBlockFrame, aTextContent, textFrame, blockContent, aParentFrame, sc, aResult); } else { // Make an inflow first-letter frame nsIFrame* letterFrame = NS_NewFirstLetterFrame(mPresShell, sc); @@ -11017,17 +11028,18 @@ nsCSSFrameConstructor::ConstructInline(n // Text("f") nsIContent* const content = aItem.mContent; nsStyleContext* const styleContext = aItem.mStyleContext; bool positioned = NS_STYLE_DISPLAY_INLINE == aDisplay->mDisplay && (NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition || - aDisplay->HasTransform()); + aDisplay->HasTransform()) && + !aParentFrame->IsSVGText(); nsIFrame* newFrame = NS_NewInlineFrame(mPresShell, styleContext); if (!newFrame) { return NS_ERROR_OUT_OF_MEMORY; } // Initialize the frame InitAndRestoreFrame(aState, content, aParentFrame, nullptr, newFrame); @@ -11117,17 +11129,17 @@ nsCSSFrameConstructor::CreateIBSiblings( nsCSSAnonBoxes::mozAnonymousBlock, styleContext); nsIFrame* lastNewInline = aInitialInline->GetFirstContinuation(); do { // On entry to this loop aChildItems is not empty and the first frame in it // is block-level. NS_PRECONDITION(aChildItems.NotEmpty(), "Should have child items"); - NS_PRECONDITION(!IsInlineOutside(aChildItems.FirstChild()), + NS_PRECONDITION(!aChildItems.FirstChild()->IsInlineOutside(), "Must have list starting with block"); // The initial run of blocks belongs to an anonymous block that we create // right now. The anonymous block will be the parent of these block // children of the inline. nsIFrame* blockFrame; blockFrame = NS_NewBlockFrame(mPresShell, blockSC); @@ -11568,17 +11580,17 @@ nsCSSFrameConstructor::WipeContainingBlo // 3) Not an inline frame // We're guaranteed to find one, since nsStyleContext::ApplyStyleFixups // enforces that the root is display:none, display:table, or display:block. // Note that walking up "too far" is OK in terms of correctness, even if it // might be a little inefficient. This is why we walk out of all // pseudo-frames -- telling which ones are or are not OK to walk out of is // too hard (and I suspect that we do in fact need to walk out of all of // them). - while (IsFrameSpecial(aContainingBlock) || IsInlineOutside(aContainingBlock) || + while (IsFrameSpecial(aContainingBlock) || aContainingBlock->IsInlineOutside() || aContainingBlock->GetStyleContext()->GetPseudo()) { aContainingBlock = aContainingBlock->GetParent(); NS_ASSERTION(aContainingBlock, "Must have non-inline, non-special, non-pseudo frame as root " "(or child of root, for a table root)!"); } // Tell parent of the containing block to reformulate the
--- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -690,16 +690,19 @@ private: would have been scrollable but has been forced to be non-scrollable due to being in a paginated context. */ #define FCDATA_FORCED_NON_SCROLLABLE_BLOCK 0x20000 /* If FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a block formatting context wrapper around the kids of this frame using the FrameConstructionData's mPseudoAtom for its anonymous box type. */ #define FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS 0x40000 + /* If FCDATA_IS_SVG_TEXT is set, then this text frame is a descendant of + an SVG text frame. */ +#define FCDATA_IS_SVG_TEXT 0x80000 /* Structure representing information about how a frame should be constructed. */ struct FrameConstructionData { // Flag bits that can modify the way the construction happens PRUint32 mBits; // We have exactly one of three types of functions, so use a union for // better cache locality for the ones that aren't pointer-to-member. That @@ -1368,17 +1371,17 @@ private: PRInt32 aNameSpaceID, nsIFrame* aParentFrame, nsStyleContext* aStyleContext); /* Not static because it does PropagateScrollToViewport. If this changes, make this static */ const FrameConstructionData* FindDisplayData(const nsStyleDisplay* aDisplay, Element* aElement, - nsStyleContext* aStyleContext); + nsIFrame* aParentFrame, nsStyleContext* aStyleContext); /** * Construct a scrollable block frame */ nsresult ConstructScrollableBlock(nsFrameConstructorState& aState, FrameConstructionItem& aItem, nsIFrame* aParentFrame, const nsStyleDisplay* aDisplay,
--- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -416,17 +416,17 @@ nsLayoutUtils::GetChildListNameFor(nsIFr // XXX FIXME: Bug 350740 // Return here, because the postcondition for this function actually // fails for this case, since the popups are not in a "real" frame list // in the popup set. return nsIFrame::kPopupList; #endif // MOZ_XUL } else { - NS_ASSERTION(aChildFrame->GetStyleDisplay()->IsFloating(), + NS_ASSERTION(aChildFrame->IsFloating(), "not a floated frame"); id = nsIFrame::kFloatList; } } else { nsIAtom* childType = aChildFrame->GetType(); if (nsGkAtoms::menuPopupFrame == childType) { nsIFrame* parent = aChildFrame->GetParent(); @@ -452,17 +452,17 @@ nsLayoutUtils::GetChildListNameFor(nsIFr // corresponding overflow list. nsIFrame* parent = aChildFrame->GetParent(); bool found = parent->GetChildList(id).ContainsFrame(aChildFrame); if (!found) { if (!(aChildFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { found = parent->GetChildList(nsIFrame::kOverflowList) .ContainsFrame(aChildFrame); } - else if (aChildFrame->GetStyleDisplay()->IsFloating()) { + else if (aChildFrame->IsFloating()) { found = parent->GetChildList(nsIFrame::kOverflowOutOfFlowList) .ContainsFrame(aChildFrame); } // else it's positioned and should have been on the 'id' child list. NS_POSTCONDITION(found, "not in child list"); } #endif @@ -530,17 +530,17 @@ nsLayoutUtils::GetStyleFrame(nsIFrame* a nsIFrame* nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) { NS_ASSERTION(nsGkAtoms::placeholderFrame == aFrame->GetType(), "Must have a placeholder here"); if (aFrame->GetStateBits() & PLACEHOLDER_FOR_FLOAT) { nsIFrame *outOfFlowFrame = nsPlaceholderFrame::GetRealFrameForPlaceholder(aFrame); - NS_ASSERTION(outOfFlowFrame->GetStyleDisplay()->IsFloating(), + NS_ASSERTION(outOfFlowFrame->IsFloating(), "How did that happen?"); return outOfFlowFrame; } return nullptr; } // static @@ -1883,17 +1883,17 @@ nsLayoutUtils::PaintFrame(nsRenderingCon // Flush the list so we don't trigger the IsEmpty-on-destruction assertion list.DeleteAll(); return NS_OK; } PRInt32 nsLayoutUtils::GetZIndex(nsIFrame* aFrame) { - if (!aFrame->GetStyleDisplay()->IsPositioned()) + if (!aFrame->IsPositioned()) return 0; const nsStylePosition* position = aFrame->GetStylePosition(); if (position->mZIndex.GetUnit() == eStyleUnit_Integer) return position->mZIndex.GetIntValue(); // sort the auto and 0 elements together @@ -3440,17 +3440,17 @@ nsLayoutUtils::CalculateContentBottom(ns return contentBottom; } /* static */ nsIFrame* nsLayoutUtils::GetClosestLayer(nsIFrame* aFrame) { nsIFrame* layer; for (layer = aFrame; layer; layer = layer->GetParent()) { - if (layer->GetStyleDisplay()->IsPositioned() || + if (layer->IsPositioned() || (layer->GetParent() && layer->GetParent()->GetType() == nsGkAtoms::scrollFrame)) break; } if (layer) return layer; return aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame(); } @@ -4049,31 +4049,23 @@ nsLayoutUtils::GetDisplayRootFrame(nsIFr return f; nsIFrame* parent = GetCrossDocParentFrame(f); if (!parent) return f; f = parent; } } -static bool -IsNonzeroCoord(const nsStyleCoord& aCoord) -{ - if (eStyleUnit_Coord == aCoord.GetUnit()) - return aCoord.GetCoordValue() != 0; - return false; -} - /* static */ PRUint32 nsLayoutUtils::GetTextRunFlagsForStyle(nsStyleContext* aStyleContext, - const nsStyleText* aStyleText, - const nsStyleFont* aStyleFont) + const nsStyleFont* aStyleFont, + nscoord aLetterSpacing) { PRUint32 result = 0; - if (IsNonzeroCoord(aStyleText->mLetterSpacing)) { + if (aLetterSpacing != 0) { result |= gfxTextRunFactory::TEXT_DISABLE_OPTIONAL_LIGATURES; } switch (aStyleContext->GetStyleSVG()->mTextRendering) { case NS_STYLE_TEXT_RENDERING_OPTIMIZESPEED: result |= gfxTextRunFactory::TEXT_OPTIMIZE_SPEED; break; case NS_STYLE_TEXT_RENDERING_AUTO: if (aStyleFont->mFont.size <
--- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1306,18 +1306,18 @@ public: /** * Get textrun construction flags determined by a given style; in particular * some combination of: * -- TEXT_DISABLE_OPTIONAL_LIGATURES if letter-spacing is in use * -- TEXT_OPTIMIZE_SPEED if the text-rendering CSS property and font size * and prefs indicate we should be optimizing for speed over quality */ static PRUint32 GetTextRunFlagsForStyle(nsStyleContext* aStyleContext, - const nsStyleText* aStyleText, - const nsStyleFont* aStyleFont); + const nsStyleFont* aStyleFont, + nscoord aLetterSpacing); /** * Takes two rectangles whose origins must be the same, and computes * the difference between their union and their intersection as two * rectangles. (This difference is a superset of the difference * between the two rectangles.) */ static void GetRectDifferenceStrips(const nsRect& aR1, const nsRect& aR2,
--- a/layout/forms/nsLegendFrame.cpp +++ b/layout/forms/nsLegendFrame.cpp @@ -12,17 +12,17 @@ #include "nsStyleConsts.h" #include "nsFormControlFrame.h" nsIFrame* NS_NewLegendFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { #ifdef DEBUG const nsStyleDisplay* disp = aContext->GetStyleDisplay(); - NS_ASSERTION(!disp->IsAbsolutelyPositioned() && !disp->IsFloating(), + NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle() && !disp->IsFloatingStyle(), "Legends should not be positioned and should not float"); #endif nsIFrame* f = new (aPresShell) nsLegendFrame(aContext); if (f) { f->AddStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); } return f;
--- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -12,16 +12,17 @@ #include "nsContentUtils.h" #include "nsGfxScrollFrame.h" #include "nsIScrollableFrame.h" #include "nsLayoutUtils.h" #include "nsPresContext.h" #include "nsRect.h" #include "nsRenderingContext.h" #include "nsTextFrame.h" +#include "nsStyleStructInlines.h" #include "mozilla/Util.h" namespace mozilla { namespace css { static const PRUnichar kEllipsisChar[] = { 0x2026, 0x0 }; static const PRUnichar kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 }; @@ -48,17 +49,17 @@ GetSelfOrNearestBlock(nsIFrame* aFrame) // Return true if the frame is an atomic inline-level element. // It's not supposed to be called for block frames since we never // process block descendants for text-overflow. static bool IsAtomicElement(nsIFrame* aFrame, const nsIAtom* aFrameType) { NS_PRECONDITION(!nsLayoutUtils::GetAsBlock(aFrame) || - !aFrame->GetStyleDisplay()->IsBlockOutside(), + !aFrame->IsBlockOutside(), "unexpected block frame"); NS_PRECONDITION(aFrameType != nsGkAtoms::placeholderFrame, "unexpected placeholder frame"); return !aFrame->IsFrameOfType(nsIFrame::eLineParticipant); } static bool IsFullyClipped(nsTextFrame* aFrame, nscoord aLeft, nscoord aRight,
--- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -48,16 +48,17 @@ #include "nsDisplayList.h" #include "nsContentErrors.h" #include "nsCSSAnonBoxes.h" #include "nsCSSFrameConstructor.h" #include "nsCSSRendering.h" #include "FrameLayerBuilder.h" #include "nsRenderingContext.h" #include "TextOverflow.h" +#include "nsStyleStructInlines.h" #include "mozilla/Util.h" // for DebugOnly #ifdef IBMBIDI #include "nsBidiPresUtils.h" #endif // IBMBIDI #include "nsIDOMHTMLBodyElement.h" #include "nsIDOMHTMLHtmlElement.h" @@ -1570,21 +1571,24 @@ nsBlockFrame::MarkLineDirty(line_iterato #endif } } /** * Test whether lines are certain to be aligned left so that we can make * resizing optimizations */ -bool static inline IsAlignedLeft(const PRUint8 aAlignment, - const PRUint8 aDirection, - const PRUint8 aUnicodeBidi) -{ - return (NS_STYLE_TEXT_ALIGN_LEFT == aAlignment || +static inline bool +IsAlignedLeft(PRUint8 aAlignment, + PRUint8 aDirection, + PRUint8 aUnicodeBidi, + nsIFrame* aFrame) +{ + return (aFrame->IsSVGText() || + NS_STYLE_TEXT_ALIGN_LEFT == aAlignment || ((NS_STYLE_TEXT_ALIGN_DEFAULT == aAlignment && NS_STYLE_DIRECTION_LTR == aDirection) || (NS_STYLE_TEXT_ALIGN_END == aAlignment && NS_STYLE_DIRECTION_RTL == aDirection)) && !(NS_STYLE_UNICODE_BIDI_PLAINTEXT & aUnicodeBidi)); } nsresult @@ -1592,17 +1596,18 @@ nsBlockFrame::PrepareResizeReflow(nsBloc { const nsStyleText* styleText = GetStyleText(); const nsStyleTextReset* styleTextReset = GetStyleTextReset(); // See if we can try and avoid marking all the lines as dirty bool tryAndSkipLines = // The text must be left-aligned. IsAlignedLeft(styleText->mTextAlign, aState.mReflowState.mStyleVisibility->mDirection, - styleTextReset->mUnicodeBidi) && + styleTextReset->mUnicodeBidi, + this) && // The left content-edge must be a constant distance from the left // border-edge. !GetStylePadding()->mPadding.GetLeft().HasPercent(); #ifdef DEBUG if (gDisableResizeOpt) { tryAndSkipLines = false; } @@ -1631,17 +1636,18 @@ nsBlockFrame::PrepareResizeReflow(nsBloc printf(": trying to avoid marking all lines dirty\n"); } #endif // The last line might not be aligned left even if the rest of the block is bool skipLastLine = NS_STYLE_TEXT_ALIGN_AUTO == styleText->mTextAlignLast || IsAlignedLeft(styleText->mTextAlignLast, aState.mReflowState.mStyleVisibility->mDirection, - styleTextReset->mUnicodeBidi); + styleTextReset->mUnicodeBidi, + this); for (line_iterator line = begin_lines(), line_end = end_lines(); line != line_end; ++line) { // We let child blocks make their own decisions the same // way we are here. bool isLastLine = line == mLines.back() && !GetNextInFlow(); @@ -2626,17 +2632,17 @@ nsBlockFrame::PullFrameFrom(nsBlockReflo nsFrameList& aFromFrameList, nsLineList::iterator aFromLine) { nsLineBox* fromLine = aFromLine; NS_ABORT_IF_FALSE(fromLine, "bad line to pull from"); NS_ABORT_IF_FALSE(fromLine->GetChildCount(), "empty line"); NS_ABORT_IF_FALSE(aLine->GetChildCount(), "empty line"); - NS_ASSERTION(fromLine->IsBlock() == fromLine->mFirstChild->GetStyleDisplay()->IsBlockOutside(), + NS_ASSERTION(fromLine->IsBlock() == fromLine->mFirstChild->IsBlockOutside(), "Disagreement about whether it's a block or not"); if (fromLine->IsBlock()) { // If our line is not empty and the child in aFromLine is a block // then we cannot pull up the frame into this line. In this case // we stop pulling. return nullptr; } @@ -4243,25 +4249,27 @@ nsBlockFrame::PlaceLine(nsBlockReflowSta // Only block frames horizontally align their children because // inline frames "shrink-wrap" around their children (therefore // there is no extra horizontal space). const nsStyleText* styleText = GetStyleText(); /** * text-align-last defaults to the same value as text-align when - * text-align-last is set to auto (unless when text-align is set to justify), + * text-align-last is set to auto (except when text-align is set to justify), * so in that case we don't need to set isLastLine. * * In other words, isLastLine really means isLastLineAndWeCare. */ - bool isLastLine = ((NS_STYLE_TEXT_ALIGN_AUTO != styleText->mTextAlignLast || - NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign) && - (aLineLayout.GetLineEndsInBR() || - IsLastLine(aState, aLine))); + bool isLastLine = + !IsSVGText() && + ((NS_STYLE_TEXT_ALIGN_AUTO != styleText->mTextAlignLast || + NS_STYLE_TEXT_ALIGN_JUSTIFY == styleText->mTextAlign) && + (aLineLayout.GetLineEndsInBR() || + IsLastLine(aState, aLine))); aLineLayout.HorizontalAlignFrames(aLine->mBounds, isLastLine); // XXX: not only bidi: right alignment can be broken after // RelativePositionFrames!!! // XXXldb Is something here considering relatively positioned frames at // other than their original positions? #ifdef IBMBIDI // XXXldb Why don't we do this earlier? if (aState.mPresContext->BidiEnabled()) { @@ -4943,21 +4951,21 @@ nsBlockFrame::AddFrames(nsFrameList& aFr // Walk through the new frames being added and update the line data // structures to fit. for (nsFrameList::Enumerator e(newFrames); !e.AtEnd(); e.Next()) { nsIFrame* newFrame = e.get(); NS_ASSERTION(!aPrevSibling || aPrevSibling->GetNextSibling() == newFrame, "Unexpected aPrevSibling"); NS_ASSERTION(newFrame->GetType() != nsGkAtoms::placeholderFrame || - (!newFrame->GetStyleDisplay()->IsAbsolutelyPositioned() && - !newFrame->GetStyleDisplay()->IsFloating()), + (!newFrame->IsAbsolutelyPositioned() && + !newFrame->IsFloating()), "Placeholders should not float or be positioned"); - bool isBlock = newFrame->GetStyleDisplay()->IsBlockOutside(); + bool isBlock = newFrame->IsBlockOutside(); // If the frame is a block frame, or if there is no previous line or if the // previous line is a block line we need to make a new line. We also make // a new line, as an optimization, in the two cases we know we'll need it: // if the previous line ended with a <br>, or if it has significant whitespace // and ended in a newline. if (isBlock || prevSibLine == lineList->end() || prevSibLine->IsBlock() || (aPrevSibling && ShouldPutNextSiblingOnNewLine(aPrevSibling))) { @@ -5120,18 +5128,17 @@ nsBlockFrame::RemoveFrame(ChildListID aL void nsBlockFrame::DoRemoveOutOfFlowFrame(nsIFrame* aFrame) { // The containing block is always the parent of aFrame. nsBlockFrame* block = (nsBlockFrame*)aFrame->GetParent(); // Remove aFrame from the appropriate list. - const nsStyleDisplay* display = aFrame->GetStyleDisplay(); - if (display->IsAbsolutelyPositioned()) { + if (aFrame->IsAbsolutelyPositioned()) { // This also deletes the next-in-flows block->GetAbsoluteContainingBlock()->RemoveFrame(block, kAbsoluteList, aFrame); } else { // First remove aFrame's next-in-flows nsIFrame* nif = aFrame->GetNextInFlow(); @@ -5631,17 +5638,17 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aD nsresult nsBlockFrame::StealFrame(nsPresContext* aPresContext, nsIFrame* aChild, bool aForceNormal) { NS_PRECONDITION(aPresContext && aChild, "null pointer"); if ((aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && - aChild->GetStyleDisplay()->IsFloating()) { + aChild->IsFloating()) { bool removed = mFloats.RemoveFrameIfPresent(aChild); if (!removed) { nsFrameList* list = GetPushedFloats(); if (list) { removed = list->RemoveFrameIfPresent(aChild); } } return removed ? NS_OK : NS_ERROR_UNEXPECTED; @@ -6467,17 +6474,17 @@ nsLineBox* nsBlockFrame::GetFirstLineCon return cursor.get(); } /* virtual */ void nsBlockFrame::ChildIsDirty(nsIFrame* aChild) { // See if the child is absolutely positioned if (aChild->GetStateBits() & NS_FRAME_OUT_OF_FLOW && - aChild->GetStyleDisplay()->IsAbsolutelyPositioned()) { + aChild->IsAbsolutelyPositioned()) { // do nothing } else if (aChild == GetOutsideBullet()) { // The bullet lives in the first line, unless the first line has // height 0 and there is a second line, in which case it lives // in the second line. line_iterator bulletLine = begin_lines(); if (bulletLine != end_lines() && bulletLine->mBounds.height == 0 && bulletLine != mLines.back()) { @@ -6559,17 +6566,18 @@ nsBlockFrame::SetInitialChildList(ChildL // block. nsIAtom *pseudo = GetStyleContext()->GetPseudo(); bool haveFirstLetterStyle = (!pseudo || (pseudo == nsCSSAnonBoxes::cellContent && mParent->GetStyleContext()->GetPseudo() == nullptr) || pseudo == nsCSSAnonBoxes::fieldsetContent || pseudo == nsCSSAnonBoxes::scrolledContent || - pseudo == nsCSSAnonBoxes::columnContent) && + pseudo == nsCSSAnonBoxes::columnContent || + pseudo == nsCSSAnonBoxes::mozSVGText) && !IsFrameOfType(eMathML) && nsRefPtr<nsStyleContext>(GetFirstLetterStyle(presContext)) != nullptr; NS_ASSERTION(haveFirstLetterStyle == ((mState & NS_BLOCK_HAS_FIRST_LETTER_STYLE) != 0), "NS_BLOCK_HAS_FIRST_LETTER_STYLE state out of sync"); #endif rv = AddFrames(aChildList, nullptr);
--- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -769,17 +769,17 @@ nsContainerFrame::SyncFrameViewPropertie // See if the view should be hidden or visible vm->SetViewVisibility(aView, aStyleContext->GetStyleVisibility()->IsVisible() ? nsViewVisibility_kShow : nsViewVisibility_kHide); } // See if the frame is being relatively positioned or absolutely // positioned - bool isPositioned = aStyleContext->GetStyleDisplay()->IsPositioned(); + bool isPositioned = aFrame->IsPositioned(); PRInt32 zIndex = 0; bool autoZIndex = false; if (!isPositioned) { autoZIndex = true; } else { // Make sure z-index is correct
--- a/layout/generic/nsContainerFrame.h +++ b/layout/generic/nsContainerFrame.h @@ -510,17 +510,17 @@ protected: * in nsAbsoluteContainingBlock and pretend the continuation is an overflow * container. This isn't an ideal solution, but it lets us print the content * at least. See bug 154892. */ #define IS_TRUE_OVERFLOW_CONTAINER(frame) \ ( (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) \ && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && \ - frame->GetStyleDisplay()->IsAbsolutelyPositioned() ) ) + frame->IsAbsolutelyPositioned() ) ) //XXXfr This check isn't quite correct, because it doesn't handle cases // where the out-of-flow has overflow.. but that's rare. // We'll need to revisit the way abspos continuations are handled later // for various reasons, this detail is one of them. See bug 154892 /** * Helper class for tracking overflow container continuations during reflow. *
--- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -440,18 +440,18 @@ IsFontSizeInflationContainer(nsIFrame* a */ // The root frame should always be an inflation container. if (!aFrame->GetParent()) { return true; } nsIContent *content = aFrame->GetContent(); - bool isInline = (aStyleDisplay->mDisplay == NS_STYLE_DISPLAY_INLINE || - (aStyleDisplay->IsFloating() && + bool isInline = (aFrame->GetDisplay() == NS_STYLE_DISPLAY_INLINE || + (aFrame->IsFloating() && aFrame->GetType() == nsGkAtoms::letterFrame) || // Given multiple frames for the same node, only the // outer one should be considered a container. // (Important, e.g., for nsSelectsAreaFrame.) (aFrame->GetParent()->GetContent() == content) || (content && (content->IsHTML(nsGkAtoms::option) || content->IsHTML(nsGkAtoms::optgroup) || content->IsInNativeAnonymousSubtree()))) && @@ -496,17 +496,18 @@ nsFrame::Init(nsIContent* aContent, NS_FRAME_MAY_BE_TRANSFORMED | NS_FRAME_MAY_HAVE_GENERATED_CONTENT); } if (mParent) { nsFrameState state = mParent->GetStateBits(); // Make bits that are currently off (see constructor) the same: mState |= state & (NS_FRAME_INDEPENDENT_SELECTION | - NS_FRAME_GENERATED_CONTENT); + NS_FRAME_GENERATED_CONTENT | + NS_FRAME_IS_SVG_TEXT); } const nsStyleDisplay *disp = GetStyleDisplay(); if (disp->HasTransform()) { // The frame gets reconstructed if we toggle the -moz-transform // property, so we can set this bit here and then ignore it. mState |= NS_FRAME_MAY_BE_TRANSFORMED; } @@ -516,17 +517,17 @@ nsFrame::Init(nsIContent* aContent, // font size inflation is not enabled. || true #endif ) { if (IsFontSizeInflationContainer(this, disp)) { AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER); if (!GetParent() || // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet. - disp->IsFloating() || disp->IsAbsolutelyPositioned()) { + disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) { AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); } } NS_ASSERTION(GetParent() || (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER), "root frame should always be a container"); } @@ -806,17 +807,18 @@ const nsIFrame::ChildListID nsIFrame::kS const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList; #endif /* virtual */ nsMargin nsIFrame::GetUsedMargin() const { nsMargin margin(0, 0, 0, 0); if ((mState & NS_FRAME_FIRST_REFLOW) && - !(mState & NS_FRAME_IN_REFLOW)) + !(mState & NS_FRAME_IN_REFLOW) || + (mState & NS_FRAME_IS_SVG_TEXT)) return margin; nsMargin *m = static_cast<nsMargin*> (Properties().Get(UsedMarginProperty())); if (m) { margin = *m; } else { #ifdef DEBUG @@ -828,17 +830,18 @@ nsIFrame::GetUsedMargin() const return margin; } /* virtual */ nsMargin nsIFrame::GetUsedBorder() const { nsMargin border(0, 0, 0, 0); if ((mState & NS_FRAME_FIRST_REFLOW) && - !(mState & NS_FRAME_IN_REFLOW)) + !(mState & NS_FRAME_IN_REFLOW) || + (mState & NS_FRAME_IS_SVG_TEXT)) return border; // Theme methods don't use const-ness. nsIFrame *mutable_this = const_cast<nsIFrame*>(this); const nsStyleDisplay *disp = GetStyleDisplay(); if (mutable_this->IsThemed(disp)) { nsIntMargin result; @@ -863,17 +866,18 @@ nsIFrame::GetUsedBorder() const return border; } /* virtual */ nsMargin nsIFrame::GetUsedPadding() const { nsMargin padding(0, 0, 0, 0); if ((mState & NS_FRAME_FIRST_REFLOW) && - !(mState & NS_FRAME_IN_REFLOW)) + !(mState & NS_FRAME_IN_REFLOW) || + (mState & NS_FRAME_IS_SVG_TEXT)) return padding; // Theme methods don't use const-ness. nsIFrame *mutable_this = const_cast<nsIFrame*>(this); const nsStyleDisplay *disp = GetStyleDisplay(); if (mutable_this->IsThemed(disp)) { nsPresContext *presContext = PresContext(); @@ -1487,17 +1491,17 @@ inline static bool IsSVGContentWithCSSCl bool nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp, nsRect* aRect, const nsSize& aSize) const { NS_PRECONDITION(aRect, "Must have aRect out parameter"); if (!(aDisp->mClipFlags & NS_STYLE_CLIP_RECT) || - !(aDisp->IsAbsolutelyPositioned() || IsSVGContentWithCSSClip(this))) { + !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) { return false; } *aRect = aDisp->mClip; if (NS_STYLE_CLIP_RIGHT_AUTO & aDisp->mClipFlags) { aRect->width = aSize.width - aRect->x; } if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) { @@ -2095,18 +2099,18 @@ nsIFrame::BuildDisplayListForChild(nsDis // Child is composited if it's transformed, partially transparent, or has // SVG effects. const nsStyleDisplay* disp = child->GetStyleDisplay(); bool isVisuallyAtomic = child->HasOpacity() || child->IsTransformed() || nsSVGIntegrationUtils::UsingEffectsForFrame(child); - bool isPositioned = !isSVG && disp->IsPositioned(); - if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating()) || + bool isPositioned = !isSVG && disp->IsPositioned(child); + if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) || ((disp->mClipFlags & NS_STYLE_CLIP_RECT) && IsSVGContentWithCSSClip(child)) || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) { // If you change this, also change IsPseudoStackingContextFromStyle() pseudoStackingContext = true; } // This controls later whether we build an nsDisplayWrapList or an @@ -2237,17 +2241,17 @@ nsIFrame::BuildDisplayListForChild(nsDis nsDisplayList fixedPosDescendantList; fixedPosDescendantList.AppendToTop(item); aLists.PositionedDescendants()->AppendNewToTop( new (aBuilder) nsDisplayFixedPosition(aBuilder, item->GetUnderlyingFrame(), child, &fixedPosDescendantList)); } } } - } else if (!isSVG && disp->IsFloating()) { + } else if (!isSVG && disp->IsFloating(child)) { if (!list.IsEmpty()) { rv = aLists.Floats()->AppendNewToTop(new (aBuilder) nsDisplayWrapList(aBuilder, child, &list)); NS_ENSURE_SUCCESS(rv, rv); } } else { aLists.Content()->AppendToTop(&list); } @@ -3464,17 +3468,17 @@ nsIFrame::ContentOffsets OffsetsForSingl offsets.secondaryOffset = range.end; offsets.associateWithNext = true; return offsets; } // Figure out whether the offsets should be over, after, or before the frame nsRect rect(nsPoint(0, 0), aFrame->GetSize()); - bool isBlock = (aFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE); + bool isBlock = aFrame->GetDisplay() != NS_STYLE_DISPLAY_INLINE; bool isRtl = (aFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL); if ((isBlock && rect.y < aPoint.y) || (!isBlock && ((isRtl && rect.x + rect.width / 2 > aPoint.x) || (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) { offsets.offset = range.end; if (rect.Contains(aPoint)) offsets.secondaryOffset = range.start; else @@ -5009,17 +5013,18 @@ ComputeOutlineAndEffectsRect(nsIFrame* a } return r; } nsPoint nsIFrame::GetRelativeOffset(const nsStyleDisplay* aDisplay) const { - if (!aDisplay || NS_STYLE_POSITION_RELATIVE == aDisplay->mPosition) { + if (!aDisplay || + aDisplay->IsRelativelyPositioned(this)) { nsPoint *offsets = static_cast<nsPoint*> (Properties().Get(ComputedOffsetProperty())); if (offsets) { return *offsets; } } return nsPoint(0,0); } @@ -5285,17 +5290,17 @@ GetNearestBlockContainer(nsIFrame* frame } nsIFrame* nsIFrame::GetContainingBlock() const { // MathML frames might have absolute positioning style, but they would // still be in-flow. So we have to check to make sure that the frame // is really out-of-flow too. - if (GetStyleDisplay()->IsAbsolutelyPositioned() && + if (IsAbsolutelyPositioned() && (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { return GetParent(); // the parent is always the containing block } return GetNearestBlockContainer(GetParent()); } #ifdef DEBUG @@ -7404,16 +7409,62 @@ nsIFrame::IsFocusable(PRInt32 *aTabIndex * should return false if this is not a text frame. */ bool nsIFrame::HasTerminalNewline() const { return false; } +static PRUint8 +ConvertSVGDominantBaselineToVerticalAlign(PRUint8 aDominantBaseline) +{ + switch (aDominantBaseline) { + case NS_STYLE_DOMINANT_BASELINE_HANGING: + case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE: + return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP; + case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE: + case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC: + return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM; + case NS_STYLE_DOMINANT_BASELINE_CENTRAL: + case NS_STYLE_DOMINANT_BASELINE_MIDDLE: + return NS_STYLE_VERTICAL_ALIGN_MIDDLE; + case NS_STYLE_DOMINANT_BASELINE_AUTO: + case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC: + return NS_STYLE_VERTICAL_ALIGN_BASELINE; + default: + NS_NOTREACHED("unexpected aDominantBaseline value"); + return NS_STYLE_VERTICAL_ALIGN_BASELINE; + } +} + +PRUint8 +nsIFrame::VerticalAlignEnum() const +{ + if (mState & NS_FRAME_IS_SVG_TEXT) { + PRUint8 dominantBaseline; + for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) { + dominantBaseline = frame->GetStyleSVGReset()->mDominantBaseline; + if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO || + frame->GetType() == nsGkAtoms::svgTextFrame) { + break; + } + } + return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline); + } + + const nsStyleCoord& verticalAlign = + GetStyleContext()->GetStyleTextReset()->mVerticalAlign; + if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) { + return verticalAlign.GetIntValue(); + } + + return eInvalidVerticalAlign; +} + /* static */ void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui, nsIFrame::Cursor& aCursor) { aCursor.mCursor = ui->mCursor; aCursor.mHaveHotspot = false; aCursor.mHotspotX = aCursor.mHotspotY = 0.0f; @@ -9308,19 +9359,19 @@ nsHTMLReflowState::DisplayInitFrameTypeE printf("InitFrameType"); const nsStyleDisplay *disp = aState->mStyleDisplay; if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) printf(" out-of-flow"); if (aFrame->GetPrevInFlow()) printf(" prev-in-flow"); - if (disp->IsAbsolutelyPositioned()) + if (aFrame->IsAbsolutelyPositioned()) printf(" abspos"); - if (disp->IsFloating()) + if (aFrame->IsFloating()) printf(" float"); // This array must exactly match the NS_STYLE_DISPLAY constants. const char *const displayTypes[] = { "none", "block", "inline", "inline-block", "list-item", "marker", "run-in", "compact", "table", "inline-table", "table-row-group", "table-column", "table-column-group", "table-header-group", "table-footer-group", "table-row", "table-cell", "table-caption",
--- a/layout/generic/nsFrameSetFrame.cpp +++ b/layout/generic/nsFrameSetFrame.cpp @@ -1511,17 +1511,17 @@ nsHTMLFramesetFrame::EndMouseDrag(nsPres gDragInProgress = false; } nsIFrame* NS_NewHTMLFramesetFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { #ifdef DEBUG const nsStyleDisplay* disp = aContext->GetStyleDisplay(); - NS_ASSERTION(!disp->IsAbsolutelyPositioned() && !disp->IsFloating(), + NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle() && !disp->IsFloatingStyle(), "Framesets should not be positioned and should not float"); #endif return new (aPresShell) nsHTMLFramesetFrame(aContext); } NS_IMPL_FRAMEARENA_HELPERS(nsHTMLFramesetFrame)
--- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2111,17 +2111,17 @@ void nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists, bool& aCreateLayer, bool aPositioned) { for (nsIFrame* kid = mOuter->GetFirstPrincipalChild(); kid; kid = kid->GetNextSibling()) { if (kid == mScrolledFrame || - (kid->GetStyleDisplay()->IsPositioned() != aPositioned)) + (kid->IsPositioned() != aPositioned)) continue; nsDisplayListCollection partList; mOuter->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, partList, nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT); // Don't append textarea resizers to the positioned descendants because // we don't want them to float on top of overlapping elements.
--- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -390,17 +390,17 @@ IsQuirkContainingBlockHeight(const nsHTM if (nsGkAtoms::blockFrame == aFrameType || #ifdef MOZ_XUL nsGkAtoms::XULLabelFrame == aFrameType || #endif nsGkAtoms::scrollFrame == aFrameType) { // Note: This next condition could change due to a style change, // but that would cause a style reflow anyway, which means we're ok. if (NS_AUTOHEIGHT == rs->ComputedHeight()) { - if (!rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) { + if (!rs->frame->IsAbsolutelyPositioned()) { return false; } } } return true; } @@ -636,39 +636,39 @@ nsHTMLReflowState::InitFrameType(nsIAtom DISPLAY_INIT_TYPE(frame, this); if (aFrameType == nsGkAtoms::tableFrame) { mFrameType = NS_CSS_FRAME_TYPE_BLOCK; return; } - NS_ASSERTION(frame->GetStyleDisplay()->IsAbsolutelyPositioned() == - disp->IsAbsolutelyPositioned(), + NS_ASSERTION(frame->GetStyleDisplay()->IsAbsolutelyPositionedStyle() == + disp->IsAbsolutelyPositionedStyle(), "Unexpected position style"); - NS_ASSERTION(frame->GetStyleDisplay()->IsFloating() == - disp->IsFloating(), "Unexpected float style"); + NS_ASSERTION(frame->GetStyleDisplay()->IsFloatingStyle() == + disp->IsFloatingStyle(), "Unexpected float style"); if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { - if (disp->IsAbsolutelyPositioned()) { + if (disp->IsAbsolutelyPositioned(frame)) { frameType = NS_CSS_FRAME_TYPE_ABSOLUTE; //XXXfr hack for making frames behave properly when in overflow container lists // see bug 154892; need to revisit later if (frame->GetPrevInFlow()) frameType = NS_CSS_FRAME_TYPE_BLOCK; } - else if (disp->IsFloating()) { + else if (disp->IsFloating(frame)) { frameType = NS_CSS_FRAME_TYPE_FLOATING; } else { NS_ASSERTION(disp->mDisplay == NS_STYLE_DISPLAY_POPUP, "unknown out of flow frame type"); frameType = NS_CSS_FRAME_TYPE_UNKNOWN; } } else { - switch (disp->mDisplay) { + switch (GetDisplay()) { case NS_STYLE_DISPLAY_BLOCK: case NS_STYLE_DISPLAY_LIST_ITEM: case NS_STYLE_DISPLAY_TABLE: case NS_STYLE_DISPLAY_TABLE_CAPTION: frameType = NS_CSS_FRAME_TYPE_BLOCK; break; case NS_STYLE_DISPLAY_INLINE: @@ -1083,17 +1083,17 @@ nsHTMLReflowState::CalculateHypothetical aHypotheticalBox.mTop = placeholderOffset.y; } else { NS_ASSERTION(iter.GetContainer() == blockFrame, "Found placeholder in wrong block!"); nsBlockFrame::line_iterator lineBox = iter.GetLine(); // How we determine the hypothetical box depends on whether the element // would have been inline-level or block-level - if (mStyleDisplay->IsOriginalDisplayInlineOutside()) { + if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) { // Use the top of the inline box which the placeholder lives in // as the hypothetical box's top. aHypotheticalBox.mTop = lineBox->mBounds.y + blockYOffset; } else { // The element would have been block-level which means it would // be below the line containing the placeholder frame, unless // all the frames before it are empty. In that case, it would // have been just before this line. @@ -1135,17 +1135,17 @@ nsHTMLReflowState::CalculateHypothetical aHypotheticalBox.mTop = placeholderOffset.y; } // Second, determine the hypothetical box's mLeft & mRight // To determine the left and right offsets we need to look at the block's 'direction' if (NS_STYLE_DIRECTION_LTR == blockVis->mDirection) { // How we determine the hypothetical box depends on whether the element // would have been inline-level or block-level - if (mStyleDisplay->IsOriginalDisplayInlineOutside()) { + if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) { // The placeholder represents the left edge of the hypothetical box aHypotheticalBox.mLeft = placeholderOffset.x; } else { aHypotheticalBox.mLeft = aBlockLeftContentEdge; } #ifdef DEBUG aHypotheticalBox.mLeftIsExact = true; #endif @@ -1162,17 +1162,17 @@ nsHTMLReflowState::CalculateHypothetical aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth; #ifdef DEBUG aHypotheticalBox.mRightIsExact = false; #endif } } else { // The placeholder represents the right edge of the hypothetical box - if (mStyleDisplay->IsOriginalDisplayInlineOutside()) { + if (mStyleDisplay->IsOriginalDisplayInlineOutsideStyle()) { aHypotheticalBox.mRight = placeholderOffset.x; } else { aHypotheticalBox.mRight = aBlockLeftContentEdge + aBlockContentWidth; } #ifdef DEBUG aHypotheticalBox.mRightIsExact = true; #endif @@ -1603,17 +1603,17 @@ CalcQuirkContainingBlockHeight(const nsH secondAncestorRS = firstAncestorRS; firstAncestorRS = (nsHTMLReflowState*)rs; // If the current frame we're looking at is positioned, we don't want to // go any further (see bug 221784). The behavior we want here is: 1) If // not auto-height, use this as the percentage base. 2) If auto-height, // keep looking, unless the frame is positioned. if (NS_AUTOHEIGHT == rs->ComputedHeight()) { - if (rs->frame->GetStyleDisplay()->IsAbsolutelyPositioned()) { + if (rs->frame->IsAbsolutelyPositioned()) { break; } else { continue; } } } else if (nsGkAtoms::canvasFrame == frameType) { // Always continue on to the height calculation @@ -1689,17 +1689,17 @@ nsHTMLReflowState::ComputeContainingBloc // formed by the content edge of the nearest block-level ancestor aContainingBlockWidth = aContainingBlockRS->mComputedWidth; aContainingBlockHeight = aContainingBlockRS->mComputedHeight; // mFrameType for abs-pos tables is NS_CSS_FRAME_TYPE_BLOCK, so we need to // special case them here. if (NS_FRAME_GET_TYPE(mFrameType) == NS_CSS_FRAME_TYPE_ABSOLUTE || (frame->GetType() == nsGkAtoms::tableFrame && - frame->GetStyleDisplay()->IsAbsolutelyPositioned() && + frame->IsAbsolutelyPositioned() && (frame->GetParent()->GetStateBits() & NS_FRAME_OUT_OF_FLOW))) { // See if the ancestor is block-level or inline-level if (NS_FRAME_GET_TYPE(aContainingBlockRS->mFrameType) == NS_CSS_FRAME_TYPE_INLINE) { // Base our size on the actual size of the frame. In cases when this is // completely bogus (eg initial reflow), this code shouldn't even be // called, since the code in nsInlineFrame::Reflow will pass in // the containing block dimensions to our constructor. // XXXbz we should be taking the in-flows into account too, but @@ -1892,17 +1892,17 @@ nsHTMLReflowState::InitConstraints(nsPre heightUnit = eStyleUnit_Auto; } } } // Compute our offsets if the element is relatively positioned. We need // the correct containing block width and height here, which is why we need // to do it after all the quirks-n-such above. - if (NS_STYLE_POSITION_RELATIVE == mStyleDisplay->mPosition) { + if (mStyleDisplay->IsRelativelyPositioned(frame)) { PRUint8 direction = NS_STYLE_DIRECTION_LTR; if (cbrs && NS_STYLE_DIRECTION_RTL == cbrs->mStyleVisibility->mDirection) { direction = NS_STYLE_DIRECTION_RTL; } ComputeRelativeOffsets(direction, frame, aContainingBlockWidth, aContainingBlockHeight, mComputedOffsets); } else { // Initialize offsets to 0 @@ -2079,16 +2079,19 @@ nsCSSOffsetState::InitOffsets(nscoord aC frame, disp->mAppearance, &widget)) { mComputedPadding.top = presContext->DevPixelsToAppUnits(widget.top); mComputedPadding.right = presContext->DevPixelsToAppUnits(widget.right); mComputedPadding.bottom = presContext->DevPixelsToAppUnits(widget.bottom); mComputedPadding.left = presContext->DevPixelsToAppUnits(widget.left); needPaddingProp = false; } + else if (frame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) { + mComputedPadding.SizeTo(0, 0, 0, 0); + } else if (aPadding) { // padding is an input arg mComputedPadding = *aPadding; needPaddingProp = frame->GetStylePadding()->IsWidthDependent(); } else { needPaddingProp = ComputePadding(aContainingBlockWidth, aFrameType); } @@ -2101,16 +2104,19 @@ nsCSSOffsetState::InitOffsets(nscoord aC presContext->DevPixelsToAppUnits(widget.top); mComputedBorderPadding.right = presContext->DevPixelsToAppUnits(widget.right); mComputedBorderPadding.bottom = presContext->DevPixelsToAppUnits(widget.bottom); mComputedBorderPadding.left = presContext->DevPixelsToAppUnits(widget.left); } + else if (frame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) { + mComputedBorderPadding.SizeTo(0, 0, 0, 0); + } else if (aBorder) { // border is an input arg mComputedBorderPadding = *aBorder; } else { mComputedBorderPadding = frame->GetStyleBorder()->GetComputedBorder(); } mComputedBorderPadding += mComputedPadding; @@ -2343,16 +2349,21 @@ nsHTMLReflowState::CalcLineHeight(nsStyl NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up"); return lineHeight; } bool nsCSSOffsetState::ComputeMargin(nscoord aContainingBlockWidth) { + // SVG text frames have no margin. + if (frame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) { + return false; + } + // If style style can provide us the margin directly, then use it. const nsStyleMargin *styleMargin = frame->GetStyleMargin(); bool isWidthDependent = !styleMargin->GetMargin(mComputedMargin); if (isWidthDependent) { // We have to compute the value mComputedMargin.left = nsLayoutUtils:: ComputeWidthDependentValue(aContainingBlockWidth, styleMargin->mMargin.GetLeft());
--- a/layout/generic/nsHTMLReflowState.h +++ b/layout/generic/nsHTMLReflowState.h @@ -5,16 +5,17 @@ /* struct containing the input to nsIFrame::Reflow */ #ifndef nsHTMLReflowState_h___ #define nsHTMLReflowState_h___ #include "nsMargin.h" #include "nsStyleCoord.h" +#include "nsStyleStructInlines.h" #include "nsIFrame.h" #include "mozilla/AutoRestore.h" class nsPresContext; class nsRenderingContext; class nsFloatManager; class nsLineLayout; class nsIPercentHeightObserver; @@ -287,16 +288,24 @@ public: const nsStyleDisplay* mStyleDisplay; const nsStyleVisibility* mStyleVisibility; const nsStylePosition* mStylePosition; const nsStyleBorder* mStyleBorder; const nsStyleMargin* mStyleMargin; const nsStylePadding* mStylePadding; const nsStyleText* mStyleText; + bool IsFloating() const { + return mStyleDisplay->IsFloating(frame); + } + + PRUint8 GetDisplay() const { + return mStyleDisplay->GetDisplay(frame); + } + // a frame (e.g. nsTableCellFrame) which may need to generate a special // reflow for percent height calculations nsIPercentHeightObserver* mPercentHeightObserver; // CSS margin collapsing sometimes requires us to reflow // optimistically assuming that margins collapse to see if clearance // is required. When we discover that clearance is required, we // store the frame in which clearance was discovered to the location
--- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -18,18 +18,19 @@ /* nsIFrame is in the process of being deCOMtaminated, i.e., this file is eventually going to be eliminated, and all callers will use nsFrame instead. At the moment we're midway through this process, so you will see inlined functions and member variables in this file. -dwh */ #include <stdio.h> #include "nsQueryFrame.h" #include "nsEvent.h" +#include "nsStyleContext.h" #include "nsStyleStruct.h" -#include "nsStyleContext.h" +#include "nsStyleStructFwd.h" #include "nsIContent.h" #include "nsHTMLReflowMetrics.h" #include "gfxMatrix.h" #include "nsFrameList.h" #include "nsAlgorithm.h" #include "mozilla/layout/FrameChildList.h" #include "FramePropertyTable.h" @@ -292,16 +293,20 @@ typedef PRUint64 nsFrameState; // alpha children. With BasicLayers we avoid creating these, so we mark // the frames for future reference. #define NS_FRAME_NO_COMPONENT_ALPHA NS_FRAME_STATE_BIT(45) // Frame has a cached rasterization of anV // nsDisplayBackground display item #define NS_FRAME_HAS_CACHED_BACKGROUND NS_FRAME_STATE_BIT(46) +// The frame is a descendant of nsSVGTextFrame2 and is thus used for SVG +// text layout. +#define NS_FRAME_IS_SVG_TEXT NS_FRAME_STATE_BIT(47) + // Box layout bits #define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22) #define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31) // Helper macros #define NS_SUBTREE_DIRTY(_frame) \ (((_frame)->GetStateBits() & \ (NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN)) != 0) @@ -2494,17 +2499,19 @@ public: /** * Determines whether this frame is a pseudo stacking context, looking * only as style --- i.e., assuming that it's in-flow and not a replaced * element and not an SVG element. * XXX maybe check IsTransformed()? */ bool IsPseudoStackingContextFromStyle() { const nsStyleDisplay* disp = GetStyleDisplay(); - return disp->mOpacity != 1.0f || disp->IsPositioned() || disp->IsFloating(); + return disp->mOpacity != 1.0f || + disp->IsPositioned(this) || + disp->IsFloating(this); } virtual bool HonorPrintBackgroundSettings() { return true; } /** * Determine whether the frame is logically empty, which is roughly * whether the layout would be the same whether or not the frame is * present. Placeholder frames should return true. Block frames @@ -2829,16 +2836,37 @@ NS_PTR_TO_INT32(frame->Properties().Get( // If the VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY flag is passed then we // ignore the chrome/content boundary, otherwise we stop looking when we // reach it. enum { VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY = 0x01 }; bool IsVisibleConsideringAncestors(PRUint32 aFlags = 0) const; + inline bool IsBlockInside() const; + inline bool IsBlockOutside() const; + inline bool IsInlineOutside() const; + inline PRUint8 GetDisplay() const; + inline bool IsFloating() const; + inline bool IsPositioned() const; + inline bool IsRelativelyPositioned() const; + inline bool IsAbsolutelyPositioned() const; + + /** + * Returns the vertical-align value to be used for layout, if it is one + * of the enumerated values. If this is an SVG text frame, it returns a value + * that corresponds to the value of dominant-baseline. If the + * vertical-align property has length or percentage value, this returns + * eInvalidVerticalAlign. + */ + PRUint8 VerticalAlignEnum() const; + enum { eInvalidVerticalAlign = 0xFF }; + + bool IsSVGText() const { return mState & NS_FRAME_IS_SVG_TEXT; } + protected: // Members nsRect mRect; nsIContent* mContent; nsStyleContext* mStyleContext; nsIFrame* mParent; private: nsIFrame* mNextSibling; // doubly-linked list of frames @@ -3139,9 +3167,60 @@ nsFrameList::Enumerator::Next() inline nsFrameList::FrameLinkEnumerator:: FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame) : Enumerator(aList) { mPrev = aPrevFrame; mFrame = aPrevFrame ? aPrevFrame->GetNextSibling() : aList.FirstChild(); } + +#include "nsStyleStructInlines.h" + +bool +nsIFrame::IsFloating() const +{ + return GetStyleDisplay()->IsFloating(this); +} + +bool +nsIFrame::IsPositioned() const +{ + return GetStyleDisplay()->IsPositioned(this); +} + +bool +nsIFrame::IsRelativelyPositioned() const +{ + return GetStyleDisplay()->IsRelativelyPositioned(this); +} + +bool +nsIFrame::IsAbsolutelyPositioned() const +{ + return GetStyleDisplay()->IsAbsolutelyPositioned(this); +} + +bool +nsIFrame::IsBlockInside() const +{ + return GetStyleDisplay()->IsBlockInside(this); +} + +bool +nsIFrame::IsBlockOutside() const +{ + return GetStyleDisplay()->IsBlockOutside(this); +} + +bool +nsIFrame::IsInlineOutside() const +{ + return GetStyleDisplay()->IsInlineOutside(this); +} + +PRUint8 +nsIFrame::GetDisplay() const +{ + return GetStyleDisplay()->GetDisplay(this); +} + #endif /* nsIFrame_h___ */
--- a/layout/generic/nsLineBox.cpp +++ b/layout/generic/nsLineBox.cpp @@ -10,16 +10,17 @@ #include "nsLineLayout.h" #include "prprf.h" #include "nsBlockFrame.h" #include "nsIFrame.h" #include "nsPresArena.h" #ifdef IBMBIDI #include "nsBidiPresUtils.h" #endif +#include "nsStyleStructInlines.h" #ifdef DEBUG static PRInt32 ctorCount; PRInt32 nsLineBox::GetCtorCount() { return ctorCount; } #endif #ifndef _MSC_VER // static nsLineBox constant; initialized in the header file. @@ -31,17 +32,17 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, P // NOTE: memory is already zeroed since we allocate with AllocateByObjectID. { MOZ_COUNT_CTOR(nsLineBox); #ifdef DEBUG ++ctorCount; NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child"); nsIFrame* f = aFrame; for (PRInt32 n = aCount; n > 0; f = f->GetNextSibling(), --n) { - NS_ASSERTION(aIsBlock == f->GetStyleDisplay()->IsBlockOutside(), + NS_ASSERTION(aIsBlock == f->IsBlockOutside(), "wrong kind of child frame"); } #endif #if NS_STYLE_CLEAR_NONE > 0 mFlags.mBreakType = NS_STYLE_CLEAR_NONE; #endif mChildCount = aCount;
--- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -972,18 +972,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra if (!continuingTextRun && !pfd->GetFlag(PFD_SKIPWHENTRIMMINGWHITESPACE)) { mTrimmableWidth = 0; } // See if we can place the frame. If we can't fit it, then we // return now. bool optionalBreakAfterFits; NS_ASSERTION(isText || - reflowStateHolder.ref().mStyleDisplay->mFloats == - NS_STYLE_FLOAT_NONE, + !reflowStateHolder.ref().IsFloating(), "How'd we get a floated inline frame? " "The frame ctor should've dealt with this."); // Direction is inherited, so using the psd direction is fine. // Get it off the reflow state instead of the frame to save style // data computation (especially for the text). PRUint8 direction = isText ? psd->mReflowState->mStyleVisibility->mDirection : reflowStateHolder.ref().mStyleVisibility->mDirection; @@ -1046,17 +1045,17 @@ nsLineLayout::ReflowFrame(nsIFrame* aFra return rv; } void nsLineLayout::ApplyStartMargin(PerFrameData* pfd, nsHTMLReflowState& aReflowState) { - NS_ASSERTION(aReflowState.mStyleDisplay->mFloats == NS_STYLE_FLOAT_NONE, + NS_ASSERTION(!aReflowState.IsFloating(), "How'd we get a floated inline frame? " "The frame ctor should've dealt with this."); // XXXwaterson probably not the right way to get this; e.g., embeddings, etc. bool ltr = (NS_STYLE_DIRECTION_LTR == aReflowState.mStyleVisibility->mDirection); // Only apply start-margin on the first-in flow for inline frames, // and make sure to not apply it to any inline other than the first @@ -1447,21 +1446,17 @@ nsLineLayout::VerticalAlignLine() // If the frame being reflowed has text decorations, we simulate the // propagation of those decorations to a line-level element by storing the // offset in a frame property on any child frames that are vertically-aligned // somewhere other than the baseline. This property is then used by // nsTextFrame::GetTextDecorations when the same conditions are met. if (rootPFD.mFrame->GetStyleContext()->HasTextDecorationLines()) { for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) { const nsIFrame *const f = pfd->mFrame; - const nsStyleCoord& vAlign = - f->GetStyleContext()->GetStyleTextReset()->mVerticalAlign; - - if (vAlign.GetUnit() != eStyleUnit_Enumerated || - vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE) { + if (f->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) { const nscoord offset = baselineY - pfd->mBounds.y; f->Properties().Set(nsIFrame::LineBaselineOffset(), NS_INT32_TO_PTR(offset)); } } } // Fill in returned line-box and max-element-width data @@ -1771,28 +1766,34 @@ nsLineLayout::VerticalAlignFrames(PerSpa // frames height plus its margins. logicalHeight = pfd->mBounds.height + pfd->mMargin.top + pfd->mMargin.bottom; } // Get vertical-align property const nsStyleCoord& verticalAlign = frame->GetStyleTextReset()->mVerticalAlign; + PRUint8 verticalAlignEnum = frame->VerticalAlignEnum(); #ifdef NOISY_VERTICAL_ALIGN printf(" [frame]"); nsFrame::ListTag(stdout, frame); - printf(": verticalAlignUnit=%d (enum == %d)\n", + printf(": verticalAlignUnit=%d (enum == %d", verticalAlign.GetUnit(), ((eStyleUnit_Enumerated == verticalAlign.GetUnit()) ? verticalAlign.GetIntValue() : -1)); + if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) { + printf(", after SVG dominant-baseline conversion == %d", + verticalAlignEnum); + } + printf(")\n"); #endif - if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) { - switch (verticalAlign.GetIntValue()) { + if (verticalAlignEnum != nsIFrame::eInvalidVerticalAlign) { + switch (verticalAlignEnum) { default: case NS_STYLE_VERTICAL_ALIGN_BASELINE: { // The element's baseline is aligned with the baseline of // the parent. pfd->mBounds.y = baselineY - pfd->mAscent; pfd->mVerticalAlign = VALIGN_OTHER; break; @@ -2467,17 +2468,18 @@ nsLineLayout::HorizontalAlignFrames(nsRe nscoord remainingWidth = availWidth - aLineBounds.width; #ifdef NOISY_HORIZONTAL_ALIGN nsFrame::ListTag(stdout, mBlockReflowState->frame); printf(": availWidth=%d lineWidth=%d delta=%d\n", availWidth, aLineBounds.width, remainingWidth); #endif nscoord dx = 0; - if (remainingWidth > 0) { + if (remainingWidth > 0 && + !(mBlockReflowState->frame->IsSVGText())) { PRUint8 textAlign = mStyleText->mTextAlign; /* * 'text-align-last: auto' is equivalent to the value of the 'text-align' * property except when 'text-align' is set to 'justify', in which case it * is 'justify' when 'text-justify' is 'distribute' and 'start' otherwise. * * XXX: the code below will have to change when we implement text-justify
--- a/layout/generic/nsPlaceholderFrame.cpp +++ b/layout/generic/nsPlaceholderFrame.cpp @@ -77,32 +77,32 @@ nsPlaceholderFrame::AddInlineMinWidth(ns { // Override AddInlineMinWith so that *nothing* happens. In // particular, we don't want to zero out |aData->trailingWhitespace|, // since nsLineLayout skips placeholders when trimming trailing // whitespace, and we don't want to set aData->skipWhitespace to // false. // ...but push floats onto the list - if (mOutOfFlowFrame->GetStyleDisplay()->IsFloating()) + if (mOutOfFlowFrame->IsFloating()) aData->floats.AppendElement(mOutOfFlowFrame); } /* virtual */ void nsPlaceholderFrame::AddInlinePrefWidth(nsRenderingContext *aRenderingContext, nsIFrame::InlinePrefWidthData *aData) { // Override AddInlinePrefWith so that *nothing* happens. In // particular, we don't want to zero out |aData->trailingWhitespace|, // since nsLineLayout skips placeholders when trimming trailing // whitespace, and we don't want to set aData->skipWhitespace to // false. // ...but push floats onto the list - if (mOutOfFlowFrame->GetStyleDisplay()->IsFloating()) + if (mOutOfFlowFrame->IsFloating()) aData->floats.AppendElement(mOutOfFlowFrame); } NS_IMETHODIMP nsPlaceholderFrame::Reflow(nsPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState, nsReflowStatus& aStatus)
--- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -13,16 +13,18 @@ #include "nsSplittableFrame.h" #include "nsLineLayout.h" #include "nsString.h" #include "nsUnicharUtils.h" #include "nsPresContext.h" #include "nsIContent.h" #include "nsStyleConsts.h" #include "nsStyleContext.h" +#include "nsStyleStruct.h" +#include "nsStyleStructInlines.h" #include "nsCoord.h" #include "nsRenderingContext.h" #include "nsIPresShell.h" #include "nsITimer.h" #include "nsTArray.h" #include "nsIDocument.h" #include "nsCSSPseudoElements.h" #include "nsCSSFrameConstructor.h" @@ -1149,17 +1151,17 @@ BuildTextRuns(gfxContext* aContext, nsTe lineContainerChild = aForFrame->PresContext()->PresShell()-> GetPlaceholderFrameFor(aForFrame->GetParent()); } aLineContainer = FindLineContainer(lineContainerChild); } else { NS_ASSERTION(!aForFrame || (aLineContainer == FindLineContainer(aForFrame) || (aLineContainer->GetType() == nsGkAtoms::letterFrame && - aLineContainer->GetStyleDisplay()->IsFloating())), + aLineContainer->IsFloating())), "Wrong line container hint"); } nsPresContext* presContext = aLineContainer->PresContext(); BuildTextRunsScanner scanner(presContext, aContext, aLineContainer, aWhichTextRun); nsBlockFrame* block = nsLayoutUtils::GetAsBlock(aLineContainer); @@ -1452,16 +1454,40 @@ static bool HasTerminalNewline(const nsTextFrame* aFrame) { if (aFrame->GetContentLength() == 0) return false; const nsTextFragment* frag = aFrame->GetContent()->GetText(); return frag->CharAt(aFrame->GetContentEnd() - 1) == '\n'; } +static nscoord +LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nsnull) +{ + if (aFrame->IsSVGText()) { + return 0; + } + if (!aStyleText) { + aStyleText = aFrame->GetStyleText(); + } + return StyleToCoord(aStyleText->mLetterSpacing); +} + +static nscoord +WordSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nsnull) +{ + if (aFrame->IsSVGText()) { + return 0; + } + if (!aStyleText) { + aStyleText = aFrame->GetStyleText(); + } + return aStyleText->mWordSpacing; +} + bool BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1, nsTextFrame* aFrame2) { // We don't need to check font size inflation, since // |FindLineContainer| above (via |nsIFrame::CanContinueTextRun|) // ensures that text runs never cross block boundaries. This means // that the font size inflation on all text frames in the text run is // already guaranteed to be the same as each other (and for the line @@ -1491,23 +1517,25 @@ BuildTextRunsScanner::ContinueTextRunAcr // because that would violate our invariant that two flows in the same // textrun have different content elements. return false; } nsStyleContext* sc2 = aFrame2->GetStyleContext(); if (sc1 == sc2) return true; + const nsStyleFont* fontStyle1 = sc1->GetStyleFont(); const nsStyleFont* fontStyle2 = sc2->GetStyleFont(); - const nsStyleText* textStyle2 = sc2->GetStyleText(); + nscoord letterSpacing1 = LetterSpacing(aFrame1); + nscoord letterSpacing2 = LetterSpacing(aFrame2); return fontStyle1->mFont.BaseEquals(fontStyle2->mFont) && sc1->GetStyleFont()->mLanguage == sc2->GetStyleFont()->mLanguage && - nsLayoutUtils::GetTextRunFlagsForStyle(sc1, textStyle1, fontStyle1) == - nsLayoutUtils::GetTextRunFlagsForStyle(sc2, textStyle2, fontStyle2); + nsLayoutUtils::GetTextRunFlagsForStyle(sc1, fontStyle1, letterSpacing1) == + nsLayoutUtils::GetTextRunFlagsForStyle(sc2, fontStyle2, letterSpacing2); } void BuildTextRunsScanner::ScanFrame(nsIFrame* aFrame) { // First check if we can extend the current mapped frame block. This is common. if (mMappedFlows.Length() > 0) { MappedFlow* mappedFlow = &mMappedFlows[mMappedFlows.Length() - 1]; if (mappedFlow->mEndFrame == aFrame && @@ -1742,17 +1770,18 @@ BuildTextRunsScanner::BuildTextRunForFra userData->mLastFlowIndex = 0; PRUint32 currentTransformedTextOffset = 0; PRUint32 nextBreakIndex = 0; nsTextFrame* nextBreakBeforeFrame = GetNextBreakBeforeFrame(&nextBreakIndex); bool enabledJustification = mLineContainer && (mLineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY || - mLineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY); + mLineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY) && + !mLineContainer->IsSVGText(); // for word-break style switch (mLineContainer->GetStyleText()->mWordBreak) { case NS_STYLE_WORDBREAK_BREAK_ALL: mLineBreaker.SetWordBreak(nsILineBreaker::kWordBreak_BreakAll); break; case NS_STYLE_WORDBREAK_KEEP_ALL: mLineBreaker.SetWordBreak(nsILineBreaker::kWordBreak_KeepAll); @@ -1771,18 +1800,18 @@ BuildTextRunsScanner::BuildTextRunForFra nsTextFrame* f = mappedFlow->mStartFrame; lastStyleContext = f->GetStyleContext(); // Detect use of text-transform or font-variant anywhere in the run textStyle = f->GetStyleText(); if (NS_STYLE_TEXT_TRANSFORM_NONE != textStyle->mTextTransform) { anyTextTransformStyle = true; } - textFlags |= GetSpacingFlags(StyleToCoord(textStyle->mLetterSpacing)); - textFlags |= GetSpacingFlags(textStyle->mWordSpacing); + textFlags |= GetSpacingFlags(LetterSpacing(f)); + textFlags |= GetSpacingFlags(WordSpacing(f)); nsTextFrameUtils::CompressionMode compression = CSSWhitespaceToCompressionMode[textStyle->mWhiteSpace]; if (enabledJustification && !textStyle->WhiteSpaceIsSignificant()) { textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING; } fontStyle = f->GetStyleFont(); if (NS_STYLE_FONT_VARIANT_SMALL_CAPS == fontStyle->mFont.variant) { anySmallcapsStyle = true; @@ -1887,19 +1916,20 @@ BuildTextRunsScanner::BuildTextRunForFra } if (mNextRunContextInfo & nsTextFrameUtils::INCOMING_WHITESPACE) { textFlags |= nsTextFrameUtils::TEXT_TRAILING_WHITESPACE; } if (mNextRunContextInfo & nsTextFrameUtils::INCOMING_ARABICCHAR) { textFlags |= gfxTextRunFactory::TEXT_TRAILING_ARABICCHAR; } // ContinueTextRunAcrossFrames guarantees that it doesn't matter which - // frame's style is used, so use the last frame's + // frame's style is used, so we use a mixture of the first frame and + // last frame's style textFlags |= nsLayoutUtils::GetTextRunFlagsForStyle(lastStyleContext, - textStyle, fontStyle); + fontStyle, LetterSpacing(firstFrame, textStyle)); // XXX this is a bit of a hack. For performance reasons, if we're favouring // performance over quality, don't try to get accurate glyph extents. if (!(textFlags & gfxTextRunFactory::TEXT_OPTIMIZE_SPEED)) { textFlags |= gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX; } gfxSkipChars skipChars; skipChars.TakeFrom(&builder); @@ -2602,18 +2632,18 @@ public: nscoord aOffsetFromBlockOriginForTabs, nsTextFrame::TextRunType aWhichTextRun) : mTextRun(aTextRun), mFontGroup(nullptr), mTextStyle(aTextStyle), mFrag(aFrag), mLineContainer(aLineContainer), mFrame(aFrame), mStart(aStart), mTempIterator(aStart), mTabWidths(nullptr), mTabWidthsAnalyzedLimit(0), mLength(aLength), - mWordSpacing(mTextStyle->mWordSpacing), - mLetterSpacing(StyleToCoord(mTextStyle->mLetterSpacing)), + mWordSpacing(WordSpacing(aFrame, aTextStyle)), + mLetterSpacing(LetterSpacing(aFrame, aTextStyle)), mJustificationSpacing(0), mHyphenWidth(-1), mOffsetFromBlockOriginForTabs(aOffsetFromBlockOriginForTabs), mReflowing(true), mWhichTextRun(aWhichTextRun) { NS_ASSERTION(mStart.IsInitialized(), "Start not initialized?"); } @@ -2627,18 +2657,18 @@ public: nsTextFrame::TextRunType aWhichTextRun) : mTextRun(aFrame->GetTextRun(aWhichTextRun)), mFontGroup(nullptr), mTextStyle(aFrame->GetStyleText()), mFrag(aFrame->GetContent()->GetText()), mLineContainer(nullptr), mFrame(aFrame), mStart(aStart), mTempIterator(aStart), mTabWidths(nullptr), mTabWidthsAnalyzedLimit(0), mLength(aFrame->GetContentLength()), - mWordSpacing(mTextStyle->mWordSpacing), - mLetterSpacing(StyleToCoord(mTextStyle->mLetterSpacing)), + mWordSpacing(WordSpacing(aFrame)), + mLetterSpacing(LetterSpacing(aFrame)), mJustificationSpacing(0), mHyphenWidth(-1), mOffsetFromBlockOriginForTabs(0), mReflowing(false), mWhichTextRun(aWhichTextRun) { NS_ASSERTION(mTextRun, "Textrun not initialized!"); } @@ -4533,21 +4563,17 @@ nsTextFrame::GetTextDecorations(nsPresCo // Not updating positions once we hit a parent block is equivalent to // the CSS 2.1 spec that blocks should propagate decorations down to their // children (albeit the style should be preserved) // However, if we're vertically aligned within a block, then we need to // recover the right baseline from the line by querying the FrameProperty // that should be set (see nsLineLayout::VerticalAlignLine). if (firstBlock) { // At this point, fChild can't be null since TextFrames can't be blocks - const nsStyleCoord& vAlign = - fChild->GetStyleContext()->GetStyleTextReset()->mVerticalAlign; - if (vAlign.GetUnit() != eStyleUnit_Enumerated || - vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE) - { + if (fChild->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) { // Since offset is the offset in the child's coordinate space, we have // to undo the accumulation to bring the transform out of the block's // coordinate space baselineOffset = frameTopOffset - (fChild->GetRect().y - fChild->GetRelativeOffset().y) - NS_PTR_TO_INT32( fChild->Properties().Get(nsIFrame::LineBaselineOffset())); } @@ -4576,31 +4602,31 @@ nsTextFrame::GetTextDecorations(nsPresCo if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) { aDecorations.mStrikes.AppendElement( nsTextFrame::LineDecoration(f, baselineOffset, color, style)); } } // In all modes, if we're on an inline-block or inline-table (or // inline-stack, inline-box, inline-grid), we're done. - const nsStyleDisplay *disp = context->GetStyleDisplay(); - if (disp->mDisplay != NS_STYLE_DISPLAY_INLINE && - disp->IsInlineOutside()) { + PRUint8 display = f->GetDisplay(); + if (display != NS_STYLE_DISPLAY_INLINE && + nsStyleDisplay::IsDisplayTypeInlineOutside(display)) { break; } if (compatMode == eCompatibility_NavQuirks) { // In quirks mode, if we're on an HTML table element, we're done. if (f->GetContent()->IsHTML(nsGkAtoms::table)) { break; } } else { // In standards/almost-standards mode, if we're on an // absolutely-positioned element or a floating element, we're done. - if (disp->IsFloating() || disp->IsAbsolutelyPositioned()) { + if (f->IsFloating() || f->IsAbsolutelyPositioned()) { break; } } } } void nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext, @@ -7151,17 +7177,17 @@ nsTextFrame::SetLength(PRInt32 aLength, } #endif } bool nsTextFrame::IsFloatingFirstLetterChild() const { nsIFrame* frame = GetParent(); - return frame && frame->GetStyleDisplay()->IsFloating() && + return frame && frame->IsFloating() && frame->GetType() == nsGkAtoms::letterFrame; } struct NewlineProperty { PRInt32 mStartOffset; // The offset of the first \n after mStartOffset, or -1 if there is none PRInt32 mNewlineOffset; @@ -7717,17 +7743,18 @@ nsTextFrame::ReflowText(nsLineLayout& aL } } else if (cachedNewlineOffset) { mContent->DeleteProperty(nsGkAtoms::newline); } // Compute space and letter counts for justification, if required if (!textStyle->WhiteSpaceIsSignificant() && (lineContainer->GetStyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY || - lineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY)) { + lineContainer->GetStyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY) && + !lineContainer->IsSVGText()) { AddStateBits(TEXT_JUSTIFICATION_ENABLED); // This will include a space for trailing whitespace, if any is present. // This is corrected for in nsLineLayout::TrimWhiteSpaceIn. PRInt32 numJustifiableCharacters = provider.ComputeJustifiableCharacters(offset, charsFit); NS_ASSERTION(numJustifiableCharacters <= charsFit, "Bad justifiable character count"); aLineLayout.SetTextJustificationWeights(numJustifiableCharacters,
--- a/layout/style/nsCSSAnonBoxList.h +++ b/layout/style/nsCSSAnonBoxList.h @@ -78,8 +78,9 @@ CSS_ANON_BOX(moztreeimage, ":-moz-tree-i CSS_ANON_BOX(moztreecelltext, ":-moz-tree-cell-text") CSS_ANON_BOX(moztreecheckbox, ":-moz-tree-checkbox") CSS_ANON_BOX(moztreeprogressmeter, ":-moz-tree-progressmeter") CSS_ANON_BOX(moztreedropfeedback, ":-moz-tree-drop-feedback") #endif CSS_ANON_BOX(mozSVGOuterSVGAnonChild, ":-moz-svg-outer-svg-anon-child") CSS_ANON_BOX(mozSVGForeignContent, ":-moz-svg-foreign-content") +CSS_ANON_BOX(mozSVGText, ":-moz-svg-text")
--- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -4848,17 +4848,17 @@ nsRuleNode::ComputeDisplayData(void* aSt display->mOriginalDisplay = display->mDisplay = NS_STYLE_DISPLAY_INLINE; // We can't cache the data in the rule tree since if a more specific // rule has 'float: left' we'll end up with the wrong 'display' // property. canStoreInRuleTree = false; } - if (display->IsAbsolutelyPositioned()) { + if (display->IsAbsolutelyPositionedStyle()) { // 1) if position is 'absolute' or 'fixed' then display must be // block-level and float must be 'none' EnsureBlockDisplay(display->mDisplay); display->mFloats = NS_STYLE_FLOAT_NONE; // Note that it's OK to cache this struct in the ruletree // because it's fine as-is for any style context that points to // it directly, and any use of it as aStartStruct (e.g. if a
--- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1033,23 +1033,25 @@ nsChangeHint nsStyleSVGReset::CalcDiffer nsChangeHint hint = nsChangeHint(0); if (!EqualURIs(mClipPath, aOther.mClipPath) || !EqualURIs(mFilter, aOther.mFilter) || !EqualURIs(mMask, aOther.mMask)) { NS_UpdateHint(hint, nsChangeHint_UpdateEffects); NS_UpdateHint(hint, nsChangeHint_ReflowFrame); NS_UpdateHint(hint, nsChangeHint_RepaintFrame); - } else if (mStopColor != aOther.mStopColor || - mFloodColor != aOther.mFloodColor || - mLightingColor != aOther.mLightingColor || - mStopOpacity != aOther.mStopOpacity || - mFloodOpacity != aOther.mFloodOpacity || - mDominantBaseline != aOther.mDominantBaseline || - mVectorEffect != aOther.mVectorEffect) + } else if (mDominantBaseline != aOther.mDominantBaseline) { + NS_UpdateHint(hint, nsChangeHint_NeedReflow); + NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); + } else if (mStopColor != aOther.mStopColor || + mFloodColor != aOther.mFloodColor || + mLightingColor != aOther.mLightingColor || + mStopOpacity != aOther.mStopOpacity || + mFloodOpacity != aOther.mFloodOpacity || + mVectorEffect != aOther.mVectorEffect) NS_UpdateHint(hint, nsChangeHint_RepaintFrame); return hint; } #ifdef DEBUG /* static */ nsChangeHint nsStyleSVGReset::MaxDifference()
--- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1595,26 +1595,26 @@ struct nsStyleDisplay { mAnimationDurationCount, mAnimationDelayCount, mAnimationNameCount, mAnimationDirectionCount, mAnimationFillModeCount, mAnimationPlayStateCount, mAnimationIterationCountCount; - bool IsBlockInside() const { + bool IsBlockInsideStyle() const { return NS_STYLE_DISPLAY_BLOCK == mDisplay || NS_STYLE_DISPLAY_LIST_ITEM == mDisplay || NS_STYLE_DISPLAY_INLINE_BLOCK == mDisplay; // Should TABLE_CELL and TABLE_CAPTION go here? They have // block frames nested inside of them. // (But please audit all callers before changing.) } - bool IsBlockOutside() const { + bool IsBlockOutsideStyle() const { return NS_STYLE_DISPLAY_BLOCK == mDisplay || #ifdef MOZ_FLEXBOX NS_STYLE_DISPLAY_FLEX == mDisplay || #endif // MOZ_FLEXBOX NS_STYLE_DISPLAY_LIST_ITEM == mDisplay || NS_STYLE_DISPLAY_TABLE == mDisplay; } @@ -1625,50 +1625,68 @@ struct nsStyleDisplay { NS_STYLE_DISPLAY_INLINE_BOX == aDisplay || #ifdef MOZ_FLEXBOX NS_STYLE_DISPLAY_INLINE_FLEX == aDisplay || #endif // MOZ_FLEXBOX NS_STYLE_DISPLAY_INLINE_GRID == aDisplay || NS_STYLE_DISPLAY_INLINE_STACK == aDisplay; } - bool IsInlineOutside() const { + bool IsInlineOutsideStyle() const { return IsDisplayTypeInlineOutside(mDisplay); } - bool IsOriginalDisplayInlineOutside() const { + bool IsOriginalDisplayInlineOutsideStyle() const { return IsDisplayTypeInlineOutside(mOriginalDisplay); } - bool IsFloating() const { + bool IsFloatingStyle() const { return NS_STYLE_FLOAT_NONE != mFloats; } - bool IsAbsolutelyPositioned() const {return (NS_STYLE_POSITION_ABSOLUTE == mPosition) || - (NS_STYLE_POSITION_FIXED == mPosition);} + bool IsAbsolutelyPositionedStyle() const { + return NS_STYLE_POSITION_ABSOLUTE == mPosition || + NS_STYLE_POSITION_FIXED == mPosition; + } /* Returns true if we're positioned or there's a transform in effect. */ - bool IsPositioned() const { - return IsAbsolutelyPositioned() || - NS_STYLE_POSITION_RELATIVE == mPosition || HasTransform(); + bool IsPositionedStyle() const { + return IsAbsolutelyPositionedStyle() || + IsRelativelyPositionedStyle() || + HasTransform(); + } + + bool IsRelativelyPositionedStyle() const { + return mPosition == NS_STYLE_POSITION_RELATIVE; } bool IsScrollableOverflow() const { // mOverflowX and mOverflowY always match when one of them is // NS_STYLE_OVERFLOW_VISIBLE or NS_STYLE_OVERFLOW_CLIP. return mOverflowX != NS_STYLE_OVERFLOW_VISIBLE && mOverflowX != NS_STYLE_OVERFLOW_CLIP; } /* Returns whether the element has the -moz-transform property. */ bool HasTransform() const { return mSpecifiedTransform != nullptr || mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN; } + + // These are defined in nsStyleStructInlines.h. + inline bool IsBlockInside(const nsIFrame* aFrame) const; + inline bool IsBlockOutside(const nsIFrame* aFrame) const; + inline bool IsInlineOutside(const nsIFrame* aFrame) const; + inline bool IsOriginalDisplayInlineOutside(const nsIFrame* aFrame) const; + inline PRUint8 GetDisplay(const nsIFrame* aFrame) const; + inline bool IsFloating(const nsIFrame* aFrame) const; + inline bool IsPositioned(const nsIFrame* aFrame) const; + inline bool IsRelativelyPositioned(const nsIFrame* aFrame) const; + inline bool IsAbsolutelyPositioned(const nsIFrame* aFrame) const; }; struct nsStyleTable { nsStyleTable(void); nsStyleTable(const nsStyleTable& aOther); ~nsStyleTable(void); void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
--- a/layout/style/nsStyleStructInlines.h +++ b/layout/style/nsStyleStructInlines.h @@ -6,16 +6,17 @@ /* * Inline methods that belong in nsStyleStruct.h, except that they * require more headers. */ #ifndef nsStyleStructInlines_h_ #define nsStyleStructInlines_h_ +#include "nsIFrame.h" #include "nsStyleStruct.h" #include "imgIRequest.h" #include "imgIContainer.h" inline void nsStyleBorder::SetBorderImage(imgIRequest* aImage) { mBorderImageSource = aImage; @@ -49,9 +50,81 @@ inline imgIContainer* nsStyleBorder::GetSubImage(PRUint8 aIndex) const { imgIContainer* subImage = nullptr; if (aIndex < mSubImages.Count()) subImage = mSubImages[aIndex]; return subImage; } +bool +nsStyleDisplay::IsBlockInside(const nsIFrame* aFrame) const +{ + if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) { + return aFrame->GetType() == nsGkAtoms::blockFrame; + } + return IsBlockInsideStyle(); +} + +bool +nsStyleDisplay::IsBlockOutside(const nsIFrame* aFrame) const +{ + if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) { + return aFrame->GetType() == nsGkAtoms::blockFrame; + } + return IsBlockOutsideStyle(); +} + +bool +nsStyleDisplay::IsInlineOutside(const nsIFrame* aFrame) const +{ + if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) { + return aFrame->GetType() != nsGkAtoms::blockFrame; + } + return IsInlineOutsideStyle(); +} + +bool +nsStyleDisplay::IsOriginalDisplayInlineOutside(const nsIFrame* aFrame) const +{ + if (aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) { + return aFrame->GetType() != nsGkAtoms::blockFrame; + } + return IsOriginalDisplayInlineOutsideStyle(); +} + +PRUint8 +nsStyleDisplay::GetDisplay(const nsIFrame* aFrame) const +{ + if ((aFrame->GetStateBits() & NS_FRAME_IS_SVG_TEXT) && + mDisplay != NS_STYLE_DISPLAY_NONE) { + return aFrame->GetType() == nsGkAtoms::blockFrame ? + NS_STYLE_DISPLAY_BLOCK : + NS_STYLE_DISPLAY_INLINE; + } + return mDisplay; +} + +bool +nsStyleDisplay::IsFloating(const nsIFrame* aFrame) const +{ + return IsFloatingStyle() && !aFrame->IsSVGText(); +} + +bool +nsStyleDisplay::IsPositioned(const nsIFrame* aFrame) const +{ + return IsPositionedStyle() && !aFrame->IsSVGText(); +} + +bool +nsStyleDisplay::IsRelativelyPositioned(const nsIFrame* aFrame) const +{ + return IsRelativelyPositionedStyle() && !aFrame->IsSVGText(); +} + +bool +nsStyleDisplay::IsAbsolutelyPositioned(const nsIFrame* aFrame) const +{ + return IsAbsolutelyPositionedStyle() && !aFrame->IsSVGText(); +} + #endif /* !defined(nsStyleStructInlines_h_) */
--- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -1671,17 +1671,17 @@ nsSVGGlyphFrame::EnsureTextRun(float *aD font.AddFontFeaturesToStyle(&fontStyle); nsRefPtr<gfxFontGroup> fontGroup = gfxPlatform::GetPlatform()->CreateFontGroup(font.name, &fontStyle, presContext->GetUserFontSet()); PRUint32 flags = gfxTextRunFactory::TEXT_NEED_BOUNDING_BOX | GetTextRunFlags(text.Length()) | - nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleText(), GetStyleFont()); + nsLayoutUtils::GetTextRunFlagsForStyle(GetStyleContext(), GetStyleFont(), 0); // XXX We should use a better surface here! But then we'd have to // change things so we can ensure we always have the "right" sort of // surface available, by creating the textrun only at the right times nsRefPtr<gfxContext> tmpCtx = MakeTmpCtx(); tmpCtx->SetMatrix(m); // Use only the fonts' internal word caching here.
--- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -887,17 +887,17 @@ nsTableRowFrame::ReflowChildren(nsPresCo } desiredSize.width = cellDesiredSize.width; desiredSize.height = cellDesiredSize.height; desiredSize.mOverflowAreas = cellFrame->GetOverflowAreas(); // if we are in a floated table, our position is not yet established, so we cannot reposition our views // the containing block will do this for us after positioning the table - if (!aTableFrame.GetStyleDisplay()->IsFloating()) { + if (!aTableFrame.IsFloating()) { // Because we may have moved the frame we need to make sure any views are // positioned properly. We have to do this, because any one of our parent // frames could have moved and we have no way of knowing... nsTableFrame::RePositionViews(kidFrame); } } if (NS_UNCONSTRAINEDSIZE == aReflowState.availableHeight) {
--- a/mobile/android/base/Tab.java +++ b/mobile/android/base/Tab.java @@ -449,49 +449,49 @@ public final class Tab { public void readerMode() { if (!mReaderEnabled) return; GeckoApp.mAppContext.loadUrl("about:reader?url=" + Uri.encode(getURL())); } - public boolean doReload() { + public void doReload() { GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", ""); GeckoAppShell.sendEventToGecko(e); - return true; } + // Our version of nsSHistory::GetCanGoBack public boolean canDoBack() { - return (mHistoryIndex < 1 ? false : true); + return mHistoryIndex > 0; } public boolean doBack() { - if (mHistoryIndex < 1) { + if (!canDoBack()) return false; - } + GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Back", ""); GeckoAppShell.sendEventToGecko(e); return true; } - public boolean doStop() { + public void doStop() { GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Stop", ""); GeckoAppShell.sendEventToGecko(e); - return true; } + // Our version of nsSHistory::GetCanGoForward public boolean canDoForward() { - return (mHistoryIndex + 1 < mHistorySize); + return mHistoryIndex < mHistorySize - 1; } public boolean doForward() { - if (mHistoryIndex + 1 >= mHistorySize) { + if (!canDoForward()) return false; - } + GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Forward", ""); GeckoAppShell.sendEventToGecko(e); return true; } public void addDoorHanger(String value, DoorHanger dh) { mDoorHangers.put(value, dh); } @@ -526,52 +526,58 @@ public final class Tab { } public HashMap<String, DoorHanger> getDoorHangers() { return mDoorHangers; } void handleSessionHistoryMessage(String event, JSONObject message) throws JSONException { if (event.equals("New")) { - final String uri = message.getString("uri"); + final String url = message.getString("url"); mHistoryIndex++; mHistorySize = mHistoryIndex + 1; GeckoAppShell.getHandler().post(new Runnable() { public void run() { - GlobalHistory.getInstance().add(uri); + GlobalHistory.getInstance().add(url); } }); } else if (event.equals("Back")) { - if (mHistoryIndex - 1 < 0) { + if (!canDoBack()) { Log.e(LOGTAG, "Received unexpected back notification"); return; } mHistoryIndex--; } else if (event.equals("Forward")) { - if (mHistoryIndex + 1 >= mHistorySize) { + if (!canDoForward()) { Log.e(LOGTAG, "Received unexpected forward notification"); return; } mHistoryIndex++; } else if (event.equals("Goto")) { int index = message.getInt("index"); if (index < 0 || index >= mHistorySize) { Log.e(LOGTAG, "Received unexpected history-goto notification"); return; } mHistoryIndex = index; } else if (event.equals("Purge")) { - int numEntries = message.getInt("index"); + int numEntries = message.getInt("numEntries"); + if (numEntries > mHistorySize) { + Log.e(LOGTAG, "Received unexpectedly large number of history entries to purge"); + mHistoryIndex = -1; + mHistorySize = 0; + return; + } + mHistorySize -= numEntries; mHistoryIndex -= numEntries; - if (mHistorySize < 0 || mHistoryIndex < -1) { - Log.e(LOGTAG, "Unexpected history state: index = " + mHistoryIndex + ", size = " + mHistorySize); - mHistorySize = 0; - mHistoryIndex = -1; - } + + // If we weren't at the last history entry, mHistoryIndex may have become too small + if (mHistoryIndex < -1) + mHistoryIndex = -1; } } private void saveThumbnailToDB() { try { String url = getURL(); if (url == null) return;
--- a/mobile/android/chrome/content/WebAppRT.js +++ b/mobile/android/chrome/content/WebAppRT.js @@ -40,16 +40,21 @@ var WebAppRT = { case "boolean": Services.prefs.setBoolPref(aPref.name, aPref.value); break; case "number": Services.prefs.setIntPref(aPref.name, aPref.value); break; } }); + + // update the blocklist url to use a different app id + var blocklist = Services.prefs.getCharPref("extensions.blocklist.url"); + blocklist = blocklist.replace(/%APP_ID%/g, "webapprt-mobile@mozilla.org"); + Services.prefs.setCharPref("extensions.blocklist.url", blocklist); } }, handleEvent: function(event) { let target = event.target; if (!(target instanceof HTMLAnchorElement) || target.getAttribute("target") != "_blank") {
--- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2966,59 +2966,63 @@ Tab.prototype = { }, onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) { }, onStatusChange: function(aBrowser, aWebProgress, aRequest, aStatus, aMessage) { }, - _sendHistoryEvent: function(aMessage, aIndex, aUri) { + _sendHistoryEvent: function(aMessage, aParams) { let message = { gecko: { type: "SessionHistory:" + aMessage, tabID: this.id, } }; - if (aIndex != -1) { - message.gecko.index = aIndex; - } - if (aUri != null) { - message.gecko.uri = aUri; - } + + if (aParams) { + if ("url" in aParams) + message.gecko.url = aParams.url; + if ("index" in aParams) + message.gecko.index = aParams.index; + if ("numEntries" in aParams) + message.gecko.numEntries = aParams.numEntries; + } + sendMessageToJava(message); }, OnHistoryNewEntry: function(aUri) { - this._sendHistoryEvent("New", -1, aUri.spec); + this._sendHistoryEvent("New", { url: aUri.spec }); }, OnHistoryGoBack: function(aUri) { - this._sendHistoryEvent("Back", -1, null); + this._sendHistoryEvent("Back"); return true; }, OnHistoryGoForward: function(aUri) { - this._sendHistoryEvent("Forward", -1, null); + this._sendHistoryEvent("Forward"); return true; }, OnHistoryReload: function(aUri, aFlags) { // we don't do anything with this, so don't propagate it // for now anyway return true; }, OnHistoryGotoIndex: function(aIndex, aUri) { - this._sendHistoryEvent("Goto", aIndex, null); + this._sendHistoryEvent("Goto", { index: aIndex }); return true; }, OnHistoryPurge: function(aNumEntries) { - this._sendHistoryEvent("Purge", aNumEntries, null); + this._sendHistoryEvent("Purge", { numEntries: aNumEntries }); return true; }, get metadata() { return ViewportHandler.getMetadataForDocument(this.browser.contentDocument); }, /** Update viewport when the metadata changes. */
--- a/mobile/android/components/AboutRedirector.js +++ b/mobile/android/components/AboutRedirector.js @@ -34,27 +34,27 @@ let modules = { uri: "chrome://browser/content/aboutRights.xhtml", #else uri: "chrome://global/content/aboutRights-unbranded.xhtml", #endif privileged: false }, blocked: { uri: "chrome://browser/content/blockedSite.xhtml", - privileged: true, + privileged: false, hide: true }, certerror: { uri: "chrome://browser/content/aboutCertError.xhtml", - privileged: true, + privileged: false, hide: true }, home: { uri: "chrome://browser/content/aboutHome.xhtml", - privileged: true + privileged: false }, apps: { uri: "chrome://browser/content/aboutApps.xhtml", privileged: true }, downloads: { uri: "chrome://browser/content/aboutDownloads.xhtml", privileged: true
--- a/mobile/xul/app/nsBrowserApp.cpp +++ b/mobile/xul/app/nsBrowserApp.cpp @@ -195,28 +195,22 @@ int main(int argc, char* argv[]) strcpy(++lastSlash, XPCOM_DLL); int gotCounters; #if defined(XP_UNIX) struct rusage initialRUsage; gotCounters = !getrusage(RUSAGE_SELF, &initialRUsage); #elif defined(XP_WIN) - // GetProcessIoCounters().ReadOperationCount seems to have little to - // do with actual read operations. It reports 0 or 1 at this stage - // in the program. Luckily 1 coincides with when prefetch is - // enabled. If Windows prefetch didn't happen we can do our own - // faster dll preloading. IO_COUNTERS ioCounters; gotCounters = GetProcessIoCounters(GetCurrentProcess(), &ioCounters); - if (gotCounters && !ioCounters.ReadOperationCount) #endif - { - XPCOMGlueEnablePreload(); - } + + // We do this because of data in bug 771745 + XPCOMGlueEnablePreload(); #if MOZ_PLATFORM_MAEMO == 6 nsFastStartup startup; startup.CreateFastStartup(argc, argv, exePath, GeckoPreLoader); #else rv = XPCOMGlueStartup(exePath); if (NS_FAILED(rv)) { Output("Couldn't load XPCOM.\n");
--- a/netwerk/base/public/nsISocketTransport.idl +++ b/netwerk/base/public/nsISocketTransport.idl @@ -103,16 +103,20 @@ interface nsISocketTransport : nsITransp * is no ambiguity. * * The values of these status codes must never change. * * The status codes appear in near-chronological order (not in numeric * order). STATUS_RESOLVING may be skipped if the host does not need to be * resolved. STATUS_WAITING_FOR is an optional status code, which the impl * of this interface may choose not to generate. + * + * In C++, these constants have a type of PRUint32, so C++ callers must use + * the NS_NET_STATUS_* constants defined below, which have a type of + * nsresult. */ const unsigned long STATUS_RESOLVING = 0x804b0003; const unsigned long STATUS_RESOLVED = 0x804b000b; const unsigned long STATUS_CONNECTING_TO = 0x804b0007; const unsigned long STATUS_CONNECTED_TO = 0x804b0004; const unsigned long STATUS_SENDING_TO = 0x804b0005; const unsigned long STATUS_WAITING_FOR = 0x804b000a; const unsigned long STATUS_RECEIVING_FROM = 0x804b0006; @@ -155,18 +159,25 @@ interface nsISocketTransport : nsITransp * IPTOS_PREC_ROUTINE). */ attribute octet QoSBits; }; %{C++ /** - * #define's for compatibility + * #define's with the correct type, for use by C++ code */ -#define NS_NET_STATUS_RESOLVING_HOST nsISocketTransport::STATUS_RESOLVING -#define NS_NET_STATUS_RESOLVED_HOST nsISocketTransport::STATUS_RESOLVED -#define NS_NET_STATUS_CONNECTED_TO nsISocketTransport::STATUS_CONNECTED_TO -#define NS_NET_STATUS_SENDING_TO nsISocketTransport::STATUS_SENDING_TO -#define NS_NET_STATUS_RECEIVING_FROM nsISocketTransport::STATUS_RECEIVING_FROM -#define NS_NET_STATUS_CONNECTING_TO nsISocketTransport::STATUS_CONNECTING_TO -#define NS_NET_STATUS_WAITING_FOR nsISocketTransport::STATUS_WAITING_FOR +#define NS_NET_STATUS_RESOLVING_HOST \ + static_cast<nsresult>(nsISocketTransport::STATUS_RESOLVING) +#define NS_NET_STATUS_RESOLVED_HOST \ + static_cast<nsresult>(nsISocketTransport::STATUS_RESOLVED) +#define NS_NET_STATUS_CONNECTED_TO \ + static_cast<nsresult>(nsISocketTransport::STATUS_CONNECTED_TO) +#define NS_NET_STATUS_SENDING_TO \ + static_cast<nsresult>(nsISocketTransport::STATUS_SENDING_TO) +#define NS_NET_STATUS_RECEIVING_FROM \ + static_cast<nsresult>(nsISocketTransport::STATUS_RECEIVING_FROM) +#define NS_NET_STATUS_CONNECTING_TO \ + static_cast<nsresult>(nsISocketTransport::STATUS_CONNECTING_TO) +#define NS_NET_STATUS_WAITING_FOR \ + static_cast<nsresult>(nsISocketTransport::STATUS_WAITING_FOR) %}
--- a/netwerk/base/public/nsITransport.idl +++ b/netwerk/base/public/nsITransport.idl @@ -123,16 +123,20 @@ interface nsITransport : nsISupports */ void setEventSink(in nsITransportEventSink aSink, in nsIEventTarget aEventTarget); /** * Generic nsITransportEventSink status codes. nsITransport * implementations may override these status codes with their own more * specific status codes (e.g., see nsISocketTransport). + * + * In C++, these constants have a type of PRUint32, so C++ callers must use + * the NS_NET_STATUS_* constants defined below, which have a type of + * nsresult. */ const unsigned long STATUS_READING = 0x804b0008; const unsigned long STATUS_WRITING = 0x804b0009; }; [scriptable, uuid(EDA4F520-67F7-484b-A691-8C3226A5B0A6)] interface nsITransportEventSink : nsISupports { @@ -152,8 +156,15 @@ interface nsITransportEventSink : nsISup * the maximum amount of data that will be read or written. if * unknown, 0xFFFFFFFF will be passed. */ void onTransportStatus(in nsITransport aTransport, in nsresult aStatus, in unsigned long long aProgress, in unsigned long long aProgressMax); }; + +%{C++ +#define NS_NET_STATUS_READING \ + static_cast<nsresult>(nsITransport::STATUS_READING) +#define NS_NET_STATUS_WRITING \ + static_cast<nsresult>(nsITransport::STATUS_WRITING) +%}
--- a/netwerk/base/src/nsBaseChannel.cpp +++ b/netwerk/base/src/nsBaseChannel.cpp @@ -743,17 +743,17 @@ nsBaseChannel::OnDataAvailable(nsIReques { SUSPEND_PUMP_FOR_SCOPE(); nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream, offset, count); if (mSynthProgressEvents && NS_SUCCEEDED(rv)) { PRUint64 prog = PRUint64(offset) + count; PRUint64 progMax = ContentLength64(); - OnTransportStatus(nullptr, nsITransport::STATUS_READING, prog, progMax); + OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, progMax); } return rv; } NS_IMETHODIMP nsBaseChannel::OnRedirectVerifyCallback(nsresult result) {
--- a/netwerk/base/src/nsSocketTransport2.cpp +++ b/netwerk/base/src/nsSocketTransport2.cpp @@ -353,17 +353,17 @@ nsSocketInputStream::Read(char *buf, PRU rv = mCondition; } if (NS_FAILED(rv)) mTransport->OnInputClosed(rv); // only send this notification if we have indeed read some data. // see bug 196827 for an example of why this is important. if (n > 0) - mTransport->SendStatus(nsISocketTransport::STATUS_RECEIVING_FROM); + mTransport->SendStatus(NS_NET_STATUS_RECEIVING_FROM); return rv; } NS_IMETHODIMP nsSocketInputStream::ReadSegments(nsWriteSegmentFun writer, void *closure, PRUint32 count, PRUint32 *countRead) { // socket stream is unbuffered @@ -576,17 +576,17 @@ nsSocketOutputStream::Write(const char * rv = mCondition; } if (NS_FAILED(rv)) mTransport->OnOutputClosed(rv); // only send this notification if we have indeed written some data. // see bug 196827 for an example of why this is important. if (n > 0) - mTransport->SendStatus(nsISocketTransport::STATUS_SENDING_TO); + mTransport->SendStatus(NS_NET_STATUS_SENDING_TO); return rv; } NS_IMETHODIMP nsSocketOutputStream::WriteSegments(nsReadSegmentFun reader, void *closure, PRUint32 count, PRUint32 *countRead) { // socket stream is unbuffered @@ -864,20 +864,20 @@ nsSocketTransport::SendStatus(nsresult s SOCKET_LOG(("nsSocketTransport::SendStatus [this=%x status=%x]\n", this, status)); nsCOMPtr<nsITransportEventSink> sink; PRUint64 progress; { MutexAutoLock lock(mLock); sink = mEventSink; switch (status) { - case STATUS_SENDING_TO: + case NS_NET_STATUS_SENDING_TO: progress = mOutput.ByteCount(); break; - case STATUS_RECEIVING_FROM: + case NS_NET_STATUS_RECEIVING_FROM: progress = mInput.ByteCount(); break; default: progress = 0; break; } } if (sink) @@ -918,17 +918,17 @@ nsSocketTransport::ResolveHost() mResolving = true; PRUint32 dnsFlags = 0; if (mConnectionFlags & nsSocketTransport::BYPASS_CACHE) dnsFlags = nsIDNSService::RESOLVE_BYPASS_CACHE; if (mConnectionFlags & nsSocketTransport::DISABLE_IPV6) dnsFlags |= nsIDNSService::RESOLVE_DISABLE_IPV6; - SendStatus(STATUS_RESOLVING); + SendStatus(NS_NET_STATUS_RESOLVING_HOST); rv = dns->AsyncResolve(SocketHost(), dnsFlags, this, nullptr, getter_AddRefs(mDNSRequest)); if (NS_SUCCEEDED(rv)) { SOCKET_LOG((" advancing to STATE_RESOLVING\n")); mState = STATE_RESOLVING; } return rv; } @@ -1139,17 +1139,17 @@ nsSocketTransport::InitiateSocket() mFD = fd; mFDref = 1; mFDconnected = false; } SOCKET_LOG((" advancing to STATE_CONNECTING\n")); mState = STATE_CONNECTING; mPollTimeout = mTimeouts[TIMEOUT_CONNECT]; - SendStatus(STATUS_CONNECTING_TO); + SendStatus(NS_NET_STATUS_CONNECTING_TO); #if defined(PR_LOGGING) if (SOCKET_LOG_ENABLED()) { char buf[64]; PR_NetAddrToString(&mNetAddr, buf, sizeof(buf)); SOCKET_LOG((" trying address: %s\n", buf)); } #endif @@ -1376,17 +1376,17 @@ nsSocketTransport::OnSocketConnected() // to trample over mFDref if mFD is already set. { MutexAutoLock lock(mLock); NS_ASSERTION(mFD, "no socket"); NS_ASSERTION(mFDref == 1, "wrong socket ref count"); mFDconnected = true; } - SendStatus(STATUS_CONNECTED_TO); + SendStatus(NS_NET_STATUS_CONNECTED_TO); } PRFileDesc * nsSocketTransport::GetFD_Locked() { // mFD is not available to the streams while disconnected. if (!mFDconnected) return nullptr; @@ -1439,17 +1439,17 @@ nsSocketTransport::OnSocketEvent(PRUint3 if (mState == STATE_CLOSED) mCondition = ResolveHost(); else SOCKET_LOG((" ignoring redundant event\n")); break; case MSG_DNS_LOOKUP_COMPLETE: if (mDNSRequest) // only send this if we actually resolved anything - SendStatus(STATUS_RESOLVED); + SendStatus(NS_NET_STATUS_RESOLVED_HOST); SOCKET_LOG((" MSG_DNS_LOOKUP_COMPLETE\n")); mDNSRequest = 0; if (param) { mDNSRecord = static_cast<nsIDNSRecord *>(param); mDNSRecord->GetNextAddr(SocketPort(), &mNetAddr); } // status contains DNS lookup status
--- a/netwerk/base/src/nsStreamTransportService.cpp +++ b/netwerk/base/src/nsStreamTransportService.cpp @@ -195,17 +195,18 @@ nsInputStreamTransport::Read(char *buf, if (count > max) count = max; nsresult rv = mSource->Read(buf, count, result); if (NS_SUCCEEDED(rv)) { mOffset += *result; if (mEventSink) - mEventSink->OnTransportStatus(this, STATUS_READING, mOffset, mLimit); + mEventSink->OnTransportStatus(this, NS_NET_STATUS_READING, mOffset, + mLimit); } return rv; } NS_IMETHODIMP nsInputStreamTransport::ReadSegments(nsWriteSegmentFun writer, void *closure, PRUint32 count, PRUint32 *result) { @@ -394,17 +395,18 @@ nsOutputStreamTransport::Write(const cha if (count > max) count = max; nsresult rv = mSink->Write(buf, count, result); if (NS_SUCCEEDED(rv)) { mOffset += *result; if (mEventSink) - mEventSink->OnTransportStatus(this, STATUS_WRITING, mOffset, mLimit); + mEventSink->OnTransportStatus(this, NS_NET_STATUS_WRITING, mOffset, + mLimit); } return rv; } NS_IMETHODIMP nsOutputStreamTransport::WriteSegments(nsReadSegmentFun reader, void *closure, PRUint32 count, PRUint32 *result) {
--- a/netwerk/protocol/file/nsFileChannel.cpp +++ b/netwerk/protocol/file/nsFileChannel.cpp @@ -94,17 +94,17 @@ nsFileCopyEvent::DoCopy() if (result != (PRUint32) num) { rv = NS_ERROR_FILE_DISK_FULL; // stopped prematurely (out of disk space) break; } // Dispatch progress notification if (mSink) { progress += num; - mSink->OnTransportStatus(nullptr, nsITransport::STATUS_WRITING, progress, + mSink->OnTransportStatus(nullptr, NS_NET_STATUS_WRITING, progress, mLen); } len -= num; } if (NS_FAILED(rv)) mStatus = rv;
--- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -358,18 +358,18 @@ HttpChannelChild::OnTransportAndData(con // - JDUELL: may not need mStatus/mIsPending checks, given this is always called // during OnDataAvailable, and we've already checked mCanceled. Code // dupe'd from nsHttpChannel if (mProgressSink && NS_SUCCEEDED(mStatus) && mIsPending && !(mLoadFlags & LOAD_BACKGROUND)) { // OnStatus // - NS_ASSERTION(status == nsISocketTransport::STATUS_RECEIVING_FROM || - status == nsITransport::STATUS_READING, + NS_ASSERTION(status == NS_NET_STATUS_RECEIVING_FROM || + status == NS_NET_STATUS_READING, "unexpected status code"); nsCAutoString host; mURI->GetHost(host); mProgressSink->OnStatus(this, nullptr, status, NS_ConvertUTF8toUTF16(host).get()); // OnProgress //
--- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -24,17 +24,17 @@ #include "nsIRedirectChannelRegistrar.h" #include "prinit.h" namespace mozilla { namespace net { HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding) : mIPCClosed(false) - , mStoredStatus(0) + , mStoredStatus(NS_OK) , mStoredProgress(0) , mStoredProgressMax(0) , mSentRedirect1Begin(false) , mSentRedirect1BeginFailed(false) , mReceivedRedirect2Verify(false) , mHaveLoadContext(false) , mIsContent(false) , mUsePrivateBrowsing(false) @@ -504,41 +504,41 @@ HttpChannelParent::OnDataAvailable(nsIRe NS_IMETHODIMP HttpChannelParent::OnProgress(nsIRequest *aRequest, nsISupports *aContext, PRUint64 aProgress, PRUint64 aProgressMax) { // OnStatus has always just set mStoredStatus. If it indicates this precedes // OnDataAvailable, store and ODA will send to child. - if (mStoredStatus == nsISocketTransport::STATUS_RECEIVING_FROM || - mStoredStatus == nsITransport::STATUS_READING) + if (mStoredStatus == NS_NET_STATUS_RECEIVING_FROM || + mStoredStatus == NS_NET_STATUS_READING) { mStoredProgress = aProgress; mStoredProgressMax = aProgressMax; } else { // Send to child now. The only case I've observed that this handles (i.e. // non-ODA status with progress > 0) is data upload progress notification - // (status == nsISocketTransport::STATUS_SENDING_TO) + // (status == NS_NET_STATUS_SENDING_TO) if (mIPCClosed || !SendOnProgress(aProgress, aProgressMax)) return NS_ERROR_UNEXPECTED; } return NS_OK; } NS_IMETHODIMP HttpChannelParent::OnStatus(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatus, const PRUnichar *aStatusArg) { // If this precedes OnDataAvailable, store and ODA will send to child. - if (aStatus == nsISocketTransport::STATUS_RECEIVING_FROM || - aStatus == nsITransport::STATUS_READING) + if (aStatus == NS_NET_STATUS_RECEIVING_FROM || + aStatus == NS_NET_STATUS_READING) { mStoredStatus = aStatus; return NS_OK; } // Otherwise, send to child now if (mIPCClosed || !SendOnStatus(aStatus)) return NS_ERROR_UNEXPECTED; return NS_OK;
--- a/netwerk/protocol/http/nsHttpBasicAuth.cpp +++ b/netwerk/protocol/http/nsHttpBasicAuth.cpp @@ -84,13 +84,13 @@ nsHttpBasicAuth::GenerateCredentials(nsI return NS_ERROR_OUT_OF_MEMORY; memcpy(*creds, "Basic ", 6); PL_Base64Encode(userpass.get(), userpass.Length(), *creds + 6); return NS_OK; } NS_IMETHODIMP -nsHttpBasicAuth::GetAuthFlags(nsresult *flags) +nsHttpBasicAuth::GetAuthFlags(PRUint32 *flags) { *flags = REQUEST_BASED | REUSABLE_CREDENTIALS | REUSABLE_CHALLENGE; return NS_OK; }
--- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -5049,19 +5049,19 @@ nsHttpChannel::OnDataAvailable(nsIReques if (mListener) { // // synthesize transport progress event. we do this here since we want // to delay OnProgress events until we start streaming data. this is // crucially important since it impacts the lock icon (see bug 240053). // nsresult transportStatus; if (request == mCachePump) - transportStatus = nsITransport::STATUS_READING; + transportStatus = NS_NET_STATUS_READING; else - transportStatus = nsISocketTransport::STATUS_RECEIVING_FROM; + transportStatus = NS_NET_STATUS_RECEIVING_FROM; // mResponseHead may reference new or cached headers, but either way it // holds our best estimate of the total content length. Even in the case // of a byte range request, the content length stored in the cached // response headers is what we want to use here. PRUint64 progressMax(PRUint64(mResponseHead->ContentLength())); PRUint64 progress = mLogicalOffset + PRUint64(count); @@ -5103,18 +5103,18 @@ nsHttpChannel::OnDataAvailable(nsIReques NS_IMETHODIMP nsHttpChannel::OnTransportStatus(nsITransport *trans, nsresult status, PRUint64 progress, PRUint64 progressMax) { // cache the progress sink so we don't have to query for it each time. if (!mProgressSink) GetCallback(mProgressSink); - if (status == nsISocketTransport::STATUS_CONNECTED_TO || - status == nsISocketTransport::STATUS_WAITING_FOR) { + if (status == NS_NET_STATUS_CONNECTED_TO || + status == NS_NET_STATUS_WAITING_FOR) { nsCOMPtr<nsISocketTransport> socketTransport = do_QueryInterface(trans); if (socketTransport) { socketTransport->GetSelfAddr(&mSelfAddr); socketTransport->GetPeerAddr(&mPeerAddr); } }
--- a/netwerk/protocol/http/nsHttpConnection.cpp +++ b/netwerk/protocol/http/nsHttpConnection.cpp @@ -1262,17 +1262,17 @@ nsHttpConnection::OnSocketWritable() else if (n == 0) { // // at this point we've written out the entire transaction, and now we // must wait for the server's response. we manufacture a status message // here to reflect the fact that we are waiting. this message will be // trumped (overwritten) if the server responds quickly. // mTransaction->OnTransportStatus(mSocketTransport, - nsISocketTransport::STATUS_WAITING_FOR, + NS_NET_STATUS_WAITING_FOR, LL_ZERO); rv = ResumeRecv(); // start reading again = false; } // write more to the socket until error or end-of-request... } while (again);
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -292,17 +292,18 @@ nsHttpConnectionMgr::RescheduleTransacti } nsresult nsHttpConnectionMgr::CancelTransaction(nsHttpTransaction *trans, nsresult reason) { LOG(("nsHttpConnectionMgr::CancelTransaction [trans=%x reason=%x]\n", trans, reason)); NS_ADDREF(trans); - nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction, reason, trans); + nsresult rv = PostEvent(&nsHttpConnectionMgr::OnMsgCancelTransaction, + static_cast<PRInt32>(reason), trans); if (NS_FAILED(rv)) NS_RELEASE(trans); return rv; } nsresult nsHttpConnectionMgr::PruneDeadConnections() { @@ -1874,38 +1875,39 @@ nsHttpConnectionMgr::OnMsgReschedTransac } void nsHttpConnectionMgr::OnMsgCancelTransaction(PRInt32 reason, void *param) { NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); LOG(("nsHttpConnectionMgr::OnMsgCancelTransaction [trans=%p]\n", param)); + nsresult closeCode = static_cast<nsresult>(reason); nsHttpTransaction *trans = (nsHttpTransaction *) param; // // if the transaction owns a connection and the transaction is not done, // then ask the connection to close the transaction. otherwise, close the // transaction directly (removing it from the pending queue first). // nsAHttpConnection *conn = trans->Connection(); if (conn && !trans->IsDone()) - conn->CloseTransaction(trans, reason); + conn->CloseTransaction(trans, closeCode); else { nsConnectionEntry *ent = LookupConnectionEntry(trans->ConnectionInfo(), nullptr, trans); if (ent) { PRInt32 index = ent->mPendingQ.IndexOf(trans); if (index >= 0) { ent->mPendingQ.RemoveElementAt(index); nsHttpTransaction *temp = trans; NS_RELEASE(temp); // b/c NS_RELEASE nulls its argument! } } - trans->Close(reason); + trans->Close(closeCode); } NS_RELEASE(trans); } void nsHttpConnectionMgr::OnMsgProcessPendingQ(PRInt32, void *param) { NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread"); @@ -2689,17 +2691,17 @@ nsHttpConnectionMgr::nsHalfOpenSocket::O if (trans != mSocketTransport) return NS_OK; // if we are doing spdy coalescing and haven't recorded the ip address // for this entry before then make the hash key if our dns lookup // just completed. We can't do coalescing if using a proxy because the // ip addresses are not available to the client. - if (status == nsISocketTransport::STATUS_CONNECTED_TO && + if (status == NS_NET_STATUS_CONNECTED_TO && gHttpHandler->IsSpdyEnabled() && gHttpHandler->CoalesceSpdy() && mEnt && mEnt->mConnInfo && mEnt->mConnInfo->UsingSSL() && !mEnt->mConnInfo->UsingHttpProxy() && mEnt->mCoalescingKey.IsEmpty()) { PRNetAddr addr; nsresult rv = mSocketTransport->GetPeerAddr(&addr); @@ -2720,30 +2722,30 @@ nsHttpConnectionMgr::nsHalfOpenSocket::O "%s [%s]", mEnt->mConnInfo->Host(), mEnt->mCoalescingKey.get())); gHttpHandler->ConnMgr()->ProcessSpdyPendingQ(mEnt); } } switch (status) { - case nsISocketTransport::STATUS_CONNECTING_TO: + case NS_NET_STATUS_CONNECTING_TO: // Passed DNS resolution, now trying to connect, start the backup timer // only prevent creating another backup transport. // We also check for mEnt presence to not instantiate the timer after // this half open socket has already been abandoned. It may happen // when we get this notification right between main-thread calls to // nsHttpConnectionMgr::Shutdown and nsSocketTransportService::Shutdown // where the first abandones all half open socket instances and only // after that the second stops the socket thread. if (mEnt && !mBackupTransport && !mSynTimer) SetupBackupTimer(); break; - case nsISocketTransport::STATUS_CONNECTED_TO: + case NS_NET_STATUS_CONNECTED_TO: // TCP connection's up, now transfer or SSL negotiantion starts, // no need for backup socket CancelBackupTimer(); break; default: break; }
--- a/netwerk/protocol/http/nsHttpPipeline.cpp +++ b/netwerk/protocol/http/nsHttpPipeline.cpp @@ -696,18 +696,17 @@ nsHttpPipeline::WriteSegments(nsAHttpSeg PRUint32 len = mPushBackLen, n; mPushBackLen = 0; // This progress notification has previously been sent from // the socket transport code, but it was delivered to the // previous transaction on the pipeline. nsITransport *transport = Transport(); if (transport) - OnTransportStatus(transport, - nsISocketTransport::STATUS_RECEIVING_FROM, + OnTransportStatus(transport, NS_NET_STATUS_RECEIVING_FROM, mReceivingFromProgress); // the push back buffer is never larger than NS_HTTP_SEGMENT_SIZE, // so we are guaranteed that the next response will eat the entire // push back buffer (even though it might again call PushBack). rv = WriteSegments(&writer, len, &n); }
--- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -399,38 +399,38 @@ nsHttpTransaction::GetSecurityCallbacks( void nsHttpTransaction::OnTransportStatus(nsITransport* transport, nsresult status, PRUint64 progress) { LOG(("nsHttpTransaction::OnSocketStatus [this=%x status=%x progress=%llu]\n", this, status, progress)); if (TimingEnabled()) { - if (status == nsISocketTransport::STATUS_RESOLVING) { + if (status == NS_NET_STATUS_RESOLVING_HOST) { mTimings.domainLookupStart = mozilla::TimeStamp::Now(); - } else if (status == nsISocketTransport::STATUS_RESOLVED) { + } else if (status == NS_NET_STATUS_RESOLVED_HOST) { mTimings.domainLookupEnd = mozilla::TimeStamp::Now(); - } else if (status == nsISocketTransport::STATUS_CONNECTING_TO) { + } else if (status == NS_NET_STATUS_CONNECTING_TO) { mTimings.connectStart = mozilla::TimeStamp::Now(); - } else if (status == nsISocketTransport::STATUS_CONNECTED_TO) { + } else if (status == NS_NET_STATUS_CONNECTED_TO) { mTimings.connectEnd = mozilla::TimeStamp::Now(); } } if (!mTransportSink) return; NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread"); // Need to do this before the STATUS_RECEIVING_FROM check below, to make // sure that the activity distributor gets told about all status events. if (mActivityDistributor) { // upon STATUS_WAITING_FOR; report request body sent if ((mHasRequestBody) && - (status == nsISocketTransport::STATUS_WAITING_FOR)) + (status == NS_NET_STATUS_WAITING_FOR)) mActivityDistributor->ObserveActivity( mChannel, NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION, NS_HTTP_ACTIVITY_SUBTYPE_REQUEST_BODY_SENT, PR_Now(), LL_ZERO, EmptyCString()); // report the status and progress if (!mRestartInProgressVerifier.IsDiscardingContent()) @@ -439,22 +439,22 @@ nsHttpTransaction::OnTransportStatus(nsI NS_HTTP_ACTIVITY_TYPE_SOCKET_TRANSPORT, static_cast<PRUint32>(status), PR_Now(), progress, EmptyCString()); } // nsHttpChannel synthesizes progress events in OnDataAvailable - if (status == nsISocketTransport::STATUS_RECEIVING_FROM) + if (status == NS_NET_STATUS_RECEIVING_FROM) return; PRUint64 progressMax; - if (status == nsISocketTransport::STATUS_SENDING_TO) { + if (status == NS_NET_STATUS_SENDING_TO) { // suppress progress when only writing request headers if (!mHasRequestBody) return; nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mRequestStream); NS_ASSERTION(seekable, "Request stream isn't seekable?!?"); PRInt64 prog = 0;
--- a/nsprpub/pr/include/prinit.h +++ b/nsprpub/pr/include/prinit.h @@ -26,21 +26,21 @@ PR_BEGIN_EXTERN_C /* ** NSPR's version is used to determine the likelihood that the version you ** used to build your component is anywhere close to being compatible with ** what is in the underlying library. ** ** The format of the version string is ** "<major version>.<minor version>[.<patch level>] [<Beta>]" */ -#define PR_VERSION "4.9.2 Beta" +#define PR_VERSION "4.9.2" #define PR_VMAJOR 4 #define PR_VMINOR 9 #define PR_VPATCH 2 -#define PR_BETA PR_TRUE +#define PR_BETA PR_FALSE /* ** PRVersionCheck ** ** The basic signature of the function that is called to provide version ** checking. The result will be a boolean that indicates the likelihood ** that the underling library will perform as the caller expects. **
--- a/nsprpub/pr/src/pthreads/ptthread.c +++ b/nsprpub/pr/src/pthreads/ptthread.c @@ -1638,41 +1638,46 @@ PR_IMPLEMENT(PRStatus) PR_SetCurrentThre memcpy(thread->name, name, nameLen + 1); #if defined(OPENBSD) || defined(FREEBSD) result = pthread_set_name_np(thread->id, name); #else /* not BSD */ /* * On OSX, pthread_setname_np is only available in 10.6 or later, so test * for it at runtime. It also may not be available on all linux distros. - * The name length limit is 16 bytes. */ #if defined(DARWIN) int (*dynamic_pthread_setname_np)(const char*); #else int (*dynamic_pthread_setname_np)(pthread_t, const char*); #endif *(void**)(&dynamic_pthread_setname_np) = dlsym(RTLD_DEFAULT, "pthread_setname_np"); if (!dynamic_pthread_setname_np) return PR_SUCCESS; + /* + * The 15-character name length limit is an experimentally determined + * length of a null-terminated string that most linux distros and OS X + * accept as an argument to pthread_setname_np. Otherwise the E2BIG + * error is returned by the function. + */ #define SETNAME_LENGTH_CONSTRAINT 15 #define SETNAME_FRAGMENT1_LENGTH (SETNAME_LENGTH_CONSTRAINT >> 1) #define SETNAME_FRAGMENT2_LENGTH \ (SETNAME_LENGTH_CONSTRAINT - SETNAME_FRAGMENT1_LENGTH - 1) char name_dup[SETNAME_LENGTH_CONSTRAINT + 1]; if (nameLen > SETNAME_LENGTH_CONSTRAINT) { memcpy(name_dup, name, SETNAME_FRAGMENT1_LENGTH); name_dup[SETNAME_FRAGMENT1_LENGTH] = '~'; + /* Note that this also copies the null terminator. */ memcpy(name_dup + SETNAME_FRAGMENT1_LENGTH + 1, name + nameLen - SETNAME_FRAGMENT2_LENGTH, - SETNAME_FRAGMENT2_LENGTH); - name_dup[SETNAME_LENGTH_CONSTRAINT] = '\0'; + SETNAME_FRAGMENT2_LENGTH + 1); name = name_dup; } #if defined(DARWIN) result = dynamic_pthread_setname_np(name); #else result = dynamic_pthread_setname_np(thread->id, name); #endif
--- a/testing/mochitest/dynamic/getMyDirectory.sjs +++ b/testing/mochitest/dynamic/getMyDirectory.sjs @@ -1,14 +1,14 @@ function handleRequest(request, response) { var file; getObjectState("SERVER_ROOT", function(serverRoot) { - var ref = request.getHeader("Referer"); + var ref = request.getHeader("Referer").split("?")[0]; // 8 is "https://".length which is the longest string before the host. var pathStart = ref.indexOf("/", 8) + 1; var pathEnd = ref.lastIndexOf("/") + 1; file = serverRoot.getFile(ref.substring(pathStart, pathEnd) + "x"); }); response.setHeader("Content-Type", "text/plain", false); response.write(file.path.substr(0, file.path.length-1));
--- a/testing/mozbase/README +++ b/testing/mozbase/README @@ -1,9 +1,27 @@ -This is the git repo for the Mozilla mozbase suite of python utilities. +This is the git repository for the Mozilla mozbase suite of python utilities. + +MozBase is composed of several python packages. These packages work +together to form the basis of a test harness. + +* Firefox is launched via [mozrunner](https://github.com/mozilla/mozbase/tree/master/mozrunner) +** which sets up a profile with preferences and extensions using + [mozprofile ](https://github.com/mozilla/mozbase/tree/master/mozprofile) +** and runs the application under test using [mozprocess](https://github.com/mozilla/mozbase/tree/master/mozprocess) +* [mozInstall](https://github.com/mozilla/mozbase/tree/master/mozinstall) is used to install the test application +* A test harness may direct Firefox to load web pages. These may be + served using [mozhttpd](https://github.com/mozilla/mozbase/tree/master/mozhttpd) for testing +* The machine environment is introspected by [mozinfo](https://github.com/mozilla/mozbase/tree/master/mozinfo) +* A test manifest may be read to determine the tests to be run. These + manifests are processed by [ManifestDestiny](https://github.com/mozilla/mozbase/tree/master/manifestdestiny) +* For mozbile testing, the test runner communicates to the test agent + using [mozdevice](https://github.com/mozilla/mozbase/tree/master/mozdevice) + (Note that the canonical location of mozdevice is + mozilla-central: http://mxr.mozilla.org/mozilla-central/source/build/mobile/) Learn more about mozbase here: https://wiki.mozilla.org/Auto-tools/Projects/MozBase Bugs live at https://bugzilla.mozilla.org/buglist.cgi?resolution=---&component=Mozbase&product=Testing and https://bugzilla.mozilla.org/buglist.cgi?resolution=---&status_whiteboard_type=allwordssubstr&query_format=advanced&status_whiteboard=mozbase To file a bug, go to
--- a/testing/mozbase/mozprocess/mozprocess/processhandler.py +++ b/testing/mozbase/mozprocess/mozprocess/processhandler.py @@ -557,16 +557,17 @@ falling back to not using job objects fo will be logged. """ self.cmd = cmd self.args = args self.cwd = cwd self.didTimeout = False self._ignore_children = ignore_children self.keywordargs = kwargs + self.outThread = None if env is None: env = os.environ.copy() self.env = env # handlers self.processOutputLineHandlers = list(processOutputLine) self.onTimeoutHandlers = list(onTimeout) @@ -642,55 +643,79 @@ falling back to not using job objects fo for handler in self.onTimeoutHandlers: handler() def onFinish(self): """Called when a process finishes without a timeout.""" for handler in self.onFinishHandlers: handler() - def waitForFinish(self, timeout=None, outputTimeout=None): + def processOutput(self, timeout=None, outputTimeout=None): """ Handle process output until the process terminates or times out. If timeout is not None, the process will be allowed to continue for that number of seconds before being killed. If outputTimeout is not None, the process will be allowed to continue for that number of seconds without producing any output before being killed. """ - - if not hasattr(self, 'proc'): - self.run() - - self.didTimeout = False - logsource = self.proc.stdout + def _processOutput(): + if not hasattr(self, 'proc'): + self.run() - lineReadTimeout = None - if timeout: - lineReadTimeout = timeout - (datetime.now() - self.startTime).seconds - elif outputTimeout: - lineReadTimeout = outputTimeout + self.didTimeout = False + logsource = self.proc.stdout - (line, self.didTimeout) = self.readWithTimeout(logsource, lineReadTimeout) - while line != "" and not self.didTimeout: - self.processOutputLine(line.rstrip()) + lineReadTimeout = None if timeout: lineReadTimeout = timeout - (datetime.now() - self.startTime).seconds + elif outputTimeout: + lineReadTimeout = outputTimeout + (line, self.didTimeout) = self.readWithTimeout(logsource, lineReadTimeout) + while line != "" and not self.didTimeout: + self.processOutputLine(line.rstrip()) + if timeout: + lineReadTimeout = timeout - (datetime.now() - self.startTime).seconds + (line, self.didTimeout) = self.readWithTimeout(logsource, lineReadTimeout) + + if self.didTimeout: + self.proc.kill() + self.onTimeout() + else: + self.onFinish() + + if not self.outThread: + self.outThread = threading.Thread(target=_processOutput) + self.outThread.daemon = True + self.outThread.start() - if self.didTimeout: - self.proc.kill() - self.onTimeout() - else: - self.onFinish() + + def waitForFinish(self, timeout=None): + """ + Waits until all output has been read and the process is + terminated. - status = self.proc.wait() - return status + If timeout is not None, will return after timeout seconds. + This timeout is only for waitForFinish and doesn't affect + the didTimeout or onTimeout properties. + """ + if self.outThread: + # Thread.join() blocks the main thread until outThread is finished + # wake up once a second in case a keyboard interrupt is sent + count = 0 + while self.outThread.isAlive(): + self.outThread.join(timeout=1) + count += 1 + if timeout and count > timeout: + return + + return self.proc.wait() ### Private methods from here on down. Thar be dragons. if mozinfo.isWin: # Windows Specific private functions are defined in this block PeekNamedPipe = ctypes.windll.kernel32.PeekNamedPipe GetLastError = ctypes.windll.kernel32.GetLastError @@ -757,17 +782,16 @@ class LogOutput(object): self.file = file(self.filename, 'a') self.file.write(line + '\n') self.file.flush() def __del__(self): if self.file is not None: self.file.close() - ### front end class with the default handlers class ProcessHandler(ProcessHandlerMixin): def __init__(self, cmd, logfile=None, storeOutput=True, **kwargs): """ If storeOutput=True, the output produced by the process will be saved as self.output.
--- a/testing/mozbase/mozprocess/tests/mozprocess1.py +++ b/testing/mozbase/mozprocess/tests/mozprocess1.py @@ -41,30 +41,30 @@ def check_for_process(processName): output -- if process exists, stdout of the process, '' otherwise """ output = '' if sys.platform == "win32": # On windows we use tasklist p1 = subprocess.Popen(["tasklist"], stdout=subprocess.PIPE) output = p1.communicate()[0] detected = False - for line in output: + for line in output.splitlines(): if processName in line: detected = True break else: - p1 = subprocess.Popen(["ps", "-A"], stdout=subprocess.PIPE) + p1 = subprocess.Popen(["ps", "-ef"], stdout=subprocess.PIPE) p2 = subprocess.Popen(["grep", processName], stdin=p1.stdout, stdout=subprocess.PIPE) p1.stdout.close() output = p2.communicate()[0] detected = False - for line in output: + for line in output.splitlines(): if "grep %s" % processName in line: continue - elif processName in line: + elif processName in line and not 'defunct' in line: detected = True break return detected, output class ProcTest1(unittest.TestCase): @@ -76,47 +76,50 @@ class ProcTest1(unittest.TestCase): unittest.TestCase.__init__(self, *args, **kwargs) def test_process_normal_finish(self): """Process is started, runs to completion while we wait for it""" p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"], cwd=here) p.run() + p.processOutput() p.waitForFinish() detected, output = check_for_process(self.proclaunch) self.determine_status(detected, output, p.proc.returncode, p.didTimeout) def test_process_waittimeout(self): """ Process is started, runs but we time out waiting on it to complete """ p = processhandler.ProcessHandler([self.proclaunch, "process_waittimeout.ini"], cwd=here) p.run() - p.waitForFinish(timeout=10) + p.processOutput(timeout=10) + p.waitForFinish() detected, output = check_for_process(self.proclaunch) self.determine_status(detected, output, p.proc.returncode, p.didTimeout, False, ['returncode', 'didtimeout']) def test_process_kill(self): """ Process is started, we kill it """ p = processhandler.ProcessHandler([self.proclaunch, "process_normal_finish.ini"], cwd=here) p.run() + p.processOutput() p.kill() detected, output = check_for_process(self.proclaunch) self.determine_status(detected, output, p.proc.returncode, p.didTimeout) @@ -134,24 +137,24 @@ class ProcTest1(unittest.TestCase): output -- string of data from detected process, can be '' returncode -- return code from process, defaults to 0 didtimeout -- True if process timed out, defaults to False isalive -- Use True to indicate we pass if the process exists; however, by default the test will pass if the process does not exist (isalive == False) expectedfail -- Defaults to [], used to indicate a list of fields that are expected to fail """ if 'returncode' in expectedfail: - self.assertTrue(returncode, "Detected an expected non-zero return code") - else: + self.assertTrue(returncode, "Detected an unexpected return code of: %s" % returncode) + elif not isalive: self.assertTrue(returncode == 0, "Detected non-zero return code of: %d" % returncode) if 'didtimeout' in expectedfail: - self.assertTrue(didtimeout, "Process timed out as expected") + self.assertTrue(didtimeout, "Detected that process didn't time out") else: self.assertTrue(not didtimeout, "Detected that process timed out") - if detected: - self.assertTrue(isalive, "Detected process is still running, process output: %s" % output) + if isalive: + self.assertTrue(detected, "Detected process is not running, process output: %s" % output) else: - self.assertTrue(not isalive, "Process ended") + self.assertTrue(not detected, "Detected process is still running, process output: %s" % output) if __name__ == '__main__': unittest.main()
--- a/testing/mozbase/mozprocess/tests/mozprocess2.py +++ b/testing/mozbase/mozprocess/tests/mozprocess2.py @@ -46,75 +46,97 @@ def check_for_process(processName): output -- if process exists, stdout of the process, '' otherwise """ output = '' if sys.platform == "win32": # On windows we use tasklist p1 = subprocess.Popen(["tasklist"], stdout=subprocess.PIPE) output = p1.communicate()[0] detected = False - for line in output: + for line in output.splitlines(): if processName in line: detected = True break else: - p1 = subprocess.Popen(["ps", "-A"], stdout=subprocess.PIPE) + p1 = subprocess.Popen(["ps", "-ef"], stdout=subprocess.PIPE) p2 = subprocess.Popen(["grep", processName], stdin=p1.stdout, stdout=subprocess.PIPE) p1.stdout.close() output = p2.communicate()[0] detected = False - for line in output: + for line in output.splitlines(): if "grep %s" % processName in line: continue - elif processName in line: + elif processName in line and not 'defunct' in line: detected = True break return detected, output class ProcTest2(unittest.TestCase): def __init__(self, *args, **kwargs): # Ideally, I'd use setUpClass but that only exists in 2.7. # So, we'll do this make step now. self.proclaunch = make_proclaunch(here) unittest.TestCase.__init__(self, *args, **kwargs) - def test_process_waittimeout(self): + def test_process_waitnotimeout(self): """ Process is started, runs to completion before our wait times out """ p = processhandler.ProcessHandler([self.proclaunch, "process_waittimeout_10s.ini"], cwd=here) p.run() - p.waitForFinish(timeout=30) + p.processOutput(timeout=30) + p.waitForFinish() detected, output = check_for_process(self.proclaunch) self.determine_status(detected, output, p.proc.returncode, p.didTimeout) - def test_process_waitnotimeout(self): + def test_process_wait(self): """ Process is started runs to completion while we wait indefinitely """ p = processhandler.ProcessHandler([self.proclaunch, "process_waittimeout_10s.ini"], cwd=here) p.run() p.waitForFinish() detected, output = check_for_process(self.proclaunch) self.determine_status(detected, output, p.proc.returncode, p.didTimeout) + def test_process_waittimeout(self): + """ + Process is started, then waitForFinish is called and times out. + Process is still running and didn't timeout + """ + p = processhandler.ProcessHandler([self.proclaunch, + "process_waittimeout_10s.ini"], + cwd=here) + + p.run() + p.processOutput() + p.waitForFinish(timeout=5) + + detected, output = check_for_process(self.proclaunch) + self.determine_status(detected, + output, + p.proc.returncode, + p.didTimeout, + True, + []) + def determine_status(self, detected=False, output = '', returncode = 0, didtimeout = False, isalive=False, expectedfail=[]): """ @@ -124,24 +146,24 @@ class ProcTest2(unittest.TestCase): output -- string of data from detected process, can be '' returncode -- return code from process, defaults to 0 didtimeout -- True if process timed out, defaults to False isalive -- Use True to indicate we pass if the process exists; however, by default the test will pass if the process does not exist (isalive == False) expectedfail -- Defaults to [], used to indicate a list of fields that are expected to fail """ if 'returncode' in expectedfail: - self.assertTrue(returncode, "Detected an expected non-zero return code") - else: + self.assertTrue(returncode, "Detected an unexpected return code of: %s" % returncode) + elif not isalive: self.assertTrue(returncode == 0, "Detected non-zero return code of: %d" % returncode) if 'didtimeout' in expectedfail: - self.assertTrue(didtimeout, "Process timed out as expected") + self.assertTrue(didtimeout, "Detected that process didn't time out") else: self.assertTrue(not didtimeout, "Detected that process timed out") - if detected: - self.assertTrue(isalive, "Detected process is still running, process output: %s" % output) + if isalive: + self.assertTrue(detected, "Detected process is not running, process output: %s" % output) else: - self.assertTrue(not isalive, "Process ended") + self.assertTrue(not detected, "Detected process is still running, process output: %s" % output) if __name__ == '__main__': unittest.main()
--- a/testing/mozbase/mozprofile/mozprofile/addons.py +++ b/testing/mozbase/mozprofile/mozprofile/addons.py @@ -167,18 +167,21 @@ class AddonManager(object): os.close(fd) tmpfile = path else: tmpfile = None # if the addon is a directory, install all addons in it addons = [path] if not path.endswith('.xpi') and not os.path.exists(os.path.join(path, 'install.rdf')): - assert os.path.isdir(path), "Addon '%s' cannot be installed" % path - addons = [os.path.join(path, x) for x in os.listdir(path)] + # If the path doesn't exist, then we don't really care, just return + if not os.path.isdir(path): + return + addons = [os.path.join(path, x) for x in os.listdir(path) if + os.path.isdir(os.path.join(path, x))] # install each addon for addon in addons: tmpdir = None xpifile = None if addon.endswith('.xpi'): tmpdir = tempfile.mkdtemp(suffix = '.' + os.path.split(addon)[-1]) compressed_file = zipfile.ZipFile(addon, 'r') @@ -196,17 +199,17 @@ class AddonManager(object): addon = tmpdir # determine the addon id addon_details = AddonManager.addon_details(addon) addon_id = addon_details.get('id') assert addon_id, 'The addon id could not be found: %s' % addon # copy the addon to the profile - extensions_path = os.path.join(self.profile, 'extensions') + extensions_path = os.path.join(self.profile, 'extensions', 'staged') addon_path = os.path.join(extensions_path, addon_id) if not unpack and not addon_details['unpack'] and xpifile: if not os.path.exists(extensions_path): os.makedirs(extensions_path) shutil.copy(xpifile, addon_path + '.xpi') else: dir_util.copy_tree(addon, addon_path, preserve_symlinks=1) self._addon_dirs.append(addon_path)
--- a/testing/mozbase/mozprofile/mozprofile/permissions.py +++ b/testing/mozbase/mozprofile/mozprofile/permissions.py @@ -123,19 +123,17 @@ class ServerLocations(object): def __len__(self): return len(self._locations) def add(self, location, suppress_callback=False): if "primary" in location.options: if self.hasPrimary: raise MultiplePrimaryLocationsError() self.hasPrimary = True - for loc in self._locations: - if loc.isEqual(location): - raise DuplicateLocationError(location.url()) + self._locations.append(location) if self.add_callback and not suppress_callback: self.add_callback([location]) def add_host(self, host, port='80', scheme='http', options='privileged'): if isinstance(options, basestring): options = options.split(',') self.add(Location(scheme, host, port, options)) @@ -145,17 +143,17 @@ class ServerLocations(object): Reads the file (in the format of server-locations.txt) and add all valid locations to the self._locations array. If check_for_primary is True, a MissingPrimaryLocationError exception is raised if no primary is found. This format: http://mxr.mozilla.org/mozilla-central/source/build/pgo/server-locations.txt - The only exception is that the port, if not defined, defaults to 80. + The only exception is that the port, if not defined, defaults to 80 or 443. FIXME: Shouldn't this default to the protocol-appropriate port? Is there any reason to have defaults at all? """ locationFile = codecs.open(filename, "r", "UTF-8") lineno = 0 new_locations = [] @@ -180,17 +178,21 @@ class ServerLocations(object): if '://' not in server: server = 'http://' + server scheme, netloc, path, query, fragment = urlparse.urlsplit(server) # get the host and port try: host, port = netloc.rsplit(':', 1) except ValueError: host = netloc - port = '80' + default_ports = {'http': '80', + 'https': '443', + 'ws': '443', + 'wss': '443'} + port = default_ports.get(scheme, '80') try: location = Location(scheme, host, port, options) self.add(location, suppress_callback=True) except LocationError, e: raise LocationsSyntaxError(lineno, e) new_locations.append(location) @@ -263,18 +265,18 @@ class Permissions(object): """ # Grant God-power to all the privileged servers on which tests run. prefs = [] privileged = [i for i in self._locations if "privileged" in i.options] for (i, l) in itertools.izip(itertools.count(1), privileged): prefs.append(("capability.principal.codebase.p%s.granted" % i, "UniversalXPConnect")) - # TODO: do we need the port? - prefs.append(("capability.principal.codebase.p%s.id" % i, l.scheme + "://" + l.host)) + prefs.append(("capability.principal.codebase.p%s.id" % i, "%s://%s:%s" % + (l.scheme, l.host, l.port))) prefs.append(("capability.principal.codebase.p%s.subjectName" % i, "")) if proxy: user_prefs = self.pac_prefs() else: user_prefs = [] return prefs, user_prefs @@ -284,37 +286,38 @@ class Permissions(object): return preferences for Proxy Auto Config. originally taken from http://mxr.mozilla.org/mozilla-central/source/build/automation.py.in """ prefs = [] # We need to proxy every server but the primary one. origins = ["'%s'" % l.url() - for l in self._locations - if "primary" not in l.options] + for l in self._locations] + origins = ", ".join(origins) - # TODO: this is not a reliable way to determine the Proxy host for l in self._locations: if "primary" in l.options: webServer = l.host - httpPort = l.port - sslPort = 443 + port = l.port # TODO: this should live in a template! + # TODO: So changing the 5th line of the regex below from (\\\\\\\\d+) + # to (\\\\d+) makes this code work. Not sure why there would be this + # difference between automation.py.in and this file. pacURL = """data:text/plain, function FindProxyForURL(url, host) { var origins = [%(origins)s]; var regex = new RegExp('^([a-z][-a-z0-9+.]*)' + '://' + '(?:[^/@]*@)?' + '(.*?)' + - '(?::(\\\\\\\\d+))?/'); + '(?::(\\\\d+))?/'); var matches = regex.exec(url); if (!matches) return 'DIRECT'; var isHttp = matches[1] == 'http'; var isHttps = matches[1] == 'https'; var isWebSocket = matches[1] == 'ws'; var isWebSocketSSL = matches[1] == 'wss'; if (!matches[3]) @@ -325,25 +328,22 @@ function FindProxyForURL(url, host) if (isWebSocket) matches[1] = 'http'; if (isWebSocketSSL) matches[1] = 'https'; var origin = matches[1] + '://' + matches[2] + ':' + matches[3]; if (origins.indexOf(origin) < 0) return 'DIRECT'; - if (isHttp) - return 'PROXY %(remote)s:%(httpport)s'; - if (isHttps || isWebSocket || isWebSocketSSL) - return 'PROXY %(remote)s:%(sslport)s'; + if (isHttp || isHttps || isWebSocket || isWebSocketSSL) + return 'PROXY %(remote)s:%(port)s'; return 'DIRECT'; }""" % { "origins": origins, "remote": webServer, - "httpport":httpPort, - "sslport": sslPort } + "port": port } pacURL = "".join(pacURL.splitlines()) prefs.append(("network.proxy.type", 2)) prefs.append(("network.proxy.autoconfig_url", pacURL)) return prefs def clean_db(self):
--- a/testing/mozbase/mozprofile/mozprofile/profile.py +++ b/testing/mozbase/mozprofile/mozprofile/profile.py @@ -22,17 +22,17 @@ class Profile(object): sets preferences and handles cleanup.""" def __init__(self, profile=None, # Path to the profile addons=None, # String of one or list of addons to install addon_manifests=None, # Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/ preferences=None, # Dictionary or class of preferences locations=None, # locations to proxy - proxy=False, # setup a proxy + proxy=None, # setup a proxy - dict of server-loc,server-port,ssl-port restore=True # If true remove all installed addons preferences when cleaning up ): # if true, remove installed addons/prefs afterwards self.restore = restore # prefs files written to self.written_prefs = set()
--- a/testing/mozbase/mozprofile/tests/permissions.py +++ b/testing/mozbase/mozprofile/tests/permissions.py @@ -76,38 +76,39 @@ http://127.0.0.1:8888 privileg cur.execute("select * from sqlite_master where type='table'") entries = cur.fetchall() self.assertEqual(len(entries), 0) def test_nw_prefs(self): perms = Permissions(self.profile_dir, self.locations_file.name) prefs, user_prefs = perms.network_prefs(False) + self.assertEqual(len(user_prefs), 0) self.assertEqual(len(prefs), 6) self.assertEqual(prefs[0], ('capability.principal.codebase.p1.granted', 'UniversalXPConnect')) self.assertEqual(prefs[1], ('capability.principal.codebase.p1.id', - 'http://mochi.test')) + 'http://mochi.test:8888')) self.assertEqual(prefs[2], ('capability.principal.codebase.p1.subjectName', '')) self.assertEqual(prefs[3], ('capability.principal.codebase.p2.granted', 'UniversalXPConnect')) self.assertEqual(prefs[4], ('capability.principal.codebase.p2.id', - 'http://127.0.0.1')) + 'http://127.0.0.1:8888')) self.assertEqual(prefs[5], ('capability.principal.codebase.p2.subjectName', '')) prefs, user_prefs = perms.network_prefs(True) self.assertEqual(len(user_prefs), 2) self.assertEqual(user_prefs[0], ('network.proxy.type', 2)) self.assertEqual(user_prefs[1][0], 'network.proxy.autoconfig_url') - origins_decl = "var origins = ['http://127.0.0.1:80', 'http://127.0.0.1:8888'];" + origins_decl = "var origins = ['http://mochi.test:8888', 'http://127.0.0.1:80', 'http://127.0.0.1:8888'];" self.assertTrue(origins_decl in user_prefs[1][1]) - proxy_check = "if (isHttp) return 'PROXY mochi.test:8888'; if (isHttps || isWebSocket || isWebSocketSSL) return 'PROXY mochi.test:443';" + proxy_check = "if (isHttp || isHttps || isWebSocket || isWebSocketSSL) return 'PROXY mochi.test:8888';" self.assertTrue(proxy_check in user_prefs[1][1]) if __name__ == '__main__': unittest.main()
--- a/testing/mozbase/mozprofile/tests/server_locations.py +++ b/testing/mozbase/mozprofile/tests/server_locations.py @@ -77,18 +77,21 @@ http://example.org:80 privileg self.assertEqual(len(locations), 7) self.compare_location(i.next(), 'http', 'mozilla.org', '80', ['privileged']) # test some errors self.assertRaises(MultiplePrimaryLocationsError, locations.add_host, 'primary.test', options='primary') - self.assertRaises(DuplicateLocationError, locations.add_host, - '127.0.0.1') + # We no longer throw these DuplicateLocation Error + try: + locations.add_host('127.0.0.1') + except DuplicateLocationError: + self.assertTrue(False, "Should no longer throw DuplicateLocationError") self.assertRaises(BadPortLocationError, locations.add_host, '127.0.0.1', port='abc') # test some errors in locations file f = self.create_temp_file(self.locations_no_primary) exc = None
--- a/testing/mozbase/mozrunner/mozrunner/runner.py +++ b/testing/mozbase/mozrunner/mozrunner/runner.py @@ -9,17 +9,16 @@ import mozinfo import optparse import os import platform import subprocess import sys import ConfigParser -from threading import Thread from utils import get_metadata_from_egg from utils import findInPath from mozprofile import * from mozprocess.processhandler import ProcessHandler if mozinfo.isMac: from plistlib import readPlist @@ -146,57 +145,68 @@ class Runner(object): except: repository['%s_%s' % (file, id)] = None return repository def is_running(self): return self.process_handler is not None - def start(self, debug_args=None, interactive=False): + def start(self, debug_args=None, interactive=False, timeout=None, outputTimeout=None): """ Run self.command in the proper environment. - debug_args: arguments for the debugger + - interactive: uses subprocess.Popen directly + - read_output: sends program output to stdout [default=False] + - timeout: see process_handler.waitForFinish + - outputTimeout: see process_handler.waitForFinish """ # ensure you are stopped self.stop() # ensure the profile exists if not self.profile.exists(): self.profile.reset() assert self.profile.exists(), "%s : failure to reset profile" % self.__class__.__name__ cmd = self._wrap_command(self.command+self.cmdargs) # attach a debugger, if specified if debug_args: cmd = list(debug_args) + cmd - # if interactive: self.process_handler = subprocess.Popen(cmd, env=self.env) # TODO: other arguments else: # this run uses the managed processhandler self.process_handler = self.process_class(cmd, env=self.env, **self.kp_kwargs) self.process_handler.run() - # Spin a thread to handle reading the output - self.outThread = OutputThread(self.process_handler) - self.outThread.start() + # start processing output from the process + self.process_handler.processOutput(timeout, outputTimeout) - def wait(self, timeout=None, outputTimeout=None): - """Wait for the app to exit.""" + def wait(self, timeout=None): + """ + Wait for the app to exit. + + If timeout is not None, will return after timeout seconds. + Use is_running() to determine whether or not a timeout occured. + Timeout is ignored if interactive was set to True. + """ if self.process_handler is None: return if isinstance(self.process_handler, subprocess.Popen): self.process_handler.wait() else: - self.process_handler.waitForFinish(timeout=timeout, outputTimeout=outputTimeout) + self.process_handler.waitForFinish(timeout) + if not getattr(self.process_handler.proc, 'returncode', False): + # waitForFinish timed out + return self.process_handler = None def stop(self): """Kill the app""" if self.process_handler is None: return self.process_handler.kill() self.process_handler = None @@ -242,23 +252,16 @@ class FirefoxRunner(Runner): class ThunderbirdRunner(Runner): """Specialized Runner subclass for running Thunderbird""" profile_class = ThunderbirdProfile runners = {'firefox': FirefoxRunner, 'thunderbird': ThunderbirdRunner} -class OutputThread(Thread): - def __init__(self, prochandler): - Thread.__init__(self) - self.ph = prochandler - def run(self): - self.ph.waitForFinish() - class CLI(MozProfileCLI): """Command line interface.""" module = "mozrunner" def __init__(self, args=sys.argv[1:]): """ Setup command line parser and parse arguments
--- a/testing/mozbase/test-manifest.ini +++ b/testing/mozbase/test-manifest.ini @@ -3,12 +3,13 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. # mozbase test manifest, in the format of # https://github.com/mozilla/mozbase/blob/master/manifestdestiny/README.txt # run with # https://github.com/mozilla/mozbase/blob/master/test.py +[include:manifestdestiny/tests/manifest.ini] [include:mozprocess/tests/manifest.ini] [include:mozprofile/tests/manifest.ini] [include:mozhttpd/tests/manifest.ini] [include:mozdevice/tests/manifest.ini]
--- a/testing/peptest/MANIFEST.in +++ b/testing/peptest/MANIFEST.in @@ -1,5 +1,1 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -recursive-include peptest/extension * \ No newline at end of file +# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. recursive-include peptest/extension * \ No newline at end of file
--- a/testing/peptest/peptest/extension/build.xml +++ b/testing/peptest/peptest/extension/build.xml @@ -1,14 +1,13 @@ <?xml version="1.0"?> <!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - <!-- build.xml adapted from Shawn Wilsher's rtse (http://shawnwilsher.com/extensions/rtse/) --> <project name="pep" default="pepxpi"> <tstamp> <format property="build.number" pattern="yyyyMMdd" offset="-1" unit="hour"/>
--- a/testing/peptest/peptest/extension/resource/mozmill/README.md +++ b/testing/peptest/peptest/extension/resource/mozmill/README.md @@ -1,9 +1,9 @@ <!-- This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> These folders are pulled from: https://github.com/mozilla/mozmill/tree/master/mozmill/mozmill/extension/resource -To update them, simply checkout the mozmill repo at https://github.com/mozautomation/mozmill, +To update them, simply checkout the mozmill repo at https://github.com/mozilla/mozmill, then copy and paste the 'driver' and 'stdlib' folders to this location.
--- a/testing/peptest/peptest/pepprocess.py +++ b/testing/peptest/peptest/pepprocess.py @@ -57,43 +57,40 @@ class PepProcess(ProcessHandler): self.logger.testStart(results.currentTest) elif level == 'TEST-END': metric = results.get_metric(results.currentTest) if len(tokens) > 4: threshold = float(tokens[4].rstrip()) else: threshold = 0.0 - msg = results.currentTest \ - + ' | fail threshold: ' + str(threshold) + msg = '%s | fail threshold: %s' % (results.currentTest, threshold) if metric > threshold: - msg += ' < metric: ' + str(metric) + msg += ' < metric: %s' % metric self.logger.testFail(msg) else: - msg += ' >= metric: ' + str(metric) + msg += ' >= metric: %s' % metric self.logger.testPass(msg) - self.logger.testEnd( - results.currentTest + - ' | finished in: ' + tokens[3].rstrip() + ' ms') + self.logger.testEnd('%s | finished in: %s ms' % + (results.currentTest, tokens[3].rstrip())) results.currentTest = None elif level == 'ACTION-START': results.currentAction = tokens[3].rstrip() - self.logger.debug(level + ' | ' + results.currentAction) + self.logger.debug('%s | %s' % (level, results.currentAction)) elif level == 'ACTION-END': - self.logger.debug(level + ' | ' + results.currentAction) + self.logger.debug('%s | %s' % (level, results.currentAction)) results.currentAction = None elif level in ['DEBUG', 'INFO', 'WARNING', 'ERROR']: line = line[len('PEP ' + level)+1:] getattr(self.logger, level.lower())(line.rstrip()) if level == 'ERROR': results.fails[str(results.currentTest)].append(0) else: line = line[len('PEP'):] self.logger.debug(line.rstrip()) elif tokens[0] == 'MOZ_EVENT_TRACE' and results.currentAction is not None: # The output is generated from EventTracer # Format is 'MOZ_EVENT_TRACE sample <TIMESTAMP> <VALUE> # <VALUE> is the unresponsive time in ms - self.logger.warning( - results.currentTest + ' | ' + results.currentAction + - ' | unresponsive time: ' + tokens[3].rstrip() + ' ms') + self.logger.warning('%s | %s | unresponsive time: %s ms' % + (results.currentTest, results.currentAction, tokens[3].rstrip())) results.fails[results.currentTest].append(int(tokens[3].rstrip()))
--- a/testing/peptest/peptest/runpeptests.py +++ b/testing/peptest/peptest/runpeptests.py @@ -44,17 +44,18 @@ class Peptest(): # create the profile enable_proxy = False locations = ServerLocations() if self.options.proxyLocations: if not self.options.serverPath: self.logger.warning('Can\'t set up proxy without server path') else: enable_proxy = True - locations.read(self.options.proxyLocations, False) + for proxyLocation in self.options.proxyLocations: + locations.read(proxyLocation, False) locations.add_host(host='127.0.0.1', port=self.options.serverPort, options='primary,privileged') self.profile = self.profile_class(profile=self.options.profilePath, addons=[os.path.join(here, 'extension')], locations=locations, proxy=enable_proxy) @@ -108,18 +109,18 @@ class Peptest(): cmdargs=cmdargs, env=env, process_class=PepProcess) def start(self): self.logger.debug('Starting Peptest') # start firefox - self.runner.start() - self.runner.wait(outputTimeout=self.options.timeout) + self.runner.start(outputTimeout=self.options.timeout) + self.runner.wait() crashed = self.checkForCrashes(results.currentTest) self.stop() if crashed or results.has_fails(): return 1 return 0 def runServer(self): @@ -288,21 +289,21 @@ class PeptestOptions(OptionParser): self.add_option("-p", "--profile-path", action="store", type="string", dest="profilePath", default=None, help="path to the profile to use. " "If none specified, a temporary profile is created") self.add_option("--proxy", - action="store", type="string", dest="proxyLocations", + action="append", type="string", dest="proxyLocations", default=None, - help="path to a server-location file specifying " - "domains to proxy. --server-path must also be " - "specified.") + help="a list of paths to server-location files specifying " + "domains to proxy (set with multiple --proxy agruments). " + "--server-path must also be specified.") self.add_option("--proxy-host-dirs", action="store_true", dest="proxyHostDirs", default=False, help="proxied requests are served from directories " "named by requested host. --proxy must also be " "specified.")
--- a/toolkit/components/maintenanceservice/Makefile.in +++ b/toolkit/components/maintenanceservice/Makefile.in @@ -11,17 +11,16 @@ include $(DEPTH)/config/autoconf.mk CPPSRCS = \ maintenanceservice.cpp \ serviceinstall.cpp \ workmonitor.cpp \ certificatecheck.cpp \ servicebase.cpp \ registrycertificates.cpp \ - prefetch.cpp \ $(NULL) # For debugging purposes only #DEFINES += -DDISABLE_UPDATER_AUTHENTICODE_CHECK PROGRAM = maintenanceservice$(BIN_SUFFIX) DIST_PROGRAM = maintenanceservice$(BIN_SUFFIX)
--- a/toolkit/components/maintenanceservice/maintenanceservice.cpp +++ b/toolkit/components/maintenanceservice/maintenanceservice.cpp @@ -9,17 +9,16 @@ #include <shlobj.h> #include "serviceinstall.h" #include "maintenanceservice.h" #include "servicebase.h" #include "workmonitor.h" #include "uachelper.h" #include "updatehelper.h" -#include "prefetch.h" SERVICE_STATUS gSvcStatus = { 0 }; SERVICE_STATUS_HANDLE gSvcStatusHandle = NULL; HANDLE gWorkDoneEvent = NULL; HANDLE gThread = NULL; bool gServiceControlStopping = false; // logs are pretty small, about 20 lines, so 10 seems reasonable.
deleted file mode 100644 --- a/toolkit/components/maintenanceservice/prefetch.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include <shlwapi.h> -#include "servicebase.h" -#include "updatehelper.h" -#include "nsWindowsHelpers.h" -#define MAX_KEY_LENGTH 255 - -/** - * Writes a registry DWORD with a value of 1 at BASE_SERVICE_REG_KEY - * if the prefetch was cleared successfully. - * - * @return TRUE if successful. -*/ -BOOL -WritePrefetchClearedReg() -{ - HKEY baseKeyRaw; - LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - BASE_SERVICE_REG_KEY, 0, - KEY_WRITE | KEY_WOW64_64KEY, &baseKeyRaw); - if (retCode != ERROR_SUCCESS) { - LOG(("Could not open key for prefetch. (%d)\n", retCode)); - return FALSE; - } - nsAutoRegKey baseKey(baseKeyRaw); - DWORD disabledValue = 1; - if (RegSetValueExW(baseKey, L"FFPrefetchDisabled", 0, REG_DWORD, - reinterpret_cast<LPBYTE>(&disabledValue), - sizeof(disabledValue)) != ERROR_SUCCESS) { - LOG(("Could not write prefetch cleared value to registry. (%d)\n", - GetLastError())); - return FALSE; - } - return TRUE; -} - -/** - * Update: We found that prefetch clearing was a net negative, so this - * function has been updated to delete the read only prefetch files. - * ----------------------------------------------------------------------- - * We found that prefetch actually causes large applications like Firefox - * to startup slower. This will get rid of the Windows prefetch files for - * applications like firefox (FIREFOX-*.pf files) and instead replace them - * with 0 byte files which are read only. Windows will not use prefetch - * if the associated prefetch file is a 0 byte read only file. - * Some of the problems with prefetch relating to Windows and Firefox: - * - Prefetch reads in a lot before we even run (fonts, plugins, etc...) - * - Prefetch happens before our code runs, so it delays UI showing. - * - Prefetch does not use windows readahead. - * Previous test data on an acer i7 laptop with a 5400rpm HD showed startup - * time difference was 1.6s (without prefetch) vs 2.6s+ with prefetch. - * The "Windows Internals" book mentions that prefetch can be disabled for - * the whole system only, so there is no other application specific way to - * disable it. - * - * @param prefetchProcessName The name of the process who's prefetch files - * should be cleared. - * @return TRUE if no errors occurred during the clear operation. -*/ -BOOL -ClearPrefetch(LPCWSTR prefetchProcessName) -{ - LOG(("Clearing prefetch files...\n")); - size_t prefetchProcessNameLength = wcslen(prefetchProcessName); - - // Make sure we were passed in a safe value for the prefetch process name - // because it will be appended to a filepath and deleted. - // We check for < 2 to avoid things like "." as the path - // We check for a max path of MAX_PATH - 10 because we add \\ and '.EXE-*.pf' - if (wcsstr(prefetchProcessName, L"..") || - wcsstr(prefetchProcessName, L"\\") || - wcsstr(prefetchProcessName, L"*") || - wcsstr(prefetchProcessName, L"/") || - prefetchProcessNameLength < 2 || - prefetchProcessNameLength >= (MAX_PATH - 10)) { - LOG(("Prefetch path to clear is not safe\n")); - return FALSE; - } - - // Quick shortcut to make sure we don't try to clear multiple times for - // different FIREFOX installs. - static WCHAR lastPrefetchProcessName[MAX_PATH - 10] = { '\0' }; - if (!wcscmp(lastPrefetchProcessName, prefetchProcessName)) { - LOG(("Already processed process name\n")); - return FALSE; - } - wcscpy(lastPrefetchProcessName, prefetchProcessName); - - // Obtain the windows prefetch directory path. - WCHAR prefetchPath[MAX_PATH + 1]; - if (!GetWindowsDirectoryW(prefetchPath, - sizeof(prefetchPath) / - sizeof(prefetchPath[0]))) { - LOG(("Could not obtain windows directory\n")); - return FALSE; - } - if (!PathAppendSafe(prefetchPath, L"prefetch")) { - LOG(("Could not obtain prefetch directory\n")); - return FALSE; - } - - size_t prefetchDirLen = wcslen(prefetchPath); - WCHAR prefetchSearchFile[MAX_PATH + 1]; - // We know this is safe based on the check at the start of this function - wsprintf(prefetchSearchFile, L"\\%s.EXE-*.pf", prefetchProcessName); - // Append the search file to the full path - wcscpy(prefetchPath + prefetchDirLen, prefetchSearchFile); - - // Find the first path matching and get a find handle for future calls. - WIN32_FIND_DATAW findFileData; - HANDLE findHandle = FindFirstFileW(prefetchPath, &findFileData); - if (INVALID_HANDLE_VALUE == findHandle) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) { - LOG(("No files matching firefox.exe prefetch path.\n")); - return TRUE; - } else { - LOG(("Error finding firefox.exe prefetch files. (%d)\n", - GetLastError())); - return FALSE; - } - } - - BOOL deletedAllFFPrefetch = TRUE; - size_t deletedCount = 0; - do { - // Reset back to the prefetch directory, we know from an above check that - // we aren't exceeding MAX_PATH + 1 characters with prefetchDirLen + 1. - // From above we know: prefetchPath[prefetchDirLen] == L'\\'; - prefetchPath[prefetchDirLen + 1] = L'\0'; - - // Get the new file's prefetch path - LPWSTR filenameOffsetInBuffer = prefetchPath + prefetchDirLen + 1; - if (wcslen(findFileData.cFileName) + prefetchDirLen + 1 > MAX_PATH) { - LOG(("Error appending prefetch path %ls, path is too long. (%d)\n", - findFileData.cFileName, GetLastError())); - deletedAllFFPrefetch = FALSE; - continue; - } - if (!PathAppendSafe(filenameOffsetInBuffer, findFileData.cFileName)) { - LOG(("Error appending prefetch path %ls. (%d)\n", findFileData.cFileName, - GetLastError())); - deletedAllFFPrefetch = FALSE; - continue; - } - - DWORD attributes = GetFileAttributesW(prefetchPath); - if (INVALID_FILE_ATTRIBUTES == attributes) { - LOG(("Could not get/set attributes on prefetch file: %ls. (%d)\n", - findFileData.cFileName, GetLastError())); - continue; - } - - if (!(attributes & FILE_ATTRIBUTE_READONLY)) { - LOG(("Prefetch file is not read-only, don't clear: %ls.\n", - findFileData.cFileName)); - continue; - } - - // Remove the read only attribute so a DeleteFile call will work. - if (!SetFileAttributesW(prefetchPath, - attributes & (~FILE_ATTRIBUTE_READONLY))) { - LOG(("Could not set read only on prefetch file: %ls. (%d)\n", - findFileData.cFileName, GetLastError())); - continue; - } - - if (!DeleteFileW(prefetchPath)) { - LOG(("Could not delete read only prefetch file: %ls. (%d)\n", - findFileData.cFileName, GetLastError())); - } - - ++deletedCount; - LOG(("Prefetch file cleared successfully: %ls\n", - prefetchPath)); - } while (FindNextFileW(findHandle, &findFileData)); - LOG(("Done searching prefetch paths. (%d)\n", GetLastError())); - - // Cleanup after ourselves. - FindClose(findHandle); - - if (deletedAllFFPrefetch && deletedCount > 0) { - WritePrefetchClearedReg(); - } - - return deletedAllFFPrefetch; -} - -/** - * Clears all prefetch files specified in the installation dirctories - * @return FALSE if there was an error clearing the known prefetch directories -*/ -BOOL -ClearKnownPrefetch() -{ - // The service always uses the 64-bit registry key - HKEY baseKeyRaw; - LONG retCode = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - BASE_SERVICE_REG_KEY, 0, - KEY_READ | KEY_WOW64_64KEY, &baseKeyRaw); - if (retCode != ERROR_SUCCESS) { - LOG(("Could not open maintenance service base key. (%d)\n", retCode)); - return FALSE; - } - nsAutoRegKey baseKey(baseKeyRaw); - - // Get the number of subkeys. - DWORD subkeyCount = 0; - retCode = RegQueryInfoKeyW(baseKey, NULL, NULL, NULL, &subkeyCount, NULL, - NULL, NULL, NULL, NULL, NULL, NULL); - if (retCode != ERROR_SUCCESS) { - LOG(("Could not query info key: %d\n", retCode)); - return FALSE; - } - - // Enumerate the subkeys, each subkey represents an install - for (DWORD i = 0; i < subkeyCount; i++) { - WCHAR subkeyBuffer[MAX_KEY_LENGTH]; - DWORD subkeyBufferCount = MAX_KEY_LENGTH; - retCode = RegEnumKeyExW(baseKey, i, subkeyBuffer, - &subkeyBufferCount, NULL, - NULL, NULL, NULL); - if (retCode != ERROR_SUCCESS) { - LOG(("Could not enum installations: %d\n", retCode)); - return FALSE; - } - - // Open the subkey - HKEY subKeyRaw; - retCode = RegOpenKeyExW(baseKey, - subkeyBuffer, - 0, - KEY_READ | KEY_WOW64_64KEY, - &subKeyRaw); - nsAutoRegKey subKey(subKeyRaw); - if (retCode != ERROR_SUCCESS) { - LOG(("Could not open subkey: %d\n", retCode)); - continue; // Try the next subkey - } - - const int MAX_CHAR_COUNT = 256; - DWORD valueBufSize = MAX_CHAR_COUNT * sizeof(WCHAR); - WCHAR prefetchProcessName[MAX_CHAR_COUNT] = { L'\0' }; - - // Get the prefetch process name from the registry - retCode = RegQueryValueExW(subKey, L"prefetchProcessName", 0, NULL, - (LPBYTE)prefetchProcessName, &valueBufSize); - if (retCode != ERROR_SUCCESS) { - LOG(("Could not obtain process name from registry: %d\n", retCode)); - continue; // Try the next subkey - } - - // The value for prefetch process name comes from HKLM so is trusted. - // We will do some sanity checks on it though inside ClearPrefetch. - ClearPrefetch(prefetchProcessName); - } - - return TRUE; -}
deleted file mode 100644 --- a/toolkit/components/maintenanceservice/prefetch.h +++ /dev/null @@ -1,5 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -BOOL ClearKnownPrefetch();
--- a/toolkit/components/maintenanceservice/workmonitor.cpp +++ b/toolkit/components/maintenanceservice/workmonitor.cpp @@ -19,17 +19,16 @@ #include "workmonitor.h" #include "serviceinstall.h" #include "servicebase.h" #include "registrycertificates.h" #include "uachelper.h" #include "updatehelper.h" #include "errors.h" -#include "prefetch.h" // Wait 15 minutes for an update operation to run at most. // Updates usually take less than a minute so this seems like a // significantly large and safe amount of time to wait. static const int TIME_TO_WAIT_ON_UPDATER = 15 * 60 * 1000; PRUnichar* MakeCommandLine(int argc, PRUnichar **argv); BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode); BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, @@ -499,18 +498,16 @@ ExecuteServiceCommand(int argc, LPWSTR * BOOL result = FALSE; if (!lstrcmpi(argv[2], L"software-update")) { result = ProcessSoftwareUpdateCommand(argc - 3, argv + 3); // We might not reach here if the service install succeeded // because the service self updates itself and the service // installer will stop the service. LOG(("Service command %ls complete.\n", argv[2])); - } else if (!lstrcmpi(argv[2], L"clear-prefetch")) { - result = ClearKnownPrefetch(); } else { LOG(("Service command not recognized: %ls.\n", argv[2])); // result is already set to FALSE } LOG(("service command %ls complete with result: %ls.\n", argv[1], (result ? L"Success" : L"Failure"))); return TRUE;
--- a/widget/gtkxtbin/gtk2xtbin.c +++ b/widget/gtkxtbin/gtk2xtbin.c @@ -472,17 +472,17 @@ xt_client_xloop_create(void) } /* * hook Xt event loop into the glib event loop. */ /* the assumption is that gtk_init has already been called */ GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource)); if (!gs) { - return NULL; + return; } g_source_set_priority(gs, GDK_PRIORITY_EVENTS); g_source_set_can_recurse(gs, TRUE); tag = g_source_attach(gs, (GMainContext*)NULL); #ifdef VMS cnumber = XConnectionNumber(xtdisplay); #else
--- a/widget/xpwidgets/GfxInfoX11.cpp +++ b/widget/xpwidgets/GfxInfoX11.cpp @@ -37,16 +37,17 @@ GfxInfo::Init() mGLMajorVersion = 0; mMajorVersion = 0; mMinorVersion = 0; mRevisionVersion = 0; mIsMesa = false; mIsNVIDIA = false; mIsFGLRX = false; mIsNouveau = false; + mIsIntel = false; mHasTextureFromPixmap = false; return GfxInfoBase::Init(); } void GfxInfo::GetData() { // to understand this function, see bug 639842. We retrieve the OpenGL driver information in a @@ -204,16 +205,18 @@ GfxInfo::GetData() const char *Mesa_in_version_string = strstr(mVersion.get(), "Mesa"); if (Mesa_in_version_string) { mIsMesa = true; // with Mesa, the version string contains "Mesa major.minor" and that's all the version information we get: // there is no actual driver version info. whereToReadVersionNumbers = Mesa_in_version_string + strlen("Mesa"); if (strcasestr(mVendor.get(), "nouveau")) mIsNouveau = true; + if (strcasestr(mRenderer.get(), "intel")) // yes, intel is in the renderer string + mIsIntel = true; } else if (strstr(mVendor.get(), "NVIDIA Corporation")) { mIsNVIDIA = true; // with the NVIDIA driver, the version string contains "NVIDIA major.minor" // note that here the vendor and version strings behave differently, that's why we don't put this above // alongside Mesa_in_version_string. const char *NVIDIA_in_version_string = strstr(mVersion.get(), "NVIDIA"); if (NVIDIA_in_version_string) whereToReadVersionNumbers = NVIDIA_in_version_string + strlen("NVIDIA"); @@ -322,16 +325,23 @@ GfxInfo::GetFeatureStatusImpl(PRInt32 aF if (mIsMesa) { if (mIsNouveau && version(mMajorVersion, mMinorVersion) < version(8,0)) { *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; aSuggestedDriverVersion.AssignLiteral("Mesa 8.0"); } else if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(7,10,3)) { *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; aSuggestedDriverVersion.AssignLiteral("Mesa 7.10.3"); } + if (aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) + { + if (mIsIntel && version(mMajorVersion, mMinorVersion) < version(8,1)) + *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; + aSuggestedDriverVersion.AssignLiteral("Mesa 8.1"); + } + } else if (mIsNVIDIA) { if (version(mMajorVersion, mMinorVersion, mRevisionVersion) < version(257,21)) { *aStatus = nsIGfxInfo::FEATURE_BLOCKED_DRIVER_VERSION; aSuggestedDriverVersion.AssignLiteral("NVIDIA 257.21"); } } else if (mIsFGLRX) { // FGLRX does not report a driver version number, so we have the OpenGL version instead. // by requiring OpenGL 3, we effectively require recent drivers.
--- a/widget/xpwidgets/GfxInfoX11.h +++ b/widget/xpwidgets/GfxInfoX11.h @@ -62,17 +62,17 @@ protected: private: nsCString mVendor; nsCString mRenderer; nsCString mVersion; nsCString mAdapterDescription; nsCString mOS; nsCString mOSRelease; - bool mIsMesa, mIsNVIDIA, mIsFGLRX, mIsNouveau; + bool mIsMesa, mIsNVIDIA, mIsFGLRX, mIsNouveau, mIsIntel; bool mHasTextureFromPixmap; int mGLMajorVersion, mMajorVersion, mMinorVersion, mRevisionVersion; void AddCrashReportAnnotations(); }; } // namespace widget } // namespace mozilla
--- a/widget/xpwidgets/nsIdleService.cpp +++ b/widget/xpwidgets/nsIdleService.cpp @@ -640,16 +640,18 @@ nsIdleService::IdleTimerCallback(void) if (!curListener.isIdle) { // If they have an idle time smaller than the actual idle time. if (curListener.reqIdleTime <= currentIdleTimeInS) { // Then add the listener to the list of listeners that should be // notified. notifyList.AppendObject(curListener.observer); // This listener is now idle. curListener.isIdle = true; + // Remember we have someone idle. + mAnyObserverIdle = true; } else { // Listeners that are not timed out yet are candidates for timing out. mDeltaToNextIdleSwitchInS = PR_MIN(mDeltaToNextIdleSwitchInS, curListener.reqIdleTime); } } } @@ -661,19 +663,16 @@ nsIdleService::IdleTimerCallback(void) Telemetry::Accumulate(Telemetry::IDLE_NOTIFY_IDLE_LISTENERS, numberOfPendingNotifications); // Bail if nothing to do. if (!numberOfPendingNotifications) { return; } - // Remember we have someone idle. - mAnyObserverIdle = true; - // We need a text string to send with any state change events. nsAutoString timeStr; timeStr.AppendInt(currentIdleTimeInS); // Notify all listeners that just timed out. while (numberOfPendingNotifications--) { PR_LOG(sLog, PR_LOG_DEBUG, ("idleService: Idle timer callback: tell observer %x user is idle",
--- a/xpcom/build/mozPoisonWriteMac.cpp +++ b/xpcom/build/mozPoisonWriteMac.cpp @@ -26,84 +26,103 @@ using namespace mozilla; struct FuncData { const char *Name; // Name of the function for the ones we use dlsym const void *Wrapper; // The function that we will replace 'Function' with void *Function; // The function that will be replaced with 'Wrapper' void *Buffer; // Will point to the jump buffer that lets us call // 'Function' after it has been replaced. }; +// Wrap aio_write. We have not seen it before, so just assert/report it. +typedef ssize_t (*aio_write_t)(struct aiocb *aiocbp); +ssize_t wrap_aio_write(struct aiocb *aiocbp); +FuncData aio_write_data = { 0, (void*) wrap_aio_write, (void*) aio_write }; +ssize_t wrap_aio_write(struct aiocb *aiocbp) { + MOZ_ASSERT(0); + aio_write_t old_write = (aio_write_t) aio_write_data.Buffer; + return old_write(aiocbp); +} + +// Wrap pwrite-like functions. +// We have not seen them before, so just assert/report it. +typedef ssize_t (*pwrite_t)(int fd, const void *buf, size_t nbyte, off_t offset); +template<FuncData &foo> +ssize_t wrap_pwrite_temp(int fd, const void *buf, size_t nbyte, off_t offset) { + MOZ_ASSERT(0); + pwrite_t old_write = (pwrite_t) foo.Buffer; + return old_write(fd, buf, nbyte, offset); +} + +// Define a FuncData for a pwrite-like functions. +// FIXME: clang accepts usinging wrap_pwrite_temp<X ## _data> in the struct +// initialization. Is this a gcc 4.2 bug? +#define DEFINE_PWRITE_DATA(X, NAME) \ +ssize_t wrap_ ## X (int fd, const void *buf, size_t nbyte, off_t offset); \ +FuncData X ## _data = { NAME, (void*) wrap_ ## X }; \ +ssize_t wrap_ ## X (int fd, const void *buf, size_t nbyte, off_t offset) { \ + return wrap_pwrite_temp<X ## _data>(fd, buf, nbyte, offset); \ +} + +// This exists everywhere. +DEFINE_PWRITE_DATA(pwrite, "pwrite") +// These exist on 32 bit OS X +DEFINE_PWRITE_DATA(pwrite_NOCANCEL_UNIX2003, "pwrite$NOCANCEL$UNIX2003"); +DEFINE_PWRITE_DATA(pwrite_UNIX2003, "pwrite$UNIX2003"); +// This exists on 64 bit OS X +DEFINE_PWRITE_DATA(pwrite_NOCANCEL, "pwrite$NOCANCEL"); + +void AbortOnBadWrite(int fd, const void *wbuf, size_t count); + +typedef ssize_t (*writev_t)(int fd, const struct iovec *iov, int iovcnt); +template<FuncData &foo> +ssize_t wrap_writev_temp(int fd, const struct iovec *iov, int iovcnt) { + AbortOnBadWrite(fd, 0, iovcnt); + writev_t old_write = (writev_t) foo.Buffer; + return old_write(fd, iov, iovcnt); +} + +// Define a FuncData for a writev-like functions. +#define DEFINE_WRITEV_DATA(X, NAME) \ +ssize_t wrap_ ## X (int fd, const struct iovec *iov, int iovcnt); \ +FuncData X ## _data = { NAME, (void*) wrap_ ## X }; \ +ssize_t wrap_ ## X (int fd, const struct iovec *iov, int iovcnt) { \ + return wrap_writev_temp<X ## _data>(fd, iov, iovcnt); \ +} + +// This exists everywhere. +DEFINE_WRITEV_DATA(writev, "writev"); +// These exist on 32 bit OS X +DEFINE_WRITEV_DATA(writev_NOCANCEL_UNIX2003, "writev$NOCANCEL$UNIX2003"); +DEFINE_WRITEV_DATA(writev_UNIX2003, "writev$UNIX2003"); +// This exists on 64 bit OS X +DEFINE_WRITEV_DATA(writev_NOCANCEL, "writev$NOCANCEL"); + typedef ssize_t (*write_t)(int fd, const void *buf, size_t count); -void AbortOnBadWrite(int fd, const void *wbuf, size_t count); template<FuncData &foo> ssize_t wrap_write_temp(int fd, const void *buf, size_t count) { AbortOnBadWrite(fd, buf, count); write_t old_write = (write_t) foo.Buffer; return old_write(fd, buf, count); } -// FIXME: clang accepts usinging wrap_data_temp<X ## _data> in the struct -// initialization. Is this a gcc 4.2 bug? - -// Define a FuncData for a function that can be found without dlsym. -#define DEFINE_F_DATA(X) \ -ssize_t wrap_ ## X (int fd, const void *buf, size_t count); \ -FuncData X ## _data = { 0, (void*) wrap_ ## X, (void*) X }; \ -ssize_t wrap_ ## X (int fd, const void *buf, size_t count) { \ - return wrap_write_temp<X ## _data>(fd, buf, count); \ -} - -// Define a FuncData for a function that can only be found with dlsym. -#define DEFINE_F_DATA_DYN(X, NAME) \ +// Define a FuncData for a write-like functions. +#define DEFINE_WRITE_DATA(X, NAME) \ ssize_t wrap_ ## X (int fd, const void *buf, size_t count); \ FuncData X ## _data = { NAME, (void*) wrap_ ## X }; \ ssize_t wrap_ ## X (int fd, const void *buf, size_t count) { \ return wrap_write_temp<X ## _data>(fd, buf, count); \ } -// Define a simple FuncData that just aborts. -#define DEFINE_F_DATA_ABORT(X) \ -void wrap_ ## X() { abort(); } \ -FuncData X ## _data = { 0, (void*) wrap_ ## X, (void*) X } - -// Define a simple FuncData that just aborts for a function that needs dlsym. -#define DEFINE_F_DATA_ABORT_DYN(X, NAME) \ -void wrap_ ## X() { abort(); } \ -FuncData X ## _data = { NAME, (void*) wrap_ ## X } - -DEFINE_F_DATA_ABORT(aio_write); -DEFINE_F_DATA_ABORT(pwrite); - +// This exists everywhere. +DEFINE_WRITE_DATA(write, "write"); // These exist on 32 bit OS X -DEFINE_F_DATA_ABORT_DYN(writev_NOCANCEL_UNIX2003, "writev$NOCANCEL$UNIX2003"); -DEFINE_F_DATA_ABORT_DYN(writev_UNIX2003, "writev$UNIX2003"); -DEFINE_F_DATA_ABORT_DYN(pwrite_NOCANCEL_UNIX2003, "pwrite$NOCANCEL$UNIX2003"); -DEFINE_F_DATA_ABORT_DYN(pwrite_UNIX2003, "pwrite$UNIX2003"); - -// These exist on 64 bit OS X -DEFINE_F_DATA_ABORT_DYN(writev_NOCANCEL, "writev$NOCANCEL"); -DEFINE_F_DATA_ABORT_DYN(pwrite_NOCANCEL, "pwrite$NOCANCEL"); - -DEFINE_F_DATA(write); - -typedef ssize_t (*writev_t)(int fd, const struct iovec *iov, int iovcnt); -ssize_t wrap_writev(int fd, const struct iovec *iov, int iovcnt); -FuncData writev_data = { 0, (void*) wrap_writev, (void*) writev }; -ssize_t wrap_writev(int fd, const struct iovec *iov, int iovcnt) { - AbortOnBadWrite(fd, 0, iovcnt); - writev_t old_write = (writev_t) writev_data.Buffer; - return old_write(fd, iov, iovcnt); -} - -// These exist on 32 bit OS X -DEFINE_F_DATA_DYN(write_NOCANCEL_UNIX2003, "write$NOCANCEL$UNIX2003"); -DEFINE_F_DATA_DYN(write_UNIX2003, "write$UNIX2003"); - -// These exist on 64 bit OS X -DEFINE_F_DATA_DYN(write_NOCANCEL, "write$NOCANCEL"); +DEFINE_WRITE_DATA(write_NOCANCEL_UNIX2003, "write$NOCANCEL$UNIX2003"); +DEFINE_WRITE_DATA(write_UNIX2003, "write$UNIX2003"); +// This exists on 64 bit OS X +DEFINE_WRITE_DATA(write_NOCANCEL, "write$NOCANCEL"); FuncData *Functions[] = { &aio_write_data, &pwrite_data, &pwrite_NOCANCEL_UNIX2003_data, &pwrite_UNIX2003_data, &pwrite_NOCANCEL_data,
--- a/xpfe/appshell/src/nsWebShellWindow.cpp +++ b/xpfe/appshell/src/nsWebShellWindow.cpp @@ -87,22 +87,16 @@ nsWebShellWindow::nsWebShellWindow(PRUin : nsXULWindow(aChromeFlags) , mSPTimerLock("nsWebShellWindow.mSPTimerLock") { } nsWebShellWindow::~nsWebShellWindow() { - if (mWindow) { - mWindow->SetClientData(0); - mWindow->Destroy(); - mWindow = nullptr; // Force release here. - } - MutexAutoLock lock(mSPTimerLock); if (mSPTimer) mSPTimer->Cancel(); } NS_IMPL_ADDREF_INHERITED(nsWebShellWindow, nsXULWindow) NS_IMPL_RELEASE_INHERITED(nsWebShellWindow, nsXULWindow)
--- a/xpfe/appshell/src/nsWindowMediator.cpp +++ b/xpfe/appshell/src/nsWindowMediator.cpp @@ -752,19 +752,29 @@ nsWindowMediator::RemoveListener(nsIWind } NS_IMETHODIMP nsWindowMediator::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData) { if (!strcmp(aTopic, "xpcom-shutdown") && mReady) { - MutexAutoLock lock(mListLock); - while (mOldestWindow) - UnregisterWindow(mOldestWindow); + // Unregistering a window may cause its destructor to run, causing it to + // call into the window mediator, try to acquire mListLock, and deadlock. + // Our solution is to hold strong refs to all windows until we release + // mListLock. + nsTArray<nsCOMPtr<nsIXULWindow> > windows; + + { + MutexAutoLock lock(mListLock); + while (mOldestWindow) { + windows.AppendElement(mOldestWindow->mWindow); + UnregisterWindow(mOldestWindow); + } + } mReady = false; } return NS_OK; } bool notifyOpenWindow(nsISupports *aElement, void* aData) {