Bug 1363168 - Add support for OSX Share feature. r=gijs, r=mstange draft
authorDale Harvey <dale@arandomurl.com>
Mon, 12 Mar 2018 09:16:51 +0000
changeset 777946 e2f59e695f038804d22046162c12e0070a475052
parent 777898 404bbf763428f34cc5d20fbc0c634eb02c5cceab
push id105344
push userbmo:dharvey@mozilla.com
push dateThu, 05 Apr 2018 15:28:45 +0000
reviewersgijs, mstange
bugs1363168
milestone61.0a1
Bug 1363168 - Add support for OSX Share feature. r=gijs, r=mstange MozReview-Commit-ID: sJXl2If9Ou
browser/base/content/browser-pageActions.js
browser/base/content/browser.xul
browser/locales/en-US/chrome/browser/browser.dtd
browser/modules/PageActions.jsm
browser/themes/shared/icons/share.svg
browser/themes/shared/jar.inc.mn
browser/themes/shared/urlbar-searchbar.inc.css
widget/cocoa/moz.build
widget/cocoa/nsMacSharingService.h
widget/cocoa/nsMacSharingService.mm
widget/cocoa/nsMacWebAppUtils.mm
widget/cocoa/nsPrintDialogX.mm
widget/cocoa/nsWidgetFactory.mm
widget/moz.build
widget/nsIMacSharingService.idl
widget/nsWidgetsCID.h
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -1257,8 +1257,60 @@ BrowserPageActions.addSearchEngine = {
         let prompt = Services.prompt.getPrompt(gBrowser.contentWindow, Ci.nsIPrompt);
         prompt.QueryInterface(Ci.nsIWritablePropertyBag2);
         prompt.setPropertyAsBool("allowTabModal", true);
         prompt.alert(title, text);
       },
     });
   },
 };
+
+// share URL
+BrowserPageActions.shareURL = {
+  onShowingInPanel(buttonNode) {
+    this.redraw = true;
+  },
+
+  onPlacedInPanel(buttonNode) {
+    let action = PageActions.actionForID("shareURL");
+    BrowserPageActions.takeActionTitleFromPanel(action);
+  },
+
+  onShowingSubview(panelViewNode) {
+    // We cache the providers + the UI if the user selects the share
+    // panel multiple times while the panel is open.
+    if (this.redraw === false) {
+      return;
+    }
+
+    let sharingService = Cc["@mozilla.org/widget/macsharingservice;1"]
+        .createInstance(Ci.nsIMacSharingService);
+    let currentURI = gBrowser.selectedBrowser.currentURI.spec;
+    let shareProviders = sharingService.getSharingProviders(currentURI);
+    let fragment = document.createDocumentFragment();
+
+    shareProviders.forEach(function(share) {
+
+      let item = document.createElement("toolbarbutton");
+      item.setAttribute("label", share.menuItemTitle);
+      item.setAttribute("share-title", share.title);
+      item.setAttribute("image", share.image);
+      item.classList.add("subviewbutton", "subviewbutton-iconic");
+
+      item.addEventListener("command", event => {
+        let shareTitle = event.target.getAttribute("share-title");
+        if (shareTitle) {
+          sharingService.shareUrl(shareTitle, currentURI);
+          PanelMultiView.hidePopup(BrowserPageActions.panelNode);
+        }
+      });
+
+      fragment.appendChild(item);
+    });
+
+    let bodyNode = panelViewNode.querySelector(".panel-subview-body");
+    while (bodyNode.firstChild) {
+      bodyNode.firstChild.remove();
+    }
+    bodyNode.appendChild(fragment);
+    this.redraw = false;
+  }
+};
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -435,17 +435,18 @@
            flip="slide"
            photon="true"
            position="bottomcenter topright"
            tabspecific="true"
            noautofocus="true"
            copyURL-title="&pageAction.copyLink.label;"
            emailLink-title="&emailPageCmd.label;"
            sendToDevice-title="&pageAction.sendTabToDevice.label;"
-           sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;">
+           sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;"
+           shareURL-title="&pageAction.shareUrl.label;">
       <panelmultiview id="pageActionPanelMultiView"
                       mainViewId="pageActionPanelMainView"
                       viewCacheId="appMenu-viewCache">
         <panelview id="pageActionPanelMainView"
                    context="pageActionContextMenu"
                    class="PanelUI-subView">
           <vbox class="panel-subview-body"/>
         </panelview>
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -987,16 +987,18 @@ you can use these alternative items. Oth
 <!ENTITY pageAction.removeFromUrlbar.label "Remove from Address Bar">
 <!ENTITY pageAction.allowInUrlbar.label "Show in Address Bar">
 <!ENTITY pageAction.disallowInUrlbar.label "Don’t Show in Address Bar">
 <!ENTITY pageAction.manageExtension.label "Manage Extension…">
 
 <!ENTITY pageAction.sendTabToDevice.label "Send Tab to Device">
 <!ENTITY sendToDevice.syncNotReady.label "Syncing Devices…">
 
+<!ENTITY pageAction.shareUrl.label "Share">
+
 <!ENTITY libraryButton.tooltip "View history, saved bookmarks, and more">
 
 <!-- LOCALIZATION NOTE: (accessibilityIndicator.tooltip): This is used to
      display a tooltip for accessibility indicator in toolbar/tabbar. It is also
      used as a textual label for the indicator used by assistive technology
      users. -->
 <!ENTITY accessibilityIndicator.tooltip "Accessibility Features Enabled">
 
--- a/browser/modules/PageActions.jsm
+++ b/browser/modules/PageActions.jsm
@@ -1162,16 +1162,35 @@ if (Services.prefs.getBoolPref("identity
     },
     onSubviewShowing(panelViewNode) {
       browserPageActions(panelViewNode).sendToDevice
         .onShowingSubview(panelViewNode);
     },
   });
 }
 
+if (AppConstants.platform == "macosx") {
+  gBuiltInActions.push(
+  // Share URL
+  {
+    id: "shareURL",
+    title: "shareURL-title",
+    onShowingInPanel(buttonNode) {
+      browserPageActions(buttonNode).shareURL.onShowingInPanel(buttonNode);
+    },
+    onPlacedInPanel(buttonNode) {
+      browserPageActions(buttonNode).shareURL.onPlacedInPanel(buttonNode);
+    },
+    wantsSubview: true,
+    onSubviewShowing(panelViewNode) {
+        browserPageActions(panelViewNode).shareURL
+          .onShowingSubview(panelViewNode);
+    },
+  });
+}
 
 /**
  * Gets a BrowserPageActions object in a browser window.
  *
  * @param  obj
  *         Either a DOM node or a browser window.
  * @return The BrowserPageActions object in the browser window related to the
  *         given object.
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/icons/share.svg
@@ -0,0 +1,7 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <path fill="context-fill" d="M12.707 4.294l-4-4A1 1 0 0 0 8.38.077a.984.984 0 0 0-.246-.05A.938.938 0 0 0 8 0a.938.938 0 0 0-.134.027.984.984 0 0 0-.246.05A1 1 0 0 0 7.291.3l-4 4a1 1 0 0 0 1.416 1.408L7 3.415V11a1 1 0 0 0 2 0V3.415l2.293 2.293a1 1 0 0 0 1.414-1.414z"></path>
+  <path fill="context-fill" d="M14 9a1 1 0 0 0-1 1v3a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1v-3a1 1 0 0 0-2 0v3a3 3 0 0 0 3 3h8a3 3 0 0 0 3-3v-3a1 1 0 0 0-1-1z"></path>
+</svg>
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -157,16 +157,17 @@
   skin/classic/browser/restore-session.svg            (../shared/icons/restore-session.svg)
   skin/classic/browser/quit.svg                       (../shared/icons/quit.svg)
   skin/classic/browser/reload.svg                     (../shared/icons/reload.svg)
   skin/classic/browser/reload-to-stop.svg             (../shared/icons/reload-to-stop.svg)
   skin/classic/browser/save.svg                       (../shared/icons/save.svg)
   skin/classic/browser/search-glass.svg               (../shared/icons/search-glass.svg)
   skin/classic/browser/send-to-device.svg             (../shared/icons/send-to-device.svg)
   skin/classic/browser/settings.svg                   (../shared/icons/settings.svg)
+  skin/classic/browser/share.svg                      (../shared/icons/share.svg)
   skin/classic/browser/sidebars.svg                   (../shared/icons/sidebars.svg)
   skin/classic/browser/sidebars-right.svg             (../shared/icons/sidebars-right.svg)
   skin/classic/browser/stop.svg                       (../shared/icons/stop.svg)
   skin/classic/browser/stop-to-reload.svg             (../shared/icons/stop-to-reload.svg)
   skin/classic/browser/sync.svg                       (../shared/icons/sync.svg)
   skin/classic/browser/tab.svg                        (../shared/icons/tab.svg)
   skin/classic/browser/bookmarks-toolbar.svg          (../shared/icons/bookmarks-toolbar.svg)
   skin/classic/browser/webIDE.svg                     (../shared/icons/webIDE.svg)
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -164,16 +164,20 @@
 }
 
 .pageAction-sendToDevice-device.signintosync,
 #pageAction-panel-sendToDevice-fxa,
 #pageAction-urlbar-sendToDevice-fxa {
   list-style-image: url("chrome://browser/skin/sync.svg");
 }
 
+#pageAction-panel-shareURL {
+  list-style-image: url("chrome://browser/skin/share.svg");
+}
+
 #pageAction-panel-addSearchEngine > .toolbarbutton-badge-stack > .toolbarbutton-icon {
   width: 16px;
   height: 16px;
 }
 #pageAction-panel-addSearchEngine > .toolbarbutton-badge-stack > .toolbarbutton-badge {
   display: -moz-box;
   background: url(chrome://browser/skin/search-indicator-badge-add.svg) no-repeat center;
   box-shadow: none;
--- a/widget/cocoa/moz.build
+++ b/widget/cocoa/moz.build
@@ -34,16 +34,17 @@ UNIFIED_SOURCES += [
     'nsColorPicker.mm',
     'nsCursorManager.mm',
     'nsDeviceContextSpecX.mm',
     'nsFilePicker.mm',
     'nsIdleServiceX.mm',
     'nsLookAndFeel.mm',
     'nsMacCursor.mm',
     'nsMacDockSupport.mm',
+    'nsMacSharingService.mm',
     'nsMacWebAppUtils.mm',
     'nsMenuBarX.mm',
     'nsMenuGroupOwnerX.mm',
     'nsMenuItemIconX.mm',
     'nsMenuItemX.mm',
     'nsMenuUtilsX.mm',
     'nsMenuX.mm',
     'nsPrintDialogX.mm',
new file mode 100644
--- /dev/null
+++ b/widget/cocoa/nsMacSharingService.h
@@ -0,0 +1,23 @@
+/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
+/* 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 nsMacSharingService_h_
+#define nsMacSharingService_h_
+
+#include "nsIMacSharingService.h"
+
+class nsMacSharingService : public nsIMacSharingService
+{
+public:
+  nsMacSharingService() {}
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMACSHARINGSERVICE
+
+protected:
+  virtual ~nsMacSharingService() {}
+};
+
+#endif // nsMacSharingService_h_
new file mode 100644
--- /dev/null
+++ b/widget/cocoa/nsMacSharingService.mm
@@ -0,0 +1,77 @@
+/* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
+/* 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 <Cocoa/Cocoa.h>
+
+#include "nsMacSharingService.h"
+#include "nsCocoaUtils.h"
+#include "mozilla/MacStringHelpers.h"
+
+NS_IMPL_ISUPPORTS(nsMacSharingService, nsIMacSharingService)
+
+NSString* NSImageToBase64(const NSImage* image) {
+  [image lockFocus];
+  NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, image.size.width, image.size.height)];
+  [image unlockFocus];
+  NSData *imageData = [bitmapRep representationUsingType:NSPNGFileType properties:@{}];
+  [bitmapRep release];
+  NSString *base64Encoded = [imageData base64EncodedStringWithOptions:0];
+  return [NSString stringWithFormat: @"data:image/png;base64,%@", base64Encoded];
+}
+
+void setStrAttribute(JSContext* aCx, JS::Rooted<JSObject*>& obj, const char* key, NSString* val) {
+  nsAutoString strVal;
+  mozilla::CopyCocoaStringToXPCOMString(val, strVal);
+  JS::Rooted<JSString*> title(aCx, JS_NewUCStringCopyZ(aCx, strVal.get()));
+  JS::Rooted<JS::Value> attVal(aCx, JS::StringValue(title));
+  JS_SetProperty(aCx, obj, key, attVal);
+}
+
+nsresult nsMacSharingService::GetSharingProviders(const nsAString& urlToShare, JSContext* aCx, JS::MutableHandleValue aResult) {
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
+  NSURL *url = [NSURL URLWithString:nsCocoaUtils::ToNSString(urlToShare)];
+
+  NSArray *sharingService = [NSSharingService sharingServicesForItems:[NSArray arrayWithObject:url]];
+  int32_t serviceCount = 0;
+
+  for (NSSharingService *currentService in sharingService) {
+
+    JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
+
+    setStrAttribute(aCx, obj, "title", currentService.title);
+    setStrAttribute(aCx, obj, "menuItemTitle", currentService.menuItemTitle);
+    setStrAttribute(aCx, obj, "image", NSImageToBase64(currentService.image));
+
+    JS::Rooted<JS::Value> element(aCx, JS::ObjectValue(*obj));
+    JS_SetElement(aCx, array, serviceCount++, element);
+  }
+
+  aResult.setObject(*array);
+
+  return NS_OK;
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+NS_IMETHODIMP nsMacSharingService::ShareUrl(const nsAString& shareTitle, const nsAString& urlToShare) {
+  NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+  NSString* titleString = nsCocoaUtils::ToNSString(shareTitle);
+  NSURL *url = [NSURL URLWithString:nsCocoaUtils::ToNSString(urlToShare)];
+
+  NSArray *sharingService = [NSSharingService sharingServicesForItems:[NSArray arrayWithObject:url]];
+
+  for (NSSharingService *currentService in sharingService) {
+    if ([currentService.title isEqualToString:titleString]) {
+      [currentService performWithItems:@[url]];
+      break;
+    }
+  }
+
+  return NS_OK;
+
+  NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
--- a/widget/cocoa/nsMacWebAppUtils.mm
+++ b/widget/cocoa/nsMacWebAppUtils.mm
@@ -4,16 +4,18 @@
 
 #import <Cocoa/Cocoa.h>
 
 #include "nsMacWebAppUtils.h"
 #include "nsCOMPtr.h"
 #include "nsCocoaUtils.h"
 #include "nsString.h"
 
+#include "mozilla/MacStringHelpers.h"
+
 // This must be included last:
 #include "nsObjCExceptions.h"
 
 // Find the path to the app with the given bundleIdentifier, if any.
 // Note that the OS will return the path to the newest binary, if there is more than one.
 // The determination of 'newest' is complex and beyond the scope of this comment.
 
 NS_IMPL_ISUPPORTS(nsMacWebAppUtils, nsIMacWebAppUtils)
--- a/widget/cocoa/nsPrintDialogX.mm
+++ b/widget/cocoa/nsPrintDialogX.mm
@@ -1,14 +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 "mozilla/ArrayUtils.h"
+#include "mozilla/gfx/PrintTargetCG.h"
 #include "mozilla/Preferences.h"
 
 #include "nsPrintDialogX.h"
 #include "nsIPrintSettings.h"
 #include "nsIPrintSettingsService.h"
 #include "nsPrintSettingsX.h"
 #include "nsCOMPtr.h"
 #include "nsQueryObject.h"
@@ -17,16 +18,17 @@
 #include "nsIStringBundle.h"
 #include "nsIWebBrowserPrint.h"
 #include "nsCRT.h"
 
 #import <Cocoa/Cocoa.h>
 #include "nsObjCExceptions.h"
 
 using namespace mozilla;
+using mozilla::gfx::PrintTarget;
 
 NS_IMPL_ISUPPORTS(nsPrintDialogServiceX, nsIPrintDialogService)
 
 nsPrintDialogServiceX::nsPrintDialogServiceX()
 {
 }
 
 nsPrintDialogServiceX::~nsPrintDialogServiceX()
--- a/widget/cocoa/nsWidgetFactory.mm
+++ b/widget/cocoa/nsWidgetFactory.mm
@@ -89,16 +89,19 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsNativeM
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
 
 #include "nsNativeThemeCocoa.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsNativeThemeCocoa)
 
 #include "nsMacDockSupport.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacDockSupport)
 
+#include "nsMacSharingService.h"
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacSharingService)
+
 #include "nsMacWebAppUtils.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacWebAppUtils)
 
 #include "nsStandaloneNativeMenu.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsStandaloneNativeMenu)
 
 #include "nsSystemStatusBarCocoa.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSystemStatusBarCocoa)
@@ -129,16 +132,17 @@ NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID
 NS_DEFINE_NAMED_CID(NS_DEVICE_CONTEXT_SPEC_CID);
 NS_DEFINE_NAMED_CID(NS_PRINTSESSION_CID);
 NS_DEFINE_NAMED_CID(NS_PRINTSETTINGSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_PRINTDIALOGSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_IDLE_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_SYSTEMALERTSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_NATIVEMENUSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_MACDOCKSUPPORT_CID);
+NS_DEFINE_NAMED_CID(NS_MACSHARINGSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_MACWEBAPPUTILS_CID);
 NS_DEFINE_NAMED_CID(NS_STANDALONENATIVEMENU_CID);
 NS_DEFINE_NAMED_CID(NS_MACSYSTEMSTATUSBAR_CID);
 NS_DEFINE_NAMED_CID(NS_GFXINFO_CID);
 
 static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
   { &kNS_WINDOW_CID, false, NULL, nsCocoaWindowConstructor },
   { &kNS_POPUP_CID, false, NULL, nsCocoaWindowConstructor },
@@ -165,16 +169,17 @@ static const mozilla::Module::CIDEntry k
   { &kNS_DEVICE_CONTEXT_SPEC_CID, false, NULL, nsDeviceContextSpecXConstructor },
   { &kNS_PRINTSESSION_CID, false, NULL, nsPrintSessionConstructor },
   { &kNS_PRINTSETTINGSSERVICE_CID, false, NULL, nsPrintSettingsServiceXConstructor },
   { &kNS_PRINTDIALOGSERVICE_CID, false, NULL, nsPrintDialogServiceXConstructor },
   { &kNS_IDLE_SERVICE_CID, false, NULL, nsIdleServiceXConstructor },
   { &kNS_SYSTEMALERTSSERVICE_CID, false, NULL, OSXNotificationCenterConstructor },
   { &kNS_NATIVEMENUSERVICE_CID, false, NULL, nsNativeMenuServiceXConstructor },
   { &kNS_MACDOCKSUPPORT_CID, false, NULL, nsMacDockSupportConstructor },
+  { &kNS_MACSHARINGSERVICE_CID, false, NULL, nsMacSharingServiceConstructor },
   { &kNS_MACWEBAPPUTILS_CID, false, NULL, nsMacWebAppUtilsConstructor },
   { &kNS_STANDALONENATIVEMENU_CID, false, NULL, nsStandaloneNativeMenuConstructor },
   { &kNS_MACSYSTEMSTATUSBAR_CID, false, NULL, nsSystemStatusBarCocoaConstructor },
   { &kNS_GFXINFO_CID, false, NULL, mozilla::widget::GfxInfoConstructor },
   { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
@@ -203,16 +208,17 @@ static const mozilla::Module::ContractID
   { "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID },
   { "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID },
   { "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID },
   { NS_PRINTDIALOGSERVICE_CONTRACTID, &kNS_PRINTDIALOGSERVICE_CID },
   { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID },
   { "@mozilla.org/system-alerts-service;1", &kNS_SYSTEMALERTSSERVICE_CID },
   { "@mozilla.org/widget/nativemenuservice;1", &kNS_NATIVEMENUSERVICE_CID },
   { "@mozilla.org/widget/macdocksupport;1", &kNS_MACDOCKSUPPORT_CID },
+  { "@mozilla.org/widget/macsharingservice;1", &kNS_MACSHARINGSERVICE_CID },
   { "@mozilla.org/widget/mac-web-app-utils;1", &kNS_MACWEBAPPUTILS_CID },
   { "@mozilla.org/widget/standalonenativemenu;1", &kNS_STANDALONENATIVEMENU_CID },
   { "@mozilla.org/widget/macsystemstatusbar;1", &kNS_MACSYSTEMSTATUSBAR_CID },
   { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
   { NULL }
 };
 
 static void
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -54,16 +54,17 @@ if toolkit == 'windows':
         'nsITaskbarTabPreview.idl',
         'nsITaskbarWindowPreview.idl',
         'nsIWindowsUIUtils.idl',
         'nsIWinTaskbar.idl',
     ]
 elif toolkit == 'cocoa':
     XPIDL_SOURCES += [
         'nsIMacDockSupport.idl',
+        'nsIMacSharingService.idl',
         'nsIMacWebAppUtils.idl',
         'nsIStandaloneNativeMenu.idl',
         'nsISystemStatusBar.idl',
         'nsITaskbarProgress.idl',
     ]
     EXPORTS += [
         'nsINativeMenuService.h',
     ]
new file mode 100644
--- /dev/null
+++ b/widget/nsIMacSharingService.idl
@@ -0,0 +1,23 @@
+/* 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 "nsISupports.idl"
+
+/**
+ * Allow applications to interface with the Mac OS X Sharing APIs.
+ */
+
+[scriptable, uuid(de59fe1a-46c8-490f-b04d-34545acb06c9)]
+interface nsIMacSharingService : nsISupports
+{
+  /**
+   * Get list of sharing providers
+   */
+  [implicit_jscontext] jsval getSharingProviders(in AString urlToShare);
+
+  /**
+   * Launch service with shareTitle with given url
+   */
+  void shareUrl(in AString shareTitle, in AString urlToShare);
+};
--- a/widget/nsWidgetsCID.h
+++ b/widget/nsWidgetsCID.h
@@ -70,16 +70,21 @@
 { 0x1F39AE50, 0xB6A0, 0x4B37,                         \
   { 0x90, 0xF4, 0x60, 0xAF, 0x61, 0x41, 0x93, 0xD8 }}
 
 // {2451BAED-8DC3-46D9-9E30-96E1BAA03666}
 #define NS_MACDOCKSUPPORT_CID \
 { 0x2451BAED, 0x8DC3, 0x46D9, \
   { 0x9E, 0x30, 0x96, 0xE1, 0xBA, 0xA0, 0x36, 0x66 } }
 
+// {de59fe1a-46c8-490f-b04d-34545acb06c9}
+#define NS_MACSHARINGSERVICE_CID \
+{ 0xde59fe1a, 0x46c8, 0x490f, \
+  { 0xb0, 0x4d, 0x34, 0x54, 0x5a, 0xcb, 0x06, 0xc9 } }
+
 // {b6e1a890-b2b8-4883-a65f-9476f6185313}
 #define NS_MACSYSTEMSTATUSBAR_CID \
 { 0xb6e1a890, 0xb2b8, 0x4883, \
   { 0xa6, 0x5f, 0x94, 0x76, 0xf6, 0x18, 0x53, 0x13 } }
 
 //-----------------------------------------------------------
 //Drag & Drop & Clipboard
 //-----------------------------------------------------------