--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2077,17 +2077,17 @@ Element::DispatchClickEvent(nsPresContex
const EventFlags* aExtraEventFlags,
nsEventStatus* aStatus)
{
NS_PRECONDITION(aTarget, "Must have target");
NS_PRECONDITION(aSourceEvent, "Must have source event");
NS_PRECONDITION(aStatus, "Null out param?");
WidgetMouseEvent event(aSourceEvent->IsTrusted(), eMouseClick,
- aSourceEvent->widget, WidgetMouseEvent::eReal);
+ aSourceEvent->mWidget, WidgetMouseEvent::eReal);
event.refPoint = aSourceEvent->refPoint;
uint32_t clickCount = 1;
float pressure = 0;
uint16_t inputSource = 0;
WidgetMouseEvent* sourceMouseEvent = aSourceEvent->AsMouseEvent();
if (sourceMouseEvent) {
clickCount = sourceMouseEvent->clickCount;
pressure = sourceMouseEvent->pressure;
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -702,60 +702,48 @@ WriteBlob(JSStructuredCloneWriter* aWrit
aHolder->BlobImpls().AppendElement(blobImpl);
return true;
}
return false;
}
// A directory is serialized as:
-// - pair of ints: SCTAG_DOM_DIRECTORY, 0
-// - pair of ints: type (eDOMRootDirectory/eDOMNotRootDirectory) - path length
+// - pair of ints: SCTAG_DOM_DIRECTORY, path length
// - path as string
bool
WriteDirectory(JSStructuredCloneWriter* aWriter,
Directory* aDirectory)
{
MOZ_ASSERT(aWriter);
MOZ_ASSERT(aDirectory);
nsAutoString path;
aDirectory->GetFullRealPath(path);
size_t charSize = sizeof(nsString::char_type);
- return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, 0) &&
- JS_WriteUint32Pair(aWriter, (uint32_t)aDirectory->Type(),
- path.Length()) &&
+ return JS_WriteUint32Pair(aWriter, SCTAG_DOM_DIRECTORY, path.Length()) &&
JS_WriteBytes(aWriter, path.get(), path.Length() * charSize);
}
JSObject*
ReadDirectory(JSContext* aCx,
JSStructuredCloneReader* aReader,
- uint32_t aZero,
+ uint32_t aPathLength,
StructuredCloneHolder* aHolder)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aReader);
MOZ_ASSERT(aHolder);
- MOZ_ASSERT(aZero == 0);
-
- uint32_t directoryType, lengthOfString;
- if (!JS_ReadUint32Pair(aReader, &directoryType, &lengthOfString)) {
- return nullptr;
- }
-
- MOZ_ASSERT(directoryType == Directory::eDOMRootDirectory ||
- directoryType == Directory::eNotDOMRootDirectory);
nsAutoString path;
- path.SetLength(lengthOfString);
+ path.SetLength(aPathLength);
size_t charSize = sizeof(nsString::char_type);
if (!JS_ReadBytes(aReader, (void*) path.BeginWriting(),
- lengthOfString * charSize)) {
+ aPathLength * charSize)) {
return nullptr;
}
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(path), true,
getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
@@ -764,18 +752,17 @@ ReadDirectory(JSContext* aCx,
// RefPtr<Directory> needs to go out of scope before toObject() is
// called because the static analysis thinks dereferencing XPCOM objects
// can GC (because in some cases it can!), and a return statement with a
// JSObject* type means that JSObject* is on the stack as a raw pointer
// while destructors are running.
JS::Rooted<JS::Value> val(aCx);
{
RefPtr<Directory> directory =
- Directory::Create(aHolder->ParentDuringRead(), file,
- (Directory::DirectoryType) directoryType);
+ Directory::Create(aHolder->ParentDuringRead(), file);
if (!ToJSValue(aCx, directory, &val)) {
return nullptr;
}
}
return &val.toObject();
}
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7793,17 +7793,16 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<
}
WidgetMouseEvent event(true, msg, widget, WidgetMouseEvent::eReal,
contextMenuKey ? WidgetMouseEvent::eContextMenuKey :
WidgetMouseEvent::eNormal);
event.mModifiers = GetWidgetModifiers(aModifiers);
event.button = aButton;
event.buttons = GetButtonsFlagForButton(aButton);
- event.widget = widget;
event.pressure = aPressure;
event.inputSource = aInputSourceArg;
event.clickCount = aClickCount;
event.mTime = PR_IntervalNow();
event.mFlags.mIsSynthesizedForTests = aIsSynthesized;
nsPresContext* presContext = aPresShell->GetPresContext();
if (!presContext)
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -667,17 +667,16 @@ nsDOMWindowUtils::SendPointerEventCommon
if (aInputSourceArg == nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN) {
aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
}
WidgetPointerEvent event(true, msg, widget);
event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
event.button = aButton;
event.buttons = nsContentUtils::GetButtonsFlagForButton(aButton);
- event.widget = widget;
event.pressure = aPressure;
event.inputSource = aInputSourceArg;
event.pointerId = aPointerId;
event.width = aWidth;
event.height = aHeight;
event.tiltX = aTiltX;
event.tiltY = aTiltY;
event.isPrimary = (nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == aInputSourceArg) ? true : aIsPrimary;
@@ -800,17 +799,16 @@ nsDOMWindowUtils::SendWheelEvent(float a
wheelEvent.mIsMomentum =
(aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0;
wheelEvent.mIsNoLineOrPageDelta =
(aOptions & WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE) != 0;
wheelEvent.mCustomizedByUserPrefs =
(aOptions & WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS) != 0;
wheelEvent.mLineOrPageDeltaX = aLineOrPageDeltaX;
wheelEvent.mLineOrPageDeltaY = aLineOrPageDeltaY;
- wheelEvent.widget = widget;
wheelEvent.mTime = PR_Now() / 1000;
nsPresContext* presContext = GetPresContext();
NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE);
wheelEvent.refPoint = nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext);
@@ -933,17 +931,16 @@ nsDOMWindowUtils::SendTouchEventCommon(c
msg = eTouchEnd;
} else if (aType.EqualsLiteral("touchcancel")) {
msg = eTouchCancel;
} else {
return NS_ERROR_UNEXPECTED;
}
WidgetTouchEvent event(true, msg, widget);
event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers);
- event.widget = widget;
event.mTime = PR_Now();
nsPresContext* presContext = GetPresContext();
if (!presContext) {
return NS_ERROR_FAILURE;
}
event.mTouches.SetCapacity(aCount);
for (uint32_t i = 0; i < aCount; ++i) {
--- a/dom/events/ContentEventHandler.cpp
+++ b/dom/events/ContentEventHandler.cpp
@@ -1529,32 +1529,32 @@ ContentEventHandler::OnQueryCharacterAtP
nsIFrame* rootFrame = mPresShell->GetRootFrame();
NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
nsIWidget* rootWidget = rootFrame->GetNearestWidget();
NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
// The root frame's widget might be different, e.g., the event was fired on
// a popup but the rootFrame is the document root.
- if (rootWidget != aEvent->widget) {
- NS_PRECONDITION(aEvent->widget, "The event must have the widget");
- nsView* view = nsView::GetViewFor(aEvent->widget);
+ if (rootWidget != aEvent->mWidget) {
+ NS_PRECONDITION(aEvent->mWidget, "The event must have the widget");
+ nsView* view = nsView::GetViewFor(aEvent->mWidget);
NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
rootFrame = view->GetFrame();
NS_ENSURE_TRUE(rootFrame, NS_ERROR_FAILURE);
rootWidget = rootFrame->GetNearestWidget();
NS_ENSURE_TRUE(rootWidget, NS_ERROR_FAILURE);
}
WidgetQueryContentEvent eventOnRoot(true, eQueryCharacterAtPoint,
rootWidget);
eventOnRoot.mUseNativeLineBreak = aEvent->mUseNativeLineBreak;
eventOnRoot.refPoint = aEvent->refPoint;
- if (rootWidget != aEvent->widget) {
- eventOnRoot.refPoint += aEvent->widget->WidgetToScreenOffset() -
+ if (rootWidget != aEvent->mWidget) {
+ eventOnRoot.refPoint += aEvent->mWidget->WidgetToScreenOffset() -
rootWidget->WidgetToScreenOffset();
}
nsPoint ptInRoot =
nsLayoutUtils::GetEventCoordinatesRelativeTo(&eventOnRoot, rootFrame);
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
if (!targetFrame || !targetFrame->GetContent() ||
!nsContentUtils::ContentIsDescendantOf(targetFrame->GetContent(),
@@ -1606,17 +1606,17 @@ ContentEventHandler::OnQueryCharacterAtP
rv = GetFlatTextLengthInRange(NodePosition(mRootContent, 0),
NodePosition(contentOffsets),
mRootContent, &offset,
GetLineBreakType(aEvent));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->widget);
+ WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->mWidget);
textRect.InitForQueryTextRect(offset, 1, aEvent->mUseNativeLineBreak);
rv = OnQueryTextRect(&textRect);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE);
// currently, we don't need to get the actual text.
aEvent->mReply.mOffset = offset;
aEvent->mReply.mRect = textRect.mReply.mRect;
@@ -1632,41 +1632,42 @@ ContentEventHandler::OnQueryDOMWidgetHit
nsresult rv = InitBasic();
if (NS_FAILED(rv)) {
return rv;
}
aEvent->mSucceeded = false;
aEvent->mReply.mWidgetIsHit = false;
- NS_ENSURE_TRUE(aEvent->widget, NS_ERROR_FAILURE);
+ NS_ENSURE_TRUE(aEvent->mWidget, NS_ERROR_FAILURE);
nsIDocument* doc = mPresShell->GetDocument();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
nsIFrame* docFrame = mPresShell->GetRootFrame();
NS_ENSURE_TRUE(docFrame, NS_ERROR_FAILURE);
- LayoutDeviceIntPoint eventLoc = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
+ LayoutDeviceIntPoint eventLoc =
+ aEvent->refPoint + aEvent->mWidget->WidgetToScreenOffset();
nsIntRect docFrameRect = docFrame->GetScreenRect(); // Returns CSS pixels
CSSIntPoint eventLocCSS(
mPresContext->DevPixelsToIntCSSPixels(eventLoc.x) - docFrameRect.x,
mPresContext->DevPixelsToIntCSSPixels(eventLoc.y) - docFrameRect.y);
Element* contentUnderMouse =
doc->ElementFromPointHelper(eventLocCSS.x, eventLocCSS.y, false, false);
if (contentUnderMouse) {
nsIWidget* targetWidget = nullptr;
nsIFrame* targetFrame = contentUnderMouse->GetPrimaryFrame();
nsIObjectFrame* pluginFrame = do_QueryFrame(targetFrame);
if (pluginFrame) {
targetWidget = pluginFrame->GetWidget();
} else if (targetFrame) {
targetWidget = targetFrame->GetNearestWidget();
}
- if (aEvent->widget == targetWidget) {
+ if (aEvent->mWidget == targetWidget) {
aEvent->mReply.mWidgetIsHit = true;
}
}
aEvent->mSucceeded = true;
return NS_OK;
}
--- a/dom/events/Event.cpp
+++ b/dom/events/Event.cpp
@@ -900,28 +900,28 @@ Event::GetScreenCoords(nsPresContext* aP
aEvent->mClass != eDragEventClass &&
aEvent->mClass != eSimpleGestureEventClass)) {
return CSSIntPoint(0, 0);
}
// Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
// seem incorrect, but it is needed to maintain legacy functionality.
WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
- if (!aPresContext || !(guiEvent && guiEvent->widget)) {
+ if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
return CSSIntPoint(aPoint.x, aPoint.y);
}
nsPoint pt =
LayoutDevicePixel::ToAppUnits(aPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
if (nsIPresShell* ps = aPresContext->GetPresShell()) {
pt = pt.RemoveResolution(nsLayoutUtils::GetCurrentAPZResolutionScale(ps));
}
- pt += LayoutDevicePixel::ToAppUnits(guiEvent->widget->WidgetToScreenOffset(),
+ pt += LayoutDevicePixel::ToAppUnits(guiEvent->mWidget->WidgetToScreenOffset(),
aPresContext->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom());
return CSSPixel::FromAppUnitsRounded(pt);
}
// static
CSSIntPoint
Event::GetPageCoords(nsPresContext* aPresContext,
@@ -959,17 +959,17 @@ Event::GetClientCoords(nsPresContext* aP
(aEvent->mClass != eMouseEventClass &&
aEvent->mClass != eMouseScrollEventClass &&
aEvent->mClass != eWheelEventClass &&
aEvent->mClass != eTouchEventClass &&
aEvent->mClass != eDragEventClass &&
aEvent->mClass != ePointerEventClass &&
aEvent->mClass != eSimpleGestureEventClass) ||
!aPresContext ||
- !aEvent->AsGUIEvent()->widget) {
+ !aEvent->AsGUIEvent()->mWidget) {
return aDefaultPoint;
}
nsIPresShell* shell = aPresContext->GetPresShell();
if (!shell) {
return CSSIntPoint(0, 0);
}
nsIFrame* rootFrame = shell->GetRootFrame();
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -817,17 +817,17 @@ EventStateManager::PreHandleEvent(nsPres
DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
break;
case eCompositionStart:
if (aEvent->IsTrusted()) {
// If the event is trusted event, set the selected text to data of
// composition event.
WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent();
WidgetQueryContentEvent selectedText(true, eQuerySelectedText,
- compositionEvent->widget);
+ compositionEvent->mWidget);
HandleQueryContentEvent(&selectedText);
NS_ASSERTION(selectedText.mSucceeded, "Failed to get selected text");
compositionEvent->mData = selectedText.mReply.mString;
}
break;
default:
break;
}
@@ -1579,22 +1579,24 @@ EventStateManager::FireContextClick()
// assume the user wants a click-hold, so fire a context-click event. We only
// want to cancel the drag gesture if the context-click event is handled.
//
void
EventStateManager::BeginTrackingDragGesture(nsPresContext* aPresContext,
WidgetMouseEvent* inDownEvent,
nsIFrame* inDownFrame)
{
- if (!inDownEvent->widget)
+ if (!inDownEvent->mWidget) {
return;
+ }
// Note that |inDownEvent| could be either a mouse down event or a
// synthesized mouse move event.
- mGestureDownPoint = inDownEvent->refPoint + inDownEvent->widget->WidgetToScreenOffset();
+ mGestureDownPoint =
+ inDownEvent->refPoint + inDownEvent->mWidget->WidgetToScreenOffset();
if (inDownFrame) {
inDownFrame->GetContentForEvent(inDownEvent,
getter_AddRefs(mGestureDownContent));
mGestureDownFrameOwner = inDownFrame->GetContent();
if (!mGestureDownFrameOwner) {
mGestureDownFrameOwner = mGestureDownContent;
@@ -1627,23 +1629,24 @@ EventStateManager::StopTrackingDragGestu
{
mGestureDownContent = nullptr;
mGestureDownFrameOwner = nullptr;
}
void
EventStateManager::FillInEventFromGestureDown(WidgetMouseEvent* aEvent)
{
- NS_ASSERTION(aEvent->widget == mCurrentTarget->GetNearestWidget(),
+ NS_ASSERTION(aEvent->mWidget == mCurrentTarget->GetNearestWidget(),
"Incorrect widget in event");
// Set the coordinates in the new event to the coordinates of
// the old event, adjusted for the fact that the widget might be
// different
- aEvent->refPoint = mGestureDownPoint - aEvent->widget->WidgetToScreenOffset();
+ aEvent->refPoint =
+ mGestureDownPoint - aEvent->mWidget->WidgetToScreenOffset();
aEvent->mModifiers = mGestureModifiers;
aEvent->buttons = mGestureDownButtons;
}
//
// GenerateDragGesture
//
// If we're in the TRACKING state of the d&d gesture tracker, check the current position
@@ -1689,17 +1692,18 @@ EventStateManager::GenerateDragGesture(n
LookAndFeel::GetInt(LookAndFeel::eIntID_DragThresholdY, 0);
if (!pixelThresholdX)
pixelThresholdX = 5;
if (!pixelThresholdY)
pixelThresholdY = 5;
}
// fire drag gesture if mouse has moved enough
- LayoutDeviceIntPoint pt = aEvent->refPoint + aEvent->widget->WidgetToScreenOffset();
+ LayoutDeviceIntPoint pt =
+ aEvent->refPoint + aEvent->mWidget->WidgetToScreenOffset();
LayoutDeviceIntPoint distance = pt - mGestureDownPoint;
if (Abs(distance.x) > AssertedCast<uint32_t>(pixelThresholdX) ||
Abs(distance.y) > AssertedCast<uint32_t>(pixelThresholdY)) {
if (Prefs::ClickHoldContextMenu()) {
// stop the click-hold before we fire off the drag gesture, in case
// it takes a long time
KillClickHoldTimer();
}
@@ -2289,21 +2293,20 @@ EventStateManager::SendLineScrollEvent(n
if (!targetContent)
return;
while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
targetContent = targetContent->GetParent();
}
WidgetMouseScrollEvent event(aEvent->IsTrusted(),
- eLegacyMouseLineOrPageScroll, aEvent->widget);
+ eLegacyMouseLineOrPageScroll, aEvent->mWidget);
event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
event.refPoint = aEvent->refPoint;
- event.widget = aEvent->widget;
event.mTime = aEvent->mTime;
event.mTimeStamp = aEvent->mTimeStamp;
event.mModifiers = aEvent->mModifiers;
event.buttons = aEvent->buttons;
event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
event.mDelta = aDelta;
event.inputSource = aEvent->inputSource;
@@ -2329,21 +2332,20 @@ EventStateManager::SendPixelScrollEvent(
return;
}
while (targetContent->IsNodeOfType(nsINode::eTEXT)) {
targetContent = targetContent->GetParent();
}
WidgetMouseScrollEvent event(aEvent->IsTrusted(),
- eLegacyMousePixelScroll, aEvent->widget);
+ eLegacyMousePixelScroll, aEvent->mWidget);
event.mFlags.mDefaultPrevented = aState.mDefaultPrevented;
event.mFlags.mDefaultPreventedByContent = aState.mDefaultPreventedByContent;
event.refPoint = aEvent->refPoint;
- event.widget = aEvent->widget;
event.mTime = aEvent->mTime;
event.mTimeStamp = aEvent->mTimeStamp;
event.mModifiers = aEvent->mModifiers;
event.buttons = aEvent->buttons;
event.mIsHorizontal = (aDeltaDirection == DELTA_DIRECTION_X);
event.mDelta = aPixelDelta;
event.inputSource = aEvent->inputSource;
@@ -3418,18 +3420,18 @@ EventStateManager::PostHandleEvent(nsPre
mCurrentTarget->GetContentForEvent(aEvent,
getter_AddRefs(targetContent));
nsCOMPtr<nsIWidget> widget = mCurrentTarget->GetNearestWidget();
WidgetDragEvent event(aEvent->IsTrusted(), eLegacyDragDrop, widget);
WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
event.refPoint = mouseEvent->refPoint;
- if (mouseEvent->widget) {
- event.refPoint += mouseEvent->widget->WidgetToScreenOffset();
+ if (mouseEvent->mWidget) {
+ event.refPoint += mouseEvent->mWidget->WidgetToScreenOffset();
}
event.refPoint -= widget->WidgetToScreenOffset();
event.mModifiers = mouseEvent->mModifiers;
event.buttons = mouseEvent->buttons;
event.inputSource = mouseEvent->inputSource;
nsEventStatus status = nsEventStatus_eIgnore;
nsCOMPtr<nsIPresShell> presShell = mPresContext->GetPresShell();
@@ -3841,31 +3843,31 @@ CreateMouseOrPointerWidgetEvent(WidgetMo
WidgetPointerEvent* sourcePointer = aMouseEvent->AsPointerEvent();
if (sourcePointer) {
PROFILER_LABEL("Input", "DispatchPointerEvent",
js::ProfileEntry::Category::EVENTS);
nsAutoPtr<WidgetPointerEvent> newPointerEvent;
newPointerEvent =
new WidgetPointerEvent(aMouseEvent->IsTrusted(), aMessage,
- aMouseEvent->widget);
+ aMouseEvent->mWidget);
newPointerEvent->isPrimary = sourcePointer->isPrimary;
newPointerEvent->pointerId = sourcePointer->pointerId;
newPointerEvent->width = sourcePointer->width;
newPointerEvent->height = sourcePointer->height;
newPointerEvent->inputSource = sourcePointer->inputSource;
newPointerEvent->relatedTarget =
nsIPresShell::GetPointerCapturingContent(sourcePointer->pointerId)
? nullptr
: aRelatedContent;
aNewEvent = newPointerEvent.forget();
} else {
aNewEvent =
new WidgetMouseEvent(aMouseEvent->IsTrusted(), aMessage,
- aMouseEvent->widget, WidgetMouseEvent::eReal);
+ aMouseEvent->mWidget, WidgetMouseEvent::eReal);
aNewEvent->relatedTarget = aRelatedContent;
}
aNewEvent->refPoint = aMouseEvent->refPoint;
aNewEvent->mModifiers = aMouseEvent->mModifiers;
aNewEvent->button = aMouseEvent->button;
aNewEvent->buttons = aMouseEvent->buttons;
aNewEvent->pressure = aMouseEvent->pressure;
aNewEvent->mPluginEvent = aMouseEvent->mPluginEvent;
@@ -4200,35 +4202,35 @@ EventStateManager::GenerateMouseEnterExi
nsCOMPtr<nsIContent> targetBeforeEvent = mCurrentTargetContent;
switch(aMouseEvent->mMessage) {
case eMouseMove:
{
// Mouse movement is reported on the MouseEvent.movement{X,Y} fields.
// Movement is calculated in UIEvent::GetMovementPoint() as:
// previous_mousemove_refPoint - current_mousemove_refPoint.
- if (sIsPointerLocked && aMouseEvent->widget) {
+ if (sIsPointerLocked && aMouseEvent->mWidget) {
// The pointer is locked. If the pointer is not located at the center of
// the window, dispatch a synthetic mousemove to return the pointer there.
// Doing this between "real" pointer moves gives the impression that the
// (locked) pointer can continue moving and won't stop at the screen
// boundary. We cancel the synthetic event so that we don't end up
// dispatching the centering move event to content.
LayoutDeviceIntPoint center =
- GetWindowClientRectCenter(aMouseEvent->widget);
+ GetWindowClientRectCenter(aMouseEvent->mWidget);
aMouseEvent->lastRefPoint = center;
if (aMouseEvent->refPoint != center) {
// Mouse move doesn't finish at the center of the window. Dispatch a
// synthetic native mouse event to move the pointer back to the center
// of the window, to faciliate more movement. But first, record that
// we've dispatched a synthetic mouse movement, so we can cancel it
// in the other branch here.
sSynthCenteringPoint = center;
- aMouseEvent->widget->SynthesizeNativeMouseMove(
- center + aMouseEvent->widget->WidgetToScreenOffset(), nullptr);
+ aMouseEvent->mWidget->SynthesizeNativeMouseMove(
+ center + aMouseEvent->mWidget->WidgetToScreenOffset(), nullptr);
} else if (aMouseEvent->refPoint == sSynthCenteringPoint) {
// This is the "synthetic native" event we dispatched to re-center the
// pointer. Cancel it so we don't expose the centering move to content.
aMouseEvent->StopPropagation();
// Clear sSynthCenteringPoint so we don't cancel other events
// targeted at the center.
sSynthCenteringPoint = kInvalidRefPoint;
}
@@ -4285,17 +4287,17 @@ EventStateManager::GenerateMouseEnterExi
case ePointerCancel:
case eMouseExitFromWidget:
{
// This is actually the window mouse exit or pointer leave event. We're not moving
// into any new element.
OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
if (helper->mLastOverFrame &&
- nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
+ nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
// the Mouse/PointerOut event widget doesn't have same top widget with
// mLastOverFrame, it's a spurious event for mLastOverFrame
break;
}
// Reset sLastRefPoint, so that we'll know not to report any
// movement the next time we re-enter the window.
@@ -4466,17 +4468,17 @@ void
EventStateManager::FireDragEnterOrExit(nsPresContext* aPresContext,
WidgetDragEvent* aDragEvent,
EventMessage aMessage,
nsIContent* aRelatedTarget,
nsIContent* aTargetContent,
nsWeakFrame& aTargetFrame)
{
nsEventStatus status = nsEventStatus_eIgnore;
- WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
+ WidgetDragEvent event(aDragEvent->IsTrusted(), aMessage, aDragEvent->mWidget);
event.refPoint = aDragEvent->refPoint;
event.mModifiers = aDragEvent->mModifiers;
event.buttons = aDragEvent->buttons;
event.relatedTarget = aRelatedTarget;
event.inputSource = aDragEvent->inputSource;
mCurrentTargetContent = aTargetContent;
@@ -4502,17 +4504,18 @@ EventStateManager::FireDragEnterOrExit(n
}
// Finally dispatch the event to the frame
if (aTargetFrame)
aTargetFrame->HandleEvent(aPresContext, &event, &status);
if (aMessage == eDragExit && IsRemoteTarget(aTargetContent)) {
nsEventStatus status = nsEventStatus_eIgnore;
- WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), aMessage, aDragEvent->widget);
+ WidgetDragEvent remoteEvent(aDragEvent->IsTrusted(), aMessage,
+ aDragEvent->mWidget);
remoteEvent.AssignDragEventData(*aDragEvent, true);
HandleCrossProcessEvent(&remoteEvent, &status);
}
}
void
EventStateManager::UpdateDragDataTransfer(WidgetDragEvent* dragEvent)
{
@@ -4620,26 +4623,26 @@ EventStateManager::CheckForAndDispatchCl
{
nsresult ret = NS_OK;
//If mouse is still over same element, clickcount will be > 1.
//If it has moved it will be zero, so no click.
if (0 != aEvent->clickCount) {
//Check that the window isn't disabled before firing a click
//(see bug 366544).
- if (aEvent->widget && !aEvent->widget->IsEnabled()) {
+ if (aEvent->mWidget && !aEvent->mWidget->IsEnabled()) {
return ret;
}
//fire click
bool notDispatchToContents =
(aEvent->button == WidgetMouseEvent::eMiddleButton ||
aEvent->button == WidgetMouseEvent::eRightButton);
WidgetMouseEvent event(aEvent->IsTrusted(), eMouseClick,
- aEvent->widget, WidgetMouseEvent::eReal);
+ aEvent->mWidget, WidgetMouseEvent::eReal);
event.refPoint = aEvent->refPoint;
event.clickCount = aEvent->clickCount;
event.mModifiers = aEvent->mModifiers;
event.buttons = aEvent->buttons;
event.mTime = aEvent->mTime;
event.mTimeStamp = aEvent->mTimeStamp;
event.mFlags.mNoContentDispatch = notDispatchToContents;
event.button = aEvent->button;
@@ -4663,17 +4666,17 @@ EventStateManager::CheckForAndDispatchCl
// HandleEvent clears out mCurrentTarget which we might need again
nsWeakFrame currentTarget = mCurrentTarget;
ret = presShell->HandleEventWithTarget(&event, currentTarget,
mouseContent, aStatus);
if (NS_SUCCEEDED(ret) && aEvent->clickCount == 2 &&
mouseContent && mouseContent->IsInComposedDoc()) {
//fire double click
WidgetMouseEvent event2(aEvent->IsTrusted(), eMouseDoubleClick,
- aEvent->widget, WidgetMouseEvent::eReal);
+ aEvent->mWidget, WidgetMouseEvent::eReal);
event2.refPoint = aEvent->refPoint;
event2.clickCount = aEvent->clickCount;
event2.mModifiers = aEvent->mModifiers;
event2.buttons = aEvent->buttons;
event2.mFlags.mNoContentDispatch = notDispatchToContents;
event2.button = aEvent->button;
event2.inputSource = aEvent->inputSource;
--- a/dom/events/EventStateManager.h
+++ b/dom/events/EventStateManager.h
@@ -865,17 +865,17 @@ protected:
dom::DataTransfer* aDataTransfer,
nsIContent* aDragTarget,
nsISelection* aSelection);
bool IsTrackingDragGesture ( ) const { return mGestureDownContent != nullptr; }
/**
* Set the fields of aEvent to reflect the mouse position and modifier keys
* that were set when the user first pressed the mouse button (stored by
- * BeginTrackingDragGesture). aEvent->widget must be
+ * BeginTrackingDragGesture). aEvent->mWidget must be
* mCurrentTarget->GetNearestWidget().
*/
void FillInEventFromGestureDown(WidgetMouseEvent* aEvent);
nsresult DoContentCommandEvent(WidgetContentCommandEvent* aEvent);
nsresult DoContentCommandScrollEvent(WidgetContentCommandEvent* aEvent);
dom::TabParent *GetCrossProcessTarget();
--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -753,17 +753,17 @@ bool
IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
WidgetMouseEvent* aMouseEvent)
{
if (!mUpdatePreference.WantMouseButtonEventOnChar()) {
return false;
}
if (!aMouseEvent->IsTrusted() ||
aMouseEvent->DefaultPrevented() ||
- !aMouseEvent->widget) {
+ !aMouseEvent->mWidget) {
return false;
}
// Now, we need to notify only mouse down and mouse up event.
switch (aMouseEvent->mMessage) {
case eMouseUp:
case eMouseDown:
break;
default:
@@ -771,17 +771,17 @@ IMEContentObserver::OnMouseButtonEvent(n
}
if (NS_WARN_IF(!mWidget) || NS_WARN_IF(mWidget->Destroyed())) {
return false;
}
RefPtr<IMEContentObserver> kungFuDeathGrip(this);
WidgetQueryContentEvent charAtPt(true, eQueryCharacterAtPoint,
- aMouseEvent->widget);
+ aMouseEvent->mWidget);
charAtPt.refPoint = aMouseEvent->refPoint;
ContentEventHandler handler(aPresContext);
handler.OnQueryCharacterAtPoint(&charAtPt);
if (NS_WARN_IF(!charAtPt.mSucceeded) ||
charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
return false;
}
@@ -796,18 +796,18 @@ IMEContentObserver::OnMouseButtonEvent(n
nsIWidget* topLevelWidget = mWidget->GetTopLevelWidget();
if (topLevelWidget && topLevelWidget != mWidget) {
charAtPt.mReply.mRect.MoveBy(
topLevelWidget->WidgetToScreenOffset() -
mWidget->WidgetToScreenOffset());
}
// The refPt is relative to its widget.
// We should notify it with offset in the widget.
- if (aMouseEvent->widget != mWidget) {
- charAtPt.refPoint += aMouseEvent->widget->WidgetToScreenOffset() -
+ if (aMouseEvent->mWidget != mWidget) {
+ charAtPt.refPoint += aMouseEvent->mWidget->WidgetToScreenOffset() -
mWidget->WidgetToScreenOffset();
}
IMENotification notification(NOTIFY_IME_OF_MOUSE_BUTTON_EVENT);
notification.mMouseButtonEventData.mEventMessage = aMouseEvent->mMessage;
notification.mMouseButtonEventData.mOffset = charAtPt.mReply.mOffset;
notification.mMouseButtonEventData.mCursorPos.Set(
charAtPt.refPoint.ToUnknownPoint());
--- a/dom/events/IMEStateManager.cpp
+++ b/dom/events/IMEStateManager.cpp
@@ -1142,29 +1142,29 @@ IMEStateManager::DispatchCompositionEven
RefPtr<TabParent> tabParent =
aEventTargetNode->IsContent() ?
TabParent::GetFrom(aEventTargetNode->AsContent()) : nullptr;
MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::DispatchCompositionEvent(aNode=0x%p, "
"aPresContext=0x%p, aCompositionEvent={ mMessage=%s, "
"mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
- "mOriginProcessID=0x%X }, widget(0x%p)={ "
+ "mOriginProcessID=0x%X }, mWidget(0x%p)={ "
"GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
"mOriginProcessID=0x%X }, Destroyed()=%s }, "
"mFlags={ mIsTrusted=%s, mPropagationStopped=%s } }, "
"aIsSynthesized=%s), tabParent=%p",
aEventTargetNode, aPresContext,
ToChar(aCompositionEvent->mMessage),
aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
aCompositionEvent->mNativeIMEContext.mOriginProcessID,
- aCompositionEvent->widget.get(),
- aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
- aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
- GetBoolName(aCompositionEvent->widget->Destroyed()),
+ aCompositionEvent->mWidget.get(),
+ aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
+ aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
+ GetBoolName(aCompositionEvent->mWidget->Destroyed()),
GetBoolName(aCompositionEvent->mFlags.mIsTrusted),
GetBoolName(aCompositionEvent->mFlags.mPropagationStopped),
GetBoolName(aIsSynthesized), tabParent.get()));
if (!aCompositionEvent->IsTrusted() ||
aCompositionEvent->PropagationStopped()) {
return;
}
@@ -1212,17 +1212,17 @@ IMEStateManager::DispatchCompositionEven
// during not safe to dispatch events, PresShell must have discarded
// compositionend event. Then, the synthesized compositionend event is
// the last event for the composition. In this case, we need to
// destroy the TextComposition with synthesized compositionend event.
if ((!aIsSynthesized ||
composition->WasNativeCompositionEndEventDiscarded()) &&
aCompositionEvent->CausesDOMCompositionEndEvent()) {
TextCompositionArray::index_type i =
- sTextCompositions->IndexOf(aCompositionEvent->widget);
+ sTextCompositions->IndexOf(aCompositionEvent->mWidget);
if (i != TextCompositionArray::NoIndex) {
MOZ_LOG(sISMLog, LogLevel::Debug,
("ISM: IMEStateManager::DispatchCompositionEvent(), "
"removing TextComposition from the array since NS_COMPOSTION_END "
"was dispatched"));
sTextCompositions->ElementAt(i)->Destroy();
sTextCompositions->RemoveElementAt(i);
}
@@ -1261,17 +1261,17 @@ IMEStateManager::HandleSelectionEvent(ns
GetBoolName(aSelectionEvent->mFlags.mIsTrusted),
tabParent.get()));
if (!aSelectionEvent->IsTrusted()) {
return;
}
RefPtr<TextComposition> composition = sTextCompositions ?
- sTextCompositions->GetCompositionFor(aSelectionEvent->widget) : nullptr;
+ sTextCompositions->GetCompositionFor(aSelectionEvent->mWidget) : nullptr;
if (composition) {
// When there is a composition, TextComposition should guarantee that the
// selection event will be handled in same target as composition events.
composition->HandleSelectionEvent(aSelectionEvent);
} else {
// When there is no composition, the selection event should be handled
// in the aPresContext or tabParent.
TextComposition::HandleSelectionEvent(aPresContext, tabParent,
@@ -1285,41 +1285,41 @@ IMEStateManager::OnCompositionEventDisca
WidgetCompositionEvent* aCompositionEvent)
{
// Note that this method is never called for synthesized events for emulating
// commit or cancel composition.
MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::OnCompositionEventDiscarded(aCompositionEvent={ "
"mMessage=%s, mNativeIMEContext={ mRawNativeIMEContext=0x%X, "
- "mOriginProcessID=0x%X }, widget(0x%p)={ "
+ "mOriginProcessID=0x%X }, mWidget(0x%p)={ "
"GetNativeIMEContext()={ mRawNativeIMEContext=0x%X, "
"mOriginProcessID=0x%X }, Destroyed()=%s }, "
"mFlags={ mIsTrusted=%s } })",
ToChar(aCompositionEvent->mMessage),
aCompositionEvent->mNativeIMEContext.mRawNativeIMEContext,
aCompositionEvent->mNativeIMEContext.mOriginProcessID,
- aCompositionEvent->widget.get(),
- aCompositionEvent->widget->GetNativeIMEContext().mRawNativeIMEContext,
- aCompositionEvent->widget->GetNativeIMEContext().mOriginProcessID,
- GetBoolName(aCompositionEvent->widget->Destroyed()),
+ aCompositionEvent->mWidget.get(),
+ aCompositionEvent->mWidget->GetNativeIMEContext().mRawNativeIMEContext,
+ aCompositionEvent->mWidget->GetNativeIMEContext().mOriginProcessID,
+ GetBoolName(aCompositionEvent->mWidget->Destroyed()),
GetBoolName(aCompositionEvent->mFlags.mIsTrusted)));
if (!aCompositionEvent->IsTrusted()) {
return;
}
// Ignore compositionstart for now because sTextCompositions may not have
// been created yet.
if (aCompositionEvent->mMessage == eCompositionStart) {
return;
}
RefPtr<TextComposition> composition =
- sTextCompositions->GetCompositionFor(aCompositionEvent->widget);
+ sTextCompositions->GetCompositionFor(aCompositionEvent->mWidget);
if (!composition) {
// If the PresShell has been being destroyed during composition,
// a TextComposition instance for the composition was already removed from
// the array and destroyed in OnDestroyPresContext(). Therefore, we may
// fail to retrieve a TextComposition instance here.
MOZ_LOG(sISMLog, LogLevel::Info,
("ISM: IMEStateManager::OnCompositionEventDiscarded(), "
"TextComposition instance for the widget has already gone"));
--- a/dom/events/TextComposition.cpp
+++ b/dom/events/TextComposition.cpp
@@ -90,41 +90,41 @@ TextComposition::IsValidStateForComposit
}
bool
TextComposition::MaybeDispatchCompositionUpdate(
const WidgetCompositionEvent* aCompositionEvent)
{
MOZ_RELEASE_ASSERT(!mTabParent);
- if (!IsValidStateForComposition(aCompositionEvent->widget)) {
+ if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
return false;
}
if (mLastData == aCompositionEvent->mData) {
return true;
}
CloneAndDispatchAs(aCompositionEvent, eCompositionUpdate);
- return IsValidStateForComposition(aCompositionEvent->widget);
+ return IsValidStateForComposition(aCompositionEvent->mWidget);
}
BaseEventFlags
TextComposition::CloneAndDispatchAs(
const WidgetCompositionEvent* aCompositionEvent,
EventMessage aMessage,
nsEventStatus* aStatus,
EventDispatchingCallback* aCallBack)
{
MOZ_RELEASE_ASSERT(!mTabParent);
- MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->widget),
+ MOZ_ASSERT(IsValidStateForComposition(aCompositionEvent->mWidget),
"Should be called only when it's safe to dispatch an event");
WidgetCompositionEvent compositionEvent(aCompositionEvent->IsTrusted(),
- aMessage, aCompositionEvent->widget);
+ aMessage, aCompositionEvent->mWidget);
compositionEvent.mTime = aCompositionEvent->mTime;
compositionEvent.mTimeStamp = aCompositionEvent->mTimeStamp;
compositionEvent.mData = aCompositionEvent->mData;
compositionEvent.mNativeIMEContext = aCompositionEvent->mNativeIMEContext;
compositionEvent.mOriginalMessage = aCompositionEvent->mMessage;
compositionEvent.mFlags.mIsSynthesizedForTests =
aCompositionEvent->mFlags.mIsSynthesizedForTests;
@@ -274,17 +274,17 @@ TextComposition::DispatchCompositionEven
aCompositionEvent->mData = mLastData;
}
} else if (aCompositionEvent->mMessage == eCompositionCommit) {
NS_ASSERTION(!aCompositionEvent->mRanges,
"mRanges of eCompositionCommit should be null");
aCompositionEvent->mRanges = nullptr;
}
- if (!IsValidStateForComposition(aCompositionEvent->widget)) {
+ if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
*aStatus = nsEventStatus_eConsumeNoDefault;
return;
}
// If this instance has requested to commit or cancel composition but
// is not synthesizing commit event, that means that the IME commits or
// cancels the composition asynchronously. Typically, iBus behaves so.
// Then, synthesized events which were dispatched immediately after
@@ -372,17 +372,17 @@ TextComposition::DispatchCompositionEven
aStatus, aCallBack);
} else {
DispatchEvent(aCompositionEvent, aStatus, aCallBack);
}
} else {
*aStatus = nsEventStatus_eConsumeNoDefault;
}
- if (!IsValidStateForComposition(aCompositionEvent->widget)) {
+ if (!IsValidStateForComposition(aCompositionEvent->mWidget)) {
return;
}
// Emulate editor behavior of compositionchange event (DOM text event) handler
// if no editor handles composition events.
if (dispatchDOMTextEvent && !HasEditor()) {
EditorWillHandleCompositionChangeEvent(aCompositionEvent);
EditorDidHandleCompositionChangeEvent();
--- a/dom/events/UIEvent.cpp
+++ b/dom/events/UIEvent.cpp
@@ -120,17 +120,17 @@ UIEvent::GetMovementPoint()
if (!mEvent ||
(mEvent->mClass != eMouseEventClass &&
mEvent->mClass != eMouseScrollEventClass &&
mEvent->mClass != eWheelEventClass &&
mEvent->mClass != eDragEventClass &&
mEvent->mClass != ePointerEventClass &&
mEvent->mClass != eSimpleGestureEventClass) ||
- !mEvent->AsGUIEvent()->widget) {
+ !mEvent->AsGUIEvent()->mWidget) {
return nsIntPoint(0, 0);
}
// Calculate the delta between the last screen point and the current one.
nsIntPoint current = DevPixelsToCSSPixels(mEvent->refPoint, mPresContext);
nsIntPoint last = DevPixelsToCSSPixels(mEvent->lastRefPoint, mPresContext);
return current - last;
}
--- a/dom/events/WheelHandlingHelper.cpp
+++ b/dom/events/WheelHandlingHelper.cpp
@@ -333,18 +333,18 @@ WheelTransaction::SetTimeout()
nsITimer::TYPE_ONE_SHOT);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "nsITimer::InitWithFuncCallback failed");
}
/* static */ nsIntPoint
WheelTransaction::GetScreenPoint(WidgetGUIEvent* aEvent)
{
NS_ASSERTION(aEvent, "aEvent is null");
- NS_ASSERTION(aEvent->widget, "aEvent-widget is null");
- return (aEvent->refPoint + aEvent->widget->WidgetToScreenOffset())
+ NS_ASSERTION(aEvent->mWidget, "aEvent-mWidget is null");
+ return (aEvent->refPoint + aEvent->mWidget->WidgetToScreenOffset())
.ToUnknownPoint();
}
/* static */ uint32_t
WheelTransaction::GetTimeoutTime()
{
return Preferences::GetUint("mousewheel.transaction.timeout", 1500);
}
--- a/dom/filesystem/CreateDirectoryTask.cpp
+++ b/dom/filesystem/CreateDirectoryTask.cpp
@@ -114,19 +114,17 @@ CreateDirectoryTaskChild::HandlerCallbac
if (HasError()) {
mPromise->MaybeReject(mErrorValue);
mPromise = nullptr;
return;
}
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
- mTargetPath,
- Directory::eNotDOMRootDirectory,
- mFileSystem);
+ mTargetPath, mFileSystem);
MOZ_ASSERT(dir);
mPromise->MaybeResolve(dir);
mPromise = nullptr;
}
void
CreateDirectoryTaskChild::GetPermissionAccessType(nsCString& aAccess) const
--- a/dom/filesystem/DeviceStorageFileSystem.cpp
+++ b/dom/filesystem/DeviceStorageFileSystem.cpp
@@ -110,20 +110,42 @@ DeviceStorageFileSystem::GetParentObject
AssertIsOnOwningThread();
nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
MOZ_ASSERT_IF(!mShutdown, window);
return window ? window->AsInner() : nullptr;
}
void
-DeviceStorageFileSystem::GetRootName(nsAString& aRetval) const
+DeviceStorageFileSystem::GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+ ErrorResult& aRv) const
{
AssertIsOnOwningThread();
- aRetval = mStorageName;
+ MOZ_ASSERT(aFile);
+
+ nsCOMPtr<nsIFile> rootPath;
+ aRv = NS_NewLocalFile(LocalOrDeviceStorageRootPath(), false,
+ getter_AddRefs(rootPath));
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
+ bool equal = false;
+ aRv = aFile->Equals(rootPath, &equal);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
+ if (equal) {
+ aRetval = mStorageName;
+ return;
+ }
+
+ FileSystemBase::GetDirectoryName(aFile, aRetval, aRv);
+ NS_WARN_IF(aRv.Failed());
}
bool
DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
{
MOZ_ASSERT(XRE_IsParentProcess(), "Should be on parent process!");
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aFile);
--- a/dom/filesystem/DeviceStorageFileSystem.h
+++ b/dom/filesystem/DeviceStorageFileSystem.h
@@ -25,24 +25,28 @@ public:
void
Init(nsDOMDeviceStorage* aDeviceStorage);
// Overrides FileSystemBase
virtual already_AddRefed<FileSystemBase>
Clone() override;
+ virtual bool
+ ShouldCreateDirectory() override { return true; }
+
virtual void
Shutdown() override;
virtual nsISupports*
GetParentObject() const override;
virtual void
- GetRootName(nsAString& aRetval) const override;
+ GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+ ErrorResult& aRv) const override;
virtual bool
IsSafeFile(nsIFile* aFile) const override;
virtual bool
IsSafeDirectory(Directory* aDir) const override;
virtual void
--- a/dom/filesystem/Directory.cpp
+++ b/dom/filesystem/Directory.cpp
@@ -132,58 +132,47 @@ Directory::GetRoot(FileSystemBase* aFile
nsCOMPtr<nsIFile> path;
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(aFileSystem->LocalOrDeviceStorageRootPath()),
true, getter_AddRefs(path));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetFileOrDirectoryTaskChild> task =
- GetFileOrDirectoryTaskChild::Create(aFileSystem, path, eDOMRootDirectory,
- true, aRv);
+ GetFileOrDirectoryTaskChild::Create(aFileSystem, path, true, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
/* static */ already_AddRefed<Directory>
Directory::Create(nsISupports* aParent, nsIFile* aFile,
- DirectoryType aType, FileSystemBase* aFileSystem)
+ FileSystemBase* aFileSystem)
{
MOZ_ASSERT(aParent);
MOZ_ASSERT(aFile);
#ifdef DEBUG
bool isDir;
nsresult rv = aFile->IsDirectory(&isDir);
MOZ_ASSERT(NS_SUCCEEDED(rv) && isDir);
-
- if (aType == eNotDOMRootDirectory) {
- RefPtr<nsIFile> parent;
- rv = aFile->GetParent(getter_AddRefs(parent));
- // We must have a parent if this is not the root directory.
- MOZ_ASSERT(NS_SUCCEEDED(rv) && parent);
- }
#endif
- RefPtr<Directory> directory =
- new Directory(aParent, aFile, aType, aFileSystem);
+ RefPtr<Directory> directory = new Directory(aParent, aFile, aFileSystem);
return directory.forget();
}
Directory::Directory(nsISupports* aParent,
nsIFile* aFile,
- DirectoryType aType,
FileSystemBase* aFileSystem)
: mParent(aParent)
, mFile(aFile)
- , mType(aType)
{
MOZ_ASSERT(aFile);
// aFileSystem can be null. In this case we create a OSFileSystem when needed.
if (aFileSystem) {
// More likely, this is a OSFileSystem. This object keeps a reference of
// mParent but it's not cycle collectable and to avoid manual
// addref/release, it's better to have 1 object per directory. For this
@@ -208,28 +197,22 @@ Directory::WrapObject(JSContext* aCx, JS
return DirectoryBinding::Wrap(aCx, this, aGivenProto);
}
void
Directory::GetName(nsAString& aRetval, ErrorResult& aRv)
{
aRetval.Truncate();
- if (mType == eDOMRootDirectory) {
- RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
- if (NS_WARN_IF(aRv.Failed())) {
- return;
- }
-
- fs->GetRootName(aRetval);
+ RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
return;
}
- aRv = mFile->GetLeafName(aRetval);
- NS_WARN_IF(aRv.Failed());
+ fs->GetDirectoryName(mFile, aRetval, aRv);
}
already_AddRefed<Promise>
Directory::CreateFile(const nsAString& aPath, const CreateFileOptions& aOptions,
ErrorResult& aRv)
{
// Only exposed for DeviceStorage.
MOZ_ASSERT(NS_IsMainThread());
@@ -313,18 +296,17 @@ Directory::Get(const nsAString& aPath, E
nsresult error = DOMPathToRealPath(aPath, getter_AddRefs(realPath));
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetFileOrDirectoryTaskChild> task =
- GetFileOrDirectoryTaskChild::Create(fs, realPath, eNotDOMRootDirectory,
- false, aRv);
+ GetFileOrDirectoryTaskChild::Create(fs, realPath, false, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
@@ -404,17 +386,17 @@ Directory::GetPath(nsAString& aRetval, E
{
// This operation is expensive. Better to cache the result.
if (mPath.IsEmpty()) {
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
- fs->GetDOMPath(mFile, mType, mPath, aRv);
+ fs->GetDOMPath(mFile, mPath, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
aRetval = mPath;
}
@@ -433,17 +415,17 @@ already_AddRefed<Promise>
Directory::GetFilesAndDirectories(ErrorResult& aRv)
{
RefPtr<FileSystemBase> fs = GetFileSystem(aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<GetDirectoryListingTaskChild> task =
- GetDirectoryListingTaskChild::Create(fs, mFile, mType, mFilters, aRv);
+ GetDirectoryListingTaskChild::Create(fs, mFile, mFilters, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
@@ -473,20 +455,16 @@ Directory::SetContentFilters(const nsASt
{
mFilters = aFilters;
}
FileSystemBase*
Directory::GetFileSystem(ErrorResult& aRv)
{
if (!mFileSystem) {
- // Any subdir inherits the FileSystem of the parent Directory. If we are
- // here it's because we are dealing with the DOM root.
- MOZ_ASSERT(mType == eDOMRootDirectory);
-
nsAutoString path;
aRv = mFile->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
RefPtr<OSFileSystem> fs = new OSFileSystem(path);
fs->Init(mParent);
--- a/dom/filesystem/Directory.h
+++ b/dom/filesystem/Directory.h
@@ -54,30 +54,19 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
static bool
DeviceStorageEnabled(JSContext* aCx, JSObject* aObj);
static already_AddRefed<Promise>
GetRoot(FileSystemBase* aFileSystem, ErrorResult& aRv);
- enum DirectoryType {
- // When a directory is selected using a HTMLInputElement, that will be the
- // DOM root directory and its name will be '/'. All the sub directory will
- // be called with they real name. We use this enum to mark what we must
- // consider the '/' of this DOM filesystem.
- eDOMRootDirectory,
-
- // All the sub directories of the '/' will be marked using this other value.
- eNotDOMRootDirectory
- };
-
static already_AddRefed<Directory>
Create(nsISupports* aParent, nsIFile* aDirectory,
- DirectoryType aType, FileSystemBase* aFileSystem = 0);
+ FileSystemBase* aFileSystem = 0);
// ========= Begin WebIDL bindings. ===========
nsISupports*
GetParentObject() const;
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -140,44 +129,38 @@ public:
* picker operation.
*/
void
SetContentFilters(const nsAString& aFilters);
FileSystemBase*
GetFileSystem(ErrorResult& aRv);
- DirectoryType Type() const
- {
- return mType;
- }
-
bool
ClonableToDifferentThreadOrProcess() const;
private:
Directory(nsISupports* aParent,
- nsIFile* aFile, DirectoryType aType,
+ nsIFile* aFile,
FileSystemBase* aFileSystem = nullptr);
~Directory();
/*
* Convert relative DOM path to the absolute real path.
*/
nsresult
DOMPathToRealPath(const nsAString& aPath, nsIFile** aFile) const;
already_AddRefed<Promise>
RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive,
ErrorResult& aRv);
nsCOMPtr<nsISupports> mParent;
RefPtr<FileSystemBase> mFileSystem;
nsCOMPtr<nsIFile> mFile;
- DirectoryType mType;
nsString mFilters;
nsString mPath;
};
} // namespace dom
} // namespace mozilla
--- a/dom/filesystem/FileSystemBase.cpp
+++ b/dom/filesystem/FileSystemBase.cpp
@@ -106,83 +106,86 @@ FileSystemBase::IsSafeFile(nsIFile* aFil
bool
FileSystemBase::IsSafeDirectory(Directory* aDir) const
{
AssertIsOnOwningThread();
return false;
}
void
+FileSystemBase::GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+ ErrorResult& aRv) const
+{
+ AssertIsOnOwningThread();
+ MOZ_ASSERT(aFile);
+
+ aRv = aFile->GetLeafName(aRetval);
+ NS_WARN_IF(aRv.Failed());
+}
+
+void
FileSystemBase::GetDOMPath(nsIFile* aFile,
- Directory::DirectoryType aType,
nsAString& aRetval,
ErrorResult& aRv) const
{
AssertIsOnOwningThread();
MOZ_ASSERT(aFile);
- if (aType == Directory::eDOMRootDirectory) {
- aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
- return;
- }
+ aRetval.Truncate();
nsCOMPtr<nsIFile> fileSystemPath;
aRv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(LocalOrDeviceStorageRootPath()),
true, getter_AddRefs(fileSystemPath));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
- MOZ_ASSERT(FileSystemUtils::IsDescendantPath(fileSystemPath, aFile));
-
nsCOMPtr<nsIFile> path;
aRv = aFile->Clone(getter_AddRefs(path));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
nsTArray<nsString> parts;
while (true) {
+ nsAutoString leafName;
+ aRv = path->GetLeafName(leafName);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
+ parts.AppendElement(leafName);
+
bool equal = false;
aRv = fileSystemPath->Equals(path, &equal);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
if (equal) {
break;
}
- nsAutoString leafName;
- aRv = path->GetLeafName(leafName);
- if (NS_WARN_IF(aRv.Failed())) {
- return;
- }
-
- parts.AppendElement(leafName);
-
nsCOMPtr<nsIFile> parentPath;
aRv = path->GetParent(getter_AddRefs(parentPath));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
MOZ_ASSERT(parentPath);
aRv = parentPath->Clone(getter_AddRefs(path));
if (NS_WARN_IF(aRv.Failed())) {
return;
}
}
MOZ_ASSERT(!parts.IsEmpty());
- aRetval.Truncate();
-
for (int32_t i = parts.Length() - 1; i >= 0; --i) {
aRetval.AppendLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
aRetval.Append(parts[i]);
}
}
void
FileSystemBase::AssertIsOnOwningThread() const
--- a/dom/filesystem/FileSystemBase.h
+++ b/dom/filesystem/FileSystemBase.h
@@ -32,29 +32,28 @@ public:
// SerializeDOMPath the FileSystem to string.
virtual void
SerializeDOMPath(nsAString& aOutput) const = 0;
virtual already_AddRefed<FileSystemBase>
Clone() = 0;
+ virtual bool
+ ShouldCreateDirectory() = 0;
+
virtual nsISupports*
GetParentObject() const;
- /*
- * Get the virtual name of the root directory. This name will be exposed to
- * the content page.
- */
virtual void
- GetRootName(nsAString& aRetval) const = 0;
+ GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+ ErrorResult& aRv) const;
void
- GetDOMPath(nsIFile* aFile, Directory::DirectoryType aType,
- nsAString& aRetval, ErrorResult& aRv) const;
+ GetDOMPath(nsIFile* aFile, nsAString& aRetval, ErrorResult& aRv) const;
/*
* Return the local root path of the FileSystem implementation.
* For OSFileSystem, this is equal to the path of the root Directory;
* For DeviceStorageFileSystem, this is the path of the SDCard, parent
* directory of the exposed root Directory (per type).
*/
const nsAString&
--- a/dom/filesystem/GetDirectoryListingTask.cpp
+++ b/dom/filesystem/GetDirectoryListingTask.cpp
@@ -23,25 +23,24 @@ namespace dom {
/**
* GetDirectoryListingTaskChild
*/
/* static */ already_AddRefed<GetDirectoryListingTaskChild>
GetDirectoryListingTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv)
{
MOZ_ASSERT(aFileSystem);
aFileSystem->AssertIsOnOwningThread();
RefPtr<GetDirectoryListingTaskChild> task =
- new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aType, aFilters);
+ new GetDirectoryListingTaskChild(aFileSystem, aTargetPath, aFilters);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
@@ -52,22 +51,20 @@ GetDirectoryListingTaskChild::Create(Fil
return nullptr;
}
return task.forget();
}
GetDirectoryListingTaskChild::GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
const nsAString& aFilters)
: FileSystemTaskChildBase(aFileSystem)
, mTargetPath(aTargetPath)
, mFilters(aFilters)
- , mType(aType)
{
MOZ_ASSERT(aFileSystem);
aFileSystem->AssertIsOnOwningThread();
}
GetDirectoryListingTaskChild::~GetDirectoryListingTaskChild()
{
mFileSystem->AssertIsOnOwningThread();
@@ -88,17 +85,16 @@ GetDirectoryListingTaskChild::GetRequest
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemGetDirectoryListingParams();
}
return FileSystemGetDirectoryListingParams(aSerializedDOMPath, path,
- mType == Directory::eDOMRootDirectory,
mFilters);
}
void
GetDirectoryListingTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
mFileSystem->AssertIsOnOwningThread();
@@ -174,18 +170,17 @@ GetDirectoryListingTaskChild::HandlerCal
return;
}
MOZ_ASSERT(FileSystemUtils::IsDescendantPath(rootPath, path));
#endif
if (mTargetData[i].mType == Directory::FileOrDirectoryPath::eDirectoryPath) {
RefPtr<Directory> directory =
- Directory::Create(mFileSystem->GetParentObject(), path,
- Directory::eNotDOMRootDirectory, mFileSystem);
+ Directory::Create(mFileSystem->GetParentObject(), path, mFileSystem);
MOZ_ASSERT(directory);
// Propogate mFilter onto sub-Directory object:
directory->SetContentFilters(mFilters);
listing[i].SetAsDirectory() = directory;
} else {
MOZ_ASSERT(mTargetData[i].mType == Directory::FileOrDirectoryPath::eFilePath);
@@ -225,18 +220,16 @@ GetDirectoryListingTaskParent::Create(Fi
new GetDirectoryListingTaskParent(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
- task->mType = aParam.isRoot()
- ? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
return task.forget();
}
GetDirectoryListingTaskParent::GetDirectoryListingTaskParent(FileSystemBase* aFileSystem,
const FileSystemGetDirectoryListingParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
, mFilters(aParam.filters())
@@ -286,21 +279,20 @@ GetDirectoryListingTaskParent::IOWork()
bool exists;
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
- if (mType == Directory::eNotDOMRootDirectory) {
+ if (!mFileSystem->ShouldCreateDirectory()) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
- // If the root directory doesn't exit, create it.
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// Get isDirectory.
bool isDir;
--- a/dom/filesystem/GetDirectoryListingTask.h
+++ b/dom/filesystem/GetDirectoryListingTask.h
@@ -18,51 +18,48 @@ namespace dom {
class BlobImpl;
class GetDirectoryListingTaskChild final : public FileSystemTaskChildBase
{
public:
static already_AddRefed<GetDirectoryListingTaskChild>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
const nsAString& aFilters,
ErrorResult& aRv);
virtual
~GetDirectoryListingTaskChild();
already_AddRefed<Promise>
GetPromise();
virtual void
GetPermissionAccessType(nsCString& aAccess) const override;
private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetDirectoryListingTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
const nsAString& aFilters);
virtual FileSystemParams
GetRequestParams(const nsString& aSerializedDOMPath,
ErrorResult& aRv) const override;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv) override;
virtual void
HandlerCallback() override;
RefPtr<Promise> mPromise;
nsCOMPtr<nsIFile> mTargetPath;
nsString mFilters;
- Directory::DirectoryType mType;
// We cannot store File or Directory objects bacause this object is created
// on a different thread and File and Directory are not thread-safe.
FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
};
class GetDirectoryListingTaskParent final : public FileSystemTaskParentBase
{
@@ -84,17 +81,16 @@ private:
virtual FileSystemResponseValue
GetSuccessRequestResult(ErrorResult& aRv) const override;
virtual nsresult
IOWork() override;
nsCOMPtr<nsIFile> mTargetPath;
nsString mFilters;
- Directory::DirectoryType mType;
// We cannot store File or Directory objects bacause this object is created
// on a different thread and File and Directory are not thread-safe.
FallibleTArray<Directory::FileOrDirectoryPath> mTargetData;
};
} // namespace dom
} // namespace mozilla
--- a/dom/filesystem/GetFileOrDirectoryTask.cpp
+++ b/dom/filesystem/GetFileOrDirectoryTask.cpp
@@ -22,26 +22,24 @@ namespace dom {
/**
* GetFileOrDirectoryTaskChild
*/
/* static */ already_AddRefed<GetFileOrDirectoryTaskChild>
GetFileOrDirectoryTaskChild::Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
RefPtr<GetFileOrDirectoryTaskChild> task =
- new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aType,
- aDirectoryOnly);
+ new GetFileOrDirectoryTaskChild(aFileSystem, aTargetPath, aDirectoryOnly);
// aTargetPath can be null. In this case SetError will be called.
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetParentObject());
if (NS_WARN_IF(!globalObject)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
@@ -52,22 +50,20 @@ GetFileOrDirectoryTaskChild::Create(File
return nullptr;
}
return task.forget();
}
GetFileOrDirectoryTaskChild::GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
bool aDirectoryOnly)
: FileSystemTaskChildBase(aFileSystem)
, mTargetPath(aTargetPath)
, mIsDirectory(aDirectoryOnly)
- , mType(aType)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem);
}
GetFileOrDirectoryTaskChild::~GetFileOrDirectoryTaskChild()
{
MOZ_ASSERT(NS_IsMainThread());
@@ -87,18 +83,17 @@ GetFileOrDirectoryTaskChild::GetRequestP
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
nsAutoString path;
aRv = mTargetPath->GetPath(path);
if (NS_WARN_IF(aRv.Failed())) {
return FileSystemGetFileOrDirectoryParams();
}
- return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path,
- mType == Directory::eDOMRootDirectory);
+ return FileSystemGetFileOrDirectoryParams(aSerializedDOMPath, path);
}
void
GetFileOrDirectoryTaskChild::SetSuccessRequestResult(const FileSystemResponseValue& aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
switch (aValue.type()) {
@@ -146,17 +141,16 @@ GetFileOrDirectoryTaskChild::HandlerCall
mPromise->MaybeReject(mErrorValue);
mPromise = nullptr;
return;
}
if (mIsDirectory) {
RefPtr<Directory> dir = Directory::Create(mFileSystem->GetParentObject(),
mTargetPath,
- mType,
mFileSystem);
MOZ_ASSERT(dir);
mPromise->MaybeResolve(dir);
mPromise = nullptr;
return;
}
@@ -190,18 +184,16 @@ GetFileOrDirectoryTaskParent::Create(Fil
new GetFileOrDirectoryTaskParent(aFileSystem, aParam, aParent);
NS_ConvertUTF16toUTF8 path(aParam.realPath());
aRv = NS_NewNativeLocalFile(path, true, getter_AddRefs(task->mTargetPath));
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
- task->mType = aParam.isRoot()
- ? Directory::eDOMRootDirectory : Directory::eNotDOMRootDirectory;
return task.forget();
}
GetFileOrDirectoryTaskParent::GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskParentBase(aFileSystem, aParam, aParent)
, mIsDirectory(false)
@@ -243,42 +235,36 @@ GetFileOrDirectoryTaskParent::IOWork()
// Whether we want to get the root directory.
bool exists;
nsresult rv = mTargetPath->Exists(&exists);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!exists) {
- if (mType == Directory::eNotDOMRootDirectory) {
+ if (!mFileSystem->ShouldCreateDirectory()) {
return NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
}
- // If the root directory doesn't exit, create it.
rv = mTargetPath->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// Get isDirectory.
rv = mTargetPath->IsDirectory(&mIsDirectory);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (mIsDirectory) {
return NS_OK;
}
- // Check if the root is a directory.
- if (mType == Directory::eDOMRootDirectory) {
- return NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
- }
-
bool isFile;
// Get isFile
rv = mTargetPath->IsFile(&isFile);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!isFile) {
--- a/dom/filesystem/GetFileOrDirectoryTask.h
+++ b/dom/filesystem/GetFileOrDirectoryTask.h
@@ -18,17 +18,16 @@ namespace dom {
class BlobImpl;
class GetFileOrDirectoryTaskChild final : public FileSystemTaskChildBase
{
public:
static already_AddRefed<GetFileOrDirectoryTaskChild>
Create(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
bool aDirectoryOnly,
ErrorResult& aRv);
virtual
~GetFileOrDirectoryTaskChild();
already_AddRefed<Promise>
GetPromise();
@@ -46,25 +45,23 @@ protected:
ErrorResult& aRv) override;
virtual void
HandlerCallback() override;
private:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTaskChild(FileSystemBase* aFileSystem,
nsIFile* aTargetPath,
- Directory::DirectoryType aType,
bool aDirectoryOnly);
RefPtr<Promise> mPromise;
nsCOMPtr<nsIFile> mTargetPath;
// Whether we get a directory.
bool mIsDirectory;
- Directory::DirectoryType mType;
};
class GetFileOrDirectoryTaskParent final : public FileSystemTaskParentBase
{
public:
static already_AddRefed<GetFileOrDirectoryTaskParent>
Create(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
@@ -85,15 +82,14 @@ private:
GetFileOrDirectoryTaskParent(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent);
nsCOMPtr<nsIFile> mTargetPath;
// Whether we get a directory.
bool mIsDirectory;
- Directory::DirectoryType mType;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_GetFileOrDirectory_h
--- a/dom/filesystem/OSFileSystem.cpp
+++ b/dom/filesystem/OSFileSystem.cpp
@@ -57,23 +57,16 @@ OSFileSystem::Init(nsISupports* aParent)
nsISupports*
OSFileSystem::GetParentObject() const
{
AssertIsOnOwningThread();
return mParent;
}
-void
-OSFileSystem::GetRootName(nsAString& aRetval) const
-{
- AssertIsOnOwningThread();
- aRetval.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL);
-}
-
bool
OSFileSystem::IsSafeFile(nsIFile* aFile) const
{
// The concept of "safe files" is specific to the Device Storage API where
// files are only "safe" if they're of a type that is appropriate for the
// area of device storage that is being used.
MOZ_CRASH("Don't use OSFileSystem with the Device Storage API");
return true;
--- a/dom/filesystem/OSFileSystem.h
+++ b/dom/filesystem/OSFileSystem.h
@@ -20,22 +20,28 @@ public:
void
Init(nsISupports* aParent);
// Overrides FileSystemBase
virtual already_AddRefed<FileSystemBase>
Clone() override;
+ virtual bool
+ ShouldCreateDirectory() override
+ {
+ MOZ_CRASH("This should not be called.");
+ // Because OSFileSystem should not be used when the creation of directories
+ // is needed. For that we have OSFileSystemParent.
+ return false;
+ }
+
virtual nsISupports*
GetParentObject() const override;
- virtual void
- GetRootName(nsAString& aRetval) const override;
-
virtual bool
IsSafeFile(nsIFile* aFile) const override;
virtual bool
IsSafeDirectory(Directory* aDir) const override;
virtual void
SerializeDOMPath(nsAString& aOutput) const override;
@@ -62,25 +68,29 @@ public:
virtual already_AddRefed<FileSystemBase>
Clone() override
{
MOZ_CRASH("This should not be called on the PBackground thread.");
return nullptr;
}
+ virtual bool
+ ShouldCreateDirectory() override { return false; }
+
virtual nsISupports*
GetParentObject() const override
{
MOZ_CRASH("This should not be called on the PBackground thread.");
return nullptr;
}
virtual void
- GetRootName(nsAString& aRetval) const override
+ GetDirectoryName(nsIFile* aFile, nsAString& aRetval,
+ ErrorResult& aRv) const override
{
MOZ_CRASH("This should not be called on the PBackground thread.");
}
virtual bool
IsSafeFile(nsIFile* aFile) const override
{
MOZ_CRASH("This should not be called on the PBackground thread.");
--- a/dom/filesystem/PFileSystemParams.ipdlh
+++ b/dom/filesystem/PFileSystemParams.ipdlh
@@ -26,17 +26,17 @@ struct FileSystemCreateFileParams
FileSystemFileDataValue data;
bool replace;
};
struct FileSystemGetDirectoryListingParams
{
nsString filesystem;
nsString realPath;
- bool isRoot;
+
// 'filters' could be an array rather than a semicolon separated string
// (we'd then use InfallibleTArray<nsString> internally), but that is
// wasteful. E10s requires us to pass the filters over as a string anyway,
// so avoiding using an array avoids serialization on the side passing the
// filters. Since an nsString can share its buffer when copied,
// using that instead of InfallibleTArray<nsString> makes copying the filters
// around in any given process a bit more efficient too, since copying a
// single nsString is cheaper than copying InfallibleTArray member data and
@@ -50,17 +50,16 @@ struct FileSystemGetFilesParams
nsString realPath;
bool recursiveFlag;
};
struct FileSystemGetFileOrDirectoryParams
{
nsString filesystem;
nsString realPath;
- bool isRoot;
};
struct FileSystemRemoveParams
{
nsString filesystem;
nsString directory;
nsString targetDirectory;
bool recursive;
--- a/dom/filesystem/tests/filesystem_commons.js
+++ b/dom/filesystem/tests/filesystem_commons.js
@@ -1,42 +1,41 @@
function test_basic(aDirectory, aNext) {
ok(aDirectory, "Directory exists.");
ok(aDirectory instanceof Directory, "We have a directory.");
- is(aDirectory.name, '/', "directory.name must be '/'");
- is(aDirectory.path, '/', "directory.path must be '/'");
+ is(aDirectory.path, '/' + aDirectory.name, "directory.path must be '/'+name");
aNext();
}
function test_getFilesAndDirectories(aDirectory, aRecursive, aNext) {
function checkSubDir(dir) {
return dir.getFilesAndDirectories().then(
function(data) {
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories");
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
isnot(data[i].path, '/', "Subdirectory path should be called with the leafname");
isnot(data[i].path, dir.path, "Subdirectory path should contain the parent path.");
- is(data[i].path,dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
+ is(data[i].path, dir.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
}
}
}
);
}
aDirectory.getFilesAndDirectories().then(
function(data) {
ok(data.length, "We should have some data.");
var promises = [];
for (var i = 0; i < data.length; ++i) {
ok (data[i] instanceof File || data[i] instanceof Directory, "Just Files or Directories: " + data[i].name);
if (data[i] instanceof Directory) {
isnot(data[i].name, '/', "Subdirectory should be called with the leafname");
- is(data[i].path, '/' + data[i].name, "Subdirectory path should be called '/' + leafname");
+ is(data[i].path, aDirectory.path + '/' + data[i].name, "Subdirectory path should be called parentdir.path + '/' + leafname");
if (aRecursive) {
promises.push(checkSubDir(data[i]));
}
}
}
return Promise.all(promises);
},
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -267,18 +267,17 @@ class HTMLInputElementState final : publ
nsCOMPtr<nsIFile> file;
NS_ConvertUTF16toUTF8 path(mBlobImplsOrDirectoryPaths[i].mDirectoryPath);
nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
continue;
}
- RefPtr<Directory> directory = Directory::Create(aWindow, file,
- Directory::eDOMRootDirectory);
+ RefPtr<Directory> directory = Directory::Create(aWindow, file);
MOZ_ASSERT(directory);
OwningFileOrDirectory* element = aResult.AppendElement();
element->SetAsDirectory() = directory;
}
}
}
@@ -2306,18 +2305,17 @@ HTMLInputElement::MozSetDirectory(const
}
nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
if (NS_WARN_IF(!window)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
- RefPtr<Directory> directory = Directory::Create(window, file,
- Directory::eDOMRootDirectory);
+ RefPtr<Directory> directory = Directory::Create(window, file);
MOZ_ASSERT(directory);
nsTArray<OwningFileOrDirectory> array;
OwningFileOrDirectory* element = array.AppendElement();
element->SetAsDirectory() = directory;
SetFilesOrDirectories(array, true);
}
--- a/dom/html/nsTextEditorState.cpp
+++ b/dom/html/nsTextEditorState.cpp
@@ -897,17 +897,17 @@ nsTextInputListener::HandleEvent(nsIDOME
if (keyEvent->mMessage != eKeyPress) {
return NS_OK;
}
nsIWidget::NativeKeyBindingsType nativeKeyBindingsType =
mTxtCtrlElement->IsTextArea() ?
nsIWidget::NativeKeyBindingsForMultiLineEditor :
nsIWidget::NativeKeyBindingsForSingleLineEditor;
- nsIWidget* widget = keyEvent->widget;
+ nsIWidget* widget = keyEvent->mWidget;
// If the event is created by chrome script, the widget is nullptr.
if (!widget) {
widget = mFrame->GetNearestWidget();
NS_ENSURE_TRUE(widget, NS_OK);
}
if (widget->ExecuteNativeKeyBinding(nativeKeyBindingsType,
*keyEvent, DoCommandCallback, mFrame)) {
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -420,56 +420,61 @@ private:
~ConsoleListener() {}
ContentChild* mChild;
friend class ContentChild;
};
NS_IMPL_ISUPPORTS(ConsoleListener, nsIConsoleListener)
+// Before we send the error to the parent process (which
+// involves copying the memory), truncate any long lines. CSS
+// errors in particular share the memory for long lines with
+// repeated errors, but the IPC communication we're about to do
+// will break that sharing, so we better truncate now.
+static void
+TruncateString(nsAString& aString)
+{
+ if (aString.Length() > 1000) {
+ aString.Truncate(1000);
+ }
+}
+
NS_IMETHODIMP
ConsoleListener::Observe(nsIConsoleMessage* aMessage)
{
if (!mChild) {
return NS_OK;
}
nsCOMPtr<nsIScriptError> scriptError = do_QueryInterface(aMessage);
if (scriptError) {
nsString msg, sourceName, sourceLine;
nsXPIDLCString category;
uint32_t lineNum, colNum, flags;
nsresult rv = scriptError->GetErrorMessage(msg);
NS_ENSURE_SUCCESS(rv, rv);
+ TruncateString(msg);
rv = scriptError->GetSourceName(sourceName);
NS_ENSURE_SUCCESS(rv, rv);
+ TruncateString(sourceName);
rv = scriptError->GetSourceLine(sourceLine);
NS_ENSURE_SUCCESS(rv, rv);
-
- // Before we send the error to the parent process (which
- // involves copying the memory), truncate any long lines. CSS
- // errors in particular share the memory for long lines with
- // repeated errors, but the IPC communication we're about to do
- // will break that sharing, so we better truncate now.
- if (sourceName.Length() > 1000) {
- sourceName.Truncate(1000);
- }
- if (sourceLine.Length() > 1000) {
- sourceLine.Truncate(1000);
- }
+ TruncateString(sourceLine);
rv = scriptError->GetCategory(getter_Copies(category));
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetLineNumber(&lineNum);
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetColumnNumber(&colNum);
NS_ENSURE_SUCCESS(rv, rv);
rv = scriptError->GetFlags(&flags);
NS_ENSURE_SUCCESS(rv, rv);
+
mChild->SendScriptError(msg, sourceName, sourceLine,
lineNum, colNum, flags, category);
return NS_OK;
}
nsXPIDLString msg;
nsresult rv = aMessage->GetMessageMoz(getter_Copies(msg));
NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1851,17 +1851,17 @@ bool
TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& aEvent,
const ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId)
{
nsEventStatus unused;
InputAPZContext context(aGuid, aInputBlockId, unused);
WidgetMouseEvent localEvent(aEvent);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
mPuppetWidget->GetDefaultScale());
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
if (aEvent.mFlags.mHandledByAPZ) {
mAPZEventState->ProcessMouseEvent(aEvent, aGuid, aInputBlockId);
}
return true;
@@ -1874,17 +1874,17 @@ TabChild::RecvMouseWheelEvent(const Widg
{
if (aEvent.mFlags.mHandledByAPZ) {
nsCOMPtr<nsIDocument> document(GetDocument());
APZCCallbackHelper::SendSetTargetAPZCNotification(
mPuppetWidget, document, aEvent, aGuid, aInputBlockId);
}
WidgetWheelEvent localEvent(aEvent);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
mPuppetWidget->GetDefaultScale());
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
if (localEvent.mCanTriggerSwipe) {
SendRespondStartSwipeEvent(aInputBlockId, localEvent.TriggersSwipe());
}
@@ -1918,17 +1918,17 @@ bool
TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
const ScrollableLayerGuid& aGuid,
const uint64_t& aInputBlockId,
const nsEventStatus& aApzResponse)
{
TABC_LOG("Receiving touch event of type %d\n", aEvent.mMessage);
WidgetTouchEvent localEvent(aEvent);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
APZCCallbackHelper::ApplyCallbackTransform(localEvent, aGuid,
mPuppetWidget->GetDefaultScale());
if (localEvent.mMessage == eTouchStart && AsyncPanZoomEnabled()) {
if (gfxPrefs::TouchActionEnabled()) {
APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(mPuppetWidget,
localEvent, aInputBlockId, mSetAllowedTouchBehaviorCallback);
@@ -1963,17 +1963,17 @@ TabChild::RecvRealTouchMoveEvent(const W
}
bool
TabChild::RecvRealDragEvent(const WidgetDragEvent& aEvent,
const uint32_t& aDragAction,
const uint32_t& aDropEffect)
{
WidgetDragEvent localEvent(aEvent);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession();
if (dragSession) {
dragSession->SetDragAction(aDragAction);
nsCOMPtr<nsIDOMDataTransfer> initialDataTransfer;
dragSession->GetDataTransfer(getter_AddRefs(initialDataTransfer));
if (initialDataTransfer) {
initialDataTransfer->SetDropEffectInt(aDropEffect);
@@ -1999,17 +1999,17 @@ TabChild::RecvRealDragEvent(const Widget
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
return true;
}
bool
TabChild::RecvPluginEvent(const WidgetPluginEvent& aEvent)
{
WidgetPluginEvent localEvent(aEvent);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
if (status != nsEventStatus_eConsumeNoDefault) {
// If not consumed, we should call default action
SendDefaultProcOfPluginEvent(aEvent);
}
return true;
}
@@ -2058,17 +2058,17 @@ TabChild::RecvRealKeyEvent(const WidgetK
bindings.multiLineCommands(),
bindings.richTextCommands());
} else {
autoCache.CacheNoCommands();
}
}
WidgetKeyboardEvent localEvent(event);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
nsEventStatus status = APZCCallbackHelper::DispatchWidgetEvent(localEvent);
if (event.mMessage == eKeyDown) {
mIgnoreKeyPressEvent = status == nsEventStatus_eConsumeNoDefault;
}
if (localEvent.mFlags.mWantReplyFromContentProcess) {
SendReplyKeyEvent(localEvent);
@@ -2093,27 +2093,27 @@ TabChild::RecvKeyEvent(const nsString& a
aModifiers, aPreventDefault, &ignored);
return true;
}
bool
TabChild::RecvCompositionEvent(const WidgetCompositionEvent& event)
{
WidgetCompositionEvent localEvent(event);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
Unused << SendOnEventNeedingAckHandled(event.mMessage);
return true;
}
bool
TabChild::RecvSelectionEvent(const WidgetSelectionEvent& event)
{
WidgetSelectionEvent localEvent(event);
- localEvent.widget = mPuppetWidget;
+ localEvent.mWidget = mPuppetWidget;
APZCCallbackHelper::DispatchWidgetEvent(localEvent);
Unused << SendOnEventNeedingAckHandled(event.mMessage);
return true;
}
a11y::PDocAccessibleChild*
TabChild::AllocPDocAccessibleChild(PDocAccessibleChild*, const uint64_t&)
{
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1245,49 +1245,49 @@ bool TabParent::SendMouseWheelEvent(Widg
bool TabParent::RecvDispatchWheelEvent(const mozilla::WidgetWheelEvent& aEvent)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
WidgetWheelEvent localEvent(aEvent);
- localEvent.widget = widget;
+ localEvent.mWidget = widget;
localEvent.refPoint -= GetChildProcessOffset();
widget->DispatchInputEvent(&localEvent);
return true;
}
bool
TabParent::RecvDispatchMouseEvent(const mozilla::WidgetMouseEvent& aEvent)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
WidgetMouseEvent localEvent(aEvent);
- localEvent.widget = widget;
+ localEvent.mWidget = widget;
localEvent.refPoint -= GetChildProcessOffset();
widget->DispatchInputEvent(&localEvent);
return true;
}
bool
TabParent::RecvDispatchKeyboardEvent(const mozilla::WidgetKeyboardEvent& aEvent)
{
nsCOMPtr<nsIWidget> widget = GetWidget();
if (!widget) {
return true;
}
WidgetKeyboardEvent localEvent(aEvent);
- localEvent.widget = widget;
+ localEvent.mWidget = widget;
localEvent.refPoint -= GetChildProcessOffset();
widget->DispatchInputEvent(&localEvent);
return true;
}
static void
DoCommandCallback(mozilla::Command aCommand, void* aData)
@@ -2015,17 +2015,17 @@ TabParent::RecvReplyKeyEvent(const Widge
}
bool
TabParent::RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent)
{
NS_ENSURE_TRUE(mFrameElement, true);
WidgetKeyboardEvent localEvent(aEvent);
- localEvent.widget = GetWidget();
+ localEvent.mWidget = GetWidget();
nsIDocument* doc = mFrameElement->OwnerDoc();
nsCOMPtr<nsIPresShell> presShell = doc->GetShell();
NS_ENSURE_TRUE(presShell, true);
if (mFrameElement &&
PresShell::BeforeAfterKeyboardEventEnabled() &&
localEvent.mMessage != eKeyPress) {
--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -1,62 +1,94 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "AudioConverter.h"
#include <string.h>
+#include <speex/speex_resampler.h>
/*
* Parts derived from MythTV AudioConvert Class
* Created by Jean-Yves Avenard.
*
* Copyright (C) Bubblestuff Pty Ltd 2013
* Copyright (C) foobum@gmail.com 2010
*/
namespace mozilla {
AudioConverter::AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut)
: mIn(aIn)
, mOut(aOut)
+ , mResampler(nullptr)
{
- MOZ_DIAGNOSTIC_ASSERT(aIn.Rate() == aOut.Rate() &&
- aIn.Format() == aOut.Format() &&
+ MOZ_DIAGNOSTIC_ASSERT(aIn.Format() == aOut.Format() &&
aIn.Interleaved() == aOut.Interleaved(),
"No format or rate conversion is supported at this stage");
MOZ_DIAGNOSTIC_ASSERT((aIn.Channels() > aOut.Channels() && aOut.Channels() <= 2) ||
aIn.Channels() == aOut.Channels(),
"Only downmixing to mono or stereo is supported at this stage");
MOZ_DIAGNOSTIC_ASSERT(aOut.Interleaved(), "planar audio format not supported");
mIn.Layout().MappingTable(mOut.Layout(), mChannelOrderMap);
+ if (aIn.Rate() != aOut.Rate()) {
+ int error;
+ mResampler = speex_resampler_init(aOut.Channels(),
+ aIn.Rate(),
+ aOut.Rate(),
+ SPEEX_RESAMPLER_QUALITY_DEFAULT,
+ &error);
+
+ if (error == RESAMPLER_ERR_SUCCESS) {
+ speex_resampler_skip_zeros(mResampler);
+ } else {
+ NS_WARNING("Failed to initialize resampler.");
+ mResampler = nullptr;
+ }
+ }
+}
+
+AudioConverter::~AudioConverter()
+{
+ if (mResampler) {
+ speex_resampler_destroy(mResampler);
+ mResampler = nullptr;
+ }
}
bool
AudioConverter::CanWorkInPlace() const
{
- return mIn.Channels() * mIn.Rate() * AudioConfig::SampleSize(mIn.Format()) >=
- mOut.Channels() * mOut.Rate() * AudioConfig::SampleSize(mOut.Format());
+ bool needDownmix = mIn.Channels() > mOut.Channels();
+ bool canDownmixInPlace =
+ mIn.Channels() * AudioConfig::SampleSize(mIn.Format()) >=
+ mOut.Channels() * AudioConfig::SampleSize(mOut.Format());
+ bool needResample = mIn.Rate() != mOut.Rate();
+ bool canResampleInPlace = mIn.Rate() >= mOut.Rate();
+ // We should be able to work in place if 1s of audio input takes less space
+ // than 1s of audio output. However, as we downmix before resampling we can't
+ // perform any upsampling in place (e.g. if incoming rate >= outgoing rate)
+ return (!needDownmix || canDownmixInPlace) &&
+ (!needResample || canResampleInPlace);
}
size_t
-AudioConverter::Process(void* aOut, const void* aIn, size_t aBytes)
+AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aFrames)
{
- if (!CanWorkInPlace()) {
- return 0;
- }
if (mIn.Channels() > mOut.Channels()) {
- return DownmixAudio(aOut, aIn, aBytes);
+ return DownmixAudio(aOut, aIn, aFrames);
} else if (mIn.Layout() != mOut.Layout() &&
CanReorderAudio()) {
- ReOrderInterleavedChannels(aOut, aIn, aBytes);
+ ReOrderInterleavedChannels(aOut, aIn, aFrames);
+ } else if (aIn != aOut) {
+ memmove(aOut, aIn, FramesOutToBytes(aFrames));
}
- return aBytes;
+ return aFrames;
}
// Reorder interleaved channels.
// Can work in place (e.g aOut == aIn).
template <class AudioDataType>
void
_ReOrderInterleavedChannels(AudioDataType* aOut, const AudioDataType* aIn,
uint32_t aFrames, uint32_t aChannels,
@@ -73,95 +105,90 @@ void
}
aOut += aChannels;
aIn += aChannels;
}
}
void
AudioConverter::ReOrderInterleavedChannels(void* aOut, const void* aIn,
- size_t aDataSize) const
+ size_t aFrames) const
{
MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() == mOut.Channels());
if (mOut.Layout() == mIn.Layout()) {
return;
}
if (mOut.Channels() == 1) {
// If channel count is 1, planar and non-planar formats are the same and
// there's nothing to reorder.
if (aOut != aIn) {
- memmove(aOut, aIn, aDataSize);
+ memmove(aOut, aIn, FramesOutToBytes(aFrames));
}
return;
}
uint32_t bits = AudioConfig::FormatToBits(mOut.Format());
switch (bits) {
case 8:
_ReOrderInterleavedChannels((uint8_t*)aOut, (const uint8_t*)aIn,
- aDataSize/sizeof(uint8_t)/mIn.Channels(),
- mIn.Channels(), mChannelOrderMap);
+ aFrames, mIn.Channels(), mChannelOrderMap);
break;
case 16:
_ReOrderInterleavedChannels((int16_t*)aOut,(const int16_t*)aIn,
- aDataSize/sizeof(int16_t)/mIn.Channels(),
- mIn.Channels(), mChannelOrderMap);
+ aFrames, mIn.Channels(), mChannelOrderMap);
break;
default:
MOZ_DIAGNOSTIC_ASSERT(AudioConfig::SampleSize(mOut.Format()) == 4);
_ReOrderInterleavedChannels((int32_t*)aOut,(const int32_t*)aIn,
- aDataSize/sizeof(int32_t)/mIn.Channels(),
- mIn.Channels(), mChannelOrderMap);
+ aFrames, mIn.Channels(), mChannelOrderMap);
break;
}
}
static inline int16_t clipTo15(int32_t aX)
{
return aX < -32768 ? -32768 : aX <= 32767 ? aX : 32767;
}
size_t
-AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const
+AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const
{
MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
mIn.Format() == AudioConfig::FORMAT_FLT);
MOZ_ASSERT(mIn.Channels() >= mOut.Channels());
MOZ_ASSERT(mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()),
"Can only downmix input data in SMPTE layout");
MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
mOut.Layout() == AudioConfig::ChannelLayout(1));
uint32_t channels = mIn.Channels();
- uint32_t frames =
- aDataSize / AudioConfig::SampleSize(mOut.Format()) / channels;
if (channels == 1 && mOut.Channels() == 1) {
if (aOut != aIn) {
- memmove(aOut, aIn, aDataSize);
+ memmove(aOut, aIn, FramesOutToBytes(aFrames));
}
- return aDataSize;
+ return aFrames;
}
if (channels > 2) {
if (mIn.Format() == AudioConfig::FORMAT_FLT) {
// Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
static const float dmatrix[6][8][2]= {
/*3*/{{0.5858f,0},{0,0.5858f},{0.4142f,0.4142f}},
/*4*/{{0.4226f,0},{0,0.4226f},{0.366f, 0.2114f},{0.2114f,0.366f}},
/*5*/{{0.6510f,0},{0,0.6510f},{0.4600f,0.4600f},{0.5636f,0.3254f},{0.3254f,0.5636f}},
/*6*/{{0.5290f,0},{0,0.5290f},{0.3741f,0.3741f},{0.3741f,0.3741f},{0.4582f,0.2645f},{0.2645f,0.4582f}},
/*7*/{{0.4553f,0},{0,0.4553f},{0.3220f,0.3220f},{0.3220f,0.3220f},{0.2788f,0.2788f},{0.3943f,0.2277f},{0.2277f,0.3943f}},
/*8*/{{0.3886f,0},{0,0.3886f},{0.2748f,0.2748f},{0.2748f,0.2748f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.3366f,0.1943f},{0.1943f,0.3366f}},
};
// Re-write the buffer with downmixed data
const float* in = static_cast<const float*>(aIn);
float* out = static_cast<float*>(aOut);
- for (uint32_t i = 0; i < frames; i++) {
+ for (uint32_t i = 0; i < aFrames; i++) {
float sampL = 0.0;
float sampR = 0.0;
for (uint32_t j = 0; j < channels; j++) {
sampL += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][0];
sampR += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][1];
}
*out++ = sampL;
*out++ = sampR;
@@ -175,17 +202,17 @@ AudioConverter::DownmixAudio(void* aOut,
/*5*/{{10663,0},{0, 10663},{7540,7540},{9234,5331},{5331,9234}},
/*6*/{{8668, 0},{0, 8668},{6129,6129},{6129,6129},{7507,4335},{4335,7507}},
/*7*/{{7459, 0},{0, 7459},{5275,5275},{5275,5275},{4568,4568},{6460,3731},{3731,6460}},
/*8*/{{6368, 0},{0, 6368},{4502,4502},{4502,4502},{5514,3184},{3184,5514},{5514,3184},{3184,5514}}
};
// Re-write the buffer with downmixed data
const int16_t* in = static_cast<const int16_t*>(aIn);
int16_t* out = static_cast<int16_t*>(aOut);
- for (uint32_t i = 0; i < frames; i++) {
+ for (uint32_t i = 0; i < aFrames; i++) {
int32_t sampL = 0;
int32_t sampR = 0;
for (uint32_t j = 0; j < channels; j++) {
sampL+=in[i*channels+j]*dmatrix[channels-3][j][0];
sampR+=in[i*channels+j]*dmatrix[channels-3][j][1];
}
*out++ = clipTo15((sampL + 8192)>>14);
*out++ = clipTo15((sampR + 8192)>>14);
@@ -199,31 +226,80 @@ AudioConverter::DownmixAudio(void* aOut,
aIn = aOut;
channels = 2;
}
if (mOut.Channels() == 1) {
if (mIn.Format() == AudioConfig::FORMAT_FLT) {
const float* in = static_cast<const float*>(aIn);
float* out = static_cast<float*>(aOut);
- for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+ for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
float sample = 0.0;
// The sample of the buffer would be interleaved.
sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
*out++ = sample;
}
} else if (mIn.Format() == AudioConfig::FORMAT_S16) {
const int16_t* in = static_cast<const int16_t*>(aIn);
int16_t* out = static_cast<int16_t*>(aOut);
- for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+ for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
int32_t sample = 0.0;
// The sample of the buffer would be interleaved.
sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
*out++ = sample;
}
} else {
MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
}
}
- return frames * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels();
+ return aFrames;
}
-} // namespace mozilla
\ No newline at end of file
+size_t
+AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aFrames)
+{
+ if (!mResampler) {
+ return 0;
+ }
+ uint32_t outframes = ResampleRecipientFrames(aFrames);
+ uint32_t inframes = aFrames;
+
+ if (mOut.Format() == AudioConfig::FORMAT_FLT) {
+ const float* in = reinterpret_cast<const float*>(aIn);
+ float* out = reinterpret_cast<float*>(aOut);
+ speex_resampler_process_interleaved_float(mResampler, in, &inframes,
+ out, &outframes);
+ } else if (mOut.Format() == AudioConfig::FORMAT_S16) {
+ const int16_t* in = reinterpret_cast<const int16_t*>(aIn);
+ int16_t* out = reinterpret_cast<int16_t*>(aOut);
+ speex_resampler_process_interleaved_int(mResampler, in, &inframes,
+ out, &outframes);
+ } else {
+ MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
+ }
+ MOZ_ASSERT(inframes == aFrames, "Some frames will be dropped");
+ return outframes;
+}
+
+size_t
+AudioConverter::ResampleRecipientFrames(size_t aFrames) const
+{
+ return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
+}
+
+size_t
+AudioConverter::FramesOutToSamples(size_t aFrames) const
+{
+ return aFrames * mOut.Channels();
+}
+
+size_t
+AudioConverter::SamplesInToFrames(size_t aSamples) const
+{
+ return aSamples / mIn.Channels();
+}
+
+size_t
+AudioConverter::FramesOutToBytes(size_t aFrames) const
+{
+ return FramesOutToSamples(aFrames) * AudioConfig::SampleSize(mOut.Format());
+}
+} // namespace mozilla
--- a/dom/media/AudioConverter.h
+++ b/dom/media/AudioConverter.h
@@ -4,16 +4,19 @@
* 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/. */
#if !defined(AudioConverter_h)
#define AudioConverter_h
#include "MediaInfo.h"
+// Forward declaration
+typedef struct SpeexResamplerState_ SpeexResamplerState;
+
namespace mozilla {
template <AudioConfig::SampleFormat T> struct AudioDataBufferTypeChooser;
template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_U8>
{ typedef uint8_t Type; };
template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S16>
{ typedef int16_t Type; };
template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24LSB>
@@ -82,16 +85,26 @@ public:
"Conversion not implemented yet");
}
explicit AudioDataBuffer(const AlignedFloatBuffer&& aBuffer)
: mBuffer(Move(aBuffer))
{
static_assert(Format == AudioConfig::FORMAT_FLT,
"Conversion not implemented yet");
}
+ AudioDataBuffer& operator=(AudioDataBuffer&& aOther)
+ {
+ mBuffer = Move(aOther.mBuffer);
+ return *this;
+ }
+ AudioDataBuffer& operator=(const AudioDataBuffer& aOther)
+ {
+ mBuffer = aOther.mBuffer;
+ return *this;
+ }
Value* Data() const { return mBuffer.Data(); }
size_t Length() const { return mBuffer.Length(); }
size_t Size() const { return mBuffer.Size(); }
AlignedBuffer<Value> Forget()
{
// Correct type -> Just give values as-is.
return Move(mBuffer);
@@ -100,52 +113,117 @@ private:
AlignedBuffer<Value> mBuffer;
};
typedef AudioDataBuffer<AudioConfig::FORMAT_DEFAULT> AudioSampleBuffer;
class AudioConverter {
public:
AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut);
+ ~AudioConverter();
+
+ // Convert the AudioDataBuffer.
+ // Conversion will be done in place if possible. Otherwise a new buffer will
+ // be returned.
+ template <AudioConfig::SampleFormat Format, typename Value>
+ AudioDataBuffer<Format, Value> Process(AudioDataBuffer<Format, Value>&& aBuffer)
+ {
+ MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
+ AudioDataBuffer<Format, Value> buffer = Move(aBuffer);
+ if (CanWorkInPlace()) {
+ size_t frames = SamplesInToFrames(buffer.Length());
+ frames = ProcessInternal(buffer.Data(), buffer.Data(), frames);
+ if (frames && mIn.Rate() != mOut.Rate()) {
+ frames = ResampleAudio(buffer.Data(), buffer.Data(), frames);
+ }
+ AlignedBuffer<Value> temp = buffer.Forget();
+ temp.SetLength(FramesOutToSamples(frames));
+ return AudioDataBuffer<Format, Value>(Move(temp));;
+ }
+ return Process(buffer);
+ }
+
+ template <AudioConfig::SampleFormat Format, typename Value>
+ AudioDataBuffer<Format, Value> Process(const AudioDataBuffer<Format, Value>& aBuffer)
+ {
+ MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
+ // Perform the downmixing / reordering in temporary buffer.
+ size_t frames = SamplesInToFrames(aBuffer.Length());
+ AlignedBuffer<Value> temp1;
+ if (!temp1.SetLength(FramesOutToSamples(frames))) {
+ return AudioDataBuffer<Format, Value>(Move(temp1));
+ }
+ frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
+ if (!frames || mIn.Rate() == mOut.Rate()) {
+ temp1.SetLength(FramesOutToSamples(frames));
+ return AudioDataBuffer<Format, Value>(Move(temp1));
+ }
+
+ // At this point, temp1 contains the buffer reordered and downmixed.
+ // If we are downsampling we can re-use it.
+ AlignedBuffer<Value>* outputBuffer = &temp1;
+ AlignedBuffer<Value> temp2;
+ if (mOut.Rate() > mIn.Rate()) {
+ // We are upsampling, we can't work in place. Allocate another temporary
+ // buffer where the upsampling will occur.
+ temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)));
+ outputBuffer = &temp2;
+ }
+ frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
+ outputBuffer->SetLength(FramesOutToSamples(frames));
+ return AudioDataBuffer<Format, Value>(Move(*outputBuffer));
+ }
// Attempt to convert the AudioDataBuffer in place.
// Will return 0 if the conversion wasn't possible.
- // Process may allocate memory internally should intermediary steps be
- // required.
- template <AudioConfig::SampleFormat Type, typename Value>
- size_t Process(AudioDataBuffer<Type, Value>& aBuffer)
- {
- MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Type);
- return Process(aBuffer.Data(), aBuffer.Data(), aBuffer.Size());
- }
template <typename Value>
- size_t Process(Value* aBuffer, size_t aSamples)
+ size_t Process(Value* aBuffer, size_t aFrames)
{
MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format());
- return Process(aBuffer, aBuffer, aSamples * AudioConfig::SampleSize(mIn.Format()));
+ if (!CanWorkInPlace()) {
+ return 0;
+ }
+ size_t frames = ProcessInternal(aBuffer, aBuffer, aFrames);
+ if (frames && mIn.Rate() != mOut.Rate()) {
+ frames = ResampleAudio(aBuffer, aBuffer, aFrames);
+ }
+ return frames;
}
+
bool CanWorkInPlace() const;
bool CanReorderAudio() const
{
return mIn.Layout().MappingTable(mOut.Layout());
}
+ const AudioConfig& InputConfig() const { return mIn; }
+ const AudioConfig& OutputConfig() const { return mOut; }
+
private:
const AudioConfig mIn;
const AudioConfig mOut;
uint8_t mChannelOrderMap[MAX_AUDIO_CHANNELS];
/**
- * Process
+ * ProcessInternal
* Parameters:
* aOut : destination buffer where converted samples will be copied
* aIn : source buffer
- * aBytes: size in bytes of source buffer
+ * aSamples: number of frames in source buffer
*
- * Return Value: size in bytes of samples converted or 0 if error
+ * Return Value: number of frames converted or 0 if error
*/
- size_t Process(void* aOut, const void* aIn, size_t aBytes);
- void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aDataSize) const;
- size_t DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const;
+ size_t ProcessInternal(void* aOut, const void* aIn, size_t aFrames);
+ void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aFrames) const;
+ size_t DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
+
+ size_t FramesOutToSamples(size_t aFrames) const;
+ size_t SamplesInToFrames(size_t aSamples) const;
+ size_t FramesOutToBytes(size_t aFrames) const;
+
+ // Resampler context.
+ SpeexResamplerState* mResampler;
+ size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
+ size_t ResampleRecipientFrames(size_t aFrames) const;
};
} // namespace mozilla
#endif /* AudioConverter_h */
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -326,17 +326,17 @@ AudioStream::Init(uint32_t aNumChannels,
if (!CubebUtils::GetCubebContext()) {
return NS_ERROR_FAILURE;
}
MOZ_LOG(gAudioStreamLog, LogLevel::Debug,
("%s channels: %d, rate: %d for %p", __FUNCTION__, aNumChannels, aRate, this));
mInRate = mOutRate = aRate;
mChannels = aNumChannels;
- mOutChannels = (aNumChannels > 2) ? 2 : aNumChannels;
+ mOutChannels = mIsMonoAudioEnabled ? 1 : aNumChannels;
mDumpFile = OpenDumpFile(this);
cubeb_stream_params params;
params.rate = aRate;
params.channels = mOutChannels;
#if defined(__ANDROID__)
#if defined(MOZ_B2G)
@@ -348,19 +348,21 @@ AudioStream::Init(uint32_t aNumChannels,
if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
return NS_ERROR_INVALID_ARG;
}
#endif
params.format = ToCubebFormat<AUDIO_OUTPUT_FORMAT>::value;
mAudioClock.Init();
- AudioConfig inConfig(mChannels, mInRate);
- AudioConfig outConfig(mOutChannels, mOutRate);
- mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
+ if (mIsMonoAudioEnabled) {
+ AudioConfig inConfig(mChannels, mInRate);
+ AudioConfig outConfig(mOutChannels, mOutRate);
+ mAudioConverter = MakeUnique<AudioConverter>(inConfig, outConfig);
+ }
return OpenCubeb(params);
}
// This code used to live inside AudioStream::Init(), but on Mac (others?)
// it has been known to take 300-800 (or even 8500) ms to execute(!)
nsresult
AudioStream::OpenCubeb(cubeb_stream_params &aParams)
{
@@ -556,24 +558,18 @@ AudioStream::Downmix(Chunk* aChunk)
LOGW("mismatched sample %u, mInRate=%u", aChunk->Rate(), mInRate);
return false;
}
if (aChunk->Channels() > 8) {
return false;
}
- if (aChunk->Channels() > 2) {
- MOZ_ASSERT(mAudioConverter);
- mAudioConverter->Process(aChunk->GetWritable(),
- aChunk->Channels() * aChunk->Frames());
- }
-
- if (aChunk->Channels() >= 2 && mIsMonoAudioEnabled) {
- DownmixStereoToMono(aChunk->GetWritable(), aChunk->Frames());
+ if (mAudioConverter) {
+ mAudioConverter->Process(aChunk->GetWritable(), aChunk->Frames());
}
return true;
}
void
AudioStream::GetUnprocessed(AudioBufferWriter& aWriter)
{
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -599,16 +599,26 @@ public:
SampleFormat Format() const
{
return mFormat;
}
bool Interleaved() const
{
return mInterleaved;
}
+ bool operator==(const AudioConfig& aOther) const
+ {
+ return mChannelLayout == aOther.mChannelLayout &&
+ mRate == aOther.mRate && mFormat == aOther.mFormat &&
+ mInterleaved == aOther.mInterleaved;
+ }
+ bool operator!=(const AudioConfig& aOther) const
+ {
+ return !(*this == aOther);
+ }
static const char* FormatToString(SampleFormat aFormat);
static uint32_t SampleSize(SampleFormat aFormat);
static uint32_t FormatToBits(SampleFormat aFormat);
private:
// Channels configuration.
ChannelLayout mChannelLayout;
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -29,20 +29,16 @@
#include "GMPUtils.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDirectoryServiceDefs.h"
#include "nsXULAppAPI.h"
#include "gmp-audio-decode.h"
#include "gmp-video-decode.h"
-#if defined(XP_WIN) || defined(XP_MACOSX)
-#define PRIMETIME_EME_SUPPORTED 1
-#endif
-
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess,
mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeySystemAccess)
@@ -275,17 +271,17 @@ MediaKeySystemAccess::GetKeySystemStatus
if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
if (!Preferences::GetBool("media.eme.clearkey.enabled", true)) {
aOutMessage = NS_LITERAL_CSTRING("ClearKey was disabled");
return MediaKeySystemStatus::Cdm_disabled;
}
return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
}
-#ifdef PRIMETIME_EME_SUPPORTED
+#ifdef MOZ_ADOBE_EME
if (aKeySystem.EqualsLiteral("com.adobe.primetime")) {
if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
aOutMessage = NS_LITERAL_CSTRING("Adobe EME disabled");
return MediaKeySystemStatus::Cdm_disabled;
}
#ifdef XP_WIN
// Win Vista and later only.
if (!IsVistaOrLater()) {
--- a/dom/media/mediasink/DecodedAudioDataSink.cpp
+++ b/dom/media/mediasink/DecodedAudioDataSink.cpp
@@ -3,19 +3,21 @@
/* 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 "nsPrintfCString.h"
#include "MediaQueue.h"
#include "DecodedAudioDataSink.h"
#include "VideoUtils.h"
+#include "AudioConverter.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
+#include "gfxPrefs.h"
namespace mozilla {
extern LazyLogModule gMediaDecoderLog;
#define SINK_LOG(msg, ...) \
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, \
("DecodedAudioDataSink=%p " msg, this, ##__VA_ARGS__))
#define SINK_LOG_V(msg, ...) \
@@ -35,16 +37,24 @@ DecodedAudioDataSink::DecodedAudioDataSi
, mStartTime(aStartTime)
, mWritten(0)
, mLastGoodPosition(0)
, mInfo(aInfo)
, mChannel(aChannel)
, mPlaying(true)
, mPlaybackComplete(false)
{
+ bool resampling = gfxPrefs::AudioSinkResampling();
+ uint32_t resamplingRate = gfxPrefs::AudioSinkResampleRate();
+ mConverter =
+ MakeUnique<AudioConverter>(
+ AudioConfig(mInfo.mChannels, mInfo.mRate),
+ AudioConfig(mInfo.mChannels > 2 && gfxPrefs::AudioSinkForceStereo()
+ ? 2 : mInfo.mChannels,
+ resampling ? resamplingRate : mInfo.mRate));
}
DecodedAudioDataSink::~DecodedAudioDataSink()
{
}
RefPtr<GenericPromise>
DecodedAudioDataSink::Init(const PlaybackParams& aParams)
@@ -131,17 +141,19 @@ DecodedAudioDataSink::SetPlaying(bool aP
}
mPlaying = aPlaying;
}
nsresult
DecodedAudioDataSink::InitializeAudioStream(const PlaybackParams& aParams)
{
mAudioStream = new AudioStream(*this);
- nsresult rv = mAudioStream->Init(mInfo.mChannels, mInfo.mRate, mChannel);
+ nsresult rv = mAudioStream->Init(mConverter->OutputConfig().Channels(),
+ mConverter->OutputConfig().Rate(),
+ mChannel);
if (NS_FAILED(rv)) {
mAudioStream->Shutdown();
mAudioStream = nullptr;
return rv;
}
// Set playback params before calling Start() so they can take effect
// as soon as the 1st DataCallback of the AudioStream fires.
@@ -151,17 +163,18 @@ DecodedAudioDataSink::InitializeAudioStr
mAudioStream->Start();
return NS_OK;
}
int64_t
DecodedAudioDataSink::GetEndTime() const
{
- CheckedInt64 playedUsecs = FramesToUsecs(mWritten, mInfo.mRate) + mStartTime;
+ CheckedInt64 playedUsecs =
+ FramesToUsecs(mWritten, mConverter->OutputConfig().Rate()) + mStartTime;
if (!playedUsecs.isValid()) {
NS_WARNING("Int overflow calculating audio end time");
return -1;
}
return playedUsecs.value();
}
UniquePtr<AudioStream::Chunk>
@@ -226,40 +239,61 @@ DecodedAudioDataSink::PopFrames(uint32_t
RefPtr<MediaData> releaseMe = AudioQueue().PopFront();
continue;
}
// See if there's a gap in the audio. If there is, push silence into the
// audio hardware, so we can play across the gap.
// Calculate the timestamp of the next chunk of audio in numbers of
// samples.
- CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime, mInfo.mRate);
+ CheckedInt64 sampleTime = UsecsToFrames(AudioQueue().PeekFront()->mTime,
+ mConverter->OutputConfig().Rate());
// Calculate the number of frames that have been pushed onto the audio hardware.
- CheckedInt64 playedFrames = UsecsToFrames(mStartTime, mInfo.mRate) +
+ CheckedInt64 playedFrames = UsecsToFrames(mStartTime,
+ mConverter->OutputConfig().Rate()) +
static_cast<int64_t>(mWritten);
CheckedInt64 missingFrames = sampleTime - playedFrames;
if (!missingFrames.isValid() || !sampleTime.isValid()) {
NS_WARNING("Int overflow in DecodedAudioDataSink");
mErrored = true;
return MakeUnique<Chunk>();
}
+ const uint32_t rate = mConverter->OutputConfig().Rate();
+ const uint32_t channels = mConverter->OutputConfig().Channels();
+
if (missingFrames.value() > AUDIO_FUZZ_FRAMES) {
// The next audio chunk begins some time after the end of the last chunk
// we pushed to the audio hardware. We must push silence into the audio
// hardware so that the next audio chunk begins playback at the correct
// time.
missingFrames = std::min<int64_t>(UINT32_MAX, missingFrames.value());
auto framesToPop = std::min<uint32_t>(missingFrames.value(), aFrames);
mWritten += framesToPop;
- return MakeUnique<SilentChunk>(framesToPop, mInfo.mChannels, mInfo.mRate);
+ return MakeUnique<SilentChunk>(framesToPop, channels, rate);
}
- mCurrentData = dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
+ RefPtr<AudioData> data =
+ dont_AddRef(AudioQueue().PopFront().take()->As<AudioData>());
+ if (mConverter->InputConfig() != mConverter->OutputConfig()) {
+ AlignedAudioBuffer convertedData =
+ mConverter->Process(AudioSampleBuffer(Move(data->mAudioData))).Forget();
+ mCurrentData =
+ new AudioData(data->mOffset,
+ data->mTime,
+ data->mDuration,
+ convertedData.Length() / channels,
+ Move(convertedData),
+ channels,
+ rate);
+ } else {
+ mCurrentData = Move(data);
+ }
+
mCursor = MakeUnique<AudioBufferCursor>(mCurrentData->mAudioData.get(),
mCurrentData->mChannels,
mCurrentData->mFrames);
MOZ_ASSERT(mCurrentData->mFrames > 0);
}
auto framesToPop = std::min(aFrames, mCursor->Available());
--- a/dom/media/mediasink/DecodedAudioDataSink.h
+++ b/dom/media/mediasink/DecodedAudioDataSink.h
@@ -16,16 +16,18 @@
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/Atomics.h"
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
#include "mozilla/ReentrantMonitor.h"
namespace mozilla {
+class AudioConverter;
+
namespace media {
class DecodedAudioDataSink : public AudioSink,
private AudioStream::DataSource {
public:
DecodedAudioDataSink(MediaQueue<MediaData>& aAudioQueue,
int64_t aStartTime,
const AudioInfo& aInfo,
@@ -92,21 +94,23 @@ private:
MozPromiseHolder<GenericPromise> mEndPromise;
/*
* Members to implement AudioStream::DataSource.
* Used on the callback thread of cubeb.
*/
// The AudioData at which AudioStream::DataSource is reading.
RefPtr<AudioData> mCurrentData;
- // Keep track of the read positoin of mCurrentData.
+ // Keep track of the read position of mCurrentData.
UniquePtr<AudioBufferCursor> mCursor;
// True if there is any error in processing audio data like overflow.
bool mErrored = false;
// Set on the callback thread of cubeb once the stream has drained.
Atomic<bool> mPlaybackComplete;
+
+ UniquePtr<AudioConverter> mConverter;
};
} // namespace media
} // namespace mozilla
#endif
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -222,17 +222,17 @@ VorbisDataDecoder::DoDecode(MediaRawData
if (!mAudioConverter) {
AudioConfig in(AudioConfig::ChannelLayout(channels, VorbisLayout(channels)),
rate);
AudioConfig out(channels, rate);
mAudioConverter = MakeUnique<AudioConverter>(in, out);
}
MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
AudioSampleBuffer data(Move(buffer));
- mAudioConverter->Process(data);
+ data = mAudioConverter->Process(Move(data));
aTotalFrames += frames;
mCallback->Output(new AudioData(aOffset,
time.value(),
duration.value(),
frames,
data.Forget(),
channels,
--- a/dom/media/platforms/apple/AppleATDecoder.cpp
+++ b/dom/media/platforms/apple/AppleATDecoder.cpp
@@ -282,17 +282,17 @@ AppleATDecoder::DecodeSample(MediaRawDat
}
if (mChannelLayout && !mAudioConverter) {
AudioConfig in(*mChannelLayout.get(), rate);
AudioConfig out(channels, rate);
mAudioConverter = MakeUnique<AudioConverter>(in, out);
}
if (mAudioConverter) {
MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
- mAudioConverter->Process(data);
+ data = mAudioConverter->Process(Move(data));
}
RefPtr<AudioData> audio = new AudioData(aSample->mOffset,
aSample->mTime,
duration.ToMicroseconds(),
numFrames,
data.Forget(),
channels,
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -760,16 +760,17 @@ skip-if = appname == "seamonkey"
skip-if = toolkit == 'gonk' # bug 1128845
[test_playback_rate.html]
[test_playback_rate_playpause.html]
[test_playback_reactivate.html]
[test_played.html]
[test_preload_actions.html]
[test_preload_attribute.html]
[test_preload_suspend.html]
+[test_preserve_playbackrate_after_ui_play.html]
[test_progress.html]
[test_reactivate.html]
skip-if = toolkit == 'gonk' # bug 1128845 on gonk
[test_readyState.html]
[test_referer.html]
[test_replay_metadata.html]
[test_reset_events_async.html]
[test_reset_src.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/test/test_preserve_playbackrate_after_ui_play.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title> Bug 1013933 - preserve playbackRate after clicking play button </title>
+ <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+ <script type="application/javascript" src="browserElementTestHelpers.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<div id="content">
+ <video width="320" height="240" id="video" controls mozNoDynamicControls preload="auto"></video>
+</div>
+
+<script type="text/javascript">
+/*
+ * Positions of the UI elements, relative to the upper-left corner of the
+ * <video> box.
+ */
+const videoHeight = 240;
+const playButtonWidth = 28;
+const playButtonHeight = 28;
+const playButtonCenterX = 0 + Math.round(playButtonWidth / 2);
+const playButtonCenterY = videoHeight - Math.round(playButtonHeight / 2);
+
+var expectedPlaybackRate = 0.5
+
+function runTest() {
+ var video = document.getElementById("video");
+ video.src = "audio.wav";
+ video.loop = true;
+ video.playbackRate = expectedPlaybackRate;
+
+ video.oncanplaythrough = function() {
+ video.oncanplaythrough = null;
+ is(video.paused, true, "video is not playing yet.");
+ is(video.playbackRate, expectedPlaybackRate,
+ "playbackRate is correct before clicking play button.");
+
+ // Click the play button
+ synthesizeMouse(video, playButtonCenterX, playButtonCenterY, { });
+ };
+
+ video.onplay = function() {
+ video.onplay = null;
+ is(video.paused, false, "video starts playing.");
+ is(video.playbackRate, expectedPlaybackRate,
+ "playbackRate is correct after clicking play button.");
+ video.pause();
+ SimpleTest.finish();
+ };
+}
+
+window.addEventListener("load", runTest, false);
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>
--- a/dom/media/wave/WaveDemuxer.cpp
+++ b/dom/media/wave/WaveDemuxer.cpp
@@ -623,18 +623,16 @@ WAVTrackDemuxer::Read(uint8_t* aBuffer,
return static_cast<int32_t>(read);
}
// RIFFParser
uint32_t
RIFFParser::Parse(ByteReader& aReader)
{
- MOZ_ASSERT(&aReader);
-
while (aReader.CanRead8() && !mRiffHeader.ParseNext(aReader.ReadU8())) { }
if (mRiffHeader.IsValid()) {
return RIFF_CHUNK_SIZE;
}
return 0;
}
@@ -779,18 +777,16 @@ HeaderParser::ChunkHeader::Update(uint8_
}
}
// FormatParser
uint32_t
FormatParser::Parse(ByteReader& aReader)
{
- MOZ_ASSERT(&aReader);
-
while (aReader.CanRead8() && !mFmtChunk.ParseNext(aReader.ReadU8())) { }
if (mFmtChunk.IsValid()) {
return FMT_CHUNK_MIN_SIZE;
}
return 0;
}
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AlignmentUtils.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 AlignmentUtils_h__
+#define AlignmentUtils_h__
+
+#define IS_ALIGNED16(ptr) ((((uintptr_t)ptr + 15) & ~0x0F) == (uintptr_t)ptr)
+
+#ifdef DEBUG
+ #define ASSERT_ALIGNED16(ptr) \
+ MOZ_ASSERT(IS_ALIGNED16(ptr), \
+ #ptr " has to be aligned to a 16 byte boundary");
+#else
+ #define ASSERT_ALIGNED16(ptr)
+#endif
+
+#ifdef DEBUG
+ #define ASSERT_MULTIPLE16(v) \
+ MOZ_ASSERT(v % 16 == 0, #v " has to be a a multiple of 16");
+#else
+ #define ASSERT_MULTIPLE16(v)
+#endif
+
+#define ALIGNED16(ptr) (float*)(((uintptr_t)ptr + 15) & ~0x0F);
+
+#endif
--- a/dom/media/webaudio/AudioBlock.cpp
+++ b/dom/media/webaudio/AudioBlock.cpp
@@ -1,50 +1,53 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "AudioBlock.h"
+#include "AlignmentUtils.h"
namespace mozilla {
/**
* Heap-allocated buffer of channels of 128-sample float arrays, with
* threadsafe refcounting. Typically you would allocate one of these, fill it
* in, and then treat it as immutable while it's shared.
*
* Downstream references are accounted specially so that the creator of the
* buffer can reuse and modify its contents next iteration if other references
* are all downstream temporary references held by AudioBlock.
*
- * This only guarantees 4-byte alignment of the data. For alignment we simply
- * assume that the memory from malloc is at least 4-byte aligned and that
- * AudioBlockBuffer's size is divisible by 4.
+ * We guarantee 16 byte alignment of the channel data.
*/
class AudioBlockBuffer final : public ThreadSharedObject {
public:
virtual AudioBlockBuffer* AsAudioBlockBuffer() override { return this; };
float* ChannelData(uint32_t aChannel)
{
- return reinterpret_cast<float*>(this + 1) + aChannel * WEBAUDIO_BLOCK_SIZE;
+ float* base = reinterpret_cast<float*>(((uintptr_t)(this + 1) + 15) & ~0x0F);
+ ASSERT_ALIGNED16(base);
+ return base + aChannel * WEBAUDIO_BLOCK_SIZE;
}
static already_AddRefed<AudioBlockBuffer> Create(uint32_t aChannelCount)
{
CheckedInt<size_t> size = WEBAUDIO_BLOCK_SIZE;
size *= aChannelCount;
size *= sizeof(float);
size += sizeof(AudioBlockBuffer);
+ size += 15; //padding for alignment
if (!size.isValid()) {
MOZ_CRASH();
}
+
void* m = moz_xmalloc(size.value());
RefPtr<AudioBlockBuffer> p = new (m) AudioBlockBuffer();
NS_ASSERTION((reinterpret_cast<char*>(p.get() + 1) - reinterpret_cast<char*>(p.get())) % 4 == 0,
"AudioBlockBuffers should be at least 4-byte aligned");
return p.forget();
}
// Graph thread only.
@@ -145,18 +148,16 @@ AudioBlock::AllocateChannels(uint32_t aC
if (buffer && !buffer->HasLastingShares()) {
MOZ_ASSERT(mBufferFormat == AUDIO_FORMAT_FLOAT32);
// No need to allocate again.
mVolume = 1.0f;
return;
}
}
- // XXX for SIMD purposes we should do something here to make sure the
- // channel buffers are 16-byte aligned.
RefPtr<AudioBlockBuffer> buffer = AudioBlockBuffer::Create(aChannelCount);
mChannelData.SetLength(aChannelCount);
for (uint32_t i = 0; i < aChannelCount; ++i) {
mChannelData[i] = buffer->ChannelData(i);
}
mBuffer = buffer.forget();
mVolume = 1.0f;
mBufferFormat = AUDIO_FORMAT_FLOAT32;
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -1,15 +1,16 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "AudioDestinationNode.h"
+#include "AlignmentUtils.h"
#include "AudioContext.h"
#include "mozilla/dom/AudioDestinationNodeBinding.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "AudioChannelAgent.h"
#include "AudioChannelService.h"
#include "AudioNodeEngine.h"
@@ -82,17 +83,17 @@ public:
const uint32_t duration = std::min(WEBAUDIO_BLOCK_SIZE, mLength - mWriteIndex);
const uint32_t inputChannelCount = aInput.ChannelCount();
for (uint32_t i = 0; i < outputChannelCount; ++i) {
float* outputData = mBuffer->GetDataForWrite(i) + mWriteIndex;
if (aInput.IsNull() || i >= inputChannelCount) {
PodZero(outputData, duration);
} else {
const float* inputBuffer = static_cast<const float*>(aInput.mChannelData[i]);
- if (duration == WEBAUDIO_BLOCK_SIZE) {
+ if (duration == WEBAUDIO_BLOCK_SIZE && IS_ALIGNED16(inputBuffer)) {
// Use the optimized version of the copy with scale operation
AudioBlockCopyChannelWithScale(inputBuffer, aInput.mVolume,
outputData);
} else {
if (aInput.mVolume == 1.0f) {
PodCopy(outputData, inputBuffer, duration);
} else {
for (uint32_t j = 0; j < duration; ++j) {
--- a/dom/media/webaudio/AudioNodeEngine.cpp
+++ b/dom/media/webaudio/AudioNodeEngine.cpp
@@ -4,16 +4,19 @@
* 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 "AudioNodeEngine.h"
#ifdef BUILD_ARM_NEON
#include "mozilla/arm.h"
#include "AudioNodeEngineNEON.h"
#endif
+#ifdef USE_SSE2
+#include "AudioNodeEngineSSE2.h"
+#endif
namespace mozilla {
already_AddRefed<ThreadSharedFloatArrayBufferList>
ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount,
size_t aLength,
const mozilla::fallible_t&)
{
@@ -66,16 +69,24 @@ void AudioBufferAddWithScale(const float
uint32_t aSize)
{
#ifdef BUILD_ARM_NEON
if (mozilla::supports_neon()) {
AudioBufferAddWithScale_NEON(aInput, aScale, aOutput, aSize);
return;
}
#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ AudioBufferAddWithScale_SSE(aInput, aScale, aOutput, aSize);
+ return;
+ }
+#endif
+
if (aScale == 1.0f) {
for (uint32_t i = 0; i < aSize; ++i) {
aOutput[i] += aInput[i];
}
} else {
for (uint32_t i = 0; i < aSize; ++i) {
aOutput[i] += aInput[i]*aScale;
}
@@ -99,28 +110,44 @@ AudioBlockCopyChannelWithScale(const flo
memcpy(aOutput, aInput, WEBAUDIO_BLOCK_SIZE*sizeof(float));
} else {
#ifdef BUILD_ARM_NEON
if (mozilla::supports_neon()) {
AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
return;
}
#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ AudioBlockCopyChannelWithScale_SSE(aInput, aScale, aOutput);
+ return;
+ }
+#endif
+
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
aOutput[i] = aInput[i]*aScale;
}
}
}
void
BufferComplexMultiply(const float* aInput,
const float* aScale,
float* aOutput,
uint32_t aSize)
{
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse()) {
+ BufferComplexMultiply_SSE(aInput, aScale, aOutput, aSize);
+ return;
+ }
+#endif
+
for (uint32_t i = 0; i < aSize * 2; i += 2) {
float real1 = aInput[i];
float imag1 = aInput[i + 1];
float real2 = aScale[i];
float imag2 = aScale[i + 1];
float realResult = real1 * real2 - imag1 * imag2;
float imagResult = real1 * imag2 + imag1 * real2;
aOutput[i] = realResult;
@@ -147,16 +174,24 @@ AudioBlockCopyChannelWithScale(const flo
float aOutput[WEBAUDIO_BLOCK_SIZE])
{
#ifdef BUILD_ARM_NEON
if (mozilla::supports_neon()) {
AudioBlockCopyChannelWithScale_NEON(aInput, aScale, aOutput);
return;
}
#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ AudioBlockCopyChannelWithScale_SSE(aInput, aScale, aOutput);
+ return;
+ }
+#endif
+
for (uint32_t i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
aOutput[i] = aInput[i]*aScale[i];
}
}
void
AudioBlockInPlaceScale(float aBlock[WEBAUDIO_BLOCK_SIZE],
float aScale)
@@ -173,16 +208,24 @@ AudioBufferInPlaceScale(float* aBlock,
return;
}
#ifdef BUILD_ARM_NEON
if (mozilla::supports_neon()) {
AudioBufferInPlaceScale_NEON(aBlock, aScale, aSize);
return;
}
#endif
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ AudioBufferInPlaceScale_SSE(aBlock, aScale, aSize);
+ return;
+ }
+#endif
+
for (uint32_t i = 0; i < aSize; ++i) {
*aBlock++ *= aScale;
}
}
void
AudioBlockPanMonoToStereo(const float aInput[WEBAUDIO_BLOCK_SIZE],
float aGainL[WEBAUDIO_BLOCK_SIZE],
@@ -215,16 +258,25 @@ AudioBlockPanStereoToStereo(const float
if (mozilla::supports_neon()) {
AudioBlockPanStereoToStereo_NEON(aInputL, aInputR,
aGainL, aGainR, aIsOnTheLeft,
aOutputL, aOutputR);
return;
}
#endif
+#ifdef USE_SSE2
+ if (mozilla::supports_sse2()) {
+ AudioBlockPanStereoToStereo_SSE(aInputL, aInputR,
+ aGainL, aGainR, aIsOnTheLeft,
+ aOutputL, aOutputR);
+ return;
+ }
+#endif
+
uint32_t i;
if (aIsOnTheLeft) {
for (i = 0; i < WEBAUDIO_BLOCK_SIZE; ++i) {
aOutputL[i] = aInputL[i] + aInputR[i] * aGainL;
aOutputR[i] = aInputR[i] * aGainR;
}
} else {
@@ -264,16 +316,37 @@ AudioBlockPanStereoToStereo(const float
}
}
}
float
AudioBufferSumOfSquares(const float* aInput, uint32_t aLength)
{
float sum = 0.0f;
+
+#ifdef USE_SSE2
+ if (mozilla::supports_sse()) {
+ const float* alignedInput = ALIGNED16(aInput);
+ float vLength = (aLength >> 4) << 4;
+
+ // use scalar operations for any unaligned data at the beginning
+ while (aInput != alignedInput) {
+ sum += *aInput * *aInput;
+ ++aInput;
+ }
+
+ sum += AudioBufferSumOfSquares_SSE(alignedInput, vLength);
+
+ // adjust aInput and aLength to use scalar operations for any
+ // remaining values
+ aInput = alignedInput + 1;
+ aLength -= vLength;
+ }
+#endif
+
while (aLength--) {
sum += *aInput * *aInput;
++aInput;
}
return sum;
}
void
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AudioNodeEngineSSE2.cpp
@@ -0,0 +1,315 @@
+/* -*- 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 "AlignmentUtils.h"
+#include "AudioNodeEngineSSE2.h"
+#include <emmintrin.h>
+
+
+namespace mozilla {
+void
+AudioBufferAddWithScale_SSE(const float* aInput,
+ float aScale,
+ float* aOutput,
+ uint32_t aSize)
+{
+ __m128 vin0, vin1, vin2, vin3,
+ vscaled0, vscaled1, vscaled2, vscaled3,
+ vout0, vout1, vout2, vout3,
+ vgain;
+
+ ASSERT_ALIGNED16(aInput);
+ ASSERT_ALIGNED16(aOutput);
+ ASSERT_MULTIPLE16(aSize);
+
+ vgain = _mm_load1_ps(&aScale);
+
+ for (unsigned i = 0; i < aSize; i+=16) {
+ vin0 = _mm_load_ps(&aInput[i]);
+ vin1 = _mm_load_ps(&aInput[i + 4]);
+ vin2 = _mm_load_ps(&aInput[i + 8]);
+ vin3 = _mm_load_ps(&aInput[i + 12]);
+
+ vscaled0 = _mm_mul_ps(vin0, vgain);
+ vscaled1 = _mm_mul_ps(vin1, vgain);
+ vscaled2 = _mm_mul_ps(vin2, vgain);
+ vscaled3 = _mm_mul_ps(vin3, vgain);
+
+ vin0 = _mm_load_ps(&aOutput[i]);
+ vin1 = _mm_load_ps(&aOutput[i + 4]);
+ vin2 = _mm_load_ps(&aOutput[i + 8]);
+ vin3 = _mm_load_ps(&aOutput[i + 12]);
+
+ vout0 = _mm_add_ps(vin0, vscaled0);
+ vout1 = _mm_add_ps(vin1, vscaled1);
+ vout2 = _mm_add_ps(vin2, vscaled2);
+ vout3 = _mm_add_ps(vin3, vscaled3);
+
+ _mm_store_ps(&aOutput[i], vout0);
+ _mm_store_ps(&aOutput[i + 4], vout1);
+ _mm_store_ps(&aOutput[i + 8], vout2);
+ _mm_store_ps(&aOutput[i + 12], vout3);
+ }
+}
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float* aInput,
+ float aScale,
+ float* aOutput)
+{
+ __m128 vin0, vin1, vin2, vin3,
+ vout0, vout1, vout2, vout3;
+
+ ASSERT_ALIGNED16(aInput);
+ ASSERT_ALIGNED16(aOutput);
+
+ __m128 vgain = _mm_load1_ps(&aScale);
+
+ for (unsigned i = 0 ; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
+ vin0 = _mm_load_ps(&aInput[i]);
+ vin1 = _mm_load_ps(&aInput[i + 4]);
+ vin2 = _mm_load_ps(&aInput[i + 8]);
+ vin3 = _mm_load_ps(&aInput[i + 12]);
+ vout0 = _mm_mul_ps(vin0, vgain);
+ vout1 = _mm_mul_ps(vin1, vgain);
+ vout2 = _mm_mul_ps(vin2, vgain);
+ vout3 = _mm_mul_ps(vin3, vgain);
+ _mm_store_ps(&aOutput[i], vout0);
+ _mm_store_ps(&aOutput[i + 4], vout1);
+ _mm_store_ps(&aOutput[i + 8], vout2);
+ _mm_store_ps(&aOutput[i + 12], vout3);
+ }
+}
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float aInput[WEBAUDIO_BLOCK_SIZE],
+ const float aScale[WEBAUDIO_BLOCK_SIZE],
+ float aOutput[WEBAUDIO_BLOCK_SIZE])
+{
+ __m128 vin0, vin1, vin2, vin3,
+ vscaled0, vscaled1, vscaled2, vscaled3,
+ vout0, vout1, vout2, vout3;
+
+ ASSERT_ALIGNED16(aInput);
+ ASSERT_ALIGNED16(aScale);
+ ASSERT_ALIGNED16(aOutput);
+
+ for (unsigned i = 0 ; i < WEBAUDIO_BLOCK_SIZE; i+=16) {
+ vscaled0 = _mm_load_ps(&aScale[i]);
+ vscaled1 = _mm_load_ps(&aScale[i+4]);
+ vscaled2 = _mm_load_ps(&aScale[i+8]);
+ vscaled3 = _mm_load_ps(&aScale[i+12]);
+
+ vin0 = _mm_load_ps(&aInput[i]);
+ vin1 = _mm_load_ps(&aInput[i + 4]);
+ vin2 = _mm_load_ps(&aInput[i + 8]);
+ vin3 = _mm_load_ps(&aInput[i + 12]);
+
+ vout0 = _mm_mul_ps(vin0, vscaled0);
+ vout1 = _mm_mul_ps(vin1, vscaled1);
+ vout2 = _mm_mul_ps(vin2, vscaled2);
+ vout3 = _mm_mul_ps(vin3, vscaled3);
+
+ _mm_store_ps(&aOutput[i], vout0);
+ _mm_store_ps(&aOutput[i + 4], vout1);
+ _mm_store_ps(&aOutput[i + 8], vout2);
+ _mm_store_ps(&aOutput[i + 12], vout3);
+ }
+}
+
+void
+AudioBufferInPlaceScale_SSE(float* aBlock,
+ float aScale,
+ uint32_t aSize)
+{
+ __m128 vout0, vout1, vout2, vout3,
+ vin0, vin1, vin2, vin3;
+
+ ASSERT_ALIGNED16(aBlock);
+ ASSERT_MULTIPLE16(aSize);
+
+ __m128 vgain = _mm_load1_ps(&aScale);
+
+ for (unsigned i = 0; i < aSize; i+=16) {
+ vin0 = _mm_load_ps(&aBlock[i]);
+ vin1 = _mm_load_ps(&aBlock[i + 4]);
+ vin2 = _mm_load_ps(&aBlock[i + 8]);
+ vin3 = _mm_load_ps(&aBlock[i + 12]);
+ vout0 = _mm_mul_ps(vin0, vgain);
+ vout1 = _mm_mul_ps(vin1, vgain);
+ vout2 = _mm_mul_ps(vin2, vgain);
+ vout3 = _mm_mul_ps(vin3, vgain);
+ _mm_store_ps(&aBlock[i], vout0);
+ _mm_store_ps(&aBlock[i + 4], vout1);
+ _mm_store_ps(&aBlock[i + 8], vout2);
+ _mm_store_ps(&aBlock[i + 12], vout3);
+ }
+}
+
+void
+AudioBlockPanStereoToStereo_SSE(const float aInputL[WEBAUDIO_BLOCK_SIZE],
+ const float aInputR[WEBAUDIO_BLOCK_SIZE],
+ float aGainL, float aGainR, bool aIsOnTheLeft,
+ float aOutputL[WEBAUDIO_BLOCK_SIZE],
+ float aOutputR[WEBAUDIO_BLOCK_SIZE])
+{
+ __m128 vinl0, vinr0, vinl1, vinr1,
+ vout0, vout1,
+ vscaled0, vscaled1,
+ vgainl, vgainr;
+
+ ASSERT_ALIGNED16(aInputL);
+ ASSERT_ALIGNED16(aInputR);
+ ASSERT_ALIGNED16(aOutputL);
+ ASSERT_ALIGNED16(aOutputR);
+
+ vgainl = _mm_load1_ps(&aGainL);
+ vgainr = _mm_load1_ps(&aGainR);
+
+ if (aIsOnTheLeft) {
+ for (unsigned i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=8) {
+ vinl0 = _mm_load_ps(&aInputL[i]);
+ vinr0 = _mm_load_ps(&aInputR[i]);
+ vinl1 = _mm_load_ps(&aInputL[i+4]);
+ vinr1 = _mm_load_ps(&aInputR[i+4]);
+
+ /* left channel : aOutputL = aInputL + aInputR * gainL */
+ vscaled0 = _mm_mul_ps(vinr0, vgainl);
+ vscaled1 = _mm_mul_ps(vinr1, vgainl);
+ vout0 = _mm_add_ps(vscaled0, vinl0);
+ vout1 = _mm_add_ps(vscaled1, vinl1);
+ _mm_store_ps(&aOutputL[i], vout0);
+ _mm_store_ps(&aOutputL[i+4], vout1);
+
+ /* right channel : aOutputR = aInputR * gainR */
+ vscaled0 = _mm_mul_ps(vinr0, vgainr);
+ vscaled1 = _mm_mul_ps(vinr1, vgainr);
+ _mm_store_ps(&aOutputR[i], vscaled0);
+ _mm_store_ps(&aOutputR[i+4], vscaled1);
+ }
+ } else {
+ for (unsigned i = 0; i < WEBAUDIO_BLOCK_SIZE; i+=8) {
+ vinl0 = _mm_load_ps(&aInputL[i]);
+ vinr0 = _mm_load_ps(&aInputR[i]);
+ vinl1 = _mm_load_ps(&aInputL[i+4]);
+ vinr1 = _mm_load_ps(&aInputR[i+4]);
+
+ /* left channel : aInputL * gainL */
+ vscaled0 = _mm_mul_ps(vinl0, vgainl);
+ vscaled1 = _mm_mul_ps(vinl1, vgainl);
+ _mm_store_ps(&aOutputL[i], vscaled0);
+ _mm_store_ps(&aOutputL[i+4], vscaled1);
+
+ /* right channel: aOutputR = aInputR + aInputL * gainR */
+ vscaled0 = _mm_mul_ps(vinl0, vgainr);
+ vscaled1 = _mm_mul_ps(vinl1, vgainr);
+ vout0 = _mm_add_ps(vscaled0, vinr0);
+ vout1 = _mm_add_ps(vscaled1, vinr1);
+ _mm_store_ps(&aOutputR[i], vout0);
+ _mm_store_ps(&aOutputR[i+4], vout1);
+ }
+ }
+}
+
+void BufferComplexMultiply_SSE(const float* aInput,
+ const float* aScale,
+ float* aOutput,
+ uint32_t aSize)
+{
+ unsigned i;
+ __m128 in0, in1, in2, in3,
+ outreal0, outreal1, outreal2, outreal3,
+ outimag0, outimag1, outimag2, outimag3;
+
+ ASSERT_ALIGNED16(aInput);
+ ASSERT_ALIGNED16(aScale);
+ ASSERT_ALIGNED16(aOutput);
+ ASSERT_MULTIPLE16(aSize);
+
+ for (i = 0; i < aSize * 2; i += 16) {
+ in0 = _mm_load_ps(&aInput[i]);
+ in1 = _mm_load_ps(&aInput[i + 4]);
+ in2 = _mm_load_ps(&aInput[i + 8]);
+ in3 = _mm_load_ps(&aInput[i + 12]);
+
+ outreal0 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(2, 0, 2, 0));
+ outimag0 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(3, 1, 3, 1));
+ outreal2 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(2, 0, 2, 0));
+ outimag2 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(3, 1, 3, 1));
+
+ in0 = _mm_load_ps(&aScale[i]);
+ in1 = _mm_load_ps(&aScale[i + 4]);
+ in2 = _mm_load_ps(&aScale[i + 8]);
+ in3 = _mm_load_ps(&aScale[i + 12]);
+
+ outreal1 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(2, 0, 2, 0));
+ outimag1 = _mm_shuffle_ps(in0, in1, _MM_SHUFFLE(3, 1, 3, 1));
+ outreal3 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(2, 0, 2, 0));
+ outimag3 = _mm_shuffle_ps(in2, in3, _MM_SHUFFLE(3, 1, 3, 1));
+
+ in0 = _mm_sub_ps(_mm_mul_ps(outreal0, outreal1),
+ _mm_mul_ps(outimag0, outimag1));
+ in1 = _mm_add_ps(_mm_mul_ps(outreal0, outimag1),
+ _mm_mul_ps(outimag0, outreal1));
+ in2 = _mm_sub_ps(_mm_mul_ps(outreal2, outreal3),
+ _mm_mul_ps(outimag2, outimag3));
+ in3 = _mm_add_ps(_mm_mul_ps(outreal2, outimag3),
+ _mm_mul_ps(outimag2, outreal3));
+
+ outreal0 = _mm_unpacklo_ps(in0, in1);
+ outreal1 = _mm_unpackhi_ps(in0, in1);
+ outreal2 = _mm_unpacklo_ps(in2, in3);
+ outreal3 = _mm_unpackhi_ps(in2, in3);
+
+ _mm_store_ps(&aOutput[i], outreal0);
+ _mm_store_ps(&aOutput[i + 4], outreal1);
+ _mm_store_ps(&aOutput[i + 8], outreal2);
+ _mm_store_ps(&aOutput[i + 12], outreal3);
+ }
+}
+
+float
+AudioBufferSumOfSquares_SSE(const float* aInput, uint32_t aLength)
+{
+ unsigned i;
+ __m128 in0, in1, in2, in3,
+ acc0, acc1, acc2, acc3;
+ float out[4];
+
+ ASSERT_ALIGNED16(aInput);
+ ASSERT_MULTIPLE16(aLength);
+
+ acc0 = _mm_setzero_ps();
+ acc1 = _mm_setzero_ps();
+ acc2 = _mm_setzero_ps();
+ acc3 = _mm_setzero_ps();
+
+ for (i = 0; i < aLength; i+=16) {
+ in0 = _mm_load_ps(&aInput[i]);
+ in1 = _mm_load_ps(&aInput[i + 4]);
+ in2 = _mm_load_ps(&aInput[i + 8]);
+ in3 = _mm_load_ps(&aInput[i + 12]);
+
+ in0 = _mm_mul_ps(in0, in0);
+ in1 = _mm_mul_ps(in1, in1);
+ in2 = _mm_mul_ps(in2, in2);
+ in3 = _mm_mul_ps(in3, in3);
+
+ acc0 = _mm_add_ps(acc0, in0);
+ acc1 = _mm_add_ps(acc1, in1);
+ acc2 = _mm_add_ps(acc2, in2);
+ acc3 = _mm_add_ps(acc3, in3);
+ }
+
+ acc0 = _mm_add_ps(acc0, acc1);
+ acc0 = _mm_add_ps(acc0, acc2);
+ acc0 = _mm_add_ps(acc0, acc3);
+
+ _mm_store_ps(out, acc0);
+
+ return out[0] + out[1] + out[2] + out[3];
+}
+
+}
new file mode 100644
--- /dev/null
+++ b/dom/media/webaudio/AudioNodeEngineSSE2.h
@@ -0,0 +1,45 @@
+/* -*- 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 "AudioNodeEngine.h"
+
+namespace mozilla {
+void
+AudioBufferAddWithScale_SSE(const float* aInput,
+ float aScale,
+ float* aOutput,
+ uint32_t aSize);
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float* aInput,
+ float aScale,
+ float* aOutput);
+
+void
+AudioBlockCopyChannelWithScale_SSE(const float aInput[WEBAUDIO_BLOCK_SIZE],
+ const float aScale[WEBAUDIO_BLOCK_SIZE],
+ float aOutput[WEBAUDIO_BLOCK_SIZE]);
+
+void
+AudioBufferInPlaceScale_SSE(float* aBlock,
+ float aScale,
+ uint32_t aSize);
+
+void
+AudioBlockPanStereoToStereo_SSE(const float aInputL[WEBAUDIO_BLOCK_SIZE],
+ const float aInputR[WEBAUDIO_BLOCK_SIZE],
+ float aGainL, float aGainR, bool aIsOnTheLeft,
+ float aOutputL[WEBAUDIO_BLOCK_SIZE],
+ float aOutputR[WEBAUDIO_BLOCK_SIZE]);
+
+float
+AudioBufferSumOfSquares_SSE(const float* aInput, uint32_t aLength);
+
+void
+BufferComplexMultiply_SSE(const float* aInput,
+ const float* aScale,
+ float* aOutput,
+ uint32_t aSize);
+}
--- a/dom/media/webaudio/AudioNodeExternalInputStream.cpp
+++ b/dom/media/webaudio/AudioNodeExternalInputStream.cpp
@@ -1,13 +1,15 @@
/* -*- 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 "AlignedTArray.h"
+#include "AlignmentUtils.h"
#include "AudioNodeEngine.h"
#include "AudioNodeExternalInputStream.h"
#include "AudioChannelFormat.h"
#include "mozilla/dom/MediaStreamAudioSourceNode.h"
using namespace mozilla::dom;
namespace mozilla {
@@ -85,19 +87,30 @@ static void ConvertSegmentToAudioBlock(A
{
NS_ASSERTION(aSegment->GetDuration() == WEBAUDIO_BLOCK_SIZE, "Bad segment duration");
{
AudioSegment::ChunkIterator ci(*aSegment);
NS_ASSERTION(!ci.IsEnded(), "Should be at least one chunk!");
if (ci->GetDuration() == WEBAUDIO_BLOCK_SIZE &&
(ci->IsNull() || ci->mBufferFormat == AUDIO_FORMAT_FLOAT32)) {
+
+ bool aligned = true;
+ for (size_t i = 0; i < ci->mChannelData.Length(); ++i) {
+ if (!IS_ALIGNED16(ci->mChannelData[i])) {
+ aligned = false;
+ break;
+ }
+ }
+
// Return this chunk directly to avoid copying data.
- *aBlock = *ci;
- return;
+ if (aligned) {
+ *aBlock = *ci;
+ return;
+ }
}
}
aBlock->AllocateChannels(aFallbackChannelCount);
uint32_t duration = 0;
for (AudioSegment::ChunkIterator ci(*aSegment); !ci.IsEnded(); ci.Next()) {
switch (ci->mBufferFormat) {
@@ -187,17 +200,20 @@ AudioNodeExternalInputStream::ProcessInp
for (AudioSegment::ChunkIterator iter(segment); !iter.IsEnded(); iter.Next()) {
inputChannels = GetAudioChannelsSuperset(inputChannels, iter->ChannelCount());
}
}
uint32_t accumulateIndex = 0;
if (inputChannels) {
- AutoTArray<float,GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE> downmixBuffer;
+ // TODO: See Bug 1261168. Ideally we would use an aligned version of
+ // AutoTArray (of size GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE) here.
+ AlignedTArray<float,16> downmixBuffer;
+ downmixBuffer.SetLength(GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE);
for (uint32_t i = 0; i < audioSegments.Length(); ++i) {
AudioBlock tmpChunk;
ConvertSegmentToAudioBlock(&audioSegments[i], &tmpChunk, inputChannels);
if (!tmpChunk.IsNull()) {
if (accumulateIndex == 0) {
mLastChunks[0].AllocateChannels(inputChannels);
}
AccumulateInputChunk(accumulateIndex, tmpChunk, &mLastChunks[0], &downmixBuffer);
--- a/dom/media/webaudio/AudioNodeStream.cpp
+++ b/dom/media/webaudio/AudioNodeStream.cpp
@@ -448,29 +448,31 @@ AudioNodeStream::ObtainInputBlock(AudioB
}
if (outputChannelCount == 0) {
aTmpChunk.SetNull(WEBAUDIO_BLOCK_SIZE);
return;
}
aTmpChunk.AllocateChannels(outputChannelCount);
- // The static storage here should be 1KB, so it's fine
- AutoTArray<float, GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE> downmixBuffer;
+ // TODO: See Bug 1261168. Ideally we would use an aligned version of
+ // AutoTArray (of size GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE) here.
+ AlignedTArray<float, 16> downmixBuffer;
+ downmixBuffer.SetLength(GUESS_AUDIO_CHANNELS*WEBAUDIO_BLOCK_SIZE);
for (uint32_t i = 0; i < inputChunkCount; ++i) {
AccumulateInputChunk(i, *inputChunks[i], &aTmpChunk, &downmixBuffer);
}
}
void
AudioNodeStream::AccumulateInputChunk(uint32_t aInputIndex,
const AudioBlock& aChunk,
AudioBlock* aBlock,
- nsTArray<float>* aDownmixBuffer)
+ AlignedTArray<float, 16>* aDownmixBuffer)
{
AutoTArray<const float*,GUESS_AUDIO_CHANNELS> channels;
UpMixDownMixChunk(&aChunk, aBlock->ChannelCount(), channels, *aDownmixBuffer);
for (uint32_t c = 0; c < channels.Length(); ++c) {
const float* inputData = static_cast<const float*>(channels[c]);
float* outputData = aBlock->ChannelFloatsForWrite(c);
if (inputData) {
@@ -486,17 +488,17 @@ AudioNodeStream::AccumulateInputChunk(ui
}
}
}
void
AudioNodeStream::UpMixDownMixChunk(const AudioBlock* aChunk,
uint32_t aOutputChannelCount,
nsTArray<const float*>& aOutputChannels,
- nsTArray<float>& aDownmixBuffer)
+ AlignedTArray<float, 16>& aDownmixBuffer)
{
for (uint32_t i = 0; i < aChunk->ChannelCount(); i++) {
aOutputChannels.AppendElement(static_cast<const float*>(aChunk->mChannelData[i]));
}
if (aOutputChannels.Length() < aOutputChannelCount) {
if (mChannelInterpretation == ChannelInterpretation::Speakers) {
AudioChannelsUpMix<float>(&aOutputChannels, aOutputChannelCount, nullptr);
NS_ASSERTION(aOutputChannelCount == aOutputChannels.Length(),
--- a/dom/media/webaudio/AudioNodeStream.h
+++ b/dom/media/webaudio/AudioNodeStream.h
@@ -3,16 +3,17 @@
* 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_AUDIONODESTREAM_H_
#define MOZILLA_AUDIONODESTREAM_H_
#include "MediaStreamGraph.h"
#include "mozilla/dom/AudioNodeBinding.h"
+#include "AlignedTArray.h"
#include "AudioBlock.h"
namespace mozilla {
namespace dom {
struct ThreeDPoint;
struct AudioTimelineEvent;
class AudioContext;
@@ -185,20 +186,20 @@ protected:
* again until SetActive() is called.
*/
void CheckForInactive();
void AdvanceOutputSegment();
void FinishOutput();
void AccumulateInputChunk(uint32_t aInputIndex, const AudioBlock& aChunk,
AudioBlock* aBlock,
- nsTArray<float>* aDownmixBuffer);
+ AlignedTArray<float, 16>* aDownmixBuffer);
void UpMixDownMixChunk(const AudioBlock* aChunk, uint32_t aOutputChannelCount,
nsTArray<const float*>& aOutputChannels,
- nsTArray<float>& aDownmixBuffer);
+ AlignedTArray<float, 16>& aDownmixBuffer);
uint32_t ComputedNumberOfChannels(uint32_t aInputChannelCount);
void ObtainInputBlock(AudioBlock& aTmpChunk, uint32_t aPortIndex);
void IncrementActiveInputCount();
void DecrementActiveInputCount();
// The engine that will generate output for this node.
nsAutoPtr<AudioNodeEngine> mEngine;
--- a/dom/media/webaudio/BiquadFilterNode.cpp
+++ b/dom/media/webaudio/BiquadFilterNode.cpp
@@ -1,15 +1,16 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "BiquadFilterNode.h"
+#include "AlignmentUtils.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "AudioDestinationNode.h"
#include "PlayingRefChangeHandler.h"
#include "WebAudioUtils.h"
#include "blink/Biquad.h"
#include "mozilla/Preferences.h"
#include "mozilla/UniquePtr.h"
@@ -132,17 +133,19 @@ public:
}
void ProcessBlock(AudioNodeStream* aStream,
GraphTime aFrom,
const AudioBlock& aInput,
AudioBlock* aOutput,
bool* aFinished) override
{
- float inputBuffer[WEBAUDIO_BLOCK_SIZE];
+ float inputBuffer[WEBAUDIO_BLOCK_SIZE + 4];
+ float* alignedInputBuffer = ALIGNED16(inputBuffer);
+ ASSERT_ALIGNED16(alignedInputBuffer);
if (aInput.IsNull()) {
bool hasTail = false;
for (uint32_t i = 0; i < mBiquads.Length(); ++i) {
if (mBiquads[i].hasTail()) {
hasTail = true;
break;
}
@@ -186,22 +189,22 @@ public:
double freq = mFrequency.GetValueAtTime(pos);
double q = mQ.GetValueAtTime(pos);
double gain = mGain.GetValueAtTime(pos);
double detune = mDetune.GetValueAtTime(pos);
for (uint32_t i = 0; i < numberOfChannels; ++i) {
const float* input;
if (aInput.IsNull()) {
- input = inputBuffer;
+ input = alignedInputBuffer;
} else {
input = static_cast<const float*>(aInput.mChannelData[i]);
if (aInput.mVolume != 1.0) {
- AudioBlockCopyChannelWithScale(input, aInput.mVolume, inputBuffer);
- input = inputBuffer;
+ AudioBlockCopyChannelWithScale(input, aInput.mVolume, alignedInputBuffer);
+ input = alignedInputBuffer;
}
}
SetParamsOnBiquad(mBiquads[i], aStream->SampleRate(), mType, freq, q, gain, detune);
mBiquads[i].process(input,
aOutput->ChannelFloatsForWrite(i),
aInput.GetDuration());
}
--- a/dom/media/webaudio/ConvolverNode.cpp
+++ b/dom/media/webaudio/ConvolverNode.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "ConvolverNode.h"
#include "mozilla/dom/ConvolverNodeBinding.h"
+#include "AlignmentUtils.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "blink/Reverb.h"
#include "PlayingRefChangeHandler.h"
namespace mozilla {
namespace dom {
@@ -256,21 +257,23 @@ ConvolverNode::SetBuffer(JSContext* aCx,
mBuffer->GetThreadSharedChannelsForRate(aCx);
if (data && length < WEBAUDIO_BLOCK_SIZE) {
// For very small impulse response buffers, we need to pad the
// buffer with 0 to make sure that the Reverb implementation
// has enough data to compute FFTs from.
length = WEBAUDIO_BLOCK_SIZE;
RefPtr<ThreadSharedFloatArrayBufferList> paddedBuffer =
new ThreadSharedFloatArrayBufferList(data->GetChannels());
- float* channelData = (float*) malloc(sizeof(float) * length * data->GetChannels());
+ void* channelData = malloc(sizeof(float) * length * data->GetChannels() + 15);
+ float* alignedChannelData = ALIGNED16(channelData);
+ ASSERT_ALIGNED16(alignedChannelData);
for (uint32_t i = 0; i < data->GetChannels(); ++i) {
- PodCopy(channelData + length * i, data->GetData(i), mBuffer->Length());
- PodZero(channelData + length * i + mBuffer->Length(), WEBAUDIO_BLOCK_SIZE - mBuffer->Length());
- paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, free, channelData);
+ PodCopy(alignedChannelData + length * i, data->GetData(i), mBuffer->Length());
+ PodZero(alignedChannelData + length * i + mBuffer->Length(), WEBAUDIO_BLOCK_SIZE - mBuffer->Length());
+ paddedBuffer->SetData(i, (i == 0) ? channelData : nullptr, free, alignedChannelData);
}
data = paddedBuffer;
}
SendInt32ParameterToStream(ConvolverNodeEngine::BUFFER_LENGTH, length);
SendDoubleParameterToStream(ConvolverNodeEngine::SAMPLE_RATE,
mBuffer->SampleRate());
ns->SetBuffer(data.forget());
} else {
--- a/dom/media/webaudio/GainNode.cpp
+++ b/dom/media/webaudio/GainNode.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "GainNode.h"
#include "mozilla/dom/GainNodeBinding.h"
+#include "AlignmentUtils.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "AudioDestinationNode.h"
#include "WebAudioUtils.h"
namespace mozilla {
namespace dom {
@@ -74,28 +75,30 @@ public:
} else {
// First, compute a vector of gains for each track tick based on the
// timeline at hand, and then for each channel, multiply the values
// in the buffer with the gain vector.
aOutput->AllocateChannels(aInput.ChannelCount());
// Compute the gain values for the duration of the input AudioChunk
StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
- float computedGain[WEBAUDIO_BLOCK_SIZE];
- mGain.GetValuesAtTime(tick, computedGain, WEBAUDIO_BLOCK_SIZE);
+ float computedGain[WEBAUDIO_BLOCK_SIZE + 4];
+ float* alignedComputedGain = ALIGNED16(computedGain);
+ ASSERT_ALIGNED16(alignedComputedGain);
+ mGain.GetValuesAtTime(tick, alignedComputedGain, WEBAUDIO_BLOCK_SIZE);
for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
- computedGain[counter] *= aInput.mVolume;
+ alignedComputedGain[counter] *= aInput.mVolume;
}
// Apply the gain to the output buffer
for (size_t channel = 0; channel < aOutput->ChannelCount(); ++channel) {
const float* inputBuffer = static_cast<const float*> (aInput.mChannelData[channel]);
float* buffer = aOutput->ChannelFloatsForWrite(channel);
- AudioBlockCopyChannelWithScale(inputBuffer, computedGain, buffer);
+ AudioBlockCopyChannelWithScale(inputBuffer, alignedComputedGain, buffer);
}
}
}
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
{
// Not owned:
// - mDestination (probably)
--- a/dom/media/webaudio/StereoPannerNode.cpp
+++ b/dom/media/webaudio/StereoPannerNode.cpp
@@ -4,16 +4,17 @@
* 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 "StereoPannerNode.h"
#include "mozilla/dom/StereoPannerNodeBinding.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "AudioDestinationNode.h"
+#include "AlignmentUtils.h"
#include "WebAudioUtils.h"
#include "PanningUtils.h"
#include "AudioParamTimeline.h"
#include "AudioParam.h"
namespace mozilla {
namespace dom {
@@ -132,34 +133,36 @@ public:
GetGainValuesForPanning(panning, monoToStereo, gainL, gainR);
ApplyStereoPanning(aInput, aOutput,
gainL * aInput.mVolume,
gainR * aInput.mVolume,
panning <= 0);
}
} else {
- float computedGain[2][WEBAUDIO_BLOCK_SIZE];
+ float computedGain[2*WEBAUDIO_BLOCK_SIZE + 4];
bool onLeft[WEBAUDIO_BLOCK_SIZE];
float values[WEBAUDIO_BLOCK_SIZE];
StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
mPan.GetValuesAtTime(tick, values, WEBAUDIO_BLOCK_SIZE);
+ float* alignedComputedGain = ALIGNED16(computedGain);
+ ASSERT_ALIGNED16(alignedComputedGain);
for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
float left, right;
GetGainValuesForPanning(values[counter], monoToStereo, left, right);
- computedGain[0][counter] = left * aInput.mVolume;
- computedGain[1][counter] = right * aInput.mVolume;
+ alignedComputedGain[counter] = left * aInput.mVolume;
+ alignedComputedGain[WEBAUDIO_BLOCK_SIZE + counter] = right * aInput.mVolume;
onLeft[counter] = values[counter] <= 0;
}
// Apply the gain to the output buffer
- ApplyStereoPanning(aInput, aOutput, computedGain[0], computedGain[1], onLeft);
+ ApplyStereoPanning(aInput, aOutput, alignedComputedGain, &alignedComputedGain[WEBAUDIO_BLOCK_SIZE], onLeft);
}
}
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
{
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
--- a/dom/media/webaudio/WaveShaperNode.cpp
+++ b/dom/media/webaudio/WaveShaperNode.cpp
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "WaveShaperNode.h"
#include "mozilla/dom/WaveShaperNodeBinding.h"
+#include "AlignmentUtils.h"
#include "AudioNode.h"
#include "AudioNodeEngine.h"
#include "AudioNodeStream.h"
#include "mozilla/PodOperations.h"
namespace mozilla {
namespace dom {
@@ -226,23 +227,25 @@ public:
// or the input is null.
*aOutput = aInput;
return;
}
aOutput->AllocateChannels(channelCount);
for (uint32_t i = 0; i < channelCount; ++i) {
const float* inputSamples;
- float scaledInput[WEBAUDIO_BLOCK_SIZE];
+ float scaledInput[WEBAUDIO_BLOCK_SIZE + 4];
+ float* alignedScaledInput = ALIGNED16(scaledInput);
+ ASSERT_ALIGNED16(alignedScaledInput);
if (aInput.mVolume != 1.0f) {
AudioBlockCopyChannelWithScale(
static_cast<const float*>(aInput.mChannelData[i]),
aInput.mVolume,
- scaledInput);
- inputSamples = scaledInput;
+ alignedScaledInput);
+ inputSamples = alignedScaledInput;
} else {
inputSamples = static_cast<const float*>(aInput.mChannelData[i]);
}
float* outputBuffer = aOutput->ChannelFloatsForWrite(i);
float* sampleBuffer;
switch (mType) {
case OverSampleType::None:
--- a/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp
+++ b/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp
@@ -91,22 +91,40 @@ int ReverbAccumulationBuffer::accumulate
float* destination = m_buffer.Elements();
bool isSafe = writeIndex <= bufferLength && numberOfFrames1 + writeIndex <= bufferLength && numberOfFrames2 <= bufferLength;
MOZ_ASSERT(isSafe);
if (!isSafe)
return 0;
- AudioBufferAddWithScale(source, 1.0f, destination + writeIndex, numberOfFrames1);
+#ifdef USE_SSE2
+ // It is unlikely either the source is aligned or the number of values
+ // is a multiple of 16, so we just add them here rather than calling
+ // AudioBufferAddWithScale.
+ //
+ // TODO: Ideally we would use scalar calls when necessary and switch
+ // to vector calls when we have aligned sources and destinations.
+ // See Bug 1263910.
+ for (uint32_t i = 0; i < numberOfFrames1; ++i) {
+ destination[writeIndex + i] += source[i];
+ }
- // Handle wrap-around if necessary
+ // Handle wrap-around if necessary.
+ if (numberOfFrames2 > 0) {
+ for (uint32_t i = 0; i < numberOfFrames2; ++i) {
+ destination[i] += source[numberOfFrames1 + i];
+ }
+ }
+#else
+ AudioBufferAddWithScale(source, 1.0f, destination + writeIndex, numberOfFrames1);
if (numberOfFrames2 > 0) {
AudioBufferAddWithScale(source + numberOfFrames1, 1.0f, destination, numberOfFrames2);
}
+#endif
return writeIndex;
}
void ReverbAccumulationBuffer::reset()
{
PodZero(m_buffer.Elements(), m_buffer.Length());
m_readIndex = 0;
--- a/dom/media/webaudio/blink/ReverbAccumulationBuffer.h
+++ b/dom/media/webaudio/blink/ReverbAccumulationBuffer.h
@@ -24,23 +24,21 @@
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ReverbAccumulationBuffer_h
#define ReverbAccumulationBuffer_h
-#include "nsTArray.h"
+#include "AlignedTArray.h"
#include "mozilla/MemoryReporting.h"
namespace WebCore {
-typedef nsTArray<float> AudioFloatArray;
-
// ReverbAccumulationBuffer is a circular delay buffer with one client reading from it and multiple clients
// writing/accumulating to it at different delay offsets from the read position. The read operation will zero the memory
// just read from the buffer, so it will be ready for accumulation the next time around.
class ReverbAccumulationBuffer {
public:
explicit ReverbAccumulationBuffer(size_t length);
// This will read from, then clear-out numberOfFrames
@@ -60,16 +58,16 @@ public:
void reset();
size_t sizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
{
return m_buffer.ShallowSizeOfExcludingThis(aMallocSizeOf);
}
private:
- AudioFloatArray m_buffer;
+ AlignedTArray<float, 16> m_buffer;
size_t m_readIndex;
size_t m_readTimeFrame; // for debugging (frame on continuous timeline)
};
} // namespace WebCore
#endif // ReverbAccumulationBuffer_h
--- a/dom/media/webaudio/blink/moz.build
+++ b/dom/media/webaudio/blink/moz.build
@@ -18,14 +18,18 @@ UNIFIED_SOURCES += [
'Reverb.cpp',
'ReverbAccumulationBuffer.cpp',
'ReverbConvolver.cpp',
'ReverbConvolverStage.cpp',
'ReverbInputBuffer.cpp',
'ZeroPole.cpp',
]
+# Are we targeting x86 or x64? If so, build SSE2 files.
+if CONFIG['INTEL_ARCHITECTURE']:
+ DEFINES['USE_SSE2'] = True
+
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'/dom/media/webaudio',
]
--- a/dom/media/webaudio/moz.build
+++ b/dom/media/webaudio/moz.build
@@ -109,15 +109,22 @@ UNIFIED_SOURCES += [
if CONFIG['CPU_ARCH'] == 'arm' and CONFIG['BUILD_ARM_NEON']:
SOURCES += ['AudioNodeEngineNEON.cpp']
SOURCES['AudioNodeEngineNEON.cpp'].flags += ['-mfpu=neon']
LOCAL_INCLUDES += [
'/media/openmax_dl/dl/api/'
]
+# Are we targeting x86 or x64? If so, build SSE2 files.
+if CONFIG['INTEL_ARCHITECTURE']:
+ SOURCES += ['AudioNodeEngineSSE2.cpp']
+ DEFINES['USE_SSE2'] = True
+ SOURCES['AudioNodeEngineSSE2.cpp'].flags += CONFIG['SSE2_FLAGS']
+
+
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'..'
]
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -2534,17 +2534,17 @@ nsEventStatus nsPluginInstanceOwner::Pro
NS_PLUGIN_CALL_SAFE_TO_REENTER_GECKO);
if (response == kNPEventHandled)
rv = nsEventStatus_eConsumeNoDefault;
}
#endif
#ifdef MOZ_X11
// this code supports windowless plugins
- nsIWidget* widget = anEvent.widget;
+ nsIWidget* widget = anEvent.mWidget;
XEvent pluginEvent = XEvent();
pluginEvent.type = 0;
switch(anEvent.mClass) {
case eMouseEventClass:
{
switch (anEvent.mMessage) {
case eMouseClick:
deleted file mode 100644
--- a/dom/plugins/test/testplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-RELATIVE_PATH=.
-COCOA_NAME=Test
-include @srcdir@/testplugin.mk
deleted file mode 100644
--- a/dom/plugins/test/testplugin/flashplugin/Makefile.in
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-RELATIVE_PATH=..
-COCOA_NAME=npswftest
-include @srcdir@/../testplugin.mk
-
--- a/dom/plugins/test/testplugin/flashplugin/moz.build
+++ b/dom/plugins/test/testplugin/flashplugin/moz.build
@@ -2,9 +2,10 @@
# vim: set filetype=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/.
SharedLibrary('npswftest')
relative_path = 'flashplugin'
+cocoa_name = 'npswftest'
include('../testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/javaplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-RELATIVE_PATH=..
-COCOA_NAME=JavaTest
-include @srcdir@/../testplugin.mk
--- a/dom/plugins/test/testplugin/javaplugin/moz.build
+++ b/dom/plugins/test/testplugin/javaplugin/moz.build
@@ -2,9 +2,10 @@
# vim: set filetype=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/.
SharedLibrary('nptestjava')
relative_path = 'javaplugin'
+cocoa_name = 'JavaTest'
include('../testplugin.mozbuild')
--- a/dom/plugins/test/testplugin/moz.build
+++ b/dom/plugins/test/testplugin/moz.build
@@ -4,9 +4,10 @@
# 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/.
DIRS += ['secondplugin', 'javaplugin', 'thirdplugin', 'flashplugin', 'silverlightplugin']
SharedLibrary('nptest')
relative_path = '.'
+cocoa_name = 'Test'
include('testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/secondplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-RELATIVE_PATH=..
-COCOA_NAME=SecondTest
-include @srcdir@/../testplugin.mk
--- a/dom/plugins/test/testplugin/secondplugin/moz.build
+++ b/dom/plugins/test/testplugin/secondplugin/moz.build
@@ -2,9 +2,10 @@
# vim: set filetype=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/.
SharedLibrary('npsecondtest')
relative_path = 'secondplugin'
+cocoa_name = 'SecondTest'
include('../testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/silverlightplugin/Makefile.in
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-RELATIVE_PATH=..
-COCOA_NAME=npctrltest
-include @srcdir@/../testplugin.mk
-
--- a/dom/plugins/test/testplugin/silverlightplugin/moz.build
+++ b/dom/plugins/test/testplugin/silverlightplugin/moz.build
@@ -2,9 +2,10 @@
# vim: set filetype=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/.
SharedLibrary('npctrltest')
relative_path = 'silverlightplugin'
+cocoa_name = 'npctrltest'
include('../testplugin.mozbuild')
deleted file mode 100644
--- a/dom/plugins/test/testplugin/testplugin.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-TEST_PLUGIN_FILES = $(SHARED_LIBRARY)
-
-ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-MAC_PLIST_FILES += $(srcdir)/Info.plist
-MAC_PLIST_DEST = $(DIST)/plugins/$(COCOA_NAME).plugin/Contents
-TEST_PLUGIN_DEST = $(DIST)/plugins/$(COCOA_NAME).plugin/Contents/MacOS
-INSTALL_TARGETS += \
- TEST_PLUGIN \
- MAC_PLIST \
- $(NULL)
-else
-TEST_PLUGIN_DEST = $(DIST)/plugins
-INSTALL_TARGETS += TEST_PLUGIN
-endif
--- a/dom/plugins/test/testplugin/testplugin.mozbuild
+++ b/dom/plugins/test/testplugin/testplugin.mozbuild
@@ -1,16 +1,14 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=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/.
-DIST_INSTALL = False
-
UNIFIED_SOURCES += [
'nptest.cpp',
'nptest_utils.cpp',
]
UNIFIED_SOURCES += [
'%s/nptest_name.cpp' % relative_path,
]
@@ -69,8 +67,14 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
OS_LIBS += CONFIG['MOZ_QT_LIBS']
OS_LIBS += CONFIG['XLDFLAGS']
OS_LIBS += CONFIG['XLIBS']
if CONFIG['_MSC_VER']:
# This is intended as a temporary hack to support building with VS2015.
# conversion from 'X' to 'Y' requires a narrowing conversion
CXXFLAGS += ['-wd4838']
+
+if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
+ FINAL_TARGET = 'dist/plugins/%s.plugin/Contents/MacOS' % cocoa_name
+ OBJDIR_FILES.dist.plugins['%s.plugin' % cocoa_name].Contents += ['Info.plist']
+else:
+ FINAL_TARGET = 'dist/plugins'
deleted file mode 100644
--- a/dom/plugins/test/testplugin/thirdplugin/Makefile.in
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-RELATIVE_PATH=..
-COCOA_NAME=ThirdTest
-include @srcdir@/../testplugin.mk
--- a/dom/plugins/test/testplugin/thirdplugin/moz.build
+++ b/dom/plugins/test/testplugin/thirdplugin/moz.build
@@ -2,9 +2,10 @@
# vim: set filetype=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/.
SharedLibrary('npthirdtest')
relative_path = 'thirdplugin'
+cocoa_name = 'ThirdTest'
include('../testplugin.mozbuild')
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -701,23 +701,25 @@ nsCSPContext::logToConsole(const char16_
void
StripURIForReporting(nsIURI* aURI,
nsIPrincipal* aProtectedResourcePrincipal,
nsACString& outStrippedURI)
{
// 1) If the origin of uri is a globally unique identifier (for example,
// aURI has a scheme of data, blob, or filesystem), then return the
// ASCII serialization of uri’s scheme.
- bool isHttp =
- (NS_SUCCEEDED(aURI->SchemeIs("http", &isHttp)) && isHttp) ||
- (NS_SUCCEEDED(aURI->SchemeIs("https", &isHttp)) && isHttp);
- if (!isHttp) {
+ bool isHttpOrFtp =
+ (NS_SUCCEEDED(aURI->SchemeIs("http", &isHttpOrFtp)) && isHttpOrFtp) ||
+ (NS_SUCCEEDED(aURI->SchemeIs("https", &isHttpOrFtp)) && isHttpOrFtp) ||
+ (NS_SUCCEEDED(aURI->SchemeIs("ftp", &isHttpOrFtp)) && isHttpOrFtp);
+
+ if (!isHttpOrFtp) {
// not strictly spec compliant, but what we really care about is
- // http/https. If it's not http/https, then treat aURI as if
- // it's a globally unique identifier and just return the scheme.
+ // http/https and also ftp. If it's not http/https or ftp, then treat aURI
+ // as if it's a globally unique identifier and just return the scheme.
aURI->GetScheme(outStrippedURI);
return;
}
// 2) If the origin of uri is not the same as the origin of the protected
// resource, then return the ASCII serialization of uri’s origin.
bool sameOrigin =
NS_SUCCEEDED(aProtectedResourcePrincipal->CheckMayLoad(aURI, false, false));
--- a/dom/security/test/unit/test_csp_reports.js
+++ b/dom/security/test/unit/test_csp_reports.js
@@ -207,9 +207,18 @@ function run_test() {
makeTest(7, {"blocked-uri": selfSpec}, false,
function(csp) {
var uri = NetUtil
// shouldLoad creates and sends out the report here.
csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
NetUtil.newURI(selfSpec + "#bar"),
null, null, null, null);
});
+
+ // test scheme of ftp:
+ makeTest(8, {"blocked-uri": "ftp://blocked.test"}, false,
+ function(csp) {
+ // shouldLoad creates and sends out the report here.
+ csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
+ NetUtil.newURI("ftp://blocked.test/profile.png"),
+ null, null, null, null);
+ });
}
--- a/editor/libeditor/nsEditor.cpp
+++ b/editor/libeditor/nsEditor.cpp
@@ -5087,17 +5087,17 @@ nsEditor::IsAcceptableInputEvent(nsIDOME
// WidgetCompositionEvent.
widgetGUIEvent = aEvent->WidgetEventPtr()->AsCompositionEvent();
needsWidget = true;
break;
default:
break;
}
if (needsWidget &&
- (!widgetGUIEvent || !widgetGUIEvent->widget)) {
+ (!widgetGUIEvent || !widgetGUIEvent->mWidget)) {
return false;
}
// Accept all trusted events.
if (widgetEvent->IsTrusted()) {
return true;
}
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -639,17 +639,17 @@ nsEditorEventListener::KeyPress(nsIDOMKe
return NS_OK;
}
// Now, ask the native key bindings to handle the event.
WidgetKeyboardEvent* keyEvent =
aKeyEvent->AsEvent()->WidgetEventPtr()->AsKeyboardEvent();
MOZ_ASSERT(keyEvent,
"DOM key event's internal event must be WidgetKeyboardEvent");
- nsIWidget* widget = keyEvent->widget;
+ nsIWidget* widget = keyEvent->mWidget;
// If the event is created by chrome script, the widget is always nullptr.
if (!widget) {
nsCOMPtr<nsIPresShell> ps = GetPresShell();
nsPresContext* pc = ps ? ps->GetPresContext() : nullptr;
widget = pc ? pc->GetNearestWidget() : nullptr;
NS_ENSURE_TRUE(widget, NS_OK);
}
--- a/embedding/components/printingui/win/nsPrintDialogUtil.cpp
+++ b/embedding/components/printingui/win/nsPrintDialogUtil.cpp
@@ -50,16 +50,18 @@ WIN_LIBS=
#include "nsIStringBundle.h"
// For NS_CopyUnicodeToNative
#include "nsNativeCharsetUtils.h"
// This is for extending the dialog
#include <dlgs.h>
+#include "nsWindowsHelpers.h"
+
// Default labels for the radio buttons
static const char* kAsLaidOutOnScreenStr = "As &laid out on the screen";
static const char* kTheSelectedFrameStr = "The selected &frame";
static const char* kEachFrameSeparately = "&Each frame separately";
//-----------------------------------------------
// Global Data
@@ -457,89 +459,81 @@ static UINT CALLBACK PrintHookProc(HWND
//----------------------------------------------------------------------------------
// Returns a Global Moveable Memory Handle to a DevMode
// from the Printer by the name of aPrintName
//
// NOTE:
// This function assumes that aPrintName has already been converted from
// unicode
//
-HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS)
+static nsReturnRef<nsHGLOBAL>
+CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName,
+ nsIPrintSettings* aPS)
{
- HGLOBAL hGlobalDevMode = nullptr;
-
- HANDLE hPrinter = nullptr;
+ nsHPRINTER hPrinter = nullptr;
// const cast kludge for silly Win32 api's
LPWSTR printName = const_cast<wchar_t*>(static_cast<const wchar_t*>(aPrintName.get()));
BOOL status = ::OpenPrinterW(printName, &hPrinter, nullptr);
- if (status) {
-
- LPDEVMODEW pNewDevMode;
- DWORD dwNeeded, dwRet;
-
- // Get the buffer size
- dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr, nullptr, 0);
- if (dwNeeded == 0) {
- return nullptr;
- }
-
- // Allocate a buffer of the correct size.
- pNewDevMode = (LPDEVMODEW)::HeapAlloc (::GetProcessHeap(), HEAP_ZERO_MEMORY, dwNeeded);
- if (!pNewDevMode) return nullptr;
+ if (!status) {
+ return nsReturnRef<nsHGLOBAL>();
+ }
- hGlobalDevMode = (HGLOBAL)::GlobalAlloc(GHND, dwNeeded);
- if (!hGlobalDevMode) {
- ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
- return nullptr;
- }
-
- dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, pNewDevMode, nullptr, DM_OUT_BUFFER);
-
- if (dwRet != IDOK) {
- ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
- ::GlobalFree(hGlobalDevMode);
- ::ClosePrinter(hPrinter);
- return nullptr;
- }
+ // Make sure hPrinter is closed on all paths
+ nsAutoPrinter autoPrinter(hPrinter);
- // Lock memory and copy contents from DEVMODE (current printer)
- // to Global Memory DEVMODE
- LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hGlobalDevMode);
- if (devMode) {
- memcpy(devMode, pNewDevMode, dwNeeded);
- // Initialize values from the PrintSettings
- nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
- MOZ_ASSERT(psWin);
- psWin->CopyToNative(devMode);
+ // Get the buffer size
+ DWORD dwNeeded = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, nullptr,
+ nullptr, 0);
+ if (dwNeeded == 0) {
+ return nsReturnRef<nsHGLOBAL>();
+ }
- // Sets back the changes we made to the DevMode into the Printer Driver
- dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode, DM_IN_BUFFER | DM_OUT_BUFFER);
- if (dwRet != IDOK) {
- ::GlobalUnlock(hGlobalDevMode);
- ::GlobalFree(hGlobalDevMode);
- ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
- ::ClosePrinter(hPrinter);
- return nullptr;
- }
+ // Allocate a buffer of the correct size.
+ nsAutoDevMode newDevMode((LPDEVMODEW)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
+ dwNeeded));
+ if (!newDevMode) {
+ return nsReturnRef<nsHGLOBAL>();
+ }
- ::GlobalUnlock(hGlobalDevMode);
- } else {
- ::GlobalFree(hGlobalDevMode);
- hGlobalDevMode = nullptr;
- }
-
- ::HeapFree(::GetProcessHeap(), 0, pNewDevMode);
-
- ::ClosePrinter(hPrinter);
-
- } else {
- return nullptr;
+ nsHGLOBAL hDevMode = ::GlobalAlloc(GHND, dwNeeded);
+ nsAutoGlobalMem globalDevMode(hDevMode);
+ if (!hDevMode) {
+ return nsReturnRef<nsHGLOBAL>();
}
- return hGlobalDevMode;
+ DWORD dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, newDevMode,
+ nullptr, DM_OUT_BUFFER);
+ if (dwRet != IDOK) {
+ return nsReturnRef<nsHGLOBAL>();
+ }
+
+ // Lock memory and copy contents from DEVMODE (current printer)
+ // to Global Memory DEVMODE
+ LPDEVMODEW devMode = (DEVMODEW *)::GlobalLock(hDevMode);
+ if (!devMode) {
+ return nsReturnRef<nsHGLOBAL>();
+ }
+
+ memcpy(devMode, newDevMode.get(), dwNeeded);
+ // Initialize values from the PrintSettings
+ nsCOMPtr<nsIPrintSettingsWin> psWin = do_QueryInterface(aPS);
+ MOZ_ASSERT(psWin);
+ psWin->CopyToNative(devMode);
+
+ // Sets back the changes we made to the DevMode into the Printer Driver
+ dwRet = ::DocumentPropertiesW(gParentWnd, hPrinter, printName, devMode, devMode,
+ DM_IN_BUFFER | DM_OUT_BUFFER);
+ if (dwRet != IDOK) {
+ ::GlobalUnlock(hDevMode);
+ return nsReturnRef<nsHGLOBAL>();
+ }
+
+ ::GlobalUnlock(hDevMode);
+
+ return globalDevMode.out();
}
//------------------------------------------------------------------
// helper
static void GetDefaultPrinterNameFromGlobalPrinters(nsXPIDLString &printerName)
{
nsCOMPtr<nsIPrinterEnumerator> prtEnum = do_GetService("@mozilla.org/gfx/printerenumerator;1");
if (prtEnum) {
@@ -571,73 +565,69 @@ static nsresult
ShowNativePrintDialog(HWND aHWnd,
nsIPrintSettings* aPrintSettings)
{
//NS_ENSURE_ARG_POINTER(aHWnd);
NS_ENSURE_ARG_POINTER(aPrintSettings);
gDialogWasExtended = false;
- HGLOBAL hGlobalDevMode = nullptr;
- HGLOBAL hDevNames = nullptr;
-
// Get the Print Name to be used
nsXPIDLString printerName;
aPrintSettings->GetPrinterName(getter_Copies(printerName));
// If there is no name then use the default printer
if (printerName.IsEmpty()) {
GetDefaultPrinterNameFromGlobalPrinters(printerName);
} else {
HANDLE hPrinter = nullptr;
- if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())), &hPrinter, nullptr)) {
+ if(!::OpenPrinterW(const_cast<wchar_t*>(static_cast<const wchar_t*>(printerName.get())),
+ &hPrinter, nullptr)) {
// If the last used printer is not found, we should use default printer.
GetDefaultPrinterNameFromGlobalPrinters(printerName);
} else {
::ClosePrinter(hPrinter);
}
}
// Now create a DEVNAMES struct so the the dialog is initialized correctly.
uint32_t len = printerName.Length();
- hDevNames = (HGLOBAL)::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1) +
- sizeof(DEVNAMES));
+ nsHGLOBAL hDevNames = ::GlobalAlloc(GHND, sizeof(wchar_t) * (len + 1)
+ + sizeof(DEVNAMES));
+ nsAutoGlobalMem autoDevNames(hDevNames);
if (!hDevNames) {
return NS_ERROR_OUT_OF_MEMORY;
}
DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames);
if (!pDevNames) {
- ::GlobalFree(hDevNames);
return NS_ERROR_FAILURE;
}
pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
pDevNames->wDeviceOffset = sizeof(DEVNAMES)/sizeof(wchar_t);
pDevNames->wOutputOffset = sizeof(DEVNAMES)/sizeof(wchar_t)+len;
pDevNames->wDefault = 0;
memcpy(pDevNames+1, printerName, (len + 1) * sizeof(wchar_t));
::GlobalUnlock(hDevNames);
// Create a Moveable Memory Object that holds a new DevMode
// from the Printer Name
// The PRINTDLG.hDevMode requires that it be a moveable memory object
- // NOTE: We only need to free hGlobalDevMode when the dialog is cancelled
- // When the user prints, it comes back in the printdlg struct and
- // is used and cleaned up later
- hGlobalDevMode = CreateGlobalDevModeAndInit(printerName, aPrintSettings);
+ // NOTE: autoDevMode is automatically freed when any error occurred
+ nsAutoGlobalMem autoDevMode(CreateGlobalDevModeAndInit(printerName, aPrintSettings));
// Prepare to Display the Print Dialog
PRINTDLGW prntdlg;
memset(&prntdlg, 0, sizeof(PRINTDLGW));
prntdlg.lStructSize = sizeof(prntdlg);
prntdlg.hwndOwner = aHWnd;
- prntdlg.hDevMode = hGlobalDevMode;
+ prntdlg.hDevMode = autoDevMode.get();
prntdlg.hDevNames = hDevNames;
prntdlg.hDC = nullptr;
prntdlg.Flags = PD_ALLPAGES | PD_RETURNIC |
PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE;
// if there is a current selection then enable the "Selection" radio button
int16_t howToEnableFrameUI = nsIPrintSettings::kFrameEnableNone;
bool isOn;
@@ -677,23 +667,21 @@ ShowNativePrintDialog(HWND
BOOL result = ::PrintDlgW(&prntdlg);
if (TRUE == result) {
// check to make sure we don't have any nullptr pointers
NS_ENSURE_TRUE(aPrintSettings && prntdlg.hDevMode, NS_ERROR_FAILURE);
if (prntdlg.hDevNames == nullptr) {
- ::GlobalFree(hGlobalDevMode);
return NS_ERROR_FAILURE;
}
// Lock the deviceNames and check for nullptr
DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(prntdlg.hDevNames);
if (devnames == nullptr) {
- ::GlobalFree(hGlobalDevMode);
return NS_ERROR_FAILURE;
}
char16_t* device = &(((char16_t *)devnames)[devnames->wDeviceOffset]);
char16_t* driver = &(((char16_t *)devnames)[devnames->wDriverOffset]);
// Check to see if the "Print To File" control is checked
// then take the name from devNames and set it in the PrintSettings
@@ -711,17 +699,16 @@ ShowNativePrintDialog(HWND
} else {
// clear "print to file" info
aPrintSettings->SetPrintToFile(false);
aPrintSettings->SetToFileName(nullptr);
}
nsCOMPtr<nsIPrintSettingsWin> psWin(do_QueryInterface(aPrintSettings));
if (!psWin) {
- ::GlobalFree(hGlobalDevMode);
return NS_ERROR_FAILURE;
}
// Setup local Data members
psWin->SetDeviceName(device);
psWin->SetDriverName(driver);
#if defined(DEBUG_rods) || defined(DEBUG_dcone)
@@ -767,17 +754,16 @@ ShowNativePrintDialog(HWND
aPrintSettings->SetPrintFrameType(nsIPrintSettings::kNoFrames);
}
// Unlock DeviceNames
::GlobalUnlock(prntdlg.hDevNames);
// Transfer the settings from the native data to the PrintSettings
LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(prntdlg.hDevMode);
if (!devMode || !prntdlg.hDC) {
- ::GlobalFree(hGlobalDevMode);
return NS_ERROR_FAILURE;
}
psWin->SetDevMode(devMode); // copies DevMode
psWin->CopyFromNative(prntdlg.hDC, devMode);
::GlobalUnlock(prntdlg.hDevMode);
::DeleteDC(prntdlg.hDC);
#if defined(DEBUG_rods) || defined(DEBUG_dcone)
@@ -800,17 +786,16 @@ ShowNativePrintDialog(HWND
} else {
printf("Printing from page no. %d to %d\n", fromPageNum, toPageNum);
}
#endif
} else {
::SetFocus(aHWnd);
aPrintSettings->SetIsCancelled(true);
- if (hGlobalDevMode) ::GlobalFree(hGlobalDevMode);
return NS_ERROR_ABORT;
}
return NS_OK;
}
//------------------------------------------------------------------
static void
--- a/embedding/components/printingui/win/nsPrintDialogUtil.h
+++ b/embedding/components/printingui/win/nsPrintDialogUtil.h
@@ -4,11 +4,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsFlyOwnDialog_h___
#define nsFlyOwnDialog_h___
nsresult NativeShowPrintDialog(HWND aHWnd,
nsIWebBrowserPrint* aWebBrowserPrint,
nsIPrintSettings* aPrintSettings);
-HGLOBAL CreateGlobalDevModeAndInit(const nsXPIDLString& aPrintName, nsIPrintSettings* aPS);
-
#endif /* nsFlyOwnDialog_h___ */
--- a/gfx/layers/apz/public/GeckoContentController.h
+++ b/gfx/layers/apz/public/GeckoContentController.h
@@ -32,24 +32,16 @@ public:
/**
* Requests a paint of the given FrameMetrics |aFrameMetrics| from Gecko.
* Implementations per-platform are responsible for actually handling this.
* This method will always be called on the Gecko main thread.
*/
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) = 0;
/**
- * Acknowledges the recipt of a scroll offset update for the scrollable
- * frame with the given scroll id. This is used to maintain consistency
- * between APZ and other sources of scroll changes.
- */
- virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
- const uint32_t& aScrollGeneration) = 0;
-
- /**
* Requests handling of a double tap. |aPoint| is in CSS pixels, relative to
* the current scroll offset. This should eventually round-trip back to
* AsyncPanZoomController::ZoomToRect with the dimensions that we want to zoom
* to.
*/
virtual void HandleDoubleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) = 0;
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -3452,17 +3452,17 @@ void AsyncPanZoomController::NotifyLayer
if ((aIsFirstPaint && aThisLayerTreeUpdated) || isDefault) {
// Initialize our internal state to something sane when the content
// that was just painted is something we knew nothing about previously
CancelAnimation();
mScrollMetadata = aScrollMetadata;
if (scrollOffsetUpdated) {
- AcknowledgeScrollUpdate();
+ needContentRepaint = true;
}
mExpectedGeckoMetrics = aLayerMetrics;
ShareCompositorFrameMetrics();
if (mFrameMetrics.GetDisplayPortMargins() != ScreenMargin()) {
// A non-zero display port margin here indicates a displayport has
// been set by a previous APZC for the content at this guid. The
// scrollable rect may have changed since then, making the margins
@@ -3527,17 +3527,16 @@ void AsyncPanZoomController::NotifyLayer
// Send an acknowledgement with the new scroll generation so that any
// repaint requests later in this function go through.
// Because of the scroll generation update, any inflight paint requests are
// going to be ignored by layout, and so mExpectedGeckoMetrics
// becomes incorrect for the purposes of calculating the LD transform. To
// correct this we need to update mExpectedGeckoMetrics to be the
// last thing we know was painted by Gecko.
mFrameMetrics.CopyScrollInfoFrom(aLayerMetrics);
- AcknowledgeScrollUpdate();
mExpectedGeckoMetrics = aLayerMetrics;
// Cancel the animation (which might also trigger a repaint request)
// after we update the scroll offset above. Otherwise we can be left
// in a state where things are out of sync.
CancelAnimation();
// Since the scroll offset has changed, we need to recompute the
@@ -3559,43 +3558,28 @@ void AsyncPanZoomController::NotifyLayer
APZC_LOG("%p smooth scrolling from %s to %s in state %d\n", this,
Stringify(mFrameMetrics.GetScrollOffset()).c_str(),
Stringify(aLayerMetrics.GetSmoothScrollOffset()).c_str(),
mState);
// See comment on the similar code in the |if (scrollOffsetUpdated)| block
// above.
mFrameMetrics.CopySmoothScrollInfoFrom(aLayerMetrics);
- AcknowledgeScrollUpdate();
+ needContentRepaint = true;
mExpectedGeckoMetrics = aLayerMetrics;
SmoothScrollTo(mFrameMetrics.GetSmoothScrollOffset());
}
if (needContentRepaint) {
RequestContentRepaint();
}
UpdateSharedCompositorFrameMetrics();
}
-void
-AsyncPanZoomController::AcknowledgeScrollUpdate() const
-{
- // Once layout issues a scroll offset update, it becomes impervious to
- // 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.
- RefPtr<GeckoContentController> controller = GetGeckoContentController();
- if (controller) {
- APZC_LOG("%p sending scroll update acknowledgement with gen %u\n", this, mFrameMetrics.GetScrollGeneration());
- controller->AcknowledgeScrollUpdate(mFrameMetrics.GetScrollId(),
- mFrameMetrics.GetScrollGeneration());
- }
-}
-
const FrameMetrics& AsyncPanZoomController::GetFrameMetrics() const {
mMonitor.AssertCurrentThreadIn();
return mFrameMetrics;
}
APZCTreeManager* AsyncPanZoomController::GetApzcTreeManager() const {
mMonitor.AssertNotCurrentThreadIn();
return mTreeManager;
--- a/gfx/layers/apz/src/AsyncPanZoomController.h
+++ b/gfx/layers/apz/src/AsyncPanZoomController.h
@@ -891,18 +891,16 @@ private:
// Start an overscroll animation with the given initial velocity.
void StartOverscrollAnimation(const ParentLayerPoint& aVelocity);
void SmoothScrollTo(const CSSPoint& aDestination);
// Returns whether overscroll is allowed during an event.
bool AllowScrollHandoffInCurrentBlock() const;
- void AcknowledgeScrollUpdate() const;
-
/* ===================================================================
* The functions and members in this section are used to make ancestor chains
* out of APZC instances. These chains can only be walked or manipulated
* while holding the lock in the associated APZCTreeManager instance.
*/
public:
void SetParent(AsyncPanZoomController* aParent) {
mParent = aParent;
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -119,19 +119,19 @@ ScrollFrameTo(nsIScrollableFrame* aFrame
*/
static void
ScrollFrame(nsIContent* aContent,
FrameMetrics& aMetrics)
{
// Scroll the window to the desired spot
nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(aMetrics.GetScrollId());
if (sf) {
+ sf->ResetScrollInfoIfGeneration(aMetrics.GetScrollGeneration());
sf->SetScrollableByAPZ(!aMetrics.IsScrollInfoLayer());
}
-
bool scrollUpdated = false;
CSSPoint apzScrollOffset = aMetrics.GetScrollOffset();
CSSPoint actualScrollOffset = ScrollFrameTo(sf, apzScrollOffset, scrollUpdated);
if (scrollUpdated) {
if (aMetrics.IsScrollInfoLayer()) {
// In cases where the APZ scroll offset is different from the content scroll
// offset, we want to interpret the margins as relative to the APZ scroll
@@ -325,64 +325,16 @@ APZCCallbackHelper::InitializeRootDispla
// nsRootBoxFrame::BuildDisplayList.
nsLayoutUtils::SetDisplayPortMargins(content, aPresShell, ScreenMargin(), 0,
nsLayoutUtils::RepaintMode::DoNotRepaint);
nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(
content->GetPrimaryFrame(), nsLayoutUtils::RepaintMode::DoNotRepaint);
}
}
-class AcknowledgeScrollUpdateEvent : public nsRunnable
-{
- typedef mozilla::layers::FrameMetrics::ViewID ViewID;
-
-public:
- AcknowledgeScrollUpdateEvent(const ViewID& aScrollId, const uint32_t& aScrollGeneration)
- : mScrollId(aScrollId)
- , mScrollGeneration(aScrollGeneration)
- {
- }
-
- NS_IMETHOD Run() {
- MOZ_ASSERT(NS_IsMainThread());
-
- nsIScrollableFrame* sf = nsLayoutUtils::FindScrollableFrameFor(mScrollId);
- if (sf) {
- sf->ResetScrollInfoIfGeneration(mScrollGeneration);
- }
-
- // Since the APZ and content are in sync, we need to clear any callback transform
- // that might have been set on the last repaint request (which might have failed
- // due to the inflight scroll update that this message is acknowledging).
- nsCOMPtr<nsIContent> content = nsLayoutUtils::FindContentFor(mScrollId);
- if (content) {
- content->SetProperty(nsGkAtoms::apzCallbackTransform, new CSSPoint(),
- nsINode::DeleteProperty<CSSPoint>);
- }
-
- return NS_OK;
- }
-
-protected:
- ViewID mScrollId;
- uint32_t mScrollGeneration;
-};
-
-void
-APZCCallbackHelper::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
- const uint32_t& aScrollGeneration)
-{
- nsCOMPtr<nsIRunnable> r1 = new AcknowledgeScrollUpdateEvent(aScrollId, aScrollGeneration);
- if (!NS_IsMainThread()) {
- NS_DispatchToMainThread(r1);
- } else {
- r1->Run();
- }
-}
-
nsIPresShell*
APZCCallbackHelper::GetRootContentDocumentPresShellForContent(nsIContent* aContent)
{
nsIDocument* doc = aContent->GetComposedDoc();
if (!doc) {
return nullptr;
}
nsIPresShell* shell = doc->GetShell();
@@ -509,44 +461,43 @@ APZCCallbackHelper::ApplyCallbackTransfo
aEvent.refPoint, aGuid, aScale);
}
}
nsEventStatus
APZCCallbackHelper::DispatchWidgetEvent(WidgetGUIEvent& aEvent)
{
nsEventStatus status = nsEventStatus_eConsumeNoDefault;
- if (aEvent.widget) {
- aEvent.widget->DispatchEvent(&aEvent, status);
+ if (aEvent.mWidget) {
+ aEvent.mWidget->DispatchEvent(&aEvent, status);
}
return status;
}
nsEventStatus
APZCCallbackHelper::DispatchSynthesizedMouseEvent(EventMessage aMsg,
uint64_t aTime,
const LayoutDevicePoint& aRefPoint,
Modifiers aModifiers,
nsIWidget* aWidget)
{
MOZ_ASSERT(aMsg == eMouseMove || aMsg == eMouseDown ||
aMsg == eMouseUp || aMsg == eMouseLongTap);
- WidgetMouseEvent event(true, aMsg, nullptr,
+ WidgetMouseEvent event(true, aMsg, aWidget,
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
event.refPoint = LayoutDeviceIntPoint(aRefPoint.x, aRefPoint.y);
event.mTime = aTime;
event.button = WidgetMouseEvent::eLeftButton;
event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH;
event.ignoreRootScrollFrame = true;
if (aMsg != eMouseMove) {
event.clickCount = 1;
}
event.mModifiers = aModifiers;
- event.widget = aWidget;
return DispatchWidgetEvent(event);
}
bool
APZCCallbackHelper::DispatchMouseEvent(const nsCOMPtr<nsIPresShell>& aPresShell,
const nsString& aType,
const CSSPoint& aPoint,
--- a/gfx/layers/apz/util/APZCCallbackHelper.h
+++ b/gfx/layers/apz/util/APZCCallbackHelper.h
@@ -61,21 +61,16 @@ public:
static bool GetOrCreateScrollIdentifiers(nsIContent* aContent,
uint32_t* aPresShellIdOut,
FrameMetrics::ViewID* aViewIdOut);
/* Initialize a zero-margin displayport on the root document element of the
given presShell. */
static void InitializeRootDisplayport(nsIPresShell* aPresShell);
- /* Tell layout that we received the scroll offset update for the given view ID, so
- that it accepts future scroll offset updates from APZ. */
- static void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
- const uint32_t& aScrollGeneration);
-
/* Get the pres shell associated with the root content document enclosing |aContent|. */
static nsIPresShell* GetRootContentDocumentPresShellForContent(nsIContent* aContent);
/* Apply an "input transform" to the given |aInput| and return the transformed value.
The input transform applied is the one for the content element corresponding to
|aGuid|; this is populated in a previous call to UpdateCallbackTransform. See that
method's documentations for details.
This method additionally adjusts |aInput| by inversely scaling by the provided
--- a/gfx/layers/apz/util/APZEventState.cpp
+++ b/gfx/layers/apz/util/APZEventState.cpp
@@ -323,17 +323,17 @@ APZEventState::ProcessTouchEvent(const W
cancelEvent.mMessage = eTouchCancel;
cancelEvent.mFlags.mCancelable = false; // mMessage != eTouchCancel;
for (uint32_t i = 0; i < cancelEvent.mTouches.Length(); ++i) {
if (mozilla::dom::Touch* touch = cancelEvent.mTouches[i]) {
touch->convertToPointer = true;
}
}
nsEventStatus status;
- cancelEvent.widget->DispatchEvent(&cancelEvent, status);
+ cancelEvent.mWidget->DispatchEvent(&cancelEvent, status);
}
}
void
APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId)
{
--- a/gfx/layers/apz/util/ChromeProcessController.cpp
+++ b/gfx/layers/apz/util/ChromeProcessController.cpp
@@ -64,23 +64,16 @@ ChromeProcessController::RequestContentR
void
ChromeProcessController::PostDelayedTask(Task* aTask, int aDelayMs)
{
MessageLoop::current()->PostDelayedTask(FROM_HERE, aTask, aDelayMs);
}
void
-ChromeProcessController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
- const uint32_t& aScrollGeneration)
-{
- APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
-}
-
-void
ChromeProcessController::Destroy()
{
if (MessageLoop::current() != mUILoop) {
mUILoop->PostTask(
FROM_HERE,
NewRunnableMethod(this, &ChromeProcessController::Destroy));
return;
}
--- a/gfx/layers/apz/util/ChromeProcessController.h
+++ b/gfx/layers/apz/util/ChromeProcessController.h
@@ -35,19 +35,16 @@ protected:
public:
explicit ChromeProcessController(nsIWidget* aWidget, APZEventState* aAPZEventState, APZCTreeManager* aAPZCTreeManager);
~ChromeProcessController();
virtual void Destroy() override;
// GeckoContentController interface
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
virtual void PostDelayedTask(Task* aTask, int aDelayMs) override;
- virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
- const uint32_t& aScrollGeneration) override;
-
virtual void HandleDoubleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) override;
virtual void HandleSingleTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) override;
virtual void HandleLongTap(const mozilla::CSSPoint& aPoint, Modifiers aModifiers,
const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId) override;
virtual void NotifyAPZStateChange(const ScrollableLayerGuid& aGuid,
--- a/gfx/layers/ipc/APZChild.cpp
+++ b/gfx/layers/ipc/APZChild.cpp
@@ -90,24 +90,16 @@ APZChild::~APZChild()
bool
APZChild::RecvUpdateFrame(const FrameMetrics& aFrameMetrics)
{
return mBrowser->UpdateFrame(aFrameMetrics);
}
bool
-APZChild::RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
- const uint32_t& aScrollGeneration)
-{
- APZCCallbackHelper::AcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
- return true;
-}
-
-bool
APZChild::RecvHandleDoubleTap(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const ScrollableLayerGuid& aGuid)
{
mBrowser->HandleDoubleTap(aPoint, aModifiers, aGuid);
return true;
}
--- a/gfx/layers/ipc/APZChild.h
+++ b/gfx/layers/ipc/APZChild.h
@@ -23,19 +23,16 @@ class APZChild final : public PAPZChild
{
public:
static APZChild* Create(const dom::TabId& aTabId);
~APZChild();
virtual bool RecvUpdateFrame(const FrameMetrics& frame) override;
- virtual bool RecvAcknowledgeScrollUpdate(const ViewID& aScrollId,
- const uint32_t& aScrollGeneration) override;
-
virtual bool RecvHandleDoubleTap(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const ScrollableLayerGuid& aGuid) override;
virtual bool RecvHandleSingleTap(const CSSPoint& aPoint,
const Modifiers& aModifiers,
const ScrollableLayerGuid& aGuid,
const bool& aCallTakeFocusForClickFromTap) override;
--- a/gfx/layers/ipc/PAPZ.ipdl
+++ b/gfx/layers/ipc/PAPZ.ipdl
@@ -84,17 +84,16 @@ parent:
MaybeZoomConstraints aConstraints);
child:
async UpdateFrame(FrameMetrics frame);
// The following methods correspond to functions on the GeckoContentController
// interface in gfx/layers/apz/public/GeckoContentController.h. Refer to documentation
// in that file for these functions.
- async AcknowledgeScrollUpdate(ViewID aScrollId, uint32_t aScrollGeneration);
async HandleDoubleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid);
async HandleSingleTap(CSSPoint aPoint, Modifiers aModifiers, ScrollableLayerGuid aGuid, bool aCallTakeFocusForClickFromTap);
async HandleLongTap(CSSPoint point, Modifiers aModifiers, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
async NotifyAPZStateChange(ViewID aViewId, APZStateChange aChange, int aArg);
async NotifyFlushComplete();
async __delete__();
};
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -47,34 +47,16 @@ RemoteContentController::RequestContentR
{
MOZ_ASSERT(NS_IsMainThread());
if (CanSend()) {
Unused << SendUpdateFrame(aFrameMetrics);
}
}
void
-RemoteContentController::AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
- const uint32_t& aScrollGeneration)
-{
- if (MessageLoop::current() != mUILoop) {
- // We have to send this message from the "UI thread" (main
- // thread).
- mUILoop->PostTask(
- FROM_HERE,
- NewRunnableMethod(this, &RemoteContentController::AcknowledgeScrollUpdate,
- aScrollId, aScrollGeneration));
- return;
- }
- if (CanSend()) {
- Unused << SendAcknowledgeScrollUpdate(aScrollId, aScrollGeneration);
- }
-}
-
-void
RemoteContentController::HandleDoubleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid)
{
if (MessageLoop::current() != mUILoop) {
// We have to send this message from the "UI thread" (main
// thread).
mUILoop->PostTask(
--- a/gfx/layers/ipc/RemoteContentController.h
+++ b/gfx/layers/ipc/RemoteContentController.h
@@ -37,19 +37,16 @@ public:
explicit RemoteContentController(uint64_t aLayersId,
dom::TabParent* aBrowserParent);
virtual ~RemoteContentController();
// Needs to be called on the main thread.
virtual void RequestContentRepaint(const FrameMetrics& aFrameMetrics) override;
- virtual void AcknowledgeScrollUpdate(const FrameMetrics::ViewID& aScrollId,
- const uint32_t& aScrollGeneration) override;
-
virtual void HandleDoubleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) override;
virtual void HandleSingleTap(const CSSPoint& aPoint,
Modifiers aModifiers,
const ScrollableLayerGuid& aGuid) override;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -130,16 +130,19 @@ private:
};
// This is where DECL_GFX_PREF for each of the preferences should go.
// We will keep these in an alphabetical order to make it easier to see if
// a method accessing a pref already exists. Just add yours in the list.
// It's a short time fix, and will be removed after landing bug 1206637.
DECL_GFX_PREF(Live, "accessibility.monoaudio.enable", MonoAudio, bool, false);
+ DECL_GFX_PREF(Live, "media.resampling.enabled", AudioSinkResampling, bool, false);
+ DECL_GFX_PREF(Live, "media.resampling.rate", AudioSinkResampleRate, uint32_t, 48000);
+ DECL_GFX_PREF(Live, "media.forcestereo.enabled", AudioSinkForceStereo, bool, true);
// The apz prefs are explained in AsyncPanZoomController.cpp
DECL_GFX_PREF(Live, "apz.allow_checkerboarding", APZAllowCheckerboarding, bool, true);
DECL_GFX_PREF(Live, "apz.allow_immediate_handoff", APZAllowImmediateHandoff, bool, true);
DECL_GFX_PREF(Live, "apz.allow_zooming", APZAllowZooming, bool, false);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_angle", APZAxisBreakoutAngle, float, float(M_PI / 8.0) /* 22.5 degrees */);
DECL_GFX_PREF(Live, "apz.axis_lock.breakout_threshold", APZAxisBreakoutThreshold, float, 1.0f / 32.0f);
DECL_GFX_PREF(Live, "apz.axis_lock.direct_pan_angle", APZAllowedDirectPanAngle, float, float(M_PI / 3.0) /* 60 degrees */);
--- a/js/src/asmjs/Wasm.cpp
+++ b/js/src/asmjs/Wasm.cpp
@@ -76,16 +76,26 @@ Unify(ExprType one, ExprType two)
return two;
if (two == AnyType)
return one;
if (one == two)
return one;
return ExprType::Void;
}
+static bool
+IsI64Implemented()
+{
+#ifdef JS_CPU_X64
+ return true;
+#else
+ return false;
+#endif
+}
+
class FunctionDecoder
{
JSContext* cx_;
Decoder& d_;
ModuleGenerator& mg_;
FunctionGenerator& fg_;
uint32_t funcIndex_;
const ValTypeVector& locals_;
@@ -103,21 +113,19 @@ class FunctionDecoder
uint32_t funcIndex() const { return funcIndex_; }
const ValTypeVector& locals() const { return locals_; }
const DeclaredSig& sig() const { return mg_.funcSig(funcIndex_); }
bool fail(const char* str) {
return Fail(cx_, d_, str);
}
bool checkI64Support() {
-#ifdef JS_CPU_X64
+ if (!IsI64Implemented())
+ return fail("i64 NYI on this platform");
return true;
-#else
- return fail("i64 NYI on this platform");
-#endif
}
MOZ_WARN_UNUSED_RESULT bool pushBlock() {
return blocks_.append(AnyType);
}
ExprType popBlock() {
return blocks_.popCopy();
}
@@ -1068,24 +1076,26 @@ DecodeFunctionTable(JSContext* cx, Decod
}
return true;
}
static bool
CheckTypeForJS(JSContext* cx, Decoder& d, const Sig& sig)
{
+ bool allowI64 = IsI64Implemented() && JitOptions.wasmTestMode;
+
for (ValType argType : sig.args()) {
- if (argType == ValType::I64)
+ if (argType == ValType::I64 && !allowI64)
return Fail(cx, d, "cannot import/export i64 argument");
if (IsSimdType(argType))
return Fail(cx, d, "cannot import/export SIMD argument");
}
- if (sig.ret() == ExprType::I64)
+ if (sig.ret() == ExprType::I64 && !allowI64)
return Fail(cx, d, "cannot import/export i64 return type");
if (IsSimdType(sig.ret()))
return Fail(cx, d, "cannot import/export SIMD return type");
return true;
}
struct ImportName
--- a/js/src/asmjs/WasmIonCompile.cpp
+++ b/js/src/asmjs/WasmIonCompile.cpp
@@ -953,41 +953,65 @@ class FunctionCompiler
private:
static bool hasPushed(MBasicBlock* block)
{
uint32_t numPushed = block->stackDepth() - block->info().firstStackSlot();
MOZ_ASSERT(numPushed == 0 || numPushed == 1);
return numPushed;
}
+ static MDefinition* peekPushedDef(MBasicBlock* block)
+ {
+ MOZ_ASSERT(hasPushed(block));
+ return block->getSlot(block->stackDepth() - 1);
+ }
+
public:
void pushDef(MDefinition* def)
{
if (inDeadCode())
return;
MOZ_ASSERT(!hasPushed(curBlock_));
if (def && def->type() != MIRType_None)
curBlock_->push(def);
}
+ MDefinition* popDefIfPushed()
+ {
+ if (!hasPushed(curBlock_))
+ return nullptr;
+ MDefinition* def = curBlock_->pop();
+ MOZ_ASSERT(def->type() != MIRType_Value);
+ return def;
+ }
+
template <typename GetBlock>
void ensurePushInvariants(const GetBlock& getBlock, size_t numBlocks)
{
- // Preserve the invariant that, for every iterated MBasicBlock,
- // either: every MBasicBlock has a non-void pushed expression OR no
- // MBasicBlock has any pushed expression. This is required by
- // MBasicBlock::addPredecessor.
- bool allPushed = true;
-
- for (size_t i = 0; allPushed && i < numBlocks; i++)
- allPushed = hasPushed(getBlock(i));
+ // Preserve the invariant that, for every iterated MBasicBlock, either:
+ // every MBasicBlock has a pushed expression with the same type (to
+ // prevent creating phis with type Value) OR no MBasicBlock has any
+ // pushed expression. This is required by MBasicBlock::addPredecessor.
+ if (numBlocks < 2)
+ return;
+
+ MBasicBlock* block = getBlock(0);
+
+ bool allPushed = hasPushed(block);
+ if (allPushed) {
+ MIRType type = peekPushedDef(block)->type();
+ for (size_t i = 1; allPushed && i < numBlocks; i++) {
+ block = getBlock(i);
+ allPushed = hasPushed(block) && peekPushedDef(block)->type() == type;
+ }
+ }
if (!allPushed) {
for (size_t i = 0; i < numBlocks; i++) {
- MBasicBlock* block = getBlock(i);
+ block = getBlock(i);
if (hasPushed(block))
block->pop();
}
}
}
bool joinIf(MBasicBlock* joinBlock, BlockVector* blocks, MDefinition** def)
{
@@ -1029,20 +1053,17 @@ class FunctionCompiler
if (!goToNewBlock((*blocks)[0], &join))
return false;
for (size_t i = 1; i < blocks->length(); i++) {
if (!goToExistingBlock((*blocks)[i], join))
return false;
}
curBlock_ = join;
- if (hasPushed(curBlock_))
- *def = curBlock_->pop();
- else
- *def = nullptr;
+ *def = popDefIfPushed();
return true;
}
bool startBlock()
{
MOZ_ASSERT_IF(blockDepth_ < blockPatches_.length(), blockPatches_[blockDepth_].empty());
blockDepth_++;
return true;
@@ -1352,17 +1373,17 @@ class FunctionCompiler
MOZ_ASSERT(next);
prev->end(MGoto::New(alloc(), next));
return next->addPredecessor(alloc(), prev);
}
bool bindBranches(uint32_t absolute, MDefinition** def)
{
if (absolute >= blockPatches_.length() || blockPatches_[absolute].empty()) {
- *def = !inDeadCode() && hasPushed(curBlock_) ? curBlock_->pop() : nullptr;
+ *def = inDeadCode() ? nullptr : popDefIfPushed();
return true;
}
ControlFlowPatchVector& patches = blockPatches_[absolute];
auto getBlock = [&](size_t i) -> MBasicBlock* {
if (i < patches.length())
return patches[i].ins->block();
@@ -1395,17 +1416,17 @@ class FunctionCompiler
MOZ_ASSERT_IF(curBlock_, !curBlock_->isMarked());
for (uint32_t i = 0; i < join->numPredecessors(); i++)
join->getPredecessor(i)->unmark();
if (curBlock_ && !goToExistingBlock(curBlock_, join))
return false;
curBlock_ = join;
- *def = hasPushed(curBlock_) ? curBlock_->pop() : nullptr;
+ *def = popDefIfPushed();
patches.clear();
return true;
}
};
static bool
EmitLiteral(FunctionCompiler& f, ValType type, MDefinition** def)
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -1269,16 +1269,34 @@ Module::deoptimizeImportExit(uint32_t im
{
MOZ_ASSERT(dynamicallyLinked_);
const Import& import = imports()[importIndex];
ImportExit& exit = importToExit(import);
exit.code = code() + import.interpExitCodeOffset();
exit.baselineScript = nullptr;
}
+static JSObject*
+CreateI64Object(JSContext* cx, int64_t i64)
+{
+ RootedObject result(cx, JS_NewPlainObject(cx));
+ if (!result)
+ return nullptr;
+
+ RootedValue val(cx, Int32Value(uint32_t(i64)));
+ if (!JS_DefineProperty(cx, result, "low", val, JSPROP_ENUMERATE))
+ return nullptr;
+
+ val = Int32Value(uint32_t(i64 >> 32));
+ if (!JS_DefineProperty(cx, result, "high", val, JSPROP_ENUMERATE))
+ return nullptr;
+
+ return result;
+}
+
bool
Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
{
MOZ_ASSERT(dynamicallyLinked_);
const Export& exp = exports()[exportIndex];
// Enable/disable profiling in the Module to match the current global
@@ -1306,17 +1324,20 @@ Module::callExport(JSContext* cx, uint32
for (unsigned i = 0; i < exp.sig().args().length(); ++i) {
v = i < args.length() ? args[i] : UndefinedValue();
switch (exp.sig().arg(i)) {
case ValType::I32:
if (!ToInt32(cx, v, (int32_t*)&coercedArgs[i]))
return false;
break;
case ValType::I64:
- MOZ_CRASH("int64");
+ MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+ if (!ReadI64Object(cx, v, (int64_t*)&coercedArgs[i]))
+ return false;
+ break;
case ValType::F32:
if (!RoundFloat32(cx, v, (float*)&coercedArgs[i]))
return false;
break;
case ValType::F64:
if (!ToNumber(cx, v, (double*)&coercedArgs[i]))
return false;
break;
@@ -1369,85 +1390,125 @@ Module::callExport(JSContext* cx, uint32
// returned instead.
PlainObject* obj = NewBuiltinClassInstance<PlainObject>(cx);
if (!obj)
return false;
args.rval().set(ObjectValue(*obj));
return true;
}
- JSObject* simdObj;
+ void* retAddr = &coercedArgs[0];
+ JSObject* retObj = nullptr;
switch (exp.sig().ret()) {
case ExprType::Void:
args.rval().set(UndefinedValue());
break;
case ExprType::I32:
- args.rval().set(Int32Value(*(int32_t*)&coercedArgs[0]));
+ args.rval().set(Int32Value(*(int32_t*)retAddr));
break;
case ExprType::I64:
- MOZ_CRASH("int64");
+ MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+ retObj = CreateI64Object(cx, *(int64_t*)retAddr);
+ if (!retObj)
+ return false;
+ break;
case ExprType::F32:
+ // The entry stub has converted the F32 into a double for us.
case ExprType::F64:
- args.rval().set(NumberValue(*(double*)&coercedArgs[0]));
+ args.rval().set(NumberValue(*(double*)retAddr));
break;
case ExprType::I32x4:
- simdObj = CreateSimd<Int32x4>(cx, (int32_t*)&coercedArgs[0]);
- if (!simdObj)
+ retObj = CreateSimd<Int32x4>(cx, (int32_t*)retAddr);
+ if (!retObj)
return false;
- args.rval().set(ObjectValue(*simdObj));
break;
case ExprType::F32x4:
- simdObj = CreateSimd<Float32x4>(cx, (float*)&coercedArgs[0]);
- if (!simdObj)
+ retObj = CreateSimd<Float32x4>(cx, (float*)retAddr);
+ if (!retObj)
return false;
- args.rval().set(ObjectValue(*simdObj));
break;
case ExprType::B32x4:
- simdObj = CreateSimd<Bool32x4>(cx, (int32_t*)&coercedArgs[0]);
- if (!simdObj)
+ retObj = CreateSimd<Bool32x4>(cx, (int32_t*)retAddr);
+ if (!retObj)
return false;
- args.rval().set(ObjectValue(*simdObj));
break;
case ExprType::Limit:
MOZ_CRASH("Limit");
}
+ if (retObj)
+ args.rval().set(ObjectValue(*retObj));
+
return true;
}
bool
-Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Value* argv,
+Module::callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const uint64_t* argv,
MutableHandleValue rval)
{
MOZ_ASSERT(dynamicallyLinked_);
const Import& import = imports()[importIndex];
InvokeArgs args(cx);
if (!args.init(argc))
return false;
- for (size_t i = 0; i < argc; i++)
- args[i].set(argv[i]);
+ bool hasI64Arg = false;
+ MOZ_ASSERT(import.sig().args().length() == argc);
+ for (size_t i = 0; i < argc; i++) {
+ switch (import.sig().args()[i]) {
+ case ValType::I32:
+ args[i].set(Int32Value(*(int32_t*)&argv[i]));
+ break;
+ case ValType::F32:
+ args[i].set(JS::CanonicalizedDoubleValue(*(float*)&argv[i]));
+ break;
+ case ValType::F64:
+ args[i].set(JS::CanonicalizedDoubleValue(*(double*)&argv[i]));
+ break;
+ case ValType::I64: {
+ MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+ RootedObject obj(cx, CreateI64Object(cx, *(int64_t*)&argv[i]));
+ if (!obj)
+ return false;
+ args[i].set(ObjectValue(*obj));
+ hasI64Arg = true;
+ break;
+ }
+ case ValType::I32x4:
+ case ValType::F32x4:
+ case ValType::B32x4:
+ case ValType::Limit:
+ MOZ_CRASH("unhandled type in callImport");
+ }
+ }
RootedValue fval(cx, ObjectValue(*importToExit(import).fun));
RootedValue thisv(cx, UndefinedValue());
if (!Call(cx, fval, thisv, args, rval))
return false;
+ // Don't try to optimize if the function has at least one i64 arg or if
+ // it returns an int64. GenerateJitExit relies on this, as does the
+ // type inference code below in this function.
+ if (hasI64Arg || import.sig().ret() == ExprType::I64)
+ return true;
+
ImportExit& exit = importToExit(import);
// The exit may already have become optimized.
void* jitExitCode = code() + import.jitExitCodeOffset();
if (exit.code == jitExitCode)
return true;
// Test if the function is JIT compiled.
if (!exit.fun->hasScript())
return true;
+
JSScript* script = exit.fun->nonLazyScript();
if (!script->hasBaselineScript()) {
MOZ_ASSERT(!script->hasIonScript());
return true;
}
// Don't enable jit entry when we have a pending ion builder.
// Take the interpreter path which will link it and enable
@@ -1468,17 +1529,17 @@ Module::callImport(JSContext* cx, uint32
// the BaselineScript is discarded and when that happens the import exit is
// patched back.
if (!TypeScript::ThisTypes(script)->hasType(TypeSet::UndefinedType()))
return true;
for (uint32_t i = 0; i < exit.fun->nargs(); i++) {
TypeSet::Type type = TypeSet::UnknownType();
switch (import.sig().args()[i]) {
case ValType::I32: type = TypeSet::Int32Type(); break;
- case ValType::I64: MOZ_CRASH("NYI");
+ case ValType::I64: MOZ_CRASH("can't happen because of above guard");
case ValType::F32: type = TypeSet::DoubleType(); break;
case ValType::F64: type = TypeSet::DoubleType(); break;
case ValType::I32x4: MOZ_CRASH("NYI");
case ValType::F32x4: MOZ_CRASH("NYI");
case ValType::B32x4: MOZ_CRASH("NYI");
case ValType::Limit: MOZ_CRASH("Limit");
}
if (!TypeScript::ArgTypes(script, i)->hasType(type))
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -595,17 +595,17 @@ class Module : public mozilla::LinkedLis
bool callExport(JSContext* cx, uint32_t exportIndex, CallArgs args);
// Initially, calls to imports in wasm code call out through the generic
// callImport method. If the imported callee gets JIT compiled and the types
// match up, callImport will patch the code to instead call through a thunk
// directly into the JIT code. If the JIT code is released, the Module must
// be notified so it can go back to the generic callImport.
- bool callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const Value* argv,
+ bool callImport(JSContext* cx, uint32_t importIndex, unsigned argc, const uint64_t* argv,
MutableHandleValue rval);
void deoptimizeImportExit(uint32_t importIndex);
// At runtime, when $pc is in wasm function code (containsFunctionPC($pc)),
// $pc may be moved abruptly to interrupt() or outOfBounds() by a signal
// handler or SetContext() from another thread.
uint8_t* interrupt() const { MOZ_ASSERT(staticallyLinked_); return interrupt_; }
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -130,16 +130,18 @@ wasm::GenerateEntry(MacroAssembler& masm
masm.loadAsmJSHeapRegisterFromGlobalData();
// Put the 'argv' argument into a non-argument/return register so that we
// can use 'argv' while we fill in the arguments for the asm.js callee.
// Also, save 'argv' on the stack so that we can recover it after the call.
// Use a second non-argument/return register as temporary scratch.
Register argv = ABIArgGenerator::NonArgReturnReg0;
Register scratch = ABIArgGenerator::NonArgReturnReg1;
+ Register64 scratch64(scratch);
+
#if defined(JS_CODEGEN_X86)
masm.loadPtr(Address(masm.getStackPointer(), EntryFrameSize + masm.framePushed()), argv);
#else
masm.movePtr(IntArgReg0, argv);
#endif
masm.Push(argv);
// Save the stack pointer to the saved non-volatile registers. We will use
@@ -159,19 +161,23 @@ wasm::GenerateEntry(MacroAssembler& masm
masm.reserveStack(AlignBytes(StackArgBytes(sig.args()), AsmJSStackAlignment));
// Copy parameters out of argv and into the registers/stack-slots specified by
// the system ABI.
for (ABIArgValTypeIter iter(sig.args()); !iter.done(); iter++) {
unsigned argOffset = iter.index() * Module::SizeOfEntryArg;
Address src(argv, argOffset);
MIRType type = iter.mirType();
+ MOZ_ASSERT_IF(type == MIRType_Int64, JitOptions.wasmTestMode);
switch (iter->kind()) {
case ABIArg::GPR:
- masm.load32(src, iter->gpr());
+ if (type == MIRType_Int32)
+ masm.load32(src, iter->gpr());
+ else if (type == MIRType_Int64)
+ masm.load64(src, iter->gpr64());
break;
#ifdef JS_CODEGEN_REGISTER_PAIR
case ABIArg::GPR_PAIR:
MOZ_CRASH("wasm uses hardfp for function calls.");
break;
#endif
case ABIArg::FPU: {
static_assert(Module::SizeOfEntryArg >= jit::Simd128DataSize,
@@ -197,16 +203,20 @@ wasm::GenerateEntry(MacroAssembler& masm
break;
}
case ABIArg::Stack:
switch (type) {
case MIRType_Int32:
masm.load32(src, scratch);
masm.storePtr(scratch, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
break;
+ case MIRType_Int64:
+ masm.load64(src, scratch64);
+ masm.store64(scratch64, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
+ break;
case MIRType_Double:
masm.loadDouble(src, ScratchDoubleReg);
masm.storeDouble(ScratchDoubleReg, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
break;
case MIRType_Float32:
masm.loadFloat32(src, ScratchFloat32Reg);
masm.storeFloat32(ScratchFloat32Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
break;
@@ -240,20 +250,22 @@ wasm::GenerateEntry(MacroAssembler& masm
// Recover the 'argv' pointer which was saved before aligning the stack.
masm.Pop(argv);
// Store the return value in argv[0]
switch (sig.ret()) {
case ExprType::Void:
break;
case ExprType::I32:
- masm.storeValue(JSVAL_TYPE_INT32, ReturnReg, Address(argv, 0));
+ masm.store32(ReturnReg, Address(argv, 0));
break;
case ExprType::I64:
- MOZ_CRASH("no int64 in asm.js");
+ MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+ masm.store64(ReturnReg64, Address(argv, 0));
+ break;
case ExprType::F32:
masm.convertFloat32ToDouble(ReturnFloat32Reg, ReturnDoubleReg);
MOZ_FALLTHROUGH; // as ReturnDoubleReg now contains a Double
case ExprType::F64:
masm.canonicalizeDouble(ReturnDoubleReg);
masm.storeDouble(ReturnDoubleReg, Address(argv, 0));
break;
case ExprType::I32x4:
@@ -275,61 +287,95 @@ wasm::GenerateEntry(MacroAssembler& masm
masm.move32(Imm32(true), ReturnReg);
masm.ret();
offsets.end = masm.currentOffset();
return offsets;
}
+typedef bool ToValue;
+
static void
FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argOffset,
- unsigned offsetToCallerStackArgs, Register scratch)
+ unsigned offsetToCallerStackArgs, Register scratch, ToValue toValue)
{
+ Register64 scratch64(scratch);
for (ABIArgValTypeIter i(args); !i.done(); i++) {
Address dstAddr(masm.getStackPointer(), argOffset + i.index() * sizeof(Value));
+
+ MIRType type = i.mirType();
+ MOZ_ASSERT_IF(type == MIRType_Int64, JitOptions.wasmTestMode);
+
switch (i->kind()) {
case ABIArg::GPR:
- masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr);
+ if (type == MIRType_Int32) {
+ if (toValue)
+ masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr);
+ else
+ masm.store32(i->gpr(), dstAddr);
+ } else if (type == MIRType_Int64) {
+ // We can't box int64 into Values (yet).
+ if (toValue)
+ masm.breakpoint();
+ else
+ masm.store64(i->gpr64(), dstAddr);
+ } else {
+ MOZ_CRASH("unexpected input type?");
+ }
break;
#ifdef JS_CODEGEN_REGISTER_PAIR
case ABIArg::GPR_PAIR:
MOZ_CRASH("AsmJS uses hardfp for function calls.");
break;
#endif
case ABIArg::FPU: {
- MOZ_ASSERT(IsFloatingPointType(i.mirType()));
+ MOZ_ASSERT(IsFloatingPointType(type));
FloatRegister srcReg = i->fpu();
- if (i.mirType() == MIRType_Float32) {
- masm.convertFloat32ToDouble(i->fpu(), ScratchDoubleReg);
- srcReg = ScratchDoubleReg;
+ if (toValue) {
+ if (type == MIRType_Float32) {
+ masm.convertFloat32ToDouble(i->fpu(), ScratchDoubleReg);
+ srcReg = ScratchDoubleReg;
+ }
+ masm.canonicalizeDouble(srcReg);
}
- masm.canonicalizeDouble(srcReg);
masm.storeDouble(srcReg, dstAddr);
break;
}
case ABIArg::Stack:
- if (i.mirType() == MIRType_Int32) {
+ if (type == MIRType_Int32) {
Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
masm.load32(src, scratch);
- masm.storeValue(JSVAL_TYPE_INT32, scratch, dstAddr);
-#else
- masm.memIntToValue(src, dstAddr);
-#endif
+ if (toValue)
+ masm.storeValue(JSVAL_TYPE_INT32, scratch, dstAddr);
+ else
+ masm.store32(scratch, dstAddr);
+ } else if (type == MIRType_Int64) {
+ // We can't box int64 into Values (yet).
+ if (toValue) {
+ masm.breakpoint();
+ } else {
+ Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
+ masm.load64(src, scratch64);
+ masm.store64(scratch64, dstAddr);
+ }
} else {
- MOZ_ASSERT(IsFloatingPointType(i.mirType()));
+ MOZ_ASSERT(IsFloatingPointType(type));
Address src(masm.getStackPointer(), offsetToCallerStackArgs + i->offsetFromArgBase());
- if (i.mirType() == MIRType_Float32) {
- masm.loadFloat32(src, ScratchFloat32Reg);
- masm.convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
+ if (toValue) {
+ if (type == MIRType_Float32) {
+ masm.loadFloat32(src, ScratchFloat32Reg);
+ masm.convertFloat32ToDouble(ScratchFloat32Reg, ScratchDoubleReg);
+ } else {
+ masm.loadDouble(src, ScratchDoubleReg);
+ }
+ masm.canonicalizeDouble(ScratchDoubleReg);
} else {
masm.loadDouble(src, ScratchDoubleReg);
}
- masm.canonicalizeDouble(ScratchDoubleReg);
masm.storeDouble(ScratchDoubleReg, dstAddr);
}
break;
}
}
}
// Generate a stub that is called via the internal ABI derived from the
@@ -358,17 +404,17 @@ wasm::GenerateInterpExit(MacroAssembler&
unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, argOffset + argBytes);
ProfilingOffsets offsets;
GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets);
// Fill the argument array.
unsigned offsetToCallerStackArgs = sizeof(AsmJSFrame) + masm.framePushed();
Register scratch = ABIArgGenerator::NonArgReturnReg0;
- FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch);
+ FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch, ToValue(false));
// Prepare the arguments for the call to InvokeImport_*.
ABIArgMIRTypeIter i(invokeArgTypes);
// argument 0: importIndex
if (i->kind() == ABIArg::GPR)
masm.mov(ImmWord(importIndex), i->gpr());
else
@@ -399,20 +445,24 @@ wasm::GenerateInterpExit(MacroAssembler&
switch (sig.ret()) {
case ExprType::Void:
masm.call(SymbolicAddress::InvokeImport_Void);
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
break;
case ExprType::I32:
masm.call(SymbolicAddress::InvokeImport_I32);
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
- masm.unboxInt32(argv, ReturnReg);
+ masm.load32(argv, ReturnReg);
break;
case ExprType::I64:
- MOZ_CRASH("no int64 in asm.js");
+ MOZ_ASSERT(JitOptions.wasmTestMode);
+ masm.call(SymbolicAddress::InvokeImport_I64);
+ masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
+ masm.load64(argv, ReturnReg64);
+ break;
case ExprType::F32:
masm.call(SymbolicAddress::InvokeImport_F64);
masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw);
masm.loadDouble(argv, ReturnDoubleReg);
masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg);
break;
case ExprType::F64:
masm.call(SymbolicAddress::InvokeImport_F64);
@@ -504,17 +554,17 @@ wasm::GenerateJitExit(MacroAssembler& ma
argOffset += sizeof(size_t);
// 4. |this| value
masm.storeValue(UndefinedValue(), Address(masm.getStackPointer(), argOffset));
argOffset += sizeof(Value);
// 5. Fill the arguments
unsigned offsetToCallerStackArgs = jitFramePushed + sizeof(AsmJSFrame);
- FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch);
+ FillArgumentArray(masm, sig.args(), argOffset, offsetToCallerStackArgs, scratch, ToValue(true));
argOffset += sig.args().length() * sizeof(Value);
MOZ_ASSERT(argOffset == jitFrameBytes);
// 6. Jit code will clobber all registers, even non-volatiles. GlobalReg and
// HeapReg are removed from the general register set for asm.js code, so
// these will not have been saved by the caller like all other registers,
// so they must be explicitly preserved. Only save GlobalReg since
// HeapReg can be reloaded (from global data) after the call.
@@ -654,17 +704,21 @@ wasm::GenerateJitExit(MacroAssembler& ma
switch (sig.ret()) {
case ExprType::Void:
break;
case ExprType::I32:
masm.convertValueToInt32(JSReturnOperand, ReturnDoubleReg, ReturnReg, &oolConvert,
/* -0 check */ false);
break;
case ExprType::I64:
- MOZ_CRASH("no int64 in asm.js");
+ MOZ_ASSERT(JitOptions.wasmTestMode, "no int64 in asm.js/wasm");
+ // We don't expect int64 to be returned from Ion yet, because of a
+ // guard in callImport.
+ masm.breakpoint();
+ break;
case ExprType::F32:
masm.convertValueToFloat(JSReturnOperand, ReturnFloat32Reg, &oolConvert);
break;
case ExprType::F64:
masm.convertValueToDouble(JSReturnOperand, ReturnDoubleReg, &oolConvert);
break;
case ExprType::I32x4:
case ExprType::F32x4:
--- a/js/src/asmjs/WasmTextToBinary.cpp
+++ b/js/src/asmjs/WasmTextToBinary.cpp
@@ -632,17 +632,19 @@ class WasmAstModule : public WasmAstNode
}
bool declare(WasmAstSig&& sig, uint32_t* sigIndex) {
SigMap::AddPtr p = sigMap_.lookupForAdd(sig);
if (p) {
*sigIndex = p->value();
return true;
}
*sigIndex = sigs_.length();
- return sigs_.append(new (lifo_) WasmAstSig(WasmName(), Move(sig))) &&
+ auto* lifoSig = new (lifo_) WasmAstSig(WasmName(), Move(sig));
+ return lifoSig &&
+ sigs_.append(lifoSig) &&
sigMap_.add(p, sigs_.back(), *sigIndex);
}
bool append(WasmAstSig* sig) {
uint32_t sigIndex = sigs_.length();
if (!sigs_.append(sig))
return false;
SigMap::AddPtr p = sigMap_.lookupForAdd(*sig);
return p || sigMap_.add(p, sig, sigIndex);
@@ -2456,17 +2458,17 @@ ParseConst(WasmParseContext& c, WasmToke
switch (val.kind()) {
case WasmToken::Index:
return new(c.lifo) WasmAstConst(Val(uint64_t(val.index())));
case WasmToken::UnsignedInteger:
return new(c.lifo) WasmAstConst(Val(val.uint()));
case WasmToken::SignedInteger:
return new(c.lifo) WasmAstConst(Val(uint64_t(val.sint())));
case WasmToken::NegativeZero:
- return new(c.lifo) WasmAstConst(Val(uint32_t(0)));
+ return new(c.lifo) WasmAstConst(Val(uint64_t(0)));
default:
break;
}
break;
}
case ValType::F32: {
float result;
if (!ParseFloatLiteral(c, val, &result))
--- a/js/src/asmjs/WasmTypes.cpp
+++ b/js/src/asmjs/WasmTypes.cpp
@@ -110,62 +110,105 @@ CoerceInPlace_ToNumber(MutableHandleValu
val.set(DoubleValue(dbl));
return true;
}
// Use an int32_t return type instead of bool since bool does not have a
// specified width and the caller is assuming a word-sized return.
static int32_t
-InvokeImport_Void(int32_t importIndex, int32_t argc, Value* argv)
+InvokeImport_Void(int32_t importIndex, int32_t argc, uint64_t* argv)
{
WasmActivation* activation = JSRuntime::innermostWasmActivation();
JSContext* cx = activation->cx();
RootedValue rval(cx);
return activation->module().callImport(cx, importIndex, argc, argv, &rval);
}
// Use an int32_t return type instead of bool since bool does not have a
// specified width and the caller is assuming a word-sized return.
static int32_t
-InvokeImport_I32(int32_t importIndex, int32_t argc, Value* argv)
+InvokeImport_I32(int32_t importIndex, int32_t argc, uint64_t* argv)
{
WasmActivation* activation = JSRuntime::innermostWasmActivation();
JSContext* cx = activation->cx();
RootedValue rval(cx);
if (!activation->module().callImport(cx, importIndex, argc, argv, &rval))
return false;
int32_t i32;
if (!ToInt32(cx, rval, &i32))
return false;
- argv[0] = Int32Value(i32);
+ argv[0] = i32;
+ return true;
+}
+
+bool
+js::wasm::ReadI64Object(JSContext* cx, HandleValue v, int64_t* i64)
+{
+ if (!v.isObject()) {
+ JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_WASM_FAIL,
+ "i64 JS value must be an object");
+ return false;
+ }
+
+ RootedObject obj(cx, &v.toObject());
+
+ int32_t* i32 = (int32_t*)i64;
+
+ RootedValue val(cx);
+ if (!JS_GetProperty(cx, obj, "low", &val))
+ return false;
+ if (!ToInt32(cx, val, &i32[0]))
+ return false;
+
+ if (!JS_GetProperty(cx, obj, "high", &val))
+ return false;
+ if (!ToInt32(cx, val, &i32[1]))
+ return false;
+
+ return true;
+}
+
+static int32_t
+InvokeImport_I64(int32_t importIndex, int32_t argc, uint64_t* argv)
+{
+ WasmActivation* activation = JSRuntime::innermostWasmActivation();
+ JSContext* cx = activation->cx();
+
+ RootedValue rval(cx);
+ if (!activation->module().callImport(cx, importIndex, argc, argv, &rval))
+ return false;
+
+ if (!ReadI64Object(cx, rval, (int64_t*)argv))
+ return false;
+
return true;
}
// Use an int32_t return type instead of bool since bool does not have a
// specified width and the caller is assuming a word-sized return.
static int32_t
-InvokeImport_F64(int32_t importIndex, int32_t argc, Value* argv)
+InvokeImport_F64(int32_t importIndex, int32_t argc, uint64_t* argv)
{
WasmActivation* activation = JSRuntime::innermostWasmActivation();
JSContext* cx = activation->cx();
RootedValue rval(cx);
if (!activation->module().callImport(cx, importIndex, argc, argv, &rval))
return false;
double dbl;
if (!ToNumber(cx, rval, &dbl))
return false;
- argv[0] = DoubleValue(dbl);
+ ((double*)argv)[0] = dbl;
return true;
}
template <class F>
static inline void*
FuncCast(F* pf, ABIFunctionType type)
{
void *pv = JS_FUNC_TO_DATA_PTR(void*, pf);
@@ -196,16 +239,18 @@ wasm::AddressOf(SymbolicAddress imm, Exc
case SymbolicAddress::UnreachableTrap:
return FuncCast(UnreachableTrap, Args_General0);
case SymbolicAddress::HandleExecutionInterrupt:
return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
case SymbolicAddress::InvokeImport_Void:
return FuncCast(InvokeImport_Void, Args_General3);
case SymbolicAddress::InvokeImport_I32:
return FuncCast(InvokeImport_I32, Args_General3);
+ case SymbolicAddress::InvokeImport_I64:
+ return FuncCast(InvokeImport_I64, Args_General3);
case SymbolicAddress::InvokeImport_F64:
return FuncCast(InvokeImport_F64, Args_General3);
case SymbolicAddress::CoerceInPlace_ToInt32:
return FuncCast(CoerceInPlace_ToInt32, Args_General1);
case SymbolicAddress::CoerceInPlace_ToNumber:
return FuncCast(CoerceInPlace_ToNumber, Args_General1);
case SymbolicAddress::ToInt32:
return FuncCast<int32_t (double)>(JS::ToInt32, Args_Int_Double);
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -534,25 +534,30 @@ enum class SymbolicAddress
ReportOverRecursed,
OnOutOfBounds,
OnImpreciseConversion,
BadIndirectCall,
UnreachableTrap,
HandleExecutionInterrupt,
InvokeImport_Void,
InvokeImport_I32,
+ InvokeImport_I64,
InvokeImport_F64,
CoerceInPlace_ToInt32,
CoerceInPlace_ToNumber,
Limit
};
void*
AddressOf(SymbolicAddress imm, ExclusiveContext* cx);
+// Extracts low and high from an int64 object {low: int32, high: int32}, for
+// testing purposes mainly.
+bool ReadI64Object(JSContext* cx, HandleValue v, int64_t* val);
+
// A wasm::JumpTarget represents one of a special set of stubs that can be
// jumped to from any function. Because wasm modules can be larger than the
// range of a plain jump, these potentially out-of-range jumps must be recorded
// and patched specially by the MacroAssembler and ModuleGenerator.
enum class JumpTarget
{
StackOverflow,
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -41,17 +41,17 @@ class FullParseHandler
return node;
}
/*
* If this is a full parse to construct the bytecode for a function that
* was previously lazily parsed, that lazy function and the current index
* into its inner functions. We do not want to reparse the inner functions.
*/
- LazyScript * const lazyOuterFunction_;
+ const Rooted<LazyScript*> lazyOuterFunction_;
size_t lazyInnerFunctionIndex;
const TokenPos& pos() {
return tokenStream.currentToken().pos;
}
inline ParseNode* makeAssignmentFromArg(ParseNode* arg, ParseNode* lhs, ParseNode* rhs);
inline void replaceLastFunctionArgument(ParseNode* funcpn, ParseNode* pn);
@@ -98,17 +98,17 @@ class FullParseHandler
isParenthesizedDestructuringPattern(node);
}
FullParseHandler(ExclusiveContext* cx, LifoAlloc& alloc,
TokenStream& tokenStream, Parser<SyntaxParseHandler>* syntaxParser,
LazyScript* lazyOuterFunction)
: allocator(cx, alloc),
tokenStream(tokenStream),
- lazyOuterFunction_(lazyOuterFunction),
+ lazyOuterFunction_(cx, lazyOuterFunction),
lazyInnerFunctionIndex(0),
syntaxParser(syntaxParser)
{}
static ParseNode* null() { return nullptr; }
ParseNode* freeTree(ParseNode* pn) { return allocator.freeTree(pn); }
void prepareNodeForMutation(ParseNode* pn) { return allocator.prepareNodeForMutation(pn); }
--- a/js/src/gc/GCInternals.h
+++ b/js/src/gc/GCInternals.h
@@ -122,16 +122,17 @@ CheckHashTablesAfterMovingGC(JSRuntime*
struct MovingTracer : JS::CallbackTracer
{
explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {}
void onObjectEdge(JSObject** objp) override;
void onShapeEdge(Shape** shapep) override;
void onStringEdge(JSString** stringp) override;
void onScriptEdge(JSScript** scriptp) override;
+ void onLazyScriptEdge(LazyScript** lazyp) override;
void onChild(const JS::GCCellPtr& thing) override {
MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell()));
}
#ifdef DEBUG
TracerKind getTracerKind() const override { return TracerKind::Moving; }
#endif
};
--- a/js/src/jit-test/lib/wasm.js
+++ b/js/src/jit-test/lib/wasm.js
@@ -6,8 +6,47 @@ load(libdir + "asserts.js");
function wasmEvalText(str, imports) {
return Wasm.instantiateModule(wasmTextToBinary(str), imports).exports;
}
function mismatchError(actual, expect) {
var str = `type mismatch: expression has type ${actual} but expected ${expect}`;
return RegExp(str);
}
+
+function hasI64() {
+ return getBuildConfiguration().x64;
+}
+
+// Assert that the expected value is equal to the int64 value, as passed by
+// Baldr with --wasm-extra-tests {low: int32, high: int32}.
+// - if the expected value is in the int32 range, it can be just a number.
+// - otherwise, an object with the properties "high" and "low".
+function assertEqI64(obj, expect) {
+ assertEq(typeof obj, 'object');
+ assertEq(typeof expect === 'object' || typeof expect === 'number', true);
+
+ let {low, high} = obj;
+ if (typeof expect === 'number') {
+ assertEq(expect, expect | 0, "in int32 range");
+ assertEq(low, expect | 0, "low");
+ assertEq(high, expect < 0 ? -1 : 0), "high";
+ } else {
+ assertEq(typeof expect.low, 'number');
+ assertEq(typeof expect.high, 'number');
+ assertEq(low, expect.low | 0, "low");
+ assertEq(high, expect.high | 0, "high");
+ }
+}
+
+function createI64(val) {
+ let ret;
+ if (typeof val === 'number') {
+ assertEq(val, val|0, "number input to createI64 must be an int32");
+ ret = { low: val, high: val < 0 ? -1 : 0 };
+ } else {
+ assertEq(typeof val, 'string');
+ assertEq(val.slice(0, 2), "0x");
+ val = val.slice(2).padStart(16, '0');
+ ret = { low: parseInt(val.slice(8, 16), 16), high: parseInt(val.slice(0, 8), 16) };
+ }
+ return ret;
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1263884.js
@@ -0,0 +1,10 @@
+if (!('oomTest' in this))
+ quit();
+
+oomTest(function() {
+ eval(`
+ var argObj = function () { return arguments }()
+ for (var p in argObj);
+ delete argObj.callee;
+ `);
+});
--- a/js/src/jit-test/tests/wasm/basic-const.js
+++ b/js/src/jit-test/tests/wasm/basic-const.js
@@ -1,15 +1,15 @@
load(libdir + "wasm.js");
-if (!wasmIsSupported())
- quit();
-
function testConst(type, str, expect) {
- assertEq(wasmEvalText('(module (func (result ' + type + ') (' + type + '.const ' + str + ')) (export "" 0))')(), expect);
+ if (type === 'i64')
+ assertEqI64(wasmEvalText('(module (func (result i64) (i64.const ' + str + ')) (export "" 0))')(), expect);
+ else
+ assertEq(wasmEvalText('(module (func (result ' + type + ') (' + type + '.const ' + str + ')) (export "" 0))')(), expect);
}
function testConstError(type, str) {
// For now at least, we don't distinguish between parse errors and OOMs.
assertErrorMessage(() => wasmEvalText('(module (func (result ' + type + ') (' + type + '.const ' + str + ')) (export "" 0))')(), Error, /parsing wasm text/);
}
testConst('i32', '0', 0);
@@ -21,29 +21,69 @@ testConst('i32', '-0x23', -35);
testConst('i32', '2147483647', 2147483647);
testConst('i32', '4294967295', -1);
testConst('i32', '-2147483648', -2147483648);
testConst('i32', '0x7fffffff', 2147483647);
testConst('i32', '0x80000000', -2147483648);
testConst('i32', '-0x80000000', -2147483648);
testConst('i32', '0xffffffff', -1);
-//testConst('i64', '0', 0); // TODO: NYI
-//testConst('i64', '-0', 0); // TODO: NYI
-//testConst('i64', '23', 23); // TODO: NYI
-//testConst('i64', '-23', -23); // TODO: NYI
-//testConst('i64', '0x23', 35); // TODO: NYI
-//testConst('i64', '-0x23', -35); // TODO: NYI
-//testConst('i64', '9223372036854775807', 9223372036854775807); // TODO: NYI
-//testConst('i64', '18446744073709551615', -1); // TODO: NYI
-//testConst('i64', '-9223372036854775808', -9223372036854775808); // TODO: NYI
-//testConst('i64', '0x7fffffffffffffff', 9223372036854775807); // TODO: NYI
-//testConst('i64', '0x8000000000000000', -9223372036854775808); // TODO: NYI
-//testConst('i64', '-0x8000000000000000', -9223372036854775808); // TODO: NYI
-//testConst('i64', '0xffffffffffffffff', -1); // TODO: NYI
+if (hasI64()) {
+
+ assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /cannot .* i64/);
+
+ setJitCompilerOption('wasm.test-mode', 1);
+
+ testConst('i64', '0', 0);
+ testConst('i64', '-0', 0);
+
+ testConst('i64', '23', 23);
+ testConst('i64', '-23', -23);
+
+ testConst('i64', '0x23', 35);
+ testConst('i64', '-0x23', -35);
+
+ testConst('i64', '-0x1', -1);
+ testConst('i64', '-1', -1);
+ testConst('i64', '0xffffffffffffffff', -1);
+
+ testConst('i64', '0xdeadc0de', {low: 0xdeadc0de, high: 0x0});
+ testConst('i64', '0x1337c0de00000000', {low: 0x0, high: 0x1337c0de});
+
+ testConst('i64', '0x0102030405060708', {low: 0x05060708, high: 0x01020304});
+ testConst('i64', '-0x0102030405060708', {low: -0x05060708, high: -0x01020305});
+
+ // INT64_MAX
+ testConst('i64', '9223372036854775807', {low: 0xffffffff, high: 0x7fffffff});
+ testConst('i64', '0x7fffffffffffffff', {low: 0xffffffff, high: 0x7fffffff});
+
+ // INT64_MAX + 1
+ testConst('i64', '9223372036854775808', {low: 0x00000000, high: 0x80000000});
+ testConst('i64', '0x8000000000000000', {low: 0x00000000, high: 0x80000000});
+
+ // UINT64_MAX
+ testConst('i64', '18446744073709551615', {low: 0xffffffff, high: 0xffffffff});
+
+ // INT64_MIN
+ testConst('i64', '-9223372036854775808', {low: 0x00000000, high: 0x80000000});
+ testConst('i64', '-0x8000000000000000', {low: 0x00000000, high: 0x80000000});
+
+ // INT64_MIN - 1
+ testConstError('i64', '-9223372036854775809');
+
+ testConstError('i64', '');
+ testConstError('i64', '0.0');
+ testConstError('i64', 'not an i64');
+
+ setJitCompilerOption('wasm.test-mode', 0);
+
+ assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /cannot .* i64/);
+} else {
+ assertErrorMessage(() => wasmEvalText('(module (func (result i64) (i64.const 0)) (export "" 0))'), TypeError, /NYI/);
+}
testConst('f32', '0.0', 0.0);
testConst('f32', '-0', -0.0);
testConst('f32', '-0.0', -0.0);
testConst('f32', '0x0.0', 0.0);
testConst('f32', '-0x0.0', -0.0);
testConst('f32', '-0x0', -0.0);
testConst('f32', '0x0.0p0', 0.0);
@@ -210,22 +250,16 @@ testConst('f64', '0x24c6.004d0deaa3p-103
testConst('f64', '0', 0);
testConstError('i32', '');
testConstError('i32', '0.0');
testConstError('i32', 'not an i32');
testConstError('i32', '4294967296');
testConstError('i32', '-2147483649');
-//testConstError('i64', ''); // TODO: NYI
-//testConstError('i64', '0.0'); // TODO: NYI
-//testConstError('i64', 'not an i64'); // TODO: NYI
-//testConstError('i64', '9223372036854775808'); // TODO: NYI
-//testConstError('i64', '-9223372036854775809'); // TODO: NYI
-
testConstError('f32', '');
testConstError('f32', 'not an f32');
testConstError('f32', 'nan:');
testConstError('f32', 'nan:0');
testConstError('f32', 'nan:0x');
testConstError('f32', 'nan:0x0');
testConstError('f64', '');
--- a/js/src/jit-test/tests/wasm/basic-conversion.js
+++ b/js/src/jit-test/tests/wasm/basic-conversion.js
@@ -1,55 +1,61 @@
load(libdir + "wasm.js");
-if (!wasmIsSupported())
- quit();
-
function testConversion(resultType, opcode, paramType, op, expect) {
if (paramType === 'i64') {
// i64 cannot be imported, so we use a wrapper function.
assertEq(wasmEvalText(`(module
(func (param i64) (result ${resultType}) (${resultType}.${opcode}/i64 (get_local 0)))
- (func (result ${resultType}) (call 0 (i64.const ${op})))
- (export "" 1))`)(), expect);
+ (export "" 0))`)(createI64(op)), expect);
// The same, but now the input is a constant.
assertEq(wasmEvalText(`(module
(func (result ${resultType}) (${resultType}.${opcode}/i64 (i64.const ${op})))
(export "" 0))`)(), expect);
} else if (resultType === 'i64') {
- assertEq(wasmEvalText(`(module
+ assertEqI64(wasmEvalText(`(module
(func (param ${paramType}) (result i64) (i64.${opcode}/${paramType} (get_local 0)))
- (func (result i32) (i64.eq (i64.const ${expect}) (call 0 (${paramType}.const ${op}))))
- (export "" 1))`)(), 1);
+ (export "" 0))`)(op), createI64(expect));
// The same, but now the input is a constant.
- assertEq(wasmEvalText(`(module
+ assertEqI64(wasmEvalText(`(module
(func (result i64) (i64.${opcode}/${paramType} (${paramType}.const ${op})))
- (func (result i32) (i64.eq (i64.const ${expect}) (call 0)))
- (export "" 1))`)(), 1);
+ (export "" 0))`)(), createI64(expect));
} else {
assertEq(wasmEvalText('(module (func (param ' + paramType + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))) (export "" 0))')(op), expect);
}
- // TODO: i64 NYI
- for (var bad of ['i32', 'f32', 'f64']) {
- if (bad != resultType)
- assertErrorMessage(() => wasmEvalText('(module (func (param ' + paramType + ') (result ' + bad + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))))'),
- TypeError,
- mismatchError(resultType, bad)
- );
- if (bad != paramType)
- assertErrorMessage(() => wasmEvalText('(module (func (param ' + bad + ') (result ' + resultType + ') (' + resultType + '.' + opcode + '/' + paramType + ' (get_local 0))))'),
- TypeError,
- mismatchError(bad, paramType)
- );
+ let formerWasmExtraTests = getJitCompilerOptions()['wasm.test-mode'];
+ setJitCompilerOption('wasm.test-mode', 1);
+ for (var bad of ['i32', 'f32', 'f64', 'i64']) {
+ if (bad === 'i64' && !hasI64())
+ continue;
+
+ if (bad != resultType) {
+ assertErrorMessage(
+ () => wasmEvalText(`(module (func (param ${paramType}) (result ${bad}) (${resultType}.${opcode}/${paramType} (get_local 0))))`),
+ TypeError,
+ mismatchError(resultType, bad)
+ );
+ }
+
+ if (bad != paramType) {
+ assertErrorMessage(
+ () => wasmEvalText(`(module (func (param ${bad}) (result ${resultType}) (${resultType}.${opcode}/${paramType} (get_local 0))))`),
+ TypeError,
+ mismatchError(bad, paramType)
+ );
+ }
}
+ setJitCompilerOption('wasm.test-mode', formerWasmExtraTests);
}
-if (getBuildConfiguration().x64) {
- testConversion('i32', 'wrap', 'i64', 4294967336, 40);
+if (hasI64()) {
+ setJitCompilerOption('wasm.test-mode', 1);
+
+ testConversion('i32', 'wrap', 'i64', '0x100000028', 40);
testConversion('i32', 'wrap', 'i64', -10, -10);
testConversion('i32', 'wrap', 'i64', "0xffffffff7fffffff", 0x7fffffff);
testConversion('i32', 'wrap', 'i64', "0xffffffff00000000", 0);
testConversion('i32', 'wrap', 'i64', "0xfffffffeffffffff", -1);
testConversion('i32', 'wrap', 'i64', "0x1234567801abcdef", 0x01abcdef);
testConversion('i32', 'wrap', 'i64', "0x8000000000000002", 2);
testConversion('i64', 'extend_s', 'i32', 0, 0);
@@ -63,101 +69,101 @@ if (getBuildConfiguration().x64) {
testConversion('i64', 'extend_u', 'i32', -567, "0x00000000fffffdc9");
testConversion('i64', 'extend_u', 'i32', -1, "0x00000000ffffffff");
testConversion('i64', 'extend_u', 'i32', 0x7fffffff, "0x000000007fffffff");
testConversion('i64', 'extend_u', 'i32', 0x80000000, "0x0000000080000000");
testConversion('f32', 'convert_s', 'i64', 1, 1.0);
testConversion('f32', 'convert_s', 'i64', -1, -1.0);
testConversion('f32', 'convert_s', 'i64', 0, 0.0);
- testConversion('f32', 'convert_s', 'i64', "9223372036854775807", 9223372036854775807.0);
- testConversion('f32', 'convert_s', 'i64', "-9223372036854775808", -9223372036854775808.0);
- testConversion('f32', 'convert_s', 'i64', "314159265358979", 314159275180032.0);
+ testConversion('f32', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+ testConversion('f32', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
+ testConversion('f32', 'convert_s', 'i64', "0x11db9e76a2483", 314159275180032.0);
testConversion('f64', 'convert_s', 'i64', 1, 1.0);
testConversion('f64', 'convert_s', 'i64', -1, -1.0);
testConversion('f64', 'convert_s', 'i64', 0, 0.0);
- testConversion('f64', 'convert_s', 'i64', "9223372036854775807", 9223372036854775807.0);
- testConversion('f64', 'convert_s', 'i64', "-9223372036854775808", -9223372036854775808.0);
- testConversion('f64', 'convert_s', 'i64', "4669201609102990", 4669201609102990);
+ testConversion('f64', 'convert_s', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+ testConversion('f64', 'convert_s', 'i64', "0x8000000000000000", -9223372036854775808.0);
+ testConversion('f64', 'convert_s', 'i64', "0x10969d374b968e", 4669201609102990);
testConversion('f32', 'convert_u', 'i64', 1, 1.0);
testConversion('f32', 'convert_u', 'i64', 0, 0.0);
- testConversion('f32', 'convert_u', 'i64', "9223372036854775807", 9223372036854775807.0);
- testConversion('f32', 'convert_u', 'i64', "-9223372036854775808", 9223372036854775808.0);
+ testConversion('f32', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+ testConversion('f32', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
testConversion('f32', 'convert_u', 'i64', -1, 18446744073709551616.0);
testConversion('f32', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462598732840000.0);
testConversion('f64', 'convert_u', 'i64', 1, 1.0);
testConversion('f64', 'convert_u', 'i64', 0, 0.0);
- testConversion('f64', 'convert_u', 'i64', "9223372036854775807", 9223372036854775807.0);
- testConversion('f64', 'convert_u', 'i64', "-9223372036854775808", 9223372036854775808.0);
+ testConversion('f64', 'convert_u', 'i64', "0x7fffffffffffffff", 9223372036854775807.0);
+ testConversion('f64', 'convert_u', 'i64', "0x8000000000000000", 9223372036854775808.0);
testConversion('f64', 'convert_u', 'i64', -1, 18446744073709551616.0);
testConversion('f64', 'convert_u', 'i64', "0xffff0000ffff0000", 18446462603027743000.0);
testConversion('i64', 'trunc_s', 'f64', 0.0, 0);
testConversion('i64', 'trunc_s', 'f64', "-0.0", 0);
testConversion('i64', 'trunc_s', 'f64', 1.0, 1);
testConversion('i64', 'trunc_s', 'f64', 1.1, 1);
testConversion('i64', 'trunc_s', 'f64', 1.5, 1);
testConversion('i64', 'trunc_s', 'f64', 1.99, 1);
testConversion('i64', 'trunc_s', 'f64', 40.1, 40);
testConversion('i64', 'trunc_s', 'f64', -1.0, -1);
testConversion('i64', 'trunc_s', 'f64', -1.1, -1);
testConversion('i64', 'trunc_s', 'f64', -1.5, -1);
testConversion('i64', 'trunc_s', 'f64', -1.99, -1);
testConversion('i64', 'trunc_s', 'f64', -2.0, -2);
- testConversion('i64', 'trunc_s', 'f64', 4294967296.1, "4294967296");
- testConversion('i64', 'trunc_s', 'f64', -4294967296.8, "-4294967296");
- testConversion('i64', 'trunc_s', 'f64', 9223372036854774784.8, "9223372036854774784");
- testConversion('i64', 'trunc_s', 'f64', -9223372036854775808.3, "-9223372036854775808");
+ testConversion('i64', 'trunc_s', 'f64', 4294967296.1, "0x100000000");
+ testConversion('i64', 'trunc_s', 'f64', -4294967296.8, "0xffffffff00000000");
+ testConversion('i64', 'trunc_s', 'f64', 9223372036854774784.8, "0x7ffffffffffffc00");
+ testConversion('i64', 'trunc_s', 'f64', -9223372036854775808.3, "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f64', 0.0, 0);
testConversion('i64', 'trunc_u', 'f64', "-0.0", 0);
testConversion('i64', 'trunc_u', 'f64', 1.0, 1);
testConversion('i64', 'trunc_u', 'f64', 1.1, 1);
testConversion('i64', 'trunc_u', 'f64', 1.5, 1);
testConversion('i64', 'trunc_u', 'f64', 1.99, 1);
testConversion('i64', 'trunc_u', 'f64', -0.9, 0);
testConversion('i64', 'trunc_u', 'f64', 40.1, 40);
testConversion('i64', 'trunc_u', 'f64', 4294967295, "0xffffffff");
- testConversion('i64', 'trunc_u', 'f64', 4294967296.1, "4294967296");
- testConversion('i64', 'trunc_u', 'f64', 1e8, "100000000");
- testConversion('i64', 'trunc_u', 'f64', 1e16, "10000000000000000");
- testConversion('i64', 'trunc_u', 'f64', 9223372036854775808, "-9223372036854775808");
+ testConversion('i64', 'trunc_u', 'f64', 4294967296.1, "0x100000000");
+ testConversion('i64', 'trunc_u', 'f64', 1e8, "0x5f5e100");
+ testConversion('i64', 'trunc_u', 'f64', 1e16, "0x2386f26fc10000");
+ testConversion('i64', 'trunc_u', 'f64', 9223372036854775808, "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f64', 18446744073709549568.1, -2048);
testConversion('i64', 'trunc_s', 'f32', 0.0, 0);
testConversion('i64', 'trunc_s', 'f32', "-0.0", 0);
testConversion('i64', 'trunc_s', 'f32', 1.0, 1);
testConversion('i64', 'trunc_s', 'f32', 1.1, 1);
testConversion('i64', 'trunc_s', 'f32', 1.5, 1);
testConversion('i64', 'trunc_s', 'f32', 1.99, 1);
testConversion('i64', 'trunc_s', 'f32', 40.1, 40);
testConversion('i64', 'trunc_s', 'f32', -1.0, -1);
testConversion('i64', 'trunc_s', 'f32', -1.1, -1);
testConversion('i64', 'trunc_s', 'f32', -1.5, -1);
testConversion('i64', 'trunc_s', 'f32', -1.99, -1);
testConversion('i64', 'trunc_s', 'f32', -2.0, -2);
- testConversion('i64', 'trunc_s', 'f32', 4294967296.1, "4294967296");
- testConversion('i64', 'trunc_s', 'f32', -4294967296.8, "-4294967296");
- testConversion('i64', 'trunc_s', 'f32', 9223371487098961920.0, "9223371487098961920");
- testConversion('i64', 'trunc_s', 'f32', -9223372036854775808.3, "-9223372036854775808");
+ testConversion('i64', 'trunc_s', 'f32', 4294967296.1, "0x100000000");
+ testConversion('i64', 'trunc_s', 'f32', -4294967296.8, "0xffffffff00000000");
+ testConversion('i64', 'trunc_s', 'f32', 9223371487098961920.0, "0x7fffff8000000000");
+ testConversion('i64', 'trunc_s', 'f32', -9223372036854775808.3, "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f32', 0.0, 0);
testConversion('i64', 'trunc_u', 'f32', "-0.0", 0);
testConversion('i64', 'trunc_u', 'f32', 1.0, 1);
testConversion('i64', 'trunc_u', 'f32', 1.1, 1);
testConversion('i64', 'trunc_u', 'f32', 1.5, 1);
testConversion('i64', 'trunc_u', 'f32', 1.99, 1);
testConversion('i64', 'trunc_u', 'f32', -0.9, 0);
testConversion('i64', 'trunc_u', 'f32', 40.1, 40);
- testConversion('i64', 'trunc_u', 'f32', 1e8, "100000000");
- testConversion('i64', 'trunc_u', 'f32', 4294967296, "4294967296");
- testConversion('i64', 'trunc_u', 'f32', 18446742974197923840.0, "-1099511627776");
+ testConversion('i64', 'trunc_u', 'f32', 1e8, "0x5f5e100");
+ testConversion('i64', 'trunc_u', 'f32', 4294967296, "0x100000000");
+ testConversion('i64', 'trunc_u', 'f32', 18446742974197923840.0, "0xffffff0000000000");
// TODO: these should trap.
testConversion('i64', 'trunc_s', 'f64', 9223372036854775808.0, "0x8000000000000000");
testConversion('i64', 'trunc_s', 'f64', -9223372036854777856.0, "0x8000000000000000");
testConversion('i64', 'trunc_s', 'f64', "nan", "0x8000000000000000");
testConversion('i64', 'trunc_s', 'f64', "infinity", "0x8000000000000000");
testConversion('i64', 'trunc_s', 'f64', "-infinity", "0x8000000000000000");
@@ -174,18 +180,20 @@ if (getBuildConfiguration().x64) {
testConversion('i64', 'trunc_s', 'f32', "-infinity", "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f32', 18446744073709551616.0, "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f32', -1, "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f32', "nan", "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f32', "infinity", "0x8000000000000000");
testConversion('i64', 'trunc_u', 'f32', "-infinity", "0x8000000000000000");
- testConversion('i64', 'reinterpret', 'f64', 40.09999999999968, 4630840390592548000);
- testConversion('f64', 'reinterpret', 'i64', 4630840390592548000, 40.09999999999968);
+ testConversion('i64', 'reinterpret', 'f64', 40.09999999999968, "0x40440ccccccccca0");
+ testConversion('f64', 'reinterpret', 'i64', "0x40440ccccccccca0", 40.09999999999968);
+
+ setJitCompilerOption('wasm.test-mode', 0);
} else {
// Sleeper test: once i64 works on more platforms, remove this if-else.
try {
testConversion('i32', 'wrap', 'i64', 4294967336, 40);
assertEq(0, 1);
} catch(e) {
assertEq(e.toString().indexOf("NYI on this platform") >= 0, true);
}
--- a/js/src/jit-test/tests/wasm/basic-integer.js
+++ b/js/src/jit-test/tests/wasm/basic-integer.js
@@ -4,55 +4,50 @@ assertEq(wasmEvalText('(module (func (re
assertEq(wasmEvalText('(module (func (result i32) (i32.const -2147483648)) (export "" 0))')(), -2147483648);
assertEq(wasmEvalText('(module (func (result i32) (i32.const 4294967295)) (export "" 0))')(), -1);
function testUnary(type, opcode, op, expect) {
assertEq(wasmEvalText('(module (func (param ' + type + ') (result ' + type + ') (' + type + '.' + opcode + ' (get_local 0))) (export "" 0))')(op), expect);
}
function testBinary(type, opcode, lhs, rhs, expect) {
- if (type === 'i64') {
- // i64 cannot be imported/exported, so we use a wrapper function.
- assertEq(wasmEvalText(`(module
- (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (get_local 1)))
- (func (result i32) (i64.eq (call 0 (i64.const ${lhs}) (i64.const ${rhs})) (i64.const ${expect})))
- (export "" 1))`)(), 1);
- // The same, but now the RHS is a constant.
- assertEq(wasmEvalText(`(module
- (func (param i64) (result i64) (i64.${opcode} (get_local 0) (i64.const ${rhs})))
- (func (result i32) (i64.eq (call 0 (i64.const ${lhs})) (i64.const ${expect})))
- (export "" 1))`)(), 1);
- // LHS and RHS are constants.
- assertEq(wasmEvalText(`(module
- (func (result i64) (i64.${opcode} (i64.const ${lhs}) (i64.const ${rhs})))
- (func (result i32) (i64.eq (call 0) (i64.const ${expect})))
- (export "" 1))`)(), 1);
- } else {
- assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result ' + type + ') (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
- }
+ if (type === 'i64') {
+ let lobj = createI64(lhs);
+ let robj = createI64(rhs);
+ expect = createI64(expect);
+
+ assertEqI64(wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (get_local 1))) (export "" 0))`)(lobj, robj), expect);
+ // The same, but now the RHS is a constant.
+ assertEqI64(wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (get_local 0) (i64.const ${rhs}))) (export "" 0))`)(lobj, robj), expect);
+ // LHS and RHS are constants.
+ assertEqI64(wasmEvalText(`(module (func (param i64) (param i64) (result i64) (i64.${opcode} (i64.const ${lhs}) (i64.const ${rhs}))) (export "" 0))`)(lobj, robj), expect);
+ } else {
+ assertEq(wasmEvalText(`(module (func (param ${type}) (param ${type}) (result ${type}) (${type}.${opcode} (get_local 0) (get_local 1))) (export "" 0))`)(lhs, rhs), expect);
+ }
}
function testComparison(type, opcode, lhs, rhs, expect) {
- if (type === 'i64') {
- // i64 cannot be imported/exported, so we use a wrapper function.
- assertEq(wasmEvalText(`(module
- (func (param i64) (param i64) (result i32) (i64.${opcode} (get_local 0) (get_local 1)))
- (func (result i32) (call 0 (i64.const ${lhs}) (i64.const ${rhs})))
- (export "" 1))`)(), expect);
- // Also test if, for the compare-and-branch path.
- assertEq(wasmEvalText(`(module
- (func (param i64) (param i64) (result i32)
- (if (i64.${opcode} (get_local 0) (get_local 1))
- (i32.const 1)
- (i32.const 0)))
- (func (result i32) (call 0 (i64.const ${lhs}) (i64.const ${rhs})))
- (export "" 1))`)(), expect);
- } else {
- assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result i32) (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
- }
+ if (type === 'i64') {
+ let lobj = createI64(lhs);
+ let robj = createI64(rhs);
+
+ assertEq(wasmEvalText(`(module
+ (func (param i64) (param i64) (result i32) (i64.${opcode} (get_local 0) (get_local 1)))
+ (export "" 0))`)(lobj, robj), expect);
+
+ // Also test if, for the compare-and-branch path.
+ assertEq(wasmEvalText(`(module
+ (func (param i64) (param i64) (result i32)
+ (if (i64.${opcode} (get_local 0) (get_local 1))
+ (i32.const 1)
+ (i32.const 0)))
+ (export "" 0))`)(lobj, robj), expect);
+ } else {
+ assertEq(wasmEvalText('(module (func (param ' + type + ') (param ' + type + ') (result i32) (' + type + '.' + opcode + ' (get_local 0) (get_local 1))) (export "" 0))')(lhs, rhs), expect);
+ }
}
testUnary('i32', 'clz', 40, 26);
testUnary('i32', 'ctz', 40, 3);
testUnary('i32', 'ctz', 0, 32);
testUnary('i32', 'ctz', -2147483648, 31);
testUnary('i32', 'popcnt', 40, 2);
@@ -90,17 +85,20 @@ testComparison('i32', 'gt_u', 40, 40, 0)
testComparison('i32', 'ge_s', 40, 40, 1);
testComparison('i32', 'ge_u', 40, 40, 1);
//testUnary('i64', 'clz', 40, 58); // TODO: NYI
//testUnary('i64', 'ctz', 40, 0); // TODO: NYI
//testUnary('i64', 'popcnt', 40, 0); // TODO: NYI
//testUnary('i64', 'eqz', 40, 0); // TODO: NYI
-if (getBuildConfiguration().x64) {
+if (hasI64()) {
+
+ setJitCompilerOption('wasm.test-mode', 1);
+
testBinary('i64', 'add', 40, 2, 42);
testBinary('i64', 'add', "0x1234567887654321", -1, "0x1234567887654320");
testBinary('i64', 'add', "0xffffffffffffffff", 1, 0);
testBinary('i64', 'sub', 40, 2, 38);
testBinary('i64', 'sub', "0x1234567887654321", "0x123456789", "0x12345677641fdb98");
testBinary('i64', 'sub', 3, 5, -2);
testBinary('i64', 'mul', 40, 2, 80);
testBinary('i64', 'mul', -1, 2, -2);
@@ -152,25 +150,27 @@ if (getBuildConfiguration().x64) {
testComparison('i64', 'le_u', 40, 40, 1);
testComparison('i64', 'gt_s', 40, 40, 0);
testComparison('i64', 'gt_u', 40, 40, 0);
testComparison('i64', 'ge_s', 40, 40, 1);
testComparison('i64', 'ge_u', 40, 40, 1);
testComparison('i64', 'eq', "0x400012345678", "0x400012345678", 1);
testComparison('i64', 'ne', "0x400012345678", "0x400012345678", 0);
testComparison('i64', 'ne', "0x400012345678", "0x500012345678", 1);
- testComparison('i64', 'eq', "0xffffffffffffffff", "-1", 1);
+ testComparison('i64', 'eq', "0xffffffffffffffff", -1, 1);
testComparison('i64', 'lt_s', "0x8000000012345678", "0x1", 1);
testComparison('i64', 'lt_u', "0x8000000012345678", "0x1", 0);
- testComparison('i64', 'le_s', "-1", "0", 1);
- testComparison('i64', 'le_u', "-1", "-1", 1);
- testComparison('i64', 'gt_s', "1", "0x8000000000000000", 1);
- testComparison('i64', 'gt_u', "1", "0x8000000000000000", 0);
- testComparison('i64', 'ge_s', "1", "0x8000000000000000", 1);
- testComparison('i64', 'ge_u', "1", "0x8000000000000000", 0);
+ testComparison('i64', 'le_s', -1, 0, 1);
+ testComparison('i64', 'le_u', -1, -1, 1);
+ testComparison('i64', 'gt_s', 1, "0x8000000000000000", 1);
+ testComparison('i64', 'gt_u', 1, "0x8000000000000000", 0);
+ testComparison('i64', 'ge_s', 1, "0x8000000000000000", 1);
+ testComparison('i64', 'ge_u', 1, "0x8000000000000000", 0);
+
+ setJitCompilerOption('wasm.test-mode', 0);
} else {
// Sleeper test: once i64 works on more platforms, remove this if-else.
try {
testComparison('i64', 'eq', 40, 40, 1);
assertEq(0, 1);
} catch(e) {
assertEq(e.toString().indexOf("NYI on this platform") >= 0, true);
}
--- a/js/src/jit-test/tests/wasm/basic.js
+++ b/js/src/jit-test/tests/wasm/basic.js
@@ -82,21 +82,32 @@ assertErrorMessage(() => wasmEvalText('(
wasmEvalText('(module (func (nop)))');
wasmEvalText('(module (func (result i32) (i32.const 42)))');
wasmEvalText('(module (func (param i32)))');
wasmEvalText('(module (func (param i32) (result i32) (i32.const 42)))');
wasmEvalText('(module (func (result i32) (param i32) (i32.const 42)))');
wasmEvalText('(module (func (param f32)))');
wasmEvalText('(module (func (param f64)))');
-var hasI64 = getBuildConfiguration().x64;
-if (!hasI64) {
+if (!hasI64()) {
assertErrorMessage(() => wasmEvalText('(module (func (param i64)))'), TypeError, /NYI/);
assertErrorMessage(() => wasmEvalText('(module (func (result i64)))'), TypeError, /NYI/);
assertErrorMessage(() => wasmEvalText('(module (func (result i32) (i32.wrap/i64 (i64.add (i64.const 1) (i64.const 2)))))'), TypeError, /NYI/);
+} else {
+ assertErrorMessage(() => wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))'), TypeError, /i64 argument/);
+ assertErrorMessage(() => wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))'), TypeError, /i64 return type/);
+
+ setJitCompilerOption('wasm.test-mode', 1);
+
+ assertEqI64(wasmEvalText('(module (func (result i64) (i64.const 123)) (export "" 0))')(), {low: 123, high: 0});
+ assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (get_local 0)) (export "" 0))')({ low: 0x7fffffff, high: 0x12340000}),
+ {low: 0x7fffffff, high: 0x12340000});
+ assertEqI64(wasmEvalText('(module (func (param i64) (result i64) (i64.add (get_local 0) (i64.const 1))) (export "" 0))')({ low: 0xffffffff, high: 0x12340000}), {low: 0x0, high: 0x12340001});
+
+ setJitCompilerOption('wasm.test-mode', 0);
}
// ----------------------------------------------------------------------------
// imports
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', 1), Error, /second argument, if present, must be an object/);
assertErrorMessage(() => wasmEvalText('(module (import "a" "b"))', null), Error, /second argument, if present, must be an object/);
@@ -255,17 +266,17 @@ assertErrorMessage(() => wasmEvalText('(
assertErrorMessage(() => wasmEvalText('(module (func (local f32) (set_local 0 (nop))))'), TypeError, mismatchError("void", "f32"));
assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 1))))'), TypeError, mismatchError("f32", "i32"));
assertErrorMessage(() => wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 0))))'), TypeError, mismatchError("i32", "f32"));
wasmEvalText('(module (func (local i32) (local f32) (set_local 0 (get_local 0))))');
wasmEvalText('(module (func (local i32) (local f32) (set_local 1 (get_local 1))))');
assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (i32.const 42))) (export "" 0))')(), 42);
assertEq(wasmEvalText('(module (func (result i32) (local i32) (set_local 0 (get_local 0))) (export "" 0))')(), 0);
-if (!hasI64)
+if (!hasI64())
assertErrorMessage(() => wasmEvalText('(module (func (local i64)))'), TypeError, /NYI/);
assertEq(wasmEvalText('(module (func (param $a i32) (result i32) (get_local $a)) (export "" 0))')(), 0);
assertEq(wasmEvalText('(module (func (param $a i32) (local $b i32) (result i32) (block (set_local $b (get_local $a)) (get_local $b))) (export "" 0))')(42), 42);
wasmEvalText('(module (func (local i32) (local $a f32) (set_local 0 (i32.const 1)) (set_local $a (f32.const nan))))');
// ----------------------------------------------------------------------------
@@ -342,16 +353,80 @@ var code = '(module (import "one" "" (re
var imports = {one:()=>1, two:()=>2};
assertEq(wasmEvalText(code.replace('BODY', '(call_import 0)'), imports)(), 1);
assertEq(wasmEvalText(code.replace('BODY', '(call_import 1)'), imports)(), 2);
assertEq(wasmEvalText(code.replace('BODY', '(call 0)'), imports)(), 3);
assertEq(wasmEvalText(code.replace('BODY', '(call 1)'), imports)(), 4);
assertEq(wasmEvalText(`(module (import "evalcx" "" (param i32) (result i32)) (func (result i32) (call_import 0 (i32.const 0))) (export "" 0))`, {evalcx})(), 0);
+if (typeof evaluate === 'function')
+ evaluate(`Wasm.instantiateModule(wasmTextToBinary('(module)')) `, { fileName: null });
+
+if (hasI64()) {
+ assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /i64 argument/);
+ assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /i64 return type/);
+
+ setJitCompilerOption('wasm.test-mode', 1);
+
+ let imp = {
+ param(i64) {
+ assertEqI64(i64, {
+ low: 0x9abcdef0,
+ high: 0x12345678
+ });
+ return 42;
+ },
+ result(i32) {
+ return {
+ low: 0xabcdef01,
+ high: 0x12345678 + i32
+ }
+ },
+ paramAndResult(i64) {
+ assertEqI64(i64, {
+ low: 0x9abcdef0,
+ high: 0x12345678
+ });
+ i64.low = 1337;
+ return i64;
+ }
+ }
+
+ assertEq(wasmEvalText(`(module
+ (import "param" "" (param i64) (result i32))
+ (func (result i32) (call_import 0 (i64.const 0x123456789abcdef0)))
+ (export "" 0))`, imp)(), 42);
+
+ assertEqI64(wasmEvalText(`(module
+ (import "result" "" (param i32) (result i64))
+ (func (result i64) (call_import 0 (i32.const 3)))
+ (export "" 0))`, imp)(), { low: 0xabcdef01, high: 0x1234567b });
+
+ // Ensure the ion exit is never taken.
+ let ionThreshold = 2 * getJitCompilerOptions()['ion.warmup.trigger'];
+ assertEqI64(wasmEvalText(`(module
+ (import "paramAndResult" "" (param i64) (result i64))
+ (func (result i64) (local i32) (local i64)
+ (set_local 0 (i32.const 0))
+ (loop $out $in
+ (set_local 1 (call_import 0 (i64.const 0x123456789abcdef0)))
+ (set_local 0 (i32.add (get_local 0) (i32.const 1)))
+ (if (i32.le_s (get_local 0) (i32.const ${ionThreshold})) (br $in))
+ )
+ (get_local 1)
+ )
+ (export "" 0))`, imp)(), { low: 1337, high: 0x12345678 });
+
+ setJitCompilerOption('wasm.test-mode', 0);
+} else {
+ assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /NYI/);
+ assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /NYI/);
+}
+
var {v2i, i2i, i2v} = wasmEvalText(`(module
(type (func (result i32)))
(type (func (param i32) (result i32)))
(type (func (param i32)))
(func (type 0) (i32.const 13))
(func (type 0) (i32.const 42))
(func (type 1) (i32.add (get_local 0) (i32.const 1)))
(func (type 1) (i32.add (get_local 0) (i32.const 2)))
@@ -402,23 +477,16 @@ assertErrorMessage(() => i2v(5), Error,
}
for (bad of [6, 7, 100, Math.pow(2,31)-1, Math.pow(2,31), Math.pow(2,31)+1, Math.pow(2,32)-2, Math.pow(2,32)-1]) {
assertThrowsInstanceOf(() => v2i(bad), RangeError);
assertThrowsInstanceOf(() => i2i(bad, 0), RangeError);
assertThrowsInstanceOf(() => i2v(bad, 0), RangeError);
}
-if (hasI64) {
- assertErrorMessage(() => wasmEvalText('(module (func (param i64) (result i32) (i32.const 123)) (export "" 0))'), TypeError, /i64 argument/);
- assertErrorMessage(() => wasmEvalText('(module (func (param i32) (result i64) (i64.const 123)) (export "" 0))'), TypeError, /i64 return type/);
- assertErrorMessage(() => wasmEvalText('(module (import "a" "" (param i64) (result i32)))'), TypeError, /i64 argument/);
- assertErrorMessage(() => wasmEvalText('(module (import "a" "" (result i64)))'), TypeError, /i64 return type/);
-}
-
var {v2i, i2i, i2v} = wasmEvalText(`(module
(type $a (func (result i32)))
(type $b (func (param i32) (result i32)))
(type $c (func (param i32)))
(func $a (type $a) (i32.const 13))
(func $b (type $a) (i32.const 42))
(func $c (type $b) (i32.add (get_local 0) (i32.const 1)))
(func $d (type $b) (i32.add (get_local 0) (i32.const 2)))
@@ -577,31 +645,33 @@ testSelect('i32', Math.pow(2, 31) - 1, -
testSelect('f32', Math.fround(13.37), Math.fround(19.89));
testSelect('f32', 'infinity', '-0');
testSelect('f32', 'nan', Math.pow(2, -31));
testSelect('f64', 13.37, 19.89);
testSelect('f64', 'infinity', '-0');
testSelect('f64', 'nan', Math.pow(2, -31));
-if (!hasI64) {
+if (!hasI64()) {
assertErrorMessage(() => wasmEvalText('(module (func (select (i64.const 0) (i64.const 1) (i32.const 0))))'), TypeError, /NYI/);
} else {
+
+ setJitCompilerOption('wasm.test-mode', 1);
+
var f = wasmEvalText(`
(module
- (func (result i32) (param i32)
- (i64.gt_s
- (select
- (i64.const ${Math.pow(2, 31) + 1})
- (i64.const ${-Math.pow(2, 31) - 1})
- (get_local 0)
- )
- (i64.const ${Math.pow(2, 31)})
+ (func (result i64) (param i32)
+ (select
+ (i64.const 0xc0010ff08badf00d)
+ (i64.const 0x12345678deadc0de)
+ (get_local 0)
)
)
(export "" 0)
- )
- `, imports);
+ )`, imports);
- assertEq(f(0), 0);
- assertEq(f(1), 1);
- assertEq(f(-1), 1);
+ assertEqI64(f(0), { low: 0xdeadc0de, high: 0x12345678});
+ assertEqI64(f(1), { low: 0x8badf00d, high: 0xc0010ff0});
+ assertEqI64(f(-1), { low: 0x8badf00d, high: 0xc0010ff0});
+
+ setJitCompilerOption('wasm.test-mode', 0);
}
+
--- a/js/src/jit-test/tests/wasm/random-control-flow.js
+++ b/js/src/jit-test/tests/wasm/random-control-flow.js
@@ -123,8 +123,28 @@ wasmEvalText(`(module (func
(i32.const 0)
)
)
(br $in)
)
)
)
))`);
+
+wasmEvalText(`
+(module
+ (func $func$0
+ (select
+ (if
+ (i32.const 0)
+ (f32.const 0)
+ (i32.const 0)
+ )
+ (if
+ (i32.const 0)
+ (f32.const 0)
+ (i32.const 0)
+ )
+ (i32.const 0)
+ )
+ )
+)
+`);
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -51,16 +51,17 @@ T overrideDefault(const char* param, T d
} else {
Maybe<int> value = ParseInt(str);
if (value.isSome())
return value.ref();
Warn(param, str);
}
return dflt;
}
+
#define SET_DEFAULT(var, dflt) var = overrideDefault("JIT_OPTION_" #var, dflt)
DefaultJitOptions::DefaultJitOptions()
{
// Whether to perform expensive graph-consistency DEBUG-only assertions.
// It can be useful to disable this to reduce DEBUG-compile time of large
// asm.js programs.
SET_DEFAULT(checkGraphConsistency, true);
@@ -183,16 +184,19 @@ DefaultJitOptions::DefaultJitOptions()
if (const char* env = getenv(forcedRegisterAllocatorEnv)) {
forcedRegisterAllocator = LookupRegisterAllocator(env);
if (!forcedRegisterAllocator.isSome())
Warn(forcedRegisterAllocatorEnv, env);
}
// Toggles whether unboxed plain objects can be created by the VM.
SET_DEFAULT(disableUnboxedObjects, false);
+
+ // Test whether wasm int64 / double NaN bits testing is enabled.
+ SET_DEFAULT(wasmTestMode, false);
}
bool
DefaultJitOptions::isSmallFunction(JSScript* script) const
{
return script->length() <= smallFunctionMaxBytecodeLength_;
}
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -61,16 +61,17 @@ struct DefaultJitOptions
bool disableScalarReplacement;
bool disableSharedStubs;
bool disableSincos;
bool disableSink;
bool eagerCompilation;
bool forceInlineCaches;
bool limitScriptSize;
bool osr;
+ bool wasmTestMode;
uint32_t baselineWarmUpThreshold;
uint32_t exceptionBailoutThreshold;
uint32_t frequentBailoutThreshold;
uint32_t maxStackArgs;
uint32_t osrPcMismatchesBeforeRecompile;
uint32_t smallFunctionMaxBytecodeLength_;
uint32_t jumpThreshold;
mozilla::Maybe<uint32_t> forcedDefaultIonWarmUpThreshold;
--- a/js/src/jit/RegisterSets.h
+++ b/js/src/jit/RegisterSets.h
@@ -1282,16 +1282,23 @@ class ABIArg
#else
bool isGeneralRegPair() const { return false; }
#endif
Register gpr() const {
MOZ_ASSERT(kind() == GPR);
return Register::FromCode(u.gpr_);
}
+ Register64 gpr64() const {
+#ifdef JS_PUNBOX64
+ return Register64(gpr());
+#else
+ MOZ_CRASH("NYI");
+#endif
+ }
Register evenGpr() const {
MOZ_ASSERT(isGeneralRegPair());
return Register::FromCode(u.gpr_);
}
Register oddGpr() const {
MOZ_ASSERT(isGeneralRegPair());
return Register::FromCode(u.gpr_ + 1);
}
--- a/js/src/jit/Registers.h
+++ b/js/src/jit/Registers.h
@@ -41,16 +41,20 @@ struct Register {
Register r = { Encoding(i) };
return r;
}
static Register FromName(const char* name) {
Code code = Registers::FromName(name);
Register r = { Encoding(code) };
return r;
}
+ static Register Invalid() {
+ Register r = { Encoding(Codes::Invalid) };
+ return r;
+ }
MOZ_CONSTEXPR Code code() const {
return Code(reg_);
}
Encoding encoding() const {
MOZ_ASSERT(Code(reg_) < Registers::Total);
return reg_;
}
const char* name() const {
@@ -104,16 +108,20 @@ struct Register64
Register low;
#endif
#ifdef JS_PUNBOX64
explicit MOZ_CONSTEXPR Register64(Register r)
: reg(r)
{}
#else
+ explicit Register64(Register r)
+ : high(Register::Invalid()), low(Register::Invalid())
+ {}
+
MOZ_CONSTEXPR Register64(Register h, Register l)
: high(h), low(l)
{}
#endif
};
class RegisterDump
{
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -113,16 +113,17 @@ static MOZ_CONSTEXPR_VAR Register PreBar
static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg;
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = r3;
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = r2;
static MOZ_CONSTEXPR_VAR Register StackPointer = sp;
static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg;
static MOZ_CONSTEXPR_VAR Register ReturnReg = r0;
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::d0, VFPRegister::Single };
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::d0, VFPRegister::Double};
static MOZ_CONSTEXPR_VAR FloatRegister ReturnSimd128Reg = InvalidFloatReg;
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = { FloatRegisters::d30, VFPRegister::Single };
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = { FloatRegisters::d15, VFPRegister::Double };
static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimd128Reg = InvalidFloatReg;
static MOZ_CONSTEXPR_VAR FloatRegister ScratchUIntReg = { FloatRegisters::d15, VFPRegister::UInt };
static MOZ_CONSTEXPR_VAR FloatRegister ScratchIntReg = { FloatRegisters::d15, VFPRegister::Int };
--- a/js/src/jit/arm/MacroAssembler-arm.h
+++ b/js/src/jit/arm/MacroAssembler-arm.h
@@ -1419,21 +1419,16 @@ class MacroAssemblerARMCompat : public M
// This is the instruction sequence that gcc generated for this
// operation.
ScratchRegisterScope scratch(asMasm());
ma_sub(r, Imm32(0x80000001), scratch);
ma_cmn(scratch, Imm32(3));
ma_b(handleNotAnInt, Above);
}
- void memIntToValue(Address Source, Address Dest) {
- load32(Source, lr);
- storeValue(JSVAL_TYPE_INT32, lr, Dest);
- }
-
void lea(Operand addr, Register dest) {
ma_add(addr.baseReg(), Imm32(addr.disp()), dest);
}
void abiret() {
as_bx(lr);
}
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -50,16 +50,17 @@ static constexpr Register CallTempReg1 =
static constexpr Register CallTempReg2 = { Registers::x11 };
static constexpr Register CallTempReg3 = { Registers::x12 };
static constexpr Register CallTempReg4 = { Registers::x13 };
static constexpr Register CallTempReg5 = { Registers::x14 };
static constexpr Register PreBarrierReg = { Registers::x1 };
static constexpr Register ReturnReg = { Registers::x0 };
+static constexpr Register64 ReturnReg64(ReturnReg);
static constexpr Register JSReturnReg = { Registers::x2 };
static constexpr Register FramePointer = { Registers::fp };
static constexpr Register ZeroRegister = { Registers::sp };
static constexpr ARMRegister ZeroRegister64 = { Registers::sp, 64 };
static constexpr ARMRegister ZeroRegister32 = { Registers::sp, 32 };
static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
--- a/js/src/jit/arm64/MacroAssembler-arm64.h
+++ b/js/src/jit/arm64/MacroAssembler-arm64.h
@@ -1917,25 +1917,16 @@ class MacroAssemblerCompat : public vixl
// FIXME: See CodeGeneratorX64 calls to noteAsmJSGlobalAccess.
void patchAsmJSGlobalAccess(CodeOffset patchAt, uint8_t* code,
uint8_t* globalData, unsigned globalDataOffset)
{
MOZ_CRASH("patchAsmJSGlobalAccess");
}
- void memIntToValue(const Address& src, const Address& dest) {
- vixl::UseScratchRegisterScope temps(this);
- const Register scratch = temps.AcquireX().asUnsized();
- MOZ_ASSERT(scratch != src.base);
- MOZ_ASSERT(scratch != dest.base);
- load32(src, scratch);
- storeValue(JSVAL_TYPE_INT32, scratch, dest);
- }
-
void profilerEnterFrame(Register framePtr, Register scratch) {
AbsoluteAddress activation(GetJitContext()->runtime->addressOfProfilingActivation());
loadPtr(activation, scratch);
storePtr(framePtr, Address(scratch, JitActivation::offsetOfLastProfilingFrame()));
storePtr(ImmPtr(nullptr), Address(scratch, JitActivation::offsetOfLastProfilingCallSite()));
}
void profilerExitFrame() {
branch(GetJitContext()->runtime->jitRuntime()->getProfilerExitFrameTail());
--- a/js/src/jit/mips64/MacroAssembler-mips64.h
+++ b/js/src/jit/mips64/MacroAssembler-mips64.h
@@ -997,21 +997,16 @@ class MacroAssemblerMIPS64Compat : publi
protected:
bool buildOOLFakeExitFrame(void* fakeReturnAddr);
public:
CodeOffset labelForPatch() {
return CodeOffset(nextOffset().getOffset());
}
- void memIntToValue(Address Source, Address Dest) {
- load32(Source, ScratchRegister);
- storeValue(JSVAL_TYPE_INT32, ScratchRegister, Dest);
- }
-
void lea(Operand addr, Register dest) {
ma_daddu(dest, addr.baseReg(), Imm32(addr.disp()));
}
void abiret() {
as_jr(ra);
as_nop();
}
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -6,17 +6,16 @@
#ifndef jit_none_MacroAssembler_none_h
#define jit_none_MacroAssembler_none_h
#include "jit/JitCompartment.h"
#include "jit/MoveResolver.h"
#include "jit/shared/Assembler-shared.h"
-
namespace js {
namespace jit {
static MOZ_CONSTEXPR_VAR Register StackPointer = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register FramePointer = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register ReturnReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = { FloatRegisters::invalid_reg };
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = { FloatRegisters::invalid_reg };
@@ -67,18 +66,20 @@ static MOZ_CONSTEXPR_VAR Register RegExp
static MOZ_CONSTEXPR_VAR Register RegExpMatcherStickyReg = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = { Registers::invalid_reg };
static MOZ_CONSTEXPR_VAR Register JSReturnReg = { Registers::invalid_reg };
#if defined(JS_NUNBOX32)
static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand(InvalidReg, InvalidReg);
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
#elif defined(JS_PUNBOX64)
static MOZ_CONSTEXPR_VAR ValueOperand JSReturnOperand(InvalidReg);
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg);
#else
#error "Bad architecture"
#endif
static MOZ_CONSTEXPR_VAR uint32_t ABIStackAlignment = 4;
static MOZ_CONSTEXPR_VAR uint32_t CodeAlignment = 4;
static MOZ_CONSTEXPR_VAR uint32_t JitStackAlignment = 8;
static MOZ_CONSTEXPR_VAR uint32_t JitStackValueAlignment = JitStackAlignment / sizeof(Value);
@@ -391,17 +392,16 @@ class MacroAssemblerNone : public Assemb
void incrementInt32Value(Address) { MOZ_CRASH(); }
void ensureDouble(ValueOperand, FloatRegister, Label*) { MOZ_CRASH(); }
void handleFailureWithHandlerTail(void*) { MOZ_CRASH(); }
void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); }
bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); }
void loadWasmActivation(Register) { MOZ_CRASH(); }
void loadAsmJSHeapRegisterFromGlobalData() { MOZ_CRASH(); }
- void memIntToValue(Address, Address) { MOZ_CRASH(); }
void setPrinter(Sprinter*) { MOZ_CRASH(); }
Operand ToPayload(Operand base) { MOZ_CRASH(); }
static const Register getStackPointer() { MOZ_CRASH(); }
// Instrumentation for entering and leaving the profiler.
void profilerEnterFrame(Register , Register ) { MOZ_CRASH(); }
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -78,16 +78,17 @@ struct ScratchRegisterScope : public Aut
{
explicit ScratchRegisterScope(MacroAssembler& masm)
: AutoRegisterScope(masm, ScratchReg)
{ }
};
static MOZ_CONSTEXPR_VAR Register ReturnReg = rax;
static MOZ_CONSTEXPR_VAR Register HeapReg = r15;
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(rax);
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
static MOZ_CONSTEXPR_VAR FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Single);
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm15, FloatRegisters::Double);
static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimd128Reg = xmm15;
// Avoid rbp, which is the FramePointer, which is unavailable in some modes.
--- a/js/src/jit/x64/MacroAssembler-x64.h
+++ b/js/src/jit/x64/MacroAssembler-x64.h
@@ -937,21 +937,16 @@ class MacroAssemblerX64 : public MacroAs
void patchAsmJSGlobalAccess(CodeOffset patchAt, uint8_t* code, uint8_t* globalData,
unsigned globalDataOffset)
{
uint8_t* nextInsn = code + patchAt.offset();
MOZ_ASSERT(nextInsn <= globalData);
uint8_t* target = globalData + globalDataOffset;
((int32_t*)nextInsn)[-1] = target - nextInsn;
}
- void memIntToValue(Address Source, Address Dest) {
- ScratchRegisterScope scratch(asMasm());
- load32(Source, scratch);
- storeValue(JSVAL_TYPE_INT32, scratch, Dest);
- }
// Instrumentation for entering and leaving the profiler.
void profilerEnterFrame(Register framePtr, Register scratch);
void profilerExitFrame();
};
typedef MacroAssemblerX64 MacroAssemblerSpecific;
--- a/js/src/jit/x86-shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/Assembler-x86-shared.cpp
@@ -100,16 +100,47 @@ AssemblerX86Shared::trace(JSTracer* trc)
::TraceDataRelocations(trc, masm.data(), reader);
}
}
void
AssemblerX86Shared::executableCopy(void* buffer)
{
masm.executableCopy(buffer);
+
+ // Crash diagnostics for bug 1124397. Check the code buffer has not been
+ // poisoned with 0xE5 bytes.
+ static const size_t MinPoisoned = 16;
+ const uint8_t* bytes = (const uint8_t*)buffer;
+ size_t len = size();
+
+ for (size_t i = 0; i < len; i += MinPoisoned) {
+ if (bytes[i] != 0xE5)
+ continue;
+
+ size_t startOffset = i;
+ while (startOffset > 0 && bytes[startOffset - 1] == 0xE5)
+ startOffset--;
+
+ size_t endOffset = i;
+ while (endOffset + 1 < len && bytes[endOffset + 1] == 0xE5)
+ endOffset++;
+
+ if (endOffset - startOffset < MinPoisoned)
+ continue;
+
+ volatile uintptr_t dump[5];
+ blackbox = dump;
+ blackbox[0] = uintptr_t(0xABCD4321);
+ blackbox[1] = uintptr_t(len);
+ blackbox[2] = uintptr_t(startOffset);
+ blackbox[3] = uintptr_t(endOffset);
+ blackbox[4] = uintptr_t(0xFFFF8888);
+ MOZ_CRASH("Corrupt code buffer");
+ }
}
void
AssemblerX86Shared::processCodeLabels(uint8_t* rawCode)
{
for (size_t i = 0; i < codeLabels_.length(); i++) {
CodeLabel label = codeLabels_[i];
Bind(rawCode, label.patchAt(), rawCode + label.target()->offset());
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -39,16 +39,17 @@ static MOZ_CONSTEXPR_VAR FloatRegister x
static MOZ_CONSTEXPR_VAR Register InvalidReg = { X86Encoding::invalid_reg };
static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = FloatRegister();
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = ecx;
static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = edx;
static MOZ_CONSTEXPR_VAR Register StackPointer = esp;
static MOZ_CONSTEXPR_VAR Register FramePointer = ebp;
static MOZ_CONSTEXPR_VAR Register ReturnReg = eax;
+static MOZ_CONSTEXPR_VAR Register64 ReturnReg64(InvalidReg, InvalidReg);
static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloat32Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Single);
static MOZ_CONSTEXPR_VAR FloatRegister ReturnDoubleReg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Double);
static MOZ_CONSTEXPR_VAR FloatRegister ReturnSimd128Reg = FloatRegister(X86Encoding::xmm0, FloatRegisters::Simd128);
static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloat32Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Single);
static MOZ_CONSTEXPR_VAR FloatRegister ScratchDoubleReg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Double);
static MOZ_CONSTEXPR_VAR FloatRegister ScratchSimd128Reg = FloatRegister(X86Encoding::xmm7, FloatRegisters::Simd128);
// Avoid ebp, which is the FramePointer, which is unavailable in some modes.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -6151,16 +6151,19 @@ JS_SetGlobalJitCompilerOption(JSRuntime*
break;
case JSJITCOMPILER_JUMP_THRESHOLD:
if (value == uint32_t(-1)) {
jit::DefaultJitOptions defaultValues;
value = defaultValues.jumpThreshold;
}
jit::JitOptions.jumpThreshold = value;
break;
+ case JSJITCOMPILER_WASM_TEST_MODE:
+ jit::JitOptions.wasmTestMode = !!value;
+ break;
default:
break;
}
}
JS_PUBLIC_API(int)
JS_GetGlobalJitCompilerOption(JSRuntime* rt, JSJitCompilerOption opt)
{
@@ -6177,16 +6180,18 @@ JS_GetGlobalJitCompilerOption(JSRuntime*
case JSJITCOMPILER_ION_ENABLE:
return JS::RuntimeOptionsRef(rt).ion();
case JSJITCOMPILER_BASELINE_ENABLE:
return JS::RuntimeOptionsRef(rt).baseline();
case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE:
return rt->canUseOffthreadIonCompilation();
case JSJITCOMPILER_SIGNALS_ENABLE:
return rt->canUseSignalHandlers();
+ case JSJITCOMPILER_WASM_TEST_MODE:
+ return jit::JitOptions.wasmTestMode ? 1 : 0;
default:
break;
}
#endif
return 0;
}
/************************************************************************/
@@ -6267,17 +6272,17 @@ void AutoFilename::setScriptSource(js::S
p->incref();
setUnowned(p->filename());
}
}
void AutoFilename::setUnowned(const char* filename)
{
MOZ_ASSERT(!get());
- filename_.as<const char*>() = filename;
+ filename_.as<const char*>() = filename ? filename : "";
}
void AutoFilename::setOwned(UniqueChars&& filename)
{
MOZ_ASSERT(!get());
filename_ = AsVariant(Move(filename));
}
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5515,17 +5515,18 @@ JS_SetOffthreadIonCompilationEnabled(JSR
Register(BASELINE_WARMUP_TRIGGER, "baseline.warmup.trigger") \
Register(ION_WARMUP_TRIGGER, "ion.warmup.trigger") \
Register(ION_GVN_ENABLE, "ion.gvn.enable") \
Register(ION_FORCE_IC, "ion.forceinlineCaches") \
Register(ION_ENABLE, "ion.enable") \
Register(BASELINE_ENABLE, "baseline.enable") \
Register(OFFTHREAD_COMPILATION_ENABLE, "offthread-compilation.enable") \
Register(SIGNALS_ENABLE, "signals.enable") \
- Register(JUMP_THRESHOLD, "jump-threshold")
+ Register(JUMP_THRESHOLD, "jump-threshold") \
+ Register(WASM_TEST_MODE, "wasm.test-mode")
typedef enum JSJitCompilerOption {
#define JIT_COMPILER_DECLARE(key, str) \
JSJITCOMPILER_ ## key,
JIT_COMPILER_OPTIONS(JIT_COMPILER_DECLARE)
#undef JIT_COMPILER_DECLARE
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2040,16 +2040,17 @@ static const AllocKind AllocKindsToReloc
AllocKind::OBJECT4_BACKGROUND,
AllocKind::OBJECT8,
AllocKind::OBJECT8_BACKGROUND,
AllocKind::OBJECT12,
AllocKind::OBJECT12_BACKGROUND,
AllocKind::OBJECT16,
AllocKind::OBJECT16_BACKGROUND,
AllocKind::SCRIPT,
+ AllocKind::LAZY_SCRIPT,
AllocKind::SHAPE,
AllocKind::ACCESSOR_SHAPE,
AllocKind::FAT_INLINE_STRING,
AllocKind::STRING,
AllocKind::EXTERNAL_STRING
};
Arena*
@@ -2408,16 +2409,24 @@ void
MovingTracer::onScriptEdge(JSScript** scriptp)
{
JSScript* script = *scriptp;
if (IsForwarded(script))
*scriptp = Forwarded(script);
}
void
+MovingTracer::onLazyScriptEdge(LazyScript** lazyp)
+{
+ LazyScript* lazy = *lazyp;
+ if (IsForwarded(lazy))
+ *lazyp = Forwarded(lazy);
+}
+
+void
Zone::prepareForCompacting()
{
FreeOp* fop = runtimeFromMainThread()->defaultFreeOp();
discardJitCode(fop);
}
void
GCRuntime::sweepTypesAfterCompacting(Zone* zone)
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -1101,17 +1101,18 @@ struct MightBeForwarded
static_assert(mozilla::IsBaseOf<Cell, T>::value,
"T must derive from Cell");
static_assert(!mozilla::IsSame<Cell, T>::value && !mozilla::IsSame<TenuredCell, T>::value,
"T must not be Cell or TenuredCell");
static const bool value = mozilla::IsBaseOf<JSObject, T>::value ||
mozilla::IsBaseOf<Shape, T>::value ||
mozilla::IsBaseOf<JSString, T>::value ||
- mozilla::IsBaseOf<JSScript, T>::value;
+ mozilla::IsBaseOf<JSScript, T>::value ||
+ mozilla::IsBaseOf<js::LazyScript, T>::value;
};
template <typename T>
inline bool
IsForwarded(T* t)
{
RelocationOverlay* overlay = RelocationOverlay::fromCell(t);
if (!MightBeForwarded<T>::value) {
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -42,20 +42,16 @@ ShapeTable::init(ExclusiveContext* cx, S
{
uint32_t sizeLog2 = CeilingLog2Size(entryCount_);
uint32_t size = JS_BIT(sizeLog2);
if (entryCount_ >= size - (size >> 2))
sizeLog2++;
if (sizeLog2 < MIN_SIZE_LOG2)
sizeLog2 = MIN_SIZE_LOG2;
- /*
- * Use rt->calloc for memory accounting and overpressure handling
- * without OOM reporting. See ShapeTable::change.
- */
size = JS_BIT(sizeLog2);
entries_ = cx->pod_calloc<Entry>(size);
if (!entries_)
return false;
MOZ_ASSERT(sizeLog2 <= HASH_BITS);
hashShift_ = HASH_BITS - sizeLog2;
@@ -263,29 +259,29 @@ ShapeTable::search(jsid id)
MOZ_CRASH("Shape::search failed to find an expected entry.");
}
template ShapeTable::Entry& ShapeTable::search<MaybeAdding::Adding>(jsid id);
template ShapeTable::Entry& ShapeTable::search<MaybeAdding::NotAdding>(jsid id);
bool
-ShapeTable::change(int log2Delta, ExclusiveContext* cx)
+ShapeTable::change(ExclusiveContext* cx, int log2Delta)
{
MOZ_ASSERT(entries_);
MOZ_ASSERT(-1 <= log2Delta && log2Delta <= 1);
/*
* Grow, shrink, or compress by changing this->entries_.
*/
uint32_t oldLog2 = HASH_BITS - hashShift_;
uint32_t newLog2 = oldLog2 + log2Delta;
uint32_t oldSize = JS_BIT(oldLog2);
uint32_t newSize = JS_BIT(newLog2);
- Entry* newTable = cx->pod_calloc<Entry>(newSize);
+ Entry* newTable = cx->maybe_pod_calloc<Entry>(newSize);
if (!newTable)
return false;
/* Now that we have newTable allocated, update members. */
MOZ_ASSERT(newLog2 <= HASH_BITS);
hashShift_ = HASH_BITS - newLog2;
removedCount_ = 0;
Entry* oldTable = entries_;
@@ -313,21 +309,21 @@ ShapeTable::grow(ExclusiveContext* cx)
{
MOZ_ASSERT(needsToGrow());
uint32_t size = capacity();
int delta = removedCount_ < (size >> 2);
MOZ_ASSERT(entryCount_ + removedCount_ <= size - 1);
- if (!change(delta, cx)) {
- if (entryCount_ + removedCount_ == size - 1)
+ if (!change(cx, delta)) {
+ if (entryCount_ + removedCount_ == size - 1) {
+ ReportOutOfMemory(cx);
return false;
-
- cx->recoverFromOutOfMemory();
+ }
}
return true;
}
void
ShapeTable::trace(JSTracer* trc)
{
@@ -1043,17 +1039,17 @@ NativeObject::removeProperty(ExclusiveCo
}
/* Generate a new shape for the object, infallibly. */
JS_ALWAYS_TRUE(self->generateOwnShape(cx, spare));
/* Consider shrinking table if its load factor is <= .25. */
uint32_t size = table.capacity();
if (size > ShapeTable::MIN_SIZE && table.entryCount() <= size >> 2)
- (void) table.change(-1, cx);
+ (void) table.change(cx, -1);
} else {
/*
* Non-dictionary-mode shape tables are shared immutables, so all we
* need do is retract the last property and we'll either get or else
* lazily make via a later hashify the exact table for the new property
* lineage.
*/
MOZ_ASSERT(shape == self->lastProperty());
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -212,23 +212,21 @@ class ShapeTable {
/*
* This counts the ShapeTable object itself (which must be
* heap-allocated) and its |entries| array.
*/
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
return mallocSizeOf(this) + mallocSizeOf(entries_);
}
- /*
- * NB: init and change are fallible but do not report OOM, so callers can
- * cope or ignore. They do however use the context's calloc method in
- * order to update the malloc counter on success.
- */
+ // init() is fallible and reports OOM to the context.
bool init(ExclusiveContext* cx, Shape* lastProp);
- bool change(int log2Delta, ExclusiveContext* cx);
+
+ // change() is fallible but does not report OOM.
+ bool change(ExclusiveContext* cx, int log2Delta);
template<MaybeAdding Adding>
Entry& search(jsid id);
void trace(JSTracer* trc);
#ifdef JSGC_HASH_TABLE_CHECKS
void checkAfterMovingGC();
#endif
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -640,17 +640,17 @@ FindFrameTargetedByInputEvent(WidgetGUIE
}
// Now we basically undo the operations in GetEventCoordinatesRelativeTo, to
// get back the (now-clamped) coordinates in the event's widget's space.
nsView* view = aRootFrame->GetView();
if (!view) {
return target;
}
LayoutDeviceIntPoint widgetPoint = nsLayoutUtils::TranslateViewToWidget(
- aRootFrame->PresContext(), view, point, aEvent->widget);
+ aRootFrame->PresContext(), view, point, aEvent->mWidget);
if (widgetPoint.x != NS_UNCONSTRAINEDSIZE) {
// If that succeeded, we update the point in the event
aEvent->refPoint = widgetPoint;
}
return target;
}
} // namespace mozilla
--- a/layout/base/TouchManager.cpp
+++ b/layout/base/TouchManager.cpp
@@ -60,17 +60,16 @@ EvictTouchPoint(RefPtr<dom::Touch>& aTou
nsIPresShell* presShell = doc->GetShell();
if (presShell) {
nsIFrame* frame = presShell->GetRootFrame();
if (frame) {
nsPoint pt(aTouch->mRefPoint.x, aTouch->mRefPoint.y);
nsCOMPtr<nsIWidget> widget = frame->GetView()->GetNearestWidget(&pt);
if (widget) {
WidgetTouchEvent event(true, eTouchEnd, widget);
- event.widget = widget;
event.mTime = PR_IntervalNow();
event.mTouches.AppendElement(aTouch);
nsEventStatus status;
widget->DispatchEvent(&event, status);
return;
}
}
}
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2168,17 +2168,17 @@ nsPoint
nsLayoutUtils::GetEventCoordinatesRelativeTo(const WidgetEvent* aEvent,
const LayoutDeviceIntPoint& aPoint,
nsIFrame* aFrame)
{
if (!aFrame) {
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
- nsIWidget* widget = aEvent->AsGUIEvent()->widget;
+ nsIWidget* widget = aEvent->AsGUIEvent()->mWidget;
if (!widget) {
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
return GetEventCoordinatesRelativeTo(widget, aPoint, aFrame);
}
nsPoint
@@ -7630,16 +7630,36 @@ nsLayoutUtils::SizeOfTextRunsForFrames(n
for (nsFrameList::Enumerator e(childLists.CurrentList());
!e.AtEnd(); e.Next()) {
total += SizeOfTextRunsForFrames(e.get(), aMallocSizeOf, clear);
}
}
return total;
}
+struct PrefCallbacks
+{
+ const char* name;
+ PrefChangedFunc func;
+};
+static const PrefCallbacks kPrefCallbacks[] = {
+ { GRID_ENABLED_PREF_NAME,
+ GridEnabledPrefChangeCallback },
+ { WEBKIT_PREFIXES_ENABLED_PREF_NAME,
+ WebkitPrefixEnabledPrefChangeCallback },
+ { TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME,
+ TextAlignUnsafeEnabledPrefChangeCallback },
+ { DISPLAY_CONTENTS_ENABLED_PREF_NAME,
+ DisplayContentsEnabledPrefChangeCallback },
+ { FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME,
+ FloatLogicalValuesEnabledPrefChangeCallback },
+ { BG_CLIP_TEXT_ENABLED_PREF_NAME,
+ BackgroundClipTextEnabledPrefChangeCallback },
+};
+
/* static */
void
nsLayoutUtils::Initialize()
{
Preferences::AddUintVarCache(&sFontSizeInflationMaxRatio,
"font.size.inflation.maxRatio");
Preferences::AddUintVarCache(&sFontSizeInflationEmPerLine,
"font.size.inflation.emPerLine");
@@ -7657,56 +7677,34 @@ nsLayoutUtils::Initialize()
"nglayout.debug.invalidation");
Preferences::AddBoolVarCache(&sCSSVariablesEnabled,
"layout.css.variables.enabled");
Preferences::AddBoolVarCache(&sInterruptibleReflowEnabled,
"layout.interruptible-reflow.enabled");
Preferences::AddBoolVarCache(&sSVGTransformBoxEnabled,
"svg.transform-box.enabled");
- Preferences::RegisterCallback(GridEnabledPrefChangeCallback,
- GRID_ENABLED_PREF_NAME);
- GridEnabledPrefChangeCallback(GRID_ENABLED_PREF_NAME, nullptr);
- Preferences::RegisterCallback(WebkitPrefixEnabledPrefChangeCallback,
- WEBKIT_PREFIXES_ENABLED_PREF_NAME);
- WebkitPrefixEnabledPrefChangeCallback(WEBKIT_PREFIXES_ENABLED_PREF_NAME,
- nullptr);
- Preferences::RegisterCallback(TextAlignUnsafeEnabledPrefChangeCallback,
- TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME);
- Preferences::RegisterCallback(DisplayContentsEnabledPrefChangeCallback,
- DISPLAY_CONTENTS_ENABLED_PREF_NAME);
- DisplayContentsEnabledPrefChangeCallback(DISPLAY_CONTENTS_ENABLED_PREF_NAME,
- nullptr);
- TextAlignUnsafeEnabledPrefChangeCallback(TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME,
- nullptr);
- Preferences::RegisterCallback(FloatLogicalValuesEnabledPrefChangeCallback,
- FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME);
- FloatLogicalValuesEnabledPrefChangeCallback(FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME,
- nullptr);
- Preferences::RegisterCallback(BackgroundClipTextEnabledPrefChangeCallback,
- BG_CLIP_TEXT_ENABLED_PREF_NAME);
- BackgroundClipTextEnabledPrefChangeCallback(BG_CLIP_TEXT_ENABLED_PREF_NAME,
- nullptr);
-
+ for (auto& callback : kPrefCallbacks) {
+ Preferences::RegisterCallbackAndCall(callback.func, callback.name);
+ }
nsComputedDOMStyle::RegisterPrefChangeCallbacks();
}
/* static */
void
nsLayoutUtils::Shutdown()
{
if (sContentMap) {
delete sContentMap;
sContentMap = nullptr;
}
- Preferences::UnregisterCallback(GridEnabledPrefChangeCallback,
- GRID_ENABLED_PREF_NAME);
- Preferences::UnregisterCallback(WebkitPrefixEnabledPrefChangeCallback,
- WEBKIT_PREFIXES_ENABLED_PREF_NAME);
+ for (auto& callback : kPrefCallbacks) {
+ Preferences::UnregisterCallback(callback.func, callback.name);
+ }
nsComputedDOMStyle::UnregisterPrefChangeCallbacks();
// so the cached initial quotes array doesn't appear to be a leak
nsStyleList::Shutdown();
}
/* static */
void
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3640,17 +3640,17 @@ PresShell::DispatchSynthMouseMove(Widget
if (restyleManager->IsServo()) {
NS_ERROR("stylo: cannot dispatch synthetic mouse moves when using a "
"ServoRestyleManager yet");
return;
}
uint32_t hoverGenerationBefore =
restyleManager->AsGecko()->GetHoverGeneration();
nsEventStatus status;
- nsView* targetView = nsView::GetViewFor(aEvent->widget);
+ nsView* targetView = nsView::GetViewFor(aEvent->mWidget);
if (!targetView)
return;
targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status);
if (MOZ_UNLIKELY(mIsDestroying)) {
return;
}
if (aFlushOnHoverChange &&
hoverGenerationBefore != restyleManager->AsGecko()->GetHoverGeneration()) {
@@ -6762,27 +6762,27 @@ PresShell::RecordMouseLocation(WidgetGUI
aEvent->AsMouseEvent()->reason == WidgetMouseEvent::eReal) ||
aEvent->mMessage == eMouseEnterIntoWidget ||
aEvent->mMessage == eMouseDown ||
aEvent->mMessage == eMouseUp) {
nsIFrame* rootFrame = GetRootFrame();
if (!rootFrame) {
nsView* rootView = mViewManager->GetRootView();
mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
- aEvent->widget, aEvent->refPoint, rootView);
+ aEvent->mWidget, aEvent->refPoint, rootView);
mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
} else {
mMouseLocation =
nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
}
#ifdef DEBUG_MOUSE_LOCATION
if (aEvent->mMessage == eMouseEnterIntoWidget) {
printf("[ps=%p]got mouse enter for %p\n",
- this, aEvent->widget);
+ this, aEvent->mWidget);
}
printf("[ps=%p]setting mouse location to (%d,%d)\n",
this, mMouseLocation.x, mMouseLocation.y);
#endif
if (aEvent->mMessage == eMouseEnterIntoWidget) {
SynthesizeMouseMove(false);
}
} else if (aEvent->mMessage == eMouseExitFromWidget) {
@@ -6790,17 +6790,17 @@ PresShell::RecordMouseLocation(WidgetGUI
// pres shell doesn't receive mouse move events, we don't check which widget
// the mouse exit was for since this seems to vary by platform. Hopefully
// this won't matter at all since we'll get the mouse move or enter after
// the mouse exit when the mouse moves from one of our widgets into another.
mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
mMouseEventTargetGuid = InputAPZContext::GetTargetLayerGuid();
#ifdef DEBUG_MOUSE_LOCATION
printf("[ps=%p]got mouse exit for %p\n",
- this, aEvent->widget);
+ this, aEvent->mWidget);
printf("[ps=%p]clearing mouse location\n",
this);
#endif
}
}
nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell)
{
@@ -6899,17 +6899,17 @@ DispatchPointerFromMouseOrTouch(PresShel
for (uint32_t i = 0; i < touchEvent->mTouches.Length(); ++i) {
mozilla::dom::Touch* touch = touchEvent->mTouches[i];
if (!touch || !touch->convertToPointer) {
continue;
}
WidgetPointerEvent event(touchEvent->IsTrusted(), pointerMessage,
- touchEvent->widget);
+ touchEvent->mWidget);
event.isPrimary = i == 0;
event.pointerId = touch->Identifier();
event.refPoint = touch->mRefPoint;
event.mModifiers = touchEvent->mModifiers;
event.width = touch->RadiusX();
event.height = touch->RadiusY();
event.tiltX = touch->tiltX;
event.tiltY = touch->tiltY;
@@ -7032,17 +7032,17 @@ PresShell::DispatchBeforeKeyboardEventIn
for (int32_t i = length - 1; i >= 0; i--) {
eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
if (!eventTarget || !CanDispatchEvent(&aEvent)) {
return;
}
aChainIndex = i;
InternalBeforeAfterKeyboardEvent beforeEvent(aEvent.IsTrusted(),
- message, aEvent.widget);
+ message, aEvent.mWidget);
beforeEvent.AssignBeforeAfterKeyEventData(aEvent, false);
EventDispatcher::Dispatch(eventTarget, mPresContext, &beforeEvent);
if (beforeEvent.DefaultPrevented()) {
aDefaultPrevented = true;
return;
}
}
@@ -7066,17 +7066,17 @@ PresShell::DispatchAfterKeyboardEventInt
// Dispatch after events from the innermost element.
for (uint32_t i = aStartOffset; i < length; i++) {
eventTarget = do_QueryInterface(aChain[i]->OwnerDoc()->GetWindow());
if (!eventTarget || !CanDispatchEvent(&aEvent)) {
return;
}
InternalBeforeAfterKeyboardEvent afterEvent(aEvent.IsTrusted(),
- message, aEvent.widget);
+ message, aEvent.mWidget);
afterEvent.AssignBeforeAfterKeyEventData(aEvent, false);
afterEvent.mEmbeddedCancelled.SetValue(embeddedCancelled);
EventDispatcher::Dispatch(eventTarget, mPresContext, &afterEvent);
embeddedCancelled = afterEvent.DefaultPrevented();
}
}
void
@@ -7099,17 +7099,17 @@ PresShell::DispatchAfterKeyboardEvent(ns
}
bool
PresShell::CanDispatchEvent(const WidgetGUIEvent* aEvent) const
{
bool rv =
mPresContext && !mHaveShutDown && nsContentUtils::IsSafeToRunScript();
if (aEvent) {
- rv &= (aEvent && aEvent->widget && !aEvent->widget->Destroyed());
+ rv &= (aEvent && aEvent->mWidget && !aEvent->mWidget->Destroyed());
}
return rv;
}
void
PresShell::HandleKeyboardEvent(nsINode* aTarget,
WidgetKeyboardEvent& aEvent,
bool aEmbeddedCancelled,
@@ -8365,17 +8365,17 @@ PresShell::DispatchTouchEventToDOM(Widge
if (capturingContent->OwnerDoc() != doc) {
// Wrong document, don't dispatch anything.
continue;
}
content = capturingContent;
}
// copy the event
WidgetTouchEvent newEvent(touchEvent->IsTrusted(),
- touchEvent->mMessage, touchEvent->widget);
+ touchEvent->mMessage, touchEvent->mWidget);
newEvent.AssignTouchEventData(*touchEvent, false);
newEvent.target = targetPtr;
RefPtr<PresShell> contentPresShell;
if (doc == mDocument) {
contentPresShell = static_cast<PresShell*>(doc->GetShell());
if (contentPresShell) {
//XXXsmaug huge hack. Pushing possibly capturing content,
@@ -8473,17 +8473,17 @@ PresShell::AdjustContextMenuKeyEvent(Wid
nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu);
if (popupFrame) {
nsIFrame* itemFrame =
(static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem();
if (!itemFrame)
itemFrame = popupFrame;
nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget();
- aEvent->widget = widget;
+ aEvent->mWidget = widget;
LayoutDeviceIntPoint widgetPoint = widget->WidgetToScreenOffset();
aEvent->refPoint = LayoutDeviceIntPoint::FromUnknownPoint(
itemFrame->GetScreenRect().BottomLeft()) - widgetPoint;
mCurrentEventContent = itemFrame->GetContent();
mCurrentEventFrame = itemFrame;
return true;
@@ -8499,38 +8499,38 @@ PresShell::AdjustContextMenuKeyEvent(Wid
// Use the root view manager's widget since it's most likely to have one,
// and the coordinates returned by GetCurrentItemAndPositionForElement
// are relative to the widget of the root of the root view manager.
nsRootPresContext* rootPC = mPresContext->GetRootPresContext();
aEvent->refPoint.x = 0;
aEvent->refPoint.y = 0;
if (rootPC) {
rootPC->PresShell()->GetViewManager()->
- GetRootWidget(getter_AddRefs(aEvent->widget));
-
- if (aEvent->widget) {
+ GetRootWidget(getter_AddRefs(aEvent->mWidget));
+
+ if (aEvent->mWidget) {
// default the refpoint to the topleft of our document
nsPoint offset(0, 0);
nsIFrame* rootFrame = mFrameConstructor->GetRootFrame();
if (rootFrame) {
nsView* view = rootFrame->GetClosestView(&offset);
- offset += view->GetOffsetToWidget(aEvent->widget);
+ offset += view->GetOffsetToWidget(aEvent->mWidget);
aEvent->refPoint =
LayoutDeviceIntPoint::FromAppUnitsToNearest(offset, mPresContext->AppUnitsPerDevPixel());
}
}
} else {
- aEvent->widget = nullptr;
+ aEvent->mWidget = nullptr;
}
// see if we should use the caret position for the popup
LayoutDeviceIntPoint caretPoint;
// Beware! This may flush notifications via synchronous
// ScrollSelectionIntoView.
- if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) {
+ if (PrepareToUseCaretPosition(aEvent->mWidget, caretPoint)) {
// caret position is good
aEvent->refPoint = caretPoint;
return true;
}
// If we're here because of the key-equiv for showing context menus, we
// have to reset the event target to the currently focused element. Get it
// from the focus controller.
@@ -8540,17 +8540,17 @@ PresShell::AdjustContextMenuKeyEvent(Wid
fm->GetFocusedElement(getter_AddRefs(currentFocus));
// Reset event coordinates relative to focused frame in view
if (currentFocus) {
nsCOMPtr<nsIContent> currentPointElement;
GetCurrentItemAndPositionForElement(currentFocus,
getter_AddRefs(currentPointElement),
aEvent->refPoint,
- aEvent->widget);
+ aEvent->mWidget);
if (currentPointElement) {
mCurrentEventContent = currentPointElement;
mCurrentEventFrame = nullptr;
GetCurrentEventFrame();
}
}
return true;
@@ -9809,44 +9809,44 @@ PresShell::DelayedInputEvent::DelayedInp
PresShell::DelayedInputEvent::~DelayedInputEvent()
{
delete mEvent;
}
void
PresShell::DelayedInputEvent::Dispatch()
{
- if (!mEvent || !mEvent->widget) {
- return;
- }
- nsCOMPtr<nsIWidget> widget = mEvent->widget;
+ if (!mEvent || !mEvent->mWidget) {
+ return;
+ }
+ nsCOMPtr<nsIWidget> widget = mEvent->mWidget;
nsEventStatus status;
widget->DispatchEvent(mEvent, status);
}
PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent* aEvent) :
DelayedInputEvent()
{
WidgetMouseEvent* mouseEvent =
new WidgetMouseEvent(aEvent->IsTrusted(),
aEvent->mMessage,
- aEvent->widget,
+ aEvent->mWidget,
aEvent->reason,
aEvent->context);
mouseEvent->AssignMouseEventData(*aEvent, false);
mEvent = mouseEvent;
}
PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) :
DelayedInputEvent()
{
WidgetKeyboardEvent* keyEvent =
new WidgetKeyboardEvent(aEvent->IsTrusted(),
aEvent->mMessage,
- aEvent->widget);
+ aEvent->mWidget);
keyEvent->AssignKeyEventData(*aEvent, false);
keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests;
mEvent = keyEvent;
}
// Start of DEBUG only code
#ifdef DEBUG
--- a/layout/xul/nsResizerFrame.cpp
+++ b/layout/xul/nsResizerFrame.cpp
@@ -100,33 +100,33 @@ nsResizerFrame::HandleEvent(nsPresContex
// If there is no window, then resizing isn't allowed.
if (!window)
break;
doDefault = false;
// ask the widget implementation to begin a resize drag if it can
Direction direction = GetDirection();
- nsresult rv = aEvent->widget->BeginResizeDrag(aEvent,
+ nsresult rv = aEvent->mWidget->BeginResizeDrag(aEvent,
direction.mHorizontal, direction.mVertical);
// for native drags, don't set the fields below
if (rv != NS_ERROR_NOT_IMPLEMENTED)
break;
// if there's no native resize support, we need to do window
// resizing ourselves
window->GetPositionAndSize(&mMouseDownRect.x, &mMouseDownRect.y,
&mMouseDownRect.width, &mMouseDownRect.height);
}
// remember current mouse coordinates
LayoutDeviceIntPoint refPoint;
if (!GetEventPoint(aEvent, refPoint))
return NS_OK;
- mMouseDownPoint = refPoint + aEvent->widget->WidgetToScreenOffset();
+ mMouseDownPoint = refPoint + aEvent->mWidget->WidgetToScreenOffset();
// we're tracking
mTrackingMouseMove = true;
nsIPresShell::SetCapturingContent(GetContent(), CAPTURE_IGNOREALLOWED);
}
}
break;
@@ -164,17 +164,18 @@ nsResizerFrame::HandleEvent(nsPresContex
// both MouseMove and direction are negative when pointing to the
// top and left, and positive when pointing to the bottom and right
// retrieve the offset of the mousemove event relative to the mousedown.
// The difference is how much the resize needs to be
LayoutDeviceIntPoint refPoint;
if (!GetEventPoint(aEvent, refPoint))
return NS_OK;
- LayoutDeviceIntPoint screenPoint = refPoint + aEvent->widget->WidgetToScreenOffset();
+ LayoutDeviceIntPoint screenPoint =
+ refPoint + aEvent->mWidget->WidgetToScreenOffset();
LayoutDeviceIntPoint mouseMove(screenPoint - mMouseDownPoint);
// Determine which direction to resize by checking the dir attribute.
// For windows and menus, ensure that it can be resized in that direction.
Direction direction = GetDirection();
if (window || menuPopupFrame) {
if (menuPopupFrame) {
menuPopupFrame->CanAdjustEdges(
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -612,17 +612,17 @@ nsXULPopupManager::InitTriggerEvent(nsID
presContext->GetRootPresContext();
if (!rootDocPresContext)
return;
nsIFrame* rootDocumentRootFrame = rootDocPresContext->
PresShell()->FrameManager()->GetRootFrame();
if ((event->mClass == eMouseEventClass ||
event->mClass == eMouseScrollEventClass ||
event->mClass == eWheelEventClass) &&
- !event->AsGUIEvent()->widget) {
+ !event->AsGUIEvent()->mWidget) {
// no widget, so just use the client point if available
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(aEvent);
nsIntPoint clientPt;
mouseEvent->GetClientX(&clientPt.x);
mouseEvent->GetClientY(&clientPt.y);
// XXX this doesn't handle IFRAMEs in transforms
nsPoint thisDocToRootDocOffset = presShell->FrameManager()->
@@ -1410,20 +1410,20 @@ nsXULPopupManager::FirePopupShowingEvent
WidgetMouseEvent event(true, eXULPopupShowing, nullptr,
WidgetMouseEvent::eReal);
// coordinates are relative to the root widget
nsPresContext* rootPresContext =
presShell->GetPresContext()->GetRootPresContext();
if (rootPresContext) {
rootPresContext->PresShell()->GetViewManager()->
- GetRootWidget(getter_AddRefs(event.widget));
+ GetRootWidget(getter_AddRefs(event.mWidget));
}
else {
- event.widget = nullptr;
+ event.mWidget = nullptr;
}
event.refPoint = mCachedMousePoint;
event.mModifiers = mCachedModifiers;
EventDispatcher::Dispatch(popup, presContext, &event, nullptr, &status);
mCachedMousePoint = LayoutDeviceIntPoint(0, 0);
mOpeningPopup = nullptr;
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -180,18 +180,22 @@ convert_stream_type_to_sl_stream(cubeb_s
default:
return 0xFFFFFFFF;
}
}
#endif
static void opensl_destroy(cubeb * ctx);
+
#if defined(__ANDROID__)
+// B2G header file still contain the required function declarations.
+#ifndef MOZ_WIDGET_GONK
+
#if (__ANDROID_API__ >= ANDROID_VERSION_LOLLIPOP)
typedef int (system_property_get)(const char*, char*);
static int
__system_property_get(const char* name, char* value)
{
void* libc = dlopen("libc.so", RTLD_LAZY);
if (!libc) {
@@ -204,16 +208,18 @@ static int
if (func) {
ret = func(name, value);
}
dlclose(libc);
return ret;
}
#endif
+#endif // MOZ_WIDGET_GONK
+
static int
get_android_version(void)
{
char version_string[PROP_VALUE_MAX];
memset(version_string, 0, PROP_VALUE_MAX);
int len = __system_property_get("ro.build.version.sdk", version_string);
--- a/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in
+++ b/mobile/android/search/manifests/SearchAndroidManifest_activities.xml.in
@@ -1,10 +1,11 @@
<activity
android:name="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"
+ android:process=":search"
android:launchMode="singleTop"
android:taskAffinity="@ANDROID_PACKAGE_NAME@.SEARCH"
android:icon="@drawable/search_launcher"
android:label="@string/search_app_name"
android:configChanges="orientation|screenSize"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.ASSIST"/>
@@ -44,16 +45,17 @@
<action android:name="org.mozilla.widget.LAUNCH_NEW_TAB"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/search_widget_info" />
</receiver>
<activity
android:name="org.mozilla.search.SearchPreferenceActivity"
+ android:process=":search"
android:logo="@drawable/search_launcher"
android:label="@string/search_pref_title"
android:parentActivityName="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"
android:theme="@style/SettingsTheme" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="@MOZ_ANDROID_SEARCH_INTENT_CLASS@"/>
</activity>
--- a/netwerk/base/security-prefs.js
+++ b/netwerk/base/security-prefs.js
@@ -29,16 +29,19 @@ pref("security.ssl3.dhe_rsa_aes_256_sha"
pref("security.ssl3.ecdhe_rsa_rc4_128_sha", true);
pref("security.ssl3.ecdhe_ecdsa_rc4_128_sha", true);
pref("security.ssl3.rsa_aes_128_sha", true);
pref("security.ssl3.rsa_aes_256_sha", true);
pref("security.ssl3.rsa_des_ede3_sha", true);
pref("security.ssl3.rsa_rc4_128_sha", true);
pref("security.ssl3.rsa_rc4_128_md5", true);
+pref("security.content.signature.root_hash",
+ "97:E8:BA:9C:F1:2F:B3:DE:53:CC:42:A4:E6:57:7E:D6:4D:F4:93:C2:47:B4:14:FE:A0:36:81:8D:38:23:56:0E");
+
pref("security.default_personal_cert", "Ask Every Time");
pref("security.remember_cert_checkbox_default_setting", true);
pref("security.ask_for_password", 0);
pref("security.password_lifetime", 30);
pref("security.OCSP.enabled", 1);
pref("security.OCSP.require", false);
pref("security.OCSP.GET.enabled", false);
--- a/testing/firefox-ui/tests/puppeteer/manifest.ini
+++ b/testing/firefox-ui/tests/puppeteer/manifest.ini
@@ -8,13 +8,14 @@ tags = local
[test_security.py]
tags = remote
[test_software_update.py]
[test_utils.py]
# UI tests
[test_about_window.py]
[test_menubar.py]
+[test_notifications.py]
[test_page_info_window.py]
[test_tabbar.py]
[test_toolbars.py]
tags = remote
[test_windows.py]
new file mode 100644
index 0000000000000000000000000000000000000000..c8877b55dec371fa6417fc626ef1a6f3113cc2bc
GIT binary patch
literal 1552
zc$^FHW@Zs#U|`^2xLcX!&XKXBU5t@|;S&(^Fvu_@<>!|amlP!y=w%g$hHx@4I|ev~
zfpBRBHv=Qf3uXoeFtN7(bk<=50oU*Uy1c{uJeFQcbqa5EQfzhD{W56U@r_Mu3@@!v
z<o)^ml;)SM@4Q}|n_Dcg_kj0%p?Q|>-Zu)oD;`)ZNYONB-^7&Y;V;nT%v65;yzqYO
z_q=60Kb{MVNO-N&>f*ge^UliX*5iC^(~e)helD+ju_uR4M(m^)vvjUJda*>mHR;Wq
z<xg3vpYmig?GSu?N|?j#LU)h$+IIi#k9J&dUD@rcty2;j$>&+%CieU?*X$ndcc%jn
zM{qb^+O=wz%o+<mkEBIUHqLt-voK_;_F9dvXTD8jpJnq<?b6m~nyRr6f)sYCzmJr?
zWH5XE>1R(;{7-$}x3ABu>gUUso43^P{MWi=y!~wFzZEe%?^W2()VrU_xBnA=05EL1
z7(hTQBFmit39tjhHaVjxKQ~n$9IR_ZoWis)gEasiIUob#4KJhw0(lugEPyZ|BQ+-{
z9~eKmaFak7%_MDaouGnVjt~4?g{7VReP2pHedi3@5ZV!T%H!<Gli`;F1H8_k_xD`o
z6WX=)nHIAaTQ_s4Mr(SAlclQUO4pTLUILXXiY9PvKeFgb(E_dsA`A$>1&3$3Prjz3
zFArpcFhAUBdbx>tnQ5uTC19870bQks>9XYfypq(s5{2A6-6EjU#G;a%)Z$_VsOPv4
zL68Ov0{z15Lsh`EX#mv74YVgS52zz2N3SR)4Qz*ls8bjSquG%=`LrK6dH&?meltO6
zd86;*E4o4oVmbk;3AvLpH+)duw0z6c*M&ZDtecA7&9N@F4LtQV(DM`LHO|H1AC=BN
zGVNYeR9)>~<GMTaPu~r(DRO-6Ukav5-M(<NXy=khzt1)szv>mL_x_oYQ7-7dq`GM%
zL+P{7XWkwsotte=uhU#{u2%4OVat^5545zSz8G@U8&}61tzO-IFO=i$1n-#|>yGlt
zRE3+bWC`t<r8zf3zo=Vi&TXE>T8q7YIro&*hfZ7C9Uy(r-JzH@$GWtdLG$eDjhpyt
zH2Mo{m(Hu^kP$4oKK)IPYFBhUi;Kbw#f7skWaY_OhlyE8oqkuMY|`-6pmNi)d*K>(
ztn-?R8x~#smM5}hPvi5q%CD!}MOPS{op|xNuz7=duD0vZ<toqRQ!X5<U2OQt`N6aA
z9f=p2SGCl={9ZkG`Siw_na_3X`KtK+4o&F%$0>TEUe7T0!xg5}^&8$<h~4XPY@fEB
z=dB!*f#=2fiK<`svvluc4De=Tl4HhIz({}-5Rl2Rq!GkIEpAvL#SKQD0GWs@TS-7!
z0t{~*V}J(3GZ`x+YhX1DR~AEd-du!XNEr^Fskm|nvZ)qK448R^6_Qu*I2AK1ARD>>
cXedg?V1;B13<Fu&K$=*Aa5hk9JPU{i03S06YXATM
new file mode 100644
--- /dev/null
+++ b/testing/firefox-ui/tests/puppeteer/test_notifications.py
@@ -0,0 +1,77 @@
+# 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/.
+
+import os
+
+from marionette_driver import By
+from marionette_driver.errors import TimeoutException
+
+from firefox_ui_harness.testcases import FirefoxTestCase
+from firefox_puppeteer.ui.browser.notifications import (
+ AddOnInstallFailedNotification)
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+
+class TestNotifications(FirefoxTestCase):
+
+ def setUp(self):
+ FirefoxTestCase.setUp(self)
+ # setting this pref prevents a notification from being displayed
+ # when e10s is enabled. see http://mzl.la/1TVNAXh
+ self.prefs.set_pref('browser.tabs.remote.force-enable', True)
+
+ def tearDown(self):
+ try:
+ if self.browser.notification is not None:
+ self.browser.notification.close()
+ finally:
+ FirefoxTestCase.tearDown(self)
+
+ def test_no_notification(self):
+ """No initial notifications are shown"""
+ self.assertIsNone(self.browser.notification)
+
+ def test_notification_with_origin(self):
+ """Trigger a notification with an origin"""
+ self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+ self.assertIsNotNone(self.browser.notification.origin)
+ self.assertIsNotNone(self.browser.notification.label)
+
+ def test_close_notification(self):
+ """Trigger and dismiss a notification"""
+ self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+ self.browser.notification.close()
+ self.assertIsNone(self.browser.notification)
+
+ def test_add_on_failed_notification(self):
+ """Trigger add-on failed notification using an unsigned add-on"""
+ self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+ self.assertIsInstance(self.browser.notification,
+ AddOnInstallFailedNotification)
+
+ def test_wait_for_any_notification_timeout(self):
+ """Wait for a notification when one is not shown"""
+ message = 'No notification was shown'
+ with self.assertRaisesRegexp(TimeoutException, message):
+ self.browser.wait_for_notification()
+
+ def test_wait_for_specific_notification_timeout(self):
+ """Wait for a notification when one is not shown"""
+ message = 'AddOnInstallFailedNotification was not shown'
+ with self.assertRaisesRegexp(TimeoutException, message):
+ self.browser.wait_for_notification(AddOnInstallFailedNotification)
+
+ def test_wait_for_no_notification_timeout(self):
+ """Wait for no notification when one is shown"""
+ message = 'Unexpected notification shown'
+ self.trigger_add_on_notification('mn-restartless-unsigned.xpi')
+ with self.assertRaisesRegexp(TimeoutException, message):
+ self.browser.wait_for_notification(None)
+
+ def trigger_add_on_notification(self, add_on):
+ with self.marionette.using_context('content'):
+ self.marionette.navigate('file://{0}'.format(here))
+ self.marionette.find_element(By.LINK_TEXT, add_on).click()
+ self.browser.wait_for_notification()
--- a/testing/mozharness/configs/beetmover/repacks.yml.tmpl
+++ b/testing/mozharness/configs/beetmover/repacks.yml.tmpl
@@ -12,16 +12,19 @@ mapping:
artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.complete.mar
s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/update/{{ platform }}/{{ locale }}/firefox-{{ version }}.complete.mar
checksum:
artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums
s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums
checksum_sig:
artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.checksums.asc
s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/firefox-{{ version }}.checksums.asc
+ xpi:
+ artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.langpack.xpi
+ s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/xpi/{{ locale }}.xpi
{% if platform == "win32" %}
full_installer:
artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer.exe
s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup {{ version }}.exe
stub_installer:
artifact: {{ artifact_base_url }}/firefox-{{ app_version }}.{{ locale }}.{{ platform }}.installer-stub.exe
s3_key: {{ s3_prefix }}/{{ version }}-candidates/{{ build_num }}/{{ platform }}/{{ locale }}/Firefox Setup Stub {{ version }}.exe
--- a/testing/mozharness/scripts/desktop_partner_repacks.py
+++ b/testing/mozharness/scripts/desktop_partner_repacks.py
@@ -104,17 +104,17 @@ class DesktopPartnerRepacks(ReleaseMixin
self.fatal("repack_manifests_url not supplied.")
def _pre_config_lock(self, rw_config):
self.read_buildbot_config()
if not self.buildbot_config:
self.warning("Skipping buildbot properties overrides")
else:
props = self.buildbot_config["properties"]
- for prop in ['version', 'build_number']:
+ for prop in ['version', 'build_number', 'revision']:
if props.get(prop):
self.info("Overriding %s with %s" % (prop, props[prop]))
self.config[prop] = props.get(prop)
if self.config.get('require_buildprops', False) is True:
if not self.buildbot_config:
self.fatal("Unable to load properties from file: %s" % self.config.get('buildbot_json_path'))
buildbot_props = self.buildbot_config.get('properties', {})
@@ -187,16 +187,18 @@ class DesktopPartnerRepacks(ReleaseMixin
if self.config.get('partner'):
repack_cmd.extend(["--partner", self.config['partner']])
if self.config.get('s3cfg'):
repack_cmd.extend(["--s3cfg", self.config['s3cfg']])
if self.config.get('hgroot'):
repack_cmd.extend(["--hgroot", self.config['hgroot']])
if self.config.get('hgrepo'):
repack_cmd.extend(["--repo", self.config['hgrepo']])
+ if self.config.get('revision'):
+ repack_cmd.extend(["--tag", self.config["revision"]])
return self.run_command(repack_cmd,
cwd=self.query_abs_dirs()['abs_scripts_dir'])
# main {{{
if __name__ == '__main__':
partner_repacks = DesktopPartnerRepacks()
partner_repacks.run_and_exit()
--- a/testing/puppeteer/firefox/docs/index.rst
+++ b/testing/puppeteer/firefox/docs/index.rst
@@ -33,16 +33,17 @@ The following libraries are currently im
future. Each library is available from an instance of the FirefoxTestCase class.
.. toctree::
ui/about_window/window
ui/deck
ui/menu
ui/pageinfo/window
+ ui/browser/notifications
ui/browser/tabbar
ui/browser/toolbars
ui/browser/window
ui/update_wizard/dialog
ui/windows
api/appinfo
api/keys
api/l10n
new file mode 100644
--- /dev/null
+++ b/testing/puppeteer/firefox/docs/ui/browser/notifications.rst
@@ -0,0 +1,44 @@
+.. py:currentmodule:: firefox_puppeteer.ui.browser.notifications
+
+Notifications
+=============
+
+AddOnInstallBlockedNotification
+-------------------------------
+
+.. autoclass:: AddOnInstallBlockedNotification
+ :members:
+ :inherited-members:
+ :show-inheritance:
+
+AddOnInstallConfirmationNotification
+------------------------------------
+
+.. autoclass:: AddOnInstallConfirmationNotification
+ :members:
+ :inherited-members:
+ :show-inheritance:
+
+AddOnInstallCompleteNotification
+--------------------------------
+
+.. autoclass:: AddOnInstallCompleteNotification
+ :members:
+ :inherited-members:
+ :show-inheritance:
+
+AddOnInstallFailedNotification
+------------------------------
+
+.. autoclass:: AddOnInstallFailedNotification
+ :members:
+ :inherited-members:
+ :show-inheritance:
+
+AddOnProgressNotification
+-------------------------
+
+.. autoclass:: AddOnProgressNotification
+ :members:
+ :inherited-members:
+ :show-inheritance:
new file mode 100644
--- /dev/null
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/notifications.py
@@ -0,0 +1,84 @@
+# 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/.
+
+from abc import ABCMeta
+
+from marionette_driver import By
+
+from firefox_puppeteer.ui_base_lib import UIBaseLib
+
+
+class BaseNotification(UIBaseLib):
+ """Abstract base class for any kind of notification."""
+ __metaclass__ = ABCMeta
+
+ @property
+ def label(self):
+ """Provides access to the notification label.
+
+ :returns: The notification label.
+ """
+ return self.element.get_attribute('label')
+
+ @property
+ def origin(self):
+ """Provides access to the notification origin.
+
+ :returns: The notification origin.
+ """
+ return self.element.get_attribute('origin')
+
+ def close(self):
+ """Close the notification."""
+ self.element.find_element(
+ By.ANON_ATTRIBUTE, {'anonid': 'closebutton'}).click()
+
+
+class AddOnInstallBlockedNotification(BaseNotification):
+ """Add-on install blocked notification."""
+
+ def allow(self):
+ """Allow the add-on to be installed."""
+ self.element.find_element(
+ By.ANON_ATTRIBUTE, {'anonid': 'button'}).find_element(
+ By.ANON_ATTRIBUTE, {'anonid': 'button'}).click()
+
+
+class AddOnInstallConfirmationNotification(BaseNotification):
+ """Add-on install confirmation notification."""
+
+ @property
+ def add_on(self):
+ """Provides access to the add-on name.
+
+ :returns: The add-on name.
+ """
+ label = self.element.find_element(
+ By.CSS_SELECTOR, '#addon-install-confirmation-content label')
+ return label.get_attribute('value')
+
+ def cancel(self):
+ """Cancel installation of the add-on."""
+ self.element.find_element(
+ By.ID, 'addon-install-confirmation-cancel').click()
+
+ def install(self):
+ """Proceed with installation of the add-on."""
+ self.element.find_element(
+ By.ID, 'addon-install-confirmation-accept').click()
+
+
+class AddOnInstallCompleteNotification(BaseNotification):
+ """Add-on install complete notification."""
+ pass
+
+
+class AddOnInstallFailedNotification(BaseNotification):
+ """Add-on install failed notification."""
+ pass
+
+
+class AddOnProgressNotification(BaseNotification):
+ """Add-on progress notification."""
+ pass
--- a/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
+++ b/testing/puppeteer/firefox/firefox_puppeteer/ui/browser/window.py
@@ -1,22 +1,31 @@
# 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/.
import firefox_puppeteer.errors as errors
from marionette_driver import By, Wait
-from marionette_driver.errors import NoSuchWindowException
+from marionette_driver.errors import (
+ NoSuchElementException,
+ NoSuchWindowException)
from marionette_driver.keys import Keys
from firefox_puppeteer.api.l10n import L10n
from firefox_puppeteer.api.prefs import Preferences
from firefox_puppeteer.decorators import use_class_as_property
from firefox_puppeteer.ui.about_window.window import AboutWindow
+from firefox_puppeteer.ui.browser.notifications import (
+ AddOnInstallBlockedNotification,
+ AddOnInstallConfirmationNotification,
+ AddOnInstallCompleteNotification,
+ AddOnInstallFailedNotification,
+ AddOnProgressNotification,
+ BaseNotification)
from firefox_puppeteer.ui.browser.tabbar import TabBar
from firefox_puppeteer.ui.browser.toolbars import NavBar
from firefox_puppeteer.ui.pageinfo.window import PageInfoWindow
from firefox_puppeteer.ui.windows import BaseWindow, Windows
import firefox_puppeteer.errors as errors
class BrowserWindow(BaseWindow):
@@ -80,16 +89,50 @@ class BrowserWindow(BaseWindow):
if not self._navbar:
navbar = self.window_element.find_element(By.ID, 'nav-bar')
self._navbar = NavBar(lambda: self.marionette, self, navbar)
return self._navbar
@property
+ def notification(self):
+ """Provides access to the currently displayed notification."""
+
+ notifications_map = {
+ 'addon-install-blocked-notification': AddOnInstallBlockedNotification,
+ 'addon-install-confirmation-notification': AddOnInstallConfirmationNotification,
+ 'addon-install-complete-notification': AddOnInstallCompleteNotification,
+ 'addon-install-failed-notification': AddOnInstallFailedNotification,
+ 'addon-progress-notification': AddOnProgressNotification,
+ }
+
+ try:
+ notification = self.window_element.find_element(
+ By.CSS_SELECTOR, '#notification-popup popupnotification')
+ except NoSuchElementException:
+ return None # no notification is displayed
+ notification_id = notification.get_attribute('id')
+ return notifications_map[notification_id](
+ lambda: self.marionette, self, notification)
+
+ def wait_for_notification(self, notification_class=BaseNotification):
+ """Waits for the specified notification to be displayed."""
+ if notification_class is None:
+ Wait(self.marionette).until(
+ lambda _: self.notification is None,
+ message='Unexpected notification shown.')
+ else:
+ message = '{0} was not shown.'.format(notification_class.__name__)
+ if notification_class is BaseNotification:
+ message = 'No notification was shown.'
+ Wait(self.marionette).until(lambda _: isinstance(
+ self.notification, notification_class), message=message)
+
+ @property
def tabbar(self):
"""Provides access to the tab bar.
See the :class:`~ui.browser.tabbar.TabBar` reference.
"""
self.switch_to()
if not self._tabbar:
old mode 100644
new mode 100755
--- a/testing/xpcshell/selftest.py
+++ b/testing/xpcshell/selftest.py
@@ -414,16 +414,20 @@ class XPCShellTestsTests(unittest.TestCa
self.log = StringIO()
self.tempdir = tempfile.mkdtemp()
self.utility_path = os.path.join(objdir, 'dist', 'bin')
logger = structured.commandline.setup_logging("selftest%s" % id(self),
{},
{"tbpl": self.log})
self.x = XPCShellTests(logger)
self.x.harness_timeout = 15
+ self.symbols_path = None
+ candidate_path = os.path.join(build_obj.distdir, 'crashreporter-symbols')
+ if (os.path.isdir(candidate_path)):
+ self.symbols_path = candidate_path
def tearDown(self):
shutil.rmtree(self.tempdir)
def writeFile(self, name, contents):
"""
Write |contents| to a file named |name| in the temp directory,
and return the full path to the file.
@@ -449,25 +453,24 @@ class XPCShellTestsTests(unittest.TestCa
testlines.extend(t[1:])
self.manifest = self.writeFile("xpcshell.ini", """
[DEFAULT]
head =
tail =
""" + "\n".join(testlines))
- def assertTestResult(self, expected, shuffle=False, verbose=False,
- symbolsPath=None):
+ def assertTestResult(self, expected, shuffle=False, verbose=False):
"""
Assert that self.x.runTests with manifest=self.manifest
returns |expected|.
"""
self.assertEquals(expected,
self.x.runTests(xpcshellBin,
- symbolsPath=symbolsPath,
+ symbolsPath=self.symbols_path,
manifest=self.manifest,
mozInfo=mozinfo.info,
shuffle=shuffle,
verbose=verbose,
sequential=True,
testingModulesDir=os.path.join(objdir, '_tests', 'modules'),
utility_path=self.utility_path),
msg="""Tests should have %s, log:
@@ -527,35 +530,27 @@ tail =
self.assertNotInLog(TEST_PASS_STRING)
@unittest.skipIf(mozinfo.isWin or not mozinfo.info.get('debug'),
'We don\'t have a stack fixer on hand for windows.')
def testAssertStack(self):
"""
When an assertion is hit, we should produce a useful stack.
"""
- # Passing symbolsPath will cause the stack fixer to use
- # fix_stack_using_bpsyms and exercise the fileid utility in
- # this test.
- symbolsPath = None
- candidate_path = os.path.join(build_obj.distdir, 'crashreporter-symbols')
- if os.path.isdir(candidate_path):
- symbolsPath = candidate_path
-
self.writeFile("test_assert.js", '''
add_test(function test_asserts_immediately() {
Components.classes["@mozilla.org/xpcom/debug;1"]
.getService(Components.interfaces.nsIDebug2)
.assertion("foo", "assertion failed", "test.js", 1)
run_next_test();
});
''')
self.writeManifest(["test_assert.js"])
- self.assertTestResult(False, symbolsPath=symbolsPath)
+ self.assertTestResult(False)
self.assertInLog("###!!! ASSERTION")
log_lines = self.log.getvalue().splitlines()
line_pat = "#\d\d:"
unknown_pat = "#\d\d\: \?\?\?\[.* \+0x[a-f0-9]+\]"
self.assertFalse(any(re.search(unknown_pat, line) for line in log_lines),
"An stack frame without symbols was found in\n%s" % pprint.pformat(log_lines))
self.assertTrue(any(re.search(line_pat, line) for line in log_lines),
--- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm
+++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm
@@ -582,27 +582,27 @@ EventTargetParent.init();
// This function returns a listener that will not fire on events where
// the target is a remote xul:browser element itself. We'd rather let
// the child process handle the event and pass it up via
// EventTargetParent.
var filteringListeners = new WeakMap();
function makeFilteringListener(eventType, listener)
{
- if (filteringListeners.has(listener)) {
- return filteringListeners.get(listener);
- }
-
// Some events are actually targeted at the <browser> element
// itself, so we only handle the ones where know that won't happen.
let eventTypes = ["mousedown", "mouseup", "click"];
if (eventTypes.indexOf(eventType) == -1) {
return listener;
}
+ if (filteringListeners.has(listener)) {
+ return filteringListeners.get(listener);
+ }
+
function filter(event) {
let target = event.originalTarget;
if (target instanceof Ci.nsIDOMXULElement &&
target.localName == "browser" &&
target.isRemoteBrowser) {
return;
}
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -170,22 +170,20 @@
<body>
<![CDATA[
if (this.type == "scrubber") {
this.Utils.log("--- dragStateChanged: " + isDragging + " ---");
this.isDragging = isDragging;
if (isDragging) {
this.wasPausedBeforeDrag = this.Utils.video.paused;
this.isDraggingComplete = false;
- this.previousPlaybackRate = this.Utils.video.playbackRate;
this.Utils.video.pause();
} else if (!this.wasPausedBeforeDrag && !this.isDraggingComplete) {
this.isDraggingComplete = true;
// After the drag ends, resume playing.
- this.Utils.video.playbackRate = this.previousPlaybackRate;
this.Utils.video.play();
} else {
this.isDraggingComplete = true;
}
}
]]>
</body>
</method>
@@ -1018,17 +1016,16 @@
},
_triggeredByControls: false,
togglePause : function () {
if (this.video.paused || this.video.ended) {
this._triggeredByControls = true;
this.hideClickToPlay();
- this.video.playbackRate = this.video.defaultPlaybackRate;
this.video.play();
} else {
this.video.pause();
}
// We'll handle style changes in the event listener for
// the "play" and "pause" events, same as if content
// script was controlling video playback.
--- a/view/nsView.cpp
+++ b/view/nsView.cpp
@@ -1118,26 +1118,26 @@ nsView::RequestRepaint()
presShell->ScheduleViewManagerFlush();
}
}
nsEventStatus
nsView::HandleEvent(WidgetGUIEvent* aEvent,
bool aUseAttachedEvents)
{
- NS_PRECONDITION(nullptr != aEvent->widget, "null widget ptr");
+ NS_PRECONDITION(nullptr != aEvent->mWidget, "null widget ptr");
nsEventStatus result = nsEventStatus_eIgnore;
nsView* view;
if (aUseAttachedEvents) {
- nsIWidgetListener* listener = aEvent->widget->GetAttachedWidgetListener();
+ nsIWidgetListener* listener = aEvent->mWidget->GetAttachedWidgetListener();
view = listener ? listener->GetView() : nullptr;
}
else {
- view = GetViewFor(aEvent->widget);
+ view = GetViewFor(aEvent->mWidget);
}
if (view) {
RefPtr<nsViewManager> vm = view->GetViewManager();
vm->DispatchEvent(aEvent, view, &result);
}
return result;
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -495,46 +495,46 @@ public:
******************************************************************************/
class WidgetGUIEvent : public WidgetEvent
{
protected:
WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget,
EventClassID aEventClassID)
: WidgetEvent(aIsTrusted, aMessage, aEventClassID)
- , widget(aWidget)
+ , mWidget(aWidget)
{
}
WidgetGUIEvent()
{
}
public:
virtual WidgetGUIEvent* AsGUIEvent() override { return this; }
WidgetGUIEvent(bool aIsTrusted, EventMessage aMessage, nsIWidget* aWidget)
: WidgetEvent(aIsTrusted, aMessage, eGUIEventClass)
- , widget(aWidget)
+ , mWidget(aWidget)
{
}
virtual WidgetEvent* Duplicate() const override
{
MOZ_ASSERT(mClass == eGUIEventClass,
"Duplicate() must be overridden by sub class");
// Not copying widget, it is a weak reference.
WidgetGUIEvent* result = new WidgetGUIEvent(false, mMessage, nullptr);
result->AssignGUIEventData(*this, true);
result->mFlags = mFlags;
return result;
}
- /// Originator of the event
- nsCOMPtr<nsIWidget> widget;
+ // Originator of the event
+ nsCOMPtr<nsIWidget> mWidget;
/*
* Explanation for this PluginEvent class:
*
* WidgetGUIEvent's mPluginEvent member used to be a void* pointer,
* used to reference external, OS-specific data structures.
*
* That void* pointer wasn't serializable by itself, causing
@@ -587,17 +587,17 @@ public:
}
void Clear()
{
mBuffer.Clear();
}
};
- /// Event for NPAPI plugin
+ // Event for NPAPI plugin
PluginEvent mPluginEvent;
void AssignGUIEventData(const WidgetGUIEvent& aEvent, bool aCopyTargets)
{
AssignEventData(aEvent, aCopyTargets);
// widget should be initialized with the constructor.
--- a/widget/ContentCache.cpp
+++ b/widget/ContentCache.cpp
@@ -841,17 +841,17 @@ ContentCacheInParent::OnCompositionEvent
this, ToChar(aEvent.mMessage),
NS_ConvertUTF16toUTF8(aEvent.mData).get(), aEvent.mData.Length(),
aEvent.mRanges ? aEvent.mRanges->Length() : 0, mPendingEventsNeedingAck,
GetBoolName(mIsComposing), mCommitStringByRequest));
// We must be able to simulate the selection because
// we might not receive selection updates in time
if (!mIsComposing) {
- if (aEvent.widget && aEvent.widget->PluginHasFocus()) {
+ if (aEvent.mWidget && aEvent.mWidget->PluginHasFocus()) {
// If focus is on plugin, we cannot get selection range
mCompositionStart = 0;
} else {
mCompositionStart = mSelection.StartOffset();
}
}
mIsComposing = !aEvent.CausesDOMCompositionEndEvent();
--- a/widget/PuppetWidget.cpp
+++ b/widget/PuppetWidget.cpp
@@ -303,17 +303,17 @@ PuppetWidget::InitEvent(WidgetGUIEvent&
}
event.mTime = PR_Now() / 1000;
}
NS_IMETHODIMP
PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
{
#ifdef DEBUG
- debug_DumpEvent(stdout, event->widget, event, "PuppetWidget", 0);
+ debug_DumpEvent(stdout, event->mWidget, event, "PuppetWidget", 0);
#endif
MOZ_ASSERT(!mChild || mChild->mWindowType == eWindowType_popup,
"Unexpected event dispatch!");
AutoCacheNativeKeyCommands autoCache(this);
if (event->mFlags.mIsSynthesizedForTests && !mNativeKeyCommandsValid) {
WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
--- a/widget/TouchEvents.h
+++ b/widget/TouchEvents.h
@@ -102,17 +102,17 @@ public:
, direction(0)
, delta(0.0)
, clickCount(0)
{
}
WidgetSimpleGestureEvent(const WidgetSimpleGestureEvent& aOther)
: WidgetMouseEventBase(aOther.IsTrusted(), aOther.mMessage,
- aOther.widget, eSimpleGestureEventClass)
+ aOther.mWidget, eSimpleGestureEventClass)
, allowedDirections(aOther.allowedDirections)
, direction(aOther.direction)
, delta(aOther.delta)
, clickCount(0)
{
}
virtual WidgetEvent* Duplicate() const override
@@ -162,17 +162,17 @@ public:
virtual WidgetTouchEvent* AsTouchEvent() override { return this; }
WidgetTouchEvent()
{
MOZ_COUNT_CTOR(WidgetTouchEvent);
}
WidgetTouchEvent(const WidgetTouchEvent& aOther)
- : WidgetInputEvent(aOther.IsTrusted(), aOther.mMessage, aOther.widget,
+ : WidgetInputEvent(aOther.IsTrusted(), aOther.mMessage, aOther.mWidget,
eTouchEventClass)
{
MOZ_COUNT_CTOR(WidgetTouchEvent);
mModifiers = aOther.mModifiers;
mTime = aOther.mTime;
mTimeStamp = aOther.mTimeStamp;
mTouches.AppendElements(aOther.mTouches);
mFlags.mCancelable = mMessage != eTouchCancel;
--- a/widget/android/NativeJSContainer.cpp
+++ b/widget/android/NativeJSContainer.cpp
@@ -34,26 +34,16 @@ bool CheckThread()
if (!NS_IsMainThread()) {
jni::ThrowException("java/lang/IllegalThreadStateException",
"Not on Gecko thread");
return false;
}
return true;
}
-bool
-CheckJSCall(bool result)
-{
- if (!result) {
- jni::ThrowException("java/lang/UnsupportedOperationException",
- "JSAPI call failed");
- }
- return result;
-}
-
template<class C, typename T> bool
CheckJNIArgument(const jni::Ref<C, T>& arg)
{
if (!arg) {
jni::ThrowException("java/lang/IllegalArgumentException",
"Null argument");
}
return !!arg;
@@ -124,16 +114,26 @@ class NativeJSContainerImpl final
{
if (!mJSObject) {
jni::ThrowException("java/lang/NullPointerException",
"Null JSObject");
}
return !!mJSObject;
}
+ bool CheckJSCall(bool result) const
+ {
+ if (!result) {
+ JS_ClearPendingException(mJSContext);
+ jni::ThrowException("java/lang/UnsupportedOperationException",
+ "JSAPI call failed");
+ }
+ return result;
+ }
+
// Check that a JS Value contains a particular property type as indicaed by
// the property's InValue method (e.g. StringProperty::InValue).
bool CheckProperty(bool (Self::*InValue)(JS::HandleValue) const,
JS::HandleValue val) const
{
if (!(this->*InValue)(val)) {
// XXX this can happen when converting a double array inside a
// Bundle, because double arrays can be misidentified as an int
@@ -430,27 +430,31 @@ class NativeJSContainerImpl final
return false;
}
JS::RootedObject obj(mJSContext, &val.toObject());
bool isArray;
uint32_t length = 0;
if (!JS_IsArrayObject(mJSContext, obj, &isArray) ||
!isArray ||
!JS_GetArrayLength(mJSContext, obj, &length)) {
+ JS_ClearPendingException(mJSContext);
return false;
}
if (!length) {
// Empty arrays are always okay.
return true;
}
// We only check to see the first element is the target type. If the
// array has mixed types, we'll throw an error during actual conversion.
JS::RootedValue element(mJSContext);
- return JS_GetElement(mJSContext, obj, 0, &element) &&
- (this->*Prop::InValue)(element);
+ if (!JS_GetElement(mJSContext, obj, 0, &element)) {
+ JS_ClearPendingException(mJSContext);
+ return false;
+ }
+ return (this->*Prop::InValue)(element);
}
template<class Prop> typename Prop::NativeArray
ArrayFromValue(JS::HandleValue val)
{
JS::RootedObject obj(mJSContext, &val.toObject());
uint32_t length = 0;
if (!CheckJSCall(JS_GetArrayLength(mJSContext, obj, &length))) {
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -3096,17 +3096,17 @@ nsWindow::GeckoViewSupport::OnImeReplace
status == nsEventStatus_eConsumeNoDefault) {
MOZ_ASSERT(i > 0 &&
mIMEKeyEvents[i - 1]->mMessage == eKeyDown);
// The previous key down event resulted in eConsumeNoDefault
// so we should not dispatch the current key press event.
continue;
}
// widget for duplicated events is initially nullptr.
- event->widget = &window;
+ event->mWidget = &window;
window.DispatchEvent(event, status);
}
mIMEKeyEvents.Clear();
return;
}
{
WidgetCompositionEvent event(true, eCompositionStart, &window);
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -1431,17 +1431,17 @@ nsresult nsChildView::ConfigureChildren(
return NS_OK;
}
// Invokes callback and ProcessEvent methods on Event Listener object
NS_IMETHODIMP nsChildView::DispatchEvent(WidgetGUIEvent* event,
nsEventStatus& aStatus)
{
#ifdef DEBUG
- debug_DumpEvent(stdout, event->widget, event, "something", 0);
+ debug_DumpEvent(stdout, event->mWidget, event, "something", 0);
#endif
NS_ASSERTION(!(mTextInputHandler && mTextInputHandler->IsIMEComposing() &&
event->HasKeyEventMessage()),
"Any key events should not be fired during IME composing");
if (event->mFlags.mIsSynthesizedForTests) {
WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent();
@@ -1456,21 +1456,22 @@ NS_IMETHODIMP nsChildView::DispatchEvent
nsIWidgetListener* listener = mWidgetListener;
// If the listener is NULL, check if the parent is a popup. If it is, then
// this child is the popup content view attached to a popup. Get the
// listener from the parent popup instead.
nsCOMPtr<nsIWidget> kungFuDeathGrip = do_QueryInterface(mParentWidget ? mParentWidget : this);
if (!listener && mParentWidget) {
if (mParentWidget->WindowType() == eWindowType_popup) {
- // Check just in case event->widget isn't this widget
- if (event->widget)
- listener = event->widget->GetWidgetListener();
+ // Check just in case event->mWidget isn't this widget
+ if (event->mWidget) {
+ listener = event->mWidget->GetWidgetListener();
+ }
if (!listener) {
- event->widget = mParentWidget;
+ event->mWidget = mParentWidget;
listener = mParentWidget->GetWidgetListener();
}
}
}
if (listener)
aStatus = listener->HandleEvent(event, mUseAttachedEvents);
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -1873,24 +1873,21 @@ NS_IMETHODIMP nsCocoaWindow::GetSheetWin
}
// Invokes callback and ProcessEvent methods on Event Listener object
NS_IMETHODIMP
nsCocoaWindow::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus)
{
aStatus = nsEventStatus_eIgnore;
- nsIWidget* aWidget = event->widget;
- NS_IF_ADDREF(aWidget);
+ nsCOMPtr<nsIWidget> kungFuDeathGrip(event->mWidget);
if (mWidgetListener)
aStatus = mWidgetListener->HandleEvent(event, mUseAttachedEvents);
- NS_IF_RELEASE(aWidget);
-
return NS_OK;
}
// aFullScreen should be the window's mInFullScreenMode. We don't have access to that
// from here, so we need to pass it in. mInFullScreenMode should be the canonical
// indicator that a window is currently full screen and it makes sense to keep
// all sizemode logic here.
static nsSizeMode
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -138,17 +138,17 @@ nsWindow::DispatchKeyInput(WidgetKeyboar
{
if (!gFocusedWindow) {
return nsEventStatus_eIgnore;
}
gFocusedWindow->UserActivity();
nsEventStatus status;
- aEvent.widget = gFocusedWindow;
+ aEvent.mWidget = gFocusedWindow;
gFocusedWindow->DispatchEvent(&aEvent, status);
return status;
}
/*static*/ void
nsWindow::DispatchTouchInput(MultiTouchInput& aInput)
{
APZThreadUtils::AssertOnControllerThread();
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -550,17 +550,17 @@ nsWindow::MaybeDispatchResized()
DispatchResized();
}
}
nsresult
nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
{
#ifdef DEBUG
- debug_DumpEvent(stdout, aEvent->widget, aEvent,
+ debug_DumpEvent(stdout, aEvent->mWidget, aEvent,
"something", 0);
#endif
aStatus = nsEventStatus_eIgnore;
nsIWidgetListener* listener =
mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
if (listener) {
aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
}
@@ -6555,26 +6555,26 @@ nsWindow::GetDragInfo(WidgetMouseEvent*
#endif
// find the top-level window
gdk_window = gdk_window_get_toplevel(gdk_window);
MOZ_ASSERT(gdk_window,
"gdk_window_get_toplevel should not return null");
*aWindow = gdk_window;
- if (!aMouseEvent->widget) {
+ if (!aMouseEvent->mWidget) {
return false;
}
// FIXME: It would be nice to have the widget position at the time
// of the event, but it's relatively unlikely that the widget has
// moved since the mousedown. (On the other hand, it's quite likely
// that the mouse has moved, which is why we use the mouse position
// from the event.)
- LayoutDeviceIntPoint offset = aMouseEvent->widget->WidgetToScreenOffset();
+ LayoutDeviceIntPoint offset = aMouseEvent->mWidget->WidgetToScreenOffset();
*aRootX = aMouseEvent->refPoint.x + offset.x;
*aRootY = aMouseEvent->refPoint.y + offset.y;
return true;
}
NS_IMETHODIMP
nsWindow::BeginMoveDrag(WidgetMouseEvent* aEvent)
--- a/widget/nsBaseFilePicker.cpp
+++ b/widget/nsBaseFilePicker.cpp
@@ -41,18 +41,17 @@ LocalFileToDirectoryOrBlob(nsPIDOMWindow
{
if (aIsDirectory) {
#ifdef DEBUG
bool isDir;
aFile->IsDirectory(&isDir);
MOZ_ASSERT(isDir);
#endif
- RefPtr<Directory> directory =
- Directory::Create(aWindow, aFile, Directory::eDOMRootDirectory);
+ RefPtr<Directory> directory = Directory::Create(aWindow, aFile);
MOZ_ASSERT(directory);
directory.forget(aResult);
return NS_OK;
}
nsCOMPtr<nsIDOMBlob> blob = File::CreateFromFile(aWindow, aFile);
blob.forget(aResult);
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1281,16 +1281,17 @@ void nsBaseWidget::CreateCompositor(int
shadowManager = mCompositorBridgeChild->SendPLayerTransactionConstructor(
backendHints, 0, &textureFactoryIdentifier, &success);
}
ShadowLayerForwarder* lf = lm->AsShadowForwarder();
if (!success || !lf) {
NS_WARNING("Failed to create an OMT compositor.");
+ mAPZC = nullptr;
DestroyCompositor();
mLayerManager = nullptr;
mCompositorBridgeChild = nullptr;
mCompositorBridgeParent = nullptr;
mCompositorVsyncDispatcher = nullptr;
return;
}
--- a/widget/nsFilePickerProxy.cpp
+++ b/widget/nsFilePickerProxy.cpp
@@ -169,18 +169,17 @@ nsFilePickerProxy::Recv__delete__(const
nsCOMPtr<nsIFile> file;
NS_ConvertUTF16toUTF8 path(aData.get_InputDirectory().directoryPath());
nsresult rv = NS_NewNativeLocalFile(path, true, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return true;
}
RefPtr<Directory> directory =
- Directory::Create(mParent->GetCurrentInnerWindow(), file,
- Directory::eDOMRootDirectory);
+ Directory::Create(mParent->GetCurrentInnerWindow(), file);
MOZ_ASSERT(directory);
OwningFileOrDirectory* element = mFilesOrDirectories.AppendElement();
element->SetAsDirectory() = directory;
}
if (mCallback) {
mCallback->Done(aResult);
--- a/widget/qt/nsWindow.cpp
+++ b/widget/qt/nsWindow.cpp
@@ -676,17 +676,17 @@ nsWindow::GetNativeData(uint32_t aDataTy
LOG(("nsWindow::%s [%p] aDataType:%i\n", __FUNCTION__, (void *)this, aDataType));
return nullptr;
}
NS_IMETHODIMP
nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
{
#ifdef DEBUG
- debug_DumpEvent(stdout, aEvent->widget, aEvent,
+ debug_DumpEvent(stdout, aEvent->mWidget, aEvent,
"something", 0);
#endif
aStatus = nsEventStatus_eIgnore;
// send it to the standard callback
if (mWidgetListener) {
aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
--- a/widget/uikit/nsWindow.mm
+++ b/widget/uikit/nsWindow.mm
@@ -816,17 +816,17 @@ LayoutDeviceIntPoint nsWindow::WidgetToS
return offset;
}
NS_IMETHODIMP
nsWindow::DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
nsEventStatus& aStatus)
{
aStatus = nsEventStatus_eIgnore;
- nsCOMPtr<nsIWidget> kungFuDeathGrip = do_QueryInterface(aEvent->widget);
+ nsCOMPtr<nsIWidget> kungFuDeathGrip(aEvent->mWidget);
if (mWidgetListener)
aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
return NS_OK;
}
NS_IMETHODIMP_(void)
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3861,17 +3861,17 @@ nsWindow::CurrentMessageWidgetEventTime(
// Main event dispatch. Invokes callback and ProcessEvent method on
// Event Listener object. Part of nsIWidget.
NS_IMETHODIMP nsWindow::DispatchEvent(WidgetGUIEvent* event,
nsEventStatus& aStatus)
{
#ifdef WIDGET_DEBUG_OUTPUT
debug_DumpEvent(stdout,
- event->widget,
+ event->mWidget,
event,
"something",
(int32_t) mWnd);
#endif // WIDGET_DEBUG_OUTPUT
aStatus = nsEventStatus_eIgnore;
// Top level windows can have a view attached which requires events be sent
@@ -5368,16 +5368,26 @@ nsWindow::ProcessMessage(UINT msg, WPARA
nullptr);
}
}
break;
}
case WM_MOVING:
FinishLiveResizing(MOVING);
+ if (WinUtils::IsPerMonitorDPIAware()) {
+ // Sometimes, we appear to miss a WM_DPICHANGED message while moving
+ // a window around. Therefore, call ChangedDPI and ResetLayout here,
+ // which causes the prescontext and appshell window management code to
+ // check the appUnitsPerDevPixel value and current widget size, and
+ // refresh them if necessary. If nothing has changed, these calls will
+ // return without actually triggering any extra reflow or painting.
+ ChangedDPI();
+ ResetLayout();
+ }
break;
case WM_ENTERSIZEMOVE:
{
if (mResizeState == NOT_RESIZING) {
mResizeState = IN_SIZEMOVE;
}
break;
@@ -6919,16 +6929,17 @@ nsWindow::OnDPIChanged(int32_t x, int32_
width = std::min(width, availWidth);
height = std::min(height, availHeight);
}
}
Resize(x, y, width, height, true);
}
ChangedDPI();
+ ResetLayout();
}
/**************************************************************
**************************************************************
**
** BLOCK: IME management and accessibility
**
** Handles managing IME input and accessibility.
--- a/xpcom/base/nsWindowsHelpers.h
+++ b/xpcom/base/nsWindowsHelpers.h
@@ -207,25 +207,112 @@ public:
static void Release(RawRef aDevMode)
{
if (aDevMode != Void()) {
::HeapFree(::GetProcessHeap(), 0, aDevMode);
}
}
};
+
+// HGLOBAL is just a typedef of HANDLE which nsSimpleRef has a specialization of,
+// that means having a nsAutoRefTraits specialization for HGLOBAL is useless.
+// Therefore we create a wrapper class for HGLOBAL to make nsAutoRefTraits and
+// nsAutoRef work as intention.
+class nsHGLOBAL {
+public:
+ nsHGLOBAL(HGLOBAL hGlobal) : m_hGlobal(hGlobal)
+ {
+ }
+
+ operator HGLOBAL() const
+ {
+ return m_hGlobal;
+ }
+
+private:
+ HGLOBAL m_hGlobal;
+};
+
+
+template<>
+class nsAutoRefTraits<nsHGLOBAL>
+{
+public:
+ typedef nsHGLOBAL RawRef;
+ static RawRef Void()
+ {
+ return nullptr;
+ }
+
+ static void Release(RawRef hGlobal)
+ {
+ ::GlobalFree(hGlobal);
+ }
+};
+
+
+// Because Printer's HANDLE uses ClosePrinter and we already have nsAutoRef<HANDLE>
+// which uses CloseHandle so we need to create a wrapper class for HANDLE to have
+// another specialization for nsAutoRefTraits.
+class nsHPRINTER {
+public:
+ nsHPRINTER(HANDLE hPrinter) : m_hPrinter(hPrinter)
+ {
+ }
+
+ operator HANDLE() const
+ {
+ return m_hPrinter;
+ }
+
+ HANDLE* operator&()
+ {
+ return &m_hPrinter;
+ }
+
+private:
+ HANDLE m_hPrinter;
+};
+
+
+// winspool.h header has AddMonitor macro, it conflicts with AddMonitor member
+// function in TaskbarPreview.cpp and TaskbarTabPreview.cpp. Beside, we only
+// need ClosePrinter here for Release function, so having its prototype is enough.
+extern "C" BOOL WINAPI ClosePrinter(HANDLE hPrinter);
+
+
+template<>
+class nsAutoRefTraits<nsHPRINTER>
+{
+public:
+ typedef nsHPRINTER RawRef;
+ static RawRef Void()
+ {
+ return nullptr;
+ }
+
+ static void Release(RawRef hPrinter)
+ {
+ ::ClosePrinter(hPrinter);
+ }
+};
+
+
typedef nsAutoRef<HKEY> nsAutoRegKey;
typedef nsAutoRef<HDC> nsAutoHDC;
typedef nsAutoRef<HBRUSH> nsAutoBrush;
typedef nsAutoRef<HRGN> nsAutoRegion;
typedef nsAutoRef<HBITMAP> nsAutoBitmap;
typedef nsAutoRef<SC_HANDLE> nsAutoServiceHandle;
typedef nsAutoRef<HANDLE> nsAutoHandle;
typedef nsAutoRef<HMODULE> nsModuleHandle;
typedef nsAutoRef<DEVMODEW*> nsAutoDevMode;
+typedef nsAutoRef<nsHGLOBAL> nsAutoGlobalMem;
+typedef nsAutoRef<nsHPRINTER> nsAutoPrinter;
namespace {
// Construct a path "<system32>\<aModule>". return false if the output buffer
// is too small.
// Note: If the system path cannot be found, or doesn't fit in the output buffer
// with the module name, we will just ignore the system path and output the
// module name alone;