From 81f365c3682b78d71d304791b248f74f3b15f38f Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Mon, 16 May 2011 11:46:55 -0700 Subject: [PATCH 01/15] Bug 623134: Add HTTP logging to track down the intermittent request timeouts. r=robstrong --- .../mozapps/extensions/AddonUpdateChecker.jsm | 25 +++++++++++-------- .../test/browser/browser_updatessl.js | 18 +++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/toolkit/mozapps/extensions/AddonUpdateChecker.jsm b/toolkit/mozapps/extensions/AddonUpdateChecker.jsm index cc2e269282f2..ae2e2b71f83d 100644 --- a/toolkit/mozapps/extensions/AddonUpdateChecker.jsm +++ b/toolkit/mozapps/extensions/AddonUpdateChecker.jsm @@ -440,16 +440,21 @@ function UpdateParser(aId, aType, aUpdateKey, aUrl, aObserver) { } LOG("Requesting " + aUrl); - this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. - createInstance(Ci.nsIXMLHttpRequest); - this.request.open("GET", aUrl, true); - this.request.channel.notificationCallbacks = new BadCertHandler(!requireBuiltIn); - this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; - this.request.overrideMimeType("text/xml"); - var self = this; - this.request.onload = function(event) { self.onLoad() }; - this.request.onerror = function(event) { self.onError() }; - this.request.send(null); + try { + this.request = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]. + createInstance(Ci.nsIXMLHttpRequest); + this.request.open("GET", aUrl, true); + this.request.channel.notificationCallbacks = new BadCertHandler(!requireBuiltIn); + this.request.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE; + this.request.overrideMimeType("text/xml"); + var self = this; + this.request.onload = function(event) { self.onLoad() }; + this.request.onerror = function(event) { self.onError() }; + this.request.send(null); + } + catch (e) { + ERROR("Failed to request update manifest", e); + } } UpdateParser.prototype = { diff --git a/toolkit/mozapps/extensions/test/browser/browser_updatessl.js b/toolkit/mozapps/extensions/test/browser/browser_updatessl.js index eb7899819fbe..9694e5a2c088 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_updatessl.js +++ b/toolkit/mozapps/extensions/test/browser/browser_updatessl.js @@ -22,11 +22,29 @@ var gTests = []; var gStart = 0; var gLast = 0; +var HTTPObserver = { + observeActivity: function(aChannel, aType, aSubtype, aTimestamp, aSizeData, + aStringData) { + aChannel.QueryInterface(Ci.nsIChannel); + + dump("*** HTTP Activity 0x" + aType.toString(16) + " 0x" + aSubtype.toString(16) + + " " + aChannel.URI.spec + "\n"); + } +}; + function test() { gStart = Date.now(); requestLongerTimeout(4); waitForExplicitFinish(); + let observerService = Cc["@mozilla.org/network/http-activity-distributor;1"]. + getService(Ci.nsIHttpActivityDistributor); + observerService.addObserver(HTTPObserver); + + registerCleanupFunction(function() { + observerService.removeObserver(HTTPObserver); + }); + run_next_test(); } From 1d29d4527788976ed3230fb73793d17372a0ef37 Mon Sep 17 00:00:00 2001 From: Taras Glek Date: Mon, 16 May 2011 16:03:36 -0700 Subject: [PATCH 02/15] Bug 657480: Clean up after TelemetryPing.js r=mak --- toolkit/components/telemetry/TelemetryPing.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index 58ad8c35c9ba..d3bfa256ff87 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -235,12 +235,25 @@ TelemetryPing.prototype = { let idleService = Cc["@mozilla.org/widget/idleservice;1"]. getService(Ci.nsIIdleService); idleService.addIdleObserver(self, TELEMETRY_INTERVAL); - Services.obs.addObserver(self, "idle-daily", null); + Services.obs.addObserver(self, "idle-daily", false); + Services.obs.addObserver(self, "profile-before-change", false); self.gatherMemory(); + delete self._timer } this._timer.initWithCallback(timerCallback, TELEMETRY_DELAY, Ci.nsITimer.TYPE_ONE_SHOT); }, + /** + * Remove observers to avoid leaks + */ + uninstall: function uninstall() { + let idleService = Cc["@mozilla.org/widget/idleservice;1"]. + getService(Ci.nsIIdleService); + idleService.removeIdleObserver(this, TELEMETRY_INTERVAL); + Services.obs.removeObserver(this, "idle-daily"); + Services.obs.removeObserver(this, "profile-before-change"); + }, + /** * This observer drives telemetry. */ @@ -252,6 +265,9 @@ TelemetryPing.prototype = { case "profile-after-change": this.setup(); break; + case "profile-before-change": + this.uninstall(); + break; case "idle": this.gatherMemory(); break; From 04f1d9f0378c9ef0983821c0442a8301818d859f Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 17 May 2011 09:23:23 +0900 Subject: [PATCH 03/15] Bug 605648 Support high resolution scrolling on Windows r=jimm+smaug --- content/events/src/nsEventStateManager.cpp | 46 ++- content/events/src/nsEventStateManager.h | 14 +- widget/public/nsGUIEvent.h | 36 ++- widget/public/nsGUIEventIPC.h | 54 +++- widget/src/windows/nsWindow.cpp | 344 ++++++++++++++------- widget/src/windows/nsWindow.h | 19 +- widget/src/windows/nsWindowDefs.h | 4 + 7 files changed, 385 insertions(+), 132 deletions(-) diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index dd06c8244294..b64732025582 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -1394,6 +1394,12 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext, handler.OnQueryDOMWidgetHittest(static_cast(aEvent)); } break; + case NS_QUERY_SCROLL_TARGET_INFO: + { + DoQueryScrollTargetInfo(static_cast(aEvent), + aTargetFrame); + break; + } case NS_SELECTION_SET: { nsSelectionEvent *selectionEvent = @@ -2564,7 +2570,8 @@ nsresult nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame, nsMouseScrollEvent* aMouseEvent, nsIScrollableFrame::ScrollUnit aScrollQuantity, - PRBool aAllowScrollSpeedOverride) + PRBool aAllowScrollSpeedOverride, + nsQueryContentEvent* aQueryEvent) { nsIScrollableFrame* frameToScroll = nsnull; nsIFrame* scrollFrame = aTargetFrame; @@ -2643,6 +2650,19 @@ nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame, } if (!passToParent && frameToScroll) { + if (aQueryEvent) { + nscoord appUnitsPerDevPixel = + aTargetFrame->PresContext()->AppUnitsPerDevPixel(); + aQueryEvent->mReply.mLineHeight = + frameToScroll->GetLineScrollAmount().height / appUnitsPerDevPixel; + aQueryEvent->mReply.mPageHeight = + frameToScroll->GetPageScrollAmount().height / appUnitsPerDevPixel; + aQueryEvent->mReply.mPageWidth = + frameToScroll->GetPageScrollAmount().width / appUnitsPerDevPixel; + aQueryEvent->mSucceeded = PR_TRUE; + return NS_OK; + } + if (aScrollQuantity == nsIScrollableFrame::LINES) { numLines = nsMouseWheelTransaction::AccelerateWheelDelta(numLines, isHorizontal, @@ -2670,7 +2690,9 @@ nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame, nsIScrollableFrame::ScrollMode mode; if (aMouseEvent->scrollFlags & nsMouseScrollEvent::kNoDefer) { mode = nsIScrollableFrame::INSTANT; - } else if (aScrollQuantity != nsIScrollableFrame::DEVICE_PIXELS) { + } else if (aScrollQuantity != nsIScrollableFrame::DEVICE_PIXELS || + (aMouseEvent->scrollFlags & + nsMouseScrollEvent::kAllowSmoothScroll) != 0) { mode = nsIScrollableFrame::SMOOTH; } else { mode = nsIScrollableFrame::NORMAL; @@ -2688,7 +2710,7 @@ nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame, aTargetFrame->PresContext()->FrameManager()->GetRootFrame()); if (newFrame) return DoScrollText(newFrame, aMouseEvent, aScrollQuantity, - aAllowScrollSpeedOverride); + aAllowScrollSpeedOverride, aQueryEvent); } aMouseEvent->scrollOverflow = numLines; @@ -3051,7 +3073,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext, } if (aEvent->message == NS_MOUSE_PIXEL_SCROLL) { - if (action == MOUSE_SCROLL_N_LINES || + if (action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE || (msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) { action = MOUSE_SCROLL_PIXELS; } else { @@ -3059,7 +3081,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext, action = -1; } } else if (msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) { - if (action == MOUSE_SCROLL_N_LINES || + if (useSysNumLines || action == MOUSE_SCROLL_N_LINES || (msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) { // Don't scroll lines when a pixel scroll event will follow. // Also, don't do history scrolling or zooming for momentum scrolls. @@ -4646,6 +4668,20 @@ nsEventStateManager::DoContentCommandScrollEvent(nsContentCommandEvent* aEvent) return NS_OK; } +void +nsEventStateManager::DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent, + nsIFrame* aTargetFrame) +{ + nsMouseScrollEvent* msEvent = aEvent->mInput.mMouseScrollEvent; + nsIScrollableFrame::ScrollUnit unit; + if (msEvent->scrollFlags & nsMouseScrollEvent::kIsFullPage) { + unit = nsIScrollableFrame::PAGES; + } else { + unit = nsIScrollableFrame::LINES; + } + DoScrollText(aTargetFrame, msEvent, unit, PR_FALSE, aEvent); +} + void nsEventStateManager::SetActiveManager(nsEventStateManager* aNewESM, nsIContent* aContent) diff --git a/content/events/src/nsEventStateManager.h b/content/events/src/nsEventStateManager.h index 5d64ea9a2680..60efc71c40b1 100644 --- a/content/events/src/nsEventStateManager.h +++ b/content/events/src/nsEventStateManager.h @@ -324,10 +324,19 @@ protected: nsMouseScrollEvent* aEvent, nsPresContext* aPresContext, nsEventStatus* aStatus); + /** + * @param aQueryEvent If you set vailid pointer for this, DoScrollText() + * computes the line-height and page size of current + * mouse wheel scroll target and sets it to the event. + * And then, this method does NOT scroll any scrollable + * elements. I.e., you can just query the scroll target + * information. + */ nsresult DoScrollText(nsIFrame* aTargetFrame, nsMouseScrollEvent* aMouseEvent, nsIScrollableFrame::ScrollUnit aScrollQuantity, - PRBool aAllowScrollSpeedOverride); + PRBool aAllowScrollSpeedOverride, + nsQueryContentEvent* aQueryEvent = nsnull); void DoScrollHistory(PRInt32 direction); void DoScrollZoom(nsIFrame *aTargetFrame, PRInt32 adjustment); nsresult GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv); @@ -397,6 +406,9 @@ protected: nsresult DoContentCommandEvent(nsContentCommandEvent* aEvent); nsresult DoContentCommandScrollEvent(nsContentCommandEvent* aEvent); + void DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent, + nsIFrame* aTargetFrame); + PRBool RemoteQueryContentEvent(nsEvent *aEvent); mozilla::dom::TabParent *GetCrossProcessTarget(); PRBool IsTargetCrossProcess(nsGUIEvent *aEvent); diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index ddea45e1bd0e..3747057b2262 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -415,6 +415,12 @@ class nsHashKey; // Query if the DOM element under nsEvent::refPoint belongs to our widget // or not. #define NS_QUERY_DOM_WIDGET_HITTEST (NS_QUERY_CONTENT_EVENT_START + 9) +// Query for some information about mouse wheel event's target +// XXX This is used only for supporting high resolution mouse scroll on Windows +// and it's going to be reimplemented with another approach. At that time, +// this even is going to be removed. Therefore, DON'T use this event for +// other purpose. +#define NS_QUERY_SCROLL_TARGET_INFO (NS_QUERY_CONTENT_EVENT_START + 99) // Video events #ifdef MOZ_MEDIA @@ -1188,9 +1194,11 @@ public: // as needed. kNoDefer = 1 << 5, // For scrollable views, indicates scroll should not // occur asynchronously. - kIsMomentum = 1 << 6 // Marks scroll events that aren't controlled by the + kIsMomentum = 1 << 6, // Marks scroll events that aren't controlled by the // user but fire automatically as the result of a // "momentum" scroll. + kAllowSmoothScroll = 1 << 7 // Allow smooth scroll for the pixel scroll + // event. }; nsMouseScrollEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w) @@ -1285,6 +1293,13 @@ public: refPoint = aPoint; } + void InitForQueryScrollTargetInfo(nsMouseScrollEvent* aEvent) + { + NS_ASSERTION(message == NS_QUERY_SCROLL_TARGET_INFO, + "wrong initializer is called"); + mInput.mMouseScrollEvent = aEvent; + } + PRUint32 GetSelectionStart(void) const { NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT, @@ -1304,6 +1319,8 @@ public: struct { PRUint32 mOffset; PRUint32 mLength; + // used by NS_QUERY_SCROLL_TARGET_INFO + nsMouseScrollEvent* mMouseScrollEvent; } mInput; struct { void* mContentsRoot; @@ -1317,6 +1334,10 @@ public: PRPackedBool mWidgetIsHit; // true if DOM element under mouse belongs to widget // used by NS_QUERY_SELECTION_AS_TRANSFERABLE nsCOMPtr mTransferable; + // used by NS_QUERY_SCROLL_TARGET_INFO + PRInt32 mLineHeight; + PRInt32 mPageWidth; + PRInt32 mPageHeight; } mReply; enum { @@ -1620,15 +1641,7 @@ enum nsDragDropEventStatus { ((evnt)->message == NS_PLUGIN_FOCUS)) #define NS_IS_QUERY_CONTENT_EVENT(evnt) \ - (((evnt)->message == NS_QUERY_SELECTED_TEXT) || \ - ((evnt)->message == NS_QUERY_TEXT_CONTENT) || \ - ((evnt)->message == NS_QUERY_CARET_RECT) || \ - ((evnt)->message == NS_QUERY_TEXT_RECT) || \ - ((evnt)->message == NS_QUERY_EDITOR_RECT) || \ - ((evnt)->message == NS_QUERY_CONTENT_STATE) || \ - ((evnt)->message == NS_QUERY_SELECTION_AS_TRANSFERABLE) || \ - ((evnt)->message == NS_QUERY_CHARACTER_AT_POINT) || \ - ((evnt)->message == NS_QUERY_DOM_WIDGET_HITTEST)) + ((evnt)->eventStructType == NS_QUERY_CONTENT_EVENT) #define NS_IS_SELECTION_EVENT(evnt) \ (((evnt)->message == NS_SELECTION_SET)) @@ -1670,7 +1683,8 @@ enum nsDragDropEventStatus { // cases, you should use NS_IS_IME_RELATED_EVENT instead. #define NS_IS_IME_RELATED_EVENT(evnt) \ (NS_IS_IME_EVENT(evnt) || \ - NS_IS_QUERY_CONTENT_EVENT(evnt) || \ + (NS_IS_QUERY_CONTENT_EVENT(evnt) && \ + evnt->message != NS_QUERY_SCROLL_TARGET_INFO) || \ NS_IS_SELECTION_EVENT(evnt)) /* diff --git a/widget/public/nsGUIEventIPC.h b/widget/public/nsGUIEventIPC.h index 9c1cb2be9696..78901256e199 100644 --- a/widget/public/nsGUIEventIPC.h +++ b/widget/public/nsGUIEventIPC.h @@ -109,6 +109,50 @@ struct ParamTraits } }; +template<> +struct ParamTraits +{ + typedef nsMouseEvent_base paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, static_cast(aParam)); + WriteParam(aMsg, aParam.button); + WriteParam(aMsg, aParam.pressure); + WriteParam(aMsg, aParam.inputSource); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, static_cast(aResult)) && + ReadParam(aMsg, aIter, &aResult->button) && + ReadParam(aMsg, aIter, &aResult->pressure) && + ReadParam(aMsg, aIter, &aResult->inputSource); + } +}; + +template<> +struct ParamTraits +{ + typedef nsMouseScrollEvent paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, static_cast(aParam)); + WriteParam(aMsg, aParam.scrollFlags); + WriteParam(aMsg, aParam.delta); + WriteParam(aMsg, aParam.scrollOverflow); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + return ReadParam(aMsg, aIter, static_cast(aResult)) && + ReadParam(aMsg, aIter, &aResult->scrollFlags) && + ReadParam(aMsg, aIter, &aResult->delta) && + ReadParam(aMsg, aIter, &aResult->scrollOverflow); + } +}; + template<> struct ParamTraits { @@ -235,12 +279,16 @@ struct ParamTraits WriteParam(aMsg, aParam.mSucceeded); WriteParam(aMsg, aParam.mInput.mOffset); WriteParam(aMsg, aParam.mInput.mLength); + WriteParam(aMsg, *aParam.mInput.mMouseScrollEvent); WriteParam(aMsg, aParam.mReply.mOffset); WriteParam(aMsg, aParam.mReply.mString); WriteParam(aMsg, aParam.mReply.mRect); WriteParam(aMsg, aParam.mReply.mReversed); WriteParam(aMsg, aParam.mReply.mHasSelection); WriteParam(aMsg, aParam.mReply.mWidgetIsHit); + WriteParam(aMsg, aParam.mReply.mLineHeight); + WriteParam(aMsg, aParam.mReply.mPageHeight); + WriteParam(aMsg, aParam.mReply.mPageWidth); } static bool Read(const Message* aMsg, void** aIter, paramType* aResult) @@ -250,12 +298,16 @@ struct ParamTraits ReadParam(aMsg, aIter, &aResult->mSucceeded) && ReadParam(aMsg, aIter, &aResult->mInput.mOffset) && ReadParam(aMsg, aIter, &aResult->mInput.mLength) && + ReadParam(aMsg, aIter, aResult->mInput.mMouseScrollEvent) && ReadParam(aMsg, aIter, &aResult->mReply.mOffset) && ReadParam(aMsg, aIter, &aResult->mReply.mString) && ReadParam(aMsg, aIter, &aResult->mReply.mRect) && ReadParam(aMsg, aIter, &aResult->mReply.mReversed) && ReadParam(aMsg, aIter, &aResult->mReply.mHasSelection) && - ReadParam(aMsg, aIter, &aResult->mReply.mWidgetIsHit); + ReadParam(aMsg, aIter, &aResult->mReply.mWidgetIsHit) && + ReadParam(aMsg, aIter, &aResult->mReply.mLineHeight) && + ReadParam(aMsg, aIter, &aResult->mReply.mPageHeight) && + ReadParam(aMsg, aIter, &aResult->mReply.mPageWidth); } }; diff --git a/widget/src/windows/nsWindow.cpp b/widget/src/windows/nsWindow.cpp index 8dd2e2de26e6..79daf8bea828 100644 --- a/widget/src/windows/nsWindow.cpp +++ b/widget/src/windows/nsWindow.cpp @@ -298,6 +298,18 @@ PRUint32 nsWindow::sOOPPPluginFocusEvent = MSG nsWindow::sRedirectedKeyDown; +PRBool nsWindow::sNeedsToInitMouseWheelSettings = PR_TRUE; +ULONG nsWindow::sMouseWheelScrollLines = 0; +ULONG nsWindow::sMouseWheelScrollChars = 0; + +HWND nsWindow::sLastMouseWheelWnd = NULL; +PRInt32 nsWindow::sRemainingDeltaForScroll = 0; +PRInt32 nsWindow::sRemainingDeltaForPixel = 0; +PRBool nsWindow::sLastMouseWheelDeltaIsPositive = PR_FALSE; +PRBool nsWindow::sLastMouseWheelOrientationIsVertical = PR_FALSE; +PRBool nsWindow::sLastMouseWheelUnitIsPage = PR_FALSE; +PRUint32 nsWindow::sLastMouseWheelTime = 0; + /************************************************************** * * SECTION: globals variables @@ -4524,8 +4536,6 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, PRBool result = PR_FALSE; // call the default nsWindow proc *aRetValue = 0; - static PRBool getWheelInfo = PR_TRUE; - #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN // Glass hit testing w/custom transparent margins LRESULT dwmHitResult; @@ -5187,7 +5197,12 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, break; case WM_SETTINGCHANGE: - getWheelInfo = PR_TRUE; + switch (wParam) { + case SPI_SETWHEELSCROLLLINES: + case SPI_SETWHEELSCROLLCHARS: + sNeedsToInitMouseWheelSettings = PR_TRUE; + break; + } break; case WM_INPUTLANGCHANGEREQUEST: @@ -5259,8 +5274,9 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam, // If OnMouseWheel returns false, OnMouseWheel processed the event internally. // 'result' and 'aRetValue' will be set based on what we did with the event, so // we should fall through. - if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue)) + if (OnMouseWheel(msg, wParam, lParam, result, aRetValue)) { return result; + } } break; @@ -6281,118 +6297,152 @@ PRUint16 nsWindow::GetMouseInputSource() return inputSource; } +/* static */ void +nsWindow::InitMouseWheelScrollData() +{ + if (!sNeedsToInitMouseWheelSettings) { + return; + } + sNeedsToInitMouseWheelSettings = PR_FALSE; + ResetRemainingWheelDelta(); + + if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, + &sMouseWheelScrollLines, 0)) { + NS_WARNING("Failed to get SPI_GETWHEELSCROLLLINES"); + sMouseWheelScrollLines = 3; + } else if (sMouseWheelScrollLines > WHEEL_DELTA) { + // sMouseWheelScrollLines usually equals 3 or 0 (for no scrolling) + // However, if sMouseWheelScrollLines > WHEEL_DELTA, we assume that + // the mouse driver wants a page scroll. The docs state that + // sMouseWheelScrollLines should explicitly equal WHEEL_PAGESCROLL, but + // since some mouse drivers use an arbitrary large number instead, + // we have to handle that as well. + sMouseWheelScrollLines = WHEEL_PAGESCROLL; + } + + if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, + &sMouseWheelScrollChars, 0)) { + NS_ASSERTION(!nsUXThemeData::sIsVistaOrLater, + "Failed to get SPI_GETWHEELSCROLLCHARS"); + sMouseWheelScrollChars = 1; + } else if (sMouseWheelScrollChars > WHEEL_DELTA) { + // See the comments for the case sMouseWheelScrollLines > WHEEL_DELTA. + sMouseWheelScrollChars = WHEEL_PAGESCROLL; + } +} + +/* static */ +void +nsWindow::ResetRemainingWheelDelta() +{ + sRemainingDeltaForPixel = 0; + sRemainingDeltaForScroll = 0; + sLastMouseWheelWnd = NULL; +} + +static PRInt32 RoundDelta(double aDelta) +{ + return aDelta >= 0 ? (PRInt32)NS_floor(aDelta) : (PRInt32)NS_ceil(aDelta); +} + /* * OnMouseWheel - mouse wheel event processing. This was originally embedded * within the message case block. If returning true result should be returned * immediately (no more processing). */ -PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue) +PRBool +nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam, + PRBool& aHandled, LRESULT *aRetValue) { - // Handle both flavors of mouse wheel events. - static int iDeltaPerLine, iDeltaPerChar; - static ULONG ulScrollLines, ulScrollChars = 1; - static int currentVDelta, currentHDelta; - static HWND currentWindow = 0; + InitMouseWheelScrollData(); - PRBool isVertical = msg == WM_MOUSEWHEEL; - - // Get mouse wheel metrics (but only once). - if (getWheelInfo) { - getWheelInfo = PR_FALSE; - - SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0); - - // ulScrollLines usually equals 3 or 0 (for no scrolling) - // WHEEL_DELTA equals 120, so iDeltaPerLine will be 40. - - // However, if ulScrollLines > WHEEL_DELTA, we assume that - // the mouse driver wants a page scroll. The docs state that - // ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but - // since some mouse drivers use an arbitrary large number instead, - // we have to handle that as well. - - iDeltaPerLine = 0; - if (ulScrollLines) { - if (ulScrollLines <= WHEEL_DELTA) { - iDeltaPerLine = WHEEL_DELTA / ulScrollLines; - } else { - ulScrollLines = WHEEL_PAGESCROLL; - } - } - - if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, - &ulScrollChars, 0)) { - // Note that we may always fail to get the value before Win Vista. - ulScrollChars = 1; - } - - iDeltaPerChar = 0; - if (ulScrollChars) { - if (ulScrollChars <= WHEEL_DELTA) { - iDeltaPerChar = WHEEL_DELTA / ulScrollChars; - } else { - ulScrollChars = WHEEL_PAGESCROLL; - } - } + PRBool isVertical = (aMessage == WM_MOUSEWHEEL); + if ((isVertical && sMouseWheelScrollLines == 0) || + (!isVertical && sMouseWheelScrollChars == 0)) { + // XXX I think that we should dispatch mouse wheel events even if the + // operation will not scroll because the wheel operation really happened + // and web application may want to handle the event for non-scroll action. + ResetRemainingWheelDelta(); + *aRetValue = isVertical ? TRUE : FALSE; // means we don't process it + aHandled = PR_FALSE; + return PR_FALSE; } - if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) || - (!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar)) - return PR_FALSE; // break - // The mousewheel event will be dispatched to the toplevel // window. We need to give it to the child window. PRBool quit; - if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit)) + if (!HandleScrollingPlugins(aMessage, aWParam, aLParam, + aHandled, aRetValue, quit)) { + ResetRemainingWheelDelta(); return quit; // return immediately if it's not our window + } - // We should cancel the surplus delta if the current window is not - // same as previous. - if (currentWindow != mWnd) { - currentVDelta = 0; - currentHDelta = 0; - currentWindow = mWnd; - } - - nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this); - scrollEvent.delta = 0; - if (isVertical) { - scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical; - if (ulScrollLines == WHEEL_PAGESCROLL) { - scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage; - scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1; - } else { - currentVDelta -= (short) HIWORD (wParam); - if (PR_ABS(currentVDelta) >= iDeltaPerLine) { - scrollEvent.delta = currentVDelta / iDeltaPerLine; - currentVDelta %= iDeltaPerLine; - } - } - } else { - scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal; - if (ulScrollChars == WHEEL_PAGESCROLL) { - scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage; - scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1; - } else { - currentHDelta += (short) HIWORD (wParam); - if (PR_ABS(currentHDelta) >= iDeltaPerChar) { - scrollEvent.delta = currentHDelta / iDeltaPerChar; - currentHDelta %= iDeltaPerChar; - } - } - } - - if (!scrollEvent.delta) { - // We store the wheel delta, and it will be used next wheel message, so, - // we consume this message actually. We shouldn't call next wndproc. - result = PR_TRUE; - return PR_FALSE; // break + PRInt32 nativeDelta = (short)HIWORD(aWParam); + if (!nativeDelta) { + *aRetValue = isVertical ? TRUE : FALSE; // means we don't process it + aHandled = PR_FALSE; + ResetRemainingWheelDelta(); + return PR_FALSE; // We cannot process this message } // The event may go to a plug-in which already dispatched this message. // Then, the event can cause deadlock. We should unlock the sender here. ::ReplyMessage(isVertical ? 0 : TRUE); + PRBool isPageScroll = + ((isVertical && sMouseWheelScrollLines == WHEEL_PAGESCROLL) || + (!isVertical && sMouseWheelScrollChars == WHEEL_PAGESCROLL)); + + // Discard the remaining delta if current wheel message and last one are + // received by different window or to scroll different direction or + // different unit scroll. Furthermore, if the last event was too old. + PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow()); + if (sLastMouseWheelWnd && + (sLastMouseWheelWnd != mWnd || + sLastMouseWheelDeltaIsPositive != (nativeDelta > 0) || + sLastMouseWheelOrientationIsVertical != isVertical || + sLastMouseWheelUnitIsPage != isPageScroll || + now - sLastMouseWheelTime > 1500)) { + ResetRemainingWheelDelta(); + } + sLastMouseWheelWnd = mWnd; + sLastMouseWheelDeltaIsPositive = (nativeDelta > 0); + sLastMouseWheelOrientationIsVertical = isVertical; + sLastMouseWheelUnitIsPage = isPageScroll; + sLastMouseWheelTime = now; + + nsMouseScrollEvent testEvent(PR_TRUE, NS_MOUSE_SCROLL, this); + InitEvent(testEvent); + testEvent.scrollFlags = isPageScroll ? nsMouseScrollEvent::kIsFullPage : 0; + testEvent.scrollFlags |= isVertical ? nsMouseScrollEvent::kIsVertical : + nsMouseScrollEvent::kIsHorizontal; + testEvent.delta = sLastMouseWheelDeltaIsPositive ? -1 : 1; + nsQueryContentEvent queryEvent(PR_TRUE, NS_QUERY_SCROLL_TARGET_INFO, this); + InitEvent(queryEvent); + queryEvent.InitForQueryScrollTargetInfo(&testEvent); + DispatchWindowEvent(&queryEvent); + // If the necessary interger isn't larger than 0, we should assume that + // the event failed for us. + if (queryEvent.mSucceeded) { + if (isPageScroll) { + if (isVertical) { + queryEvent.mSucceeded = (queryEvent.mReply.mPageHeight > 0); + } else { + queryEvent.mSucceeded = (queryEvent.mReply.mPageWidth > 0); + } + } else { + queryEvent.mSucceeded = (queryEvent.mReply.mLineHeight > 0); + } + } + + *aRetValue = isVertical ? FALSE : TRUE; // means we process this message + nsModifierKeyState modKeyState; + + // Our positive delta value means to bottom or right. + // But positive nativeDelta value means to top or right. + // Use orienter for computing our delta value. + PRInt32 orienter = isVertical ? -1 : 1; + // Assume the Control key is down if the Elantech touchpad has sent the // mis-ordered WM_KEYDOWN/WM_MOUSEWHEEL messages. (See the comment in // OnKeyUp.) @@ -6401,25 +6451,97 @@ PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& ge static_cast(::GetMessageTime()) < mAssumeWheelIsZoomUntil) { isControl = PR_TRUE; } else { - isControl = IS_VK_DOWN(NS_VK_CONTROL); + isControl = modKeyState.mIsControlDown; } - scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT); - scrollEvent.isControl = isControl; - scrollEvent.isMeta = PR_FALSE; - scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT); + nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this); InitEvent(scrollEvent); - if (nsnull != mEventCallback) { - result = DispatchWindowEvent(&scrollEvent); - } - // Note that we should return zero if we process WM_MOUSEWHEEL. - // But if we process WM_MOUSEHWHEEL, we should return non-zero. + // If the query event failed, we cannot send pixel events. + scrollEvent.scrollFlags = + queryEvent.mSucceeded ? nsMouseScrollEvent::kHasPixels : 0; + scrollEvent.isShift = modKeyState.mIsShiftDown; + scrollEvent.isControl = isControl; + scrollEvent.isMeta = PR_FALSE; + scrollEvent.isAlt = modKeyState.mIsAltDown; - if (result) - *aRetValue = isVertical ? 0 : TRUE; - - return PR_FALSE; // break; -} + PRInt32 nativeDeltaForScroll = nativeDelta + sRemainingDeltaForScroll; + + if (isPageScroll) { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage; + if (isVertical) { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical; + } else { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsHorizontal; + } + scrollEvent.delta = nativeDeltaForScroll * orienter / WHEEL_DELTA; + PRInt32 recomputedNativeDelta = scrollEvent.delta * orienter / WHEEL_DELTA; + sRemainingDeltaForScroll = nativeDeltaForScroll - recomputedNativeDelta; + } else { + double deltaPerUnit; + if (isVertical) { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical; + deltaPerUnit = (double)WHEEL_DELTA / sMouseWheelScrollLines; + } else { + scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsHorizontal; + deltaPerUnit = (double)WHEEL_DELTA / sMouseWheelScrollChars; + } + scrollEvent.delta = + RoundDelta((double)nativeDeltaForScroll * orienter / deltaPerUnit); + PRInt32 recomputedNativeDelta = + (PRInt32)(scrollEvent.delta * orienter * deltaPerUnit); + sRemainingDeltaForScroll = nativeDeltaForScroll - recomputedNativeDelta; + } + + if (scrollEvent.delta) { + aHandled = DispatchWindowEvent(&scrollEvent); + if (mOnDestroyCalled) { + ResetRemainingWheelDelta(); + return PR_FALSE; + } + } + + // If the query event failed, we cannot send pixel events. + if (!queryEvent.mSucceeded) { + sRemainingDeltaForPixel = 0; + return PR_FALSE; + } + + nsMouseScrollEvent pixelEvent(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this); + InitEvent(pixelEvent); + pixelEvent.scrollFlags = nsMouseScrollEvent::kAllowSmoothScroll | + (scrollEvent.scrollFlags & ~nsMouseScrollEvent::kHasPixels); + pixelEvent.isShift = modKeyState.mIsShiftDown; + pixelEvent.isControl = modKeyState.mIsControlDown; + pixelEvent.isMeta = PR_FALSE; + pixelEvent.isAlt = modKeyState.mIsAltDown; + + PRInt32 nativeDeltaForPixel = nativeDelta + sRemainingDeltaForPixel; + + double deltaPerPixel; + if (isPageScroll) { + if (isVertical) { + deltaPerPixel = (double)WHEEL_DELTA / queryEvent.mReply.mPageHeight; + } else { + deltaPerPixel = (double)WHEEL_DELTA / queryEvent.mReply.mPageWidth; + } + } else { + if (isVertical) { + deltaPerPixel = (double)WHEEL_DELTA / sMouseWheelScrollLines; + } else { + deltaPerPixel = (double)WHEEL_DELTA / sMouseWheelScrollChars; + } + deltaPerPixel /= queryEvent.mReply.mLineHeight; + } + pixelEvent.delta = + RoundDelta((double)nativeDeltaForPixel * orienter / deltaPerPixel); + PRInt32 recomputedNativeDelta = + (PRInt32)(pixelEvent.delta * orienter * deltaPerPixel); + sRemainingDeltaForPixel = nativeDeltaForPixel - recomputedNativeDelta; + if (pixelEvent.delta != 0) { + aHandled = DispatchWindowEvent(&pixelEvent); + } + return PR_FALSE; +} static PRBool StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1, diff --git a/widget/src/windows/nsWindow.h b/widget/src/windows/nsWindow.h index 75a2b4bb7831..d6d98ca5c63a 100644 --- a/widget/src/windows/nsWindow.h +++ b/widget/src/windows/nsWindow.h @@ -411,8 +411,8 @@ protected: BOOL OnInputLangChange(HKL aHKL); PRBool OnPaint(HDC aDC, PRUint32 aNestingLevel); void OnWindowPosChanged(WINDOWPOS *wp, PRBool& aResult); - PRBool OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, - PRBool& result, PRBool& getWheelInfo, + PRBool OnMouseWheel(UINT aMessage, WPARAM aWParam, + LPARAM aLParam, PRBool& aHandled, LRESULT *aRetValue); void OnWindowPosChanging(LPWINDOWPOS& info); @@ -616,6 +616,20 @@ protected: // was reirected to SendInput() API by OnKeyDown(). static MSG sRedirectedKeyDown; + static PRBool sNeedsToInitMouseWheelSettings; + static ULONG sMouseWheelScrollLines; + static ULONG sMouseWheelScrollChars; + static void InitMouseWheelScrollData(); + + static HWND sLastMouseWheelWnd; + static PRInt32 sRemainingDeltaForScroll; + static PRInt32 sRemainingDeltaForPixel; + static PRBool sLastMouseWheelDeltaIsPositive; + static PRBool sLastMouseWheelOrientationIsVertical; + static PRBool sLastMouseWheelUnitIsPage; + static PRUint32 sLastMouseWheelTime; // in milliseconds + static void ResetRemainingWheelDelta(); + // If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is // redirected message, OnKeyDowm() prevents to dispatch NS_KEY_DOWN event // because it has been dispatched before the message was redirected. @@ -649,7 +663,6 @@ protected: nsRefPtr mWindow; const MSG &mMsg; }; - }; /** diff --git a/widget/src/windows/nsWindowDefs.h b/widget/src/windows/nsWindowDefs.h index 3bd48bc2eb86..dfb593909c5c 100644 --- a/widget/src/windows/nsWindowDefs.h +++ b/widget/src/windows/nsWindowDefs.h @@ -90,6 +90,10 @@ #define SPI_GETWHEELSCROLLCHARS 0x006C #endif +#ifndef SPI_SETWHEELSCROLLCHARS +#define SPI_SETWHEELSCROLLCHARS 0x006D +#endif + #ifndef MAPVK_VSC_TO_VK #define MAPVK_VK_TO_VSC 0 #define MAPVK_VSC_TO_VK 1 From 0c316873327a2df8ff0ec89a41f956c7676c1013 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Sun, 15 May 2011 05:47:48 -0400 Subject: [PATCH 04/15] Bug 653311 - Switch jprof from hand-rolled stackwalk code to glibc's backtrace() to work with modern x86 Linuxes, improve jprof output, update README - r=jim_nance (per bz) --- tools/jprof/README.html | 133 ++++++++++++++++------------- tools/jprof/leaky.cpp | 149 ++++++++++++++++++++++++++------- tools/jprof/leaky.h | 7 +- tools/jprof/stub/Makefile.in | 3 + tools/jprof/stub/libmalloc.cpp | 69 ++++++++++++--- tools/jprof/stub/libmalloc.h | 1 + 6 files changed, 262 insertions(+), 100 deletions(-) diff --git a/tools/jprof/README.html b/tools/jprof/README.html index 9b910afc8ff6..3d5bc521e12a 100644 --- a/tools/jprof/README.html +++ b/tools/jprof/README.html @@ -6,7 +6,8 @@

The Jprof Profiler

-jim_nance@yahoo.com +jim_nance@yahoo.com

+Recent (4/2011) updates Randell Jesup (see bugzilla for contact info)


@@ -46,12 +47,26 @@ default pull. To do this do: ac_add_options --enable-jprof to your .mozconfig) and making sure that you do not have the --enable-strip configure option set -- jprof needs symbols to -operate.

+operate. On many architectures with GCC, you'll need to add +--enable-optimize="-O3 -fno-omit-frame-pointer" or the +equivalent to ensure frame pointer generation in the compiler you're using.

Finally, build mozilla with your new configuration. Now you can run jprof.

Usage

- +Options: +
    +
  • -s depth : Limit depth looked at from captured stack + frames
  • +
  • -v : Output some information about the symbols, memory map, etc.
  • +
  • -t : Group output according to thread. Requires external + LD_PRELOAD library to help force sampling of spawned threads; jprof + normally captures the main thread only. See gprof-helper; + it may need adaption for jprof.
  • +
  • -e exclusion : Allows excluding specific stack frames
  • +
  • -i inclusion : Allows including specific stack frames
  • +
The behavior of jprof is determined by the value of the JPROF_FLAGS environment variable. This environment variable can be composed of several substrings which have the following meanings: @@ -67,7 +82,8 @@ which have the following meanings:
  • JP_FIRST=x : Wait x seconds before starting the timer
  • JP_PERIOD=y : Set timer to interrupt every y seconds. Only - values of y strictly greater than 0.001 are supported. + values of y greater than or equal to 0.001 are supported. Default is + 0.050 (50ms).
  • JP_REALTIME : Do the profiling in intervals of real time rather than intervals of time used by the mozilla process (and the kernel @@ -103,10 +119,10 @@ being profiled
             setenv JPROF_FLAGS "JP_START JP_FIRST=3 JP_PERIOD=0.025" 
    -
  • To make the timer start on your signal and fire every 1.5 milliseconds of +
  • To make the timer start on your signal and fire every 1 millisecond of program time use:
    -        setenv JPROF_FLAGS "JP_DEFER JP_PERIOD=0.0015" 
    + setenv JPROF_FLAGS "JP_DEFER JP_PERIOD=0.001"
  • To make the timer start on your signal and fire every 10 milliseconds of wall-clock time use: @@ -189,82 +205,87 @@ corresponding to one function. A typical section looks something like this:
    -             141300 PL_ProcessPendingEvents
    -                927 PL_ProcessEventsBeforeID
    - 29358   0   142227 PL_HandleEvent
    -              92394 nsInputStreamReadyEvent::EventHandler(PLEvent*)
    -              49181 HandlePLEvent(ReflowEvent*)
    -                481 handleTimerEvent(TimerEventType*)
    -                158 nsTransportStatusEvent::HandleEvent(PLEvent*)
    -                  9 PL_DestroyEvent
    -
    -                  4 __restore_rt
    + index  Count         Hits      Function Name
    +                           545 (46.4%) nsBlockFrame::ReflowInlineFrames(nsBlockReflowState&, nsLineList_iterator, int*)
    +                           100 (8.5%)  nsBlockFrame::ReflowDirtyLines(nsBlockReflowState&)
    + 72870      4 (0.3%)       645 (54.9%) nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState&, nsLineLayout&, nsLineList_iterator, nsFlowAreaRect&, int&, nsFloatManager::SavedState*, int*, LineReflowStatus*, int)
    +                           545 (46.4%) nsBlockFrame::ReflowInlineFrame(nsBlockReflowState&, nsLineLayout&, nsLineList_iterator, nsIFrame*, LineReflowStatus*)
    +                            83 (7.1%)  nsBlockFrame::PlaceLine(nsBlockReflowState&, nsLineLayout&, nsLineList_iterator, nsFloatManager::SavedState*, nsRect&, int&, int*)
    +                             9 (0.8%)  nsLineLayout::BeginLineReflow(int, int, int, int, int, int)
    +                             1 (0.1%)  nsTextFrame::GetType() const
    +                             1 (0.1%)  nsLineLayout::RelativePositionFrames(nsOverflowAreas&)
    +                             1 (0.1%)  __i686.get_pc_thunk.bx
    +                             1 (0.1%)  PL_ArenaAllocate
     
    The information this block tells us is:
      -
    • There were 0 profiler hits in PL_HandleEvent -
    • There were 142227 profiler hits under PL_HandleEvent. Of these: +
    • There were 4 profiler hits in nsBlockFrame::DoReflowInlineFrames +
    • There were 645 profiler hits in or under nsBlockFrame::DoReflowInlineFrames. Of these:
        -
      • 92394 were in or under nsInputStreamReadyEvent::EventHandler -
      • 49181 were in or under HandlePLEvent(ReflowEvent*) -
      • 481 were in or under handleTimerEvent -
      • 158 were in or under nsTransportStatusEvent::HandleEvent -
      • 9 were in or under PL_DestroyEvent -
      • 4 were in or under __restore_rt +
      • 545 were in or under nsBlockFrame::ReflowInlineFrame +
      • 83 were in or under nsBlockFrame::PlaceLine +
      • 9 were in or under nsLineLayout::BeginLineReflow +
      • 1 was in or under nsTextFrame::GetType +
      • 1 was in or under nsLineLayout::RelativePositionFrames +
      • 1 was in or under __i686.get_pc_thunk.bx +
      • 1 was in or under PL_ArenaAllocate
      -
    • Of these 142227 calls into PL_HandleEvent: +
    • Of these 645 calls into nsBlockFrame::DoReflowInlineFrames:
        -
      • 141300 came from PL_ProcessPendingEvents -
      • 927 came from PL_ProcessEventsBeforeID +
      • 545 came from nsBlockFrame::ReflowInlineFrames +
      • 100 came from nsBlockFrame::ReflowDirtyLines
    The rest of this section explains how to read this information off from the jprof output. -

    This block corresponds to the function PL_HandleEvent, which is +

    This block corresponds to the function nsBlockFrame::DoReflowInlineFrames, which is therefore bolded and not a link. The name of this function is preceded by -three numbers which have the following meaning. The number on the left (29358) -is the index number, and is not important. The center number (0) is the number -of times this function was interrupted by the timer. The last number (142227) -is the number of times this function was in the call stack when the timer went +five numbers which have the following meaning. The number on the left (72870) +is the index number, and is not important. The next number (4) and the +percentage following (0.3%) are the number +of times this function was interrupted by the timer and the percentage of +the total hits that is. The last number pair ("645 (54.9%)") +are the number of times this function was in the call stack when the timer went off. That is, the timer went off while we were in code that was ultimately -called from PL_HandleEvent. +called from nsBlockFrame::DoReflowInlineFrames.

    For our example we can see that our function was in the call stack for -142227 interrupt ticks, but we were never the function that was running when -the interrupt arrived. +645 interrupt ticks, but we were only the function that was running when +the interrupt arrived 4 times.

    -The functions listed above the line for PL_HandleEvent are its +The functions listed above the line for nsBlockFrame::DoReflowInlineFrames are its callers. The numbers to the left of these function names are the numbers of times these functions were in the call stack as callers of -PL_HandleEvent. In our example, we were called 927 times by -PL_ProcessEventsBeforeID and 141300 times by -PL_ProcessPendingEvents. +nsBlockFrame::DoReflowInlineFrames. In our example, we were called 545 times by +nsBlockFrame::ReflowInlineFrames and 100 times by +nsBlockFrame::ReflowDirtyLines.

    -The functions listed below the line for PL_HandleEvent are its +The functions listed below the line for nsBlockFrame::DoReflowInlineFrames are its callees. The numbers to the left of the function names are the numbers of -times these functions were in the callstack as callees of PL_HandleEvent. In our example, of the 142227 profiler hits under PL_HandleEvent 92394 were under nsInputStreamReadyEvent::EventHandler, 49181 were under HandlePLEvent(ReflowEvent*), and so forth. +times these functions were in the callstack as callees of +nsBlockFrame::DoReflowInlineFrames and the corresponding percentages. In our example, of the 645 profiler hits under nsBlockFrame::DoReflowInlineFrames 545 were under nsBlockFrame::ReflowInlineFrame, 83 were under nsBlockFrame::PlaceLine, and so forth.

    + +NOTE: If there are loops of execution or recursion, the numbers will +not add up and percentages can exceed 100%. If a function directly calls +itself "(self)" will be appended to the line, but indirect recursion will +not be marked.

    Bugs

    -Jprof has only been tested under Red Hat Linux 6.0, 6.1, and 6.2. It does -not work under 6.0, though it is possible hack up the source code and make -it work there. The way I determine the stack trace from inside the -signal handler is tightly bound to the version of glibc that is running. -If you know of a more portable way to get this information please let -me know. - -

    Update

    +The current build of Jprof has only been tested under Ubuntu 8.04 LTS, but +should work under any fairly modern linux distribution using GCC/GLIBC. +Please update this document with any known compatibilities/incompatibilities. +

    +If you get an error:

    Inconsistency detected by ld.so: dl-open.c: 260: dl_open_worker: Assertion `_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT' failed! +

    that means you've hit a timing hole in the version of glibc you're +running. See Redhat bug 4578. + diff --git a/tools/jprof/leaky.cpp b/tools/jprof/leaky.cpp index bcc6c58a2f15..4ebd3887f789 100644 --- a/tools/jprof/leaky.cpp +++ b/tools/jprof/leaky.cpp @@ -1,3 +1,4 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -128,6 +129,7 @@ leaky::leaky() quiet = TRUE; showAddress = FALSE; + showThreads = FALSE; stackDepth = 100000; mappedLogFile = -1; @@ -149,7 +151,8 @@ leaky::~leaky() void leaky::usageError() { - fprintf(stderr, "Usage: %s prog log\n", (char*) applicationName); + fprintf(stderr, "Usage: %s [-v][-t] [-e exclude] [-i include] [-s stackdepth] prog log\n", (char*) applicationName); + fprintf(stderr, "\t-v: verbose\n\t-t: split threads\n"); exit(-1); } @@ -165,14 +168,15 @@ void leaky::initialize(int argc, char** argv) int arg; int errflg = 0; - while ((arg = getopt(argc, argv, "adEe:gh:i:r:Rs:tqx")) != -1) { + while ((arg = getopt(argc, argv, "adEe:gh:i:r:Rs:tqvx")) != -1) { switch (arg) { case '?': + default: errflg++; break; case 'a': break; - case 'A': + case 'A': // not implemented showAddress = TRUE; break; case 'd': @@ -184,7 +188,7 @@ void leaky::initialize(int argc, char** argv) break; case 'g': break; - case 'r': + case 'r': // not implemented roots.add(optarg); if (!includes.IsEmpty()) { errflg++; @@ -207,7 +211,12 @@ void leaky::initialize(int argc, char** argv) case 'x': break; case 'q': - quiet = TRUE; + break; + case 'v': + quiet = !quiet; + break; + case 't': + showThreads = TRUE; break; } } @@ -265,6 +274,10 @@ void leaky::LoadMap() void leaky::open() { + int threadArray[100]; // should auto-expand + int last_thread = -1; + int numThreads=0; + LoadMap(); setupSymbols(progFile); @@ -279,7 +292,61 @@ void leaky::open() firstLogEntry = (malloc_log_entry*) mapFile(mappedLogFile, PROT_READ, &size); lastLogEntry = (malloc_log_entry*)((char*)firstLogEntry + size); - analyze(); + fprintf(stdout,"Jprof Profile Report\n"); + fprintf(stdout,"

    Jprof Profile Report

    \n"); + + if (showThreads) + { + // Find all the threads captured + + // pthread/linux docs say the signal can be delivered to any thread in + // the process. In practice, it appears in Linux that it's always + // delivered to the thread that called setitimer(), and each thread can + // have a separate itimer. There's a support library for gprof that + // overlays pthread_create() to set timers in any threads you spawn. + + // This loop walks through all the call stacks we recorded + for (malloc_log_entry* lep=firstLogEntry; + lep < lastLogEntry; + lep = reinterpret_cast(&lep->pcs[lep->numpcs])) { + if (lep->thread != last_thread) + { + int i; + for (i=0; ithread == threadArray[i]) + break; + } + if (i == numThreads && + i < (int) (sizeof(threadArray)/sizeof(threadArray[0]))) + { + threadArray[i] = lep->thread; + numThreads++; + fprintf(stderr,"new thread %d\n",lep->thread); + } + } + } + fprintf(stderr,"Num threads %d\n",numThreads); + + fprintf(stdout,"
    Threads:

    \n");
    +    for (int i=0; i%d

    \n", + threadArray[i],threadArray[i]); + } + fprintf(stdout,"


    "); + + for (int i=0; i\n"); exit(0); } @@ -428,14 +495,19 @@ void leaky::dumpEntryToLog(malloc_log_entry* lep) displayStackTrace(stdout, lep); } -void leaky::generateReportHTML(FILE *fp, int *countArray, int count) +void leaky::generateReportHTML(FILE *fp, int *countArray, int count, int thread) { - fprintf(fp,"Jprof Profile Report\n"); - fprintf(fp,"

    Jprof Profile Report

    \n"); fprintf(fp,"
    "); - fprintf(fp,"flat | hierarchical"); + if (showThreads) + { + fprintf(fp,"
    Thread: %d

    ", + thread,thread); + } + fprintf(fp,"flat | hierarchical", + thread,thread); fprintf(fp,"

    \n"); + int totalTimerHits = count; int *rankingTable = new int[usefulSymbols]; for(int cnt=usefulSymbols; --cnt>=0; rankingTable[cnt]=cnt); @@ -464,23 +536,29 @@ void leaky::generateReportHTML(FILE *fp, int *countArray, int count) // this loop. Later we can get callers and callees into it like gprof // does fprintf(fp, - "

    Hierarchical Profile


    \n"); + "

    Hierarchical Profile


    \n", + thread); fprintf(fp, "
    \n");
    -  fprintf(fp, "%5s %5s    %4s %s\n",
    -  "index", "Count", "Hits", "Function Name");
    +  fprintf(fp, "%6s %6s         %4s      %s\n",
    +          "index", "Count", "Hits", "Function Name");
     
       for(i=0; i0; i++) {
         Symbol *sp=&externalSymbols[rankingTable[i]];
         
    -    sp->cntP.printReport(fp, this);
    +    sp->cntP.printReport(fp, this, rankingTable[i], totalTimerHits);
     
         char *symname = htmlify(sp->name);
    -    fprintf(fp, "%6d %3d %8d %s\n", rankingTable[i],
    -            sp->timerHit, rankingTable[i], countArray[rankingTable[i]],
    +    fprintf(fp, "%6d %6d (%3.1f%%)%s %8d (%3.1f%%)%s %s\n", 
    +            rankingTable[i],
    +            sp->timerHit, (sp->timerHit*1000/totalTimerHits)/10.0,
    +            (sp->timerHit*1000/totalTimerHits)/10.0 >= 10.0 ? "" : " ",
    +            rankingTable[i], countArray[rankingTable[i]],
    +            (countArray[rankingTable[i]]*1000/totalTimerHits)/10.0,
    +            (countArray[rankingTable[i]]*1000/totalTimerHits)/10.0 >= 10.0 ? "" : " ",
                 symname);
         delete [] symname;
     
    -    sp->cntC.printReport(fp, this);
    +    sp->cntC.printReport(fp, this, rankingTable[i], totalTimerHits);
     
         fprintf(fp, "
    \n"); } @@ -508,14 +586,21 @@ void leaky::generateReportHTML(FILE *fp, int *countArray, int count) // I wanted the total before walking the list, if this // double-pass over externalSymbols gets slow we can // do single-pass and print this out after the loop finishes. - int totalTimerHits = 0; + totalTimerHits = 0; for(i=0; i0; i++) { Symbol *sp=&externalSymbols[rankingTable[i]]; totalTimerHits += sp->timerHit; } + if (totalTimerHits == 0) + totalTimerHits = 1; - fprintf(fp,"

    Flat Profile


    \n"); + if (totalTimerHits != count) + fprintf(stderr,"Hit count mismatch: count=%d; totalTimerHits=%d", + count,totalTimerHits); + + fprintf(fp,"

    Flat Profile


    \n", + thread); fprintf(fp, "
    \n");
     
       fprintf(fp, "Total hit count: %d\n", totalTimerHits);
    @@ -532,11 +617,9 @@ void leaky::generateReportHTML(FILE *fp, int *countArray, int count)
                 ((float)sp->timerHit/(float)totalTimerHits)*100.0, symname);
         delete [] symname;
       }
    -
    -  fprintf(fp,"
    \n"); } -void leaky::analyze() +void leaky::analyze(int thread) { int *countArray = new int[usefulSymbols]; int *flagArray = new int[usefulSymbols]; @@ -558,8 +641,11 @@ void leaky::analyze() lep < lastLogEntry; lep = reinterpret_cast(&lep->pcs[lep->numpcs])) { - if (excluded(lep) || !included(lep)) + if ((thread != 0 && lep->thread != thread) || + excluded(lep) || !included(lep)) + { continue; + } ++stacks; // How many stack frames did we collect @@ -568,7 +654,7 @@ void leaky::analyze() u_int n = (lep->numpcs < stackDepth) ? lep->numpcs : stackDepth; char** pcp = &lep->pcs[n-1]; int idx=-1, parrentIdx=-1; // Init idx incase n==0 - for(int i=n-1; i>=0; --i, --pcp, parrentIdx=idx) { + for (int i=n-1; i>=0; --i, --pcp) { idx = findSymbolIndex(reinterpret_cast(*pcp)); if(idx>=0) { @@ -593,6 +679,9 @@ void leaky::analyze() externalSymbols[parrentIdx].regChild(idx); externalSymbols[idx].regParrent(parrentIdx); } + // inside if() so an unknown in the middle of a stack won't break + // the link! + parrentIdx=idx; } } @@ -602,12 +691,12 @@ void leaky::analyze() } } - generateReportHTML(stdout, countArray, stacks); + generateReportHTML(stdout, countArray, stacks, thread); } -void FunctionCount::printReport(FILE *fp, leaky *lk) +void FunctionCount::printReport(FILE *fp, leaky *lk, int parent, int total) { - const char *fmt = " %6d %s\n"; + const char *fmt = " %8d (%3.1f%%)%s %s%s\n"; int nmax, tmax=((~0U)>>1); @@ -618,7 +707,11 @@ void FunctionCount::printReport(FILE *fp, leaky *lk) if(cnt==tmax) { int idx = getIndex(j); char *symname = htmlify(lk->indexToName(idx)); - fprintf(fp, fmt, idx, getCount(j), symname); + fprintf(fp, fmt, idx, getCount(j), + getCount(j)*100.0/total, + getCount(j)*100.0/total >= 10.0 ? "" : " ", + symname, + parent == idx ? " (self)" : ""); delete [] symname; } else if(cntnmax) { nmax=cnt; diff --git a/tools/jprof/leaky.h b/tools/jprof/leaky.h index 1b65ca23caeb..41250c58fd3f 100644 --- a/tools/jprof/leaky.h +++ b/tools/jprof/leaky.h @@ -52,7 +52,7 @@ struct leaky; class FunctionCount : public IntCount { public: - void printReport(FILE *fp, leaky *lk); + void printReport(FILE *fp, leaky *lk, int parent, int total); }; struct Symbol { @@ -90,6 +90,7 @@ struct leaky { int quiet; int showAddress; + int showThreads; u_int stackDepth; int mappedLogFile; @@ -115,7 +116,7 @@ struct leaky { void LoadMap(); - void analyze(); + void analyze(int thread); void dumpEntryToLog(malloc_log_entry* lep); @@ -133,7 +134,7 @@ struct leaky { const char* indexToName(int idx) {return externalSymbols[idx].name;} private: - void generateReportHTML(FILE *fp, int *countArray, int count); + void generateReportHTML(FILE *fp, int *countArray, int count, int thread); int findSymbolIndex(u_long address); }; diff --git a/tools/jprof/stub/Makefile.in b/tools/jprof/stub/Makefile.in index 52757a9673d3..8da3eac1b19f 100644 --- a/tools/jprof/stub/Makefile.in +++ b/tools/jprof/stub/Makefile.in @@ -48,6 +48,9 @@ EXPORTS = LIBRARY_NAME = jprof EXPORT_LIBRARY = 1 +# override optimization +MOZ_OPTIMIZE_FLAGS = -fno-omit-frame-pointer + CPPSRCS = \ libmalloc.cpp \ $(NULL) diff --git a/tools/jprof/stub/libmalloc.cpp b/tools/jprof/stub/libmalloc.cpp index 5e092e956c9f..5a81e7a53603 100644 --- a/tools/jprof/stub/libmalloc.cpp +++ b/tools/jprof/stub/libmalloc.cpp @@ -23,6 +23,7 @@ * Jim Nance * L. David Baron - JP_REALTIME, JPROF_PTHREAD_HACK, and SIGUSR1 handling * Mike Shaver - JP_RTC_HZ support + * Randell Jesup - glibc backtrace() support * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -61,7 +62,9 @@ #include #include #include +#include #include +#include #include "libmalloc.h" #include "jprof.h" @@ -77,6 +80,10 @@ extern r_debug _r_debug; #include #endif +#define USE_GLIBC_BACKTRACE 1 +// To debug, use #define JPROF_STATIC +#define JPROF_STATIC //static + static int gLogFD = -1; static pthread_t main_thread; @@ -87,9 +94,32 @@ static int enableRTCSignals(bool enable); //---------------------------------------------------------------------- #if defined(i386) || defined(_i386) || defined(__x86_64__) -static void CrawlStack(malloc_log_entry* me, - void* stack_top, void* top_instr_ptr) +JPROF_STATIC void CrawlStack(malloc_log_entry* me, + void* stack_top, void* top_instr_ptr) { +#if USE_GLIBC_BACKTRACE + // This probably works on more than x86! But we need a way to get the + // top instruction pointer, which is kindof arch-specific + void *array[500]; + int cnt, i; + u_long numpcs = 0; + bool tracing = false; + + // This is from glibc. A more generic version might use + // libunwind and/or CaptureStackBackTrace() on Windows + cnt = backtrace(&array[0],sizeof(array)/sizeof(array[0])); + + // StackHook->JprofLog->CrawlStack + // Then we have sigaction, which replaced top_instr_ptr + array[3] = top_instr_ptr; + for (i = 3; i < cnt; i++) + { + me->pcs[numpcs++] = (char *) array[i]; + } + me->numpcs = numpcs; + +#else + // original code - this breaks on many platforms void **bp; #if defined(__i386) __asm__( "movl %%ebp, %0" : "=g"(bp)); @@ -102,6 +132,7 @@ static void CrawlStack(malloc_log_entry* me, bp = __builtin_frame_address(0); #endif u_long numpcs = 0; + bool tracing = false; me->pcs[numpcs++] = (char*) top_instr_ptr; @@ -111,13 +142,17 @@ static void CrawlStack(malloc_log_entry* me, if (nextbp < bp) { break; } - if (bp > stack_top) { + if (tracing) { // Skip the signal handling. me->pcs[numpcs++] = (char*) pc; } + else if (pc == top_instr_ptr) { + tracing = true; + } bp = nextbp; } me->numpcs = numpcs; +#endif } #endif @@ -169,13 +204,14 @@ static void EndProfilingHook(int signum) //---------------------------------------------------------------------- -static void -Log(u_long aTime, void* stack_top, void* top_instr_ptr) +JPROF_STATIC void +JprofLog(u_long aTime, void* stack_top, void* top_instr_ptr) { // Static is simply to make debugging tollerable static malloc_log_entry me; me.delTime = aTime; + me.thread = syscall(SYS_gettid); //gettid(); CrawlStack(&me, stack_top, top_instr_ptr); @@ -281,7 +317,7 @@ static int enableRTCSignals(bool enable) } #endif -static void StackHook( +JPROF_STATIC void StackHook( int signum, siginfo_t *info, void *ucontext) @@ -325,9 +361,9 @@ void *ucontext) gregset_t &gregs = ((ucontext_t*)ucontext)->uc_mcontext.gregs; #ifdef __x86_64__ - Log(millisec, (void*)gregs[REG_RSP], (void*)gregs[REG_RIP]); + JprofLog(millisec, (void*)gregs[REG_RSP], (void*)gregs[REG_RIP]); #else - Log(millisec, (void*)gregs[REG_ESP], (void*)gregs[REG_EIP]); + JprofLog(millisec, (void*)gregs[REG_ESP], (void*)gregs[REG_EIP]); #endif if (!rtcHz) @@ -371,21 +407,26 @@ NS_EXPORT_(void) setupProfilingStuff(void) char *delay = strstr(tst,"JP_PERIOD="); if(delay) { - double tmp = strtod(delay+10, NULL); - if(tmp>1e-3) { + double tmp = strtod(delay+strlen("JP_PERIOD="), NULL); + if (tmp>=1e-3) { timerMiliSec = static_cast(1000 * tmp); - } + } else { + fprintf(stderr, + "JP_PERIOD of %g less than 0.001 (1ms), using 1ms\n", + tmp); + timerMiliSec = 1; + } } char *first = strstr(tst, "JP_FIRST="); if(first) { - firstDelay = atol(first+9); + firstDelay = atol(first+strlen("JP_FIRST=")); } char *rtc = strstr(tst, "JP_RTC_HZ="); if (rtc) { #if defined(linux) - rtcHz = atol(rtc+10); + rtcHz = atol(rtc+strlen("JP_RTC_HZ=")); timerMiliSec = 0; /* This makes JP_FIRST work right. */ realTime = 1; /* It's the _R_TC and all. ;) */ @@ -420,6 +461,8 @@ NS_EXPORT_(void) setupProfilingStuff(void) atexit(DumpAddressMap); main_thread = pthread_self(); + //fprintf(stderr,"jprof: main_thread = %u\n", + // (unsigned int)main_thread); sigemptyset(&mset); action.sa_handler = NULL; diff --git a/tools/jprof/stub/libmalloc.h b/tools/jprof/stub/libmalloc.h index 80e7b57cca0a..b6d40a1fe8c0 100644 --- a/tools/jprof/stub/libmalloc.h +++ b/tools/jprof/stub/libmalloc.h @@ -52,6 +52,7 @@ typedef unsigned long u_long; struct malloc_log_entry { u_long delTime; u_long numpcs; + int thread; char* pcs[MAX_STACK_CRAWL]; }; From 514ab4a72072f97dbbdf4bc513701bf9fa8538cc Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Tue, 17 May 2011 00:12:40 -0400 Subject: [PATCH 05/15] Bug 657067 - XPIProvider.jsm refers to nsIPrefBranch.getComplexPref... which doesn't exist [r=dtownsend] --- toolkit/mozapps/extensions/XPIProvider.jsm | 6 +++--- toolkit/mozapps/extensions/nsBlocklistService.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index 324c303c51cb..84ad6a2cf97b 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -344,7 +344,7 @@ SafeInstallOperation.prototype = { function getLocale() { if (Prefs.getBoolPref(PREF_MATCH_OS_LOCALE, false)) return Services.locale.getLocaleComponentForUserAgent(); - let locale = Prefs.getComplexPref(PREF_SELECTED_LOCALE, Ci.nsIPrefLocalizedString); + let locale = Prefs.getComplexValue(PREF_SELECTED_LOCALE, Ci.nsIPrefLocalizedString); if (locale) return locale; return Prefs.getCharPref(PREF_SELECTED_LOCALE, "en-US"); @@ -1229,9 +1229,9 @@ var Prefs = { * A value to return if the preference does not exist * @return the value of the preference or aDefaultValue if there is none */ - getComplexPref: function(aName, aType, aDefaultValue) { + getComplexValue: function(aName, aType, aDefaultValue) { try { - return Services.prefs.getComplexPref(aName, aType).data; + return Services.prefs.getComplexValue(aName, aType).data; } catch (e) { } diff --git a/toolkit/mozapps/extensions/nsBlocklistService.js b/toolkit/mozapps/extensions/nsBlocklistService.js index 427977ad2a55..ec6d30e13aef 100644 --- a/toolkit/mozapps/extensions/nsBlocklistService.js +++ b/toolkit/mozapps/extensions/nsBlocklistService.js @@ -246,8 +246,8 @@ function getLocale() { try { // Get the default branch var defaultPrefs = gPref.getDefaultBranch(null); - return defaultPrefs.getComplexPref(PREF_GENERAL_USERAGENT_LOCALE, - Ci.nsIPrefLocalizedString).data; + return defaultPrefs.getComplexValue(PREF_GENERAL_USERAGENT_LOCALE, + Ci.nsIPrefLocalizedString).data; } catch (e) {} return gPref.getCharPref(PREF_GENERAL_USERAGENT_LOCALE); From f1dc6cff4ad7012594f450fb1c4ea99cb0f0e1e2 Mon Sep 17 00:00:00 2001 From: Mark Banner Date: Tue, 17 May 2011 07:54:59 +0100 Subject: [PATCH 06/15] Bug 653662 Disable incremental linking of libxul on Windows for the time being. Some developers and tree builders are hitting a hard-coded limit in Visual Studio where the link fails if the incremental link data file is over a certain size. r=ted --- toolkit/library/Makefile.in | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index 75d7869f8952..893ad1e4c3aa 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -132,6 +132,16 @@ else SDK_LIBRARY = $(SHARED_LIBRARY) endif +# See bug 653662 - some builders are hitting an internal size limit +# on incremental builds. Disable this for debug builds for now. We may +# be able to revisit this after our builders are upgraded to something +# later than Visual Studio 2005. +ifeq ($(OS_ARCH),WINNT) +ifdef MOZ_DEBUG +EXTRA_DSO_LDOPTS += -INCREMENTAL:NO +endif +endif + EXTRA_DSO_LDOPTS += $(LIBS_DIR) $(EXTRA_DSO_LIBS) ifndef MOZ_ENABLE_LIBXUL From f3370e122185add2fdd6f5c088ee42e4b123b5cc Mon Sep 17 00:00:00 2001 From: Henri Sivonen Date: Tue, 17 May 2011 10:15:48 +0300 Subject: [PATCH 07/15] Bug 656881 - Make timer in file_bug534293-slow.sjs not suspectible to early GC. r=jwalden. --- parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs b/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs index 287ee12437f8..ec456f3ebdc8 100644 --- a/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs +++ b/parser/htmlparser/tests/mochitest/file_bug534293-slow.sjs @@ -1,10 +1,12 @@ +var timer; + function handleRequest(request, response) { response.setHeader("Cache-Control", "no-cache", false); response.setHeader("Content-Type", "text/javascript", false); response.write("ok(true, 'Slow script ran.');"); response.processAsync(); - var timer = Components.classes["@mozilla.org/timer;1"] + timer = Components.classes["@mozilla.org/timer;1"] .createInstance(Components.interfaces.nsITimer); timer.initWithCallback(function() { response.finish(); From b7d8bff6f5c74d4b3584034933eb826a13ac26a6 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 17 May 2011 09:34:20 +0200 Subject: [PATCH 08/15] Bug 657396 - Move LDFLAGS after other flags when building elfhack test case. r=ted --- build/unix/elfhack/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/unix/elfhack/Makefile.in b/build/unix/elfhack/Makefile.in index 81ef3b29714f..00ce11c0c08d 100644 --- a/build/unix/elfhack/Makefile.in +++ b/build/unix/elfhack/Makefile.in @@ -91,7 +91,7 @@ test$(DLL_SUFFIX): test.$(OBJ_SUFFIX) elfhack $(CSRCS:.c=.$(OBJ_SUFFIX)) [ $$(objdump -R $@.bak | wc -l) -gt $$(objdump -R $@ | wc -l) ] dummy: dummy.$(OBJ_SUFFIX) test$(DLL_SUFFIX) - $(CC) $(LDFLAGS) -o $@ $^ + $(CC) -o $@ $^ $(LDFLAGS) libs:: dummy # Will either crash or return exit code 1 if elfhack is broken From aacb2ec3c5f4883117d504e8d12b6d22bb2d3ee0 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 17 May 2011 11:55:05 +0200 Subject: [PATCH 09/15] Bug 653146: switch awesomescreen tabs immediately on tap [r=wesj] --- mobile/chrome/content/bindings.xml | 36 +++++++++++++++++++++-------- mobile/chrome/content/browser-ui.js | 14 +++++------ mobile/themes/core/browser.css | 22 ++++++++++++++++++ 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/mobile/chrome/content/bindings.xml b/mobile/chrome/content/bindings.xml index bdb64784cfdc..8e2692fd94d6 100644 --- a/mobile/chrome/content/bindings.xml +++ b/mobile/chrome/content/bindings.xml @@ -1254,17 +1254,25 @@ + + + @@ -1364,17 +1372,25 @@ + + + diff --git a/mobile/chrome/content/browser-ui.js b/mobile/chrome/content/browser-ui.js index d69f2a50a326..af7c190fa9d0 100644 --- a/mobile/chrome/content/browser-ui.js +++ b/mobile/chrome/content/browser-ui.js @@ -1196,15 +1196,11 @@ var BrowserUI = { this.activePanel = HistoryList; break; case "cmd_remoteTabs": - // remove the checked state set by the click it will be reset by setting - // checked on the command element if we decide to show this panel (see AwesomePanel.js) - document.getElementById("remotetabs-button").removeAttribute("checked"); - if (Weave.Status.checkSetup() == Weave.CLIENT_NOT_CONFIGURED) { - this.activePanel = null; - WeaveGlue.open(); } else if (!Weave.Service.isLoggedIn) { + // unchecked the relative command button + document.getElementById("remotetabs-button").removeAttribute("checked"); this.activePanel = null; BrowserUI.showPanel("prefs-container"); @@ -1217,9 +1213,11 @@ var BrowserUI = { prefsBox.scrollBoxObject.scrollTo(0, syncAreaY - prefsBoxY); }, 0); } - } else { - this.activePanel = RemoteTabsList; + + return; } + + this.activePanel = RemoteTabsList; break; case "cmd_quit": GlobalOverlay.goQuitApplication(); diff --git a/mobile/themes/core/browser.css b/mobile/themes/core/browser.css index faa4b1d438f8..e505000c1006 100644 --- a/mobile/themes/core/browser.css +++ b/mobile/themes/core/browser.css @@ -414,6 +414,28 @@ toolbarbutton.choice-remotetabs { list-style-image: url(chrome://browser/skin/images/remotetabs-48.png); } +/* awesomescreen panels ---------------------------------------------------- */ +historylist > hbox.history-throbber-box, +remotetabslist > hbox.remotetabs-throbber-box { + display: none; +} + +.history-throbber-box > image, +.remotetabs-throbber-box > image { + list-style-image: url("chrome://browser/skin/images/throbber.png"); +} + +historylist[loading="true"] > hbox.history-throbber-box, +remotetabslist[loading="true"] > hbox.remotetabs-throbber-box { + background-color: white; + display: -moz-box; +} + +historylist[loading="true"] > richlistbox.history-list-children, +remotetabslist[loading="true"] > richlistbox.remotetabs-list-children { + visibility: collapse; +} + /* browsers ---------------------------------------------------------------- */ .input-overlay:-moz-focusring { outline: 0 !important; From 4f0d491bdd40afcf9114b9d8360aa7be80631b3a Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 17 May 2011 11:55:05 +0200 Subject: [PATCH 10/15] Bug 656373: Turn off Form Assistant zooming, panning and next/prev on tablets [r=mfinkle] --- mobile/app/mobile.js | 3 ++- mobile/chrome/content/Util.js | 7 +++++++ mobile/chrome/content/common-ui.js | 32 +++++++++++++++++++++++------- mobile/chrome/content/forms.js | 14 +++++++------ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/mobile/app/mobile.js b/mobile/app/mobile.js index f2d8b1ed17c6..b3526067cb01 100644 --- a/mobile/app/mobile.js +++ b/mobile/app/mobile.js @@ -172,7 +172,8 @@ pref("signon.expireMasterPassword", false); pref("signon.SignonFileName", "signons.txt"); /* form helper */ -pref("formhelper.enabled", true); +// 0 = disabled, 1 = enabled, 2 = dynamic depending on screen size +pref("formhelper.mode", 2); pref("formhelper.autozoom", true); pref("formhelper.autozoom.caret", true); pref("formhelper.restore", false); diff --git a/mobile/chrome/content/Util.js b/mobile/chrome/content/Util.js index 5d33f2209562..4594a237d277 100644 --- a/mobile/chrome/content/Util.js +++ b/mobile/chrome/content/Util.js @@ -161,6 +161,13 @@ let Util = { return (!appInfo || appInfo.getService(Ci.nsIXULRuntime).processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT); }, + isTablet: function isTablet() { + // See the tablet_panel_minwidth from mobile/themes/core/defines.inc + let tablet_panel_minwidth = 124; + let dpmm = Util.getWindowUtils(window).displayDPI / 25.4; + return (window.innerWidth / dpmm <= tablet_panel_minwidth); + }, + isPortrait: function isPortrait() { #ifdef MOZ_PLATFORM_MAEMO return (screen.width <= screen.height); diff --git a/mobile/chrome/content/common-ui.js b/mobile/chrome/content/common-ui.js index df00ab7f4321..250106e2c652 100644 --- a/mobile/chrome/content/common-ui.js +++ b/mobile/chrome/content/common-ui.js @@ -675,6 +675,12 @@ var FormHelperUI = { // Listen some events to show/hide arrows Elements.browsers.addEventListener("PanBegin", this, false); Elements.browsers.addEventListener("PanFinished", this, false); + + // Dynamically enabled/disabled the form helper if needed depending on + // the size of the screen + let mode = Services.prefs.getIntPref("formhelper.mode"); + let state = (mode == 2) ? !Util.isTablet() : !!mode; + Services.prefs.setBoolPref("formhelper.enabled", state); }, _currentBrowser: null, @@ -792,22 +798,34 @@ var FormHelperUI = { }, receiveMessage: function formHelperReceiveMessage(aMessage) { - if (!this._open && aMessage.name != "FormAssist:Show" && aMessage.name != "FormAssist:Hide") + let allowedMessages = ["FormAssist:Show", "FormAssist:Hide", "FormAssist:AutoComplete"]; + if (!this._open && allowedMessages.indexOf(aMessage.name) == -1) return; let json = aMessage.json; switch (aMessage.name) { case "FormAssist:Show": // if the user has manually disabled the Form Assistant UI we still - // want to show a UI for element and still want to show + // autocomplete suggestions but not managed by FormHelperUI + if (this.enabled) { + this.show(json.current, json.hasPrevious, json.hasNext) + } else if (json.current.choices) { + SelectHelperUI.show(json.current.choices, json.current.title); + } else { + this._currentElementRect = Rect.fromRect(json.current.rect); + this._currentBrowser = getBrowser(); + this._updateSuggestionsFor(json.current); + } break; case "FormAssist:Hide": - this.enabled ? this.hide() - : SelectHelperUI.hide(); + if (this.enabled) { + this.hide(); + } else { + SelectHelperUI.hide(); + ContentPopupHelper.popup = null; + } break; case "FormAssist:Resize": diff --git a/mobile/chrome/content/forms.js b/mobile/chrome/content/forms.js index d0df32cc86da..30cdd83afe54 100644 --- a/mobile/chrome/content/forms.js +++ b/mobile/chrome/content/forms.js @@ -179,10 +179,12 @@ FormAssistant.prototype = { return false; } - // If form assistant is disabled but the element is a type of choice list - // we still want to show the simple select list + // There is some case where we still want some data to be send to the + // parent process even if form assistant is disabled: + // - the element is a choice list + // - the element has autocomplete suggestions this._enabled = Services.prefs.getBoolPref("formhelper.enabled"); - if (!this._enabled && !this._isSelectElement(aElement)) + if (!this._enabled && !this._isSelectElement(aElement) && !this._isAutocomplete(aElement)) return this.close(); if (this._enabled) { @@ -210,7 +212,7 @@ FormAssistant.prototype = { receiveMessage: function receiveMessage(aMessage) { let currentElement = this.currentElement; - if ((!this._enabled && !getWrapperForElement(currentElement)) || !currentElement) + if ((!this._enabled && !this._isAutocomplete(currentElement) && !getWrapperForElement(currentElement)) || !currentElement) return; let json = aMessage.json; @@ -729,8 +731,8 @@ FormAssistant.prototype = { maxLength: element.maxLength, type: (element.getAttribute("type") || "").toLowerCase(), choices: choices, - isAutocomplete: this._isAutocomplete(this.currentElement), - list: this._getListSuggestions(this.currentElement), + isAutocomplete: this._isAutocomplete(element), + list: this._getListSuggestions(element), rect: this._getRect(), caretRect: this._getCaretRect() }, From 3ea309cc44ed7feaa529537588416dbeee925180 Mon Sep 17 00:00:00 2001 From: Vivien Nicolas <21@vingtetun.org> Date: Tue, 17 May 2011 11:55:05 +0200 Subject: [PATCH 11/15] Bug 640630 - about:home advertises add-ons that are installed already [r=mfinkle] --- mobile/chrome/content/aboutHome.xhtml | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/mobile/chrome/content/aboutHome.xhtml b/mobile/chrome/content/aboutHome.xhtml index 89d82ee01530..21b5dfa68617 100644 --- a/mobile/chrome/content/aboutHome.xhtml +++ b/mobile/chrome/content/aboutHome.xhtml @@ -98,6 +98,7 @@