diff --git a/accessible/src/atk/AccessibleWrap.cpp b/accessible/src/atk/AccessibleWrap.cpp index fef2bae5b7e..5f98faac2cc 100644 --- a/accessible/src/atk/AccessibleWrap.cpp +++ b/accessible/src/atk/AccessibleWrap.cpp @@ -691,6 +691,8 @@ getRoleCB(AtkObject *aAtkObj) if (aAtkObj->role == ATK_ROLE_LIST_BOX && !IsAtkVersionAtLeast(2, 1)) aAtkObj->role = ATK_ROLE_LIST; + else if (aAtkObj->role == ATK_ROLE_TABLE_ROW && !IsAtkVersionAtLeast(2, 1)) + aAtkObj->role = ATK_ROLE_LIST_ITEM; return aAtkObj->role; } diff --git a/accessible/src/atk/nsMai.h b/accessible/src/atk/nsMai.h index 903d4229f4f..5de552ac67a 100644 --- a/accessible/src/atk/nsMai.h +++ b/accessible/src/atk/nsMai.h @@ -39,7 +39,8 @@ extern int atkMajorVersion, atkMinorVersion; static inline bool IsAtkVersionAtLeast(int aMajor, int aMinor) { - return aMajor < atkMajorVersion && aMinor < atkMinorVersion; + return aMajor < atkMajorVersion || + (aMajor == atkMajorVersion && aMinor <= atkMinorVersion); } #endif /* __NS_MAI_H__ */ diff --git a/accessible/src/base/RoleMap.h b/accessible/src/base/RoleMap.h index 7b770610339..70a3721b1f6 100644 --- a/accessible/src/base/RoleMap.h +++ b/accessible/src/base/RoleMap.h @@ -242,7 +242,7 @@ ROLE(COLUMN, ROLE(ROW, "row", - ATK_ROLE_LIST_ITEM, + ATK_ROLE_TABLE_ROW, NSAccessibilityRowRole, ROLE_SYSTEM_ROW, ROLE_SYSTEM_ROW, diff --git a/build/autoconf/icu.m4 b/build/autoconf/icu.m4 index 1bc69c240b4..320e4b388f8 100644 --- a/build/autoconf/icu.m4 +++ b/build/autoconf/icu.m4 @@ -168,7 +168,7 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then WINNT) ICU_TARGET=MSYS/MSVC ;; - *bsd*|dragonfly*) + DragonFly|FreeBSD|NetBSD|OpenBSD|GNU_kFreeBSD) ICU_TARGET=BSD ;; esac diff --git a/configure.in b/configure.in index 34d38afe12a..91b1493b3d7 100644 --- a/configure.in +++ b/configure.in @@ -1023,6 +1023,24 @@ darwin*) linux*) HOST_OS_ARCH=Linux ;; +kfreebsd*-gnu) + HOST_OS_ARCH=GNU_kFreeBSD + ;; +gnu*) + HOST_OS_ARCH=GNU + ;; +dragonfly*) + HOST_OS_ARCH=DragonFly + ;; +freebsd*) + HOST_OS_ARCH=FreeBSD + ;; +netbsd*) + HOST_OS_ARCH=NetBSD + ;; +openbsd*) + HOST_OS_ARCH=OpenBSD + ;; solaris*) HOST_OS_ARCH=SunOS SOLARIS_SUNPRO_CC= diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 18cc7120352..a98441a1486 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -457,7 +457,7 @@ nsFrameMessageManager::GetDelayedFrameScripts(JSContext* aCx, JS::MutableHandle< return NS_ERROR_NOT_IMPLEMENTED; } - JS::Rooted array(aCx, JS_NewArrayObject(aCx, mPendingScripts.Length(), nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, mPendingScripts.Length())); NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY); JS::Rooted url(aCx); @@ -466,10 +466,11 @@ nsFrameMessageManager::GetDelayedFrameScripts(JSContext* aCx, JS::MutableHandle< url = JS_NewUCStringCopyN(aCx, mPendingScripts[i].get(), mPendingScripts[i].Length()); NS_ENSURE_TRUE(url, NS_ERROR_OUT_OF_MEMORY); - JS::Value pairElts[] = { JS::StringValue(url), - JS::BooleanValue(mPendingScriptsGlobalStates[i]) }; + JS::AutoValueArray<2> pairElts(aCx); + pairElts[0].setString(url); + pairElts[1].setBoolean(mPendingScriptsGlobalStates[i]); - pair = JS_NewArrayObject(aCx, 2, pairElts); + pair = JS_NewArrayObject(aCx, pairElts); NS_ENSURE_TRUE(pair, NS_ERROR_OUT_OF_MEMORY); NS_ENSURE_TRUE(JS_SetElement(aCx, array, i, pair), @@ -598,7 +599,7 @@ nsFrameMessageManager::SendMessage(const nsAString& aMessageName, } uint32_t len = retval.Length(); - JS::Rooted dataArray(aCx, JS_NewArrayObject(aCx, len, nullptr)); + JS::Rooted dataArray(aCx, JS_NewArrayObject(aCx, len)); NS_ENSURE_TRUE(dataArray, NS_ERROR_OUT_OF_MEMORY); for (uint32_t i = 0; i < len; ++i) { diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index 084c86ccdb6..82c8dc52c56 100644 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -1245,14 +1245,13 @@ CanvasRenderingContext2D::SetTransform(double m11, double m12, JSObject* MatrixToJSObject(JSContext* cx, const Matrix& matrix, ErrorResult& error) { - JS::Value elts[] = { - DOUBLE_TO_JSVAL(matrix._11), DOUBLE_TO_JSVAL(matrix._12), - DOUBLE_TO_JSVAL(matrix._21), DOUBLE_TO_JSVAL(matrix._22), - DOUBLE_TO_JSVAL(matrix._31), DOUBLE_TO_JSVAL(matrix._32) - }; + JS::AutoValueArray<6> elts(cx); + elts[0].setDouble(matrix._11); elts[1].setDouble(matrix._12); + elts[2].setDouble(matrix._21); elts[3].setDouble(matrix._22); + elts[4].setDouble(matrix._31); elts[5].setDouble(matrix._32); // XXX Should we enter GetWrapper()'s compartment? - JSObject* obj = JS_NewArrayObject(cx, 6, elts); + JSObject* obj = JS_NewArrayObject(cx, elts); if (!obj) { error.Throw(NS_ERROR_OUT_OF_MEMORY); } diff --git a/content/canvas/src/CanvasUtils.h b/content/canvas/src/CanvasUtils.h index 68487aeae9e..86387f418a1 100644 --- a/content/canvas/src/CanvasUtils.h +++ b/content/canvas/src/CanvasUtils.h @@ -158,7 +158,7 @@ DashArrayToJSVal(FallibleTArray& dashes, return JSVAL_NULL; } JS::Rooted obj(cx, - JS_NewArrayObject(cx, dashes.Length(), nullptr)); + JS_NewArrayObject(cx, dashes.Length())); if (!obj) { rv.Throw(NS_ERROR_OUT_OF_MEMORY); return JSVAL_NULL; diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index bf85c7b5a9d..19369d8b7e4 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -1907,10 +1907,10 @@ WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog, if (unitSize == 1) { return JS::BooleanValue(iv[0] ? true : false); } else { - JS::Value uv[16]; + JS::AutoValueArray<16> uv(cx); for (int k = 0; k < unitSize; k++) - uv[k] = JS::BooleanValue(iv[k] ? true : false); - JSObject* obj = JS_NewArrayObject(cx, unitSize, uv); + uv[k].setBoolean(iv[k]); + JSObject* obj = JS_NewArrayObject(cx, JS::HandleValueArray::subarray(uv, 0, unitSize)); if (!obj) { ErrorOutOfMemory("getUniform: out of memory"); return JS::NullValue(); diff --git a/content/canvas/src/WebGLContextState.cpp b/content/canvas/src/WebGLContextState.cpp index 96ec28f8157..88a7050c7ef 100644 --- a/content/canvas/src/WebGLContextState.cpp +++ b/content/canvas/src/WebGLContextState.cpp @@ -423,11 +423,12 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) { realGLboolean gl_bv[4] = { 0 }; gl->fGetBooleanv(pname, gl_bv); - JS::Value vals[4] = { JS::BooleanValue(bool(gl_bv[0])), - JS::BooleanValue(bool(gl_bv[1])), - JS::BooleanValue(bool(gl_bv[2])), - JS::BooleanValue(bool(gl_bv[3])) }; - JSObject* obj = JS_NewArrayObject(cx, 4, vals); + JS::AutoValueArray<4> vals(cx); + vals[0].setBoolean(gl_bv[0]); + vals[1].setBoolean(gl_bv[1]); + vals[2].setBoolean(gl_bv[2]); + vals[3].setBoolean(gl_bv[3]); + JSObject* obj = JS_NewArrayObject(cx, vals); if (!obj) { rv = NS_ERROR_OUT_OF_MEMORY; } diff --git a/content/media/directshow/AudioSinkInputPin.cpp b/content/media/directshow/AudioSinkInputPin.cpp index 88d417fc302..03f4b63b8e8 100644 --- a/content/media/directshow/AudioSinkInputPin.cpp +++ b/content/media/directshow/AudioSinkInputPin.cpp @@ -9,7 +9,6 @@ #include "SampleSink.h" #include "prlog.h" -#include #include using namespace mozilla::media; diff --git a/content/media/directshow/moz.build b/content/media/directshow/moz.build index 5119f58f7db..760f5b521a8 100644 --- a/content/media/directshow/moz.build +++ b/content/media/directshow/moz.build @@ -13,7 +13,6 @@ EXPORTS += [ ] UNIFIED_SOURCES += [ - 'AudioSinkFilter.cpp', 'AudioSinkInputPin.cpp', 'DirectShowDecoder.cpp', 'DirectShowReader.cpp', @@ -22,6 +21,10 @@ UNIFIED_SOURCES += [ 'SourceFilter.cpp', ] +SOURCES += [ + 'AudioSinkFilter.cpp', +] + # If WebRTC isn't being built, we need to compile the DirectShow base classes so that # they're available at link time. if not CONFIG['MOZ_WEBRTC']: diff --git a/content/media/wmf/WMF.h b/content/media/wmf/WMF.h index 886bf3c58dd..2a8d150a4d5 100644 --- a/content/media/wmf/WMF.h +++ b/content/media/wmf/WMF.h @@ -29,7 +29,6 @@ which makes Windows Media Foundation unavailable. #include #include #include -#include #include #include #include diff --git a/content/media/wmf/WMFUtils.cpp b/content/media/wmf/WMFUtils.cpp index 83f18b8cf50..57c6d563cd2 100644 --- a/content/media/wmf/WMFUtils.cpp +++ b/content/media/wmf/WMFUtils.cpp @@ -14,6 +14,7 @@ #include "nsWindowsHelpers.h" #include "mozilla/CheckedInt.h" #include "VideoUtils.h" +#include #ifdef WMF_MUST_DEFINE_AAC_MFT_CLSID // Some SDK versions don't define the AAC decoder CLSID. diff --git a/content/media/wmf/moz.build b/content/media/wmf/moz.build index ebdc76d0ccc..4e18744edac 100644 --- a/content/media/wmf/moz.build +++ b/content/media/wmf/moz.build @@ -18,6 +18,9 @@ UNIFIED_SOURCES += [ 'WMFDecoder.cpp', 'WMFReader.cpp', 'WMFSourceReaderCallback.cpp', +] + +SOURCES += [ 'WMFUtils.cpp', ] diff --git a/dom/base/MessagePort.cpp b/dom/base/MessagePort.cpp index 0a69933b30c..435569a6af9 100644 --- a/dom/base/MessagePort.cpp +++ b/dom/base/MessagePort.cpp @@ -372,9 +372,15 @@ MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, JS::Rooted transferable(aCx, JS::UndefinedValue()); if (aTransferable.WasPassed()) { const Sequence& realTransferable = aTransferable.Value(); + + // The input sequence only comes from the generated bindings code, which + // ensures it is rooted. + JS::HandleValueArray elements = + JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), + realTransferable.Elements()); + JSObject* array = - JS_NewArrayObject(aCx, realTransferable.Length(), - const_cast(realTransferable.Elements())); + JS_NewArrayObject(aCx, elements); if (!array) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index c1dc3af8dcd..3fc2b05f09d 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -7940,9 +7940,13 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, JS::Rooted transferArray(aCx, JS::UndefinedValue()); if (aTransfer.WasPassed()) { const Sequence& values = aTransfer.Value(); - transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, - values.Length(), - const_cast(values.Elements()))); + + // The input sequence only comes from the generated bindings code, which + // ensures it is rooted. + JS::HandleValueArray elements = + JS::HandleValueArray::fromMarkedLocation(values.Length(), values.Elements()); + + transferArray = JS::ObjectOrNullValue(JS_NewArrayObject(aCx, elements)); if (transferArray.isNull()) { aError.Throw(NS_ERROR_OUT_OF_MEMORY); return; diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index d2e86fe8a2a..095cc41cc47 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1169,7 +1169,7 @@ nsJSContext::SetProperty(JS::Handle aTarget, const char* aPropName, n } } - JSObject* array = ::JS_NewArrayObject(mContext, args.length(), args.begin()); + JSObject* array = ::JS_NewArrayObject(mContext, args); if (!array) { return NS_ERROR_FAILURE; } diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index a4d50e5f64f..f8e4937dbda 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -4428,7 +4428,7 @@ if (%s.IsNull()) { innerTemplate = CGIndenter(CGGeneric(innerTemplate), 6).define() return ((""" uint32_t length = %s.Length(); -JS::Rooted returnArray(cx, JS_NewArrayObject(cx, length, nullptr)); +JS::Rooted returnArray(cx, JS_NewArrayObject(cx, length)); if (!returnArray) { %s } diff --git a/dom/camera/CameraControlImpl.cpp b/dom/camera/CameraControlImpl.cpp index 054a5074dde..4a0294b561e 100644 --- a/dom/camera/CameraControlImpl.cpp +++ b/dom/camera/CameraControlImpl.cpp @@ -146,7 +146,7 @@ CameraControlImpl::Get(JSContext* aCx, uint32_t aKey, JS::Value* aValue) GetParameter(aKey, regionArray); - JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0, nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0)); if (!array) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/dom/camera/DOMCameraCapabilities.cpp b/dom/camera/DOMCameraCapabilities.cpp index b6cb01ab58b..34d2c4af7ff 100644 --- a/dom/camera/DOMCameraCapabilities.cpp +++ b/dom/camera/DOMCameraCapabilities.cpp @@ -121,7 +121,7 @@ DOMCameraCapabilities::ParameterListToNewArray(JSContext* aCx, return NS_OK; } - aArray.set(JS_NewArrayObject(aCx, 0, nullptr)); + aArray.set(JS_NewArrayObject(aCx, 0)); if (!aArray) { return NS_ERROR_OUT_OF_MEMORY; } @@ -378,7 +378,7 @@ DOMCameraCapabilities::GetVideoSizes(JSContext* cx, JS::MutableHandle return NS_OK; } - JS::Rooted array(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted array(cx, JS_NewArrayObject(cx, 0)); if (!array) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/dom/events/TextComposition.cpp b/dom/events/TextComposition.cpp index 77920d4ebee..dc19c28eb5b 100644 --- a/dom/events/TextComposition.cpp +++ b/dom/events/TextComposition.cpp @@ -9,6 +9,7 @@ #include "nsContentUtils.h" #include "nsEventDispatcher.h" #include "nsIContent.h" +#include "nsIEditor.h" #include "nsIMEStateManager.h" #include "nsIPresShell.h" #include "nsPresContext.h" @@ -27,7 +28,8 @@ TextComposition::TextComposition(nsPresContext* aPresContext, mPresContext(aPresContext), mNode(aNode), mNativeContext(aEvent->widget->GetInputContext().mNativeIMEContext), mCompositionStartOffset(0), mCompositionTargetOffset(0), - mIsSynthesizedForTests(aEvent->mFlags.mIsSynthesizedForTests) + mIsSynthesizedForTests(aEvent->mFlags.mIsSynthesizedForTests), + mIsComposing(false) { } @@ -49,6 +51,20 @@ TextComposition::DispatchEvent(WidgetGUIEvent* aEvent, nsEventDispatcher::Dispatch(mNode, mPresContext, aEvent, nullptr, aStatus, aCallBack); + // Emulate editor behavior of text event handler if no editor handles + // composition/text events. + if (aEvent->message == NS_TEXT_TEXT && !HasEditor()) { + EditorWillHandleTextEvent(aEvent->AsTextEvent()); + EditorDidHandleTextEvent(); + } + +#ifdef DEBUG + else if (aEvent->message == NS_COMPOSITION_END) { + MOZ_ASSERT(!mIsComposing, "Why is the editor still composing?"); + MOZ_ASSERT(!HasEditor(), "Why does the editor still keep to hold this?"); + } +#endif // #ifdef DEBUG + // Notify composition update to widget if possible NotityUpdateComposition(aEvent); } @@ -123,6 +139,53 @@ TextComposition::NotifyIME(widget::NotificationToIME aNotification) return nsIMEStateManager::NotifyIME(aNotification, mPresContext); } +void +TextComposition::EditorWillHandleTextEvent(const WidgetTextEvent* aTextEvent) +{ + mIsComposing = aTextEvent->IsComposing(); + + MOZ_ASSERT(mLastData == aTextEvent->theText, + "The text of a text event must be same as previous data attribute value " + "of the latest compositionupdate event"); +} + +void +TextComposition::EditorDidHandleTextEvent() +{ + mString = mLastData; +} + +void +TextComposition::StartHandlingComposition(nsIEditor* aEditor) +{ + MOZ_ASSERT(!HasEditor(), "There is a handling editor already"); + mEditorWeak = do_GetWeakReference(aEditor); +} + +void +TextComposition::EndHandlingComposition(nsIEditor* aEditor) +{ +#ifdef DEBUG + nsCOMPtr editor = GetEditor(); + MOZ_ASSERT(editor == aEditor, "Another editor handled the composition?"); +#endif // #ifdef DEBUG + mEditorWeak = nullptr; +} + +already_AddRefed +TextComposition::GetEditor() const +{ + nsCOMPtr editor = do_QueryReferent(mEditorWeak); + return editor.forget(); +} + +bool +TextComposition::HasEditor() const +{ + nsCOMPtr editor = GetEditor(); + return !!editor; +} + /****************************************************************************** * TextComposition::CompositionEventDispatcher ******************************************************************************/ diff --git a/dom/events/TextComposition.h b/dom/events/TextComposition.h index ccd42342fb2..6e3ef174076 100644 --- a/dom/events/TextComposition.h +++ b/dom/events/TextComposition.h @@ -9,6 +9,7 @@ #include "nsCOMPtr.h" #include "nsINode.h" +#include "nsIWeakReference.h" #include "nsIWidget.h" #include "nsTArray.h" #include "nsThreadUtils.h" @@ -17,8 +18,8 @@ #include "mozilla/EventForwards.h" class nsDispatchingCallback; +class nsIEditor; class nsIMEStateManager; -class nsIWidget; namespace mozilla { @@ -47,7 +48,14 @@ public: nsPresContext* GetPresContext() const { return mPresContext; } nsINode* GetEventTargetNode() const { return mNode; } // The latest CompositionEvent.data value except compositionstart event. - const nsString& GetLastData() const { return mLastData; } + // This value is modified at dispatching compositionupdate. + const nsString& LastData() const { return mLastData; } + // The composition string which is already handled by the focused editor. + // I.e., this value must be same as the composition string on the focused + // editor. This value is modified at a call of EditorDidHandleTextEvent(). + // Note that mString and mLastData are different between dispatcing + // compositionupdate and text event handled by focused editor. + const nsString& String() const { return mString; } // Returns true if the composition is started with synthesized event which // came from nsDOMWindowUtils. bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; } @@ -73,6 +81,45 @@ public: */ uint32_t OffsetOfTargetClause() const { return mCompositionTargetOffset; } + /** + * Returns true if there is non-empty composition string and it's not fixed. + * Otherwise, false. + */ + bool IsComposing() const { return mIsComposing; } + + /** + * StartHandlingComposition() and EndHandlingComposition() are called by + * editor when it holds a TextComposition instance and release it. + */ + void StartHandlingComposition(nsIEditor* aEditor); + void EndHandlingComposition(nsIEditor* aEditor); + + /** + * TextEventHandlingMarker class should be created at starting to handle text + * event in focused editor. This calls EditorWillHandleTextEvent() and + * EditorDidHandleTextEvent() automatically. + */ + class MOZ_STACK_CLASS TextEventHandlingMarker + { + public: + TextEventHandlingMarker(TextComposition* aComposition, + const WidgetTextEvent* aTextEvent) + : mComposition(aComposition) + { + mComposition->EditorWillHandleTextEvent(aTextEvent); + } + + ~TextEventHandlingMarker() + { + mComposition->EditorDidHandleTextEvent(); + } + + private: + nsRefPtr mComposition; + TextEventHandlingMarker(); + TextEventHandlingMarker(const TextEventHandlingMarker& aOther); + }; + private: // This class holds nsPresContext weak. This instance shouldn't block // destroying it. When the presContext is being destroyed, it's notified to @@ -85,10 +132,17 @@ private: // composition. Don't access the instance, it may not be available. void* mNativeContext; + // mEditorWeak is a weak reference to the focused editor handling composition. + nsWeakPtr mEditorWeak; + // mLastData stores the data attribute of the latest composition event (except // the compositionstart event). nsString mLastData; + // mString stores the composition text which has been handled by the focused + // editor. + nsString mString; + // Offset of the composition string from start of the editor uint32_t mCompositionStartOffset; // Offset of the selected clause of the composition string from start of the @@ -98,10 +152,35 @@ private: // See the comment for IsSynthesizedForTests(). bool mIsSynthesizedForTests; + // See the comment for IsComposing(). + bool mIsComposing; + // Hide the default constructor and copy constructor. TextComposition() {} TextComposition(const TextComposition& aOther); + /** + * GetEditor() returns nsIEditor pointer of mEditorWeak. + */ + already_AddRefed GetEditor() const; + + /** + * HasEditor() returns true if mEditorWeak holds nsIEditor instance which is + * alive. Otherwise, false. + */ + bool HasEditor() const; + + /** + * EditorWillHandleTextEvent() must be called before the focused editor + * handles the text event. + */ + void EditorWillHandleTextEvent(const WidgetTextEvent* aTextEvent); + + /** + * EditorDidHandleTextEvent() must be called after the focused editor handles + * a text event. + */ + void EditorDidHandleTextEvent(); /** * DispatchEvent() dispatches the aEvent to the mContent synchronously. diff --git a/dom/events/nsIMEStateManager.cpp b/dom/events/nsIMEStateManager.cpp index 5ee5267431d..41bb5ec8a6e 100644 --- a/dom/events/nsIMEStateManager.cpp +++ b/dom/events/nsIMEStateManager.cpp @@ -617,9 +617,9 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, case REQUEST_TO_COMMIT_COMPOSITION: { nsCOMPtr widget(aWidget); nsEventStatus status = nsEventStatus_eIgnore; - if (!composition->GetLastData().IsEmpty()) { + if (!composition->LastData().IsEmpty()) { WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget); - textEvent.theText = composition->GetLastData(); + textEvent.theText = composition->LastData(); textEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&textEvent, status); if (widget->Destroyed()) { @@ -629,7 +629,7 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, status = nsEventStatus_eIgnore; WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget); - endEvent.data = composition->GetLastData(); + endEvent.data = composition->LastData(); endEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&endEvent, status); @@ -638,9 +638,9 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, case REQUEST_TO_CANCEL_COMPOSITION: { nsCOMPtr widget(aWidget); nsEventStatus status = nsEventStatus_eIgnore; - if (!composition->GetLastData().IsEmpty()) { + if (!composition->LastData().IsEmpty()) { WidgetCompositionEvent updateEvent(true, NS_COMPOSITION_UPDATE, widget); - updateEvent.data = composition->GetLastData(); + updateEvent.data = composition->LastData(); updateEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&updateEvent, status); if (widget->Destroyed()) { @@ -649,7 +649,7 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, status = nsEventStatus_eIgnore; WidgetTextEvent textEvent(true, NS_TEXT_TEXT, widget); - textEvent.theText = composition->GetLastData(); + textEvent.theText = composition->LastData(); textEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&textEvent, status); if (widget->Destroyed()) { @@ -659,7 +659,7 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification, status = nsEventStatus_eIgnore; WidgetCompositionEvent endEvent(true, NS_COMPOSITION_END, widget); - endEvent.data = composition->GetLastData(); + endEvent.data = composition->LastData(); endEvent.mFlags.mIsSynthesizedForTests = true; widget->DispatchEvent(&endEvent, status); @@ -1126,9 +1126,23 @@ nsIMEStateManager::GetFocusSelectionAndRoot(nsISelection** aSel, return NS_OK; } -TextComposition* +// static +already_AddRefed nsIMEStateManager::GetTextCompositionFor(nsIWidget* aWidget) { - return sTextCompositions ? - sTextCompositions->GetCompositionFor(aWidget) : nullptr; + if (!sTextCompositions) { + return nullptr; + } + nsRefPtr textComposition = + sTextCompositions->GetCompositionFor(aWidget); + return textComposition.forget(); +} + +// static +already_AddRefed +nsIMEStateManager::GetTextCompositionFor(WidgetGUIEvent* aEvent) +{ + MOZ_ASSERT(aEvent->AsCompositionEvent() || aEvent->AsTextEvent(), + "aEvent has to be WidgetCompositionEvent or WidgetTextEvent"); + return GetTextCompositionFor(aEvent->widget); } diff --git a/dom/events/nsIMEStateManager.h b/dom/events/nsIMEStateManager.h index f349cd952e0..2480298e436 100644 --- a/dom/events/nsIMEStateManager.h +++ b/dom/events/nsIMEStateManager.h @@ -98,7 +98,17 @@ public: /** * Get TextComposition from widget. */ - static mozilla::TextComposition* GetTextCompositionFor(nsIWidget* aWidget); + static already_AddRefed + GetTextCompositionFor(nsIWidget* aWidget); + + /** + * Returns TextComposition instance for the event. + * + * @param aEvent Should be a composition event or a text event which is + * being dispatched. + */ + static already_AddRefed + GetTextCompositionFor(mozilla::WidgetGUIEvent* aEvent); /** * Send a notification to IME. It depends on the IME or platform spec what diff --git a/dom/file/ArchiveRequest.cpp b/dom/file/ArchiveRequest.cpp index 02bb9d0e05e..2b77ef4fe43 100644 --- a/dom/file/ArchiveRequest.cpp +++ b/dom/file/ArchiveRequest.cpp @@ -174,7 +174,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx, JS::Value* aValue, nsTArray >& aFileList) { - JS::Rooted array(aCx, JS_NewArrayObject(aCx, aFileList.Length(), nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, aFileList.Length())); nsresult rv; if (!array) { @@ -232,7 +232,7 @@ ArchiveRequest::GetFilesResult(JSContext* aCx, JS::MutableHandle aValue, nsTArray >& aFileList) { - JS::Rooted array(aCx, JS_NewArrayObject(aCx, aFileList.Length(), nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, aFileList.Length())); if (!array) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/dom/indexedDB/AsyncConnectionHelper.cpp b/dom/indexedDB/AsyncConnectionHelper.cpp index 0896b2ab7b1..e86c61d70d4 100644 --- a/dom/indexedDB/AsyncConnectionHelper.cpp +++ b/dom/indexedDB/AsyncConnectionHelper.cpp @@ -58,7 +58,7 @@ ConvertCloneReadInfosToArrayInternal( nsTArray& aReadInfos, JS::MutableHandle aResult) { - JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0, nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0)); if (!array) { IDB_WARNING("Failed to make array!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; diff --git a/dom/indexedDB/IDBIndex.cpp b/dom/indexedDB/IDBIndex.cpp index ed2478f2d8a..0101a4edd9e 100644 --- a/dom/indexedDB/IDBIndex.cpp +++ b/dom/indexedDB/IDBIndex.cpp @@ -1447,7 +1447,7 @@ GetAllKeysHelper::GetSuccessResult(JSContext* aCx, nsTArray keys; mKeys.SwapElements(keys); - JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0, nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0)); if (!array) { IDB_WARNING("Failed to make array!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 043e6729590..a88252c2b0d 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -4931,7 +4931,7 @@ GetAllKeysHelper::GetSuccessResult(JSContext* aCx, nsTArray keys; mKeys.SwapElements(keys); - JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0, nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0)); if (!array) { IDB_WARNING("Failed to make array!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; diff --git a/dom/indexedDB/Key.cpp b/dom/indexedDB/Key.cpp index 274b9cd97e8..f2ffc1acd3d 100644 --- a/dom/indexedDB/Key.cpp +++ b/dom/indexedDB/Key.cpp @@ -191,7 +191,7 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd, NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR); if (*aPos - aTypeOffset >= eArray) { - JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0, nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, 0)); if (!array) { NS_WARNING("Failed to make array!"); IDB_REPORT_INTERNAL_ERR(); diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index a694c84a53e..fdb5dd4e166 100644 --- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -389,7 +389,7 @@ KeyPath::ExtractKeyAsJSVal(JSContext* aCx, const JS::Value& aValue, } const uint32_t len = mStrings.Length(); - JS::Rooted arrayObj(aCx, JS_NewArrayObject(aCx, len, nullptr)); + JS::Rooted arrayObj(aCx, JS_NewArrayObject(aCx, len)); if (!arrayObj) { return NS_ERROR_OUT_OF_MEMORY; } @@ -501,7 +501,7 @@ KeyPath::ToJSVal(JSContext* aCx, JS::MutableHandle aValue) const { if (IsArray()) { uint32_t len = mStrings.Length(); - JS::Rooted array(aCx, JS_NewArrayObject(aCx, len, nullptr)); + JS::Rooted array(aCx, JS_NewArrayObject(aCx, len)); if (!array) { IDB_WARNING("Failed to make array!"); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; diff --git a/dom/mobilemessage/src/MmsMessage.cpp b/dom/mobilemessage/src/MmsMessage.cpp index 89ecec1b655..5286ebd48fc 100644 --- a/dom/mobilemessage/src/MmsMessage.cpp +++ b/dom/mobilemessage/src/MmsMessage.cpp @@ -483,7 +483,7 @@ MmsMessage::GetDeliveryInfo(JSContext* aCx, JS::MutableHandle aDelive } JS::Rooted deliveryInfo( - aCx, JS_NewArrayObject(aCx, length, nullptr)); + aCx, JS_NewArrayObject(aCx, length)); NS_ENSURE_TRUE(deliveryInfo, NS_ERROR_OUT_OF_MEMORY); for (uint32_t i = 0; i < length; ++i) { @@ -614,7 +614,7 @@ MmsMessage::GetAttachments(JSContext* aCx, JS::MutableHandle aAttachm uint32_t length = mAttachments.Length(); JS::Rooted attachments( - aCx, JS_NewArrayObject(aCx, length, nullptr)); + aCx, JS_NewArrayObject(aCx, length)); NS_ENSURE_TRUE(attachments, NS_ERROR_OUT_OF_MEMORY); for (uint32_t i = 0; i < length; ++i) { diff --git a/dom/mobilemessage/src/MobileMessageCallback.cpp b/dom/mobilemessage/src/MobileMessageCallback.cpp index 80cfe6d2b18..5b387dccf16 100644 --- a/dom/mobilemessage/src/MobileMessageCallback.cpp +++ b/dom/mobilemessage/src/MobileMessageCallback.cpp @@ -167,7 +167,7 @@ MobileMessageCallback::NotifyMessageDeleted(bool *aDeleted, uint32_t aSize) NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE); JS::Rooted deleteArrayObj(cx, - JS_NewArrayObject(cx, aSize, nullptr)); + JS_NewArrayObject(cx, aSize)); for (uint32_t i = 0; i < aSize; i++) { JS_SetElement(cx, deleteArrayObj, i, aDeleted[i]); } diff --git a/dom/mobilemessage/src/MobileMessageManager.cpp b/dom/mobilemessage/src/MobileMessageManager.cpp index b2f18b1cb04..c9de75f543c 100644 --- a/dom/mobilemessage/src/MobileMessageManager.cpp +++ b/dom/mobilemessage/src/MobileMessageManager.cpp @@ -241,7 +241,7 @@ MobileMessageManager::Send(JS::Handle aNumber, } JS::Rooted obj(aCx); - obj = JS_NewArrayObject(aCx, requests.length(), requests.begin()); + obj = JS_NewArrayObject(aCx, requests); if (!obj) { return NS_ERROR_FAILURE; } diff --git a/dom/mobilemessage/src/SmsFilter.cpp b/dom/mobilemessage/src/SmsFilter.cpp index e127c3bcd29..f85c6d02534 100644 --- a/dom/mobilemessage/src/SmsFilter.cpp +++ b/dom/mobilemessage/src/SmsFilter.cpp @@ -145,7 +145,7 @@ SmsFilter::GetNumbers(JSContext* aCx, JS::MutableHandle aNumbers) numbers[i].setString(str); } - JSObject* obj = JS_NewArrayObject(aCx, numbers.length(), numbers.begin()); + JSObject* obj = JS_NewArrayObject(aCx, numbers); if (!obj) { return NS_ERROR_FAILURE; } diff --git a/dom/mobilemessage/src/ipc/SmsParent.cpp b/dom/mobilemessage/src/ipc/SmsParent.cpp index fa3c63dc501..f4db44729ee 100644 --- a/dom/mobilemessage/src/ipc/SmsParent.cpp +++ b/dom/mobilemessage/src/ipc/SmsParent.cpp @@ -115,8 +115,7 @@ GetParamsFromSendMmsMessageRequest(JSContext* aCx, // attachments JS::Rooted attachmentArray(aCx, JS_NewArrayObject(aCx, - aRequest.attachments().Length(), - nullptr)); + aRequest.attachments().Length())); for (uint32_t i = 0; i < aRequest.attachments().Length(); i++) { JS::Rooted obj(aCx, MmsAttachmentDataToJSObject(aCx, aRequest.attachments().ElementAt(i))); diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index b099e263386..7baaf209176 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -608,7 +608,7 @@ public: MOZ_ASSERT(aCountdown != 0); JSContext* cx = aGlobal.GetContext(); JSAutoCompartment ac(cx, aGlobal.Get()); - mValues = JS_NewArrayObject(cx, aCountdown, nullptr); + mValues = JS_NewArrayObject(cx, aCountdown); mozilla::HoldJSObjects(this); } @@ -731,7 +731,7 @@ Promise::All(const GlobalObject& aGlobal, JSContext* aCx, } if (aIterable.Length() == 0) { - JS::Rooted empty(aCx, JS_NewArrayObject(aCx, 0, nullptr)); + JS::Rooted empty(aCx, JS_NewArrayObject(aCx, 0)); if (!empty) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return nullptr; diff --git a/dom/src/notification/Notification.cpp b/dom/src/notification/Notification.cpp index 63f67d2bba3..5a6a5a17649 100644 --- a/dom/src/notification/Notification.cpp +++ b/dom/src/notification/Notification.cpp @@ -48,7 +48,7 @@ public: MOZ_ASSERT(aPromise); JSContext* cx = aGlobal.GetContext(); JSAutoCompartment ac(cx, mGlobal); - mNotifications = JS_NewArrayObject(cx, 0, nullptr); + mNotifications = JS_NewArrayObject(cx, 0); HoldData(); } diff --git a/dom/workers/Console.cpp b/dom/workers/Console.cpp index 3ad0cdcdd3c..de99a939017 100644 --- a/dom/workers/Console.cpp +++ b/dom/workers/Console.cpp @@ -292,7 +292,7 @@ private: JS::Rooted stackValue(cx); { JS::Rooted stackObj(cx, - JS_NewArrayObject(cx, mStackData.Length(), nullptr)); + JS_NewArrayObject(cx, mStackData.Length())); if (!stackObj) { return; } @@ -447,8 +447,7 @@ WorkerConsole::Method(JSContext* aCx, const char* aMethodName, stack.swap(caller); } - JS::Rooted arguments(aCx, - JS_NewArrayObject(aCx, aData.Length(), nullptr)); + JS::Rooted arguments(aCx, JS_NewArrayObject(aCx, aData.Length())); if (!arguments) { return; } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index b1f5508aabf..83dbdb72793 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2707,9 +2707,15 @@ WorkerPrivateParent::PostMessageInternal( JS::Rooted transferable(aCx, JS::UndefinedValue()); if (aTransferable.WasPassed()) { const Sequence& realTransferable = aTransferable.Value(); + + // The input sequence only comes from the generated bindings code, which + // ensures it is rooted. + JS::HandleValueArray elements = + JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), + realTransferable.Elements()); + JSObject* array = - JS_NewArrayObject(aCx, realTransferable.Length(), - const_cast(realTransferable.Elements())); + JS_NewArrayObject(aCx, elements); if (!array) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; @@ -4923,9 +4929,14 @@ WorkerPrivate::PostMessageToParentInternal( JS::Rooted transferable(aCx, JS::UndefinedValue()); if (aTransferable.WasPassed()) { const Sequence& realTransferable = aTransferable.Value(); - JSObject* array = - JS_NewArrayObject(aCx, realTransferable.Length(), - const_cast(realTransferable.Elements())); + + // The input sequence only comes from the generated bindings code, which + // ensures it is rooted. + JS::HandleValueArray elements = + JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), + realTransferable.Elements()); + + JSObject* array = JS_NewArrayObject(aCx, elements); if (!array) { aRv = NS_ERROR_OUT_OF_MEMORY; return; diff --git a/editor/libeditor/base/nsEditor.cpp b/editor/libeditor/base/nsEditor.cpp index 8afab8a0761..89fcc1ba590 100644 --- a/editor/libeditor/base/nsEditor.cpp +++ b/editor/libeditor/base/nsEditor.cpp @@ -21,6 +21,7 @@ #include "JoinElementTxn.h" // for JoinElementTxn #include "PlaceholderTxn.h" // for PlaceholderTxn #include "SplitElementTxn.h" // for SplitElementTxn +#include "TextComposition.h" // for TextComposition #include "mozFlushType.h" // for mozFlushType::Flush_Frames #include "mozISpellCheckingEngine.h" #include "mozInlineSpellChecker.h" // for mozInlineSpellChecker @@ -139,12 +140,9 @@ nsEditor::nsEditor() , mPlaceHolderBatch(0) , mAction(EditAction::none) , mIMETextOffset(0) -, mIMEBufferLength(0) , mDirection(eNone) , mDocDirtyState(-1) , mSpellcheckCheckboxState(eTriUnset) -, mInIMEMode(false) -, mIsIMEComposing(false) , mShouldTxnSetSelection(true) , mDidPreDestroy(false) , mDidPostCreate(false) @@ -248,8 +246,6 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot, nsISelectionController * /* initialize IME stuff */ mIMETextNode = nullptr; mIMETextOffset = 0; - mIMEBufferLength = 0; - /* Show the caret */ selCon->SetCaretReadOnly(false); selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); @@ -361,6 +357,10 @@ nsEditor::RemoveEventListeners() return; } reinterpret_cast(mEventListener.get())->Disconnect(); + if (mComposition) { + mComposition->EndHandlingComposition(this); + mComposition = nullptr; + } mEventTarget = nullptr; } @@ -966,7 +966,9 @@ nsEditor::EndPlaceHolderTransaction() } // notify editor observers of action but if composing, it's done by // text event handler. - if (!mInIMEMode) NotifyEditorObservers(); + if (!mComposition) { + NotifyEditorObservers(); + } } } mPlaceHolderBatch--; @@ -2010,11 +2012,26 @@ nsEditor::StopPreservingSelection() mSavedSel.MakeEmpty(); } +void +nsEditor::EnsureComposition(mozilla::WidgetGUIEvent* aEvent) +{ + if (mComposition) { + return; + } + // The compositionstart event must cause creating new TextComposition + // instance at being dispatched by nsIMEStateManager. + mComposition = nsIMEStateManager::GetTextCompositionFor(aEvent); + if (!mComposition) { + MOZ_CRASH("nsIMEStateManager doesn't return proper composition"); + } + mComposition->StartHandlingComposition(this); +} nsresult -nsEditor::BeginIMEComposition() +nsEditor::BeginIMEComposition(WidgetCompositionEvent* aCompositionEvent) { - mInIMEMode = true; + MOZ_ASSERT(!mComposition, "There is composition already"); + EnsureComposition(aCompositionEvent); if (mPhonetic) { mPhonetic->Truncate(0); } @@ -2024,7 +2041,7 @@ nsEditor::BeginIMEComposition() void nsEditor::EndIMEComposition() { - NS_ENSURE_TRUE_VOID(mInIMEMode); // nothing to do + NS_ENSURE_TRUE_VOID(mComposition); // nothing to do // commit the IME transaction..we can get at it via the transaction mgr. // Note that this means IME won't work without an undo stack! @@ -2041,9 +2058,8 @@ nsEditor::EndIMEComposition() /* reset the data we need to construct a transaction */ mIMETextNode = nullptr; mIMETextOffset = 0; - mIMEBufferLength = 0; - mInIMEMode = false; - mIsIMEComposing = false; + mComposition->EndHandlingComposition(this); + mComposition = nullptr; // notify editor observers of action NotifyEditorObservers(); @@ -2073,7 +2089,7 @@ nsEditor::ForceCompositionEnd() return NS_ERROR_NOT_AVAILABLE; } - if (!mInIMEMode) { + if (!mComposition) { // XXXmnakano see bug 558976, ResetInputState() has two meaning which are // "commit the composition" and "cursor is moved". This method name is // "ForceCompositionEnd", so, ResetInputState() should be used only for the @@ -2312,7 +2328,7 @@ nsEditor::InsertTextImpl(const nsAString& aStringToInsert, NS_ENSURE_TRUE(aInOutNode && *aInOutNode && aInOutOffset && aDoc, NS_ERROR_NULL_POINTER); - if (!mInIMEMode && aStringToInsert.IsEmpty()) { + if (!mComposition && aStringToInsert.IsEmpty()) { return NS_OK; } @@ -2352,7 +2368,7 @@ nsEditor::InsertTextImpl(const nsAString& aStringToInsert, } nsresult res; - if (mInIMEMode) { + if (mComposition) { if (!node->IsNodeOfType(nsINode::eTEXT)) { // create a text node nsCOMPtr doc = do_QueryInterface(aDoc); @@ -2407,7 +2423,7 @@ nsresult nsEditor::InsertTextIntoTextNodeImpl(const nsAString& aStringToInsert, bool isIMETransaction = false; // aSuppressIME is used when editor must insert text, yet this text is not // part of current ime operation. example: adjusting whitespace around an ime insertion. - if (mIMETextRangeList && mInIMEMode && !aSuppressIME) + if (mIMETextRangeList && mComposition && !aSuppressIME) { if (!mIMETextNode) { @@ -4179,45 +4195,16 @@ nsEditor::DeleteSelectionAndCreateNode(const nsAString& aTag, /* Non-interface, protected methods */ -int32_t -nsEditor::GetIMEBufferLength() +TextComposition* +nsEditor::GetComposition() const { - return mIMEBufferLength; -} - -void -nsEditor::SetIsIMEComposing(){ - // We set mIsIMEComposing according to mIMETextRangeList. - nsCOMPtr rangePtr; - uint16_t listlen, type; - - mIsIMEComposing = false; - listlen = mIMETextRangeList->GetLength(); - - for (uint16_t i = 0; i < listlen; i++) - { - rangePtr = mIMETextRangeList->Item(i); - if (!rangePtr) continue; - nsresult result = rangePtr->GetRangeType(&type); - if (NS_FAILED(result)) continue; - if ( type == nsIPrivateTextRange::TEXTRANGE_RAWINPUT || - type == nsIPrivateTextRange::TEXTRANGE_CONVERTEDTEXT || - type == nsIPrivateTextRange::TEXTRANGE_SELECTEDRAWTEXT || - type == nsIPrivateTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT ) - { - mIsIMEComposing = true; -#ifdef DEBUG_IME - printf("nsEditor::mIsIMEComposing = true\n"); -#endif - break; - } - } - return; + return mComposition; } bool -nsEditor::IsIMEComposing() { - return mIsIMEComposing; +nsEditor::IsIMEComposing() const +{ + return mComposition && mComposition->IsComposing(); } nsresult @@ -4414,7 +4401,9 @@ nsEditor::CreateTxnForIMEText(const nsAString& aStringToInsert, nsRefPtr txn = new IMETextTxn(); - nsresult rv = txn->Init(mIMETextNode, mIMETextOffset, mIMEBufferLength, + // During handling IME composition, mComposition must have been initialized. + nsresult rv = txn->Init(mIMETextNode, mIMETextOffset, + mComposition->String().Length(), mIMETextRangeList, aStringToInsert, this); if (NS_SUCCEEDED(rv)) { @@ -5225,6 +5214,23 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent) if (!focusedContent) { return false; } + } else { + nsAutoString eventType; + aEvent->GetType(eventType); + // If composition event or text event isn't dispatched via widget, + // we need to ignore them since they cannot be managed by TextComposition. + // E.g., the event was created by chrome JS. + // Note that if we allow to handle such events, editor may be confused by + // strange event order. + if (eventType.EqualsLiteral("text") || + eventType.EqualsLiteral("compositionstart") || + eventType.EqualsLiteral("compositionend")) { + WidgetGUIEvent* widgetGUIEvent = + aEvent->GetInternalNSEvent()->AsGUIEvent(); + if (!widgetGUIEvent || !widgetGUIEvent->widget) { + return false; + } + } } bool isTrusted; diff --git a/editor/libeditor/base/nsEditor.h b/editor/libeditor/base/nsEditor.h index b0c0f934944..237bc7f4430 100644 --- a/editor/libeditor/base/nsEditor.h +++ b/editor/libeditor/base/nsEditor.h @@ -69,6 +69,7 @@ class nsTransactionManager; namespace mozilla { class Selection; +class TextComposition; namespace dom { class Element; @@ -242,9 +243,8 @@ public: mozilla::dom::Element** aContent); // IME event handlers - virtual nsresult BeginIMEComposition(); - virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString, - nsIPrivateTextRangeList *aTextRange)=0; + virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent); + virtual nsresult UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) = 0; void EndIMEComposition(); void SwitchTextDirectionTo(uint32_t aDirection); @@ -413,6 +413,13 @@ protected: return !IsPasswordEditor() && !IsReadonly() && !IsDisabled() && !ShouldSkipSpellCheck(); } + /** + * EnsureComposition() should be composition event handlers or text event + * handler. This tries to get the composition for the event and set it to + * mComposition. + */ + void EnsureComposition(mozilla::WidgetGUIEvent* aEvent); + public: /** All editor operations which alter the doc should be prefaced @@ -592,9 +599,14 @@ public: /** Find the deep first and last children. */ nsINode* GetFirstEditableNode(nsINode* aRoot); - int32_t GetIMEBufferLength(); - bool IsIMEComposing(); /* test if IME is in composition state */ - void SetIsIMEComposing(); /* call this before |IsIMEComposing()| */ + /** + * Returns current composition. + */ + mozilla::TextComposition* GetComposition() const; + /** + * Returns true if there is composition string and not fixed. + */ + bool IsIMEComposing() const; /** from html rules code - migration in progress */ static nsresult GetTagString(nsIDOMNode *aNode, nsAString& outString); @@ -830,6 +842,9 @@ protected: nsIAtom *mPlaceHolderName; // name of placeholder transaction nsSelectionState *mSelState; // saved selection state for placeholder txn batching nsString *mPhonetic; + // IME composition this is not null between compositionstart and + // compositionend. + nsRefPtr mComposition; // various listeners nsCOMArray mActionListeners; // listens to all low level actions on the doc @@ -848,16 +863,11 @@ protected: EditAction mAction; // the current editor action uint32_t mIMETextOffset; // offset in text node where IME comp string begins - uint32_t mIMEBufferLength; // current length of IME comp string EDirection mDirection; // the current direction of editor action int8_t mDocDirtyState; // -1 = not initialized uint8_t mSpellcheckCheckboxState; // a Tristate value - bool mInIMEMode; // are we inside an IME composition? - bool mIsIMEComposing; // is IME in composition state? - // This is different from mInIMEMode. see Bug 98434. - bool mShouldTxnSetSelection; // turn off for conservative selection adjustment by txns bool mDidPreDestroy; // whether PreDestroy has been called bool mDidPostCreate; // whether PostCreate has been called diff --git a/editor/libeditor/base/nsEditorEventListener.cpp b/editor/libeditor/base/nsEditorEventListener.cpp index 0cf9430f3e7..5a38ba649f8 100644 --- a/editor/libeditor/base/nsEditorEventListener.cpp +++ b/editor/libeditor/base/nsEditorEventListener.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/Preferences.h" // for Preferences +#include "mozilla/TextEvents.h" // for WidgetCompositionEvent #include "mozilla/dom/Element.h" // for Element #include "mozilla/dom/EventTarget.h" // for EventTarget #include "nsAString.h" @@ -42,8 +43,6 @@ #include "nsINode.h" // for nsINode, ::NODE_IS_EDITABLE, etc #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc #include "nsIPresShell.h" // for nsIPresShell -#include "nsIPrivateTextEvent.h" // for nsIPrivateTextEvent -#include "nsIPrivateTextRange.h" // for nsIPrivateTextRangeList #include "nsISelection.h" // for nsISelection #include "nsISelectionController.h" // for nsISelectionController, etc #include "nsISelectionPrivate.h" // for nsISelectionPrivate @@ -661,24 +660,12 @@ nsEditorEventListener::HandleText(nsIDOMEvent* aTextEvent) return NS_OK; } - nsCOMPtr textEvent = do_QueryInterface(aTextEvent); - if (!textEvent) { - //non-ui event passed in. bad things. - return NS_OK; - } - - nsAutoString composedText; - nsCOMPtr textRangeList; - - textEvent->GetText(composedText); - textRangeList = textEvent->GetInputRange(); - // if we are readonly or disabled, then do nothing. if (mEditor->IsReadonly() || mEditor->IsDisabled()) { return NS_OK; } - return mEditor->UpdateIMEComposition(composedText, textRangeList); + return mEditor->UpdateIMEComposition(aTextEvent); } /** @@ -905,7 +892,9 @@ nsEditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent) if (!mEditor->IsAcceptableInputEvent(aCompositionEvent)) { return NS_OK; } - return mEditor->BeginIMEComposition(); + WidgetCompositionEvent* compositionStart = + aCompositionEvent->GetInternalNSEvent()->AsCompositionEvent(); + return mEditor->BeginIMEComposition(compositionStart); } void diff --git a/editor/libeditor/text/moz.build b/editor/libeditor/text/moz.build index 09ece694ff1..0824c30d7a5 100644 --- a/editor/libeditor/text/moz.build +++ b/editor/libeditor/text/moz.build @@ -20,6 +20,7 @@ FAIL_ON_WARNINGS = True LOCAL_INCLUDES += [ '../base', '/content/base/src', + '/dom/events', '/editor/txmgr/src', ] diff --git a/editor/libeditor/text/nsPlaintextEditor.cpp b/editor/libeditor/text/nsPlaintextEditor.cpp index a4992bbd8b7..c6552f7cbc8 100644 --- a/editor/libeditor/text/nsPlaintextEditor.cpp +++ b/editor/libeditor/text/nsPlaintextEditor.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "TextComposition.h" #include "mozilla/Assertions.h" #include "mozilla/Preferences.h" #include "mozilla/Selection.h" @@ -39,6 +40,7 @@ #include "nsINameSpaceManager.h" #include "nsINode.h" #include "nsIPresShell.h" +#include "nsIPrivateTextEvent.h" #include "nsIPrivateTextRange.h" #include "nsISelection.h" #include "nsISelectionController.h" @@ -695,8 +697,7 @@ NS_IMETHODIMP nsPlaintextEditor::InsertText(const nsAString &aStringToInsert) nsCOMPtr kungFuDeathGrip(mRules); EditAction opID = EditAction::insertText; - if (mInIMEMode) - { + if (mComposition) { opID = EditAction::insertIMEText; } nsAutoPlaceHolderBatch batch(this, nullptr); @@ -811,9 +812,9 @@ NS_IMETHODIMP nsPlaintextEditor::InsertLineBreak() } nsresult -nsPlaintextEditor::BeginIMEComposition() +nsPlaintextEditor::BeginIMEComposition(WidgetCompositionEvent* aEvent) { - NS_ENSURE_TRUE(!mInIMEMode, NS_OK); + NS_ENSURE_TRUE(!mComposition, NS_OK); if (IsPasswordEditor()) { NS_ENSURE_TRUE(mRules, NS_ERROR_NULL_POINTER); @@ -825,14 +826,19 @@ nsPlaintextEditor::BeginIMEComposition() textEditRules->ResetIMETextPWBuf(); } - return nsEditor::BeginIMEComposition(); + return nsEditor::BeginIMEComposition(aEvent); } nsresult -nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString, - nsIPrivateTextRangeList* aTextRangeList) +nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent) { - NS_ABORT_IF_FALSE(aTextRangeList, "aTextRangeList must not be nullptr"); + NS_ABORT_IF_FALSE(aDOMTextEvent, "aDOMTextEvent must not be nullptr"); + + WidgetTextEvent* widgetTextEvent = + aDOMTextEvent->GetInternalNSEvent()->AsTextEvent(); + NS_ENSURE_TRUE(widgetTextEvent, NS_ERROR_INVALID_ARG); + + EnsureComposition(widgetTextEvent); nsCOMPtr ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); @@ -843,19 +849,23 @@ nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString, nsRefPtr caretP = ps->GetCaret(); - // Update information of clauses in the new composition string. - // This will be refered by followed methods. - mIMETextRangeList = aTextRangeList; - - // We set mIsIMEComposing properly. - SetIsIMEComposing(); + nsCOMPtr privateTextEvent = + do_QueryInterface(aDOMTextEvent); + NS_ENSURE_TRUE(privateTextEvent, NS_ERROR_INVALID_ARG); { + TextComposition::TextEventHandlingMarker + textEventHandlingMarker(mComposition, widgetTextEvent); + + // Update information of clauses in the new composition string. + // This will be refered by followed methods. + mIMETextRangeList = privateTextEvent->GetInputRange(); + NS_ABORT_IF_FALSE(mIMETextRangeList, + "mIMETextRangeList must not be nullptr"); + nsAutoPlaceHolderBatch batch(this, nsGkAtoms::IMETxnName); - rv = InsertText(aCompositionString); - - mIMEBufferLength = aCompositionString.Length(); + rv = InsertText(widgetTextEvent->theText); if (caretP) { caretP->SetCaretDOMSelection(selection); @@ -866,7 +876,7 @@ nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString, // Note that if committed, we don't need to notify it since it will be // notified at followed compositionend event. // NOTE: We must notify after the auto batch will be gone. - if (mIsIMEComposing) { + if (IsIMEComposing()) { NotifyEditorObservers(); } diff --git a/editor/libeditor/text/nsPlaintextEditor.h b/editor/libeditor/text/nsPlaintextEditor.h index 252694c71fe..dc0b6407444 100644 --- a/editor/libeditor/text/nsPlaintextEditor.h +++ b/editor/libeditor/text/nsPlaintextEditor.h @@ -122,9 +122,8 @@ public: virtual already_AddRefed GetDOMEventTarget(); - virtual nsresult BeginIMEComposition(); - virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString, - nsIPrivateTextRangeList *aTextRange); + virtual nsresult BeginIMEComposition(mozilla::WidgetCompositionEvent* aEvent); + virtual nsresult UpdateIMEComposition(nsIDOMEvent* aTextEvent) MOZ_OVERRIDE; virtual already_AddRefed GetInputEventTargetContent(); diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/text/nsTextEditRules.cpp index 740ffb4f754..18f296d1ec5 100644 --- a/editor/libeditor/text/nsTextEditRules.cpp +++ b/editor/libeditor/text/nsTextEditRules.cpp @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "TextComposition.h" #include "mozilla/Assertions.h" #include "mozilla/LookAndFeel.h" #include "mozilla/Preferences.h" @@ -1208,7 +1209,8 @@ nsTextEditRules::TruncateInsertionIfNeeded(Selection* aSelection, nsContentUtils::GetSelectionInTextControl(aSelection, mEditor->GetRoot(), start, end); - int32_t oldCompStrLength = mEditor->GetIMEBufferLength(); + TextComposition* composition = mEditor->GetComposition(); + int32_t oldCompStrLength = composition ? composition->String().Length() : 0; const int32_t selectionLength = end - start; const int32_t resultingDocLength = docLength - selectionLength - oldCompStrLength; diff --git a/gfx/2d/DrawTargetD2D1.cpp b/gfx/2d/DrawTargetD2D1.cpp index 96c7a3beee7..67e90b7290f 100644 --- a/gfx/2d/DrawTargetD2D1.cpp +++ b/gfx/2d/DrawTargetD2D1.cpp @@ -3,6 +3,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include #include "DrawTargetD2D1.h" #include "DrawTargetD2D.h" #include "FilterNodeSoftware.h" diff --git a/gfx/2d/RadialGradientEffectD2D1.cpp b/gfx/2d/RadialGradientEffectD2D1.cpp index ec9224bbe56..c94f905777d 100644 --- a/gfx/2d/RadialGradientEffectD2D1.cpp +++ b/gfx/2d/RadialGradientEffectD2D1.cpp @@ -50,11 +50,11 @@ static const PCWSTR kXmlDescription = ); // {FB947CDA-718E-40CC-AE7B-D255830D7D14} -DEFINE_GUID(GUID_SampleRadialGradientPS, -0xfb947cda, 0x718e, 0x40cc, 0xae, 0x7b, 0xd2, 0x55, 0x83, 0xd, 0x7d, 0x14); +static const GUID GUID_SampleRadialGradientPS = + {0xfb947cda, 0x718e, 0x40cc, {0xae, 0x7b, 0xd2, 0x55, 0x83, 0xd, 0x7d, 0x14}}; // {2C468128-6546-453C-8E25-F2DF0DE10A0F} -DEFINE_GUID(GUID_SampleRadialGradientA0PS, -0x2c468128, 0x6546, 0x453c, 0x8e, 0x25, 0xf2, 0xdf, 0xd, 0xe1, 0xa, 0xf); +static const GUID GUID_SampleRadialGradientA0PS = + {0x2c468128, 0x6546, 0x453c, {0x8e, 0x25, 0xf2, 0xdf, 0xd, 0xe1, 0xa, 0xf}}; namespace mozilla { namespace gfx { diff --git a/gfx/2d/gfx2d.vcxproj b/gfx/2d/gfx2d.vcxproj index 238652ac659..f1af481bd6b 100644 --- a/gfx/2d/gfx2d.vcxproj +++ b/gfx/2d/gfx2d.vcxproj @@ -1,4 +1,4 @@ - + @@ -42,7 +42,7 @@ - INITGUID;USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN + USE_SSE2;WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions);GFX_LOG_DEBUG;GFX_LOG_WARNING;MFBT_STAND_ALONE;XP_WIN MultiThreadedDebugDLL Level3 ProgramDatabase @@ -62,7 +62,7 @@ - INITGUID;USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + USE_SSE2;WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) MultiThreadedDLL Level3 ProgramDatabase diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build index ecf71a92e18..c2b7518eb1c 100644 --- a/gfx/2d/moz.build +++ b/gfx/2d/moz.build @@ -52,7 +52,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'SourceSurfaceD2DTarget.cpp', ] DEFINES['WIN32'] = True - DEFINES['INITGUID'] = True # For Direct2D 1.1 we require WINSDK_MAXVER 0x06020000 or higher. if CONFIG['MOZ_ENABLE_DIRECT2D1_1']: SOURCES += [ diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 7c03f373c54..38ca291ff8c 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -76,6 +76,7 @@ static const char *sExtensionNames[] = { "GL_IMG_read_format", "GL_EXT_read_format_bgra", "GL_APPLE_client_storage", + "GL_APPLE_texture_range", "GL_ARB_texture_non_power_of_two", "GL_ARB_pixel_buffer_object", "GL_ARB_ES2_compatibility", @@ -756,6 +757,17 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl) } } + if (IsExtensionSupported(APPLE_texture_range)) { + SymLoadStruct vaoSymbols[] = { + { (PRFuncPtr*) &mSymbols.fTextureRangeAPPLE, { "TextureRangeAPPLE", nullptr } }, + { nullptr, { nullptr } }, + }; + + if (!LoadSymbols(&vaoSymbols[0], trygl, prefix)) { + mSymbols.fTextureRangeAPPLE = nullptr; + } + } + if (IsExtensionSupported(ARB_vertex_array_object) || IsExtensionSupported(OES_vertex_array_object)) { SymLoadStruct vaoSymbols[] = { diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index cf307abb6f4..b4fb60ff662 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -352,6 +352,7 @@ public: IMG_read_format, EXT_read_format_bgra, APPLE_client_storage, + APPLE_texture_range, ARB_texture_non_power_of_two, ARB_pixel_buffer_object, ARB_ES2_compatibility, @@ -1344,6 +1345,12 @@ public: AFTER_GL_CALL; } + void fTextureRangeAPPLE(GLenum target, GLsizei length, GLvoid *pointer) { + BEFORE_GL_CALL; + mSymbols.fTextureRangeAPPLE(target, length, pointer); + AFTER_GL_CALL; + } + void fPointParameterf(GLenum pname, GLfloat param) { BEFORE_GL_CALL; mSymbols.fPointParameterf(pname, param); diff --git a/gfx/gl/GLContextSymbols.h b/gfx/gl/GLContextSymbols.h index a30ebc5f3f5..77d5d04318b 100644 --- a/gfx/gl/GLContextSymbols.h +++ b/gfx/gl/GLContextSymbols.h @@ -211,6 +211,8 @@ struct GLContextSymbols PFNGLTEXIMAGE2DPROC fTexImage2D; typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); PFNGLTEXSUBIMAGE2DPROC fTexSubImage2D; + typedef void (GLAPIENTRY * PFNGLTEXTURERANGEAPPLEPROC) (GLenum target, GLsizei length, GLvoid *pointer); + PFNGLTEXTURERANGEAPPLEPROC fTextureRangeAPPLE; typedef void (GLAPIENTRY * PFNGLUNIFORM1FPROC) (GLint location, GLfloat v0); PFNGLUNIFORM1FPROC fUniform1f; typedef void (GLAPIENTRY * PFNGLUNIFORM1FVPROC) (GLint location, GLsizei count, const GLfloat* value); diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index fcac8317d17..120ac72a601 100644 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -20,6 +20,7 @@ #include "SharedSurfaceIO.h" #endif #include "ScopedGLHelpers.h" +#include "gfx2DGlue.h" using namespace mozilla::gfx; @@ -478,9 +479,22 @@ GLScreenBuffer::CreateRead(SharedSurface_GL* surf) return ReadBuffer::Create(gl, caps, formats, surf); } +void +GLScreenBuffer::Readback(SharedSurface_GL* src, DataSourceSurface* dest) +{ + MOZ_ASSERT(src && dest); + DataSourceSurface::MappedSurface ms; + dest->Map(DataSourceSurface::MapType::READ, &ms); + nsRefPtr wrappedDest = + new gfxImageSurface(ms.mData, + ThebesIntSize(dest->GetSize()), + ms.mStride, + SurfaceFormatToImageFormat(dest->GetFormat())); + DeprecatedReadback(src, wrappedDest); +} void -GLScreenBuffer::Readback(SharedSurface_GL* src, gfxImageSurface* dest) +GLScreenBuffer::DeprecatedReadback(SharedSurface_GL* src, gfxImageSurface* dest) { MOZ_ASSERT(src && dest); MOZ_ASSERT(ToIntSize(dest->GetSize()) == src->Size()); @@ -509,8 +523,6 @@ GLScreenBuffer::Readback(SharedSurface_GL* src, gfxImageSurface* dest) } } - - DrawBuffer* DrawBuffer::Create(GLContext* const gl, const SurfaceCaps& caps, diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 2c37f1e7094..4ba86ba74ff 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -18,6 +18,7 @@ #include "SurfaceTypes.h" #include "GLContextTypes.h" #include "GLDefs.h" +#include "mozilla/gfx/2D.h" #include "mozilla/gfx/Point.h" // Forwards: @@ -277,7 +278,8 @@ public: bool Resize(const gfx::IntSize& size); - void Readback(SharedSurface_GL* src, gfxImageSurface* dest); + void Readback(SharedSurface_GL* src, gfx::DataSourceSurface* dest); + void DeprecatedReadback(SharedSurface_GL* src, gfxImageSurface* dest); protected: void Attach(SharedSurface* surface, const gfx::IntSize& size); diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index 8066f62f073..747708617f2 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -22,6 +22,7 @@ #include "nsISupportsImpl.h" // for gfxContext::AddRef, etc #include "nsRect.h" // for nsIntRect #include "nsSize.h" // for nsIntSize +#include "LayerUtils.h" using namespace mozilla::gfx; using namespace mozilla::gl; @@ -56,7 +57,8 @@ CopyableCanvasLayer::Initialize(const Data& aData) // `GLScreenBuffer::Morph`ing is only needed in BasicShadowableCanvasLayer. } else if (aData.mDrawTarget) { mDrawTarget = aData.mDrawTarget; - mSurface = + mSurface = mDrawTarget->Snapshot(); + mDeprecatedSurface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget); mNeedsYFlip = false; } else { @@ -73,7 +75,8 @@ CopyableCanvasLayer::IsDataValid(const Data& aData) } void -CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) +CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget, + SourceSurface* aMaskSurface) { if (!IsDirty()) return; @@ -81,14 +84,105 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) if (mDrawTarget) { mDrawTarget->Flush(); - mSurface = + mSurface = mDrawTarget->Snapshot(); + } + + if (!mGLContext && aDestTarget) { + PaintWithOpacity(aDestTarget, 1.0f, aMaskSurface); + return; + } + + if (mGLContext) { + RefPtr readSurf; + RefPtr resultSurf; + + SharedSurface* sharedSurf = mGLContext->RequestFrame(); + if (!sharedSurf) { + NS_WARNING("Null frame received."); + return; + } + + IntSize readSize(sharedSurf->Size()); + SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE) + ? SurfaceFormat::B8G8R8X8 + : SurfaceFormat::B8G8R8A8; + + if (aDestTarget) { + resultSurf = aDestTarget->Snapshot(); + if (!resultSurf) { + resultSurf = GetTempSurface(readSize, format); + } + } else { + resultSurf = GetTempSurface(readSize, format); + } + MOZ_ASSERT(resultSurf); + MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL); + SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf); + + if (surfGL->Type() == SharedSurfaceType::Basic) { + // sharedSurf_Basic->mData must outlive readSurf. Alas, readSurf may not + // leave the scope it was declared in. + SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); + readSurf = sharedSurf_Basic->GetData(); + } else { + if (resultSurf->GetSize() != readSize || + !(readSurf = resultSurf->GetDataSurface()) || + readSurf->GetFormat() != format) + { + readSurf = GetTempSurface(readSize, format); + } + + // Readback handles Flush/MarkDirty. + mGLContext->Screen()->Readback(surfGL, readSurf); + } + MOZ_ASSERT(readSurf); + + bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult; + if (needsPremult) { + PremultiplySurface(readSurf); + } + + if (readSurf != resultSurf) { + RefPtr resultDataSurface = + resultSurf->GetDataSurface(); + RefPtr dt = + Factory::CreateDrawTargetForData(BackendType::CAIRO, + resultDataSurface->GetData(), + resultDataSurface->GetSize(), + resultDataSurface->Stride(), + resultDataSurface->GetFormat()); + IntSize readSize = readSurf->GetSize(); + Rect r(0, 0, readSize.width, readSize.height); + DrawOptions opts(1.0f, CompositionOp::OP_SOURCE, AntialiasMode::DEFAULT); + dt->DrawSurface(readSurf, r, r, DrawSurfaceOptions(), opts); + } + + // If !aDestSurface then we will end up painting using mSurface, so + // stick our surface into mSurface, so that the Paint() path is the same. + if (!aDestTarget) { + mSurface = resultSurf; + } + } +} + +void +CopyableCanvasLayer::DeprecatedUpdateSurface(gfxASurface* aDestSurface, + Layer* aMaskLayer) +{ + if (!IsDirty()) + return; + Painted(); + + if (mDrawTarget) { + mDrawTarget->Flush(); + mDeprecatedSurface = gfxPlatform::GetPlatform()->CreateThebesSurfaceAliasForDrawTarget_hack(mDrawTarget); } if (!mGLContext && aDestSurface) { nsRefPtr tmpCtx = new gfxContext(aDestSurface); tmpCtx->SetOperator(gfxContext::OPERATOR_SOURCE); - CopyableCanvasLayer::PaintWithOpacity(tmpCtx, 1.0f, aMaskLayer); + DeprecatedPaintWithOpacity(tmpCtx, 1.0f, aMaskLayer); return; } @@ -111,7 +205,7 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) if (aDestSurface) { resultSurf = aDestSurface; } else { - resultSurf = GetTempSurface(readSize, format); + resultSurf = DeprecatedGetTempSurface(readSize, format); } MOZ_ASSERT(resultSurf); if (resultSurf->CairoStatus() != 0) { @@ -136,11 +230,11 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) !(readSurf = resultSurf->GetAsImageSurface()) || readSurf->Format() != format) { - readSurf = GetTempSurface(readSize, format); + readSurf = DeprecatedGetTempSurface(readSize, format); } // Readback handles Flush/MarkDirty. - mGLContext->Screen()->Readback(surfGL, readSurf); + mGLContext->Screen()->DeprecatedReadback(surfGL, readSurf); } MOZ_ASSERT(readSurf); @@ -150,7 +244,7 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) gfxUtils::PremultiplyImageSurface(readSurf); readSurf->MarkDirty(); } - + if (readSurf != resultSurf) { readSurf->Flush(); nsRefPtr ctx = new gfxContext(resultSurf); @@ -162,23 +256,69 @@ CopyableCanvasLayer::UpdateSurface(gfxASurface* aDestSurface, Layer* aMaskLayer) // If !aDestSurface then we will end up painting using mSurface, so // stick our surface into mSurface, so that the Paint() path is the same. if (!aDestSurface) { - mSurface = resultSurf; + mDeprecatedSurface = resultSurf; } } } void -CopyableCanvasLayer::PaintWithOpacity(gfxContext* aContext, +CopyableCanvasLayer::PaintWithOpacity(gfx::DrawTarget* aTarget, float aOpacity, - Layer* aMaskLayer, - gfxContext::GraphicsOperator aOperator) + SourceSurface* aMaskSurface, + gfx::CompositionOp aOperator) { if (!mSurface) { NS_WARNING("No valid surface to draw!"); return; } - nsRefPtr pat = new gfxPattern(mSurface); + SurfacePattern pat(mSurface, ExtendMode::CLAMP, Matrix(), ToFilter(mFilter)); + + Matrix oldTransform; + if (mNeedsYFlip) { + oldTransform = aTarget->GetTransform(); + Matrix flipped = oldTransform; + flipped.Translate(0, mBounds.height); + flipped.Scale(1.0, -1.0); + aTarget->SetTransform(flipped); + } + + DrawOptions options = DrawOptions(aOpacity, CompositionOp::OP_SOURCE); + + // If content opaque, then save off current operator and set to source. + // This ensures that alpha is not applied even if the source surface + // has an alpha channel + if (GetContentFlags() & CONTENT_OPAQUE) { + options.mCompositionOp = CompositionOp::OP_SOURCE; + } + + if (aOperator != CompositionOp::OP_OVER) { + options.mCompositionOp = aOperator; + } + + Rect rect = Rect(0, 0, mBounds.width, mBounds.height); + aTarget->FillRect(rect, pat, options); + if (aMaskSurface) { + aTarget->MaskSurface(pat, aMaskSurface, Point(0, 0), options); + } + + if (mNeedsYFlip) { + aTarget->SetTransform(oldTransform); + } +} + +void +CopyableCanvasLayer::DeprecatedPaintWithOpacity(gfxContext* aContext, + float aOpacity, + Layer* aMaskLayer, + gfxContext::GraphicsOperator aOperator) +{ + if (!mDeprecatedSurface) { + NS_WARNING("No valid surface to draw!"); + return; + } + + nsRefPtr pat = new gfxPattern(mDeprecatedSurface); pat->SetFilter(mFilter); pat->SetExtend(gfxPattern::EXTEND_PAD); @@ -216,27 +356,50 @@ CopyableCanvasLayer::PaintWithOpacity(gfxContext* aContext, } } -gfxImageSurface* -CopyableCanvasLayer::GetTempSurface(const IntSize& aSize, const gfxImageFormat aFormat) +DataSourceSurface* +CopyableCanvasLayer::GetTempSurface(const IntSize& aSize, + const SurfaceFormat aFormat) { if (!mCachedTempSurface || aSize.width != mCachedSize.width || aSize.height != mCachedSize.height || aFormat != mCachedFormat) { - mCachedTempSurface = new gfxImageSurface(ThebesIntSize(aSize), aFormat); + mCachedTempSurface = Factory::CreateDataSourceSurface(aSize, aFormat); mCachedSize = aSize; mCachedFormat = aFormat; } - MOZ_ASSERT(mCachedTempSurface->Stride() == mCachedTempSurface->Width() * 4); + MOZ_ASSERT(mCachedTempSurface->Stride() == + mCachedTempSurface->GetSize().width * 4); return mCachedTempSurface; } +gfxImageSurface* +CopyableCanvasLayer::DeprecatedGetTempSurface(const IntSize& aSize, + const gfxImageFormat aFormat) +{ + if (!mDeprecatedCachedTempSurface || + aSize.width != mCachedSize.width || + aSize.height != mCachedSize.height || + aFormat != mDeprecatedCachedFormat) + { + mDeprecatedCachedTempSurface = + new gfxImageSurface(ThebesIntSize(aSize), aFormat); + mCachedSize = aSize; + mDeprecatedCachedFormat = aFormat; + } + + MOZ_ASSERT(mDeprecatedCachedTempSurface->Stride() == + mDeprecatedCachedTempSurface->Width() * 4); + return mDeprecatedCachedTempSurface; +} + void CopyableCanvasLayer::DiscardTempSurface() { mCachedTempSurface = nullptr; + mDeprecatedCachedTempSurface = nullptr; } } diff --git a/gfx/layers/CopyableCanvasLayer.h b/gfx/layers/CopyableCanvasLayer.h index 1930d697540..7a6bbc39889 100644 --- a/gfx/layers/CopyableCanvasLayer.h +++ b/gfx/layers/CopyableCanvasLayer.h @@ -41,15 +41,16 @@ public: virtual bool IsDataValid(const Data& aData); protected: - void PaintWithOpacity(gfxContext* aContext, + void PaintWithOpacity(gfx::DrawTarget* aTarget, float aOpacity, - Layer* aMaskLayer, - gfxContext::GraphicsOperator aOperator = gfxContext::OPERATOR_OVER); + gfx::SourceSurface* aMaskSurface, + gfx::CompositionOp aOperator = gfx::CompositionOp::OP_OVER); - void UpdateSurface(gfxASurface* aDestSurface = nullptr, - Layer* aMaskLayer = nullptr); + void UpdateTarget(gfx::DrawTarget* aDestTarget = nullptr, + gfx::SourceSurface* aMaskSurface = nullptr); - nsRefPtr mSurface; + RefPtr mSurface; + nsRefPtr mDeprecatedSurface; nsRefPtr mGLContext; mozilla::RefPtr mDrawTarget; @@ -59,13 +60,30 @@ protected: bool mNeedsYFlip; bool mForceReadback; - nsRefPtr mCachedTempSurface; + RefPtr mCachedTempSurface; + nsRefPtr mDeprecatedCachedTempSurface; gfx::IntSize mCachedSize; - gfxImageFormat mCachedFormat; + gfx::SurfaceFormat mCachedFormat; + gfxImageFormat mDeprecatedCachedFormat; - gfxImageSurface* GetTempSurface(const gfx::IntSize& aSize, const gfxImageFormat aFormat); + gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize, + const gfx::SurfaceFormat aFormat); void DiscardTempSurface(); + + /* Deprecated thebes methods */ +protected: + void DeprecatedPaintWithOpacity(gfxContext* aContext, + float aOpacity, + Layer* aMaskLayer, + gfxContext::GraphicsOperator aOperator = gfxContext::OPERATOR_OVER); + + void DeprecatedUpdateSurface(gfxASurface* aDestSurface = nullptr, + Layer* aMaskLayer = nullptr); + + gfxImageSurface* DeprecatedGetTempSurface(const gfx::IntSize& aSize, + const gfxImageFormat aFormat); + }; } diff --git a/gfx/layers/ImageContainer.h b/gfx/layers/ImageContainer.h index e5dc7d4399e..151e2ea89c5 100644 --- a/gfx/layers/ImageContainer.h +++ b/gfx/layers/ImageContainer.h @@ -710,8 +710,8 @@ class AutoLockImage { public: AutoLockImage(ImageContainer *aContainer) : mContainer(aContainer) { mImage = mContainer->LockCurrentImage(); } - AutoLockImage(ImageContainer *aContainer, gfxASurface **aSurface) : mContainer(aContainer) { - *aSurface = mContainer->DeprecatedLockCurrentAsSurface(&mSize, getter_AddRefs(mImage)).get(); + AutoLockImage(ImageContainer *aContainer, RefPtr *aSurface) : mContainer(aContainer) { + *aSurface = mContainer->LockCurrentAsSourceSurface(&mSize, getter_AddRefs(mImage)); } ~AutoLockImage() { if (mContainer) { mContainer->UnlockCurrentImage(); } } diff --git a/gfx/layers/LayerUtils.cpp b/gfx/layers/LayerUtils.cpp new file mode 100644 index 00000000000..ab0dc1e6416 --- /dev/null +++ b/gfx/layers/LayerUtils.cpp @@ -0,0 +1,79 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "LayerUtils.h" +#include "PremultiplyTables.h" + +namespace mozilla { +namespace layers { + +using namespace mozilla::gfx; + +static inline const uint8_t PremultiplyValue(uint8_t a, uint8_t v) { + return PremultiplyTable[a*256+v]; +} + +static inline const uint8_t UnpremultiplyValue(uint8_t a, uint8_t v) { + return UnpremultiplyTable[a*256+v]; +} + +void +PremultiplySurface(DataSourceSurface* srcSurface, + DataSourceSurface* destSurface) +{ + if (!destSurface) + destSurface = srcSurface; + + IntSize srcSize = srcSurface->GetSize(); + MOZ_ASSERT(srcSurface->GetFormat() == destSurface->GetFormat() && + srcSize.width == destSurface->GetSize().width && + srcSize.height == destSurface->GetSize().height && + srcSurface->Stride() == destSurface->Stride(), + "Source and destination surfaces don't have identical characteristics"); + + MOZ_ASSERT(srcSurface->Stride() == srcSize.width * 4, + "Source surface stride isn't tightly packed"); + + // Only premultiply ARGB32 + if (srcSurface->GetFormat() != SurfaceFormat::B8G8R8A8) { + if (destSurface != srcSurface) { + memcpy(destSurface->GetData(), srcSurface->GetData(), + srcSurface->Stride() * srcSize.height); + } + return; + } + + uint8_t *src = srcSurface->GetData(); + uint8_t *dst = destSurface->GetData(); + + uint32_t dim = srcSize.width * srcSize.height; + for (uint32_t i = 0; i < dim; ++i) { +#ifdef IS_LITTLE_ENDIAN + uint8_t b = *src++; + uint8_t g = *src++; + uint8_t r = *src++; + uint8_t a = *src++; + + *dst++ = PremultiplyValue(a, b); + *dst++ = PremultiplyValue(a, g); + *dst++ = PremultiplyValue(a, r); + *dst++ = a; +#else + uint8_t a = *src++; + uint8_t r = *src++; + uint8_t g = *src++; + uint8_t b = *src++; + + *dst++ = a; + *dst++ = PremultiplyValue(a, r); + *dst++ = PremultiplyValue(a, g); + *dst++ = PremultiplyValue(a, b); +#endif + } +} + + +} +} diff --git a/gfx/layers/LayerUtils.h b/gfx/layers/LayerUtils.h new file mode 100644 index 00000000000..72c8fd497e3 --- /dev/null +++ b/gfx/layers/LayerUtils.h @@ -0,0 +1,21 @@ +/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef MOZILLA_LAYERS_LAYERUTILS_H_ +#define MOZILLA_LAYERS_LAYERUTILS_H_ + +#include "mozilla/gfx/2D.h" + +namespace mozilla { +namespace layers { + +void +PremultiplySurface(gfx::DataSourceSurface* srcSurface, + gfx::DataSourceSurface* destSurface = nullptr); + +} +} + +#endif /* MOZILLA_LAYERS_LAYERUTILS_H_ */ diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 232895b8bb0..b1ffbb2e7eb 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -169,7 +169,7 @@ Layer::Layer(LayerManager* aManager, void* aImplData) : mPostXScale(1.0f), mPostYScale(1.0f), mOpacity(1.0), - mMixBlendMode(gfxContext::OPERATOR_OVER), + mMixBlendMode(CompositionOp::OP_OVER), mForceIsolatedGroup(false), mContentFlags(0), mUseClipRect(false), @@ -670,20 +670,26 @@ Layer::GetEffectiveOpacity() return opacity; } -gfxContext::GraphicsOperator +CompositionOp Layer::GetEffectiveMixBlendMode() { - if(mMixBlendMode != gfxContext::OPERATOR_OVER) + if(mMixBlendMode != CompositionOp::OP_OVER) return mMixBlendMode; for (ContainerLayer* c = GetParent(); c && !c->UseIntermediateSurface(); c = c->GetParent()) { - if(c->mMixBlendMode != gfxContext::OPERATOR_OVER) + if(c->mMixBlendMode != CompositionOp::OP_OVER) return c->mMixBlendMode; } return mMixBlendMode; } +gfxContext::GraphicsOperator +Layer::DeprecatedGetEffectiveMixBlendMode() +{ + return ThebesOp(GetEffectiveMixBlendMode()); +} + void Layer::ComputeEffectiveTransformForMaskLayer(const Matrix4x4& aTransformToSurface) { diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index feed4660233..b28b0336275 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -18,6 +18,7 @@ #include "GraphicsFilter.h" // for GraphicsFilter #include "gfxPoint.h" // for gfxPoint #include "gfxRect.h" // for gfxRect +#include "gfx2DGlue.h" #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2, etc #include "mozilla/DebugOnly.h" // for DebugOnly #include "mozilla/EventForwards.h" // for nsPaintEvent @@ -786,7 +787,7 @@ public: } } - void SetMixBlendMode(gfxContext::GraphicsOperator aMixBlendMode) + void SetMixBlendMode(gfx::CompositionOp aMixBlendMode) { if (mMixBlendMode != aMixBlendMode) { MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) MixBlendMode", this)); @@ -795,6 +796,11 @@ public: } } + void DeprecatedSetMixBlendMode(gfxContext::GraphicsOperator aMixBlendMode) + { + SetMixBlendMode(gfx::CompositionOpForOp(aMixBlendMode)); + } + void SetForceIsolatedGroup(bool aForceIsolatedGroup) { if(mForceIsolatedGroup != aForceIsolatedGroup) { @@ -1033,7 +1039,7 @@ public: // These getters can be used anytime. float GetOpacity() { return mOpacity; } - gfxContext::GraphicsOperator GetMixBlendMode() const { return mMixBlendMode; } + gfx::CompositionOp GetMixBlendMode() const { return mMixBlendMode; } const nsIntRect* GetClipRect() { return mUseClipRect ? &mClipRect : nullptr; } uint32_t GetContentFlags() { return mContentFlags; } const nsIntRegion& GetVisibleRegion() { return mVisibleRegion; } @@ -1207,7 +1213,8 @@ public: /** * Returns the blendmode of this layer. */ - gfxContext::GraphicsOperator GetEffectiveMixBlendMode(); + gfx::CompositionOp GetEffectiveMixBlendMode(); + gfxContext::GraphicsOperator DeprecatedGetEffectiveMixBlendMode(); /** * This returns the effective transform computed by @@ -1408,7 +1415,7 @@ protected: AnimationArray mAnimations; InfallibleTArray mAnimationData; float mOpacity; - gfxContext::GraphicsOperator mMixBlendMode; + gfx::CompositionOp mMixBlendMode; bool mForceIsolatedGroup; nsIntRect mClipRect; nsIntRect mTileSourceRect; diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in index dd14db9707b..c4a71a60305 100644 --- a/gfx/layers/Makefile.in +++ b/gfx/layers/Makefile.in @@ -13,3 +13,6 @@ CXXFLAGS += \ $(NULL) CXXFLAGS += $(MOZ_CAIRO_CFLAGS) $(TK_CFLAGS) + +PremultiplyTables.h: $(srcdir)/genTables.py + $(PYTHON) $(srcdir)/genTables.py diff --git a/gfx/layers/RotatedBuffer.cpp b/gfx/layers/RotatedBuffer.cpp index 8476c16b2ad..946c230d9ab 100644 --- a/gfx/layers/RotatedBuffer.cpp +++ b/gfx/layers/RotatedBuffer.cpp @@ -301,9 +301,17 @@ RotatedContentBuffer::BufferContentType() bool RotatedContentBuffer::BufferSizeOkFor(const nsIntSize& aSize) { - return (aSize == mBufferRect.Size() || - (SizedToVisibleBounds != mBufferSizePolicy && - aSize < mBufferRect.Size())); + if (aSize == mBufferRect.Size()) { + return true; + } + + if (SizedToVisibleBounds != mBufferSizePolicy && + aSize < mBufferRect.Size()) { + return (aSize.width * 2 > mBufferRect.width) && + (aSize.height * 2 > mBufferRect.height); + } + + return false; } bool @@ -503,8 +511,9 @@ RotatedContentBuffer::BeginPaint(ThebesLayer* aLayer, // or call CreateBuffer before this call. FinalizeFrame(result.mRegionToDraw); - if (result.mRegionToDraw.IsEmpty()) + if (result.mRegionToDraw.IsEmpty()) { return result; + } nsIntRect drawBounds = result.mRegionToDraw.GetBounds(); RefPtr destDTBuffer; @@ -614,7 +623,7 @@ RotatedContentBuffer::BeginPaint(ThebesLayer* aLayer, mBufferRotation = nsIntPoint(0,0); } } else { - // The buffer's not big enough, so allocate a new one + // The buffer's not big enough or the buffer needs to shrink, so allocate a new one CreateBuffer(result.mContentType, destBufferRect, bufferFlags, &destDTBuffer, &destDTBufferOnWhite); if (!destDTBuffer) { diff --git a/gfx/layers/basic/BasicCanvasLayer.cpp b/gfx/layers/basic/BasicCanvasLayer.cpp index f6bec46643b..6fd69021cc5 100644 --- a/gfx/layers/basic/BasicCanvasLayer.cpp +++ b/gfx/layers/basic/BasicCanvasLayer.cpp @@ -9,6 +9,8 @@ #include "nsAutoPtr.h" // for nsRefPtr #include "nsCOMPtr.h" // for already_AddRefed #include "nsISupportsImpl.h" // for Layer::AddRef, etc +#include "gfx2DGlue.h" + class gfxContext; using namespace mozilla::gfx; @@ -18,17 +20,39 @@ namespace mozilla { namespace layers { void -BasicCanvasLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) +BasicCanvasLayer::Paint(DrawTarget* aTarget, SourceSurface* aMaskSurface) { if (IsHidden()) return; FirePreTransactionCallback(); - UpdateSurface(); + UpdateTarget(); FireDidTransactionCallback(); - gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode(); - PaintWithOpacity(aContext, GetEffectiveOpacity(), aMaskLayer, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : GetOperator()); + CompositionOp mixBlendMode = GetEffectiveMixBlendMode(); + PaintWithOpacity(aTarget, + GetEffectiveOpacity(), + aMaskSurface, + mixBlendMode != CompositionOp::OP_OVER ? mixBlendMode : GetOperator()); +} + +void +BasicCanvasLayer::DeprecatedPaint(gfxContext* aContext, Layer* aMaskLayer) +{ + if (IsHidden()) + return; + + FirePreTransactionCallback(); + DeprecatedUpdateSurface(); + FireDidTransactionCallback(); + + gfxContext::GraphicsOperator mixBlendMode = DeprecatedGetEffectiveMixBlendMode(); + DeprecatedPaintWithOpacity(aContext, + GetEffectiveOpacity(), + aMaskLayer, + mixBlendMode != gfxContext::OPERATOR_OVER ? + mixBlendMode : + DeprecatedGetOperator()); } already_AddRefed diff --git a/gfx/layers/basic/BasicCanvasLayer.h b/gfx/layers/basic/BasicCanvasLayer.h index 3dd3ae8280b..17d1bd2312f 100644 --- a/gfx/layers/basic/BasicCanvasLayer.h +++ b/gfx/layers/basic/BasicCanvasLayer.h @@ -34,7 +34,9 @@ public: CanvasLayer::SetVisibleRegion(aRegion); } - virtual void Paint(gfxContext* aContext, Layer* aMaskLayer); + virtual void Paint(gfx::DrawTarget* aTarget, + gfx::SourceSurface* aMaskSurface); + virtual void DeprecatedPaint(gfxContext* aContext, Layer* aMaskLayer); protected: BasicLayerManager* BasicManager() diff --git a/gfx/layers/basic/BasicColorLayer.cpp b/gfx/layers/basic/BasicColorLayer.cpp index 08930abf192..b170dc737af 100644 --- a/gfx/layers/basic/BasicColorLayer.cpp +++ b/gfx/layers/basic/BasicColorLayer.cpp @@ -9,6 +9,7 @@ #include "BasicLayers.h" // for BasicLayerManager #include "gfxContext.h" // for gfxContext, etc #include "gfxRect.h" // for gfxRect +#include "gfx2DGlue.h" #include "mozilla/mozalloc.h" // for operator new #include "nsAutoPtr.h" // for nsRefPtr #include "nsCOMPtr.h" // for already_AddRefed @@ -43,13 +44,35 @@ public: ColorLayer::SetVisibleRegion(aRegion); } - virtual void Paint(gfxContext* aContext, Layer* aMaskLayer) + virtual void Paint(DrawTarget* aTarget, SourceSurface* aMaskSurface) { - if (IsHidden()) + if (IsHidden()) { return; + } + CompositionOp mixBlendMode = GetEffectiveMixBlendMode(); + CompositionOp op = + mixBlendMode != CompositionOp::OP_OVER ? mixBlendMode : GetOperator(); + + DrawOptions opts = DrawOptions(); + opts.mCompositionOp = op; + ColorPattern pattern(ToColor(mColor)); + aTarget->MaskSurface(pattern, + aMaskSurface, + ToIntRect(GetBounds()).TopLeft(), + opts); + } + + virtual void DeprecatedPaint(gfxContext* aContext, Layer* aMaskLayer) + { + if (IsHidden()) { + return; + } gfxContextAutoSaveRestore contextSR(aContext); - gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode(); - AutoSetOperator setOptimizedOperator(aContext, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : GetOperator()); + gfxContext::GraphicsOperator mixBlendMode = DeprecatedGetEffectiveMixBlendMode(); + AutoSetOperator setOptimizedOperator(aContext, + mixBlendMode != gfxContext::OPERATOR_OVER ? + mixBlendMode : + DeprecatedGetOperator()); aContext->SetColor(mColor); diff --git a/gfx/layers/basic/BasicContainerLayer.cpp b/gfx/layers/basic/BasicContainerLayer.cpp index 46672bc8465..d3166c1eea3 100644 --- a/gfx/layers/basic/BasicContainerLayer.cpp +++ b/gfx/layers/basic/BasicContainerLayer.cpp @@ -59,7 +59,7 @@ BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSur Layer* child = GetFirstChild(); bool hasSingleBlendingChild = false; if (!HasMultipleChildren() && child) { - hasSingleBlendingChild = child->GetMixBlendMode() != gfxContext::OPERATOR_OVER; + hasSingleBlendingChild = child->GetMixBlendMode() != CompositionOp::OP_OVER; } /* If we have a single childand it is not blending,, it can just inherit our opacity, @@ -72,7 +72,7 @@ BasicContainerLayer::ComputeEffectiveTransforms(const Matrix4x4& aTransformToSur mUseIntermediateSurface = GetMaskLayer() || GetForceIsolatedGroup() || - (GetMixBlendMode() != gfxContext::OPERATOR_OVER && HasMultipleChildren()) || + (GetMixBlendMode() != CompositionOp::OP_OVER && HasMultipleChildren()) || (GetEffectiveOpacity() != 1.0 && (HasMultipleChildren() || hasSingleBlendingChild)); } diff --git a/gfx/layers/basic/BasicImageLayer.cpp b/gfx/layers/basic/BasicImageLayer.cpp index ba1da6167ea..5d97603a528 100644 --- a/gfx/layers/basic/BasicImageLayer.cpp +++ b/gfx/layers/basic/BasicImageLayer.cpp @@ -52,7 +52,8 @@ public: ImageLayer::SetVisibleRegion(aRegion); } - virtual void Paint(gfxContext* aContext, Layer* aMaskLayer); + virtual void Paint(DrawTarget* aTarget, SourceSurface* aMaskSurface); + virtual void DeprecatedPaint(gfxContext* aContext, Layer* aMaskLayer); virtual bool GetAsSurface(gfxASurface** aSurface, SurfaceDescriptor* aDescriptor); @@ -64,43 +65,104 @@ protected: } // only paints the image if aContext is non-null - already_AddRefed - GetAndPaintCurrentImage(gfxContext* aContext, + void + GetAndPaintCurrentImage(DrawTarget* aTarget, float aOpacity, - Layer* aMaskLayer); + SourceSurface* aMaskSurface); + already_AddRefed + DeprecatedGetAndPaintCurrentImage(gfxContext* aContext, + float aOpacity, + Layer* aMaskLayer); gfx::IntSize mSize; }; +static void +DeprecatedPaintContext(gfxPattern* aPattern, + const nsIntRegion& aVisible, + float aOpacity, + gfxContext* aContext, + Layer* aMaskLayer); + void -BasicImageLayer::Paint(gfxContext* aContext, Layer* aMaskLayer) +BasicImageLayer::Paint(DrawTarget* aTarget, SourceSurface* aMaskSurface) { - if (IsHidden()) + if (IsHidden()) { return; + } + GetAndPaintCurrentImage(aTarget, GetEffectiveOpacity(), aMaskSurface); +} + +void +BasicImageLayer::DeprecatedPaint(gfxContext* aContext, Layer* aMaskLayer) +{ + if (IsHidden()) { + return; + } nsRefPtr dontcare = - GetAndPaintCurrentImage(aContext, GetEffectiveOpacity(), aMaskLayer); + DeprecatedGetAndPaintCurrentImage(aContext, + GetEffectiveOpacity(), + aMaskLayer); +} + +void +BasicImageLayer::GetAndPaintCurrentImage(DrawTarget* aTarget, + float aOpacity, + SourceSurface* aMaskSurface) +{ + if (!mContainer) { + return; + } + + mContainer->SetImageFactory(mManager->IsCompositingCheap() ? + nullptr : + BasicManager()->GetImageFactory()); + IntSize size; + Image* image = nullptr; + RefPtr surf = + mContainer->LockCurrentAsSourceSurface(&size, &image); + + if (!surf) { + return; + } + + if (aTarget) { + // The visible region can extend outside the image, so just draw + // within the image bounds. + SurfacePattern pat(surf, ExtendMode::CLAMP, Matrix(), ToFilter(mFilter)); + CompositionOp mixBlendMode = GetEffectiveMixBlendMode(); + CompositionOp op = + mixBlendMode != CompositionOp::OP_OVER ? mixBlendMode : GetOperator(); + DrawOptions opts(aOpacity, op); + + aTarget->MaskSurface(pat, aMaskSurface, Point(0, 0), opts); + + GetContainer()->NotifyPaintedImage(image); + } + + mContainer->UnlockCurrentImage(); } already_AddRefed -BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext, - float aOpacity, - Layer* aMaskLayer) +BasicImageLayer::DeprecatedGetAndPaintCurrentImage(gfxContext* aContext, + float aOpacity, + Layer* aMaskLayer) { if (!mContainer) return nullptr; mContainer->SetImageFactory(mManager->IsCompositingCheap() ? nullptr : BasicManager()->GetImageFactory()); - nsRefPtr surface; - AutoLockImage autoLock(mContainer, getter_AddRefs(surface)); + RefPtr surface; + AutoLockImage autoLock(mContainer, &surface); Image *image = autoLock.GetImage(); gfx::IntSize size = mSize = autoLock.GetSize(); - if (!surface || surface->CairoStatus()) { + if (!surface || !surface->IsValid()) { return nullptr; } - nsRefPtr pat = new gfxPattern(surface); + nsRefPtr pat = new gfxPattern(surface, gfx::Matrix()); if (!pat) { return nullptr; } @@ -110,10 +172,12 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext, // The visible region can extend outside the image, so just draw // within the image bounds. if (aContext) { - gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode(); - AutoSetOperator setOptimizedOperator(aContext, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : GetOperator()); + CompositionOp mixBlendMode = GetEffectiveMixBlendMode(); + CompositionOp op = + mixBlendMode != CompositionOp::OP_OVER ? mixBlendMode : GetOperator(); + AutoSetOperator setOptimizedOperator(aContext, ThebesOp(op)); - PaintContext(pat, + DeprecatedPaintContext(pat, nsIntRegion(nsIntRect(0, 0, size.width, size.height)), aOpacity, aContext, aMaskLayer); @@ -123,12 +187,12 @@ BasicImageLayer::GetAndPaintCurrentImage(gfxContext* aContext, return pat.forget(); } -void -PaintContext(gfxPattern* aPattern, - const nsIntRegion& aVisible, - float aOpacity, - gfxContext* aContext, - Layer* aMaskLayer) +static void +DeprecatedPaintContext(gfxPattern* aPattern, + const nsIntRegion& aVisible, + float aOpacity, + gfxContext* aContext, + Layer* aMaskLayer) { // Set PAD mode so that when the video is being scaled, we do not sample // outside the bounds of the video image. diff --git a/gfx/layers/basic/BasicImplData.h b/gfx/layers/basic/BasicImplData.h index 7f8a2193f5d..5c56ae14afc 100644 --- a/gfx/layers/basic/BasicImplData.h +++ b/gfx/layers/basic/BasicImplData.h @@ -9,6 +9,8 @@ #include "gfxContext.h" // for gfxContext, etc #include "nsDebug.h" // for NS_ASSERTION #include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc +#include "mozilla/gfx/Types.h" + class gfxASurface; namespace mozilla { @@ -44,7 +46,7 @@ public: BasicImplData() : mHidden(false), mClipToVisibleRegion(false), mDrawAtomically(false), - mOperator(gfxContext::OPERATOR_OVER) + mOperator(gfx::CompositionOp::OP_OVER) { MOZ_COUNT_CTOR(BasicImplData); } @@ -59,7 +61,9 @@ public: * set up to account for all the properties of the layer (transform, * opacity, etc). */ - virtual void Paint(gfxContext* aContext, Layer* aMaskLayer) {} + virtual void Paint(gfx::DrawTarget* aTarget, + gfx::SourceSurface* aMaskSurface) {} + virtual void DeprecatedPaint(gfxContext* aContext, Layer* aMaskLayer) {} /** * Like Paint() but called for ThebesLayers with the additional parameters @@ -94,14 +98,19 @@ public: * the operator to be used when compositing the layer in this transaction. It must * be OVER or SOURCE. */ - void SetOperator(gfxContext::GraphicsOperator aOperator) + void SetOperator(gfx::CompositionOp aOperator) { - NS_ASSERTION(aOperator == gfxContext::OPERATOR_OVER || - aOperator == gfxContext::OPERATOR_SOURCE, + NS_ASSERTION(aOperator == gfx::CompositionOp::OP_OVER || + aOperator == gfx::CompositionOp::OP_SOURCE, "Bad composition operator"); mOperator = aOperator; } - gfxContext::GraphicsOperator GetOperator() const { return mOperator; } + + gfx::CompositionOp GetOperator() const { return mOperator; } + gfxContext::GraphicsOperator DeprecatedGetOperator() const + { + return gfx::ThebesOp(mOperator); + } /** * Return a surface for this layer. Will use an existing surface, if @@ -123,7 +132,7 @@ protected: bool mHidden; bool mClipToVisibleRegion; bool mDrawAtomically; - gfxContext::GraphicsOperator mOperator; + gfx::CompositionOp mOperator; }; } // layers diff --git a/gfx/layers/basic/BasicLayerManager.cpp b/gfx/layers/basic/BasicLayerManager.cpp index ee815a02978..c4eba72c526 100644 --- a/gfx/layers/basic/BasicLayerManager.cpp +++ b/gfx/layers/basic/BasicLayerManager.cpp @@ -415,7 +415,7 @@ MarkLayersHidden(Layer* aLayer, const nsIntRect& aClipRect, } BasicImplData* data = ToData(aLayer); - data->SetOperator(gfxContext::OPERATOR_OVER); + data->SetOperator(CompositionOp::OP_OVER); data->SetClipToVisibleRegion(false); data->SetDrawAtomically(false); @@ -500,13 +500,13 @@ ApplyDoubleBuffering(Layer* aLayer, const nsIntRect& aVisibleRect) // using OPERATOR_SOURCE to ensure that alpha values in a transparent window // are cleared. This can also be faster than OPERATOR_OVER. if (!container) { - data->SetOperator(gfxContext::OPERATOR_SOURCE); + data->SetOperator(CompositionOp::OP_SOURCE); data->SetDrawAtomically(true); } else { if (container->UseIntermediateSurface() || !container->ChildrenPartitionVisibleRegion(newVisibleRect)) { // We need to double-buffer this container. - data->SetOperator(gfxContext::OPERATOR_SOURCE); + data->SetOperator(CompositionOp::OP_SOURCE); container->ForceIntermediateSurface(); } else { // Tell the children to clip to their visible regions so our assumption @@ -824,7 +824,7 @@ BasicLayerManager::PaintSelfOrChildren(PaintLayerContext& aPaintContext, aPaintContext.mCallback, aPaintContext.mCallbackData, aPaintContext.mReadback); } else { - data->Paint(aGroupTarget, aPaintContext.mLayer->GetMaskLayer()); + data->DeprecatedPaint(aGroupTarget, aPaintContext.mLayer->GetMaskLayer()); } } else { ReadbackProcessor readback; @@ -862,7 +862,8 @@ BasicLayerManager::FlushGroup(PaintLayerContext& aPaintContext, bool aNeedsClipT aPaintContext.mLayer->GetEffectiveVisibleRegion()); } BasicContainerLayer* container = static_cast(aPaintContext.mLayer); - AutoSetOperator setOperator(aPaintContext.mTarget, container->GetOperator()); + AutoSetOperator setOperator(aPaintContext.mTarget, + ThebesOp(container->GetOperator())); PaintWithMask(aPaintContext.mTarget, aPaintContext.mLayer->GetEffectiveOpacity(), aPaintContext.mLayer->GetMaskLayer()); } @@ -896,7 +897,7 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget, bool needsClipToVisibleRegion = data->GetClipToVisibleRegion() && !aLayer->AsThebesLayer(); NS_ASSERTION(needsGroup || !aLayer->GetFirstChild() || - container->GetOperator() == gfxContext::OPERATOR_OVER, + container->GetOperator() == CompositionOp::OP_OVER, "non-OVER operator should have forced UseIntermediateSurface"); NS_ASSERTION(!aLayer->GetFirstChild() || !aLayer->GetMaskLayer() || container->UseIntermediateSurface(), diff --git a/gfx/layers/basic/BasicLayers.h b/gfx/layers/basic/BasicLayers.h index b52ea4367b7..6101c0a7cca 100644 --- a/gfx/layers/basic/BasicLayers.h +++ b/gfx/layers/basic/BasicLayers.h @@ -197,13 +197,6 @@ protected: bool mCompositorMightResample; }; -void -PaintContext(gfxPattern* aPattern, - const nsIntRegion& aVisible, - float aOpacity, - gfxContext* aContext, - Layer* aMaskLayer); - } } diff --git a/gfx/layers/basic/BasicThebesLayer.cpp b/gfx/layers/basic/BasicThebesLayer.cpp index 84a606dc401..2bd38fdd3e1 100644 --- a/gfx/layers/basic/BasicThebesLayer.cpp +++ b/gfx/layers/basic/BasicThebesLayer.cpp @@ -62,7 +62,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, } float opacity = GetEffectiveOpacity(); - gfxContext::GraphicsOperator mixBlendMode = GetEffectiveMixBlendMode(); + CompositionOp mixBlendMode = GetEffectiveMixBlendMode(); if (!BasicManager()->IsRetained()) { NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer"); @@ -83,14 +83,17 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, aContext->Save(); bool needsClipToVisibleRegion = GetClipToVisibleRegion(); - bool needsGroup = - opacity != 1.0 || GetOperator() != gfxContext::OPERATOR_OVER || mixBlendMode != gfxContext::OPERATOR_OVER || aMaskLayer; + bool needsGroup = opacity != 1.0 || + GetOperator() != CompositionOp::OP_OVER || + mixBlendMode != CompositionOp::OP_OVER || + aMaskLayer; nsRefPtr groupContext; if (needsGroup) { groupContext = BasicManager()->PushGroupForLayer(aContext, this, toDraw, &needsClipToVisibleRegion); - if (GetOperator() != gfxContext::OPERATOR_OVER || mixBlendMode != gfxContext::OPERATOR_OVER) { + if (GetOperator() != CompositionOp::OP_OVER || + mixBlendMode != CompositionOp::OP_OVER) { needsClipToVisibleRegion = true; } } else { @@ -103,7 +106,9 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, if (needsClipToVisibleRegion) { gfxUtils::ClipToRegion(aContext, toDraw); } - AutoSetOperator setOptimizedOperator(aContext, mixBlendMode != gfxContext::OPERATOR_OVER ? mixBlendMode : GetOperator()); + CompositionOp op = + mixBlendMode != CompositionOp::OP_OVER ? mixBlendMode : GetOperator(); + AutoSetOperator setOptimizedOperator(aContext, ThebesOp(op)); PaintWithMask(aContext, opacity, aMaskLayer); } @@ -132,7 +137,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext, if (!IsHidden() && !clipExtents.IsEmpty()) { mContentClient->DrawTo(this, aContext->GetDrawTarget(), opacity, - CompositionOpForOp(GetOperator()), + GetOperator(), maskSurface, &maskTransform); } diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 65e5ab0a21a..b84d9654fbf 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -76,9 +76,10 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) return; } - nsRefPtr surface = mBuffer->AsTextureClientSurface()->GetAsSurface(); - if (surface) { - aLayer->UpdateSurface(surface); + RefPtr drawTarget = + mBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget(); + if (drawTarget) { + aLayer->UpdateTarget(drawTarget); } mBuffer->Unlock(); @@ -88,7 +89,7 @@ CanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) return; } - if (surface) { + if (drawTarget) { GetForwarder()->UpdatedTexture(this, mBuffer, nullptr); GetForwarder()->UseTexture(this, mBuffer); } @@ -215,7 +216,7 @@ DeprecatedCanvasClient2D::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) } gfxASurface* surface = mDeprecatedTextureClient->LockSurface(); - aLayer->UpdateSurface(surface); + aLayer->DeprecatedUpdateSurface(surface); mDeprecatedTextureClient->Unlock(); } diff --git a/gfx/layers/client/ClientImageLayer.cpp b/gfx/layers/client/ClientImageLayer.cpp index 90ffb57ece8..df8c63aeefe 100644 --- a/gfx/layers/client/ClientImageLayer.cpp +++ b/gfx/layers/client/ClientImageLayer.cpp @@ -105,8 +105,8 @@ protected: return mImageClientTypeContainer; } - nsRefPtr surface; - AutoLockImage autoLock(mContainer, getter_AddRefs(surface)); + RefPtr surface; + AutoLockImage autoLock(mContainer, &surface); mImageClientTypeContainer = autoLock.GetImage() ? BUFFER_IMAGE_SINGLE : BUFFER_UNKNOWN; diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index 5860eec210a..eeb126d3f43 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -216,10 +216,10 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, GetForwarder()->UseTexture(this, mFrontBuffer); } else { - nsRefPtr surface = image->DeprecatedGetAsSurface(); + RefPtr surface = image->GetAsSourceSurface(); MOZ_ASSERT(surface); - gfx::IntSize size = gfx::IntSize(image->GetSize().width, image->GetSize().height); + gfx::IntSize size = image->GetSize(); if (mFrontBuffer && (mFrontBuffer->IsImmutable() || mFrontBuffer->GetSize() != size)) { @@ -230,7 +230,7 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, bool bufferCreated = false; if (!mFrontBuffer) { gfxImageFormat format - = gfxPlatform::GetPlatform()->OptimalFormatForContent(surface->GetContentType()); + = gfxPlatform::GetPlatform()->OptimalFormatForContent(gfx::ContentForFormat(surface->GetFormat())); mFrontBuffer = CreateTextureClientForDrawing(gfx::ImageFormatToSurfaceFormat(format), mTextureFlags); MOZ_ASSERT(mFrontBuffer->AsTextureClientDrawTarget()); @@ -249,9 +249,8 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, { // We must not keep a reference to the DrawTarget after it has been unlocked. RefPtr dt = mFrontBuffer->AsTextureClientDrawTarget()->GetAsDrawTarget(); - RefPtr source = gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, surface); - MOZ_ASSERT(source.get()); - dt->CopySurface(source, IntRect(IntPoint(), source->GetSize()), IntPoint()); + MOZ_ASSERT(surface.get()); + dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } mFrontBuffer->Unlock(); diff --git a/gfx/layers/d3d10/CanvasLayerD3D10.cpp b/gfx/layers/d3d10/CanvasLayerD3D10.cpp index c48a6e5ae85..7ad206c469e 100644 --- a/gfx/layers/d3d10/CanvasLayerD3D10.cpp +++ b/gfx/layers/d3d10/CanvasLayerD3D10.cpp @@ -82,25 +82,12 @@ CanvasLayerD3D10::Initialize(const Data& aData) // XXX we should store mDrawTarget and use it directly in UpdateSurface, // bypassing Thebes - mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); + mSurface = mDrawTarget->Snapshot(); } else { NS_ERROR("CanvasLayer created without mSurface, mDrawTarget or mGLContext?"); } mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); - - if (mSurface && mSurface->GetType() == gfxSurfaceType::D2D) { - void *data = mSurface->GetData(&gKeyD3D10Texture); - if (data) { - mTexture = static_cast(data); - mIsD2DTexture = true; - device()->CreateShaderResourceView(mTexture, nullptr, getter_AddRefs(mSRView)); - mHasAlpha = - mSurface->GetContentType() == gfxContentType::COLOR_ALPHA; - return; - } - } - mIsD2DTexture = false; // Create a texture in case we need to readback. @@ -127,7 +114,6 @@ CanvasLayerD3D10::UpdateSurface() if (mDrawTarget) { mDrawTarget->Flush(); } else if (mIsD2DTexture) { - mSurface->Flush(); return; } @@ -179,12 +165,6 @@ CanvasLayerD3D10::UpdateSurface() MOZ_CRASH("Unhandled SharedSurfaceType."); } } else if (mSurface) { - RECT r; - r.left = 0; - r.top = 0; - r.right = mBounds.width; - r.bottom = mBounds.height; - D3D10_MAPPED_TEXTURE2D map; HRESULT hr = mTexture->Map(0, D3D10_MAP_WRITE_DISCARD, 0, &map); @@ -193,17 +173,13 @@ CanvasLayerD3D10::UpdateSurface() return; } - nsRefPtr dstSurface; + RefPtr destTarget = + Factory::CreateDrawTargetForD3D10Texture(mTexture, + SurfaceFormat::R8G8B8A8); + Rect r(Point(0, 0), ToRect(mBounds).Size()); + destTarget->DrawSurface(mSurface, r, r, DrawSurfaceOptions(), + DrawOptions(1.0F, CompositionOp::OP_SOURCE)); - dstSurface = new gfxImageSurface((unsigned char*)map.pData, - gfxIntSize(mBounds.width, mBounds.height), - map.RowPitch, - gfxImageFormat::ARGB32); - nsRefPtr ctx = new gfxContext(dstSurface); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(mSurface); - ctx->Paint(); - mTexture->Unmap(0); mSRView = mUploadSRView; } diff --git a/gfx/layers/d3d10/CanvasLayerD3D10.h b/gfx/layers/d3d10/CanvasLayerD3D10.h index 93edc2e0086..3693adf1714 100644 --- a/gfx/layers/d3d10/CanvasLayerD3D10.h +++ b/gfx/layers/d3d10/CanvasLayerD3D10.h @@ -39,7 +39,7 @@ private: void UpdateSurface(); - nsRefPtr mSurface; + RefPtr mSurface; mozilla::RefPtr mDrawTarget; nsRefPtr mGLContext; nsRefPtr mTexture; diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.cpp b/gfx/layers/d3d9/CanvasLayerD3D9.cpp index a8c3be6c497..d0fe7cb867b 100644 --- a/gfx/layers/d3d9/CanvasLayerD3D9.cpp +++ b/gfx/layers/d3d9/CanvasLayerD3D9.cpp @@ -42,11 +42,10 @@ CanvasLayerD3D9::~CanvasLayerD3D9() void CanvasLayerD3D9::Initialize(const Data& aData) { - NS_ASSERTION(mSurface == nullptr, "BasicCanvasLayer::Initialize called twice!"); + NS_ASSERTION(mDrawTarget == nullptr, "BasicCanvasLayer::Initialize called twice!"); if (aData.mDrawTarget) { mDrawTarget = aData.mDrawTarget; - mSurface = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(mDrawTarget); mNeedsYFlip = false; mDataIsPremultiplied = true; } else if (aData.mGLContext) { @@ -55,7 +54,7 @@ CanvasLayerD3D9::Initialize(const Data& aData) mDataIsPremultiplied = aData.mIsGLAlphaPremult; mNeedsYFlip = true; } else { - NS_ERROR("CanvasLayer created without mSurface, mGLContext or mDrawTarget?"); + NS_ERROR("CanvasLayer created without mGLContext or mDrawTarget?"); } mBounds.SetRect(0, 0, aData.mSize.width, aData.mSize.height); @@ -79,87 +78,37 @@ CanvasLayerD3D9::UpdateSurface() } } + RefPtr surface; + if (mGLContext) { SharedSurface* surf = mGLContext->RequestFrame(); if (!surf) return; SharedSurface_Basic* shareSurf = SharedSurface_Basic::Cast(surf); - - // WebGL reads entire surface. - LockTextureRectD3D9 textureLock(mTexture); - if (!textureLock.HasLock()) { - NS_WARNING("Failed to lock CanvasLayer texture."); - return; - } - - D3DLOCKED_RECT rect = textureLock.GetLockRect(); - - DataSourceSurface* frameData = shareSurf->GetData(); - // Scope for DrawTarget, so it's destroyed early. - { - RefPtr rectDt = Factory::CreateDrawTargetForData(BackendType::CAIRO, - (uint8_t*)rect.pBits, - frameData->GetSize(), - rect.Pitch, - SurfaceFormat::B8G8R8A8); - - Rect drawRect(0, 0, frameData->GetSize().width, frameData->GetSize().height); - rectDt->DrawSurface(frameData, drawRect, drawRect, - DrawSurfaceOptions(), DrawOptions(1.0F, CompositionOp::OP_SOURCE)); - rectDt->Flush(); - } + surface = shareSurf->GetData(); } else { - RECT r; - r.left = mBounds.x; - r.top = mBounds.y; - r.right = mBounds.XMost(); - r.bottom = mBounds.YMost(); - - LockTextureRectD3D9 textureLock(mTexture); - if (!textureLock.HasLock()) { - NS_WARNING("Failed to lock CanvasLayer texture."); - return; - } - - D3DLOCKED_RECT lockedRect = textureLock.GetLockRect(); - - nsRefPtr sourceSurface; - - if (mSurface->GetType() == gfxSurfaceType::Win32) { - sourceSurface = mSurface->GetAsImageSurface(); - } else if (mSurface->GetType() == gfxSurfaceType::Image) { - sourceSurface = static_cast(mSurface.get()); - if (sourceSurface->Format() != gfxImageFormat::ARGB32 && - sourceSurface->Format() != gfxImageFormat::RGB24) - { - return; - } - } else { - sourceSurface = new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height), - gfxImageFormat::ARGB32); - nsRefPtr ctx = new gfxContext(sourceSurface); - ctx->SetOperator(gfxContext::OPERATOR_SOURCE); - ctx->SetSource(mSurface); - ctx->Paint(); - } - - uint8_t *startBits = sourceSurface->Data(); - uint32_t sourceStride = sourceSurface->Stride(); - - if (sourceSurface->Format() != gfxImageFormat::ARGB32) { - mHasAlpha = false; - } else { - mHasAlpha = true; - } - - for (int y = 0; y < mBounds.height; y++) { - memcpy((uint8_t*)lockedRect.pBits + lockedRect.Pitch * y, - startBits + sourceStride * y, - mBounds.width * 4); - } - + surface = mDrawTarget->Snapshot(); } + + // WebGL reads entire surface. + LockTextureRectD3D9 textureLock(mTexture); + if (!textureLock.HasLock()) { + NS_WARNING("Failed to lock CanvasLayer texture."); + return; + } + + D3DLOCKED_RECT rect = textureLock.GetLockRect(); + RefPtr rectDt = Factory::CreateDrawTargetForData(BackendType::CAIRO, + (uint8_t*)rect.pBits, + surface->GetSize(), + rect.Pitch, + SurfaceFormat::B8G8R8A8); + + Rect drawRect(0, 0, surface->GetSize().width, surface->GetSize().height); + rectDt->DrawSurface(surface, drawRect, drawRect, + DrawSurfaceOptions(), DrawOptions(1.0F, CompositionOp::OP_SOURCE)); + rectDt->Flush(); } Layer* diff --git a/gfx/layers/d3d9/CanvasLayerD3D9.h b/gfx/layers/d3d9/CanvasLayerD3D9.h index dd0fe8d634a..931103f8b55 100644 --- a/gfx/layers/d3d9/CanvasLayerD3D9.h +++ b/gfx/layers/d3d9/CanvasLayerD3D9.h @@ -39,7 +39,6 @@ protected: void UpdateSurface(); - nsRefPtr mSurface; nsRefPtr mGLContext; nsRefPtr mTexture; RefPtr mDrawTarget; diff --git a/gfx/layers/genTables.py b/gfx/layers/genTables.py new file mode 100644 index 00000000000..369ec10d47e --- /dev/null +++ b/gfx/layers/genTables.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +def table_generator(f): + return ",\n".join([", ".join(["0x%2.2x" % h for h in [f(i) for i in range(r,r+16)]]) for r in range(0, 65536, 16)]) + +with open("PremultiplyTables.h", "w") as f: + f.write("const uint8_t PremultiplyTable[256*256] = {\n"); + f.write(table_generator(lambda i: ((i / 256) * (i % 256) + 254) / 255) + "\n") + f.write("};\n"); + f.write("const uint8_t UnpremultiplyTable[256*256] = {\n"); + f.write(table_generator(lambda i: (i % 256) * 255 / ((i / 256) if (i / 256) > 0 else 255) % 256) + "\n") + f.write("};\n"); diff --git a/gfx/layers/ipc/AsyncPanZoomController.cpp b/gfx/layers/ipc/AsyncPanZoomController.cpp index 36a59e4f612..e07313bf5dd 100644 --- a/gfx/layers/ipc/AsyncPanZoomController.cpp +++ b/gfx/layers/ipc/AsyncPanZoomController.cpp @@ -1705,6 +1705,12 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aLayerMetri // scroll offset updates from APZ until we acknowledge the update it sent. // This prevents APZ updates from clobbering scroll updates from other // more "legitimate" sources like content scripts. + // Furthermore, any inflight paint requests we have already dispatched are + // going to be ignored by layout, and so mLastDispatchedPaintMetrics + // becomes incorrect for the purposes of calculating the LD transform. To + // correct this we need to update mLastDispatchedPaintMetrics to be the + // last thing we know was painted by Gecko. + mLastDispatchedPaintMetrics = aLayerMetrics; nsRefPtr controller = GetGeckoContentController(); if (controller) { controller->AcknowledgeScrollUpdate(aLayerMetrics.mScrollId, diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 54b8c8f3304..66180e712b1 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -60,13 +60,13 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'd3d9/ContainerLayerD3D9.cpp', 'd3d9/ImageLayerD3D9.cpp', 'd3d9/LayerManagerD3D9.cpp', - 'd3d9/Nv3DVUtils.cpp', 'd3d9/TextureD3D9.cpp', 'd3d9/ThebesLayerD3D9.cpp', ] SOURCES += [ 'd3d9/CompositorD3D9.cpp', 'd3d9/DeviceManagerD3D9.cpp', + 'd3d9/Nv3DVUtils.cpp', ] if CONFIG['MOZ_ENABLE_D3D10_LAYER']: EXPORTS += [ @@ -261,6 +261,7 @@ UNIFIED_SOURCES += [ 'LayerScope.cpp', 'LayersLogging.cpp', 'LayerSorter.cpp', + 'LayerUtils.cpp', 'opengl/CompositingRenderTargetOGL.cpp', 'opengl/CompositorOGL.cpp', 'opengl/OGLShaderProgram.cpp', @@ -324,3 +325,7 @@ if CONFIG['MOZ_DEBUG']: if CONFIG['MOZ_ENABLE_D3D10_LAYER']: DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True + +GENERATED_FILES = [ + 'PremultiplyTables.h', +] diff --git a/gfx/src/nsScriptableRegion.cpp b/gfx/src/nsScriptableRegion.cpp index da653deb534..76d04c39171 100644 --- a/gfx/src/nsScriptableRegion.cpp +++ b/gfx/src/nsScriptableRegion.cpp @@ -136,7 +136,7 @@ NS_IMETHODIMP nsScriptableRegion::GetRects(JSContext* aCx, JS::MutableHandle destArray(aCx, JS_NewArrayObject(aCx, numRects * 4, nullptr)); + JS::Rooted destArray(aCx, JS_NewArrayObject(aCx, numRects * 4)); if (!destArray) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/gfx/thebes/Makefile.in b/gfx/thebes/Makefile.in index 1cbc960ec4e..e9f6b6c380b 100644 --- a/gfx/thebes/Makefile.in +++ b/gfx/thebes/Makefile.in @@ -41,5 +41,5 @@ gfxAlphaRecoverySSE2.$(OBJ_SUFFIX): OS_CXXFLAGS += -xarch=sse2 -xO4 endif endif -PremultiplyTables.h: $(srcdir)/genTables.py +DeprecatedPremultiplyTables.h: $(srcdir)/genTables.py $(PYTHON) $(srcdir)/genTables.py diff --git a/gfx/thebes/genTables.py b/gfx/thebes/genTables.py index d3a924ff4b8..cf8b3487d8d 100644 --- a/gfx/thebes/genTables.py +++ b/gfx/thebes/genTables.py @@ -3,7 +3,7 @@ def table_generator(f): return ",\n".join([", ".join(["0x%2.2x" % h for h in [f(i) for i in range(r,r+16)]]) for r in range(0, 65536, 16)]) -with open("PremultiplyTables.h", "w") as f: +with open("DeprecatedPremultiplyTables.h", "w") as f: f.write("const uint8_t gfxUtils::sPremultiplyTable[256*256] = {\n"); f.write(table_generator(lambda i: ((i / 256) * (i % 256) + 254) / 255) + "\n") f.write("};\n"); diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 41a5b6530ee..93e2a8d4f3c 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -22,7 +22,7 @@ using namespace mozilla; using namespace mozilla::layers; using namespace mozilla::gfx; -#include "PremultiplyTables.h" +#include "DeprecatedPremultiplyTables.h" static const uint8_t PremultiplyValue(uint8_t a, uint8_t v) { return gfxUtils::sPremultiplyTable[a*256+v]; diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index a662ae35bf9..dc0e6eb0d85 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -628,7 +628,7 @@ gfxWindowsPlatform::CreatePlatformFontList() #ifdef CAIRO_HAS_DWRITE_FONT // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd // crashers so blacklist them altogether - if (IsWin7RTMOrLater() && GetDWriteFactory()) { + if (IsNotWin7PreRTM() && GetDWriteFactory()) { pfl = new gfxDWriteFontList(); if (NS_SUCCEEDED(pfl->InitFontList())) { return pfl; diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index 27ff45afb1c..8559f1c3037 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -268,7 +268,7 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' GENERATED_FILES = [ - 'PremultiplyTables.h', + 'DeprecatedPremultiplyTables.h', ] LOCAL_INCLUDES += [ diff --git a/ipc/chromium/src/third_party/libevent-use-non-deprecated-syscalls.patch b/ipc/chromium/src/third_party/libevent-use-non-deprecated-syscalls.patch new file mode 100644 index 00000000000..17319a19b4b --- /dev/null +++ b/ipc/chromium/src/third_party/libevent-use-non-deprecated-syscalls.patch @@ -0,0 +1,43 @@ +--- + ipc/chromium/src/third_party/libevent/epoll_sub.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +--- mozilla-central.orig/ipc/chromium/src/third_party/libevent/epoll_sub.c ++++ mozilla-central/ipc/chromium/src/third_party/libevent/epoll_sub.c +@@ -29,15 +29,24 @@ + #include + #include + #include + #include + #include ++#include + + int + epoll_create(int size) + { ++#if !defined(__NR_epoll_create) && defined(__NR_epoll_create1) ++ if (size <= 0) { ++ errno = EINVAL; ++ return -1; ++ } ++ return (syscall(__NR_epoll_create1, 0)); ++#else + return (syscall(__NR_epoll_create, size)); ++#endif + } + + int + epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) + { +@@ -46,7 +55,11 @@ epoll_ctl(int epfd, int op, int fd, stru + } + + int + epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) + { ++#if !defined(__NR_epoll_wait) && defined(__NR_epoll_pwait) ++ return (syscall(__NR_epoll_pwait, epfd, events, maxevents, timeout, NULL, 0)); ++#else + return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout)); ++#endif + } diff --git a/ipc/chromium/src/third_party/libevent/README.mozilla b/ipc/chromium/src/third_party/libevent/README.mozilla index 10c6845ffab..3e3e78d023f 100644 --- a/ipc/chromium/src/third_party/libevent/README.mozilla +++ b/ipc/chromium/src/third_party/libevent/README.mozilla @@ -13,3 +13,5 @@ These files are taken from libevent-2.0.21-stable built on the development envir 3. Apply "add mac-arc4random-buf.patch", which removes some bad OS X compatibility code. This will allow libevent to compile on all supported versions of OS X. 4. Apply "openbsd-no-arc4random_addrandom.patch", which fixes the build on OpenBSD (which doesnt provide arc4random_addrandom anymore, see #931354) + +5. Apply "libevent-use-non-deprecated-syscalls.patch", which fixes the build on AArch64 architecture (which does not provide deprecated syscalls) diff --git a/ipc/chromium/src/third_party/libevent/epoll_sub.c b/ipc/chromium/src/third_party/libevent/epoll_sub.c index 3738b26bf1e..facbc09fac8 100644 --- a/ipc/chromium/src/third_party/libevent/epoll_sub.c +++ b/ipc/chromium/src/third_party/libevent/epoll_sub.c @@ -31,11 +31,20 @@ #include #include #include +#include int epoll_create(int size) { +#if !defined(__NR_epoll_create) && defined(__NR_epoll_create1) + if (size <= 0) { + errno = EINVAL; + return -1; + } + return (syscall(__NR_epoll_create1, 0)); +#else return (syscall(__NR_epoll_create, size)); +#endif } int @@ -48,5 +57,9 @@ epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) { +#if !defined(__NR_epoll_wait) && defined(__NR_epoll_pwait) + return (syscall(__NR_epoll_pwait, epfd, events, maxevents, timeout, NULL, 0)); +#else return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout)); +#endif } diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index d308cd51d36..933e62974f2 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -138,7 +138,6 @@ class Float32x4Defn { const JSFunctionSpec js::Float32x4Defn::TypeDescriptorMethods[] = { JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0), - JS_SELF_HOSTED_FN("handle", "HandleCreate", 2, 0), JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0), JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0), JS_FS_END @@ -160,7 +159,6 @@ const JSFunctionSpec js::Float32x4Defn::TypedDatumMethods[] = { const JSFunctionSpec js::Int32x4Defn::TypeDescriptorMethods[] = { JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0), - JS_SELF_HOSTED_FN("handle", "HandleCreate", 2, 0), JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0), JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0), JS_FS_END, diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 0feb9a87a62..c741983b180 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -216,7 +216,6 @@ const Class js::ScalarTypeDescr::class_ = { const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = { JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0), - {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"}, {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"}, {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"}, JS_FS_END @@ -317,7 +316,6 @@ const Class js::ReferenceTypeDescr::class_ = { const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = { JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0), - {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"}, {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"}, {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"}, JS_FS_END @@ -467,7 +465,6 @@ const JSPropertySpec ArrayMetaTypeDescr::typeObjectProperties[] = { }; const JSFunctionSpec ArrayMetaTypeDescr::typeObjectMethods[] = { - {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"}, {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"}, JS_FN("dimension", UnsizedArrayTypeDescr::dimension, 1, 0), JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0), @@ -756,7 +753,6 @@ const JSPropertySpec StructMetaTypeDescr::typeObjectProperties[] = { }; const JSFunctionSpec StructMetaTypeDescr::typeObjectMethods[] = { - {"handle", {nullptr, nullptr}, 2, 0, "HandleCreate"}, {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"}, JS_SELF_HOSTED_FN("toSource", "DescrToSourceMethod", 0, 0), {"equivalent", {nullptr, nullptr}, 1, 0, "TypeDescrEquivalent"}, @@ -1250,24 +1246,6 @@ GlobalObject::initTypedObjectModule(JSContext *cx, Handle global) JSPROP_READONLY | JSPROP_PERMANENT)) return nullptr; - // Handle - - RootedObject handle(cx, NewBuiltinClassInstance(cx, &JSObject::class_)); - if (!module) - return nullptr; - - if (!JS_DefineFunctions(cx, handle, TypedHandle::handleStaticMethods)) - return nullptr; - - RootedValue handleValue(cx, ObjectValue(*handle)); - if (!JSObject::defineProperty(cx, module, cx->names().Handle, - handleValue, - nullptr, nullptr, - JSPROP_READONLY | JSPROP_PERMANENT)) - { - return nullptr; - } - // Everything is setup, install module on the global object: RootedValue moduleValue(cx, ObjectValue(*module)); global->setConstructor(JSProto_TypedObject, moduleValue); diff --git a/js/src/builtin/TypedObject.js b/js/src/builtin/TypedObject.js index d2b0af721ea..40856d5c928 100644 --- a/js/src/builtin/TypedObject.js +++ b/js/src/builtin/TypedObject.js @@ -181,6 +181,12 @@ TypedObjectPointer.prototype.reset = function(inPtr) { return this; }; +TypedObjectPointer.prototype.bump = function(size) { + assert(TO_INT32(this.offset) === this.offset, "current offset not int"); + assert(TO_INT32(size) === size, "size not int"); + this.offset += size; +} + TypedObjectPointer.prototype.kind = function() { return DESCR_KIND(this.descr); } @@ -312,8 +318,7 @@ TypedObjectPointer.prototype.moveToFieldIndex = function(index) { // Reifies the value referenced by the pointer, meaning that it // returns a new object pointing at the value. If the value is // a scalar, it will return a JS number, but otherwise the reified -// result will be a typed object or handle, depending on the type -// of the ptr's datum. +// result will be a datum of the same class as the ptr's datum. TypedObjectPointer.prototype.get = function() { assert(ObjectIsAttached(this.datum), "get() called with unattached datum"); @@ -328,10 +333,8 @@ TypedObjectPointer.prototype.get = function() { return this.getX4(); case JS_TYPEREPR_SIZED_ARRAY_KIND: - return NewDerivedTypedDatum(this.descr, this.datum, this.offset); - case JS_TYPEREPR_STRUCT_KIND: - return NewDerivedTypedDatum(this.descr, this.datum, this.offset); + return this.getDerived(); case JS_TYPEREPR_UNSIZED_ARRAY_KIND: assert(false, "Unhandled repr kind: " + this.kind()); @@ -341,6 +344,12 @@ TypedObjectPointer.prototype.get = function() { return undefined; } +TypedObjectPointer.prototype.getDerived = function() { + assert(!TypeDescrIsSimpleType(this.descr), + "getDerived() used with simple type"); + return NewDerivedTypedDatum(this.descr, this.datum, this.offset); +} + TypedObjectPointer.prototype.getScalar = function() { var type = DESCR_TYPE(this.descr); switch (type) { @@ -726,99 +735,6 @@ function TypedArrayRedimension(newArrayType) { return NewDerivedTypedDatum(newArrayType, this, 0); } -/////////////////////////////////////////////////////////////////////////// -// Handles -// -// Note: these methods are directly invokable by users and so must be -// defensive. - -// This is the `handle([obj, [...path]])` method on type objects. -// User exposed! -// -// FIXME bug 929656 -- label algorithms with steps from the spec -function HandleCreate(obj, ...path) { - if (!IsObject(this) || !ObjectIsTypeDescr(this)) - ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Type", "handle", "value"); - - switch (DESCR_KIND(this)) { - case JS_TYPEREPR_SCALAR_KIND: - case JS_TYPEREPR_REFERENCE_KIND: - case JS_TYPEREPR_X4_KIND: - case JS_TYPEREPR_SIZED_ARRAY_KIND: - case JS_TYPEREPR_STRUCT_KIND: - break; - - case JS_TYPEREPR_UNSIZED_ARRAY_KIND: - ThrowError(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED); - } - - var handle = NewTypedHandle(this); - - if (obj !== undefined) - HandleMoveInternal(handle, obj, path); - - return handle; -} - -// Handle.move: user exposed! -// FIXME bug 929656 -- label algorithms with steps from the spec -function HandleMove(handle, obj, ...path) { - if (!IsObject(handle) || !ObjectIsTypedHandle(handle)) - ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value); - - HandleMoveInternal(handle, obj, path); -} - -function HandleMoveInternal(handle, obj, path) { - assert(IsObject(handle) && ObjectIsTypedHandle(handle), - "HandleMoveInternal: not typed handle"); - - if (!IsObject(obj) || !ObjectIsTypedDatum(obj)) - ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", "value"); - - var ptr = TypedObjectPointer.fromTypedDatum(obj); - for (var i = 0; i < path.length; i++) - ptr.moveTo(path[i]); - - // Check that the new destination is equivalent to the handle type. - if (DESCR_TYPE_REPR(ptr.descr) !== DATUM_TYPE_REPR(handle)) - ThrowError(JSMSG_TYPEDOBJECT_HANDLE_BAD_TYPE); - - AttachHandle(handle, ptr.datum, ptr.offset) -} - -// Handle.get: user exposed! -// FIXME bug 929656 -- label algorithms with steps from the spec -function HandleGet(handle) { - if (!IsObject(handle) || !ObjectIsTypedHandle(handle)) - ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value); - - if (!ObjectIsAttached(handle)) - ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); - - var ptr = TypedObjectPointer.fromTypedDatum(handle); - return ptr.get(); -} - -// Handle.set: user exposed! -// FIXME bug 929656 -- label algorithms with steps from the spec -function HandleSet(handle, value) { - if (!IsObject(handle) || !ObjectIsTypedHandle(handle)) - ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Handle", "set", typeof value); - - if (!ObjectIsAttached(handle)) - ThrowError(JSMSG_TYPEDOBJECT_HANDLE_UNATTACHED); - - var ptr = TypedObjectPointer.fromTypedDatum(handle); - ptr.set(value); -} - -// Handle.isHandle: user exposed! -// FIXME bug 929656 -- label algorithms with steps from the spec -function HandleTest(obj) { - return IsObject(obj) && ObjectIsTypedHandle(obj); -} - /////////////////////////////////////////////////////////////////////////// // X4 @@ -953,7 +869,6 @@ function TypedObjectArrayTypeFrom(a, b, c) { // supporting an explicit depth of 1; while for typed input array, // the expectation is explicit depth. - if (untypedInput) { var explicitDepth = (b === 1); if (explicitDepth && IsCallable(c)) @@ -1168,25 +1083,25 @@ function BuildTypedSeqImpl(arrayType, len, depth, func) { indices[i] = 0; } - var handle = callFunction(HandleCreate, grainType); - var offset = 0; + var grainTypeIsSimple = TypeDescrIsSimpleType(grainType); + var size = DESCR_SIZE(grainType); + var outPointer = new TypedObjectPointer(grainType, result, 0); for (i = 0; i < totalLength; i++) { - // Position handle to point at &result[...indices] - AttachHandle(handle, result, offset); + // Position out-pointer to point at &result[...indices], if appropriate. + var userOutPointer = (grainTypeIsSimple + ? undefined + : outPointer.getDerived()); - // Invoke func(...indices, out) - callFunction(std_Array_push, indices, handle); - var r = callFunction(std_Function_apply, func, void 0, indices); + // Invoke func(...indices, userOutPointer) and store the result + callFunction(std_Array_push, indices, userOutPointer); + var r = callFunction(std_Function_apply, func, undefined, indices); callFunction(std_Array_pop, indices); + if (r !== undefined) + outPointer.set(r); // result[...indices] = r; - if (r !== undefined) { - // result[...indices] = r; - AttachHandle(handle, result, offset); // (func might have moved handle) - HandleSet(handle, r); // *handle = r - } // Increment indices. - offset += DESCR_SIZE(grainType); IncrementIterationSpace(indices, iterationSpace); + outPointer.bump(size); } return result; @@ -1261,35 +1176,32 @@ function MapUntypedSeqImpl(inArray, outputType, maybeFunc) { // Create a zeroed instance with no data var result = outputType.variable ? new outputType(inArray.length) : new outputType(); - var outHandle = callFunction(HandleCreate, outGrainType); var outUnitSize = DESCR_SIZE(outGrainType); + var outGrainTypeIsSimple = TypeDescrIsSimpleType(outGrainType); + var outPointer = new TypedObjectPointer(outGrainType, result, 0); // Core of map computation starts here (comparable to // DoMapTypedSeqDepth1 and DoMapTypedSeqDepthN below). - var offset = 0; for (var i = 0; i < outLength; i++) { // In this loop, since depth is 1, "indices" denotes singleton array [i]. - // Adjust handle to point at &array[...indices] for result array. - AttachHandle(outHandle, result, offset); - if (i in inArray) { // Check for holes (only needed for untyped case). - - // Extract element value (no input handles for untyped case). + // Extract element value. var element = inArray[i]; - // Invoke: var r = func(element, ...indices, collection, out); - var r = func(element, i, inArray, outHandle); + // Create out pointer to point at &array[...indices] for result array. + var out = (outGrainTypeIsSimple ? undefined : outPointer.getDerived()); - if (r !== undefined) { - AttachHandle(outHandle, result, offset); // (func could move handle) - HandleSet(outHandle, r); // *handle = r; (i.e. result[i] = r). - } + // Invoke: var r = func(element, ...indices, collection, out); + var r = func(element, i, inArray, out); + + if (r !== undefined) + outPointer.set(r); // result[i] = r } // Update offset and (implicitly) increment indices. - offset += outUnitSize; + outPointer.bump(outUnitSize); } return result; @@ -1320,40 +1232,33 @@ function MapTypedSeqImpl(inArray, depth, outputType, func) { // Create a zeroed instance with no data var result = outputType.variable ? new outputType(inArray.length) : new outputType(); - var inHandle = callFunction(HandleCreate, inGrainType); - var outHandle = callFunction(HandleCreate, outGrainType); + var inGrainTypeIsSimple = TypeDescrIsSimpleType(inGrainType); + var outGrainTypeIsSimple = TypeDescrIsSimpleType(outGrainType); + + var inPointer = new TypedObjectPointer(inGrainType, inArray, 0); + var outPointer = new TypedObjectPointer(outGrainType, result, 0); + var inUnitSize = DESCR_SIZE(inGrainType); var outUnitSize = DESCR_SIZE(outGrainType); - var inGrainTypeIsSimple = TypeDescrIsSimpleType(inGrainType); - // Bug 956914: add additional variants for depth = 2, 3, etc. function DoMapTypedSeqDepth1() { - var inOffset = 0; - var outOffset = 0; - for (var i = 0; i < totalLength; i++) { // In this loop, since depth is 1, "indices" denotes singleton array [i]. - // Adjust handles to point at &array[...indices] for in and out array. - AttachHandle(inHandle, inArray, inOffset); - AttachHandle(outHandle, result, outOffset); - - // Extract element value if simple; if not, handle acts as array element. - var element = (inGrainTypeIsSimple ? HandleGet(inHandle) : inHandle); + // Prepare input element/handle and out pointer + var element = inPointer.get(); + var out = (outGrainTypeIsSimple ? undefined : outPointer.getDerived()); // Invoke: var r = func(element, ...indices, collection, out); - var r = func(element, i, inArray, outHandle); - - if (r !== undefined) { - AttachHandle(outHandle, result, outOffset); // (func could move handle) - HandleSet(outHandle, r); // *handle = r; (i.e. result[i] = r). - } + var r = func(element, i, inArray, out); + if (r !== undefined) + outPointer.set(r); // result[i] = r // Update offsets and (implicitly) increment indices. - inOffset += inUnitSize; - outOffset += outUnitSize; + inPointer.bump(inUnitSize); + outPointer.bump(outUnitSize); } return result; @@ -1362,30 +1267,22 @@ function MapTypedSeqImpl(inArray, depth, outputType, func) { function DoMapTypedSeqDepthN() { var indices = new Uint32Array(depth); - var inOffset = 0; - var outOffset = 0; for (var i = 0; i < totalLength; i++) { - // Adjust handles to point at &array[...indices] for in and out array. - AttachHandle(inHandle, inArray, inOffset); - AttachHandle(outHandle, result, outOffset); - - // Extract element value if simple; if not, handle acts as array element. - var element = (inGrainTypeIsSimple ? HandleGet(inHandle) : inHandle); + // Prepare input element and out pointer + var element = inPointer.get(); + var out = (outGrainTypeIsSimple ? undefined : outPointer.getDerived()); // Invoke: var r = func(element, ...indices, collection, out); var args = [element]; callFunction(std_Function_apply, std_Array_push, args, indices); - callFunction(std_Array_push, args, inArray, outHandle); + callFunction(std_Array_push, args, inArray, out); var r = callFunction(std_Function_apply, func, void 0, args); - - if (r !== undefined) { - AttachHandle(outHandle, result, outOffset); // (func could move handle) - HandleSet(outHandle, r); // *handle = r - } + if (r !== undefined) + outPointer.set(r); // result[...indices] = r // Update offsets and explicitly increment indices. - inOffset += inUnitSize; - outOffset += outUnitSize; + inPointer.bump(inUnitSize); + outPointer.bump(outUnitSize); IncrementIterationSpace(indices, iterationSpace); } @@ -1481,14 +1378,15 @@ function FilterTypedSeqImpl(array, func) { var elementType = arrayType.elementType; var flags = new Uint8Array(NUM_BYTES(array.length)); - var handle = callFunction(HandleCreate, elementType); var count = 0; + var size = DESCR_SIZE(elementType); + var inPointer = new TypedObjectPointer(elementType, array, 0); for (var i = 0; i < array.length; i++) { - HandleMove(handle, array, i); - if (func(HandleGet(handle), i, array)) { + if (func(inPointer.get(), i, array)) { SET_BIT(flags, i); count++; } + inPointer.bump(size); } var resultType = (arrayType.variable ? arrayType : arrayType.unsized); diff --git a/js/src/configure.in b/js/src/configure.in index f27f5ade0c5..da9767c6161 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -826,6 +826,24 @@ darwin*) linux*) HOST_OS_ARCH=Linux ;; +kfreebsd*-gnu) + HOST_OS_ARCH=GNU_kFreeBSD + ;; +gnu*) + HOST_OS_ARCH=GNU + ;; +dragonfly*) + HOST_OS_ARCH=DragonFly + ;; +freebsd*) + HOST_OS_ARCH=FreeBSD + ;; +netbsd*) + HOST_OS_ARCH=NetBSD + ;; +openbsd*) + HOST_OS_ARCH=OpenBSD + ;; solaris*) HOST_OS_ARCH=SunOS SOLARIS_SUNPRO_CC= diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 5713e0399ba..4d9c1cdd3a6 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -5138,7 +5138,7 @@ StructType::BuildFieldsArray(JSContext* cx, JSObject* obj) return nullptr; } - RootedObject fieldsProp(cx, JS_NewArrayObject(cx, len, fieldsVec.begin())); + RootedObject fieldsProp(cx, JS_NewArrayObject(cx, fieldsVec)); if (!fieldsProp) return nullptr; @@ -5946,7 +5946,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JS::CallArgs args) for (size_t i = 0; i < len; ++i) vec[i] = JS::ObjectValue(*fninfo->mArgTypes[i]); - argTypes = JS_NewArrayObject(cx, len, vec.begin()); + argTypes = JS_NewArrayObject(cx, vec); if (!argTypes) return false; } diff --git a/js/src/gdb/tests/test-Root.cpp b/js/src/gdb/tests/test-Root.cpp index 0be4901d3dc..86f33cc5271 100644 --- a/js/src/gdb/tests/test-Root.cpp +++ b/js/src/gdb/tests/test-Root.cpp @@ -25,7 +25,7 @@ FRAGMENT(Root, handle) { FRAGMENT(Root, HeapSlot) { JS::Rooted plinth(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "plinth"))); - JS::Rooted array(cx, JS_NewArrayObject(cx, 1, plinth.address())); + JS::Rooted array(cx, JS_NewArrayObject(cx, plinth)); breakpoint(); diff --git a/js/src/jit-test/tests/TypedObject/gcunattachedhandle.js b/js/src/jit-test/tests/TypedObject/gcunattachedhandle.js deleted file mode 100644 index 8849c9a7473..00000000000 --- a/js/src/jit-test/tests/TypedObject/gcunattachedhandle.js +++ /dev/null @@ -1,13 +0,0 @@ -// Test that we can trace a unattached handle. - -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -if (!this.hasOwnProperty("TypedObject")) - quit(); - -var Object = TypedObject.Object; -var handle0 = Object.handle(); -gc(); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index f56a1877647..73aa3496d5e 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1926,7 +1926,6 @@ ICCompare_Fallback::Compiler::generateStubCode(MacroAssembler &masm) masm.pushValue(R0); masm.push(BaselineStubReg); masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); - return tailCallVM(DoCompareFallbackInfo, masm); } diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 825ce701b1f..1f43a68dd16 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -218,7 +218,7 @@ jit::BaselineCompile(JSContext *cx, HandleScript script) { JS_ASSERT(!script->hasBaselineScript()); JS_ASSERT(script->canBaselineCompile()); - + JS_ASSERT(IsBaselineEnabled(cx)); LifoAlloc alloc(BASELINE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE); script->ensureNonLazyCanonicalFunction(cx); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 2681e5c652d..32443c743ef 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -2147,8 +2147,11 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun, if (!script) return false; - if (!script->compileAndGo() || !script->canBaselineCompile()) + if (!jit::IsIonEnabled(cx) || !jit::IsBaselineEnabled(cx) || + !script->compileAndGo() || !script->canBaselineCompile()) + { return true; + } static const uint32_t MAX_SCRIPT_SIZE = 2000; if (script->length() > MAX_SCRIPT_SIZE) diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 6d8638c2b2a..b6ebe09ddeb 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -3493,6 +3493,7 @@ MacroAssemblerARMCompat::setupABICall(uint32_t args) #ifdef JS_CODEGEN_ARM_HARDFP usedIntSlots_ = 0; usedFloatSlots_ = 0; + usedFloat32_ = false; padding_ = 0; #else usedSlots_ = 0; @@ -3535,17 +3536,33 @@ MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Type type) switch (type) { case MoveOp::FLOAT32: case MoveOp::DOUBLE: { + // N.B. this isn't a limitation of the ABI, it is a limitation of the compiler right now. + // There isn't a good way to handle odd numbered single registers, so everything goes to hell + // when we try. Current fix is to never use more than one float in a function call. + // Fix coming along with complete float32 support in bug 957504. + JS_ASSERT(!usedFloat32_); + if (type == MoveOp::FLOAT32) + usedFloat32_ = true; FloatRegister fr; if (GetFloatArgReg(usedIntSlots_, usedFloatSlots_, &fr)) { if (from.isFloatReg() && from.floatReg() == fr) { // Nothing to do; the value is in the right register already + usedFloatSlots_++; + if (type == MoveOp::FLOAT32) + passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32; + else + passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Double; return; } to = MoveOperand(fr); } else { // If (and only if) the integer registers have started spilling, do we // need to take the register's alignment into account - uint32_t disp = GetFloatArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_); + uint32_t disp = INT_MAX; + if (type == MoveOp::FLOAT32) + disp = GetFloat32ArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_); + else + disp = GetDoubleArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_); to = MoveOperand(sp, disp); } usedFloatSlots_++; @@ -3560,6 +3577,8 @@ MacroAssemblerARMCompat::passABIArg(const MoveOperand &from, MoveOp::Type type) if (GetIntArgReg(usedIntSlots_, usedFloatSlots_, &r)) { if (from.isGeneralReg() && from.reg() == r) { // Nothing to do; the value is in the right register already + usedIntSlots_++; + passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_General; return; } to = MoveOperand(r); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 81f28d4e81b..a12cfd3360b 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -448,6 +448,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM #ifdef JS_CODEGEN_ARM_HARDFP uint32_t usedIntSlots_; uint32_t usedFloatSlots_; + bool usedFloat32_; uint32_t padding_; #else // ARM treats arguments as a vector in registers/memory, that looks like: diff --git a/js/src/jsapi-tests/testAddPropertyPropcache.cpp b/js/src/jsapi-tests/testAddPropertyPropcache.cpp index 844ed96afc9..e9c1d9accbb 100644 --- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp +++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp @@ -42,7 +42,7 @@ BEGIN_TEST(testAddPropertyHook) JS_InitClass(cx, global, obj, &AddPropertyClass, nullptr, 0, nullptr, nullptr, nullptr, nullptr); - obj = JS_NewArrayObject(cx, 0, nullptr); + obj = JS_NewArrayObject(cx, 0); CHECK(obj); JS::RootedValue arr(cx, OBJECT_TO_JSVAL(obj)); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 15a0667eb80..97ca884a16c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -3774,16 +3774,24 @@ JS_SetReservedSlot(JSObject *obj, uint32_t index, Value value) } JS_PUBLIC_API(JSObject *) -JS_NewArrayObject(JSContext *cx, int length, jsval *vector) +JS_NewArrayObject(JSContext *cx, const JS::HandleValueArray& contents) { - AutoArrayRooter tvr(cx, length, vector); - JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); AssertHeapIsIdle(cx); CHECK_REQUEST(cx); - assertSameCompartment(cx, JSValueArray(vector, vector ? (uint32_t)length : 0)); - return NewDenseCopiedArray(cx, (uint32_t)length, vector); + assertSameCompartment(cx, contents); + return NewDenseCopiedArray(cx, contents.length(), contents.begin()); +} + +JS_PUBLIC_API(JSObject *) +JS_NewArrayObject(JSContext *cx, size_t length) +{ + JS_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + + return NewDenseAllocatedArray(cx, length); } JS_PUBLIC_API(bool) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 085ad475144..e7092ed4c0b 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -626,7 +626,7 @@ class HandleValueArray return HandleValueArray(len, elements); } - static HandleValueArray subarray(const AutoValueVector& values, size_t startIndex, size_t len) { + static HandleValueArray subarray(const HandleValueArray& values, size_t startIndex, size_t len) { JS_ASSERT(startIndex + len <= values.length()); return HandleValueArray(len, values.begin() + startIndex); } @@ -3070,7 +3070,10 @@ JS_DeleteUCProperty2(JSContext *cx, JS::HandleObject obj, const jschar *name, si bool *succeeded); extern JS_PUBLIC_API(JSObject *) -JS_NewArrayObject(JSContext *cx, int length, jsval *vector); +JS_NewArrayObject(JSContext *cx, const JS::HandleValueArray& contents); + +extern JS_PUBLIC_API(JSObject *) +JS_NewArrayObject(JSContext *cx, size_t length); extern JS_PUBLIC_API(bool) JS_IsArrayObject(JSContext *cx, JS::HandleValue value); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 5b3f96b3df7..62ff1814799 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2336,7 +2336,7 @@ GetPDA(JSContext *cx, unsigned argc, jsval *vp) return true; } - RootedObject aobj(cx, JS_NewArrayObject(cx, 0, nullptr)); + RootedObject aobj(cx, JS_NewArrayObject(cx, 0)); if (!aobj) return false; args.rval().setObject(*aobj); @@ -5397,7 +5397,7 @@ BindScriptArgs(JSContext *cx, JSObject *obj_, OptionParser *op) MultiStringRange msr = op->getMultiStringArg("scriptArgs"); RootedObject scriptArgs(cx); - scriptArgs = JS_NewArrayObject(cx, 0, nullptr); + scriptArgs = JS_NewArrayObject(cx, 0); if (!scriptArgs) return false; diff --git a/js/src/shell/jsheaptools.cpp b/js/src/shell/jsheaptools.cpp index 2727560efd4..35737b56ff2 100644 --- a/js/src/shell/jsheaptools.cpp +++ b/js/src/shell/jsheaptools.cpp @@ -511,7 +511,7 @@ ReferenceFinder::addReferrer(jsval referrerArg, Path *path) return false; if (v.isUndefined()) { /* Create an array to accumulate referents under this path. */ - JSObject *array = JS_NewArrayObject(context, 1, referrer.address()); + JSObject *array = JS_NewArrayObject(context, referrer); if (!array) return false; v.setObject(*array); diff --git a/js/src/tests/ecma_6/TypedObject/handle.js b/js/src/tests/ecma_6/TypedObject/handle.js deleted file mode 100644 index 33c859a0c05..00000000000 --- a/js/src/tests/ecma_6/TypedObject/handle.js +++ /dev/null @@ -1,60 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) - -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -var BUGNUMBER = 898342; -var summary = 'Handles'; - -var T = TypedObject; - -function runTests() { - var Point = T.float32.array(3); - var Line = new T.StructType({from: Point, to: Point}); - var Lines = Line.array(3); - - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - var handle = Lines.handle(lines); - var handle0 = Line.handle(lines, 0); - var handle2 = Line.handle(lines, 2); - - // Reads from handles should see the correct data: - assertEq(handle[0].from[0], 1); - assertEq(handle0.from[0], 1); - assertEq(handle2.from[0], 13); - - // Writes to handles should modify the original: - handle2.from[0] = 22; - assertEq(lines[2].from[0], 22); - - // Reads from handles should see the updated data: - assertEq(handle[0].from[0], 1); - assertEq(handle0.from[0], 1); - assertEq(handle2.from[0], 22); - - // isHandle, when called on nonsense, returns false: - assertEq(T.Handle.isHandle(22), false); - assertEq(T.Handle.isHandle({}), false); - - // Derived handles should remain handles: - assertEq(T.Handle.isHandle(lines), false); - assertEq(T.Handle.isHandle(lines[0]), false); - assertEq(T.Handle.isHandle(lines[0].from), false); - assertEq(T.Handle.isHandle(handle), true); - assertEq(T.Handle.isHandle(handle[0]), true); - assertEq(T.Handle.isHandle(handle[0].from), true); - - reportCompare(true, true); - print("Tests complete"); -} - -runTests(); - - diff --git a/js/src/tests/ecma_6/TypedObject/handle_get_set.js b/js/src/tests/ecma_6/TypedObject/handle_get_set.js deleted file mode 100644 index 4ad6f21c0de..00000000000 --- a/js/src/tests/ecma_6/TypedObject/handle_get_set.js +++ /dev/null @@ -1,79 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) - -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -var BUGNUMBER = 898342; -var summary = 'Handle Move'; - -var T = TypedObject; - -var Point = T.float32.array(3); -var Line = new T.StructType({from: Point, to: Point}); -var Lines = Line.array(3); - -var Objects = T.Object.array(3); - -function runTests() { - function testHandleGetSetWithScalarType() { - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - var handle = T.float32.handle(lines, 0, "to", 1); - assertEq(T.Handle.get(handle), 5); - T.Handle.set(handle, 22); - assertEq(T.Handle.get(handle), 22); - assertEq(lines[0].to[1], 22); - } - testHandleGetSetWithScalarType(); - - function testHandleGetSetWithObjectType() { - var one = {x: 1}; - var two = {x: 2}; - var three = {x: 3}; - var objects = new Objects([one, two, three]); - - var handle = T.Object.handle(objects, 0); - assertEq(T.Handle.get(handle), one); - T.Handle.set(handle, three); - assertEq(T.Handle.get(handle), three); - assertEq(objects[0], three); - - T.Handle.move(handle, objects, 1); - assertEq(T.Handle.get(handle), two); - } - testHandleGetSetWithScalarType(); - - function testHandleGetSetWithComplexType() { - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - var handle = Point.handle(lines, 0, "to"); - - T.Handle.set(handle, [22, 23, 24]); - - assertEq(handle[0], 22); - assertEq(handle[1], 23); - assertEq(handle[2], 24); - - assertEq(T.Handle.get(handle)[0], 22); - assertEq(T.Handle.get(handle)[1], 23); - assertEq(T.Handle.get(handle)[2], 24); - } - testHandleGetSetWithComplexType(); - - reportCompare(true, true); - print("Tests complete"); -} - -runTests(); - - diff --git a/js/src/tests/ecma_6/TypedObject/handle_move.js b/js/src/tests/ecma_6/TypedObject/handle_move.js deleted file mode 100644 index 2e1cf52ef7f..00000000000 --- a/js/src/tests/ecma_6/TypedObject/handle_move.js +++ /dev/null @@ -1,162 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) - -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -var BUGNUMBER = 898342; -var summary = 'Handle Move'; - -var T = TypedObject; - -var Point = T.float32.array(3); -var Line = new T.StructType({from: Point, to: Point}); -var Lines = Line.array(3); - -function runTests() { - function testHandleToPoint() { - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - function allPoints(lines, func) { - var handle = Point.handle(); - for (var i = 0; i < lines.length; i++) { - T.Handle.move(handle, lines, i, "from"); - func(handle); - - T.Handle.move(handle, lines, i, "to"); - func(handle); - } - } - - // Iterate over all ponts and mutate them in place: - allPoints(lines, function(p) { - p[0] += 100; - p[1] += 200; - p[2] += 300; - }); - - // Spot check the results - assertEq(lines[0].from[0], 101); - assertEq(lines[1].to[1], 211); - assertEq(lines[2].to[2], 318); - } - testHandleToPoint(); - - function testHandleToFloat() { - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - function allPoints(lines, func) { - var handle = T.float32.handle(); - for (var i = 0; i < lines.length; i++) { - T.Handle.move(handle, lines, i, "from", 0); - func(handle); - - T.Handle.move(handle, lines, i, "from", 1); - func(handle); - - T.Handle.move(handle, lines, i, "from", 2); - func(handle); - - T.Handle.move(handle, lines, i, "to", 0); - func(handle); - - T.Handle.move(handle, lines, i, "to", 1); - func(handle); - - T.Handle.move(handle, lines, i, "to", 2); - func(handle); - } - } - - // Iterate over all ponts and mutate them in place: - allPoints(lines, function(p) { - T.Handle.set(p, T.Handle.get(p) + 100); - }); - - // Spot check the results - assertEq(lines[0].from[0], 101); - assertEq(lines[1].to[1], 111); - assertEq(lines[2].to[2], 118); - } - testHandleToFloat(); - - function testHandleToEquivalentType() { - var Point2 = T.float32.array(3); - - assertEq(Point.equivalent(Point2), true); - - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - var handle = Point2.handle(lines, 0, "to"); - assertEq(handle[0], 4); - assertEq(handle[1], 5); - assertEq(handle[2], 6); - } - testHandleToEquivalentType(); - - function testHandleMoveToIllegalType() { - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - // Moving a handle to a value of incorrect type should report an error: - assertThrowsInstanceOf(function() { - Line.handle(lines); - }, TypeError, "handle moved to destination of incorrect type"); - assertThrowsInstanceOf(function() { - var h = Line.handle(); - T.Handle.move(h, lines); - }, TypeError, "handle moved to destination of incorrect type"); - assertThrowsInstanceOf(function() { - var h = T.float32.handle(); - T.Handle.move(h, lines, 0); - }, TypeError, "handle moved to destination of incorrect type"); - } - testHandleMoveToIllegalType(); - - function testHandleMoveToIllegalProperty() { - var lines = new Lines([ - {from: [1, 2, 3], to: [4, 5, 6]}, - {from: [7, 8, 9], to: [10, 11, 12]}, - {from: [13, 14, 15], to: [16, 17, 18]} - ]); - - assertThrowsInstanceOf(function() { - var h = Point.handle(); - T.Handle.move(h, lines, 0, "foo"); - }, TypeError, "No such property: foo"); - - assertThrowsInstanceOf(function() { - var h = Point.handle(); - T.Handle.move(h, lines, 22, "to"); - }, TypeError, "No such property: 22"); - - assertThrowsInstanceOf(function() { - var h = Point.handle(); - T.Handle.move(h, lines, -100, "to"); - }, TypeError, "No such property: -100"); - } - testHandleMoveToIllegalProperty(); - - reportCompare(true, true); - print("Tests complete"); -} - -runTests(); - - diff --git a/js/src/tests/ecma_6/TypedObject/handle_unattached.js b/js/src/tests/ecma_6/TypedObject/handle_unattached.js deleted file mode 100644 index 579951a364d..00000000000 --- a/js/src/tests/ecma_6/TypedObject/handle_unattached.js +++ /dev/null @@ -1,49 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) - -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/licenses/publicdomain/ - */ - -var BUGNUMBER = 898342; -var summary = 'Unattached handles'; - -var T = TypedObject; - -function runTests() { - var Line = new T.StructType({from: T.uint8, to: T.uint8}); - var Lines = Line.array(3); - - // Create unattached handle to array, struct: - var handle = Lines.handle(); - var handle0 = Line.handle(); - - // Accessing length throws: - assertThrowsInstanceOf(function() handle.length, TypeError, - "handle.length did not yield error"); - - // Accessing properties throws: - assertThrowsInstanceOf(function() handle[0], TypeError, - "Unattached handle did not yield error"); - assertThrowsInstanceOf(function() handle0.from, TypeError, - "Unattached handle did not yield error"); - - // Handle.get() throws: - assertThrowsInstanceOf(function() T.Handle.get(handle), TypeError, - "Unattached handle did not yield error"); - assertThrowsInstanceOf(function() T.Handle.get(handle0), TypeError, - "Unattached handle did not yield error"); - - // Handle.set() throws: - assertThrowsInstanceOf(function() T.Handle.set(handle, [{},{},{}]), TypeError, - "Unattached handle did not yield error"); - assertThrowsInstanceOf(function() T.Handle.set(handle0, {}), TypeError, - "Unattached handle did not yield error"); - - reportCompare(true, true); - print("Tests complete"); -} - -runTests(); - - diff --git a/js/src/tests/ecma_6/TypedObject/method_build.js b/js/src/tests/ecma_6/TypedObject/method_build.js index 75bdf4293ef..c23f629c129 100644 --- a/js/src/tests/ecma_6/TypedObject/method_build.js +++ b/js/src/tests/ecma_6/TypedObject/method_build.js @@ -19,15 +19,11 @@ var int32 = TypedObject.int32; var float32 = TypedObject.float32; var float64 = TypedObject.float64; -var Handle = TypedObject.Handle; - function oneDimensionalArrayOfUints() { var grain = uint32; var type = grain.array(4); var r1 = type.build(x => x * 2); - var r2 = type.build((x, out) => Handle.set(out, x * 2)); assertTypedEqual(type, r1, new type([0, 2, 4, 6])); - assertTypedEqual(type, r1, r2); } function oneDimensionalArrayOfStructs() { @@ -87,10 +83,8 @@ function threeDimensionalArrayOfUintsWithDepth3() { var grain = uint32; var type = grain.array(2).array(2).array(2); var r1 = type.build(3, (x,y,z) => x * 100 + y * 10 + z); - var r2 = type.build(3, (x,y,z, out) => Handle.set(out, x * 100 + y * 10 + z)); assertTypedEqual(type, r1, new type([[[ 0, 1], [ 10, 11]], [[100, 101], [110, 111]]])); - assertTypedEqual(type, r1, r2); } function threeDimensionalArrayOfUintsWithDepth2() { diff --git a/js/src/tests/ecma_6/TypedObject/method_from.js b/js/src/tests/ecma_6/TypedObject/method_from.js index 3a85abf9099..6f0aab19b6e 100644 --- a/js/src/tests/ecma_6/TypedObject/method_from.js +++ b/js/src/tests/ecma_6/TypedObject/method_from.js @@ -19,8 +19,6 @@ var int32 = TypedObject.int32; var float32 = TypedObject.float32; var float64 = TypedObject.float64; -var Handle = TypedObject.Handle; - // Test name format: // fromDimArrayOfsTos where is a positive integer (or its @@ -58,9 +56,7 @@ function fromTwoDimArrayOfUint8ToUint32s() { var r1 = type.from(i1, 2, x => x*2); var r2 = type.from(i1, 1, a => rowtype.from(a, 1, x => x*2)); - var r3 = type.from(i1, 1, - a => rowtype.from(a, 1, (x, j, c, out) => Handle.set(out, x*2))); - var r4 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2; + var r3 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2; out[1] = a[1]*2; out[2] = a[2]*2; out[3] = a[3]*2; }); @@ -70,7 +66,6 @@ function fromTwoDimArrayOfUint8ToUint32s() { [80, 82, 84, 86]])); assertTypedEqual(type, r1, r2); assertTypedEqual(type, r1, r3); - assertTypedEqual(type, r1, r4); } function fromTwoDimArrayOfUint32ToUint8s() { @@ -84,9 +79,7 @@ function fromTwoDimArrayOfUint32ToUint8s() { var r1 = type.from(i1, 2, x => x*2); var r2 = type.from(i1, 1, a => rowtype.from(a, 1, x => x*2)); - var r3 = type.from(i1, 1, - a => rowtype.from(a, 1, (x, j, c, out) => Handle.set(out, x*2))); - var r4 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2; + var r3 = type.from(i1, 1, (a, j, c, out) => { out[0] = a[0]*2; out[1] = a[1]*2; out[2] = a[2]*2; out[3] = a[3]*2; }); @@ -96,7 +89,6 @@ function fromTwoDimArrayOfUint32ToUint8s() { [80, 82, 84, 86]])); assertTypedEqual(type, r1, r2); assertTypedEqual(type, r1, r3); - assertTypedEqual(type, r1, r4); } function fromOneDimArrayOfArrayOfUint8ToUint32s() { @@ -110,13 +102,10 @@ function fromOneDimArrayOfArrayOfUint8ToUint32s() { function combine(a,b,c,d) { return a << 24 | b << 16 | c << 8 | d; } var r1 = type.from(i1, x => combine(x[0], x[1], x[2], x[3])); - var r2 = type.from(i1, 1, - (x, i, c, out) => Handle.set(out, combine(x[0], x[1], x[2], x[3]))); assertTypedEqual(type, r1, new type([0xddccbbaa, 0x09080706, 0x15141312, 0x23324150])); - assertTypedEqual(type, r1, r2); } function fromOneDimArrayOfUint32ToArrayOfUint8s() { diff --git a/js/src/tests/ecma_6/TypedObject/method_map.js b/js/src/tests/ecma_6/TypedObject/method_map.js index 7136e308ed5..e5bf9b3ee5b 100644 --- a/js/src/tests/ecma_6/TypedObject/method_map.js +++ b/js/src/tests/ecma_6/TypedObject/method_map.js @@ -19,8 +19,6 @@ var int32 = TypedObject.int32; var float32 = TypedObject.float32; var float64 = TypedObject.float64; -var Handle = TypedObject.Handle; - // Test name format: // mapDimArrayOfsTos where is a positive integer (or its @@ -54,8 +52,7 @@ function mapTwoDimArrayOfUint8() { var r1 = i1.map(2, x => x*2); var r2 = i1.map(1, a => a.map(1, x => x*2)); - var r3 = i1.map(1, a => a.map(1, (x, j, c, out) => Handle.set(out, x*2))); - var r4 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2; + var r3 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2; out[1] = a[1]*2; out[2] = a[2]*2; out[3] = a[3]*2; }); @@ -65,7 +62,6 @@ function mapTwoDimArrayOfUint8() { [80, 82, 84, 86]])); assertTypedEqual(type, r1, r2); assertTypedEqual(type, r1, r3); - assertTypedEqual(type, r1, r4); } function mapTwoDimArrayOfUint32() { @@ -77,8 +73,7 @@ function mapTwoDimArrayOfUint32() { var r1 = i1.map(2, x => x*2); var r2 = i1.map(1, a => a.map(1, x => x*2)); - var r3 = i1.map(1, a => a.map(1, (x, j, c, out) => Handle.set(out, x*2))); - var r4 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2; + var r3 = i1.map(1, (a, j, c, out) => { out[0] = a[0]*2; out[1] = a[1]*2; out[2] = a[2]*2; out[3] = a[3]*2; }); @@ -88,7 +83,6 @@ function mapTwoDimArrayOfUint32() { [80, 82, 84, 86]])); assertTypedEqual(type, r1, r2); assertTypedEqual(type, r1, r3); - assertTypedEqual(type, r1, r4); } var Grain = new StructType({f: uint32}); diff --git a/js/xpconnect/public/nsTArrayHelpers.h b/js/xpconnect/public/nsTArrayHelpers.h index 62b05ca8b3f..e072a6a8282 100644 --- a/js/xpconnect/public/nsTArrayHelpers.h +++ b/js/xpconnect/public/nsTArrayHelpers.h @@ -17,7 +17,7 @@ nsTArrayToJSArray(JSContext* aCx, const nsTArray& aSourceArray, MOZ_ASSERT(aCx); JS::Rooted arrayObj(aCx, - JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr)); + JS_NewArrayObject(aCx, aSourceArray.Length())); if (!arrayObj) { NS_WARNING("JS_NewArrayObject failed!"); return NS_ERROR_OUT_OF_MEMORY; @@ -59,7 +59,7 @@ nsTArrayToJSArray(JSContext* aCx, MOZ_ASSERT(aCx); JS::Rooted arrayObj(aCx, - JS_NewArrayObject(aCx, aSourceArray.Length(), nullptr)); + JS_NewArrayObject(aCx, aSourceArray.Length())); if (!arrayObj) { NS_WARNING("JS_NewArrayObject failed!"); return NS_ERROR_OUT_OF_MEMORY; diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 045d206a0a3..95dbb061ce4 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3041,7 +3041,7 @@ nsXPCComponents_Utils::CreateArrayIn(HandleValue vobj, JSContext *cx, RootedObject obj(cx); { JSAutoCompartment ac(cx, scope); - obj = JS_NewArrayObject(cx, 0, nullptr); + obj = JS_NewArrayObject(cx, 0); if (!obj) return NS_ERROR_FAILURE; } diff --git a/js/xpconnect/src/XPCConvert.cpp b/js/xpconnect/src/XPCConvert.cpp index a2cb7dbf6cb..b718e502a95 100644 --- a/js/xpconnect/src/XPCConvert.cpp +++ b/js/xpconnect/src/XPCConvert.cpp @@ -1362,7 +1362,7 @@ XPCConvert::NativeArray2JS(MutableHandleValue d, const void** s, // XXX add support to indicate *which* array element was not convertable - RootedObject array(cx, JS_NewArrayObject(cx, count, nullptr)); + RootedObject array(cx, JS_NewArrayObject(cx, count)); if (!array) return false; diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 285b424726a..1e9ebb792b0 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1093,7 +1093,7 @@ ProcessArgs(JSContext *cx, JS::Handle obj, char **argv, int argc, XPC * Create arguments early and define it to root it, so it's safe from any * GC calls nested below, and so it is available to -f arguments. */ - argsObj = JS_NewArrayObject(cx, 0, nullptr); + argsObj = JS_NewArrayObject(cx, 0); if (!argsObj) return 1; if (!JS_DefineProperty(cx, obj, "arguments", OBJECT_TO_JSVAL(argsObj), diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index 86afcc11798..5516b060582 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -641,7 +641,7 @@ VARIANT_DONE: } case nsIDataType::VTYPE_EMPTY_ARRAY: { - JSObject* array = JS_NewArrayObject(cx, 0, nullptr); + JSObject* array = JS_NewArrayObject(cx, 0); if (!array) return false; pJSVal.setObject(*array); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index a10cf98884e..ce221ff17db 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -3268,7 +3268,7 @@ nsDisplayMixBlendMode::BuildLayer(nsDisplayListBuilder* aBuilder, return nullptr; } - container->SetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mFrame->StyleDisplay()->mMixBlendMode)); + container->DeprecatedSetMixBlendMode(nsCSSRendering::GetGFXBlendMode(mFrame->StyleDisplay()->mMixBlendMode)); return container.forget(); } diff --git a/media/webrtc/moz.build b/media/webrtc/moz.build index da338199bb5..357cbd3ec54 100644 --- a/media/webrtc/moz.build +++ b/media/webrtc/moz.build @@ -29,7 +29,8 @@ webrtc_non_unified_sources = [ 'trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit.mm', # Because of name clash in the nsAutoreleasePool class 'trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info.mm', # Because of name clash in the nsAutoreleasePool class 'trunk/webrtc/modules/video_capture/windows/device_info_ds.cc', # Because of the MEDIASUBTYPE_HDYC variable - 'trunk/webrtc/modules/video_capture/windows/sink_filter_ds.cc', # Because of the MEDIASUBTYPE_HDYC variable + 'trunk/webrtc/modules/video_capture/windows/help_functions_ds.cc', # Because of initguid.h + 'trunk/webrtc/modules/video_capture/windows/sink_filter_ds.cc', # Because of the MEDIASUBTYPE_HDYC variable and initguid.h ] GYP_DIRS += ['trunk'] diff --git a/media/webrtc/trunk/webrtc/typedefs.h b/media/webrtc/trunk/webrtc/typedefs.h index 22edf454fa3..3e1456f1238 100644 --- a/media/webrtc/trunk/webrtc/typedefs.h +++ b/media/webrtc/trunk/webrtc/typedefs.h @@ -103,6 +103,16 @@ #define WEBRTC_ARCH_32_BITS 1 #define WEBRTC_ARCH_BIG_ENDIAN #define WEBRTC_BIG_ENDIAN +#elif defined(__aarch64__) +#define WEBRTC_ARCH_AARCH64 1 +#define WEBRTC_ARCH_64_BITS 1 +#if defined(__AARCH64EL__) +#define WEBRTC_ARCH_LITTLE_ENDIAN +#define WEBRTC_LITTLE_ENDIAN +#elif defined(__AARCH64EB__) +#define WEBRTC_ARCH_BIG_ENDIAN +#define WEBRTC_BIG_ENDIAN +#endif #elif defined(__alpha__) #define WEBRTC_ARCH_ALPHA 1 #define WEBRTC_ARCH_64_BITS 1 diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index 7691899aaa8..6605fde16bb 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -179,13 +179,13 @@ #endif - @@ -196,13 +196,13 @@ - + WebappAllocator. --> -#define FRAGMENT WebAppManifestFragment.xml.frag.in -#include WebAppFragmentRepeater.inc +#define FRAGMENT WebappManifestFragment.xml.frag.in +#include WebappFragmentRepeater.inc classes to the WebApps class. + * Declare a predefined number of Webapp classes to the Webapps class. * These are used so that each web app can launch in its own process. Keep this - * number in sync with the number of web apps handled in WebAppAllocator. + * number in sync with the number of web apps handled in WebappAllocator. */ public final class WebApps { -#define FRAGMENT WebAppsFragment.java.frag -#include WebAppFragmentRepeater.inc +#define FRAGMENT WebappsFragment.java.frag +#include WebappFragmentRepeater.inc } diff --git a/mobile/android/base/WebApp.java.in b/mobile/android/base/Webapp.java.in similarity index 67% rename from mobile/android/base/WebApp.java.in rename to mobile/android/base/Webapp.java.in index bb050250ae5..e0e87664950 100644 --- a/mobile/android/base/WebApp.java.in +++ b/mobile/android/base/Webapp.java.in @@ -7,12 +7,12 @@ package @ANDROID_PACKAGE_NAME@; #ifdef MOZ_ANDROID_SYNTHAPKS -import org.mozilla.gecko.webapp.WebAppImpl; +import org.mozilla.gecko.webapp.WebappImpl; #else -import org.mozilla.gecko.WebAppImpl; +import org.mozilla.gecko.WebappImpl; #endif /** - * This class serves only as a namespace wrapper for WebAppImpl. + * This class serves only as a namespace wrapper for WebappImpl. */ -public class WebApp extends WebAppImpl {} +public class Webapp extends WebappImpl {} diff --git a/mobile/android/base/WebAppAllocator.java b/mobile/android/base/WebappAllocator.java similarity index 90% rename from mobile/android/base/WebAppAllocator.java rename to mobile/android/base/WebappAllocator.java index 34385216dbf..236c4ef28e0 100644 --- a/mobile/android/base/WebAppAllocator.java +++ b/mobile/android/base/WebappAllocator.java @@ -16,19 +16,19 @@ import android.util.Log; import java.util.ArrayList; -public class WebAppAllocator { - private final String LOGTAG = "GeckoWebAppAllocator"; - // The number of WebApp# and WEBAPP# activites/apps/intents +public class WebappAllocator { + private final String LOGTAG = "GeckoWebappAllocator"; + // The number of Webapp# and WEBAPP# activites/apps/intents private final static int MAX_WEB_APPS = 100; - protected static WebAppAllocator sInstance = null; - public static WebAppAllocator getInstance() { + protected static WebappAllocator sInstance = null; + public static WebappAllocator getInstance() { return getInstance(GeckoAppShell.getContext()); } - public static synchronized WebAppAllocator getInstance(Context cx) { + public static synchronized WebappAllocator getInstance(Context cx) { if (sInstance == null) { - sInstance = new WebAppAllocator(cx); + sInstance = new WebappAllocator(cx); } return sInstance; @@ -36,7 +36,7 @@ public class WebAppAllocator { SharedPreferences mPrefs; - protected WebAppAllocator(Context context) { + protected WebappAllocator(Context context) { mPrefs = context.getSharedPreferences("webapps", Context.MODE_PRIVATE | Context.MODE_MULTI_PROCESS); } diff --git a/mobile/android/base/WebAppFragmentRepeater.inc b/mobile/android/base/WebappFragmentRepeater.inc similarity index 100% rename from mobile/android/base/WebAppFragmentRepeater.inc rename to mobile/android/base/WebappFragmentRepeater.inc diff --git a/mobile/android/base/WebAppImpl.java b/mobile/android/base/WebappImpl.java similarity index 92% rename from mobile/android/base/WebAppImpl.java rename to mobile/android/base/WebappImpl.java index 5254605a715..4de0ad7ec86 100644 --- a/mobile/android/base/WebAppImpl.java +++ b/mobile/android/base/WebappImpl.java @@ -26,8 +26,8 @@ import android.view.Display; import java.net.URL; import java.io.File; -public class WebAppImpl extends GeckoApp { - private static final String LOGTAG = "GeckoWebAppImpl"; +public class WebappImpl extends GeckoApp { + private static final String LOGTAG = "GeckoWebappImpl"; private URL mOrigin; private TextView mTitlebarText = null; @@ -62,12 +62,12 @@ public class WebAppImpl extends GeckoApp { mTitlebarText = (TextView)findViewById(R.id.webapp_title); mTitlebar = findViewById(R.id.webapp_titlebar); if (!action.startsWith(ACTION_WEBAPP_PREFIX)) { - Log.e(LOGTAG, "WebApp launch, but intent action is " + action + "!"); + Log.e(LOGTAG, "Webapp launch, but intent action is " + action + "!"); return; } - // Try to use the origin stored in the WebAppAllocator first - String origin = WebAppAllocator.getInstance(this).getAppForIndex(getIndex()); + // Try to use the origin stored in the WebappAllocator first + String origin = WebappAllocator.getInstance(this).getAppForIndex(getIndex()); try { mOrigin = new URL(origin); } catch (java.net.MalformedURLException ex) { @@ -90,11 +90,11 @@ public class WebAppImpl extends GeckoApp { protected void loadStartupTab(String uri) { String action = getIntent().getAction(); if (GeckoApp.ACTION_WEBAPP_PREFIX.equals(action)) { - // This action assumes the uri is not an installed WebApp. We will - // use the WebAppAllocator to register the uri with an Android + // This action assumes the uri is not an installed Webapp. We will + // use the WebappAllocator to register the uri with an Android // process so it can run chromeless. - int index = WebAppAllocator.getInstance(this).findAndAllocateIndex(uri, "App", (Bitmap) null); - Intent appIntent = GeckoAppShell.getWebAppIntent(index, uri); + int index = WebappAllocator.getInstance(this).findAndAllocateIndex(uri, "App", (Bitmap) null); + Intent appIntent = GeckoAppShell.getWebappIntent(index, uri); startActivity(appIntent); finish(); } @@ -105,7 +105,7 @@ public class WebAppImpl extends GeckoApp { // get the favicon dominant color, stored when the app was installed int[] colors = new int[2]; - int dominantColor = prefs.getInt(WebAppAllocator.iconKey(getIndex()), -1); + int dominantColor = prefs.getInt(WebappAllocator.iconKey(getIndex()), -1); // now lighten it, to ensure that the icon stands out in the center float[] f = new float[3]; @@ -144,7 +144,7 @@ public class WebAppImpl extends GeckoApp { protected String getDefaultProfileName() { String action = getIntent().getAction(); if (!action.startsWith(ACTION_WEBAPP_PREFIX)) { - Log.e(LOGTAG, "WebApp launch, but intent action is " + action + "!"); + Log.e(LOGTAG, "Webapp launch, but intent action is " + action + "!"); return null; } diff --git a/mobile/android/base/WebAppManifestFragment.xml.frag.in b/mobile/android/base/WebappManifestFragment.xml.frag.in similarity index 93% rename from mobile/android/base/WebAppManifestFragment.xml.frag.in rename to mobile/android/base/WebappManifestFragment.xml.frag.in index 189f000d7e3..b08924fc05b 100644 --- a/mobile/android/base/WebAppManifestFragment.xml.frag.in +++ b/mobile/android/base/WebappManifestFragment.xml.frag.in @@ -2,7 +2,7 @@ android:label="@string/webapp_generic_name" android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation|screenSize" android:windowSoftInputMode="stateUnspecified|adjustResize" - android:process=":@ANDROID_PACKAGE_NAME@.WebApp@APPNUM@" + android:process=":@ANDROID_PACKAGE_NAME@.Webapp@APPNUM@" android:theme="@style/Gecko.App" #ifdef MOZ_ANDROID_SYNTHAPKS android:launchMode="singleTop" diff --git a/mobile/android/base/WebAppsFragment.java.frag b/mobile/android/base/WebappsFragment.java.frag similarity index 56% rename from mobile/android/base/WebAppsFragment.java.frag rename to mobile/android/base/WebappsFragment.java.frag index c257c018a44..4ce77fe145e 100644 --- a/mobile/android/base/WebAppsFragment.java.frag +++ b/mobile/android/base/WebappsFragment.java.frag @@ -1,4 +1,4 @@ -public static class WebApp@APPNUM@ extends WebApp { +public static class WebApp@APPNUM@ extends Webapp { @Override protected int getIndex() { return @APPNUM@; } } diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 1133aa6d425..3b22f1a5219 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -349,9 +349,9 @@ gbjar.sources += [ 'webapp/InstallHelper.java', 'webapp/InstallListener.java', 'webapp/UninstallListener.java', - 'webapp/WebAppImpl.java', - 'WebAppAllocator.java', - 'WebAppImpl.java', + 'webapp/WebappImpl.java', + 'WebappAllocator.java', + 'WebappImpl.java', 'widget/ActivityChooserModel.java', 'widget/AllCapsTextView.java', 'widget/AnimatedHeightLayout.java', @@ -385,7 +385,7 @@ android_package_dir = CONFIG['ANDROID_PACKAGE_NAME'].replace('.', '/') # R.java is handled even more specially than the others! gbjar.generated_sources += [ android_package_dir + f for f in [ '/App.java', - '/WebApp.java', + '/Webapp.java', '/WebApps.java', ] ] gbjar.generated_sources += [ diff --git a/mobile/android/base/webapp/Allocator.java b/mobile/android/base/webapp/Allocator.java index 573cd7f97e2..feb5503b57d 100644 --- a/mobile/android/base/webapp/Allocator.java +++ b/mobile/android/base/webapp/Allocator.java @@ -18,12 +18,12 @@ import android.util.Log; public class Allocator { - private final String LOGTAG = "GeckoWebAppAllocator"; + private final String LOGTAG = "GeckoWebappAllocator"; private static final String PREFIX_ORIGIN = "webapp-origin-"; private static final String PREFIX_PACKAGE_NAME = "webapp-package-name-"; - // The number of WebApp# and WEBAPP# activites/apps/intents + // The number of Webapp# and WEBAPP# activities/apps/intents private final static int MAX_WEB_APPS = 100; protected static Allocator sInstance = null; diff --git a/mobile/android/base/webapp/ApkResources.java b/mobile/android/base/webapp/ApkResources.java index dad7fe17509..16caa720e88 100644 --- a/mobile/android/base/webapp/ApkResources.java +++ b/mobile/android/base/webapp/ApkResources.java @@ -21,7 +21,7 @@ import android.os.Environment; import android.util.Log; public class ApkResources { - private static final String LOGTAG = "GeckoWebAppApkResources"; + private static final String LOGTAG = "GeckoWebappApkResources"; private final String mPackageName; private final ApplicationInfo mInfo; private final Context mContext; @@ -58,7 +58,7 @@ public class ApkResources { } public boolean isPackaged() { - return "packaged".equals(getWebAppType()); + return "packaged".equals(getWebappType()); } public boolean isDebuggable() { @@ -94,7 +94,7 @@ public class ApkResources { return info().loadIcon(mContext.getPackageManager()); } - public String getWebAppType() { + public String getWebappType() { return metadata().getString("webapp"); } diff --git a/mobile/android/base/webapp/Dispatcher.java b/mobile/android/base/webapp/Dispatcher.java index 358469119e5..61fa7dc7b26 100644 --- a/mobile/android/base/webapp/Dispatcher.java +++ b/mobile/android/base/webapp/Dispatcher.java @@ -11,7 +11,7 @@ import android.os.Bundle; import android.util.Log; public class Dispatcher extends Activity { - private static final String LOGTAG = "GeckoWebAppDispatcher"; + private static final String LOGTAG = "GeckoWebappDispatcher"; @Override protected void onCreate(Bundle bundle) { @@ -25,10 +25,16 @@ public class Dispatcher extends Activity { if (bundle == null) { Log.e(LOGTAG, "Passed intent data missing."); + return; } String packageName = bundle.getString("packageName"); + if (packageName == null) { + Log.e(LOGTAG, "Package name data missing."); + return; + } + int index = allocator.getIndexForApp(packageName); boolean isInstalled = index >= 0; if (!isInstalled) { diff --git a/mobile/android/base/webapp/EventListener.java b/mobile/android/base/webapp/EventListener.java index b29473f5551..15a5cde88c0 100644 --- a/mobile/android/base/webapp/EventListener.java +++ b/mobile/android/base/webapp/EventListener.java @@ -15,7 +15,7 @@ import org.mozilla.gecko.util.EventDispatcher; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.GeckoEventResponder; import org.mozilla.gecko.util.ThreadUtils; -import org.mozilla.gecko.WebAppAllocator; +import org.mozilla.gecko.WebappAllocator; import android.app.Activity; import android.app.ActivityManager; @@ -40,7 +40,7 @@ import org.json.JSONObject; public class EventListener implements GeckoEventListener, GeckoEventResponder { - private static final String LOGTAG = "GeckoWebAppEventListener"; + private static final String LOGTAG = "GeckoWebappEventListener"; private EventListener() { } @@ -63,55 +63,55 @@ public class EventListener implements GeckoEventListener, GeckoEventResponder { } public static void registerEvents() { - registerEventListener("WebApps:PreInstall"); - registerEventListener("WebApps:InstallApk"); - registerEventListener("WebApps:PostInstall"); - registerEventListener("WebApps:Open"); - registerEventListener("WebApps:Uninstall"); - registerEventListener("WebApps:GetApkVersions"); + registerEventListener("Webapps:Preinstall"); + registerEventListener("Webapps:InstallApk"); + registerEventListener("Webapps:Postinstall"); + registerEventListener("Webapps:Open"); + registerEventListener("Webapps:Uninstall"); + registerEventListener("Webapps:GetApkVersions"); } public static void unregisterEvents() { - unregisterEventListener("WebApps:PreInstall"); - unregisterEventListener("WebApps:InstallApk"); - unregisterEventListener("WebApps:PostInstall"); - unregisterEventListener("WebApps:Open"); - unregisterEventListener("WebApps:Uninstall"); - unregisterEventListener("WebApps:GetApkVersions"); + unregisterEventListener("Webapps:Preinstall"); + unregisterEventListener("Webapps:InstallApk"); + unregisterEventListener("Webapps:Postinstall"); + unregisterEventListener("Webapps:Open"); + unregisterEventListener("Webapps:Uninstall"); + unregisterEventListener("Webapps:GetApkVersions"); } @Override public void handleMessage(String event, JSONObject message) { try { - if (AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:InstallApk")) { + if (AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("Webapps:InstallApk")) { installApk(GeckoAppShell.getGeckoInterface().getActivity(), message.getString("filePath"), message.getString("data")); - } else if (event.equals("WebApps:PostInstall")) { + } else if (event.equals("Webapps:Postinstall")) { if (AppConstants.MOZ_ANDROID_SYNTHAPKS) { - postInstallWebApp(message.getString("apkPackageName"), message.getString("origin")); + postInstallWebapp(message.getString("apkPackageName"), message.getString("origin")); } else { - postInstallWebApp(message.getString("name"), + postInstallWebapp(message.getString("name"), message.getString("manifestURL"), message.getString("origin"), message.getString("iconURL"), message.getString("originalOrigin")); } - } else if (event.equals("WebApps:Open")) { - Intent intent = GeckoAppShell.getWebAppIntent(message.getString("manifestURL"), + } else if (event.equals("Webapps:Open")) { + Intent intent = GeckoAppShell.getWebappIntent(message.getString("manifestURL"), message.getString("origin"), "", null); if (intent == null) { return; } GeckoAppShell.getGeckoInterface().getActivity().startActivity(intent); - } else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:Uninstall")) { - uninstallWebApp(message.getString("origin")); - } else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("WebApps:PreInstall")) { + } else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("Webapps:Uninstall")) { + uninstallWebapp(message.getString("origin")); + } else if (!AppConstants.MOZ_ANDROID_SYNTHAPKS && event.equals("Webapps:Preinstall")) { String name = message.getString("name"); String manifestURL = message.getString("manifestURL"); String origin = message.getString("origin"); // preInstallWebapp will return a File object pointing to the profile directory of the webapp - mCurrentResponse = preInstallWebApp(name, manifestURL, origin).toString(); + mCurrentResponse = preInstallWebapp(name, manifestURL, origin).toString(); } else if (event.equals("WebApps:GetApkVersions")) { mCurrentResponse = getApkVersions(GeckoAppShell.getGeckoInterface().getActivity(), message.getJSONArray("packageNames")).toString(); @@ -128,15 +128,15 @@ public class EventListener implements GeckoEventListener, GeckoEventResponder { } // Not used by MOZ_ANDROID_SYNTHAPKS. - public static File preInstallWebApp(String aTitle, String aURI, String aOrigin) { - int index = WebAppAllocator.getInstance(GeckoAppShell.getContext()).findAndAllocateIndex(aOrigin, aTitle, (String) null); + public static File preInstallWebapp(String aTitle, String aURI, String aOrigin) { + int index = WebappAllocator.getInstance(GeckoAppShell.getContext()).findAndAllocateIndex(aOrigin, aTitle, (String) null); GeckoProfile profile = GeckoProfile.get(GeckoAppShell.getContext(), "webapp" + index); return profile.getDir(); } // Not used by MOZ_ANDROID_SYNTHAPKS. - public static void postInstallWebApp(String aTitle, String aURI, String aOrigin, String aIconURL, String aOriginalOrigin) { - WebAppAllocator allocator = WebAppAllocator.getInstance(GeckoAppShell.getContext()); + public static void postInstallWebapp(String aTitle, String aURI, String aOrigin, String aIconURL, String aOriginalOrigin) { + WebappAllocator allocator = WebappAllocator.getInstance(GeckoAppShell.getContext()); int index = allocator.getIndexForApp(aOriginalOrigin); assert aIconURL != null; @@ -151,13 +151,13 @@ public class EventListener implements GeckoEventListener, GeckoEventResponder { } // Used by MOZ_ANDROID_SYNTHAPKS. - public static void postInstallWebApp(String aPackageName, String aOrigin) { + public static void postInstallWebapp(String aPackageName, String aOrigin) { Allocator allocator = Allocator.getInstance(GeckoAppShell.getContext()); int index = allocator.findOrAllocatePackage(aPackageName); allocator.putOrigin(index, aOrigin); } - public static void uninstallWebApp(final String uniqueURI) { + public static void uninstallWebapp(final String uniqueURI) { // On uninstall, we need to do a couple of things: // 1. nuke the running app process. // 2. nuke the profile that was assigned to that webapp @@ -173,7 +173,7 @@ public class EventListener implements GeckoEventListener, GeckoEventResponder { // kill the app if it's running String targetProcessName = GeckoAppShell.getContext().getPackageName(); - targetProcessName = targetProcessName + ":" + targetProcessName + ".WebApp" + index; + targetProcessName = targetProcessName + ":" + targetProcessName + ".Webapp" + index; ActivityManager am = (ActivityManager) GeckoAppShell.getContext().getSystemService(Context.ACTIVITY_SERVICE); List procs = am.getRunningAppProcesses(); diff --git a/mobile/android/base/webapp/InstallHelper.java b/mobile/android/base/webapp/InstallHelper.java index 9652ccd6772..3a084c72c91 100644 --- a/mobile/android/base/webapp/InstallHelper.java +++ b/mobile/android/base/webapp/InstallHelper.java @@ -27,8 +27,8 @@ import android.net.Uri; import android.util.Log; public class InstallHelper implements GeckoEventListener { - private static final String LOGTAG = "GeckoWebAppInstallHelper"; - private static final String[] INSTALL_EVENT_NAMES = new String[] {"WebApps:PostInstall"}; + private static final String LOGTAG = "GeckoWebappInstallHelper"; + private static final String[] INSTALL_EVENT_NAMES = new String[] {"Webapps:Postinstall"}; private final Context mContext; private final InstallCallback mCallback; private final ApkResources mApkResources; @@ -86,7 +86,7 @@ public class InstallHelper implements GeckoEventListener { message.put("title", mApkResources.getAppName()); message.put("manifest", new JSONObject(mApkResources.getManifest(mContext))); - String appType = mApkResources.getWebAppType(); + String appType = mApkResources.getWebappType(); message.putOpt("type", appType); if ("packaged".equals(appType)) { message.putOpt("updateManifest", new JSONObject(mApkResources.getMiniManifest(mContext))); diff --git a/mobile/android/base/webapp/InstallListener.java b/mobile/android/base/webapp/InstallListener.java index 10811ceea71..6a450c33345 100644 --- a/mobile/android/base/webapp/InstallListener.java +++ b/mobile/android/base/webapp/InstallListener.java @@ -24,7 +24,7 @@ import android.util.Log; public class InstallListener extends BroadcastReceiver { - private static String LOGTAG = "GeckoWebAppInstallListener"; + private static String LOGTAG = "GeckoWebappInstallListener"; private JSONObject mData = null; private String mManifestUrl; diff --git a/mobile/android/base/webapp/UninstallListener.java b/mobile/android/base/webapp/UninstallListener.java index ba3a08c559a..fd26c7930b4 100644 --- a/mobile/android/base/webapp/UninstallListener.java +++ b/mobile/android/base/webapp/UninstallListener.java @@ -28,7 +28,7 @@ import java.util.ArrayList; public class UninstallListener extends BroadcastReceiver { - private static String LOGTAG = "GeckoWebAppUninstallListener"; + private static String LOGTAG = "GeckoWebappUninstallListener"; @Override public void onReceive(Context context, Intent intent) { diff --git a/mobile/android/base/webapp/WebAppImpl.java b/mobile/android/base/webapp/WebappImpl.java similarity index 97% rename from mobile/android/base/webapp/WebAppImpl.java rename to mobile/android/base/webapp/WebappImpl.java index 92f4dd076bd..3c838f99c04 100644 --- a/mobile/android/base/webapp/WebAppImpl.java +++ b/mobile/android/base/webapp/WebappImpl.java @@ -42,8 +42,8 @@ import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.TextView; -public class WebAppImpl extends GeckoApp implements InstallCallback { - private static final String LOGTAG = "GeckoWebAppImpl"; +public class WebappImpl extends GeckoApp implements InstallCallback { + private static final String LOGTAG = "GeckoWebappImpl"; private URL mOrigin; private TextView mTitlebarText = null; @@ -127,7 +127,7 @@ public class WebAppImpl extends GeckoApp implements InstallCallback { } return; } else { - launchWebApp(origin, mApkResources.getManifestUrl(), mApkResources.getAppName()); + launchWebapp(origin, mApkResources.getManifestUrl(), mApkResources.getAppName()); } setTitle(mApkResources.getAppName()); @@ -290,9 +290,9 @@ public class WebAppImpl extends GeckoApp implements InstallCallback { return; } - if (event.equals("WebApps:PostInstall")) { + if (event.equals("Webapps:Postinstall")) { String origin = message.optString("origin"); - launchWebApp(origin, mApkResources.getManifestUrl(), mApkResources.getAppName()); + launchWebapp(origin, mApkResources.getManifestUrl(), mApkResources.getAppName()); } } @@ -301,7 +301,7 @@ public class WebAppImpl extends GeckoApp implements InstallCallback { Log.e(LOGTAG, "Install errored", exception); } - public void launchWebApp(String origin, String manifestUrl, String name) { + public void launchWebapp(String origin, String manifestUrl, String name) { try { mOrigin = new URL(origin); } catch (java.net.MalformedURLException ex) { diff --git a/mobile/android/chrome/content/WebAppRT.js b/mobile/android/chrome/content/WebappRT.js similarity index 99% rename from mobile/android/chrome/content/WebAppRT.js rename to mobile/android/chrome/content/WebappRT.js index fb1568a4bc7..78d4e37391d 100644 --- a/mobile/android/chrome/content/WebAppRT.js +++ b/mobile/android/chrome/content/WebappRT.js @@ -24,7 +24,7 @@ function pref(name, value) { } } -let WebAppRT = { +let WebappRT = { DEFAULT_PREFS_FILENAME: "default-prefs.js", prefs: [ diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 30d0ee11dde..43e39f4a694 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -460,9 +460,9 @@ var BrowserApp = { _initRuntime: function(status, url, callback) { let sandbox = {}; - Services.scriptloader.loadSubScript("chrome://browser/content/WebAppRT.js", sandbox); - window.WebAppRT = sandbox.WebAppRT; - WebAppRT.init(status, url, callback); + Services.scriptloader.loadSubScript("chrome://browser/content/WebappRT.js", sandbox); + window.WebappRT = sandbox.WebappRT; + WebappRT.init(status, url, callback); }, initContextMenu: function ba_initContextMenu() { @@ -7116,7 +7116,7 @@ var WebappsUI = { break; case "webapps-uninstall": sendMessageToJava({ - type: "WebApps:Uninstall", + type: "Webapps:Uninstall", origin: data.origin }); break; @@ -7132,7 +7132,7 @@ var WebappsUI = { // Get a profile for the app to be installed in. We'll download everything before creating the icons. let origin = aData.app.origin; let profilePath = sendMessageToJava({ - type: "WebApps:PreInstall", + type: "Webapps:Preinstall", name: manifest.name, manifestURL: aData.app.manifestURL, origin: origin @@ -7164,7 +7164,7 @@ var WebappsUI = { // aData.app.origin may now point to the app: url that hosts this app sendMessageToJava({ - type: "WebApps:PostInstall", + type: "Webapps:Postinstall", name: localeManifest.name, manifestURL: aData.app.manifestURL, originalOrigin: origin, @@ -7232,7 +7232,7 @@ var WebappsUI = { openURL: function openURL(aManifestURL, aOrigin) { sendMessageToJava({ - type: "WebApps:Open", + type: "Webapps:Open", manifestURL: aManifestURL, origin: aOrigin }); diff --git a/mobile/android/chrome/jar.mn b/mobile/android/chrome/jar.mn index 81b02564f7f..d2152b011ea 100644 --- a/mobile/android/chrome/jar.mn +++ b/mobile/android/chrome/jar.mn @@ -40,7 +40,7 @@ chrome.jar: content/SelectHelper.js (content/SelectHelper.js) content/SelectionHandler.js (content/SelectionHandler.js) content/dbg-browser-actors.js (content/dbg-browser-actors.js) -* content/WebAppRT.js (content/WebAppRT.js) +* content/WebappRT.js (content/WebappRT.js) content/InputWidgetHelper.js (content/InputWidgetHelper.js) content/WebrtcUI.js (content/WebrtcUI.js) content/MemoryObserver.js (content/MemoryObserver.js) diff --git a/mobile/android/modules/WebappManager.jsm b/mobile/android/modules/WebappManager.jsm index d12b297d0f1..b6f3cb82ce0 100644 --- a/mobile/android/modules/WebappManager.jsm +++ b/mobile/android/modules/WebappManager.jsm @@ -85,7 +85,7 @@ this.WebappManager = { } sendMessageToJava({ - type: "WebApps:InstallApk", + type: "Webapps:InstallApk", filePath: filePath, data: JSON.stringify(aMessage), }); @@ -157,7 +157,7 @@ this.WebappManager = { // aData.app.origin may now point to the app: url that hosts this app. sendMessageToJava({ - type: "WebApps:PostInstall", + type: "Webapps:Postinstall", apkPackageName: aData.app.apkPackageName, origin: aData.app.origin, }); @@ -171,7 +171,7 @@ this.WebappManager = { log("launchWebapp: " + manifestURL); sendMessageToJava({ - type: "WebApps:Open", + type: "Webapps:Open", manifestURL: manifestURL, origin: origin }); @@ -285,7 +285,7 @@ this.WebappManager = { // Map APK names to APK versions. let apkNameToVersion = JSON.parse(sendMessageToJava({ - type: "WebApps:GetApkVersions", + type: "Webapps:GetApkVersions", packageNames: installedApps.map(app => app.packageName).filter(packageName => !!packageName) })); @@ -450,11 +450,11 @@ this.WebappManager = { for (let apk of downloadedApks) { let msg = { app: apk.app, - // TODO: figure out why WebApps:InstallApk needs the "from" property. + // TODO: figure out why Webapps:InstallApk needs the "from" property. from: apk.app.installOrigin, }; sendMessageToJava({ - type: "WebApps:InstallApk", + type: "Webapps:InstallApk", filePath: apk.filePath, data: JSON.stringify(msg), }); @@ -530,7 +530,11 @@ this.WebappManager = { // build any app specific default prefs let prefs = []; if (aManifest.orientation) { - prefs.push({name:"app.orientation.default", value: aManifest.orientation.join(",") }); + let orientation = aManifest.orientation; + if (Array.isArray(orientation)) { + orientation = orientation.join(","); + } + prefs.push({ name: "app.orientation.default", value: orientation }); } // write them into the app profile diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp index b94f306a8f6..748406baa5a 100644 --- a/netwerk/ipc/RemoteOpenFileChild.cpp +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -557,6 +557,12 @@ RemoteOpenFileChild::MoveToNative(nsIFile *newParent, const nsACString &newName) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +RemoteOpenFileChild::RenameTo(nsIFile *newParentDir, const nsAString &newName) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP RemoteOpenFileChild::Remove(bool recursive) { diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 3c1bf9ec73c..d580ff596b5 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -664,6 +664,11 @@ class RecursiveMakeBackend(CommonBackend): '#error "%(cppfile)s forces NSPR logging, ' 'so it cannot be built in unified mode."\n' '#undef FORCE_PR_LOG\n' + '#endif\n' + '#ifdef INITGUID\n' + '#error "%(cppfile)s defines INITGUID, ' + 'so it cannot be built in unified mode."\n' + '#undef INITGUID\n' '#endif') f.write('\n'.join(includeTemplate % { "cppfile": s } for s in source_filenames)) diff --git a/security/manager/ssl/tests/unit/test_cert_signatures.js b/security/manager/ssl/tests/unit/test_cert_signatures.js index c64fa9124be..09714093082 100644 --- a/security/manager/ssl/tests/unit/test_cert_signatures.js +++ b/security/manager/ssl/tests/unit/test_cert_signatures.js @@ -24,43 +24,19 @@ do_get_profile(); // must be called before getting nsIX509CertDB const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB); -const ca_usage = 'SSL CA'; -const int_usage = 'Client,Server,Sign,Encrypt,SSL CA,Status Responder'; -const ee_usage = 'Client,Server,Sign,Encrypt'; - -const cert2usage = { - // certs without the "int" prefix are end entity certs. - 'int-rsa-valid': int_usage, - 'rsa-valid': ee_usage, - 'int-p384-valid': int_usage, - 'p384-valid': ee_usage, - 'int-dsa-valid': int_usage, - 'dsa-valid': ee_usage, - - 'rsa-valid-int-tampered-ee': "", - 'p384-valid-int-tampered-ee': "", - 'dsa-valid-int-tampered-ee': "", - - 'int-rsa-tampered': "", - 'rsa-tampered-int-valid-ee': "", - 'int-p384-tampered': "", - 'p384-tampered-int-valid-ee': "", - 'int-dsa-tampered': "", - 'dsa-tampered-int-valid-ee': "", - -}; - function load_ca(ca_name) { let ca_filename = ca_name + ".der"; addCertFromFile(certdb, "test_cert_signatures/" + ca_filename, 'CTu,CTu,CTu'); +} +function check_ca(ca_name) { do_print("ca_name=" + ca_name); let cert = certdb.findCertByNickname(null, ca_name); let verified = {}; let usages = {}; cert.getUsagesString(true, verified, usages); - do_check_eq(ca_usage, usages.value); + do_check_eq('SSL CA', usages.value); } function run_test() { @@ -69,13 +45,58 @@ function run_test() { load_ca("ca-p384"); load_ca("ca-dsa"); + run_test_in_mode(true); + run_test_in_mode(false); +} + +function run_test_in_mode(useInsanity) { + Services.prefs.setBoolPref("security.use_insanity_verification", useInsanity); + clearOCSPCache(); + clearSessionCache(); + + check_ca("ca-rsa"); + check_ca("ca-p384"); + check_ca("ca-dsa"); + + // insanity::pkix does not allow CA certs to be validated for end-entity + // usages. + let int_usage = useInsanity + ? 'SSL CA' + : 'Client,Server,Sign,Encrypt,SSL CA,Status Responder'; + + // insanity::pkix doesn't implement the Netscape Object Signer restriction. + const ee_usage = useInsanity + ? 'Client,Server,Sign,Encrypt,Object Signer' + : 'Client,Server,Sign,Encrypt'; + + let cert2usage = { + // certs without the "int" prefix are end entity certs. + 'int-rsa-valid': int_usage, + 'rsa-valid': ee_usage, + 'int-p384-valid': int_usage, + 'p384-valid': ee_usage, + 'int-dsa-valid': int_usage, + 'dsa-valid': ee_usage, + + 'rsa-valid-int-tampered-ee': "", + 'p384-valid-int-tampered-ee': "", + 'dsa-valid-int-tampered-ee': "", + + 'int-rsa-tampered': "", + 'rsa-tampered-int-valid-ee': "", + 'int-p384-tampered': "", + 'p384-tampered-int-valid-ee': "", + 'int-dsa-tampered': "", + 'dsa-tampered-int-valid-ee': "", + + }; + // Load certs first for (let cert_name in cert2usage) { let cert_filename = cert_name + ".der"; addCertFromFile(certdb, "test_cert_signatures/" + cert_filename, ',,'); } - // Now do the checks for (let cert_name in cert2usage) { do_print("cert_name=" + cert_name); diff --git a/security/manager/ssl/tests/unit/test_certificate_usages.js b/security/manager/ssl/tests/unit/test_certificate_usages.js index 19ac51f4ad4..4b0be71d5d4 100644 --- a/security/manager/ssl/tests/unit/test_certificate_usages.js +++ b/security/manager/ssl/tests/unit/test_certificate_usages.js @@ -19,89 +19,108 @@ do_get_profile(); // must be called before getting nsIX509CertDB const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(Ci.nsIX509CertDB); -var ca_usages = ['Client,Server,Sign,Encrypt,SSL CA,Status Responder', - 'SSL CA', - 'Client,Server,Sign,Encrypt,SSL CA,Status Responder', - -/* XXX - When using PKIX the usage for the fourth CA (key usage= all but certsigning) the - usage returned is 'Status Responder' only. (no SSL CA) - Thus (self-consistently) the ee_usages are all empty. - - Reading rfc 5280 the combination of basic contraints+usages is not clear: - - Asserted key usage keyCertSign MUST have CA basic contraints. - - CA NOT asserted => keyCertSignt MUST NOT be asserted. - - But the tests include -> basic CA asserted and Keyusage NOT asserted. - In this case, the 'classic' mode uses the 'union' of the capabilites -> - the cert is considered a CA. libpkix uses the 'intersection' of - capabilites, the cert is NOT considered a CA. - - I think the intersection is a better way to interpret this as the extension - is marked as critical. - - This should be: 'Status Responder' - -*/ - 'Client,Server,Sign,Encrypt,Status Responder']; - -var ee_usages = [ - ['Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - '', - 'Client,Server,Sign,Encrypt,Object Signer,Status Responder', - 'Client,Server', - 'Sign,Encrypt,Object Signer', - 'Server,Status Responder' - ], - ['Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - '', - 'Client,Server,Sign,Encrypt,Object Signer,Status Responder', - 'Client,Server', - 'Sign,Encrypt,Object Signer', - 'Server,Status Responder' - ], - ['Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - '', - 'Client,Server,Sign,Encrypt,Object Signer,Status Responder', - 'Client,Server', - 'Sign,Encrypt,Object Signer', - 'Server,Status Responder' - ], - -/* XXX - The values for the following block of tests should all be empty - */ - - ['Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - 'Client,Server,Sign,Encrypt', - '', - 'Client,Server,Sign,Encrypt,Object Signer,Status Responder', - 'Client,Server', - 'Sign,Encrypt,Object Signer', - 'Server,Status Responder' - ] - ]; - +const gNumCAs = 4; function run_test() { //ca's are one based! - for (var i = 0; i < ca_usages.length; i++) { + for (var i = 0; i < gNumCAs; i++) { var ca_name = "ca-" + (i + 1); var ca_filename = ca_name + ".der"; addCertFromFile(certdb, "test_certificate_usages/" + ca_filename, "CTu,CTu,CTu"); do_print("ca_name=" + ca_name); - var cert; - cert = certdb.findCertByNickname(null, ca_name); + var cert = certdb.findCertByNickname(null, ca_name); + } + run_test_in_mode(true); + run_test_in_mode(false); +} + +function run_test_in_mode(useInsanity) { + Services.prefs.setBoolPref("security.use_insanity_verification", useInsanity); + clearOCSPCache(); + clearSessionCache(); + + // insanity::pkix does not allow CA certs to be validated for non-CA usages. + var allCAUsages = useInsanity + ? 'SSL CA' + : 'Client,Server,Sign,Encrypt,SSL CA,Status Responder'; + + // insanity::pkix doesn't allow CA certificates to have the Status Responder + // EKU. + var ca_usages = [allCAUsages, + 'SSL CA', + allCAUsages, + useInsanity ? '' + : 'Client,Server,Sign,Encrypt,Status Responder']; + + // insanity::pkix doesn't implement the Netscape Object Signer restriction. + var basicEndEntityUsages = useInsanity + ? 'Client,Server,Sign,Encrypt,Object Signer' + : 'Client,Server,Sign,Encrypt'; + var basicEndEntityUsagesWithObjectSigner = basicEndEntityUsages + ",Object Signer" + + // insanity::pkix won't let a certificate with the "Status Responder" EKU get + // validated for any other usage. + var statusResponderUsages = (useInsanity ? "" : "Server,") + "Status Responder"; + var statusResponderUsagesFull + = useInsanity ? statusResponderUsages + : basicEndEntityUsages + ',Object Signer,Status Responder'; + + var ee_usages = [ + [ basicEndEntityUsages, + basicEndEntityUsages, + basicEndEntityUsages, + '', + statusResponderUsagesFull, + 'Client,Server', + 'Sign,Encrypt,Object Signer', + statusResponderUsages + ], + + [ basicEndEntityUsages, + basicEndEntityUsages, + basicEndEntityUsages, + '', + statusResponderUsagesFull, + 'Client,Server', + 'Sign,Encrypt,Object Signer', + statusResponderUsages + ], + + [ basicEndEntityUsages, + basicEndEntityUsages, + basicEndEntityUsages, + '', + statusResponderUsagesFull, + 'Client,Server', + 'Sign,Encrypt,Object Signer', + statusResponderUsages + ], + + // The CA has isCA=true without keyCertSign. + // + // The 'classic' NSS mode uses the 'union' of the + // capabilites so the cert is considered a CA. + // insanity::pkix and libpkix use the intersection of + // capabilites, so the cert is NOT considered a CA. + [ useInsanity ? '' : basicEndEntityUsages, + useInsanity ? '' : basicEndEntityUsages, + useInsanity ? '' : basicEndEntityUsages, + '', + useInsanity ? '' : statusResponderUsagesFull, + useInsanity ? '' : 'Client,Server', + useInsanity ? '' : 'Sign,Encrypt,Object Signer', + useInsanity ? '' : 'Server,Status Responder' + ] + ]; + + do_check_eq(gNumCAs, ca_usages.length); + + for (var i = 0; i < gNumCAs; i++) { + var ca_name = "ca-" + (i + 1); var verified = {}; var usages = {}; + var cert = certdb.findCertByNickname(null, ca_name); cert.getUsagesString(true, verified, usages); do_print("usages.value=" + usages.value); do_check_eq(ca_usages[i], usages.value); @@ -120,7 +139,5 @@ function run_test() { do_print("cert usages.value=" + usages.value); do_check_eq(ee_usages[i][j], usages.value); } - } - } diff --git a/security/manager/ssl/tests/unit/test_getchain.js b/security/manager/ssl/tests/unit/test_getchain.js index 7e95c3bd084..7510f5db1df 100644 --- a/security/manager/ssl/tests/unit/test_getchain.js +++ b/security/manager/ssl/tests/unit/test_getchain.js @@ -70,7 +70,11 @@ function check_getchain(ee_cert, ssl_ca, email_ca){ check_matching_issuer_and_getchain(ee_cert.issuer.serialNumber, ee_cert); } -function run_test() { +function run_test_in_mode(useInsanity) { + Services.prefs.setBoolPref("security.use_insanity_verification", useInsanity); + clearOCSPCache(); + clearSessionCache(); + for (let i = 0 ; i < certList.length; i++) { load_cert(certList[i], ',,'); } @@ -83,7 +87,9 @@ function run_test() { check_getchain(ee_cert, ca[1], ca[2]); // Swap ca certs to deal alternate trust settings. check_getchain(ee_cert, ca[2], ca[1]); - - run_next_test(); } +function run_test() { + run_test_in_mode(true); + run_test_in_mode(false); +} diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints.js b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints.js new file mode 100644 index 00000000000..72aa31bca5c --- /dev/null +++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints.js @@ -0,0 +1,139 @@ +"use strict"; +/* To regenerate the certificates for this test: + * + * cd security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints + * ./generate.py + * cd ../../../../../.. + * make -C $OBJDIR/security/manager/ssl/tests + * + * Check in the generated files. These steps are not done as part of the build + * because we do not want to add a build-time dependency on the OpenSSL or NSS + * tools or libraries built for the host platform. + */ + +do_get_profile(); // must be called before getting nsIX509CertDB +const certdb = Cc["@mozilla.org/security/x509certdb;1"] + .getService(Ci.nsIX509CertDB); + +function load_cert(name, trust) { + let filename = "test_intermediate_basic_usage_constraints/" + name + ".der"; + addCertFromFile(certdb, filename, trust); +} + +function test_cert_for_usages(certChainNicks, expected_usages_string) { + let certs = []; + for (let i in certChainNicks) { + let certNick = certChainNicks[i]; + let certDER = readFile(do_get_file( + "test_intermediate_basic_usage_constraints/" + + certNick + ".der"), false); + certs.push(certdb.constructX509(certDER, certDER.length)); + } + + let cert = certs[0]; + let verified = {}; + let usages = {}; + cert.getUsagesString(true, verified, usages); + do_print("usages.value = " + usages.value); + do_check_eq(expected_usages_string, usages.value); +} + +function run_test_in_mode(useInsanity) { + Services.prefs.setBoolPref("security.use_insanity_verification", useInsanity); + + // insanity::pkix doesn't support the obsolete Netscape object signing + // extension, but NSS does. + let ee_usage1 = useInsanity + ? 'Client,Server,Sign,Encrypt,Object Signer' + : 'Client,Server,Sign,Encrypt' + + // insanity::pkix doesn't validate CA certificates for non-CA uses, but + // NSS does. + let ca_usage1 = useInsanity + ? "SSL CA" + : 'Client,Server,Sign,Encrypt,SSL CA,Status Responder'; + + // Load the ca into mem + let ca_name = "ca"; + load_cert(ca_name, "CTu,CTu,CTu"); + do_print("ca_name = " + ca_name); + test_cert_for_usages([ca_name], ca_usage1); + + // A certificate with no basicConstraints extension is considered an EE. + test_cert_for_usages(["int-no-extensions"], ee_usage1); + + // int-no-extensions is an EE (see previous case), so no certs can chain to + // it. + test_cert_for_usages(["ee-int-no-extensions", "int-no-extensions"], ""); + + // a certificate with bsaicConstraints.cA==false is considered an EE. + test_cert_for_usages(["int-not-a-ca"], ee_usage1); + + // int-not-a-ca is an EE (see previous case), so no certs can chain to it. + test_cert_for_usages(["ee-int-not-a-ca", "int-not-a-ca"], ""); + + // int-limited-depth has cA==true and a path length constraint of zero. + test_cert_for_usages(["int-limited-depth"], ca_usage1); + + // path length constraints do not affect the ability of a non-CA cert to + // chain to to the CA cert. + test_cert_for_usages(["ee-int-limited-depth", "int-limited-depth"], + ee_usage1); + + // ca + // int-limited-depth (cA==true, pathLenConstraint==0) + // int-limited-depth-invalid (cA==true) + // + // XXX: It seems the NSS code does not consider the path length of the + // certificate we're validating, but insanity::pkix does. insanity::pkix's + // behavior is correct. + test_cert_for_usages(["int-limited-depth-invalid", "int-limited-depth"], + useInsanity ? "" : ca_usage1); + test_cert_for_usages(["ee-int-limited-depth-invalid", + "int-limited-depth-invalid", + "int-limited-depth"], + ""); + + // int-valid-ku-no-eku has keyCertSign + test_cert_for_usages(["int-valid-ku-no-eku"], "SSL CA"); + test_cert_for_usages(["ee-int-valid-ku-no-eku", "int-valid-ku-no-eku"], + ee_usage1); + + // int-bad-ku-no-eku has basicConstraints.cA==true and has a KU extension + // but the KU extension is missing keyCertSign. Note that insanity::pkix + // doesn't validate certificates with basicConstraints.Ca==true for non-CA + // uses, but NSS does. + test_cert_for_usages(["int-bad-ku-no-eku"], + useInsanity + ? "" + : 'Client,Server,Sign,Encrypt,Status Responder'); + test_cert_for_usages(["ee-int-bad-ku-no-eku", "int-bad-ku-no-eku"], ""); + + // int-no-ku-no-eku has basicConstraints.cA==true and no KU extension. + // We treat a missing KU as "any key usage is OK". + test_cert_for_usages(["int-no-ku-no-eku"], ca_usage1); + test_cert_for_usages(["ee-int-no-ku-no-eku", "int-no-ku-no-eku"], ee_usage1); + + // int-valid-ku-server-eku has basicConstraints.cA==true, keyCertSign in KU, + // and EKU=={id-kp-serverAuth,id-kp-clientAuth}. + test_cert_for_usages(["int-valid-ku-server-eku"], "SSL CA"); + test_cert_for_usages(["ee-int-valid-ku-server-eku", + "int-valid-ku-server-eku"], "Client,Server"); + + // int-bad-ku-server-eku has basicConstraints.cA==true, a KU without + // keyCertSign, and EKU=={id-kp-serverAuth,id-kp-clientAuth}. + test_cert_for_usages(["int-bad-ku-server-eku"], ""); + test_cert_for_usages(["ee-int-bad-ku-server-eku", "int-bad-ku-server-eku"], + ""); + + // int-bad-ku-server-eku has basicConstraints.cA==true, no KU, and + // EKU=={id-kp-serverAuth,id-kp-clientAuth}. + test_cert_for_usages(["int-no-ku-server-eku"], "SSL CA"); + test_cert_for_usages(["ee-int-no-ku-server-eku", "int-no-ku-server-eku"], + "Client,Server"); +} + +function run_test() { + run_test_in_mode(true); + run_test_in_mode(false); +} diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.der new file mode 100644 index 00000000000..ef708fb1329 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ca.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.der new file mode 100644 index 00000000000..43e2acf2d35 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-no-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.der new file mode 100644 index 00000000000..80c041ec1f5 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-bad-ku-server-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.der new file mode 100644 index 00000000000..ba301ad0164 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth-invalid.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.der new file mode 100644 index 00000000000..3b40ea44a3e Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-limited-depth.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.der new file mode 100644 index 00000000000..5a2a5f41dad Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-extensions.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.der new file mode 100644 index 00000000000..e7199a84429 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-no-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.der new file mode 100644 index 00000000000..90aff830418 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-no-ku-server-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.der new file mode 100644 index 00000000000..cc4e018df32 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-not-a-ca.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.der new file mode 100644 index 00000000000..0d682325152 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-no-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.der new file mode 100644 index 00000000000..abbb4783105 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/ee-int-valid-ku-server-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/generate.py b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/generate.py new file mode 100644 index 00000000000..1484e94dc35 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/generate.py @@ -0,0 +1,99 @@ +#!/usr/bin/python + +# 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/. + +# requires openssl >= 1.0.0 + +import tempfile, os, sys, random +libpath = os.path.abspath('../psm_common_py') + +sys.path.append(libpath) + +import CertUtils + + +srcdir = os.getcwd() +db = tempfile.mkdtemp() + +CA_basic_constraints = "basicConstraints = critical, CA:TRUE\n" +CA_limited_basic_constraints = "basicConstraints = critical,CA:TRUE, pathlen:0\n" +EE_basic_constraints = "basicConstraints = CA:FALSE\n" + +CA_min_ku = "keyUsage = critical, keyCertSign\n" +CA_bad_ku = "keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, cRLSign\n" +EE_full_ku ="keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement\n" + +Server_eku = "extendedKeyUsage = critical, serverAuth, clientAuth\n " + +key_type = 'rsa' + +def generate_int_and_ee2(ca_key, ca_cert, suffix, int_ext_text, ee_ext_text): + int_name = "int-" + suffix; + ee_name = "ee-int-" + suffix; + int_serial = random.randint(100, 40000000); + ee_serial = random.randint(100, 40000000); + [int_key, int_cert] = CertUtils.generate_cert_generic(db, + srcdir, + int_serial, + key_type, + int_name, + int_ext_text, + ca_key, + ca_cert); + [ee_key, ee_cert] = CertUtils.generate_cert_generic(db, + srcdir, + ee_serial, + key_type, + ee_name, + ee_ext_text, + int_key, + int_cert); + return [int_key, int_cert, ee_key, ee_cert] + +def generate_certs(): + ca_name = "ca" + [ca_key, ca_cert ] = CertUtils.generate_cert_generic(db, + srcdir, + 1, + key_type, + ca_name, + CA_basic_constraints) + ee_ext_text = EE_basic_constraints + EE_full_ku + + #now the intermediates + generate_int_and_ee2(ca_key, ca_cert, "no-extensions", "", ee_ext_text) + generate_int_and_ee2(ca_key, ca_cert, "not-a-ca", EE_basic_constraints, + ee_ext_text) + + [int_key, int_cert, a, b] = generate_int_and_ee2(ca_key, ca_cert, + "limited-depth", + CA_limited_basic_constraints, + ee_ext_text); + #and a child using this one + generate_int_and_ee2(int_key, int_cert, "limited-depth-invalid", + CA_basic_constraints, ee_ext_text); + + # now we do it again for valid basic constraints but strange eku/ku at the + # intermediate layer + generate_int_and_ee2(ca_key, ca_cert, "valid-ku-no-eku", + CA_basic_constraints + CA_min_ku, ee_ext_text); + generate_int_and_ee2(ca_key, ca_cert, "bad-ku-no-eku", + CA_basic_constraints + CA_bad_ku, ee_ext_text); + generate_int_and_ee2(ca_key, ca_cert, "no-ku-no-eku", + CA_basic_constraints, ee_ext_text); + + generate_int_and_ee2(ca_key, ca_cert, "valid-ku-server-eku", + CA_basic_constraints + CA_min_ku + Server_eku, + ee_ext_text); + generate_int_and_ee2(ca_key, ca_cert, "bad-ku-server-eku", + CA_basic_constraints + CA_bad_ku + Server_eku, + ee_ext_text); + generate_int_and_ee2(ca_key, ca_cert, "no-ku-server-eku", + CA_basic_constraints + Server_eku, ee_ext_text); + + +generate_certs() + + diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.der new file mode 100644 index 00000000000..0dbed201b56 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-no-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.der new file mode 100644 index 00000000000..8957ccf7b6b Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-bad-ku-server-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.der new file mode 100644 index 00000000000..bd9b6d8828a Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth-invalid.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.der new file mode 100644 index 00000000000..078ad25c703 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-limited-depth.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.der new file mode 100644 index 00000000000..458272a20bb Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-extensions.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.der new file mode 100644 index 00000000000..8cb3b6134b8 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-no-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.der new file mode 100644 index 00000000000..303f64241c4 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-no-ku-server-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.der new file mode 100644 index 00000000000..76914ec4702 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-not-a-ca.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.der new file mode 100644 index 00000000000..9b000a6f4f1 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-no-eku.der differ diff --git a/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.der b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.der new file mode 100644 index 00000000000..63d1563e0ea Binary files /dev/null and b/security/manager/ssl/tests/unit/test_intermediate_basic_usage_constraints/int-valid-ku-server-eku.der differ diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index 41f08c9aa79..61a4aefd036 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -8,6 +8,7 @@ support-files = test_cert_signatures/** test_ev_certs/** test_getchain/** + test_intermediate_basic_usage_constraints/** [test_certificate_usages.js] # Bug 676972: test fails consistently on Android @@ -60,3 +61,7 @@ fail-if = os == "android" [test_getchain.js] # Bug 676972: test fails consistently on Android fail-if = os == "android" +[test_intermediate_basic_usage_constraints.js] +# Bug 676972: test hangs consistently on Android +skip-if = os == "android" + diff --git a/storage/src/mozStorageStatementRow.cpp b/storage/src/mozStorageStatementRow.cpp index 65077e89e1c..3a0886da719 100644 --- a/storage/src/mozStorageStatementRow.cpp +++ b/storage/src/mozStorageStatementRow.cpp @@ -86,7 +86,7 @@ StatementRow::GetProperty(nsIXPConnectWrappedNative *aWrapper, uint32_t length; const uint8_t *blob = static_cast(mStatement)-> AsSharedBlob(idx, &length); - JSObject *obj = ::JS_NewArrayObject(aCtx, length, nullptr); + JSObject *obj = ::JS_NewArrayObject(aCtx, length); if (!obj) { *_retval = false; return NS_OK; diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index 7a142f8afbb..2e93abdd2d0 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -383,6 +383,14 @@ class MochitestOptions(optparse.OptionParser): "help": "Produce a DMD dump after each test in the directory specified " "by --dump-output-directory." }], + [["--slowscript"], + { "action": "store_true", + "default": False, + "dest": "slowscript", + "help": "Do not set the JS_DISABLE_SLOW_SCRIPT_SIGNALS env variable; " + "when not set, recoverable but misleading SIGSEGV instances " + "may occur in Ion/Odin JIT code." + }], ] def __init__(self, **kwargs): diff --git a/toolkit/components/downloads/nsDownloadScanner.h b/toolkit/components/downloads/nsDownloadScanner.h index 32723d13d34..2dd5fd8ea6d 100644 --- a/toolkit/components/downloads/nsDownloadScanner.h +++ b/toolkit/components/downloads/nsDownloadScanner.h @@ -11,7 +11,6 @@ #ifdef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN #endif -#define INITGUID #include #define AVVENDOR #include diff --git a/toolkit/components/places/History.cpp b/toolkit/components/places/History.cpp index 37dee5bf496..33ea3bde3ce 100644 --- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -248,7 +248,7 @@ GetJSArrayFromJSValue(JS::Handle aValue, // Build a temporary array to store this one item so the code below can // just loop. *_arrayLength = 1; - _array.set(JS_NewArrayObject(aCtx, 0, nullptr)); + _array.set(JS_NewArrayObject(aCtx, 0)); NS_ENSURE_TRUE(_array, NS_ERROR_OUT_OF_MEMORY); bool rc = JS_DefineElement(aCtx, _array, 0, aValue, nullptr, nullptr, 0); diff --git a/toolkit/components/places/PlaceInfo.cpp b/toolkit/components/places/PlaceInfo.cpp index a7b6d739ded..f31d874b671 100644 --- a/toolkit/components/places/PlaceInfo.cpp +++ b/toolkit/components/places/PlaceInfo.cpp @@ -101,7 +101,7 @@ PlaceInfo::GetVisits(JSContext* aContext, // TODO bug 625913 when we use this in situations that have more than one // visit here, we will likely want to make this cache the value. JS::Rooted visits(aContext, - JS_NewArrayObject(aContext, 0, nullptr)); + JS_NewArrayObject(aContext, 0)); NS_ENSURE_TRUE(visits, NS_ERROR_OUT_OF_MEMORY); JS::Rooted global(aContext, JS::CurrentGlobalOrNull(aContext)); diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 40247d5fb1c..d26431806af 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -458,17 +458,16 @@ bool TelemetryIOInterposeObserver::ReflectFileStats(FileIOEntryType* entry, } // Array we want to report - jsval stats[] = { - JS_NumberValue(entry->mData.totalTime), - UINT_TO_JSVAL(entry->mData.creates), - UINT_TO_JSVAL(entry->mData.reads), - UINT_TO_JSVAL(entry->mData.writes), - UINT_TO_JSVAL(entry->mData.fsyncs), - UINT_TO_JSVAL(entry->mData.stats) - }; + JS::AutoValueArray<6> stats(cx); + stats[0].setNumber(entry->mData.totalTime); + stats[1].setNumber(entry->mData.creates); + stats[2].setNumber(entry->mData.reads); + stats[3].setNumber(entry->mData.writes); + stats[4].setNumber(entry->mData.fsyncs); + stats[5].setNumber(entry->mData.stats); // Create jsEntry as array of elements above - JS::RootedObject jsEntry(cx, JS_NewArrayObject(cx, ArrayLength(stats), stats)); + JS::RootedObject jsEntry(cx, JS_NewArrayObject(cx, stats)); if (!jsEntry) { return false; } @@ -804,7 +803,7 @@ ReflectHistogramAndSamples(JSContext *cx, JS::Handle obj, Histogram * } const size_t count = h->bucket_count(); - JS::Rooted rarray(cx, JS_NewArrayObject(cx, count, nullptr)); + JS::Rooted rarray(cx, JS_NewArrayObject(cx, count)); if (!rarray) { return REFLECT_FAILURE; } @@ -814,7 +813,7 @@ ReflectHistogramAndSamples(JSContext *cx, JS::Handle obj, Histogram * return REFLECT_FAILURE; } - JS::Rooted counts_array(cx, JS_NewArrayObject(cx, count, nullptr)); + JS::Rooted counts_array(cx, JS_NewArrayObject(cx, count)); if (!counts_array) { return REFLECT_FAILURE; } @@ -1245,7 +1244,7 @@ TelemetryImpl::ReflectSQL(const SlowSQLEntryType *entry, const nsACString &sql = entry->GetKey(); - JS::Rooted arrayObj(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted arrayObj(cx, JS_NewArrayObject(cx, 0)); if (!arrayObj) { return false; } @@ -1739,9 +1738,9 @@ TelemetryImpl::GetChromeHangs(JSContext *cx, JS::MutableHandle ret) ret.setObject(*fullReportObj); - JS::Rooted durationArray(cx, JS_NewArrayObject(cx, 0, nullptr)); - JS::Rooted systemUptimeArray(cx, JS_NewArrayObject(cx, 0, nullptr)); - JS::Rooted firefoxUptimeArray(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted durationArray(cx, JS_NewArrayObject(cx, 0)); + JS::Rooted systemUptimeArray(cx, JS_NewArrayObject(cx, 0)); + JS::Rooted firefoxUptimeArray(cx, JS_NewArrayObject(cx, 0)); if (!durationArray || !systemUptimeArray || !firefoxUptimeArray) { return NS_ERROR_FAILURE; } @@ -1790,7 +1789,7 @@ CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) { return nullptr; } - JS::Rooted moduleArray(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted moduleArray(cx, JS_NewArrayObject(cx, 0)); if (!moduleArray) { return nullptr; } @@ -1807,7 +1806,7 @@ CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) { const Telemetry::ProcessedStack::Module& module = stacks.GetModule(moduleIndex); - JS::Rooted moduleInfoArray(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted moduleInfoArray(cx, JS_NewArrayObject(cx, 0)); if (!moduleInfoArray) { return nullptr; } @@ -1836,7 +1835,7 @@ CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) { } } - JS::Rooted reportArray(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted reportArray(cx, JS_NewArrayObject(cx, 0)); if (!reportArray) { return nullptr; } @@ -1850,7 +1849,7 @@ CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) { const size_t length = stacks.GetStackCount(); for (size_t i = 0; i < length; ++i) { // Represent call stack PCs as (module index, offset) pairs. - JS::Rooted pcArray(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted pcArray(cx, JS_NewArrayObject(cx, 0)); if (!pcArray) { return nullptr; } @@ -1863,7 +1862,7 @@ CreateJSStackObject(JSContext *cx, const CombinedStacks &stacks) { const uint32_t pcCount = stack.size(); for (size_t pcIndex = 0; pcIndex < pcCount; ++pcIndex) { const Telemetry::ProcessedStack::Frame& frame = stack[pcIndex]; - JS::Rooted framePair(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::Rooted framePair(cx, JS_NewArrayObject(cx, 0)); if (!framePair) { return nullptr; } @@ -2005,9 +2004,9 @@ CreateJSTimeHistogram(JSContext* cx, const Telemetry::TimeHistogram& time) } JS::RootedObject ranges( - cx, JS_NewArrayObject(cx, ArrayLength(time) + 1, nullptr)); + cx, JS_NewArrayObject(cx, ArrayLength(time) + 1)); JS::RootedObject counts( - cx, JS_NewArrayObject(cx, ArrayLength(time) + 1, nullptr)); + cx, JS_NewArrayObject(cx, ArrayLength(time) + 1)); if (!ranges || !counts) { return nullptr; } @@ -2042,7 +2041,7 @@ CreateJSHangHistogram(JSContext* cx, const Telemetry::HangHistogram& hang) const Telemetry::HangHistogram::Stack& hangStack = hang.GetStack(); JS::RootedObject stack(cx, - JS_NewArrayObject(cx, hangStack.length(), nullptr)); + JS_NewArrayObject(cx, hangStack.length())); if (!ret) { return nullptr; } @@ -2085,7 +2084,7 @@ CreateJSThreadHangStats(JSContext* cx, const Telemetry::ThreadHangStats& thread) return nullptr; } - JS::RootedObject hangs(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::RootedObject hangs(cx, JS_NewArrayObject(cx, 0)); if (!hangs) { return nullptr; } @@ -2105,12 +2104,13 @@ CreateJSThreadHangStats(JSContext* cx, const Telemetry::ThreadHangStats& thread) NS_IMETHODIMP TelemetryImpl::GetThreadHangStats(JSContext* cx, JS::MutableHandle ret) { - JS::RootedObject retObj(cx, JS_NewArrayObject(cx, 0, nullptr)); + JS::RootedObject retObj(cx, JS_NewArrayObject(cx, 0)); if (!retObj) { return NS_ERROR_FAILURE; } size_t threadIndex = 0; +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR /* First add active threads; we need to hold |iter| (and its lock) throughout this method to avoid a race condition where a thread can be recorded twice if the thread is destroyed while this method is @@ -2124,6 +2124,7 @@ TelemetryImpl::GetThreadHangStats(JSContext* cx, JS::MutableHandle re return NS_ERROR_FAILURE; } } +#endif // Add saved threads next MutexAutoLock autoLock(mThreadHangStatsMutex); diff --git a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js index 3acb744d2a5..25bac79365d 100644 --- a/toolkit/content/tests/chrome/file_autocomplete_with_composition.js +++ b/toolkit/content/tests/chrome/file_autocomplete_with_composition.js @@ -280,7 +280,7 @@ nsDoTestsForAutoCompleteWithComposition.prototype = { { description: "compositionupdate shouldn't reopen the popup", completeDefaultIndex: false, execute: function (aWindow) { - synthesizeComposition({ type: "compositionupdate", data: "ll" }, aWindow); + synthesizeComposition({ type: "compositionupdate", data: "zi" }, aWindow); synthesizeText( { "composition": { "string": "zi", diff --git a/tools/profiler/JSObjectBuilder.cpp b/tools/profiler/JSObjectBuilder.cpp index c2a350fb5b8..d698cf0945e 100644 --- a/tools/profiler/JSObjectBuilder.cpp +++ b/tools/profiler/JSObjectBuilder.cpp @@ -127,7 +127,7 @@ JSObjectBuilder::ArrayPush(JS::HandleObject aArray, JS::HandleObject aObject) JSObject* JSObjectBuilder::CreateArray() { - JSObject *array = JS_NewArrayObject(mCx, 0, nullptr); + JSObject *array = JS_NewArrayObject(mCx, 0); if (!array) mOk = false; diff --git a/uriloader/exthandler/win/nsOSHelperAppService.h b/uriloader/exthandler/win/nsOSHelperAppService.h index 8e1c961dca5..099cbc64d86 100644 --- a/uriloader/exthandler/win/nsOSHelperAppService.h +++ b/uriloader/exthandler/win/nsOSHelperAppService.h @@ -20,7 +20,6 @@ #undef _WIN32_WINNT #endif #define _WIN32_WINNT 0x0600 -#define INITGUID #include class nsMIMEInfoWin; diff --git a/widget/TextEvents.h b/widget/TextEvents.h index 589924ecce6..5b574292d49 100644 --- a/widget/TextEvents.h +++ b/widget/TextEvents.h @@ -236,6 +236,16 @@ public: // Currently, we don't need to copy the other members because they are // for internal use only (not available from JS). } + + bool IsComposing() const + { + for (uint32_t i = 0; i < rangeCount; i++) { + if (rangeArray[i].IsClause()) { + return true; + } + } + return false; + } }; /****************************************************************************** diff --git a/widget/TextRange.h b/widget/TextRange.h index 77e3cbd3bc1..085a2843c2f 100644 --- a/widget/TextRange.h +++ b/widget/TextRange.h @@ -147,6 +147,14 @@ struct TextRange TextRangeStyle mRangeStyle; uint32_t Length() const { return mEndOffset - mStartOffset; } + + bool IsClause() const + { + MOZ_ASSERT(mRangeType >= NS_TEXTRANGE_CARETPOSITION && + mRangeType <= NS_TEXTRANGE_SELECTEDCONVERTEDTEXT, + "Invalid range type"); + return mRangeType != NS_TEXTRANGE_CARETPOSITION; + } }; /****************************************************************************** diff --git a/widget/windows/nsToolkit.cpp b/widget/windows/nsToolkit.cpp index e5551b7df29..5a3449be9ee 100644 --- a/widget/windows/nsToolkit.cpp +++ b/widget/windows/nsToolkit.cpp @@ -12,7 +12,6 @@ #include "nsIServiceManager.h" #include "nsComponentManagerUtils.h" #include -#include #include "WinUtils.h" #include "nsUXThemeData.h" diff --git a/xpcom/base/WindowsVersion.h b/xpcom/base/WindowsVersion.h index 0d860be0b25..5d56d177c60 100644 --- a/xpcom/base/WindowsVersion.h +++ b/xpcom/base/WindowsVersion.h @@ -114,10 +114,10 @@ namespace mozilla { return IsWindowsVersionOrLater(0x06020000ul); } MOZ_ALWAYS_INLINE bool - IsWin7RTMOrLater() + IsNotWin7PreRTM() { - return IsWin7SP1OrLater() || - (IsWin7OrLater() && IsWindowsBuildOrLater(7600)); + return IsWin7SP1OrLater() || !IsWin7OrLater() || + IsWindowsBuildOrLater(7600); } } diff --git a/xpcom/io/nsIFile.idl b/xpcom/io/nsIFile.idl index 2392c6f4136..332bc5329ac 100644 --- a/xpcom/io/nsIFile.idl +++ b/xpcom/io/nsIFile.idl @@ -42,7 +42,7 @@ interface nsISimpleEnumerator; * be safely passed to javascript via xpconnect. Therefore, the "native * methods" are not scriptable. */ -[scriptable, uuid(272a5020-64f5-485c-a8c4-44b2882ae0a2), builtinclass] +[scriptable, uuid(a99a6a06-f90d-4659-8fce-c2f87feb1167), builtinclass] interface nsIFile : nsISupports { /** @@ -180,6 +180,16 @@ interface nsIFile : nsISupports void moveTo(in nsIFile newParentDir, in AString newName); [noscript] void moveToNative(in nsIFile newParentDir, in ACString newName); + /** + * renameTo + * + * This method is identical to moveTo except that if this file or directory + * is moved to a a different volume, it fails and returns an error + * (NS_ERROR_FILE_ACCESS_DENIED). + * This object will still point to the old location after renaming. + */ + void renameTo(in nsIFile newParentDir, in AString newName); + /** * This will try to delete this file. The 'recursive' flag * must be PR_TRUE to delete directories which are not empty. diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index 9297851657f..bacf06c4047 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -2000,6 +2000,43 @@ nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) { SET_UCS_2ARGS_2(MoveToNative, newParentDir, newName); } + +NS_IMETHODIMP +nsLocalFile::RenameTo(nsIFile *newParentDir, const nsAString &newName) +{ + nsresult rv; + + // check to make sure that this has been initialized properly + CHECK_mPath(); + + // check to make sure that we have a new parent + nsAutoCString newPathName; + nsAutoCString newNativeName; + rv = NS_CopyUnicodeToNative(newName, newNativeName); + if (NS_FAILED(rv)) { + return rv; + } + rv = GetNativeTargetPathName(newParentDir, newNativeName, newPathName); + if (NS_FAILED(rv)) { + return rv; + } + + // try for atomic rename + if (rename(mPath.get(), newPathName.get()) < 0) { +#ifdef VMS + if (errno == EXDEV || errno == ENXIO) { +#else + if (errno == EXDEV) { +#endif + rv = NS_ERROR_FILE_ACCESS_DENIED; + } else { + rv = NSRESULT_FOR_ERRNO(); + } + } + + return rv; +} + nsresult nsLocalFile::GetTarget(nsAString &_retval) { diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 5e438d2668b..1e484e2ddf3 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -1781,13 +1781,13 @@ IsRemoteFilePath(LPCWSTR path, bool &remote) nsresult nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, - const nsAString &newName, - bool followSymlinks, bool move, - bool skipNtfsAclReset) + const nsAString &newName, uint32_t options) { - nsresult rv; + nsresult rv = NS_OK; nsAutoString filePath; + bool move = options & (Move | Rename); + // get the path that we are going to copy to. // Since windows does not know how to auto // resolve shortcuts, we must work with the @@ -1809,7 +1809,7 @@ nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, } - if (followSymlinks) + if (options & FollowSymlinks) { rv = sourceFile->GetTarget(filePath); if (filePath.IsEmpty()) @@ -1855,6 +1855,9 @@ nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, // as this could be an SMBV2 mapped drive. if (!copyOK && GetLastError() == ERROR_NOT_SAME_DEVICE) { + if (options & Rename) { + return NS_ERROR_FILE_ACCESS_DENIED; + } copyOK = CopyFileExW(filePath.get(), destPath.get(), nullptr, nullptr, nullptr, dwCopyFlags); @@ -1865,7 +1868,7 @@ nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, if (!copyOK) // CopyFileEx and MoveFileEx return zero at failure. rv = ConvertWinError(GetLastError()); - else if (move && !skipNtfsAclReset) + else if (move && !(options & SkipNtfsAclReset)) { // Set security permissions to inherit from parent. // Note: propagates to all children: slow for big file trees @@ -1887,13 +1890,16 @@ nsLocalFile::CopySingleFile(nsIFile *sourceFile, nsIFile *destParent, } nsresult -nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool followSymlinks, bool move) +nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, uint32_t options) { + bool move = options & (Move | Rename); + bool followSymlinks = options & FollowSymlinks; + nsCOMPtr newParentDir = aParentDir; // check to see if this exists, otherwise return an error. // we will check this by resolving. If the user wants us // to follow links, then we are talking about the target, - // hence we can use the |followSymlinks| parameter. + // hence we can use the |FollowSymlinks| option. nsresult rv = ResolveAndStat(); if (NS_FAILED(rv)) return rv; @@ -1945,7 +1951,7 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow if (NS_FAILED(rv)) return rv; - return CopyMove(realDest, newName, followSymlinks, move); + return CopyMove(realDest, newName, options); } } else @@ -1966,8 +1972,10 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow if (move || !isDir || (isSymlink && !followSymlinks)) { // Copy/Move single file, or move a directory - rv = CopySingleFile(this, newParentDir, newName, followSymlinks, move, - !aParentDir); + if (!aParentDir) { + options |= SkipNtfsAclReset; + } + rv = CopySingleFile(this, newParentDir, newName, options); done = NS_SUCCEEDED(rv); // If we are moving a directory and that fails, fallback on directory // enumeration. See bug 231300 for details. @@ -2135,21 +2143,72 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow NS_IMETHODIMP nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) { - return CopyMove(newParentDir, newName, false, false); + return CopyMove(newParentDir, newName, 0); } NS_IMETHODIMP nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) { - return CopyMove(newParentDir, newName, true, false); + return CopyMove(newParentDir, newName, FollowSymlinks); } NS_IMETHODIMP nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) { - return CopyMove(newParentDir, newName, false, true); + return CopyMove(newParentDir, newName, Move); } +NS_IMETHODIMP +nsLocalFile::RenameTo(nsIFile *newParentDir, const nsAString & newName) +{ + nsCOMPtr targetParentDir = newParentDir; + // check to see if this exists, otherwise return an error. + // we will check this by resolving. If the user wants us + // to follow links, then we are talking about the target, + // hence we can use the |followSymlinks| parameter. + nsresult rv = ResolveAndStat(); + if (NS_FAILED(rv)) { + return rv; + } + + if (!targetParentDir) { + // no parent was specified. We must rename. + if (newName.IsEmpty()) { + return NS_ERROR_INVALID_ARG; + } + rv = GetParent(getter_AddRefs(targetParentDir)); + if (NS_FAILED(rv)) { + return rv; + } + } + + if (!targetParentDir) { + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + + // make sure it exists and is a directory. Create it if not there. + bool exists; + targetParentDir->Exists(&exists); + if (!exists) { + rv = targetParentDir->Create(DIRECTORY_TYPE, 0644); + if (NS_FAILED(rv)) { + return rv; + } + } else { + bool isDir; + targetParentDir->IsDirectory(&isDir); + if (!isDir) { + return NS_ERROR_FILE_DESTINATION_NOT_DIR; + } + } + + uint32_t options = Rename; + if (!newParentDir) { + options |= SkipNtfsAclReset; + } + // Move single file, or move a directory + return CopySingleFile(this, targetParentDir, newName, options); +} NS_IMETHODIMP nsLocalFile::Load(PRLibrary * *_retval) diff --git a/xpcom/io/nsLocalFileWin.h b/xpcom/io/nsLocalFileWin.h index f706ba843ac..46b2deb5af5 100644 --- a/xpcom/io/nsLocalFileWin.h +++ b/xpcom/io/nsLocalFileWin.h @@ -54,6 +54,14 @@ public: static void GlobalShutdown(); private: + // CopyMove and CopySingleFile constants for |options| parameter: + enum CopyFileOption { + FollowSymlinks = 1u << 0, + Move = 1u << 1, + SkipNtfsAclReset = 1u << 2, + Rename = 1u << 3 + }; + nsLocalFile(const nsLocalFile& other); ~nsLocalFile() {} @@ -88,11 +96,10 @@ private: void EnsureShortPath(); nsresult CopyMove(nsIFile *newParentDir, const nsAString &newName, - bool followSymlinks, bool move); + uint32_t options); nsresult CopySingleFile(nsIFile *source, nsIFile* dest, const nsAString &newName, - bool followSymlinks, bool move, - bool skipNtfsAclReset = false); + uint32_t options); nsresult SetModDate(int64_t aLastModifiedTime, const wchar_t *filePath); nsresult HasFileAttribute(DWORD fileAttrib, bool *_retval); diff --git a/xpcom/tests/unit/test_file_renameTo.js b/xpcom/tests/unit/test_file_renameTo.js new file mode 100644 index 00000000000..e5e91e36623 --- /dev/null +++ b/xpcom/tests/unit/test_file_renameTo.js @@ -0,0 +1,61 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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/. */ + +const Cc = Components.classes; +const Ci = Components.interfaces; + +function run_test() +{ + // Create the base directory. + let base = Cc['@mozilla.org/file/directory_service;1'] + .getService(Ci.nsIProperties) + .get('TmpD', Ci.nsILocalFile); + base.append('renameTesting'); + if (base.exists()) { + base.remove(true); + } + base.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0777', 8)); + + // Create a sub directory under the base. + let subdir = base.clone(); + subdir.append('subdir'); + subdir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt('0777', 8)); + + // Create a file under the sub directory. + let tempFile = subdir.clone(); + tempFile.append('file0.txt'); + tempFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt('0777', 8)); + + // Test renameTo in the base directory + tempFile.renameTo(null, 'file1.txt'); + do_check_true(exists(subdir, 'file1.txt')); + + // Test moving across directories + tempFile = subdir.clone(); + tempFile.append('file1.txt'); + tempFile.renameTo(base, ''); + do_check_true(exists(base, 'file1.txt')); + + // Test moving across directories and renaming at the same time + tempFile = base.clone(); + tempFile.append('file1.txt'); + tempFile.renameTo(subdir, 'file2.txt'); + do_check_true(exists(subdir, 'file2.txt')); + + // Test moving a directory + subdir.renameTo(base, 'renamed'); + do_check_true(exists(base, 'renamed')); + let renamed = base.clone(); + renamed.append('renamed'); + do_check_true(exists(renamed, 'file2.txt')); + + base.remove(true); +} + +function exists(parent, filename) { + let file = parent.clone(); + file.append(filename); + return file.exists(); +} diff --git a/xpcom/tests/unit/xpcshell.ini b/xpcom/tests/unit/xpcshell.ini index fb075b7aa8d..80c8fac9953 100644 --- a/xpcom/tests/unit/xpcshell.ini +++ b/xpcom/tests/unit/xpcshell.ini @@ -63,3 +63,4 @@ skip-if = os != "win" skip-if = os == "win" # Bug 676998: test fails consistently on Android fail-if = os == "android" +[test_file_renameTo.js] diff --git a/xpcom/threads/BackgroundHangMonitor.cpp b/xpcom/threads/BackgroundHangMonitor.cpp index 170467fd1f3..47a6e6f14e8 100644 --- a/xpcom/threads/BackgroundHangMonitor.cpp +++ b/xpcom/threads/BackgroundHangMonitor.cpp @@ -410,6 +410,7 @@ BackgroundHangThread::NotifyActivity() BackgroundHangThread* BackgroundHangThread::FindThread() { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR if (sTlsKey.initialized()) { // Use TLS if available return sTlsKey.get(); @@ -427,6 +428,7 @@ BackgroundHangThread::FindThread() return thread; } } +#endif // Current thread is not initialized return nullptr; } @@ -435,15 +437,18 @@ BackgroundHangThread::FindThread() void BackgroundHangMonitor::Startup() { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR MOZ_ASSERT(!BackgroundHangManager::sInstance, "Already initialized"); ThreadStackHelper::Startup(); BackgroundHangThread::Startup(); BackgroundHangManager::sInstance = new BackgroundHangManager(); +#endif } void BackgroundHangMonitor::Shutdown() { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR MOZ_ASSERT(BackgroundHangManager::sInstance, "Not initialized"); /* Scope our lock inside Shutdown() because the sInstance object can be destroyed as soon as we set sInstance to nullptr below, and @@ -451,6 +456,7 @@ BackgroundHangMonitor::Shutdown() BackgroundHangManager::sInstance->Shutdown(); BackgroundHangManager::sInstance = nullptr; ThreadStackHelper::Shutdown(); +#endif } BackgroundHangMonitor::BackgroundHangMonitor(const char* aName, @@ -458,15 +464,19 @@ BackgroundHangMonitor::BackgroundHangMonitor(const char* aName, uint32_t aMaxTimeoutMs) : mThread(BackgroundHangThread::FindThread()) { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR if (!mThread) { mThread = new BackgroundHangThread(aName, aTimeoutMs, aMaxTimeoutMs); } +#endif } BackgroundHangMonitor::BackgroundHangMonitor() : mThread(BackgroundHangThread::FindThread()) { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR MOZ_ASSERT(mThread, "Thread not initialized for hang monitoring"); +#endif } BackgroundHangMonitor::~BackgroundHangMonitor() @@ -476,13 +486,17 @@ BackgroundHangMonitor::~BackgroundHangMonitor() void BackgroundHangMonitor::NotifyActivity() { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR mThread->NotifyActivity(); +#endif } void BackgroundHangMonitor::NotifyWait() { +#ifdef MOZ_ENABLE_BACKGROUND_HANG_MONITOR mThread->NotifyWait(); +#endif } diff --git a/xpcom/threads/BackgroundHangMonitor.h b/xpcom/threads/BackgroundHangMonitor.h index 8647a6e7d09..776ead11e97 100644 --- a/xpcom/threads/BackgroundHangMonitor.h +++ b/xpcom/threads/BackgroundHangMonitor.h @@ -17,6 +17,11 @@ namespace Telemetry { class ThreadHangStats; }; +#ifndef RELEASE_BUILD +// Undefine to disable background hang monitor +#define MOZ_ENABLE_BACKGROUND_HANG_MONITOR +#endif + class BackgroundHangThread; /** diff --git a/xpfe/appshell/src/nsAppShellService.cpp b/xpfe/appshell/src/nsAppShellService.cpp index f0c0e43c3a5..16e7eb9e0cc 100644 --- a/xpfe/appshell/src/nsAppShellService.cpp +++ b/xpfe/appshell/src/nsAppShellService.cpp @@ -46,7 +46,9 @@ #include "nsIWebBrowser.h" #include "nsIDocShell.h" +#ifdef MOZ_INSTRUMENT_EVENT_LOOP #include "EventTracer.h" +#endif using namespace mozilla; @@ -872,13 +874,17 @@ nsAppShellService::Observe(nsISupports* aSubject, const char *aTopic, NS_IMETHODIMP nsAppShellService::StartEventLoopLagTracking(bool* aResult) { +#ifdef MOZ_INSTRUMENT_EVENT_LOOP *aResult = mozilla::InitEventTracing(true); +#endif return NS_OK; } NS_IMETHODIMP nsAppShellService::StopEventLoopLagTracking() { +#ifdef MOZ_INSTRUMENT_EVENT_LOOP mozilla::ShutdownEventTracing(); +#endif return NS_OK; }