From 3ad07f32b9edac0c9d2ab653a0e10405c05e6da0 Mon Sep 17 00:00:00 2001 From: Thi Huynh Date: Mon, 10 Sep 2018 16:08:10 +0000 Subject: [PATCH 01/20] Bug 1485695 - Remove unused uptime property from the main ping. r=Dexter Differential Revision: https://phabricator.services.mozilla.com/D4296 --HG-- extra : moz-landing-system : lando --- toolkit/components/telemetry/docs/data/main-ping.rst | 4 ---- toolkit/components/telemetry/pings/TelemetrySession.jsm | 1 - .../components/telemetry/tests/unit/test_TelemetrySession.js | 1 - 3 files changed, 6 deletions(-) diff --git a/toolkit/components/telemetry/docs/data/main-ping.rst b/toolkit/components/telemetry/docs/data/main-ping.rst index 7effba27023b..ff59a90b7dfe 100644 --- a/toolkit/components/telemetry/docs/data/main-ping.rst +++ b/toolkit/components/telemetry/docs/data/main-ping.rst @@ -149,10 +149,6 @@ totalTime ~~~~~~~~~ A non-monotonic integer representing the number of seconds the session has been alive. -uptime -~~~~~~ -A non-monotonic integer representing the number of minutes the session has been alive. - addonManager ~~~~~~~~~~~~ Only available in the extended set of measures, it contains a set of counters related to Addons. See `here `__ for a list of recorded measures. diff --git a/toolkit/components/telemetry/pings/TelemetrySession.jsm b/toolkit/components/telemetry/pings/TelemetrySession.jsm index 824f738d9662..3a23b67a9f40 100644 --- a/toolkit/components/telemetry/pings/TelemetrySession.jsm +++ b/toolkit/components/telemetry/pings/TelemetrySession.jsm @@ -745,7 +745,6 @@ var Impl = { let elapsedTime = Date.now() - si.process; var ret = { totalTime: Math.round(elapsedTime / 1000), // totalTime, in seconds - uptime: Math.round(elapsedTime / 60000), // uptime in minutes }; // Look for app-specific timestamps diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js index da30473ff62f..c1fe771bcce2 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js @@ -280,7 +280,6 @@ function checkPayload(payload, reason, successfulPings) { checkPayloadInfo(payload.info, reason); Assert.ok(payload.simpleMeasurements.totalTime >= 0); - Assert.ok(payload.simpleMeasurements.uptime >= 0); Assert.equal(payload.simpleMeasurements.startupInterrupted, 1); Assert.equal(payload.simpleMeasurements.shutdownDuration, SHUTDOWN_TIME); Assert.ok("maximalNumberOfConcurrentThreads" in payload.simpleMeasurements); From 7a9297b3acbce098a35a7261f421ffac6ffd064a Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Tue, 11 Sep 2018 07:24:27 +0000 Subject: [PATCH 02/20] Bug 1490192 - Get rid of nsIEditorMailSupport.getEmbeddedObjects. r=masayuki Since I have landed bug 1478546, no one (inc. bluegriffon) uses this method. Differential Revision: https://phabricator.services.mozilla.com/D5497 --HG-- extra : moz-landing-system : lando --- editor/libeditor/HTMLEditor.cpp | 44 --------------------------------- editor/nsIEditorMailSupport.idl | 5 ---- 2 files changed, 49 deletions(-) diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index b0f957940147..ef858c4f94e9 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -3303,50 +3303,6 @@ HTMLEditor::GetStyleSheetForURL(const nsAString& aURL) return mStyleSheets[foundIndex]; } -NS_IMETHODIMP -HTMLEditor::GetEmbeddedObjects(nsIArray** aNodeList) -{ - if (NS_WARN_IF(!aNodeList)) { - return NS_ERROR_INVALID_ARG; - } - - nsresult rv; - nsCOMPtr nodes = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - nsCOMPtr iter = NS_NewContentIterator(); - - nsCOMPtr doc = GetDocument(); - if (NS_WARN_IF(!doc)) { - return NS_ERROR_UNEXPECTED; - } - - iter->Init(doc->GetRootElement()); - - // Loop through the content iterator for each content node. - while (!iter->IsDone()) { - nsINode* node = iter->GetCurrentNode(); - if (node->IsElement()) { - dom::Element* element = node->AsElement(); - - // See if it's an image or an embed and also include all links. - // Let mail decide which link to send or not - if (element->IsAnyOfHTMLElements(nsGkAtoms::img, nsGkAtoms::embed, - nsGkAtoms::a) || - (element->IsHTMLElement(nsGkAtoms::body) && - element->HasAttr(kNameSpaceID_None, nsGkAtoms::background))) { - nodes->AppendElement(node); - } - } - iter->Next(); - } - - nodes.forget(aNodeList); - return NS_OK; -} - nsresult HTMLEditor::DeleteSelectionWithTransaction(EDirection aAction, EStripWrappers aStripWrappers) diff --git a/editor/nsIEditorMailSupport.idl b/editor/nsIEditorMailSupport.idl index 1667fc2fc3bb..18862065c653 100644 --- a/editor/nsIEditorMailSupport.idl +++ b/editor/nsIEditorMailSupport.idl @@ -58,10 +58,5 @@ interface nsIEditorMailSupport : nsISupports * @param aRespectNewlines Try to maintain newlines in the original? */ void rewrap(in boolean aRespectNewlines); - - /** - * Get a list of IMG and OBJECT tags in the current document. - */ - nsIArray getEmbeddedObjects(); }; From 9762aae24f2904d76814271aafc344250d2c0aeb Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 11 Sep 2018 08:15:52 +0000 Subject: [PATCH 03/20] Bug 1485921 - Create HTMLEditor::RefreshResizersInternal() for internal use r=m_kato HTMLEditor::RefreshResizers() is an XPCOM method but it's used internally. So, HTMLEditor should implement it with non-virtual method and use new one for internal use. This patch also makes related methods nested-creation of resizers aware. This issue must not be dangerous, but looks like buggy. Differential Revision: https://phabricator.services.mozilla.com/D5426 --HG-- extra : moz-landing-system : lando --- editor/libeditor/HTMLAbsPositionEditor.cpp | 15 +- editor/libeditor/HTMLAnonymousNodeEditor.cpp | 2 +- editor/libeditor/HTMLEditor.h | 30 +- editor/libeditor/HTMLEditorObjectResizer.cpp | 303 ++++++++++++++----- editor/nsIHTMLObjectResizer.idl | 4 +- 5 files changed, 267 insertions(+), 87 deletions(-) diff --git a/editor/libeditor/HTMLAbsPositionEditor.cpp b/editor/libeditor/HTMLAbsPositionEditor.cpp index 4b4899e83a0a..72a052ea55d4 100644 --- a/editor/libeditor/HTMLAbsPositionEditor.cpp +++ b/editor/libeditor/HTMLAbsPositionEditor.cpp @@ -373,9 +373,12 @@ HTMLEditor::StartMoving() // now, let's create the resizing shadow mPositioningShadow = CreateShadow(*parentContent, *mAbsolutelyPositionedObject); - NS_ENSURE_TRUE(mPositioningShadow, NS_ERROR_FAILURE); - nsresult rv = SetShadowPosition(mPositioningShadow, - mAbsolutelyPositionedObject, + if (NS_WARN_IF(!mPositioningShadow) || + NS_WARN_IF(!mAbsolutelyPositionedObject)) { + return NS_ERROR_FAILURE; + } + nsresult rv = SetShadowPosition(*mPositioningShadow, + *mAbsolutelyPositionedObject, mPositionedObjectX, mPositionedObjectY); NS_ENSURE_SUCCESS(rv, rv); @@ -493,7 +496,11 @@ HTMLEditor::SetFinalPosition(int32_t aX, mPositionedObjectX = newX; mPositionedObjectY = newY; - return RefreshResizers(); + rv = RefreshResizers(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; } void diff --git a/editor/libeditor/HTMLAnonymousNodeEditor.cpp b/editor/libeditor/HTMLAnonymousNodeEditor.cpp index 49aebcfadb2e..9be74e628a97 100644 --- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp +++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp @@ -453,7 +453,7 @@ HTMLEditor::RefereshEditingUI(Selection& aSelection) mResizedObjectIsAnImage = true; } if (mResizedObject) { - nsresult rv = RefreshResizers(); + nsresult rv = RefreshResizersInternal(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index 8bc3942a47f5..cc613e81e396 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -43,6 +43,7 @@ class nsRange; namespace mozilla { class AutoSelectionSetterAfterTableEdit; +class DocumentResizeEventListener; class EmptyEditableFunctor; class ResizerSelectionListener; enum class EditSubAction : int32_t; @@ -1797,6 +1798,12 @@ protected: // Shouldn't be used by friend classes void UpdateRootElement(); + /** + * SetAllResizersPosition() moves all resizers to proper position. + * If the resizers are hidden or replaced with another set of resizers + * while this is running, this returns error. So, callers shouldn't + * keep handling the resizers if this returns error. + */ nsresult SetAllResizersPosition(); /** @@ -1811,15 +1818,31 @@ protected: // Shouldn't be used by friend classes */ nsresult HideResizersInternal(); + /** + * RefreshResizersInternal() moves resizers to proper position. This does + * nothing if there is no resizing target. + */ + nsresult RefreshResizersInternal(); + ManualNACPtr CreateResizer(int16_t aLocation, nsIContent& aParentContent); void SetAnonymousElementPosition(int32_t aX, int32_t aY, Element* aResizer); ManualNACPtr CreateShadow(nsIContent& aParentContent, Element& aOriginalObject); - nsresult SetShadowPosition(Element* aShadow, Element* aOriginalObject, - int32_t aOriginalObjectX, - int32_t aOriginalObjectY); + + /** + * SetShadowPosition() moves the shadow element to proper position. + * + * @param aShadowElement Must be mResizingShadow or mPositioningShadow. + * @param aElement The element which has the shadow. + * @param aElementX Left of aElement. + * @param aElementY Top of aElement. + */ + nsresult SetShadowPosition(Element& aShadowElement, + Element& aElement, + int32_t aElementLeft, + int32_t aElementTop); ManualNACPtr CreateResizingInfo(nsIContent& aParentContent); nsresult SetResizingInfoPosition(int32_t aX, int32_t aY, @@ -2092,6 +2115,7 @@ protected: friend class AutoSelectionSetterAfterTableEdit; friend class CSSEditUtils; + friend class DocumentResizeEventListener; friend class EditorBase; friend class EmptyEditableFunctor; friend class HTMLEditRules; diff --git a/editor/libeditor/HTMLEditorObjectResizer.cpp b/editor/libeditor/HTMLEditorObjectResizer.cpp index 36aa606fd43d..c2177ce1d590 100644 --- a/editor/libeditor/HTMLEditorObjectResizer.cpp +++ b/editor/libeditor/HTMLEditorObjectResizer.cpp @@ -55,8 +55,12 @@ NS_IMETHODIMP DocumentResizeEventListener::HandleEvent(Event* aMouseEvent) { RefPtr htmlEditor = mHTMLEditorWeak.get(); - if (htmlEditor) { - return htmlEditor->RefreshResizers(); + if (!htmlEditor) { + return NS_OK; + } + nsresult rv = htmlEditor->RefreshResizersInternal(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } return NS_OK; } @@ -175,16 +179,15 @@ HTMLEditor::CreateResizingInfo(nsIContent& aParentContent) nsresult HTMLEditor::SetAllResizersPosition() { - NS_ENSURE_TRUE(mTopLeftHandle, NS_ERROR_FAILURE); + if (NS_WARN_IF(!mTopLeftHandle)) { + return NS_ERROR_FAILURE; // There are no resizers. + } int32_t x = mResizedObjectX; int32_t y = mResizedObjectY; int32_t w = mResizedObjectWidth; int32_t h = mResizedObjectHeight; - // now let's place all the resizers around the image - - // get the size of resizers nsAutoString value; float resizerWidth, resizerHeight; RefPtr dummyUnit; @@ -195,19 +198,54 @@ HTMLEditor::SetAllResizersPosition() value); CSSEditUtils::ParseLength(value, &resizerHeight, getter_AddRefs(dummyUnit)); - int32_t rw = (int32_t)((resizerWidth + 1) / 2); - int32_t rh = (int32_t)((resizerHeight+ 1) / 2); + int32_t rw = static_cast((resizerWidth + 1) / 2); + int32_t rh = static_cast((resizerHeight+ 1) / 2); - SetAnonymousElementPosition(x-rw, y-rh, mTopLeftHandle); - SetAnonymousElementPosition(x+w/2-rw, y-rh, mTopHandle); - SetAnonymousElementPosition(x+w-rw-1, y-rh, mTopRightHandle); + // While moving each resizer, mutation event listener may hide the resizers. + // And in worst case, new resizers may be recreated. So, we need to store + // all resizers here, and then, if we detect a resizer is removed or replaced, + // we should do nothing anymore. + // FYI: Note that only checking if mTopLeftHandle is replaced is enough. + // We're may be in hot path if user resizes an element a lot. So, + // we should just add-ref mTopLeftHandle. + RefPtr topLeftHandle = mTopLeftHandle.get(); + SetAnonymousElementPosition(x - rw, y - rh, mTopLeftHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } + SetAnonymousElementPosition(x + w/2-rw, y - rh, mTopHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } + SetAnonymousElementPosition(x + w-rw-1, y - rh, mTopRightHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } - SetAnonymousElementPosition(x-rw, y+h/2-rh, mLeftHandle); - SetAnonymousElementPosition(x+w-rw-1, y+h/2-rh, mRightHandle); + SetAnonymousElementPosition(x - rw, y + h / 2 - rh, mLeftHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } + SetAnonymousElementPosition(x + w-rw-1, y + h / 2 - rh, mRightHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } - SetAnonymousElementPosition(x-rw, y+h-rh-1, mBottomLeftHandle); - SetAnonymousElementPosition(x+w/2-rw, y+h-rh-1, mBottomHandle); - SetAnonymousElementPosition(x+w-rw-1, y+h-rh-1, mBottomRightHandle); + SetAnonymousElementPosition(x - rw, y + h - rh - 1, + mBottomLeftHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } + SetAnonymousElementPosition(x + w / 2 - rw, y + h - rh - 1, + mBottomHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } + SetAnonymousElementPosition(x + w - rw - 1, y + h - rh - 1, + mBottomRightHandle); + if (NS_WARN_IF(topLeftHandle != mTopLeftHandle)) { + return NS_ERROR_FAILURE; + } return NS_OK; } @@ -215,26 +253,49 @@ HTMLEditor::SetAllResizersPosition() NS_IMETHODIMP HTMLEditor::RefreshResizers() { - // nothing to do if resizers are not displayed... - NS_ENSURE_TRUE(mResizedObject, NS_OK); + if (NS_WARN_IF(!mResizedObject)) { + return NS_OK; + } + nsresult rv = RefreshResizersInternal(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; +} - nsresult rv = - GetPositionAndDimensions( - *mResizedObject, - mResizedObjectX, - mResizedObjectY, - mResizedObjectWidth, - mResizedObjectHeight, - mResizedObjectBorderLeft, - mResizedObjectBorderTop, - mResizedObjectMarginLeft, - mResizedObjectMarginTop); +nsresult +HTMLEditor::RefreshResizersInternal() +{ + if (!mResizedObject) { + return NS_OK; + } + + nsresult rv = GetPositionAndDimensions(*mResizedObject, + mResizedObjectX, + mResizedObjectY, + mResizedObjectWidth, + mResizedObjectHeight, + mResizedObjectBorderLeft, + mResizedObjectBorderTop, + mResizedObjectMarginLeft, + mResizedObjectMarginTop); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } - NS_ENSURE_SUCCESS(rv, rv); rv = SetAllResizersPosition(); - NS_ENSURE_SUCCESS(rv, rv); - return SetShadowPosition(mResizingShadow, mResizedObject, - mResizedObjectX, mResizedObjectY); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + MOZ_ASSERT(mResizingShadow, + "SetAllResizersPosition() should return error if resizers are hidden"); + rv = SetShadowPosition(*mResizingShadow, *mResizedObject, + mResizedObjectX, mResizedObjectY); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; } nsresult @@ -261,56 +322,110 @@ HTMLEditor::ShowResizersInternal(Element& aResizedElement) mResizedObject = &aResizedElement; // The resizers and the shadow will be anonymous siblings of the element. - mTopLeftHandle = + // Note that creating a resizer or shadow may causes calling + // HideRisizersInternal() via a mutation event listener. So, we should + // store new resizer to a local variable, then, check: + // - whether creating resizer is already set to the member or not + // - whether resizing element is changed to another element + // If showing resizers are canceled, we hit the latter check. + // If resizers for another element is shown during this, we hit the latter + // check too. + // If resizers are just shown again for same element, we hit the former + // check. + ManualNACPtr newResizer = CreateResizer(nsIHTMLObjectResizer::eTopLeft, *parentContent); - if (NS_WARN_IF(!mTopLeftHandle)) { + if (NS_WARN_IF(!newResizer)) { break; } - mTopHandle = CreateResizer(nsIHTMLObjectResizer::eTop, *parentContent); - if (NS_WARN_IF(!mTopHandle)) { + if (NS_WARN_IF(mTopLeftHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + // Don't hide current resizers in this case because they are not what + // we're creating. + return NS_ERROR_FAILURE; + } + mTopLeftHandle = std::move(newResizer); + newResizer = CreateResizer(nsIHTMLObjectResizer::eTop, *parentContent); + if (NS_WARN_IF(!newResizer)) { break; } - mTopRightHandle = - CreateResizer(nsIHTMLObjectResizer::eTopRight, *parentContent); - if (NS_WARN_IF(!mTopRightHandle)) { + if (NS_WARN_IF(mTopHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mTopHandle = std::move(newResizer); + newResizer = CreateResizer(nsIHTMLObjectResizer::eTopRight, *parentContent); + if (NS_WARN_IF(!newResizer)) { break; } + if (NS_WARN_IF(mTopRightHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mTopRightHandle = std::move(newResizer); - mLeftHandle = CreateResizer(nsIHTMLObjectResizer::eLeft, *parentContent); - if (NS_WARN_IF(!mLeftHandle)) { + newResizer = CreateResizer(nsIHTMLObjectResizer::eLeft, *parentContent); + if (NS_WARN_IF(!newResizer)) { break; } - mRightHandle = CreateResizer(nsIHTMLObjectResizer::eRight, *parentContent); - if (NS_WARN_IF(!mRightHandle)) { + if (NS_WARN_IF(mLeftHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mLeftHandle = std::move(newResizer); + newResizer = CreateResizer(nsIHTMLObjectResizer::eRight, *parentContent); + if (NS_WARN_IF(!newResizer)) { break; } + if (NS_WARN_IF(mRightHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mRightHandle = std::move(newResizer); - mBottomLeftHandle = + newResizer = CreateResizer(nsIHTMLObjectResizer::eBottomLeft, *parentContent); - if (NS_WARN_IF(!mBottomLeftHandle)) { + if (NS_WARN_IF(!newResizer)) { break; } - mBottomHandle = - CreateResizer(nsIHTMLObjectResizer::eBottom, *parentContent); - if (NS_WARN_IF(!mBottomHandle)) { + if (NS_WARN_IF(mBottomLeftHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mBottomLeftHandle = std::move(newResizer); + newResizer = CreateResizer(nsIHTMLObjectResizer::eBottom, *parentContent); + if (NS_WARN_IF(!newResizer)) { break; } - mBottomRightHandle = + if (NS_WARN_IF(mBottomHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mBottomHandle = std::move(newResizer); + newResizer = CreateResizer(nsIHTMLObjectResizer::eBottomRight, *parentContent); - if (NS_WARN_IF(!mBottomRightHandle)) { + if (NS_WARN_IF(!newResizer)) { break; } + if (NS_WARN_IF(mBottomRightHandle) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mBottomRightHandle = std::move(newResizer); - nsresult rv = - GetPositionAndDimensions(aResizedElement, - mResizedObjectX, - mResizedObjectY, - mResizedObjectWidth, - mResizedObjectHeight, - mResizedObjectBorderLeft, - mResizedObjectBorderTop, - mResizedObjectMarginLeft, - mResizedObjectMarginTop); + // Store the last resizer which we created. This is useful when we + // need to check whether our resizers are hiddedn and recreated another + // set of resizers or not. + RefPtr createdBottomRightNalde = mBottomRightHandle.get(); + + nsresult rv = GetPositionAndDimensions(aResizedElement, + mResizedObjectX, + mResizedObjectY, + mResizedObjectWidth, + mResizedObjectHeight, + mResizedObjectBorderLeft, + mResizedObjectBorderTop, + mResizedObjectMarginLeft, + mResizedObjectMarginTop); if (NS_WARN_IF(NS_FAILED(rv))) { break; } @@ -318,26 +433,43 @@ HTMLEditor::ShowResizersInternal(Element& aResizedElement) // and let's set their absolute positions in the document rv = SetAllResizersPosition(); if (NS_WARN_IF(NS_FAILED(rv))) { + if (NS_WARN_IF(mBottomRightHandle.get() != createdBottomRightNalde)) { + return NS_ERROR_FAILURE; + } break; } // now, let's create the resizing shadow - mResizingShadow = CreateShadow(*parentContent, aResizedElement); - if (NS_WARN_IF(!mResizingShadow)) { + ManualNACPtr newShadow = CreateShadow(*parentContent, aResizedElement); + if (NS_WARN_IF(!newShadow)) { break; } + if (NS_WARN_IF(mResizingShadow) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mResizingShadow = std::move(newShadow); + // and set its position - rv = SetShadowPosition(mResizingShadow, &aResizedElement, + rv = SetShadowPosition(*mResizingShadow, aResizedElement, mResizedObjectX, mResizedObjectY); if (NS_WARN_IF(NS_FAILED(rv))) { + if (NS_WARN_IF(mBottomRightHandle.get() != createdBottomRightNalde)) { + return NS_ERROR_FAILURE; + } break; } // and then the resizing info tooltip - mResizingInfo = CreateResizingInfo(*parentContent); - if (NS_WARN_IF(!mResizingInfo)) { + ManualNACPtr newResizingInfo = CreateResizingInfo(*parentContent); + if (NS_WARN_IF(!newResizingInfo)) { break; } + if (NS_WARN_IF(mResizingInfo) || + NS_WARN_IF(mResizedObject != &aResizedElement)) { + return NS_ERROR_FAILURE; + } + mResizingInfo = std::move(newResizingInfo); // and listen to the "resize" event on the window first, get the // window from the document... @@ -734,19 +866,33 @@ HTMLEditor::SetResizingInfoPosition(int32_t aX, } nsresult -HTMLEditor::SetShadowPosition(Element* aShadow, - Element* aOriginalObject, - int32_t aOriginalObjectX, - int32_t aOriginalObjectY) +HTMLEditor::SetShadowPosition(Element& aShadowElement, + Element& aElement, + int32_t aElementX, + int32_t aElementY) { - SetAnonymousElementPosition(aOriginalObjectX, aOriginalObjectY, aShadow); + MOZ_ASSERT(&aShadowElement == mResizingShadow || + &aShadowElement == mPositioningShadow); + RefPtr handlingShadowElement = + &aShadowElement == mResizingShadow ? + mResizingShadow.get() : mPositioningShadow.get(); - if (HTMLEditUtils::IsImage(aOriginalObject)) { - nsAutoString imageSource; - aOriginalObject->GetAttr(kNameSpaceID_None, nsGkAtoms::src, imageSource); - nsresult rv = aShadow->SetAttr(kNameSpaceID_None, nsGkAtoms::src, - imageSource, true); - NS_ENSURE_SUCCESS(rv, rv); + SetAnonymousElementPosition(aElementX, aElementY, &aShadowElement); + if (NS_WARN_IF(&aShadowElement != handlingShadowElement)) { + return NS_ERROR_FAILURE; + } + + if (!HTMLEditUtils::IsImage(&aElement)) { + return NS_OK; + } + + nsAutoString imageSource; + aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::src, imageSource); + nsresult rv = aShadowElement.SetAttr(kNameSpaceID_None, nsGkAtoms::src, + imageSource, true); + if (NS_WARN_IF(NS_FAILED(rv)) || + NS_WARN_IF(&aShadowElement != handlingShadowElement)) { + return NS_ERROR_FAILURE; } return NS_OK; } @@ -995,7 +1141,8 @@ HTMLEditor::SetFinalSize(int32_t aX, mResizedObjectWidth = width; mResizedObjectHeight = height; - RefreshResizers(); + DebugOnly rv = RefreshResizersInternal(); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed ot refresh resizers"); } NS_IMETHODIMP diff --git a/editor/nsIHTMLObjectResizer.idl b/editor/nsIHTMLObjectResizer.idl index 77849f9c6d74..d57198049cad 100644 --- a/editor/nsIHTMLObjectResizer.idl +++ b/editor/nsIHTMLObjectResizer.idl @@ -40,7 +40,9 @@ interface nsIHTMLObjectResizer : nsISupports void hideResizers(); /** - * Refresh visible resizers + * Refresh positions of resizers. If you change size of target of resizers, + * you need to refresh position of resizers with calling this. + * FYI: Current user in script is only BlueGriffon. */ void refreshResizers(); }; From 811a32c96f4350bf202fe67b34868aa06705d91d Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 11 Sep 2018 05:02:30 +0000 Subject: [PATCH 04/20] Bug 1485927 - Get rid of nsIHTMLObjectResizers.resizedObject r=m_kato nsIHTMLObjectResizers.resizedObject is used only for avoiding warning of nsIHTMLObjectResizers.refreshResizers() if resizers are not visible. Therefore, if we remove the unnecessary warnings, we can get rid of the attribute. Differential Revision: https://phabricator.services.mozilla.com/D5427 --HG-- extra : moz-landing-system : lando --- editor/libeditor/HTMLEditorObjectResizer.cpp | 22 ++++++++------------ editor/nsIHTMLObjectResizer.idl | 5 ----- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/editor/libeditor/HTMLEditorObjectResizer.cpp b/editor/libeditor/HTMLEditorObjectResizer.cpp index c2177ce1d590..7dbb7718f567 100644 --- a/editor/libeditor/HTMLEditorObjectResizer.cpp +++ b/editor/libeditor/HTMLEditorObjectResizer.cpp @@ -253,9 +253,6 @@ HTMLEditor::SetAllResizersPosition() NS_IMETHODIMP HTMLEditor::RefreshResizers() { - if (NS_WARN_IF(!mResizedObject)) { - return NS_OK; - } nsresult rv = RefreshResizersInternal(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -266,6 +263,9 @@ HTMLEditor::RefreshResizers() nsresult HTMLEditor::RefreshResizersInternal() { + // Don't warn even if resizers are not visible since script cannot check + // if they are visible and this is non-virtual method. So, the cost of + // calling this can be ignored. if (!mResizedObject) { return NS_OK; } @@ -302,7 +302,8 @@ nsresult HTMLEditor::ShowResizersInternal(Element& aResizedElement) { // When we have visible resizers, we cannot show new resizers. - // So, the caller should call HideResizersInternal() first. + // So, the caller should call HideResizersInternal() first if this + // returns error. if (NS_WARN_IF(mResizedObject)) { return NS_ERROR_UNEXPECTED; } @@ -520,7 +521,10 @@ HTMLEditor::HideResizers() nsresult HTMLEditor::HideResizersInternal() { - if (NS_WARN_IF(!mResizedObject)) { + // Don't warn even if resizers are visible since script cannot check + // if they are visible and this is non-virtual method. So, the cost of + // calling this can be ignored. + if (!mResizedObject) { return NS_OK; } @@ -1145,14 +1149,6 @@ HTMLEditor::SetFinalSize(int32_t aX, NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed ot refresh resizers"); } -NS_IMETHODIMP -HTMLEditor::GetResizedObject(Element** aResizedObject) -{ - RefPtr ret = mResizedObject; - ret.forget(aResizedObject); - return NS_OK; -} - NS_IMETHODIMP HTMLEditor::GetObjectResizingEnabled(bool* aIsObjectResizingEnabled) { diff --git a/editor/nsIHTMLObjectResizer.idl b/editor/nsIHTMLObjectResizer.idl index d57198049cad..54f863d51f4d 100644 --- a/editor/nsIHTMLObjectResizer.idl +++ b/editor/nsIHTMLObjectResizer.idl @@ -23,11 +23,6 @@ interface nsIHTMLObjectResizer : nsISupports const short eBottom = 6; const short eBottomRight = 7; - /** - * the element currently displaying resizers - */ - readonly attribute Element resizedObject; - /** * a boolean indicating if object resizing is enabled in the editor */ From 7aca24afe971904920480d4e1aa37b88628f669a Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Tue, 11 Sep 2018 08:56:13 +0000 Subject: [PATCH 05/20] Bug 1489499 - Don't call gtk_header_bar_get_decoration_layout() to get titlebar layout, r=jhorak We don't set gtk_header_bar_set_decoration_layout() so we don't need to query the layout by gtk_header_bar_get_decoration_layout(). That means we don't need to create the GtkHeaderBar at startup when titlebar rendering is disabled. Also unify window/header bar construction at CreateHeaderBarWidget() and assert when the widgets are already created. Differential Revision: https://phabricator.services.mozilla.com/D5417 --HG-- extra : moz-landing-system : lando --- widget/gtk/WidgetStyleCache.cpp | 23 +++++++++++------------ widget/gtk/gtk3drawing.cpp | 18 +++--------------- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/widget/gtk/WidgetStyleCache.cpp b/widget/gtk/WidgetStyleCache.cpp index e72738d33db9..174df11dddc6 100644 --- a/widget/gtk/WidgetStyleCache.cpp +++ b/widget/gtk/WidgetStyleCache.cpp @@ -528,23 +528,31 @@ CreateNotebookWidget() return widget; } -static GtkWidget* +static void CreateHeaderBarWidget(WidgetNodeType aWidgetType) { MOZ_ASSERT(gtk_check_version(3, 10, 0) == nullptr, "GtkHeaderBar is only available on GTK 3.10+."); + MOZ_ASSERT(sWidgetStorage[aWidgetType] == nullptr, + "Header bar widget is already created!"); static auto sGtkHeaderBarNewPtr = (GtkWidget* (*)()) dlsym(RTLD_DEFAULT, "gtk_header_bar_new"); GtkWidget* headerbar = sGtkHeaderBarNewPtr(); + sWidgetStorage[aWidgetType] = headerbar; + GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP); GtkStyleContext* style = gtk_widget_get_style_context(window); if (aWidgetType == MOZ_GTK_HEADER_BAR_MAXIMIZED) { gtk_style_context_add_class(style, "maximized"); + MOZ_ASSERT(sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED] == nullptr, + "Window widget is already created!"); sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED] = window; } else { + MOZ_ASSERT(sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW] == nullptr, + "Window widget is already created!"); sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW] = window; } @@ -571,8 +579,6 @@ CreateHeaderBarWidget(WidgetNodeType aWidgetType) // We need to fix titlebar size calculation to also include // titlebar button sizes. (Bug 1419442) gtk_style_context_add_class(style, "default-decoration"); - - return headerbar; } #define ICON_SCALE_VARIANTS 2 @@ -761,15 +767,8 @@ CreateHeaderBarButtons() static void CreateHeaderBar() { - MOZ_ASSERT(sWidgetStorage[MOZ_GTK_HEADER_BAR] == nullptr && - sWidgetStorage[MOZ_GTK_HEADER_BAR_MAXIMIZED] == nullptr, - "Header bar widget is already created!"); - - sWidgetStorage[MOZ_GTK_HEADER_BAR] = - CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR); - sWidgetStorage[MOZ_GTK_HEADER_BAR_MAXIMIZED] = - CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR_MAXIMIZED); - + CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR); + CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR_MAXIMIZED); CreateHeaderBarButtons(); } diff --git a/widget/gtk/gtk3drawing.cpp b/widget/gtk/gtk3drawing.cpp index 4ab5bbca8fcb..affa29cb5e05 100644 --- a/widget/gtk/gtk3drawing.cpp +++ b/widget/gtk/gtk3drawing.cpp @@ -428,22 +428,10 @@ GetGtkHeaderBarButtonLayout(WidgetNodeType* aButtonLayout, int aMaxButtonNums) NS_ASSERTION(aMaxButtonNums >= TOOLBAR_BUTTONS, "Requested number of buttons is higher than storage capacity!"); - static auto sGtkHeaderBarGetDecorationLayoutPtr = - (const gchar* (*)(GtkWidget*)) - dlsym(RTLD_DEFAULT, "gtk_header_bar_get_decoration_layout"); - const gchar* decorationLayout = nullptr; - if (sGtkHeaderBarGetDecorationLayoutPtr) { - GtkWidget* headerBar = GetWidget(MOZ_GTK_HEADER_BAR); - decorationLayout = sGtkHeaderBarGetDecorationLayoutPtr(headerBar); - if (!decorationLayout) { - GtkSettings *settings = gtk_settings_get_for_screen( - gdk_screen_get_default()); - g_object_get(settings, "gtk-decoration-layout", - &decorationLayout, - nullptr); - } - } + GtkSettings *settings = + gtk_settings_get_for_screen(gdk_screen_get_default()); + g_object_get(settings, "gtk-decoration-layout", &decorationLayout, nullptr); // Use a default layout if (!decorationLayout) { From 3d7f73594c6a566d1c6bf55fdea9117fc8f68645 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Tue, 11 Sep 2018 11:01:26 +0000 Subject: [PATCH 06/20] Bug 1442755 - Redraw titlebar widgets when application focus changes and draw inactive titlebar with GTK_STATE_FLAG_BACKDROP state, r=jhorak Differential Revision: https://phabricator.services.mozilla.com/D5409 --HG-- extra : moz-landing-system : lando --- widget/gtk/gtk3drawing.cpp | 11 ++++++---- widget/gtk/gtkdrawing.h | 1 + widget/gtk/mozgtk/mozgtk.c | 1 - widget/gtk/nsNativeThemeGTK.cpp | 36 ++++++++++++++++++++++++++++++++ widget/gtk/nsNativeThemeGTK.h | 3 +++ widget/gtk/nsWindow.cpp | 37 +++++++++++++++++++++++++++++++++ widget/gtk/nsWindow.h | 3 +++ 7 files changed, 87 insertions(+), 5 deletions(-) diff --git a/widget/gtk/gtk3drawing.cpp b/widget/gtk/gtk3drawing.cpp index affa29cb5e05..e2cb3fe5c335 100644 --- a/widget/gtk/gtk3drawing.cpp +++ b/widget/gtk/gtk3drawing.cpp @@ -172,6 +172,8 @@ GetStateFlagsFromGtkWidgetState(GtkWidgetState* state) stateFlags = static_cast(stateFlags|GTK_STATE_FLAG_PRELIGHT); if (state->focused) stateFlags = static_cast(stateFlags|GTK_STATE_FLAG_FOCUSED); + if (state->backdrop) + stateFlags = static_cast(stateFlags|GTK_STATE_FLAG_BACKDROP); } return stateFlags; @@ -2311,8 +2313,9 @@ moz_gtk_header_bar_paint(WidgetNodeType widgetType, cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state) { GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); - GtkStyleContext *style = GetStyleContext(widgetType, GTK_TEXT_DIR_LTR, - state_flags); + GtkStyleContext *style = + GetStyleContext(widgetType, GTK_TEXT_DIR_NONE, state_flags); + InsetByMargin(rect, style); // Some themes (Adwaita for instance) draws bold dark line at @@ -2320,6 +2323,8 @@ moz_gtk_header_bar_paint(WidgetNodeType widgetType, // draw with some extent to make the titlebar bottom part invisible. #define TITLEBAR_EXTENT 4 + // We don't need to draw window decoration for MOZ_GTK_HEADER_BAR_MAXIMIZED, + // i.e. when main window is maximized. if (widgetType == MOZ_GTK_HEADER_BAR) { GtkStyleContext* windowStyle = GetStyleContext(MOZ_GTK_WINDOW); bool solidDecorations = @@ -2344,8 +2349,6 @@ moz_gtk_header_bar_paint(WidgetNodeType widgetType, return MOZ_GTK_SUCCESS; } - - static GtkBorder GetMarginBorderPadding(GtkStyleContext* aStyle) { diff --git a/widget/gtk/gtkdrawing.h b/widget/gtk/gtkdrawing.h index 4512925db438..501aba92644c 100644 --- a/widget/gtk/gtkdrawing.h +++ b/widget/gtk/gtkdrawing.h @@ -31,6 +31,7 @@ typedef struct { /* The depressed state is for buttons which remain active for a longer period: * activated toggle buttons or buttons showing a popup menu. */ guint8 depressed; + guint8 backdrop; gint32 curpos; /* curpos and maxpos are used for scrollbars */ gint32 maxpos; gint32 scale; /* actual widget scale */ diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index 11dfa7b89a07..09511d935b0e 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -658,4 +658,3 @@ XShmQueryExtension(Display* aDisplay) return False; } #endif - diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp index e0ce4f2b6fa8..7a8807977953 100644 --- a/widget/gtk/nsNativeThemeGTK.cpp +++ b/widget/gtk/nsNativeThemeGTK.cpp @@ -41,6 +41,7 @@ #include "mozilla/Preferences.h" #include "mozilla/layers/StackingContextHelper.h" #include "mozilla/StaticPrefs.h" +#include "nsWindow.h" #ifdef MOZ_X11 # ifdef CAIRO_HAS_XLIB_SURFACE @@ -444,6 +445,15 @@ nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aWidgetType, nsIFrame* aF *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused); } } + + if (aWidgetType == StyleAppearance::MozWindowTitlebar || + aWidgetType == StyleAppearance::MozWindowTitlebarMaximized || + aWidgetType == StyleAppearance::MozWindowButtonClose || + aWidgetType == StyleAppearance::MozWindowButtonMinimize || + aWidgetType == StyleAppearance::MozWindowButtonMaximize || + aWidgetType == StyleAppearance::MozWindowButtonRestore) { + aState->backdrop = !nsWindow::GetTopLevelWindowActiveState(aFrame); + } } switch (aWidgetType) { @@ -1787,6 +1797,16 @@ nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, return NS_OK; } + if (aWidgetType == StyleAppearance::MozWindowTitlebar || + aWidgetType == StyleAppearance::MozWindowTitlebarMaximized || + aWidgetType == StyleAppearance::MozWindowButtonClose || + aWidgetType == StyleAppearance::MozWindowButtonMinimize || + aWidgetType == StyleAppearance::MozWindowButtonMaximize || + aWidgetType == StyleAppearance::MozWindowButtonRestore) { + *aShouldRepaint = true; + return NS_OK; + } + if ((aWidgetType == StyleAppearance::ScrollbarthumbVertical || aWidgetType == StyleAppearance::ScrollbarthumbHorizontal) && aAttribute == nsGkAtoms::active) { @@ -2083,3 +2103,19 @@ nsNativeThemeGTK::GetWidgetTransparency(nsIFrame* aFrame, } } + +bool +nsNativeThemeGTK::WidgetAppearanceDependsOnWindowFocus(StyleAppearance aWidgetType) +{ + switch (aWidgetType) { + case StyleAppearance::MozWindowTitlebar: + case StyleAppearance::MozWindowTitlebarMaximized: + case StyleAppearance::MozWindowButtonClose: + case StyleAppearance::MozWindowButtonMinimize: + case StyleAppearance::MozWindowButtonMaximize: + case StyleAppearance::MozWindowButtonRestore: + return true; + default: + return false; + } +} diff --git a/widget/gtk/nsNativeThemeGTK.h b/widget/gtk/nsNativeThemeGTK.h index 8543943cf280..25448b376d81 100644 --- a/widget/gtk/nsNativeThemeGTK.h +++ b/widget/gtk/nsNativeThemeGTK.h @@ -76,6 +76,9 @@ public: virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, WidgetType aWidgetType) override; + + virtual bool WidgetAppearanceDependsOnWindowFocus(WidgetType aWidgetType) override; + nsNativeThemeGTK(); protected: diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 58ce7fc2289a..e3ee1399f484 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -7381,3 +7381,40 @@ nsIWidget::CreateChildWindow() nsCOMPtr window = new nsWindow(); return window.forget(); } + +bool +nsWindow::GetTopLevelWindowActiveState(nsIFrame *aFrame) +{ + // Used by window frame and button box rendering. We can end up in here in + // the content process when rendering one of these moz styles freely in a + // page. Fail in this case, there is no applicable window focus state. + if (!XRE_IsParentProcess()) { + return false; + } + // All headless windows are considered active so they are painted. + if (gfxPlatform::IsHeadless()) { + return true; + } + // Get the widget. nsIFrame's GetNearestWidget walks up the view chain + // until it finds a real window. + nsWindow* window = static_cast(aFrame->GetNearestWidget()); + if (!window) { + return false; + } + + // Get our toplevel nsWindow. + if (!window->mIsTopLevel) { + GtkWidget *widget = window->GetMozContainerWidget(); + if (!widget) { + return false; + } + + GtkWidget *toplevelWidget = gtk_widget_get_toplevel(widget); + window = get_window_for_gtk_widget(toplevelWidget); + if (!window) { + return false; + } + } + + return (gFocusWindow == window); +} diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index f6065ee3dee2..4cb697f21f1f 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -15,6 +15,7 @@ #include "nsITimer.h" #include "nsGkAtoms.h" #include "nsRefPtrHashtable.h" +#include "nsIFrame.h" #include "nsBaseWidget.h" #include "CompositorWidget.h" @@ -428,6 +429,8 @@ public: */ static CSDSupportLevel GetSystemCSDSupportLevel(); + static bool GetTopLevelWindowActiveState(nsIFrame *aFrame); + protected: virtual ~nsWindow(); From 05853e660ad16dedfddecaaa01eac53843825ef8 Mon Sep 17 00:00:00 2001 From: Pavel Slepushkin Date: Tue, 11 Sep 2018 11:34:50 +0000 Subject: [PATCH 07/20] Bug 1471888 - [mozprofile] Add support for Python 3. r=davehunt Bug 1471888 - [mozprofile] Add support for Python 3. Differential Revision: https://phabricator.services.mozilla.com/D5187 --HG-- extra : moz-landing-system : lando --- .../mozbase/mozprofile/mozprofile/addons.py | 12 ++++++------ .../mozprofile/mozprofile/permissions.py | 3 ++- .../mozbase/mozprofile/mozprofile/prefs.py | 3 +++ .../mozbase/mozprofile/mozprofile/profile.py | 6 ++---- testing/mozbase/mozprofile/setup.cfg | 2 ++ testing/mozbase/mozprofile/setup.py | 4 ++-- testing/mozbase/mozprofile/tests/manifest.ini | 1 - .../mozprofile/tests/test_preferences.py | 19 +++++++++---------- .../mozprofile/tests/test_profile_view.py | 13 ++++++++++--- 9 files changed, 36 insertions(+), 27 deletions(-) create mode 100644 testing/mozbase/mozprofile/setup.cfg diff --git a/testing/mozbase/mozprofile/mozprofile/addons.py b/testing/mozbase/mozprofile/mozprofile/addons.py index d7bf27713b8e..6c3ccc534935 100644 --- a/testing/mozbase/mozprofile/mozprofile/addons.py +++ b/testing/mozbase/mozprofile/mozprofile/addons.py @@ -11,14 +11,14 @@ import shutil import tempfile import zipfile import hashlib +import binascii from xml.dom import minidom - from six import reraise, string_types import mozfile from mozlog.unstructured import getLogger -_SALT = os.urandom(32).encode('hex') +_SALT = binascii.hexlify(os.urandom(32)) _TEMPORARY_ADDON_SUFFIX = "@temporary-addon" # Logger for 'mozprofile.addons' module @@ -203,7 +203,7 @@ class AddonManager(object): @classmethod def _gen_iid(cls, addon_path): hash = hashlib.sha1(_SALT) - hash.update(addon_path) + hash.update(addon_path.encode()) return hash.hexdigest() + _TEMPORARY_ADDON_SUFFIX @classmethod @@ -262,7 +262,7 @@ class AddonManager(object): manifest = compressed_file.read('install.rdf') elif 'manifest.json' in filenames: is_webext = True - manifest = compressed_file.read('manifest.json') + manifest = compressed_file.read('manifest.json').decode() manifest = json.loads(manifest) else: raise KeyError("No manifest") @@ -279,7 +279,7 @@ class AddonManager(object): else: raise IOError('Add-on path is neither an XPI nor a directory: %s' % addon_path) except (IOError, KeyError) as e: - reraise(AddonFormatError(str(e)), None, sys.exc_info()[2]) + reraise(AddonFormatError, AddonFormatError(str(e)), sys.exc_info()[2]) if is_webext: details['version'] = manifest['version'] @@ -309,7 +309,7 @@ class AddonManager(object): if entry in details.keys(): details.update({entry: get_text(node)}) except Exception as e: - reraise(AddonFormatError(str(e)), None, sys.exc_info()[2]) + reraise(AddonFormatError, AddonFormatError(str(e)), sys.exc_info()[2]) # turn unpack into a true/false value if isinstance(details['unpack'], string_types): diff --git a/testing/mozbase/mozprofile/mozprofile/permissions.py b/testing/mozbase/mozprofile/mozprofile/permissions.py index 047fa54e1ee7..0671e8ac8e97 100644 --- a/testing/mozbase/mozprofile/mozprofile/permissions.py +++ b/testing/mozbase/mozprofile/mozprofile/permissions.py @@ -15,6 +15,7 @@ import sqlite3 from six import string_types from six.moves.urllib import parse +import six __all__ = ['MissingPrimaryLocationError', 'MultiplePrimaryLocationsError', 'DEFAULT_PORTS', 'DuplicateLocationError', 'BadPortLocationError', @@ -271,7 +272,7 @@ class Permissions(object): for location in locations: # set the permissions permissions = {'allowXULXBL': 'noxul' not in location.options} - for perm, allow in permissions.iteritems(): + for perm, allow in six.iteritems(permissions): if allow: permission_type = 1 else: diff --git a/testing/mozbase/mozprofile/mozprofile/prefs.py b/testing/mozbase/mozprofile/mozprofile/prefs.py index 79df9baca010..0a79ac55f318 100644 --- a/testing/mozbase/mozprofile/mozprofile/prefs.py +++ b/testing/mozbase/mozprofile/mozprofile/prefs.py @@ -168,6 +168,9 @@ class Preferences(object): lines = [i.strip() for i in mozfile.load(path).readlines()] _lines = [] for line in lines: + # decode bytes in case of URL processing + if isinstance(line, bytes): + line = line.decode() if not line.startswith(pref_setter): continue if '//' in line: diff --git a/testing/mozbase/mozprofile/mozprofile/profile.py b/testing/mozbase/mozprofile/mozprofile/profile.py index 44af73b8127b..81dfc091a913 100644 --- a/testing/mozbase/mozprofile/mozprofile/profile.py +++ b/testing/mozbase/mozprofile/mozprofile/profile.py @@ -14,7 +14,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty from shutil import copytree import mozfile -from six import string_types +from six import string_types, python_2_unicode_compatible from .addons import AddonManager from .permissions import Permissions @@ -150,6 +150,7 @@ class BaseProfile(object): return os.path.exists(self.profile) +@python_2_unicode_compatible class Profile(BaseProfile): """Handles all operations regarding profile. @@ -421,9 +422,6 @@ class Profile(BaseProfile): return retval def __str__(self): - return unicode(self).encode('utf-8') - - def __unicode__(self): return self.summary() diff --git a/testing/mozbase/mozprofile/setup.cfg b/testing/mozbase/mozprofile/setup.cfg new file mode 100644 index 000000000000..3c6e79cf31da --- /dev/null +++ b/testing/mozbase/mozprofile/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/testing/mozbase/mozprofile/setup.py b/testing/mozbase/mozprofile/setup.py index e53d8d671c79..c7eafb6d8f8a 100644 --- a/testing/mozbase/mozprofile/setup.py +++ b/testing/mozbase/mozprofile/setup.py @@ -7,7 +7,7 @@ from __future__ import absolute_import from setuptools import setup PACKAGE_NAME = 'mozprofile' -PACKAGE_VERSION = '1.1.0' +PACKAGE_VERSION = '2.0.0' deps = [ 'mozfile==1.*', @@ -25,7 +25,7 @@ setup(name=PACKAGE_NAME, 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', 'Topic :: Software Development :: Libraries :: Python Modules', ], keywords='mozilla', diff --git a/testing/mozbase/mozprofile/tests/manifest.ini b/testing/mozbase/mozprofile/tests/manifest.ini index 3f7aec4a27d9..74cfec024730 100644 --- a/testing/mozbase/mozprofile/tests/manifest.ini +++ b/testing/mozbase/mozprofile/tests/manifest.ini @@ -1,6 +1,5 @@ [DEFAULT] subsuite = mozbase, os == "linux" -skip-if = python == 3 [test_addonid.py] [test_server_locations.py] [test_preferences.py] diff --git a/testing/mozbase/mozprofile/tests/test_preferences.py b/testing/mozbase/mozprofile/tests/test_preferences.py index 1edab4216fa4..6ea316cf8284 100755 --- a/testing/mozbase/mozprofile/tests/test_preferences.py +++ b/testing/mozbase/mozprofile/tests/test_preferences.py @@ -72,8 +72,7 @@ def test_basic_prefs(compare_generated): _prefs = {"browser.startup.homepage": "http://planet.mozilla.org/"} commandline = [] - _prefs = _prefs.items() - for pref, value in _prefs: + for pref, value in _prefs.items(): commandline += ["--pref", "%s:%s" % (pref, value)] compare_generated(_prefs, commandline) @@ -100,8 +99,8 @@ browser.startup.homepage = http://planet.mozilla.org/ browser.startup.homepage = http://github.com/ """ try: - fd, name = tempfile.mkstemp(suffix='.ini') - os.write(fd, _ini) + fd, name = tempfile.mkstemp(suffix='.ini', text=True) + os.write(fd, _ini.encode()) os.close(fd) commandline = ["--preferences", name] @@ -129,8 +128,8 @@ def test_ini_keep_case(compare_generated): general.warnOnAboutConfig = False """ try: - fd, name = tempfile.mkstemp(suffix='.ini') - os.write(fd, _ini) + fd, name = tempfile.mkstemp(suffix='.ini', text=True) + os.write(fd, _ini.encode()) os.close(fd) commandline = ["--preferences", name] @@ -294,7 +293,7 @@ def test_can_read_prefs_with_multiline_comments(): user_pref("webgl.enabled_for_all_sites", true); user_pref("webgl.force-enabled", true); -""") +""".encode()) assert Preferences.read_prefs(user_js.name) == [ ('webgl.enabled_for_all_sites', True), ('webgl.force-enabled', True) @@ -309,7 +308,7 @@ def test_json(compare_generated): # just repr it...could use the json module but we don't need it here with mozfile.NamedTemporaryFile(suffix='.json') as f: - f.write(json) + f.write(json.encode()) f.flush() commandline = ["--preferences", f.name] @@ -321,7 +320,7 @@ def test_json_datatypes(): json = """{"zoom.minPercent": 30.1, "zoom.maxPercent": 300}""" with mozfile.NamedTemporaryFile(suffix='.json') as f: - f.write(json) + f.write(json.encode()) f.flush() with pytest.raises(PreferencesReadError): @@ -342,7 +341,7 @@ def test_prefs_write(): path = None read_prefs = None try: - with mozfile.NamedTemporaryFile(suffix='.js', delete=False) as f: + with mozfile.NamedTemporaryFile(suffix='.js', delete=False, mode='w+t') as f: path = f.name preferences.write(f, _prefs) diff --git a/testing/mozbase/mozprofile/tests/test_profile_view.py b/testing/mozbase/mozprofile/tests/test_profile_view.py index 26c3f0611c28..1bc27a94df20 100644 --- a/testing/mozbase/mozprofile/tests/test_profile_view.py +++ b/testing/mozbase/mozprofile/tests/test_profile_view.py @@ -8,6 +8,8 @@ from __future__ import absolute_import import mozprofile import os +import sys +import pytest import mozunit @@ -37,9 +39,14 @@ def test_profileprint(tmpdir): def test_str_cast(): """Test casting to a string.""" profile = mozprofile.Profile() - assert str(profile) == profile.summary().encode("utf-8") + if sys.version_info[0] >= 3: + assert str(profile) == profile.summary() + else: + assert str(profile) == profile.summary().encode("utf-8") +@pytest.mark.skipif(sys.version_info[0] >= 3, + reason="no unicode() operator starting from python3") def test_unicode_cast(): """Test casting to a unicode string.""" profile = mozprofile.Profile() @@ -55,14 +62,14 @@ def test_profile_diff(): # diff two profiles diff = dict(mozprofile.diff(profile1, profile2)) - assert diff.keys() == ['user.js'] + assert list(diff.keys()) == ['user.js'] lines = [line.strip() for line in diff['user.js'].splitlines()] assert '+foo: bar' in lines # diff a blank vs FirefoxProfile ff_profile = mozprofile.FirefoxProfile() diff = dict(mozprofile.diff(profile2, ff_profile)) - assert diff.keys() == ['user.js'] + assert list(diff.keys()) == ['user.js'] lines = [line.strip() for line in diff['user.js'].splitlines()] assert '-foo: bar' in lines ff_pref_lines = ['+%s: %s' % (key, value) From 3a76399ecb87426136c7e034d2c599191668d84a Mon Sep 17 00:00:00 2001 From: Cosmin Sabou Date: Tue, 11 Sep 2018 15:11:02 +0300 Subject: [PATCH 08/20] Backed out changeset 19e2c611e889 (bug 1442755) for wpt reftest failures. CLOSED TREE --- widget/gtk/gtk3drawing.cpp | 11 ++++------ widget/gtk/gtkdrawing.h | 1 - widget/gtk/mozgtk/mozgtk.c | 1 + widget/gtk/nsNativeThemeGTK.cpp | 36 -------------------------------- widget/gtk/nsNativeThemeGTK.h | 3 --- widget/gtk/nsWindow.cpp | 37 --------------------------------- widget/gtk/nsWindow.h | 3 --- 7 files changed, 5 insertions(+), 87 deletions(-) diff --git a/widget/gtk/gtk3drawing.cpp b/widget/gtk/gtk3drawing.cpp index e2cb3fe5c335..affa29cb5e05 100644 --- a/widget/gtk/gtk3drawing.cpp +++ b/widget/gtk/gtk3drawing.cpp @@ -172,8 +172,6 @@ GetStateFlagsFromGtkWidgetState(GtkWidgetState* state) stateFlags = static_cast(stateFlags|GTK_STATE_FLAG_PRELIGHT); if (state->focused) stateFlags = static_cast(stateFlags|GTK_STATE_FLAG_FOCUSED); - if (state->backdrop) - stateFlags = static_cast(stateFlags|GTK_STATE_FLAG_BACKDROP); } return stateFlags; @@ -2313,9 +2311,8 @@ moz_gtk_header_bar_paint(WidgetNodeType widgetType, cairo_t *cr, GdkRectangle* rect, GtkWidgetState* state) { GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state); - GtkStyleContext *style = - GetStyleContext(widgetType, GTK_TEXT_DIR_NONE, state_flags); - + GtkStyleContext *style = GetStyleContext(widgetType, GTK_TEXT_DIR_LTR, + state_flags); InsetByMargin(rect, style); // Some themes (Adwaita for instance) draws bold dark line at @@ -2323,8 +2320,6 @@ moz_gtk_header_bar_paint(WidgetNodeType widgetType, // draw with some extent to make the titlebar bottom part invisible. #define TITLEBAR_EXTENT 4 - // We don't need to draw window decoration for MOZ_GTK_HEADER_BAR_MAXIMIZED, - // i.e. when main window is maximized. if (widgetType == MOZ_GTK_HEADER_BAR) { GtkStyleContext* windowStyle = GetStyleContext(MOZ_GTK_WINDOW); bool solidDecorations = @@ -2349,6 +2344,8 @@ moz_gtk_header_bar_paint(WidgetNodeType widgetType, return MOZ_GTK_SUCCESS; } + + static GtkBorder GetMarginBorderPadding(GtkStyleContext* aStyle) { diff --git a/widget/gtk/gtkdrawing.h b/widget/gtk/gtkdrawing.h index 501aba92644c..4512925db438 100644 --- a/widget/gtk/gtkdrawing.h +++ b/widget/gtk/gtkdrawing.h @@ -31,7 +31,6 @@ typedef struct { /* The depressed state is for buttons which remain active for a longer period: * activated toggle buttons or buttons showing a popup menu. */ guint8 depressed; - guint8 backdrop; gint32 curpos; /* curpos and maxpos are used for scrollbars */ gint32 maxpos; gint32 scale; /* actual widget scale */ diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index 09511d935b0e..11dfa7b89a07 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -658,3 +658,4 @@ XShmQueryExtension(Display* aDisplay) return False; } #endif + diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp index 7a8807977953..e0ce4f2b6fa8 100644 --- a/widget/gtk/nsNativeThemeGTK.cpp +++ b/widget/gtk/nsNativeThemeGTK.cpp @@ -41,7 +41,6 @@ #include "mozilla/Preferences.h" #include "mozilla/layers/StackingContextHelper.h" #include "mozilla/StaticPrefs.h" -#include "nsWindow.h" #ifdef MOZ_X11 # ifdef CAIRO_HAS_XLIB_SURFACE @@ -445,15 +444,6 @@ nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aWidgetType, nsIFrame* aF *aWidgetFlags = CheckBooleanAttr(aFrame, nsGkAtoms::parentfocused); } } - - if (aWidgetType == StyleAppearance::MozWindowTitlebar || - aWidgetType == StyleAppearance::MozWindowTitlebarMaximized || - aWidgetType == StyleAppearance::MozWindowButtonClose || - aWidgetType == StyleAppearance::MozWindowButtonMinimize || - aWidgetType == StyleAppearance::MozWindowButtonMaximize || - aWidgetType == StyleAppearance::MozWindowButtonRestore) { - aState->backdrop = !nsWindow::GetTopLevelWindowActiveState(aFrame); - } } switch (aWidgetType) { @@ -1797,16 +1787,6 @@ nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame, return NS_OK; } - if (aWidgetType == StyleAppearance::MozWindowTitlebar || - aWidgetType == StyleAppearance::MozWindowTitlebarMaximized || - aWidgetType == StyleAppearance::MozWindowButtonClose || - aWidgetType == StyleAppearance::MozWindowButtonMinimize || - aWidgetType == StyleAppearance::MozWindowButtonMaximize || - aWidgetType == StyleAppearance::MozWindowButtonRestore) { - *aShouldRepaint = true; - return NS_OK; - } - if ((aWidgetType == StyleAppearance::ScrollbarthumbVertical || aWidgetType == StyleAppearance::ScrollbarthumbHorizontal) && aAttribute == nsGkAtoms::active) { @@ -2103,19 +2083,3 @@ nsNativeThemeGTK::GetWidgetTransparency(nsIFrame* aFrame, } } - -bool -nsNativeThemeGTK::WidgetAppearanceDependsOnWindowFocus(StyleAppearance aWidgetType) -{ - switch (aWidgetType) { - case StyleAppearance::MozWindowTitlebar: - case StyleAppearance::MozWindowTitlebarMaximized: - case StyleAppearance::MozWindowButtonClose: - case StyleAppearance::MozWindowButtonMinimize: - case StyleAppearance::MozWindowButtonMaximize: - case StyleAppearance::MozWindowButtonRestore: - return true; - default: - return false; - } -} diff --git a/widget/gtk/nsNativeThemeGTK.h b/widget/gtk/nsNativeThemeGTK.h index 25448b376d81..8543943cf280 100644 --- a/widget/gtk/nsNativeThemeGTK.h +++ b/widget/gtk/nsNativeThemeGTK.h @@ -76,9 +76,6 @@ public: virtual Transparency GetWidgetTransparency(nsIFrame* aFrame, WidgetType aWidgetType) override; - - virtual bool WidgetAppearanceDependsOnWindowFocus(WidgetType aWidgetType) override; - nsNativeThemeGTK(); protected: diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index e3ee1399f484..58ce7fc2289a 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -7381,40 +7381,3 @@ nsIWidget::CreateChildWindow() nsCOMPtr window = new nsWindow(); return window.forget(); } - -bool -nsWindow::GetTopLevelWindowActiveState(nsIFrame *aFrame) -{ - // Used by window frame and button box rendering. We can end up in here in - // the content process when rendering one of these moz styles freely in a - // page. Fail in this case, there is no applicable window focus state. - if (!XRE_IsParentProcess()) { - return false; - } - // All headless windows are considered active so they are painted. - if (gfxPlatform::IsHeadless()) { - return true; - } - // Get the widget. nsIFrame's GetNearestWidget walks up the view chain - // until it finds a real window. - nsWindow* window = static_cast(aFrame->GetNearestWidget()); - if (!window) { - return false; - } - - // Get our toplevel nsWindow. - if (!window->mIsTopLevel) { - GtkWidget *widget = window->GetMozContainerWidget(); - if (!widget) { - return false; - } - - GtkWidget *toplevelWidget = gtk_widget_get_toplevel(widget); - window = get_window_for_gtk_widget(toplevelWidget); - if (!window) { - return false; - } - } - - return (gFocusWindow == window); -} diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index 4cb697f21f1f..f6065ee3dee2 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -15,7 +15,6 @@ #include "nsITimer.h" #include "nsGkAtoms.h" #include "nsRefPtrHashtable.h" -#include "nsIFrame.h" #include "nsBaseWidget.h" #include "CompositorWidget.h" @@ -429,8 +428,6 @@ public: */ static CSDSupportLevel GetSystemCSDSupportLevel(); - static bool GetTopLevelWindowActiveState(nsIFrame *aFrame); - protected: virtual ~nsWindow(); From 80e58fff22b094475e1f1a24753acf8ebd690ac2 Mon Sep 17 00:00:00 2001 From: Cosmin Sabou Date: Tue, 11 Sep 2018 15:12:53 +0300 Subject: [PATCH 09/20] Backed out changeset 30ec08a53991 (bug 1471888) for awsy test failures. CLOSED TREE --- .../mozbase/mozprofile/mozprofile/addons.py | 12 ++++++------ .../mozprofile/mozprofile/permissions.py | 3 +-- .../mozbase/mozprofile/mozprofile/prefs.py | 3 --- .../mozbase/mozprofile/mozprofile/profile.py | 6 ++++-- testing/mozbase/mozprofile/setup.cfg | 2 -- testing/mozbase/mozprofile/setup.py | 4 ++-- testing/mozbase/mozprofile/tests/manifest.ini | 1 + .../mozprofile/tests/test_preferences.py | 19 ++++++++++--------- .../mozprofile/tests/test_profile_view.py | 13 +++---------- 9 files changed, 27 insertions(+), 36 deletions(-) delete mode 100644 testing/mozbase/mozprofile/setup.cfg diff --git a/testing/mozbase/mozprofile/mozprofile/addons.py b/testing/mozbase/mozprofile/mozprofile/addons.py index 6c3ccc534935..d7bf27713b8e 100644 --- a/testing/mozbase/mozprofile/mozprofile/addons.py +++ b/testing/mozbase/mozprofile/mozprofile/addons.py @@ -11,14 +11,14 @@ import shutil import tempfile import zipfile import hashlib -import binascii from xml.dom import minidom + from six import reraise, string_types import mozfile from mozlog.unstructured import getLogger -_SALT = binascii.hexlify(os.urandom(32)) +_SALT = os.urandom(32).encode('hex') _TEMPORARY_ADDON_SUFFIX = "@temporary-addon" # Logger for 'mozprofile.addons' module @@ -203,7 +203,7 @@ class AddonManager(object): @classmethod def _gen_iid(cls, addon_path): hash = hashlib.sha1(_SALT) - hash.update(addon_path.encode()) + hash.update(addon_path) return hash.hexdigest() + _TEMPORARY_ADDON_SUFFIX @classmethod @@ -262,7 +262,7 @@ class AddonManager(object): manifest = compressed_file.read('install.rdf') elif 'manifest.json' in filenames: is_webext = True - manifest = compressed_file.read('manifest.json').decode() + manifest = compressed_file.read('manifest.json') manifest = json.loads(manifest) else: raise KeyError("No manifest") @@ -279,7 +279,7 @@ class AddonManager(object): else: raise IOError('Add-on path is neither an XPI nor a directory: %s' % addon_path) except (IOError, KeyError) as e: - reraise(AddonFormatError, AddonFormatError(str(e)), sys.exc_info()[2]) + reraise(AddonFormatError(str(e)), None, sys.exc_info()[2]) if is_webext: details['version'] = manifest['version'] @@ -309,7 +309,7 @@ class AddonManager(object): if entry in details.keys(): details.update({entry: get_text(node)}) except Exception as e: - reraise(AddonFormatError, AddonFormatError(str(e)), sys.exc_info()[2]) + reraise(AddonFormatError(str(e)), None, sys.exc_info()[2]) # turn unpack into a true/false value if isinstance(details['unpack'], string_types): diff --git a/testing/mozbase/mozprofile/mozprofile/permissions.py b/testing/mozbase/mozprofile/mozprofile/permissions.py index 0671e8ac8e97..047fa54e1ee7 100644 --- a/testing/mozbase/mozprofile/mozprofile/permissions.py +++ b/testing/mozbase/mozprofile/mozprofile/permissions.py @@ -15,7 +15,6 @@ import sqlite3 from six import string_types from six.moves.urllib import parse -import six __all__ = ['MissingPrimaryLocationError', 'MultiplePrimaryLocationsError', 'DEFAULT_PORTS', 'DuplicateLocationError', 'BadPortLocationError', @@ -272,7 +271,7 @@ class Permissions(object): for location in locations: # set the permissions permissions = {'allowXULXBL': 'noxul' not in location.options} - for perm, allow in six.iteritems(permissions): + for perm, allow in permissions.iteritems(): if allow: permission_type = 1 else: diff --git a/testing/mozbase/mozprofile/mozprofile/prefs.py b/testing/mozbase/mozprofile/mozprofile/prefs.py index 0a79ac55f318..79df9baca010 100644 --- a/testing/mozbase/mozprofile/mozprofile/prefs.py +++ b/testing/mozbase/mozprofile/mozprofile/prefs.py @@ -168,9 +168,6 @@ class Preferences(object): lines = [i.strip() for i in mozfile.load(path).readlines()] _lines = [] for line in lines: - # decode bytes in case of URL processing - if isinstance(line, bytes): - line = line.decode() if not line.startswith(pref_setter): continue if '//' in line: diff --git a/testing/mozbase/mozprofile/mozprofile/profile.py b/testing/mozbase/mozprofile/mozprofile/profile.py index 81dfc091a913..44af73b8127b 100644 --- a/testing/mozbase/mozprofile/mozprofile/profile.py +++ b/testing/mozbase/mozprofile/mozprofile/profile.py @@ -14,7 +14,7 @@ from abc import ABCMeta, abstractmethod, abstractproperty from shutil import copytree import mozfile -from six import string_types, python_2_unicode_compatible +from six import string_types from .addons import AddonManager from .permissions import Permissions @@ -150,7 +150,6 @@ class BaseProfile(object): return os.path.exists(self.profile) -@python_2_unicode_compatible class Profile(BaseProfile): """Handles all operations regarding profile. @@ -422,6 +421,9 @@ class Profile(BaseProfile): return retval def __str__(self): + return unicode(self).encode('utf-8') + + def __unicode__(self): return self.summary() diff --git a/testing/mozbase/mozprofile/setup.cfg b/testing/mozbase/mozprofile/setup.cfg deleted file mode 100644 index 3c6e79cf31da..000000000000 --- a/testing/mozbase/mozprofile/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[bdist_wheel] -universal=1 diff --git a/testing/mozbase/mozprofile/setup.py b/testing/mozbase/mozprofile/setup.py index c7eafb6d8f8a..e53d8d671c79 100644 --- a/testing/mozbase/mozprofile/setup.py +++ b/testing/mozbase/mozprofile/setup.py @@ -7,7 +7,7 @@ from __future__ import absolute_import from setuptools import setup PACKAGE_NAME = 'mozprofile' -PACKAGE_VERSION = '2.0.0' +PACKAGE_VERSION = '1.1.0' deps = [ 'mozfile==1.*', @@ -25,7 +25,7 @@ setup(name=PACKAGE_NAME, 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3', 'Topic :: Software Development :: Libraries :: Python Modules', ], keywords='mozilla', diff --git a/testing/mozbase/mozprofile/tests/manifest.ini b/testing/mozbase/mozprofile/tests/manifest.ini index 74cfec024730..3f7aec4a27d9 100644 --- a/testing/mozbase/mozprofile/tests/manifest.ini +++ b/testing/mozbase/mozprofile/tests/manifest.ini @@ -1,5 +1,6 @@ [DEFAULT] subsuite = mozbase, os == "linux" +skip-if = python == 3 [test_addonid.py] [test_server_locations.py] [test_preferences.py] diff --git a/testing/mozbase/mozprofile/tests/test_preferences.py b/testing/mozbase/mozprofile/tests/test_preferences.py index 6ea316cf8284..1edab4216fa4 100755 --- a/testing/mozbase/mozprofile/tests/test_preferences.py +++ b/testing/mozbase/mozprofile/tests/test_preferences.py @@ -72,7 +72,8 @@ def test_basic_prefs(compare_generated): _prefs = {"browser.startup.homepage": "http://planet.mozilla.org/"} commandline = [] - for pref, value in _prefs.items(): + _prefs = _prefs.items() + for pref, value in _prefs: commandline += ["--pref", "%s:%s" % (pref, value)] compare_generated(_prefs, commandline) @@ -99,8 +100,8 @@ browser.startup.homepage = http://planet.mozilla.org/ browser.startup.homepage = http://github.com/ """ try: - fd, name = tempfile.mkstemp(suffix='.ini', text=True) - os.write(fd, _ini.encode()) + fd, name = tempfile.mkstemp(suffix='.ini') + os.write(fd, _ini) os.close(fd) commandline = ["--preferences", name] @@ -128,8 +129,8 @@ def test_ini_keep_case(compare_generated): general.warnOnAboutConfig = False """ try: - fd, name = tempfile.mkstemp(suffix='.ini', text=True) - os.write(fd, _ini.encode()) + fd, name = tempfile.mkstemp(suffix='.ini') + os.write(fd, _ini) os.close(fd) commandline = ["--preferences", name] @@ -293,7 +294,7 @@ def test_can_read_prefs_with_multiline_comments(): user_pref("webgl.enabled_for_all_sites", true); user_pref("webgl.force-enabled", true); -""".encode()) +""") assert Preferences.read_prefs(user_js.name) == [ ('webgl.enabled_for_all_sites', True), ('webgl.force-enabled', True) @@ -308,7 +309,7 @@ def test_json(compare_generated): # just repr it...could use the json module but we don't need it here with mozfile.NamedTemporaryFile(suffix='.json') as f: - f.write(json.encode()) + f.write(json) f.flush() commandline = ["--preferences", f.name] @@ -320,7 +321,7 @@ def test_json_datatypes(): json = """{"zoom.minPercent": 30.1, "zoom.maxPercent": 300}""" with mozfile.NamedTemporaryFile(suffix='.json') as f: - f.write(json.encode()) + f.write(json) f.flush() with pytest.raises(PreferencesReadError): @@ -341,7 +342,7 @@ def test_prefs_write(): path = None read_prefs = None try: - with mozfile.NamedTemporaryFile(suffix='.js', delete=False, mode='w+t') as f: + with mozfile.NamedTemporaryFile(suffix='.js', delete=False) as f: path = f.name preferences.write(f, _prefs) diff --git a/testing/mozbase/mozprofile/tests/test_profile_view.py b/testing/mozbase/mozprofile/tests/test_profile_view.py index 1bc27a94df20..26c3f0611c28 100644 --- a/testing/mozbase/mozprofile/tests/test_profile_view.py +++ b/testing/mozbase/mozprofile/tests/test_profile_view.py @@ -8,8 +8,6 @@ from __future__ import absolute_import import mozprofile import os -import sys -import pytest import mozunit @@ -39,14 +37,9 @@ def test_profileprint(tmpdir): def test_str_cast(): """Test casting to a string.""" profile = mozprofile.Profile() - if sys.version_info[0] >= 3: - assert str(profile) == profile.summary() - else: - assert str(profile) == profile.summary().encode("utf-8") + assert str(profile) == profile.summary().encode("utf-8") -@pytest.mark.skipif(sys.version_info[0] >= 3, - reason="no unicode() operator starting from python3") def test_unicode_cast(): """Test casting to a unicode string.""" profile = mozprofile.Profile() @@ -62,14 +55,14 @@ def test_profile_diff(): # diff two profiles diff = dict(mozprofile.diff(profile1, profile2)) - assert list(diff.keys()) == ['user.js'] + assert diff.keys() == ['user.js'] lines = [line.strip() for line in diff['user.js'].splitlines()] assert '+foo: bar' in lines # diff a blank vs FirefoxProfile ff_profile = mozprofile.FirefoxProfile() diff = dict(mozprofile.diff(profile2, ff_profile)) - assert list(diff.keys()) == ['user.js'] + assert diff.keys() == ['user.js'] lines = [line.strip() for line in diff['user.js'].splitlines()] assert '-foo: bar' in lines ff_pref_lines = ['+%s: %s' % (key, value) From 63856d6d6e8e18efd06cc7dff64627e30b8eb4eb Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Tue, 11 Sep 2018 12:10:54 +0000 Subject: [PATCH 10/20] Bug 1485929 - Create HTMLEditor::RefreshInlineTableEditingUIInternal() for internal use r=m_kato HTMLEditor::RefreshInlineTableEditingUI() is an XPCOM method. Therefore, we should create a non-virtual method for internal use. Additionally, this patch makes related methods safer for nested calls of ShowInlineTableEditingUI() and HideInlineTableEditingUI(). If ShowInlineTableEditingUI() and RefreshInlineTableEditingUIInternal() detects hiding or replacing current UI, they return error to make the callers stop handling anything for new UI. Differential Revision: https://phabricator.services.mozilla.com/D5428 --HG-- extra : moz-landing-system : lando --- editor/libeditor/HTMLAnonymousNodeEditor.cpp | 18 +- editor/libeditor/HTMLEditor.h | 21 +- editor/libeditor/HTMLInlineTableEditor.cpp | 258 ++++++++++++------- editor/nsIHTMLInlineTableEditor.idl | 6 +- 4 files changed, 200 insertions(+), 103 deletions(-) diff --git a/editor/libeditor/HTMLAnonymousNodeEditor.cpp b/editor/libeditor/HTMLAnonymousNodeEditor.cpp index 9be74e628a97..b42fabb05a14 100644 --- a/editor/libeditor/HTMLAnonymousNodeEditor.cpp +++ b/editor/libeditor/HTMLAnonymousNodeEditor.cpp @@ -290,8 +290,8 @@ HTMLEditor::HideAnonymousEditingUIs() NS_ASSERTION(!mAbsolutelyPositionedObject, "HideGrabber failed"); } if (mInlineEditedCell) { - HideInlineTableEditingUI(); - NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed"); + HideInlineTableEditingUIInternal(); + NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUIInternal failed"); } if (mResizedObject) { DebugOnly rv = HideResizersInternal(); @@ -315,8 +315,8 @@ HTMLEditor::HideAnonymousEditingUIsIfUnnecessary() if (!IsInlineTableEditorEnabled() && mInlineEditedCell) { // XXX If we're resizing a table element, we need to cancel or commit the // operation now. - HideInlineTableEditingUI(); - NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed"); + HideInlineTableEditingUIInternal(); + NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUIInternal failed"); } if (!IsObjectResizerEnabled() && mResizedObject) { // XXX If we're resizing something, we need to cancel or commit the @@ -438,10 +438,8 @@ HTMLEditor::RefereshEditingUI(Selection& aSelection) if (IsInlineTableEditorEnabled() && mInlineEditedCell && mInlineEditedCell != cellElement) { - // XXX HideInlineTableEditingUI() won't return error. Should be change it - // void later. - HideInlineTableEditingUI(); - NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUI failed"); + HideInlineTableEditingUIInternal(); + NS_ASSERTION(!mInlineEditedCell, "HideInlineTableEditingUIInternal failed"); } // now, let's display all contextual UI for good @@ -483,12 +481,12 @@ HTMLEditor::RefereshEditingUI(Selection& aSelection) if (IsInlineTableEditorEnabled() && cellElement && IsModifiableNode(*cellElement) && cellElement != hostContent) { if (mInlineEditedCell) { - nsresult rv = RefreshInlineTableEditingUI(); + nsresult rv = RefreshInlineTableEditingUIInternal(); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { - nsresult rv = ShowInlineTableEditingUI(cellElement); + nsresult rv = ShowInlineTableEditingUIInternal(*cellElement); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } diff --git a/editor/libeditor/HTMLEditor.h b/editor/libeditor/HTMLEditor.h index cc613e81e396..11701b02bcf8 100644 --- a/editor/libeditor/HTMLEditor.h +++ b/editor/libeditor/HTMLEditor.h @@ -1927,15 +1927,26 @@ protected: // Shouldn't be used by friend classes nsAString& aReturn); /** - * Shows inline table editing UI around a table cell - * @param aCell [IN] a DOM Element being a table cell, td or th + * Shows inline table editing UI around a element which contains + * aCellElement. This returns error if creating UI is hidden during this, + * or detects another set of UI during this. In such case, callers + * shouldn't keep handling anything for the UI. + * + * @param aCellElement Must be an
or element. */ - nsresult ShowInlineTableEditingUI(Element* aCell); + nsresult ShowInlineTableEditingUIInternal(Element& aCellElement); /** - * Hide all inline table editing UI + * Hide all inline table editing UI. */ - void HideInlineTableEditingUI(); + void HideInlineTableEditingUIInternal(); + + /** + * RefreshInlineTableEditingUIInternal() moves inline table editing UI to + * proper position. This returns error if the UI is hidden or replaced + * during moving. + */ + nsresult RefreshInlineTableEditingUIInternal(); /** * IsEmptyTextNode() returns true if aNode is a text node and does not have diff --git a/editor/libeditor/HTMLInlineTableEditor.cpp b/editor/libeditor/HTMLInlineTableEditor.cpp index 469b96f0a932..23da37a7166b 100644 --- a/editor/libeditor/HTMLInlineTableEditor.cpp +++ b/editor/libeditor/HTMLInlineTableEditor.cpp @@ -21,10 +21,6 @@ namespace mozilla { -// Uncomment the following line if you want to disable -// table deletion when the only column/row is removed -// #define DISABLE_TABLE_DELETION 1 - NS_IMETHODIMP HTMLEditor::SetInlineTableEditingEnabled(bool aIsEnabled) { @@ -40,62 +36,135 @@ HTMLEditor::GetInlineTableEditingEnabled(bool* aIsEnabled) } nsresult -HTMLEditor::ShowInlineTableEditingUI(Element* aCell) +HTMLEditor::ShowInlineTableEditingUIInternal(Element& aCellElement) { - // do nothing if aCell is not a table cell... - if (!aCell || !HTMLEditUtils::IsTableCell(aCell)) { + if (NS_WARN_IF(!HTMLEditUtils::IsTableCell(&aCellElement))) { return NS_OK; } - if (NS_WARN_IF(!IsDescendantOfEditorRoot(aCell))) { - return NS_ERROR_UNEXPECTED; + if (NS_WARN_IF(!IsDescendantOfEditorRoot(&aCellElement))) { + return NS_ERROR_FAILURE; } - if (mInlineEditedCell) { - NS_ERROR("call HideInlineTableEditingUI first"); - return NS_ERROR_UNEXPECTED; + if (NS_WARN_IF(mInlineEditedCell)) { + return NS_ERROR_FAILURE; } + mInlineEditedCell = &aCellElement; + // the resizers and the shadow will be anonymous children of the body RefPtr bodyElement = GetRoot(); - NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER); + if (NS_WARN_IF(!bodyElement)) { + return NS_ERROR_FAILURE; + } - mAddColumnBeforeButton = - CreateAnonymousElement(nsGkAtoms::a, *bodyElement, - NS_LITERAL_STRING("mozTableAddColumnBefore"), false); - mRemoveColumnButton = - CreateAnonymousElement(nsGkAtoms::a, *bodyElement, - NS_LITERAL_STRING("mozTableRemoveColumn"), false); - mAddColumnAfterButton = - CreateAnonymousElement(nsGkAtoms::a, *bodyElement, - NS_LITERAL_STRING("mozTableAddColumnAfter"), false); + do { + // The buttons of inline table editor will be children of the + // element. Creating the anonymous elements may cause calling + // HideInlineTableEditingUIInternal() via a mutation event listener. + // So, we should store new button to a local variable, then, check: + // - whether creating a button is already set to the member or not + // - whether already created buttons are changed to another set + // If creating the buttons are canceled, we hit the latter check. + // If buttons for another table are created during this, we hit the latter + // check too. + // If buttons are just created again for same element, we hit the former + // check. + ManualNACPtr addColumnBeforeButton = + CreateAnonymousElement(nsGkAtoms::a, *bodyElement, + NS_LITERAL_STRING("mozTableAddColumnBefore"), false); + if (NS_WARN_IF(!addColumnBeforeButton)) { + break; // Hide unnecessary buttons created above. + } + if (NS_WARN_IF(mAddColumnBeforeButton) || + NS_WARN_IF(mInlineEditedCell != &aCellElement)) { + return NS_ERROR_FAILURE; // Don't hide another set of buttons. + } + mAddColumnBeforeButton = std::move(addColumnBeforeButton); - mAddRowBeforeButton = - CreateAnonymousElement(nsGkAtoms::a, *bodyElement, - NS_LITERAL_STRING("mozTableAddRowBefore"), false); - mRemoveRowButton = - CreateAnonymousElement(nsGkAtoms::a, *bodyElement, - NS_LITERAL_STRING("mozTableRemoveRow"), false); - mAddRowAfterButton = - CreateAnonymousElement(nsGkAtoms::a, *bodyElement, - NS_LITERAL_STRING("mozTableAddRowAfter"), false); + ManualNACPtr removeColumnButton = + CreateAnonymousElement(nsGkAtoms::a, *bodyElement, + NS_LITERAL_STRING("mozTableRemoveColumn"), false); + if (NS_WARN_IF(!removeColumnButton)) { + break; + } + if (NS_WARN_IF(mRemoveColumnButton) || + NS_WARN_IF(mInlineEditedCell != &aCellElement)) { + return NS_ERROR_FAILURE; + } + mRemoveColumnButton = std::move(removeColumnButton); - AddMouseClickListener(mAddColumnBeforeButton); - AddMouseClickListener(mRemoveColumnButton); - AddMouseClickListener(mAddColumnAfterButton); - AddMouseClickListener(mAddRowBeforeButton); - AddMouseClickListener(mRemoveRowButton); - AddMouseClickListener(mAddRowAfterButton); + ManualNACPtr addColumnAfterButton = + CreateAnonymousElement(nsGkAtoms::a, *bodyElement, + NS_LITERAL_STRING("mozTableAddColumnAfter"), + false); + if (NS_WARN_IF(!addColumnAfterButton)) { + break; + } + if (NS_WARN_IF(mAddColumnAfterButton) || + NS_WARN_IF(mInlineEditedCell != &aCellElement)) { + return NS_ERROR_FAILURE; + } + mAddColumnAfterButton = std::move(addColumnAfterButton); - mInlineEditedCell = aCell; + ManualNACPtr addRowBeforeButton = + CreateAnonymousElement(nsGkAtoms::a, *bodyElement, + NS_LITERAL_STRING("mozTableAddRowBefore"), false); + if (NS_WARN_IF(!addRowBeforeButton)) { + break; + } + if (NS_WARN_IF(mAddRowBeforeButton) || + NS_WARN_IF(mInlineEditedCell != &aCellElement)) { + return NS_ERROR_FAILURE; + } + mAddRowBeforeButton = std::move(addRowBeforeButton); - mHasShownInlineTableEditor = true; + ManualNACPtr removeRowButton = + CreateAnonymousElement(nsGkAtoms::a, *bodyElement, + NS_LITERAL_STRING("mozTableRemoveRow"), false); + if (NS_WARN_IF(!removeRowButton)) { + break; + } + if (NS_WARN_IF(mRemoveRowButton) || + NS_WARN_IF(mInlineEditedCell != &aCellElement)) { + return NS_ERROR_FAILURE; + } + mRemoveRowButton = std::move(removeRowButton); - return RefreshInlineTableEditingUI(); + ManualNACPtr addRowAfterButton = + CreateAnonymousElement(nsGkAtoms::a, *bodyElement, + NS_LITERAL_STRING("mozTableAddRowAfter"), false); + if (NS_WARN_IF(!addRowAfterButton)) { + break; + } + if (NS_WARN_IF(mAddRowAfterButton) || + NS_WARN_IF(mInlineEditedCell != &aCellElement)) { + return NS_ERROR_FAILURE; + } + mAddRowAfterButton = std::move(addRowAfterButton); + + AddMouseClickListener(mAddColumnBeforeButton); + AddMouseClickListener(mRemoveColumnButton); + AddMouseClickListener(mAddColumnAfterButton); + AddMouseClickListener(mAddRowBeforeButton); + AddMouseClickListener(mRemoveRowButton); + AddMouseClickListener(mAddRowAfterButton); + + mHasShownInlineTableEditor = true; + + nsresult rv = RefreshInlineTableEditingUIInternal(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; + } while (true); + + HideInlineTableEditingUIInternal(); + return NS_ERROR_FAILURE; } void -HTMLEditor::HideInlineTableEditingUI() +HTMLEditor::HideInlineTableEditingUIInternal() { mInlineEditedCell = nullptr; @@ -115,7 +184,7 @@ HTMLEditor::HideInlineTableEditingUI() // Calling DeleteRefToAnonymousNode() may cause showing the UI again. // Therefore, we should forget all anonymous contents first. // Otherwise, we could leak the old content because of overwritten by - // ShowInlineTableEditingUI(). + // ShowInlineTableEditingUIInternal(). ManualNACPtr addColumnBeforeButton(std::move(mAddColumnBeforeButton)); ManualNACPtr removeColumnButton(std::move(mRemoveColumnButton)); ManualNACPtr addColumnAfterButton(std::move(mAddColumnAfterButton)); @@ -159,14 +228,10 @@ HTMLEditor::DoInlineTableEditingAction(const Element& aElement) InsertTableRow(1, true); } else if (anonclass.EqualsLiteral("mozTableRemoveColumn")) { DeleteTableColumn(1); -#ifndef DISABLE_TABLE_DELETION hideUI = (colCount == 1); -#endif } else if (anonclass.EqualsLiteral("mozTableRemoveRow")) { DeleteTableRow(1); -#ifndef DISABLE_TABLE_DELETION hideUI = (rowCount == 1); -#endif } else { return NS_OK; } @@ -179,7 +244,7 @@ HTMLEditor::DoInlineTableEditingAction(const Element& aElement) } if (hideUI) { - HideInlineTableEditingUI(); + HideInlineTableEditingUIInternal(); if (hideResizersWithInlineTableUI) { DebugOnly rv = HideResizersInternal(); NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to hide resizers"); @@ -209,62 +274,81 @@ HTMLEditor::RemoveMouseClickListener(Element* aElement) NS_IMETHODIMP HTMLEditor::RefreshInlineTableEditingUI() +{ + nsresult rv = RefreshInlineTableEditingUIInternal(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; +} + +nsresult +HTMLEditor::RefreshInlineTableEditingUIInternal() { if (!mInlineEditedCell) { return NS_OK; } - RefPtr htmlElement = + RefPtr inlineEditingCellElement = nsGenericHTMLElement::FromNode(mInlineEditedCell); - if (!htmlElement) { - return NS_ERROR_NULL_POINTER; + if (NS_WARN_IF(!inlineEditingCellElement)) { + return NS_ERROR_FAILURE; } - int32_t xCell, yCell, wCell, hCell; - GetElementOrigin(*mInlineEditedCell, xCell, yCell); + int32_t cellX = 0, cellY = 0; + GetElementOrigin(*mInlineEditedCell, cellX, cellY); - wCell = htmlElement->OffsetWidth(); - hCell = htmlElement->OffsetHeight(); + int32_t cellWidth = inlineEditingCellElement->OffsetWidth(); + int32_t cellHeight = inlineEditingCellElement->OffsetHeight(); - int32_t xHoriz = xCell + wCell/2; - int32_t yVert = yCell + hCell/2; + int32_t centerOfCellX = cellX + cellWidth / 2; + int32_t centerOfCellY = cellY + cellHeight / 2; RefPtr tableElement = GetEnclosingTable(mInlineEditedCell); - int32_t rowCount, colCount; + int32_t rowCount = 0, colCount = 0; nsresult rv = GetTableSize(tableElement, &rowCount, &colCount); - NS_ENSURE_SUCCESS(rv, rv); - - SetAnonymousElementPosition(xHoriz-10, yCell-7, mAddColumnBeforeButton); -#ifdef DISABLE_TABLE_DELETION - if (colCount== 1) { - mRemoveColumnButton->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, - NS_LITERAL_STRING("hidden"), true); - } else { - if (mRemoveColumnButton->HasAttr(kNameSpaceID_None, nsGkAtoms::_class)) { - mRemoveColumnButton->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class); - } -#endif - SetAnonymousElementPosition(xHoriz-4, yCell-7, mRemoveColumnButton); -#ifdef DISABLE_TABLE_DELETION + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; } -#endif - SetAnonymousElementPosition(xHoriz+6, yCell-7, mAddColumnAfterButton); - SetAnonymousElementPosition(xCell-7, yVert-10, mAddRowBeforeButton); -#ifdef DISABLE_TABLE_DELETION - if (rowCount== 1) { - mRemoveRowButton->SetAttr(kNameSpaceID_None, nsGkAtoms::_class, - NS_LITERAL_STRING("hidden"), true); - } else { - if (mRemoveRowButton->HasAttr(kNameSpaceID_None, nsGkAtoms::_class)) { - mRemoveRowButton->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class, true); - } -#endif - SetAnonymousElementPosition(xCell-7, yVert-4, mRemoveRowButton); -#ifdef DISABLE_TABLE_DELETION + RefPtr addColumunBeforeButton = mAddColumnBeforeButton.get(); + SetAnonymousElementPosition(centerOfCellX - 10, cellY - 7, + addColumunBeforeButton); + if (NS_WARN_IF(addColumunBeforeButton != mAddColumnBeforeButton.get())) { + return NS_ERROR_FAILURE; + } + + RefPtr removeColumnButton = mRemoveColumnButton.get(); + SetAnonymousElementPosition(centerOfCellX - 4, cellY - 7, removeColumnButton); + if (NS_WARN_IF(removeColumnButton != mRemoveColumnButton.get())) { + return NS_ERROR_FAILURE; + } + + RefPtr addColumnAfterButton = mAddColumnAfterButton.get(); + SetAnonymousElementPosition(centerOfCellX + 6, cellY - 7, + addColumnAfterButton); + if (NS_WARN_IF(addColumnAfterButton != mAddColumnAfterButton.get())) { + return NS_ERROR_FAILURE; + } + + RefPtr addRowBeforeButton = mAddRowBeforeButton.get(); + SetAnonymousElementPosition(cellX - 7, centerOfCellY - 10, + addRowBeforeButton); + if (NS_WARN_IF(addRowBeforeButton != mAddRowBeforeButton.get())) { + return NS_ERROR_FAILURE; + } + + RefPtr removeRowButton = mRemoveRowButton.get(); + SetAnonymousElementPosition(cellX - 7, centerOfCellY - 4, removeRowButton); + if (NS_WARN_IF(removeRowButton != mRemoveRowButton.get())) { + return NS_ERROR_FAILURE; + } + + RefPtr addRowAfterButton = mAddRowAfterButton.get(); + SetAnonymousElementPosition(cellX - 7, centerOfCellY + 6, addRowAfterButton); + if (NS_WARN_IF(addRowAfterButton != mAddRowAfterButton.get())) { + return NS_ERROR_FAILURE; } -#endif - SetAnonymousElementPosition(xCell-7, yVert+6, mAddRowAfterButton); return NS_OK; } diff --git a/editor/nsIHTMLInlineTableEditor.idl b/editor/nsIHTMLInlineTableEditor.idl index b33570155b5f..c27290249b0c 100644 --- a/editor/nsIHTMLInlineTableEditor.idl +++ b/editor/nsIHTMLInlineTableEditor.idl @@ -19,7 +19,11 @@ interface nsIHTMLInlineTableEditor : nsISupports attribute boolean inlineTableEditingEnabled; /** - * Refresh already visible inline table editing UI + * Refresh already visible inline table editing UI. + * If inline table editing UI is not visible, this does nothing. + * If the set of inline table editing UI is hidden or replaced with new + * one while this is called, this throws an exception. + * FYI: Current user in script is only BlueGriffon. */ void refreshInlineTableEditingUI(); }; From 9d3272d9a514a194f14b27d9fe6e10b9027d2c3e Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Tue, 11 Sep 2018 03:02:50 +0000 Subject: [PATCH 11/20] Bug 1489402 - Middle-clicking a link from the address bar dropdown may apply the wrong overflow effect on the URL. r=adw Differential Revision: https://phabricator.services.mozilla.com/D5444 --HG-- extra : moz-landing-system : lando --- browser/base/content/urlbarBindings.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/browser/base/content/urlbarBindings.xml b/browser/base/content/urlbarBindings.xml index 1fdb5b7c4cbf..53fcdb907c61 100644 --- a/browser/base/content/urlbarBindings.xml +++ b/browser/base/content/urlbarBindings.xml @@ -1114,10 +1114,8 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/. } } - if (openUILinkWhere == "current") { - // Ensure the start of the URL is visible for usability reasons. - this.selectionStart = this.selectionEnd = 0; - } + // Ensure the start of the URL is visible for usability reasons. + this.selectionStart = this.selectionEnd = 0; ]]> From facbfce0780b4f714c6941b36d9a39bac2783507 Mon Sep 17 00:00:00 2001 From: James Graham Date: Tue, 11 Sep 2018 12:46:55 +0000 Subject: [PATCH 12/20] Bug 1490272 - Use the marionette reftest implemenation on Windows r=ato Differential Revision: https://phabricator.services.mozilla.com/D5519 --HG-- extra : moz-landing-system : lando --- .../tests/tools/wptrunner/wptrunner/wptcommandline.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptcommandline.py b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptcommandline.py index ba21ae6fe736..54f8dcdc67d2 100644 --- a/testing/web-platform/tests/tools/wptrunner/wptrunner/wptcommandline.py +++ b/testing/web-platform/tests/tools/wptrunner/wptrunner/wptcommandline.py @@ -498,10 +498,6 @@ def check_args(kwargs): kwargs['extra_prefs'] = [tuple(prefarg.split('=', 1)) for prefarg in kwargs['extra_prefs']] - if kwargs["reftest_internal"] is None: - # Default to the internal reftest implementation on Linux and OSX - kwargs["reftest_internal"] = sys.platform.startswith("linux") or sys.platform.startswith("darwin") - return kwargs From d3a1e8ea56015bb4ddb72724705e14b8b17d7b75 Mon Sep 17 00:00:00 2001 From: Jason Orendorff Date: Tue, 11 Sep 2018 13:00:52 +0000 Subject: [PATCH 13/20] Bug 1488417 - Even better error message on property access on undefined/null variable. r=jwalden Differential Revision: https://phabricator.services.mozilla.com/D5197 --HG-- extra : moz-landing-system : lando --- .../mochitest/browserElement_ExecuteScript.js | 2 +- js/src/jit-test/tests/basic/bug827104.js | 2 +- .../tests/basic/expression-autopsy.js | 4 +-- .../tests/basic/iterable-error-messages.js | 6 ++-- js/src/jit-test/tests/basic/testBug604210.js | 2 +- js/src/jit-test/tests/debug/bug1275001.js | 4 +-- js/src/jit-test/tests/ion/bug913749.js | 2 +- js/src/js.msg | 26 ++++++++------- js/src/jsapi-tests/testErrorInterceptor.cpp | 32 +++++++++---------- .../tests/non262/extensions/regress-353116.js | 4 +-- .../tests/non262/regress/regress-469625-03.js | 2 +- js/src/tests/non262/regress/regress-469758.js | 2 +- js/src/vm/JSContext.cpp | 14 ++++---- .../test_ext_contentscript_create_iframe.js | 2 +- 14 files changed, 54 insertions(+), 50 deletions(-) diff --git a/dom/browser-element/mochitest/browserElement_ExecuteScript.js b/dom/browser-element/mochitest/browserElement_ExecuteScript.js index 334a4f8791cd..3b217816b5df 100644 --- a/dom/browser-element/mochitest/browserElement_ExecuteScript.js +++ b/dom/browser-element/mochitest/browserElement_ExecuteScript.js @@ -91,7 +91,7 @@ function runTest() { ok(c(rv, 'YQ=='), `scriptId: ${scriptId++}`); return iframe.executeScript('window.wrappedJSObject.btoa("a")', {url}) }, bail).then(bail, (error) => { - is(error.message, `TypeError: window.wrappedJSObject is undefined, can't access property "btoa" of it`, `scriptId: ${scriptId++}`); + is(error.message, `TypeError: window.wrappedJSObject is undefined, can't access its "btoa" property`, `scriptId: ${scriptId++}`); return iframe.executeScript('42', {}) }).then(bail, error => { is(error.name, 'InvalidAccessError', `scriptId: ${scriptId++}`); diff --git a/js/src/jit-test/tests/basic/bug827104.js b/js/src/jit-test/tests/basic/bug827104.js index 343fcebcd596..a506f5ff7412 100644 --- a/js/src/jit-test/tests/basic/bug827104.js +++ b/js/src/jit-test/tests/basic/bug827104.js @@ -10,4 +10,4 @@ var e; try { f(); } catch (error) {e = error;} -assertEq(e.toString(), `TypeError: a[i] is undefined, can't access property 0 of it`); +assertEq(e.toString(), `TypeError: a[i] is undefined; can't access element at index 0`); diff --git a/js/src/jit-test/tests/basic/expression-autopsy.js b/js/src/jit-test/tests/basic/expression-autopsy.js index c3a145827ff1..06a7e0c3bc33 100644 --- a/js/src/jit-test/tests/basic/expression-autopsy.js +++ b/js/src/jit-test/tests/basic/expression-autopsy.js @@ -18,7 +18,7 @@ function check_one(expected, f, err) { ieval = eval; function check(expr, expected=expr, testStrict=true) { var end, err; - for ([end, err] of [[".random_prop", ` is undefined, can't access property \"random_prop" of it`], ["()", " is not a function"]]) { + for ([end, err] of [[".random_prop", ` is undefined; can't access its "random_prop" property`], ["()", " is not a function"]]) { var statement = "o = {};" + expr + end, f; var cases = [ // Global scope @@ -102,7 +102,7 @@ check_one("6", (function () { 6() }), " is not a function"); check_one("4", (function() { (4||eval)(); }), " is not a function"); check_one("0", (function () { Array.prototype.reverse.call('123'); }), " is read-only"); check_one("[...][Symbol.iterator](...).next(...).value", - function () { ieval("{ let x; var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined, can't access property Symbol.iterator of it"); + function () { ieval("{ let x; var [a, b, [c0, c1]] = [x, x, x]; }") }, " is undefined; can't access its Symbol.iterator property"); check_one("(void 1)", function() { (void 1)(); }, " is not a function"); check_one("(void o[1])", function() { var o = []; (void o[1])() }, " is not a function"); diff --git a/js/src/jit-test/tests/basic/iterable-error-messages.js b/js/src/jit-test/tests/basic/iterable-error-messages.js index d783d15900c3..b32b27e9c9b2 100644 --- a/js/src/jit-test/tests/basic/iterable-error-messages.js +++ b/js/src/jit-test/tests/basic/iterable-error-messages.js @@ -15,7 +15,7 @@ function testForOf(val) { for (v of [{}, Math, new Proxy({}, {})]) { assertThrowsMsg(() => testForOf(v), "val is not iterable"); } -assertThrowsMsg(() => testForOf(null), "val is null, can't access property Symbol.iterator of it"); +assertThrowsMsg(() => testForOf(null), "val is null; can't access its Symbol.iterator property"); assertThrowsMsg(() => { for (var x of () => 1) {}}, "() => 1 is not iterable"); // Destructuring @@ -25,7 +25,7 @@ function testDestr(val) { for (v of [{}, Math, new Proxy({}, {})]) { assertThrowsMsg(() => testDestr(v), "val is not iterable"); } -assertThrowsMsg(() => testDestr(null), "val is null, can't access property Symbol.iterator of it"); +assertThrowsMsg(() => testDestr(null), "val is null; can't access its Symbol.iterator property"); assertThrowsMsg(() => { [a, b] = () => 1; }, "() => 1 is not iterable"); // Spread @@ -35,5 +35,5 @@ function testSpread(val) { for (v of [{}, Math, new Proxy({}, {})]) { assertThrowsMsg(() => testSpread(v), "val is not iterable"); } -assertThrowsMsg(() => testSpread(null), "val is null, can't access property Symbol.iterator of it"); +assertThrowsMsg(() => testSpread(null), "val is null; can't access its Symbol.iterator property"); assertThrowsMsg(() => { [...() => 1]; }, "() => 1 is not iterable"); diff --git a/js/src/jit-test/tests/basic/testBug604210.js b/js/src/jit-test/tests/basic/testBug604210.js index bb96e7c4963f..f4119f016947 100644 --- a/js/src/jit-test/tests/basic/testBug604210.js +++ b/js/src/jit-test/tests/basic/testBug604210.js @@ -6,6 +6,6 @@ function f() { } catch (e) { msg = '' + e; } - assertEq(msg, `TypeError: x is undefined, can't access property "foo" of it`); + assertEq(msg, `TypeError: x is undefined; can't access its "foo" property`); } f(); diff --git a/js/src/jit-test/tests/debug/bug1275001.js b/js/src/jit-test/tests/debug/bug1275001.js index 868a7bda2cf5..84d5a7013db1 100644 --- a/js/src/jit-test/tests/debug/bug1275001.js +++ b/js/src/jit-test/tests/debug/bug1275001.js @@ -17,13 +17,13 @@ function check_one(expected, f, err) { ieval = eval function check(expr, expected = expr) { var end, err - for ([end, err] of[[".random_prop", ` is undefined, can't access property \"random_prop" of it` ]]) + for ([end, err] of [[".random_prop", ` is undefined, can't access its "random_prop" property`]]) statement = "o = {};" + expr + end; cases = [ function() { return ieval("var undef;" + statement); }, Function(statement) ] - for (f of cases) + for (f of cases) check_one(expected, f, err) } check("undef"); diff --git a/js/src/jit-test/tests/ion/bug913749.js b/js/src/jit-test/tests/ion/bug913749.js index bece1e07d37c..068086e362d4 100644 --- a/js/src/jit-test/tests/ion/bug913749.js +++ b/js/src/jit-test/tests/ion/bug913749.js @@ -15,7 +15,7 @@ for (var i = 0; i < 3; i++) { x.toString(); assertEq(0, 1); } catch (e) { - assertEq(e.message === `y is undefined, can't access property "length" of it` || + assertEq(e.message === `y is undefined; can't access its "length" property` || e.message === "undefined has no properties", true); } } diff --git a/js/src/js.msg b/js/src/js.msg index 92e5d4d0d9f7..2158cc6f7662 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -9,21 +9,22 @@ * * The format for each JS error message is: * - * MSG_DEF(, , , - * ) + * MSG_DEF(, , , + * ) * - * where ; - * is a legal C identifer that will be used in the - * JS engine source. + * where: * - * is an integer literal specifying the total number of - * replaceable arguments in the following format string. + * is a legal C identifer that will be used in the + * JS engine source. * - * is an enum JSExnType value, defined in jsapi.h. + * is an integer literal specifying the total number of + * replaceable arguments in the following format string. * - * is a string literal, optionally containing sequences - * {X} where X is an integer representing the argument number that will - * be replaced with a string value when the error is reported. + * is an enum JSExnType value, defined in jsapi.h. + * + * is a string literal, optionally containing sequences + * {X} where X is an integer representing the argument number that will + * be replaced with a string value when the error is reported. * * e.g. * @@ -55,7 +56,8 @@ MSG_DEF(JSMSG_TOPRIMITIVE_NOT_CALLABLE, 2, JSEXN_TYPEERR, "can't convert {0} to MSG_DEF(JSMSG_TOPRIMITIVE_RETURNED_OBJECT, 2, JSEXN_TYPEERR, "can't convert {0} to {1}: its [Symbol.toPrimitive] method returned an object") MSG_DEF(JSMSG_NO_PROPERTIES, 1, JSEXN_TYPEERR, "{0} has no properties") MSG_DEF(JSMSG_PROPERTY_FAIL, 2, JSEXN_TYPEERR, "can't access property {0} of {1}") -MSG_DEF(JSMSG_PROPERTY_FAIL_EXPR, 3, JSEXN_TYPEERR, "{0} is {1}, can't access property {2} of it") +MSG_DEF(JSMSG_PROPERTY_FAIL_EXPR, 3, JSEXN_TYPEERR, "{0} is {1}; can't access its {2} property") +MSG_DEF(JSMSG_ELEMENT_FAIL_EXPR, 3, JSEXN_TYPEERR, "{0} is {1}; can't access element at index {2}") MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}") MSG_DEF(JSMSG_INVALID_DATA_VIEW_LENGTH, 0, JSEXN_RANGEERR, "invalid data view length") MSG_DEF(JSMSG_OFFSET_LARGER_THAN_FILESIZE, 0, JSEXN_RANGEERR, "offset is larger than filesize") diff --git a/js/src/jsapi-tests/testErrorInterceptor.cpp b/js/src/jsapi-tests/testErrorInterceptor.cpp index ab88abdfa233..e347a226e636 100644 --- a/js/src/jsapi-tests/testErrorInterceptor.cpp +++ b/js/src/jsapi-tests/testErrorInterceptor.cpp @@ -34,25 +34,25 @@ BEGIN_TEST(testErrorInterceptor) { // Run the following snippets. const char* SAMPLES[] = { - "throw new Error('I am an Error')\0", - "throw new TypeError('I am a TypeError')\0", - "throw new ReferenceError('I am a ReferenceError')\0", - "throw new SyntaxError('I am a SyntaxError')\0", - "throw 5\0", - "undefined[0]\0", - "foo[0]\0", - "b[\0", + "throw new Error('I am an Error')", + "throw new TypeError('I am a TypeError')", + "throw new ReferenceError('I am a ReferenceError')", + "throw new SyntaxError('I am a SyntaxError')", + "throw 5", + "undefined[0]", + "foo[0]", + "b[", }; // With the simpleInterceptor, we should end up with the following error: const char* TO_STRING[] = { - "Error: I am an Error\0", - "TypeError: I am a TypeError\0", - "ReferenceError: I am a ReferenceError\0", - "SyntaxError: I am a SyntaxError\0", - "5\0", - "TypeError: can't access property 0 of undefined\0", - "ReferenceError: foo is not defined\0", - "SyntaxError: expected expression, got end of script\0", + "Error: I am an Error", + "TypeError: I am a TypeError", + "ReferenceError: I am a ReferenceError", + "SyntaxError: I am a SyntaxError", + "5", + "TypeError: can't access property 0 of undefined", + "ReferenceError: foo is not defined", + "SyntaxError: expected expression, got end of script", }; MOZ_ASSERT(mozilla::ArrayLength(SAMPLES) == mozilla::ArrayLength(TO_STRING)); diff --git a/js/src/tests/non262/extensions/regress-353116.js b/js/src/tests/non262/extensions/regress-353116.js index 0ec70e977b78..2debc2604587 100644 --- a/js/src/tests/non262/extensions/regress-353116.js +++ b/js/src/tests/non262/extensions/regress-353116.js @@ -45,7 +45,7 @@ function test() } reportCompare(expect, actual, summary); - expect = `TypeError: x is undefined, can't access property "y" of it`; + expect = `TypeError: x is undefined; can't access its "y" property`; actual = 'No Error'; try @@ -59,7 +59,7 @@ function test() } reportCompare(expect, actual, summary); - expect = `TypeError: x is null, can't access property "y" of it`; + expect = `TypeError: x is null; can't access its "y" property`; actual = 'No Error'; try diff --git a/js/src/tests/non262/regress/regress-469625-03.js b/js/src/tests/non262/regress/regress-469625-03.js index a210b0625b11..f814ef0b8bc5 100644 --- a/js/src/tests/non262/regress/regress-469625-03.js +++ b/js/src/tests/non262/regress/regress-469625-03.js @@ -25,7 +25,7 @@ function test() var [a, b, [c0, c1]] = [x, x, x]; } - expect = `TypeError: [...][Symbol.iterator](...).next(...).value is null, can't access property Symbol.iterator of it`; + expect = `TypeError: [...][Symbol.iterator](...).next(...).value is null; can't access its Symbol.iterator property`; actual = 'No Error'; try { diff --git a/js/src/tests/non262/regress/regress-469758.js b/js/src/tests/non262/regress/regress-469758.js index 9fe08149d781..2cc892e74478 100644 --- a/js/src/tests/non262/regress/regress-469758.js +++ b/js/src/tests/non262/regress/regress-469758.js @@ -9,6 +9,6 @@ try { err = e; } assertEq(err instanceof TypeError, true); -assertEq(err.message, "[][j] is undefined, can't access property 2 of it"); +assertEq(err.message, "[][j] is undefined; can't access element at index 2"); reportCompare(0, 0, 'ok'); diff --git a/js/src/vm/JSContext.cpp b/js/src/vm/JSContext.cpp index d3a37f1a4373..f32d43eb0c72 100644 --- a/js/src/vm/JSContext.cpp +++ b/js/src/vm/JSContext.cpp @@ -953,13 +953,15 @@ js::ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx, HandleValue v, Handl if (strcmp(bytes.get(), js_undefined_str) == 0 || strcmp(bytes.get(), js_null_str) == 0) { JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL, keyBytes.get(), bytes.get()); - } else if (v.isUndefined()) { - JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL_EXPR, - bytes.get(), js_undefined_str, keyBytes.get()); } else { - MOZ_ASSERT(v.isNull()); - JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL_EXPR, - bytes.get(), js_null_str, keyBytes.get()); + const char* actual = v.isUndefined() ? js_undefined_str : js_null_str; + if (JSID_IS_INT(key)) { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_ELEMENT_FAIL_EXPR, + bytes.get(), actual, keyBytes.get()); + } else { + JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_PROPERTY_FAIL_EXPR, + bytes.get(), actual, keyBytes.get()); + } } } diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_create_iframe.js b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_create_iframe.js index bd53c5e8896c..c4593d105140 100644 --- a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_create_iframe.js +++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_create_iframe.js @@ -125,7 +125,7 @@ add_task(async function test_contentscript_create_iframe() { Assert.ok(!manifest, "manifest should be undefined"); Assert.equal(String(manifestException), - `TypeError: win.browser.runtime is undefined, can't access property "getManifest" of it`, + `TypeError: win.browser.runtime is undefined, can't access its "getManifest" property`, "expected exception received"); let getManifestException = win.testGetManifestException(); From f26bf4140b6c0f89b2241a39c2c26f579b27d6c4 Mon Sep 17 00:00:00 2001 From: Jan Odvarko Date: Mon, 10 Sep 2018 17:14:57 +0000 Subject: [PATCH 14/20] Bug 1488915 - Migrate toolbox-process-window.xul to HTML; r=bgrins Differential Revision: https://phabricator.services.mozilla.com/D5255 --HG-- rename : devtools/client/framework/toolbox-process-window.xul => devtools/client/framework/toolbox-process-window.html extra : moz-landing-system : lando --- devtools/client/framework/ToolboxProcess.jsm | 2 +- .../framework/toolbox-process-window.css | 47 ++++++++++++++++++ .../framework/toolbox-process-window.html | 26 ++++++++++ .../framework/toolbox-process-window.js | 29 +++++++---- .../framework/toolbox-process-window.xul | 49 ------------------- devtools/client/jar.mn | 3 +- devtools/client/locales/en-US/toolbox.dtd | 5 -- .../client/locales/en-US/toolbox.properties | 5 ++ devtools/client/webconsole/webconsole.js | 17 ------- 9 files changed, 101 insertions(+), 82 deletions(-) create mode 100644 devtools/client/framework/toolbox-process-window.css create mode 100644 devtools/client/framework/toolbox-process-window.html delete mode 100644 devtools/client/framework/toolbox-process-window.xul diff --git a/devtools/client/framework/ToolboxProcess.jsm b/devtools/client/framework/ToolboxProcess.jsm index a2975c101642..bb1eec8ae994 100644 --- a/devtools/client/framework/ToolboxProcess.jsm +++ b/devtools/client/framework/ToolboxProcess.jsm @@ -6,7 +6,7 @@ "use strict"; -const DBG_XUL = "chrome://devtools/content/framework/toolbox-process-window.xul"; +const DBG_XUL = "chrome://devtools/content/framework/toolbox-process-window.html"; const CHROME_DEBUGGER_PROFILE_NAME = "chrome_debugger_profile"; const { require, DevToolsLoader } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {}); diff --git a/devtools/client/framework/toolbox-process-window.css b/devtools/client/framework/toolbox-process-window.css new file mode 100644 index 000000000000..f0efd80733cb --- /dev/null +++ b/devtools/client/framework/toolbox-process-window.css @@ -0,0 +1,47 @@ +/* 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/. */ + +body { + padding: 0; + margin: 0; + display: flex; + height: 100vh; +} + +/** + * The main content of the BrowserToolbox runs within an iframe. + */ +#toolbox-iframe { + border: 0; + width: 100%; + flex: 1; +} + +/** + * Status message shows connection (to the backend) info messages. + */ +#status-message-container { + width: calc(100% - 10px); + font-family: var(--monospace-font-family); + padding: 5px; +} + +/** + * Helper for hiding/showing the status message. + */ +#status-message-container[hidden="true"] { + display: none; +} + +#status-message-title { + font-size: 14px; + font-weight: bold; +} + +#status-message { + font-size: 12px; + width: 100%; + height: 200px; + overflow: auto; +} diff --git a/devtools/client/framework/toolbox-process-window.html b/devtools/client/framework/toolbox-process-window.html new file mode 100644 index 000000000000..908944d777a5 --- /dev/null +++ b/devtools/client/framework/toolbox-process-window.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/devtools/client/framework/toolbox-process-window.js b/devtools/client/framework/toolbox-process-window.js index b04b054f6902..c3a3acdb20df 100644 --- a/devtools/client/framework/toolbox-process-window.js +++ b/devtools/client/framework/toolbox-process-window.js @@ -7,6 +7,7 @@ "use strict"; var { loader, require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {}); + // Require this module to setup core modules loader.require("devtools/client/framework/devtools-browser"); @@ -16,6 +17,9 @@ var { Toolbox } = require("devtools/client/framework/toolbox"); var Services = require("Services"); var { DebuggerClient } = require("devtools/shared/client/debugger-client"); var { PrefsHelper } = require("devtools/client/shared/prefs"); +const KeyShortcuts = require("devtools/client/shared/key-shortcuts"); +const { LocalizationHelper } = require("devtools/shared/l10n"); +const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties"); // Timeout to wait before we assume that a connect() timed out without an error. // In milliseconds. (With the Debugger pane open, this has been reported to last @@ -30,19 +34,23 @@ var Prefs = new PrefsHelper("devtools.debugger", { chromeDebuggingWebSocket: ["Bool", "chrome-debugging-websocket"], }); -var gToolbox, gClient; +var gToolbox, gClient, gShortcuts; function appendStatusMessage(msg) { const statusMessage = document.getElementById("status-message"); - statusMessage.value += msg + "\n"; + statusMessage.textContent += msg + "\n"; if (msg.stack) { - statusMessage.value += msg.stack + "\n"; + statusMessage.textContent += msg.stack + "\n"; } } function toggleStatusMessage(visible = true) { const statusMessageContainer = document.getElementById("status-message-container"); - statusMessageContainer.hidden = !visible; + if (visible) { + statusMessageContainer.removeAttribute("hidden"); + } else { + statusMessageContainer.setAttribute("hidden", "true"); + } } function revealStatusMessage() { @@ -62,7 +70,7 @@ var connect = async function() { // A port needs to be passed in from the environment, for instance: // MOZ_BROWSER_TOOLBOX_PORT=6080 ./mach run -chrome \ - // chrome://devtools/content/framework/toolbox-process-window.xul + // chrome://devtools/content/framework/toolbox-process-window.html if (!port) { throw new Error("Must pass a port in an env variable with MOZ_BROWSER_TOOLBOX_PORT"); } @@ -108,9 +116,14 @@ function setPrefDefaults() { } window.addEventListener("load", async function() { - const cmdClose = document.getElementById("toolbox-cmd-close"); - cmdClose.addEventListener("command", onCloseCommand); + gShortcuts = new KeyShortcuts({window}); + gShortcuts.on("CmdOrCtrl+W", onCloseCommand); + + const statusMessageContainer = document.getElementById("status-message-title"); + statusMessageContainer.textContent = L10N.getStr("browserToolbox.statusMessage"); + setPrefDefaults(); + // Reveal status message if connecting is slow or if an error occurs. const delayedStatusReveal = setTimeout(revealStatusMessage, STATUS_REVEAL_TIME); try { @@ -222,8 +235,6 @@ function updateBadgeText(paused) { function onUnload() { window.removeEventListener("unload", onUnload); window.removeEventListener("message", onMessage); - const cmdClose = document.getElementById("toolbox-cmd-close"); - cmdClose.removeEventListener("command", onCloseCommand); gToolbox.destroy(); } diff --git a/devtools/client/framework/toolbox-process-window.xul b/devtools/client/framework/toolbox-process-window.xul deleted file mode 100644 index 73e05939d8f0..000000000000 --- a/devtools/client/framework/toolbox-process-window.xul +++ /dev/null @@ -1,49 +0,0 @@ - - - - %toolboxDTD; -]> - - - - - - -