forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1383 lines
		
	
	
	
		
			52 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			1383 lines
		
	
	
	
		
			52 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
# -*- indent-tabs-mode: nil; js-indent-level: 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/.
 | 
						|
 | 
						|
var gPluginHandler = {
 | 
						|
  PREF_NOTIFY_MISSING_FLASH: "plugins.notifyMissingFlash",
 | 
						|
  PREF_HIDE_MISSING_PLUGINS_NOTIFICATION: "plugins.hideMissingPluginsNotification",
 | 
						|
  PREF_SESSION_PERSIST_MINUTES: "plugin.sessionPermissionNow.intervalInMinutes",
 | 
						|
  PREF_PERSISTENT_DAYS: "plugin.persistentPermissionAlways.intervalInDays",
 | 
						|
 | 
						|
  getPluginUI: function (plugin, anonid) {
 | 
						|
    return plugin.ownerDocument.
 | 
						|
           getAnonymousElementByAttribute(plugin, "anonid", anonid);
 | 
						|
  },
 | 
						|
 | 
						|
#ifdef MOZ_CRASHREPORTER
 | 
						|
  get CrashSubmit() {
 | 
						|
    delete this.CrashSubmit;
 | 
						|
    Cu.import("resource://gre/modules/CrashSubmit.jsm", this);
 | 
						|
    return this.CrashSubmit;
 | 
						|
  },
 | 
						|
#endif
 | 
						|
 | 
						|
  _getPluginInfo: function (pluginElement) {
 | 
						|
    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
 | 
						|
    pluginElement.QueryInterface(Ci.nsIObjectLoadingContent);
 | 
						|
 | 
						|
    let tagMimetype;
 | 
						|
    let pluginName = gNavigatorBundle.getString("pluginInfo.unknownPlugin");
 | 
						|
    let pluginTag = null;
 | 
						|
    let permissionString = null;
 | 
						|
    let fallbackType = null;
 | 
						|
    let blocklistState = null;
 | 
						|
 | 
						|
    tagMimetype = pluginElement.actualType;
 | 
						|
    if (tagMimetype == "") {
 | 
						|
      tagMimetype = pluginElement.type;
 | 
						|
    }
 | 
						|
 | 
						|
    if (gPluginHandler.isKnownPlugin(pluginElement)) {
 | 
						|
      pluginTag = pluginHost.getPluginTagForType(pluginElement.actualType);
 | 
						|
      pluginName = gPluginHandler.makeNicePluginName(pluginTag.name);
 | 
						|
 | 
						|
      permissionString = pluginHost.getPermissionStringForType(pluginElement.actualType);
 | 
						|
      fallbackType = pluginElement.defaultFallbackType;
 | 
						|
      blocklistState = pluginHost.getBlocklistStateForType(pluginElement.actualType);
 | 
						|
      // Make state-softblocked == state-notblocked for our purposes,
 | 
						|
      // they have the same UI. STATE_OUTDATED should not exist for plugin
 | 
						|
      // items, but let's alias it anyway, just in case.
 | 
						|
      if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED ||
 | 
						|
          blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) {
 | 
						|
        blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return { mimetype: tagMimetype,
 | 
						|
             pluginName: pluginName,
 | 
						|
             pluginTag: pluginTag,
 | 
						|
             permissionString: permissionString,
 | 
						|
             fallbackType: fallbackType,
 | 
						|
             blocklistState: blocklistState,
 | 
						|
           };
 | 
						|
  },
 | 
						|
 | 
						|
  // Map the plugin's name to a filtered version more suitable for user UI.
 | 
						|
  makeNicePluginName : function (aName) {
 | 
						|
    if (aName == "Shockwave Flash")
 | 
						|
      return "Adobe Flash";
 | 
						|
 | 
						|
    // Clean up the plugin name by stripping off parenthetical clauses,
 | 
						|
    // trailing version numbers or "plugin".
 | 
						|
    // EG, "Foo Bar (Linux) Plugin 1.23_02" --> "Foo Bar"
 | 
						|
    // Do this by first stripping the numbers, etc. off the end, and then
 | 
						|
    // removing "Plugin" (and then trimming to get rid of any whitespace).
 | 
						|
    // (Otherwise, something like "Java(TM) Plug-in 1.7.0_07" gets mangled)
 | 
						|
    let newName = aName.replace(/\(.*?\)/g, "").
 | 
						|
                        replace(/[\s\d\.\-\_\(\)]+$/, "").
 | 
						|
                        replace(/\bplug-?in\b/i, "").trim();
 | 
						|
    return newName;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Update the visibility of the plugin overlay.
 | 
						|
   */
 | 
						|
  setVisibility : function (plugin, overlay, shouldShow) {
 | 
						|
    overlay.classList.toggle("visible", shouldShow);
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Check whether the plugin should be visible on the page. A plugin should
 | 
						|
   * not be visible if the overlay is too big, or if any other page content
 | 
						|
   * overlays it.
 | 
						|
   *
 | 
						|
   * This function will handle showing or hiding the overlay.
 | 
						|
   * @returns true if the plugin is invisible.
 | 
						|
   */
 | 
						|
  shouldShowOverlay : function (plugin, overlay) {
 | 
						|
    // If the overlay size is 0, we haven't done layout yet. Presume that
 | 
						|
    // plugins are visible until we know otherwise.
 | 
						|
    if (overlay.scrollWidth == 0) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // Is the <object>'s size too small to hold what we want to show?
 | 
						|
    let pluginRect = plugin.getBoundingClientRect();
 | 
						|
    // XXX bug 446693. The text-shadow on the submitted-report text at
 | 
						|
    //     the bottom causes scrollHeight to be larger than it should be.
 | 
						|
    let overflows = (overlay.scrollWidth > Math.ceil(pluginRect.width)) ||
 | 
						|
                    (overlay.scrollHeight - 5 > Math.ceil(pluginRect.height));
 | 
						|
    if (overflows) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    // Is the plugin covered up by other content so that it is not clickable?
 | 
						|
    // Floating point can confuse .elementFromPoint, so inset just a bit
 | 
						|
    let left = pluginRect.left + 2;
 | 
						|
    let right = pluginRect.right - 2;
 | 
						|
    let top = pluginRect.top + 2;
 | 
						|
    let bottom = pluginRect.bottom - 2;
 | 
						|
    let centerX = left + (right - left) / 2;
 | 
						|
    let centerY = top + (bottom - top) / 2;
 | 
						|
    let points = [[left, top],
 | 
						|
                   [left, bottom],
 | 
						|
                   [right, top],
 | 
						|
                   [right, bottom],
 | 
						|
                   [centerX, centerY]];
 | 
						|
 | 
						|
    if (right <= 0 || top <= 0) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    let contentWindow = plugin.ownerDocument.defaultView;
 | 
						|
    let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                           .getInterface(Ci.nsIDOMWindowUtils);
 | 
						|
 | 
						|
    for (let [x, y] of points) {
 | 
						|
      let el = cwu.elementFromPoint(x, y, true, true);
 | 
						|
      if (el !== plugin) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
 | 
						|
  addLinkClickCallback: function (linkNode, callbackName /*callbackArgs...*/) {
 | 
						|
    // XXX just doing (callback)(arg) was giving a same-origin error. bug?
 | 
						|
    let self = this;
 | 
						|
    let callbackArgs = Array.prototype.slice.call(arguments).slice(2);
 | 
						|
    linkNode.addEventListener("click",
 | 
						|
                              function(evt) {
 | 
						|
                                if (!evt.isTrusted)
 | 
						|
                                  return;
 | 
						|
                                evt.preventDefault();
 | 
						|
                                if (callbackArgs.length == 0)
 | 
						|
                                  callbackArgs = [ evt ];
 | 
						|
                                (self[callbackName]).apply(self, callbackArgs);
 | 
						|
                              },
 | 
						|
                              true);
 | 
						|
 | 
						|
    linkNode.addEventListener("keydown",
 | 
						|
                              function(evt) {
 | 
						|
                                if (!evt.isTrusted)
 | 
						|
                                  return;
 | 
						|
                                if (evt.keyCode == evt.DOM_VK_RETURN) {
 | 
						|
                                  evt.preventDefault();
 | 
						|
                                  if (callbackArgs.length == 0)
 | 
						|
                                    callbackArgs = [ evt ];
 | 
						|
                                  evt.preventDefault();
 | 
						|
                                  (self[callbackName]).apply(self, callbackArgs);
 | 
						|
                                }
 | 
						|
                              },
 | 
						|
                              true);
 | 
						|
  },
 | 
						|
 | 
						|
  // Helper to get the binding handler type from a plugin object
 | 
						|
  _getBindingType : function(plugin) {
 | 
						|
    if (!(plugin instanceof Ci.nsIObjectLoadingContent))
 | 
						|
      return null;
 | 
						|
 | 
						|
    switch (plugin.pluginFallbackType) {
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED:
 | 
						|
        return "PluginNotFound";
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_DISABLED:
 | 
						|
        return "PluginDisabled";
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED:
 | 
						|
        return "PluginBlocklisted";
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_OUTDATED:
 | 
						|
        return "PluginOutdated";
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
 | 
						|
        return "PluginClickToPlay";
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
 | 
						|
        return "PluginVulnerableUpdatable";
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
 | 
						|
        return "PluginVulnerableNoUpdate";
 | 
						|
      case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW:
 | 
						|
        return "PluginPlayPreview";
 | 
						|
      default:
 | 
						|
        // Not all states map to a handler
 | 
						|
        return null;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  supportedPlugins: {
 | 
						|
    "mimetypes": {
 | 
						|
      "application/x-shockwave-flash": "flash",
 | 
						|
      "application/futuresplash": "flash",
 | 
						|
      "application/x-java-.*": "java",
 | 
						|
      "application/x-director": "shockwave",
 | 
						|
      "application/(sdp|x-(mpeg|rtsp|sdp))": "quicktime",
 | 
						|
      "audio/(3gpp(2)?|AMR|aiff|basic|mid(i)?|mp4|mpeg|vnd\.qcelp|wav|x-(aiff|m4(a|b|p)|midi|mpeg|wav))": "quicktime",
 | 
						|
      "image/(pict|png|tiff|x-(macpaint|pict|png|quicktime|sgi|targa|tiff))": "quicktime",
 | 
						|
      "video/(3gpp(2)?|flc|mp4|mpeg|quicktime|sd-video|x-mpeg)": "quicktime",
 | 
						|
      "application/x-unknown": "test",
 | 
						|
    },
 | 
						|
 | 
						|
    "plugins": {
 | 
						|
      "flash": {
 | 
						|
        "displayName": "Flash",
 | 
						|
        "installWINNT": true,
 | 
						|
        "installDarwin": true,
 | 
						|
        "installLinux": true,
 | 
						|
      },
 | 
						|
      "java": {
 | 
						|
        "displayName": "Java",
 | 
						|
        "installWINNT": true,
 | 
						|
        "installDarwin": true,
 | 
						|
        "installLinux": true,
 | 
						|
      },
 | 
						|
      "shockwave": {
 | 
						|
        "displayName": "Shockwave",
 | 
						|
        "installWINNT": true,
 | 
						|
        "installDarwin": true,
 | 
						|
      },
 | 
						|
      "quicktime": {
 | 
						|
        "displayName": "QuickTime",
 | 
						|
        "installWINNT": true,
 | 
						|
      },
 | 
						|
      "test": {
 | 
						|
        "displayName": "Test plugin",
 | 
						|
        "installWINNT": true,
 | 
						|
        "installLinux": true,
 | 
						|
        "installDarwin": true,
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  nameForSupportedPlugin: function (aMimeType) {
 | 
						|
    for (let type in this.supportedPlugins.mimetypes) {
 | 
						|
      let re = new RegExp(type);
 | 
						|
      if (re.test(aMimeType)) {
 | 
						|
        return this.supportedPlugins.mimetypes[type];
 | 
						|
      }
 | 
						|
    }
 | 
						|
    return null;
 | 
						|
  },
 | 
						|
 | 
						|
  canInstallThisMimeType: function (aMimeType) {
 | 
						|
    let os = Services.appinfo.OS;
 | 
						|
    let pluginName = this.nameForSupportedPlugin(aMimeType);
 | 
						|
    if (pluginName && "install" + os in this.supportedPlugins.plugins[pluginName]) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
  },
 | 
						|
 | 
						|
  handleEvent : function(event) {
 | 
						|
    let eventType = event.type;
 | 
						|
 | 
						|
    if (eventType == "PluginRemoved") {
 | 
						|
      let doc = event.target;
 | 
						|
      let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
 | 
						|
      if (browser)
 | 
						|
        this._setPluginNotificationIcon(browser);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (eventType == "PluginCrashed" &&
 | 
						|
        !(event.target instanceof Ci.nsIObjectLoadingContent)) {
 | 
						|
      // If the event target is not a plugin object (i.e., an <object> or
 | 
						|
      // <embed> element), this call is for a window-global plugin.
 | 
						|
      this.pluginInstanceCrashed(event.target, event);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let plugin = event.target;
 | 
						|
    let doc = plugin.ownerDocument;
 | 
						|
 | 
						|
    if (!(plugin instanceof Ci.nsIObjectLoadingContent))
 | 
						|
      return;
 | 
						|
 | 
						|
    if (eventType == "PluginBindingAttached") {
 | 
						|
      // The plugin binding fires this event when it is created.
 | 
						|
      // As an untrusted event, ensure that this object actually has a binding
 | 
						|
      // and make sure we don't handle it twice
 | 
						|
      let overlay = this.getPluginUI(plugin, "main");
 | 
						|
      if (!overlay || overlay._bindingHandled) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      overlay._bindingHandled = true;
 | 
						|
 | 
						|
      // Lookup the handler for this binding
 | 
						|
      eventType = this._getBindingType(plugin);
 | 
						|
      if (!eventType) {
 | 
						|
        // Not all bindings have handlers
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    let shouldShowNotification = false;
 | 
						|
    let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
 | 
						|
    if (!browser)
 | 
						|
      return;
 | 
						|
 | 
						|
    switch (eventType) {
 | 
						|
      case "PluginCrashed":
 | 
						|
        this.pluginInstanceCrashed(plugin, event);
 | 
						|
        break;
 | 
						|
 | 
						|
      case "PluginNotFound":
 | 
						|
        let installable = this.showInstallNotification(plugin, eventType);
 | 
						|
        // For non-object plugin tags, register a click handler to install the
 | 
						|
        // plugin. Object tags can, and often do, deal with that themselves,
 | 
						|
        // so don't stomp on the page developers toes.
 | 
						|
        if (installable && !(plugin instanceof HTMLObjectElement)) {
 | 
						|
          let installStatus = this.getPluginUI(plugin, "installStatus");
 | 
						|
          installStatus.setAttribute("installable", "true");
 | 
						|
          let iconStatus = this.getPluginUI(plugin, "icon");
 | 
						|
          iconStatus.setAttribute("installable", "true");
 | 
						|
 | 
						|
          let installLink = this.getPluginUI(plugin, "installPluginLink");
 | 
						|
          this.addLinkClickCallback(installLink, "installSinglePlugin", plugin);
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case "PluginBlocklisted":
 | 
						|
      case "PluginOutdated":
 | 
						|
        shouldShowNotification = true;
 | 
						|
        break;
 | 
						|
 | 
						|
      case "PluginVulnerableUpdatable":
 | 
						|
        let updateLink = this.getPluginUI(plugin, "checkForUpdatesLink");
 | 
						|
        this.addLinkClickCallback(updateLink, "openPluginUpdatePage");
 | 
						|
        /* FALLTHRU */
 | 
						|
 | 
						|
      case "PluginVulnerableNoUpdate":
 | 
						|
      case "PluginClickToPlay":
 | 
						|
        this._handleClickToPlayEvent(plugin);
 | 
						|
        let overlay = this.getPluginUI(plugin, "main");
 | 
						|
        let pluginName = this._getPluginInfo(plugin).pluginName;
 | 
						|
        let messageString = gNavigatorBundle.getFormattedString("PluginClickToActivate", [pluginName]);
 | 
						|
        let overlayText = this.getPluginUI(plugin, "clickToPlay");
 | 
						|
        overlayText.textContent = messageString;
 | 
						|
        if (eventType == "PluginVulnerableUpdatable" ||
 | 
						|
            eventType == "PluginVulnerableNoUpdate") {
 | 
						|
          let vulnerabilityString = gNavigatorBundle.getString(eventType);
 | 
						|
          let vulnerabilityText = this.getPluginUI(plugin, "vulnerabilityStatus");
 | 
						|
          vulnerabilityText.textContent = vulnerabilityString;
 | 
						|
        }
 | 
						|
        shouldShowNotification = true;
 | 
						|
        break;
 | 
						|
 | 
						|
      case "PluginPlayPreview":
 | 
						|
        this._handlePlayPreviewEvent(plugin);
 | 
						|
        break;
 | 
						|
 | 
						|
      case "PluginDisabled":
 | 
						|
        let manageLink = this.getPluginUI(plugin, "managePluginsLink");
 | 
						|
        this.addLinkClickCallback(manageLink, "managePlugins");
 | 
						|
        shouldShowNotification = true;
 | 
						|
        break;
 | 
						|
 | 
						|
      case "PluginInstantiated":
 | 
						|
        shouldShowNotification = true;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    // Show the in-content UI if it's not too big. The crashed plugin handler already did this.
 | 
						|
    if (eventType != "PluginCrashed") {
 | 
						|
      let overlay = this.getPluginUI(plugin, "main");
 | 
						|
      if (overlay != null) {
 | 
						|
        this.setVisibility(plugin, overlay,
 | 
						|
                           this.shouldShowOverlay(plugin, overlay));
 | 
						|
        let resizeListener = (event) => {
 | 
						|
          this.setVisibility(plugin, overlay,
 | 
						|
            this.shouldShowOverlay(plugin, overlay));
 | 
						|
          this._setPluginNotificationIcon(browser);
 | 
						|
        };
 | 
						|
        plugin.addEventListener("overflow", resizeListener);
 | 
						|
        plugin.addEventListener("underflow", resizeListener);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    let closeIcon = this.getPluginUI(plugin, "closeIcon");
 | 
						|
    if (closeIcon) {
 | 
						|
      closeIcon.addEventListener("click", function(aEvent) {
 | 
						|
        if (aEvent.button == 0 && aEvent.isTrusted)
 | 
						|
          gPluginHandler.hideClickToPlayOverlay(plugin);
 | 
						|
      }, true);
 | 
						|
    }
 | 
						|
 | 
						|
    if (shouldShowNotification) {
 | 
						|
      this._showClickToPlayNotification(browser, plugin, false);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  isKnownPlugin: function PH_isKnownPlugin(objLoadingContent) {
 | 
						|
    return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) ==
 | 
						|
            Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
 | 
						|
  },
 | 
						|
 | 
						|
  canActivatePlugin: function PH_canActivatePlugin(objLoadingContent) {
 | 
						|
    // if this isn't a known plugin, we can't activate it
 | 
						|
    // (this also guards pluginHost.getPermissionStringForType against
 | 
						|
    // unexpected input)
 | 
						|
    if (!gPluginHandler.isKnownPlugin(objLoadingContent))
 | 
						|
      return false;
 | 
						|
 | 
						|
    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
 | 
						|
    let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
 | 
						|
    let principal = objLoadingContent.ownerDocument.defaultView.top.document.nodePrincipal;
 | 
						|
    let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString);
 | 
						|
 | 
						|
    let isFallbackTypeValid =
 | 
						|
      objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
 | 
						|
      objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
 | 
						|
 | 
						|
    if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) {
 | 
						|
      // checking if play preview is subject to CTP rules
 | 
						|
      let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType);
 | 
						|
      isFallbackTypeValid = !playPreviewInfo.ignoreCTP;
 | 
						|
    }
 | 
						|
 | 
						|
    return !objLoadingContent.activated &&
 | 
						|
           pluginPermission != Ci.nsIPermissionManager.DENY_ACTION &&
 | 
						|
           isFallbackTypeValid;
 | 
						|
  },
 | 
						|
 | 
						|
  hideClickToPlayOverlay: function(aPlugin) {
 | 
						|
    let overlay = this.getPluginUI(aPlugin, "main");
 | 
						|
    if (overlay) {
 | 
						|
      overlay.classList.remove("visible");
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  stopPlayPreview: function PH_stopPlayPreview(aPlugin, aPlayPlugin) {
 | 
						|
    let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
 | 
						|
    if (objLoadingContent.activated)
 | 
						|
      return;
 | 
						|
 | 
						|
    if (aPlayPlugin)
 | 
						|
      objLoadingContent.playPlugin();
 | 
						|
    else
 | 
						|
      objLoadingContent.cancelPlayPreview();
 | 
						|
  },
 | 
						|
 | 
						|
  newPluginInstalled : function(event) {
 | 
						|
    // browser elements are anonymous so we can't just use target.
 | 
						|
    var browser = event.originalTarget;
 | 
						|
    // clear the plugin list, now that at least one plugin has been installed
 | 
						|
    browser.missingPlugins = null;
 | 
						|
 | 
						|
    var notificationBox = gBrowser.getNotificationBox(browser);
 | 
						|
    var notification = notificationBox.getNotificationWithValue("missing-plugins");
 | 
						|
    if (notification)
 | 
						|
      notificationBox.removeNotification(notification);
 | 
						|
 | 
						|
    // reload the browser to make the new plugin show.
 | 
						|
    browser.reload();
 | 
						|
  },
 | 
						|
 | 
						|
  // Callback for user clicking on a missing (unsupported) plugin.
 | 
						|
  installSinglePlugin: function (plugin) {
 | 
						|
    var missingPlugins = new Map();
 | 
						|
 | 
						|
    var pluginInfo = this._getPluginInfo(plugin);
 | 
						|
    missingPlugins.set(pluginInfo.mimetype, pluginInfo);
 | 
						|
 | 
						|
    openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
 | 
						|
               "PFSWindow", "chrome,centerscreen,resizable=yes",
 | 
						|
               {plugins: missingPlugins, browser: gBrowser.selectedBrowser});
 | 
						|
  },
 | 
						|
 | 
						|
  // Callback for user clicking on a disabled plugin
 | 
						|
  managePlugins: function (aEvent) {
 | 
						|
    BrowserOpenAddonsMgr("addons://list/plugin");
 | 
						|
  },
 | 
						|
 | 
						|
  // Callback for user clicking on the link in a click-to-play plugin
 | 
						|
  // (where the plugin has an update)
 | 
						|
  openPluginUpdatePage: function (aEvent) {
 | 
						|
    openUILinkIn(Services.urlFormatter.formatURLPref("plugins.update.url"), "tab");
 | 
						|
  },
 | 
						|
 | 
						|
#ifdef MOZ_CRASHREPORTER
 | 
						|
  submitReport: function submitReport(pluginDumpID, browserDumpID, plugin) {
 | 
						|
    let keyVals = {};
 | 
						|
    if (plugin) {
 | 
						|
      let userComment = this.getPluginUI(plugin, "submitComment").value.trim();
 | 
						|
      if (userComment)
 | 
						|
        keyVals.PluginUserComment = userComment;
 | 
						|
      if (this.getPluginUI(plugin, "submitURLOptIn").checked)
 | 
						|
        keyVals.PluginContentURL = plugin.ownerDocument.URL;
 | 
						|
    }
 | 
						|
 | 
						|
    let pluginProcessType = Services.crashmanager.PROCESS_TYPE_PLUGIN;
 | 
						|
    this.CrashSubmit.submit(pluginDumpID, { processType: pluginProcessType,
 | 
						|
                                            extraExtraKeyVals: keyVals });
 | 
						|
    if (browserDumpID)
 | 
						|
      this.CrashSubmit.submit(browserDumpID);
 | 
						|
  },
 | 
						|
#endif
 | 
						|
 | 
						|
  // Callback for user clicking a "reload page" link
 | 
						|
  reloadPage: function (browser) {
 | 
						|
    browser.reload();
 | 
						|
  },
 | 
						|
 | 
						|
  // Callback for user clicking the help icon
 | 
						|
  openHelpPage: function () {
 | 
						|
    openHelpLink("plugin-crashed", false);
 | 
						|
  },
 | 
						|
 | 
						|
  showInstallNotification: function (aPlugin) {
 | 
						|
    let hideMissingPluginsNotification =
 | 
						|
      Services.prefs.getBoolPref(this.PREF_HIDE_MISSING_PLUGINS_NOTIFICATION);
 | 
						|
    if (hideMissingPluginsNotification) {
 | 
						|
      return false;
 | 
						|
    }
 | 
						|
 | 
						|
    let browser = gBrowser.getBrowserForDocument(aPlugin.ownerDocument
 | 
						|
                                                        .defaultView.top.document);
 | 
						|
    if (!browser.missingPlugins)
 | 
						|
      browser.missingPlugins = new Map();
 | 
						|
 | 
						|
    let pluginInfo = this._getPluginInfo(aPlugin);
 | 
						|
    browser.missingPlugins.set(pluginInfo.mimetype, pluginInfo);
 | 
						|
 | 
						|
    // only show notification for small subset of plugins
 | 
						|
    let mimetype = pluginInfo.mimetype.split(";")[0];
 | 
						|
    if (!this.canInstallThisMimeType(mimetype))
 | 
						|
      return false;
 | 
						|
 | 
						|
    let pluginIdentifier = this.nameForSupportedPlugin(mimetype);
 | 
						|
    if (!pluginIdentifier)
 | 
						|
      return false;
 | 
						|
 | 
						|
    let displayName = this.supportedPlugins.plugins[pluginIdentifier].displayName;
 | 
						|
 | 
						|
    // don't show several notifications
 | 
						|
    let notification = PopupNotifications.getNotification("plugins-not-found", browser);
 | 
						|
    if (notification)
 | 
						|
      return true;
 | 
						|
 | 
						|
    let messageString = gNavigatorBundle.getString("installPlugin.message");
 | 
						|
    let mainAction = {
 | 
						|
      label: gNavigatorBundle.getFormattedString("installPlugin.button.label",
 | 
						|
                                                 [displayName]),
 | 
						|
      accessKey: gNavigatorBundle.getString("installPlugin.button.accesskey"),
 | 
						|
      callback: function () {
 | 
						|
        openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul",
 | 
						|
                   "PFSWindow", "chrome,centerscreen,resizable=yes",
 | 
						|
                   {plugins: browser.missingPlugins, browser: browser});
 | 
						|
      }
 | 
						|
    };
 | 
						|
    let secondaryActions = null;
 | 
						|
    let options = { dismissed: true };
 | 
						|
 | 
						|
    let showForFlash = Services.prefs.getBoolPref(this.PREF_NOTIFY_MISSING_FLASH);
 | 
						|
    if (pluginIdentifier == "flash" && showForFlash) {
 | 
						|
      let prefNotifyMissingFlash = this.PREF_NOTIFY_MISSING_FLASH;
 | 
						|
      secondaryActions = [{
 | 
						|
        label: gNavigatorBundle.getString("installPlugin.ignoreButton.label"),
 | 
						|
        accessKey: gNavigatorBundle.getString("installPlugin.ignoreButton.accesskey"),
 | 
						|
        callback: function () {
 | 
						|
          Services.prefs.setBoolPref(prefNotifyMissingFlash, false);
 | 
						|
        }
 | 
						|
      }];
 | 
						|
      options.dismissed = false;
 | 
						|
    }
 | 
						|
    PopupNotifications.show(browser, "plugins-not-found",
 | 
						|
                            messageString, "plugin-install-notification-icon",
 | 
						|
                            mainAction, secondaryActions, options);
 | 
						|
    return true;
 | 
						|
  },
 | 
						|
  // Event listener for click-to-play plugins.
 | 
						|
  _handleClickToPlayEvent: function PH_handleClickToPlayEvent(aPlugin) {
 | 
						|
    let doc = aPlugin.ownerDocument;
 | 
						|
    let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
 | 
						|
    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
 | 
						|
    let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
 | 
						|
    // guard against giving pluginHost.getPermissionStringForType a type
 | 
						|
    // not associated with any known plugin
 | 
						|
    if (!gPluginHandler.isKnownPlugin(objLoadingContent))
 | 
						|
      return;
 | 
						|
    let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType);
 | 
						|
    let principal = doc.defaultView.top.document.nodePrincipal;
 | 
						|
    let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString);
 | 
						|
 | 
						|
    let overlay = this.getPluginUI(aPlugin, "main");
 | 
						|
 | 
						|
    if (pluginPermission == Ci.nsIPermissionManager.DENY_ACTION) {
 | 
						|
      if (overlay) {
 | 
						|
        overlay.classList.remove("visible");
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (overlay) {
 | 
						|
      overlay.addEventListener("click", gPluginHandler._overlayClickListener, true);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  _overlayClickListener: {
 | 
						|
    handleEvent: function PH_handleOverlayClick(aEvent) {
 | 
						|
      let plugin = document.getBindingParent(aEvent.target);
 | 
						|
      let contentWindow = plugin.ownerDocument.defaultView.top;
 | 
						|
      // gBrowser.getBrowserForDocument does not exist in the case where we
 | 
						|
      // drag-and-dropped a tab from a window containing only that tab. In
 | 
						|
      // that case, the window gets destroyed.
 | 
						|
      let browser = gBrowser.getBrowserForDocument ?
 | 
						|
                      gBrowser.getBrowserForDocument(contentWindow.document) :
 | 
						|
                      null;
 | 
						|
      // If browser is null here, we've been drag-and-dropped from another
 | 
						|
      // window, and this is the wrong click handler.
 | 
						|
      if (!browser) {
 | 
						|
        aEvent.target.removeEventListener("click", gPluginHandler._overlayClickListener, true);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
 | 
						|
      // Have to check that the target is not the link to update the plugin
 | 
						|
      if (!(aEvent.originalTarget instanceof HTMLAnchorElement) &&
 | 
						|
          (aEvent.originalTarget.getAttribute('anonid') != 'closeIcon') &&
 | 
						|
          aEvent.button == 0 && aEvent.isTrusted) {
 | 
						|
        gPluginHandler._showClickToPlayNotification(browser, plugin, true);
 | 
						|
        aEvent.stopPropagation();
 | 
						|
        aEvent.preventDefault();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  _handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
 | 
						|
    let doc = aPlugin.ownerDocument;
 | 
						|
    let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
 | 
						|
    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
 | 
						|
    let pluginInfo = this._getPluginInfo(aPlugin);
 | 
						|
    let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype);
 | 
						|
 | 
						|
    let previewContent = this.getPluginUI(aPlugin, "previewPluginContent");
 | 
						|
    let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
 | 
						|
    if (!iframe) {
 | 
						|
      // lazy initialization of the iframe
 | 
						|
      iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
 | 
						|
      iframe.className = "previewPluginContentFrame";
 | 
						|
      previewContent.appendChild(iframe);
 | 
						|
 | 
						|
      // Force a style flush, so that we ensure our binding is attached.
 | 
						|
      aPlugin.clientTop;
 | 
						|
    }
 | 
						|
    iframe.src = playPreviewInfo.redirectURL;
 | 
						|
 | 
						|
    // MozPlayPlugin event can be dispatched from the extension chrome
 | 
						|
    // code to replace the preview content with the native plugin
 | 
						|
    previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(aEvent) {
 | 
						|
      if (!aEvent.isTrusted)
 | 
						|
        return;
 | 
						|
 | 
						|
      previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
 | 
						|
 | 
						|
      let playPlugin = !aEvent.detail;
 | 
						|
      gPluginHandler.stopPlayPreview(aPlugin, playPlugin);
 | 
						|
 | 
						|
      // cleaning up: removes overlay iframe from the DOM
 | 
						|
      let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
 | 
						|
      if (iframe)
 | 
						|
        previewContent.removeChild(iframe);
 | 
						|
    }, true);
 | 
						|
 | 
						|
    if (!playPreviewInfo.ignoreCTP) {
 | 
						|
      gPluginHandler._showClickToPlayNotification(browser, aPlugin, false);
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {
 | 
						|
    let browser = gBrowser.selectedBrowser;
 | 
						|
    let contentWindow = browser.contentWindow;
 | 
						|
    let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                           .getInterface(Ci.nsIDOMWindowUtils);
 | 
						|
    let plugins = cwu.plugins;
 | 
						|
    for (let plugin of plugins) {
 | 
						|
      let overlay = this.getPluginUI(plugin, "main");
 | 
						|
      if (overlay)
 | 
						|
        overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
 | 
						|
      let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
 | 
						|
      if (gPluginHandler.canActivatePlugin(objLoadingContent))
 | 
						|
        gPluginHandler._handleClickToPlayEvent(plugin);
 | 
						|
    }
 | 
						|
    gPluginHandler._showClickToPlayNotification(browser, null, false);
 | 
						|
  },
 | 
						|
 | 
						|
  _clickToPlayNotificationEventCallback: function PH_ctpEventCallback(event) {
 | 
						|
    if (event == "showing") {
 | 
						|
      Services.telemetry.getHistogramById("PLUGINS_NOTIFICATION_SHOWN")
 | 
						|
        .add(!this.options.primaryPlugin);
 | 
						|
      // Histograms always start at 0, even though our data starts at 1
 | 
						|
      let histogramCount = this.options.pluginData.size - 1;
 | 
						|
      if (histogramCount > 4) {
 | 
						|
        histogramCount = 4;
 | 
						|
      }
 | 
						|
      Services.telemetry.getHistogramById("PLUGINS_NOTIFICATION_PLUGIN_COUNT")
 | 
						|
        .add(histogramCount);
 | 
						|
    }
 | 
						|
    else if (event == "dismissed") {
 | 
						|
      // Once the popup is dismissed, clicking the icon should show the full
 | 
						|
      // list again
 | 
						|
      this.options.primaryPlugin = null;
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  // Match the behaviour of nsPermissionManager
 | 
						|
  _getHostFromPrincipal: function PH_getHostFromPrincipal(principal) {
 | 
						|
    if (!principal.URI || principal.URI.schemeIs("moz-nullprincipal")) {
 | 
						|
      return "(null)";
 | 
						|
    }
 | 
						|
 | 
						|
    try {
 | 
						|
      if (principal.URI.host)
 | 
						|
        return principal.URI.host;
 | 
						|
    } catch (e) {}
 | 
						|
 | 
						|
    return principal.origin;
 | 
						|
  },
 | 
						|
 | 
						|
  /**
 | 
						|
   * Called from the plugin doorhanger to set the new permissions for a plugin
 | 
						|
   * and activate plugins if necessary.
 | 
						|
   * aNewState should be either "allownow" "allowalways" or "block"
 | 
						|
   */
 | 
						|
  _updatePluginPermission: function PH_setPermissionForPlugins(aNotification, aPluginInfo, aNewState) {
 | 
						|
    let permission;
 | 
						|
    let expireType;
 | 
						|
    let expireTime;
 | 
						|
    let histogram =
 | 
						|
      Services.telemetry.getHistogramById("PLUGINS_NOTIFICATION_USER_ACTION");
 | 
						|
 | 
						|
    // Update the permission manager.
 | 
						|
    // Also update the current state of pluginInfo.fallbackType so that
 | 
						|
    // subsequent opening of the notification shows the current state.
 | 
						|
    switch (aNewState) {
 | 
						|
      case "allownow":
 | 
						|
        permission = Ci.nsIPermissionManager.ALLOW_ACTION;
 | 
						|
        expireType = Ci.nsIPermissionManager.EXPIRE_SESSION;
 | 
						|
        expireTime = Date.now() + Services.prefs.getIntPref(this.PREF_SESSION_PERSIST_MINUTES) * 60 * 1000;
 | 
						|
        histogram.add(0);
 | 
						|
        aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
 | 
						|
        break;
 | 
						|
 | 
						|
      case "allowalways":
 | 
						|
        permission = Ci.nsIPermissionManager.ALLOW_ACTION;
 | 
						|
        expireType = Ci.nsIPermissionManager.EXPIRE_TIME;
 | 
						|
        expireTime = Date.now() +
 | 
						|
          Services.prefs.getIntPref(this.PREF_PERSISTENT_DAYS) * 24 * 60 * 60 * 1000;
 | 
						|
        histogram.add(1);
 | 
						|
        aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
 | 
						|
        break;
 | 
						|
 | 
						|
      case "block":
 | 
						|
        permission = Ci.nsIPermissionManager.PROMPT_ACTION;
 | 
						|
        expireType = Ci.nsIPermissionManager.EXPIRE_NEVER;
 | 
						|
        expireTime = 0;
 | 
						|
        histogram.add(2);
 | 
						|
        switch (aPluginInfo.blocklistState) {
 | 
						|
          case Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE:
 | 
						|
            aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE;
 | 
						|
            break;
 | 
						|
          case Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE:
 | 
						|
            aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE;
 | 
						|
            break;
 | 
						|
          default:
 | 
						|
            aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      // In case a plugin has already been allowed in another tab, the "continue allowing" button
 | 
						|
      // shouldn't change any permissions but should run the plugin-enablement code below.
 | 
						|
      case "continue":
 | 
						|
        aPluginInfo.fallbackType = Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE;
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        Cu.reportError(Error("Unexpected plugin state: " + aNewState));
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    let browser = aNotification.browser;
 | 
						|
    let contentWindow = browser.contentWindow;
 | 
						|
    if (aNewState != "continue") {
 | 
						|
      let principal = contentWindow.document.nodePrincipal;
 | 
						|
      Services.perms.addFromPrincipal(principal, aPluginInfo.permissionString,
 | 
						|
                                      permission, expireType, expireTime);
 | 
						|
      aPluginInfo.pluginPermissionType = expireType;
 | 
						|
    }
 | 
						|
 | 
						|
    // Manually activate the plugins that would have been automatically
 | 
						|
    // activated.
 | 
						|
    let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                           .getInterface(Ci.nsIDOMWindowUtils);
 | 
						|
    let plugins = cwu.plugins;
 | 
						|
    let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
 | 
						|
 | 
						|
    let pluginFound = false;
 | 
						|
    for (let plugin of plugins) {
 | 
						|
      plugin.QueryInterface(Ci.nsIObjectLoadingContent);
 | 
						|
      if (!gPluginHandler.isKnownPlugin(plugin)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) {
 | 
						|
        pluginFound = true;
 | 
						|
        if (aNewState == "block") {
 | 
						|
          plugin.reload(true);
 | 
						|
        } else {
 | 
						|
          if (gPluginHandler.canActivatePlugin(plugin)) {
 | 
						|
            let overlay = this.getPluginUI(plugin, "main");
 | 
						|
            if (overlay) {
 | 
						|
              overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true);
 | 
						|
            }
 | 
						|
            plugin.playPlugin();
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // If there are no instances of the plugin on the page any more, what the
 | 
						|
    // user probably needs is for us to allow and then refresh.
 | 
						|
    if (aNewState != "block" && !pluginFound) {
 | 
						|
      browser.reload();
 | 
						|
    }
 | 
						|
 | 
						|
    this._setPluginNotificationIcon(browser);
 | 
						|
  },
 | 
						|
 | 
						|
  _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aPlugin, aShowNow) {
 | 
						|
    let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
 | 
						|
    let plugins = [];
 | 
						|
 | 
						|
    // if aPlugin is null, that means the user has navigated back to a page with plugins, and we need
 | 
						|
    // to collect all the plugins
 | 
						|
    if (aPlugin === null) {
 | 
						|
      let contentWindow = aBrowser.contentWindow;
 | 
						|
      let contentDoc = aBrowser.contentDocument;
 | 
						|
      let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                             .getInterface(Ci.nsIDOMWindowUtils);
 | 
						|
      // cwu.plugins may contain non-plugin <object>s, filter them out
 | 
						|
      plugins = cwu.plugins.filter((plugin) =>
 | 
						|
        plugin.getContentTypeForMIMEType(plugin.actualType) == Ci.nsIObjectLoadingContent.TYPE_PLUGIN);
 | 
						|
 | 
						|
      if (plugins.length == 0) {
 | 
						|
        if (notification) {
 | 
						|
          PopupNotifications.remove(notification);
 | 
						|
        }
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      plugins = [aPlugin];
 | 
						|
    }
 | 
						|
 | 
						|
    // If this is a new notification, create a pluginData map, otherwise append
 | 
						|
    let pluginData;
 | 
						|
    if (notification) {
 | 
						|
      pluginData = notification.options.pluginData;
 | 
						|
    } else {
 | 
						|
      pluginData = new Map();
 | 
						|
    }
 | 
						|
 | 
						|
    let principal = aBrowser.contentDocument.nodePrincipal;
 | 
						|
    let principalHost = this._getHostFromPrincipal(principal);
 | 
						|
 | 
						|
    for (var plugin of plugins) {
 | 
						|
      let pluginInfo = this._getPluginInfo(plugin);
 | 
						|
      if (pluginInfo.permissionString === null) {
 | 
						|
        Cu.reportError("No permission string for active plugin.");
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (pluginData.has(pluginInfo.permissionString)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      let permissionObj = Services.perms.
 | 
						|
        getPermissionObject(principal, pluginInfo.permissionString, false);
 | 
						|
      if (permissionObj) {
 | 
						|
        pluginInfo.pluginPermissionHost = permissionObj.host;
 | 
						|
        pluginInfo.pluginPermissionType = permissionObj.expireType;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        pluginInfo.pluginPermissionHost = principalHost;
 | 
						|
        pluginInfo.pluginPermissionType = undefined;
 | 
						|
      }
 | 
						|
 | 
						|
      let url;
 | 
						|
      // TODO: allow the blocklist to specify a better link, bug 873093
 | 
						|
      if (pluginInfo.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) {
 | 
						|
        url = Services.urlFormatter.formatURLPref("plugins.update.url");
 | 
						|
      }
 | 
						|
      else if (pluginInfo.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
 | 
						|
        url = Services.blocklist.getPluginBlocklistURL(pluginInfo.pluginTag);
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "clicktoplay";
 | 
						|
      }
 | 
						|
      pluginInfo.detailsLink = url;
 | 
						|
 | 
						|
      pluginData.set(pluginInfo.permissionString, pluginInfo);
 | 
						|
    }
 | 
						|
 | 
						|
    let primaryPluginPermission = null;
 | 
						|
    if (aShowNow) {
 | 
						|
      primaryPluginPermission = this._getPluginInfo(aPlugin).permissionString;
 | 
						|
    }
 | 
						|
 | 
						|
    if (notification) {
 | 
						|
      // Don't modify the notification UI while it's on the screen, that would be
 | 
						|
      // jumpy and might allow clickjacking.
 | 
						|
      if (aShowNow) {
 | 
						|
        notification.options.primaryPlugin = primaryPluginPermission;
 | 
						|
        notification.reshow();
 | 
						|
        setTimeout(() => { this._setPluginNotificationIcon(aBrowser); }, 0);
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let options = {
 | 
						|
      dismissed: !aShowNow,
 | 
						|
      eventCallback: this._clickToPlayNotificationEventCallback,
 | 
						|
      primaryPlugin: primaryPluginPermission,
 | 
						|
      pluginData: pluginData
 | 
						|
    };
 | 
						|
    PopupNotifications.show(aBrowser, "click-to-play-plugins",
 | 
						|
                            "", "plugins-notification-icon",
 | 
						|
                            null, null, options);
 | 
						|
    setTimeout(() => { this._setPluginNotificationIcon(aBrowser); }, 0);
 | 
						|
  },
 | 
						|
 | 
						|
  _setPluginNotificationIcon : function PH_setPluginNotificationIcon(aBrowser) {
 | 
						|
    // Because this is called on a timeout, sanity-check before continuing
 | 
						|
    if (!aBrowser.docShell || !aBrowser.contentWindow) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser);
 | 
						|
    if (!notification)
 | 
						|
      return;
 | 
						|
 | 
						|
    // Make a copy of the actions, removing active plugins and checking for
 | 
						|
    // outdated plugins.
 | 
						|
    let haveInsecure = false;
 | 
						|
    let actions = new Map();
 | 
						|
    for (let action of notification.options.pluginData.values()) {
 | 
						|
      switch (action.fallbackType) {
 | 
						|
        // haveInsecure will trigger the red flashing icon and the infobar
 | 
						|
        // styling below
 | 
						|
        case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
 | 
						|
        case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
 | 
						|
          haveInsecure = true;
 | 
						|
          // fall through
 | 
						|
 | 
						|
        case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
 | 
						|
          actions.set(action.permissionString, action);
 | 
						|
          continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // check for hidden plugins
 | 
						|
    let contentWindow = aBrowser.contentWindow;
 | 
						|
    let contentDoc = aBrowser.contentDocument;
 | 
						|
    let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
 | 
						|
                           .getInterface(Ci.nsIDOMWindowUtils);
 | 
						|
    for (let plugin of cwu.plugins) {
 | 
						|
      let info = this._getPluginInfo(plugin);
 | 
						|
      if (!actions.has(info.permissionString)) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      let fallbackType = info.fallbackType;
 | 
						|
      if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) {
 | 
						|
        actions.delete(info.permissionString);
 | 
						|
        if (actions.size == 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      if (fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY &&
 | 
						|
          fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE &&
 | 
						|
          fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      let overlay = this.getPluginUI(plugin, "main");
 | 
						|
      if (!overlay) {
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      let shouldShow = this.shouldShowOverlay(plugin, overlay);
 | 
						|
      this.setVisibility(plugin, overlay, shouldShow);
 | 
						|
      if (shouldShow) {
 | 
						|
        actions.delete(info.permissionString);
 | 
						|
        if (actions.size == 0) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Set up the icon
 | 
						|
    document.getElementById("plugins-notification-icon").classList.
 | 
						|
      toggle("plugin-blocked", haveInsecure);
 | 
						|
 | 
						|
    // Now configure the notification bar
 | 
						|
 | 
						|
    let notificationBox = gBrowser.getNotificationBox(aBrowser);
 | 
						|
 | 
						|
    function hideNotification() {
 | 
						|
      let n = notificationBox.getNotificationWithValue("plugin-hidden");
 | 
						|
      if (n) {
 | 
						|
        notificationBox.removeNotification(n, true);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // There are three different cases when showing an infobar:
 | 
						|
    // 1.  A single type of plugin is hidden on the page. Show the UI for that
 | 
						|
    //     plugin.
 | 
						|
    // 2a. Multiple types of plugins are hidden on the page. Show the multi-UI
 | 
						|
    //     with the vulnerable styling.
 | 
						|
    // 2b. Multiple types of plugins are hidden on the page, but none are
 | 
						|
    //     vulnerable. Show the nonvulnerable multi-UI.
 | 
						|
    function showNotification() {
 | 
						|
      let n = notificationBox.getNotificationWithValue("plugin-hidden");
 | 
						|
      if (n) {
 | 
						|
        // If something is already shown, just keep it
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      Services.telemetry.getHistogramById("PLUGINS_INFOBAR_SHOWN").
 | 
						|
        add(true);
 | 
						|
 | 
						|
      let message;
 | 
						|
      // Icons set directly cannot be manipulated using moz-image-region, so
 | 
						|
      // we use CSS classes instead.
 | 
						|
      let host = gPluginHandler._getHostFromPrincipal(aBrowser.contentDocument.nodePrincipal);
 | 
						|
      let brand = document.getElementById("bundle_brand").getString("brandShortName");
 | 
						|
 | 
						|
      if (actions.size == 1) {
 | 
						|
        let pluginInfo = [...actions.values()][0];
 | 
						|
        let pluginName = pluginInfo.pluginName;
 | 
						|
 | 
						|
        switch (pluginInfo.fallbackType) {
 | 
						|
          case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY:
 | 
						|
            message = gNavigatorBundle.getFormattedString(
 | 
						|
              "pluginActivateNew.message",
 | 
						|
              [pluginName, host]);
 | 
						|
            break;
 | 
						|
          case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE:
 | 
						|
            message = gNavigatorBundle.getFormattedString(
 | 
						|
              "pluginActivateOutdated.message",
 | 
						|
              [pluginName, host, brand]);
 | 
						|
            break;
 | 
						|
          case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE:
 | 
						|
            message = gNavigatorBundle.getFormattedString(
 | 
						|
              "pluginActivateVulnerable.message",
 | 
						|
              [pluginName, host, brand]);
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        // Multi-plugin
 | 
						|
        message = gNavigatorBundle.getFormattedString(
 | 
						|
          "pluginActivateMultiple.message", [host]);
 | 
						|
 | 
						|
        for (let action of actions.values()) {
 | 
						|
          if (action.fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY) {
 | 
						|
            break;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      let buttons = [
 | 
						|
        {
 | 
						|
          label: gNavigatorBundle.getString("pluginContinueBlocking.label"),
 | 
						|
          accessKey: gNavigatorBundle.getString("pluginContinueBlocking.accesskey"),
 | 
						|
          callback: function() {
 | 
						|
            Services.telemetry.getHistogramById("PLUGINS_INFOBAR_BLOCK").
 | 
						|
              add(true);
 | 
						|
 | 
						|
            Services.perms.addFromPrincipal(aBrowser.contentDocument.nodePrincipal,
 | 
						|
                                            "plugin-hidden-notification",
 | 
						|
                                            Services.perms.DENY_ACTION);
 | 
						|
          }
 | 
						|
        },
 | 
						|
        {
 | 
						|
          label: gNavigatorBundle.getString("pluginActivateTrigger.label"),
 | 
						|
          accessKey: gNavigatorBundle.getString("pluginActivateTrigger.accesskey"),
 | 
						|
          callback: function() {
 | 
						|
            Services.telemetry.getHistogramById("PLUGINS_INFOBAR_ALLOW").
 | 
						|
              add(true);
 | 
						|
 | 
						|
            let curNotification =
 | 
						|
              PopupNotifications.getNotification("click-to-play-plugins",
 | 
						|
                                                 aBrowser);
 | 
						|
            if (curNotification) {
 | 
						|
              curNotification.reshow();
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      ];
 | 
						|
      n = notificationBox.
 | 
						|
        appendNotification(message, "plugin-hidden", null,
 | 
						|
                           notificationBox.PRIORITY_INFO_HIGH, buttons);
 | 
						|
      if (haveInsecure) {
 | 
						|
        n.classList.add('pluginVulnerable');
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (actions.size == 0) {
 | 
						|
      hideNotification();
 | 
						|
    } else {
 | 
						|
      let notificationPermission = Services.perms.testPermissionFromPrincipal(
 | 
						|
        aBrowser.contentDocument.nodePrincipal, "plugin-hidden-notification");
 | 
						|
      if (notificationPermission == Ci.nsIPermissionManager.DENY_ACTION) {
 | 
						|
        hideNotification();
 | 
						|
      } else {
 | 
						|
        showNotification();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  // Crashed-plugin observer. Notified once per plugin crash, before events
 | 
						|
  // are dispatched to individual plugin instances.
 | 
						|
  pluginCrashed : function(subject, topic, data) {
 | 
						|
    let propertyBag = subject;
 | 
						|
    if (!(propertyBag instanceof Ci.nsIPropertyBag2) ||
 | 
						|
        !(propertyBag instanceof Ci.nsIWritablePropertyBag2))
 | 
						|
     return;
 | 
						|
 | 
						|
#ifdef MOZ_CRASHREPORTER
 | 
						|
    let pluginDumpID = propertyBag.getPropertyAsAString("pluginDumpID");
 | 
						|
    let browserDumpID= propertyBag.getPropertyAsAString("browserDumpID");
 | 
						|
    let shouldSubmit = gCrashReporter.submitReports;
 | 
						|
    let doPrompt     = true; // XXX followup to get via gCrashReporter
 | 
						|
 | 
						|
    // Submit automatically when appropriate.
 | 
						|
    if (pluginDumpID && shouldSubmit && !doPrompt) {
 | 
						|
      this.submitReport(pluginDumpID, browserDumpID);
 | 
						|
      // Submission is async, so we can't easily show failure UI.
 | 
						|
      propertyBag.setPropertyAsBool("submittedCrashReport", true);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  },
 | 
						|
 | 
						|
  // Crashed-plugin event listener. Called for every instance of a
 | 
						|
  // plugin in content.
 | 
						|
  pluginInstanceCrashed: function (target, aEvent) {
 | 
						|
    // Ensure the plugin and event are of the right type.
 | 
						|
    if (!(aEvent instanceof Ci.nsIDOMCustomEvent))
 | 
						|
      return;
 | 
						|
 | 
						|
    let propBag = aEvent.detail.QueryInterface(Ci.nsIPropertyBag2);
 | 
						|
    let submittedReport = propBag.getPropertyAsBool("submittedCrashReport");
 | 
						|
    let doPrompt        = true; // XXX followup for .getPropertyAsBool("doPrompt");
 | 
						|
    let submitReports   = true; // XXX followup for .getPropertyAsBool("submitReports");
 | 
						|
    let pluginName      = propBag.getPropertyAsAString("pluginName");
 | 
						|
    let pluginDumpID    = propBag.getPropertyAsAString("pluginDumpID");
 | 
						|
    let browserDumpID   = null;
 | 
						|
    let gmpPlugin       = false;
 | 
						|
 | 
						|
    try {
 | 
						|
      browserDumpID = propBag.getPropertyAsAString("browserDumpID");
 | 
						|
    } catch (e) {
 | 
						|
      // For GMP crashes we don't get a browser dump.
 | 
						|
    }
 | 
						|
 | 
						|
    try {
 | 
						|
      gmpPlugin = propBag.getPropertyAsBool("gmpPlugin");
 | 
						|
    } catch (e) {
 | 
						|
      // This property is only set for GMP plugins.
 | 
						|
    }
 | 
						|
 | 
						|
    // For non-GMP plugins, remap the plugin name to a more user-presentable form.
 | 
						|
    if (!gmpPlugin) {
 | 
						|
      pluginName = this.makeNicePluginName(pluginName);
 | 
						|
    }
 | 
						|
 | 
						|
    let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);
 | 
						|
 | 
						|
    let plugin = null, doc;
 | 
						|
    if (target instanceof Ci.nsIObjectLoadingContent) {
 | 
						|
      plugin = target;
 | 
						|
      doc = plugin.ownerDocument;
 | 
						|
    } else {
 | 
						|
      doc = target.document;
 | 
						|
      if (!doc) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      // doPrompt is specific to the crashed plugin overlay, and
 | 
						|
      // therefore is not applicable for window-global plugins.
 | 
						|
      doPrompt = false;
 | 
						|
    }
 | 
						|
 | 
						|
    let status;
 | 
						|
#ifdef MOZ_CRASHREPORTER
 | 
						|
    // Determine which message to show regarding crash reports.
 | 
						|
    if (submittedReport) { // submitReports && !doPrompt, handled in observer
 | 
						|
      status = "submitted";
 | 
						|
    }
 | 
						|
    else if (!submitReports && !doPrompt) {
 | 
						|
      status = "noSubmit";
 | 
						|
    }
 | 
						|
    else if (!pluginDumpID) {
 | 
						|
      // If we don't have a minidumpID, we can't (or didn't) submit anything.
 | 
						|
      // This can happen if the plugin is killed from the task manager.
 | 
						|
      status = "noReport";
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      status = "please";
 | 
						|
    }
 | 
						|
 | 
						|
    // If we're showing the link to manually trigger report submission, we'll
 | 
						|
    // want to be able to update all the instances of the UI for this crash to
 | 
						|
    // show an updated message when a report is submitted.
 | 
						|
    if (doPrompt) {
 | 
						|
      let observer = {
 | 
						|
        QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
 | 
						|
                                               Ci.nsISupportsWeakReference]),
 | 
						|
        observe : function(subject, topic, data) {
 | 
						|
          let propertyBag = subject;
 | 
						|
          if (!(propertyBag instanceof Ci.nsIPropertyBag2))
 | 
						|
            return;
 | 
						|
          // Ignore notifications for other crashes.
 | 
						|
          if (propertyBag.get("minidumpID") != pluginDumpID)
 | 
						|
            return;
 | 
						|
          statusDiv.setAttribute("status", data);
 | 
						|
        },
 | 
						|
 | 
						|
        handleEvent : function(event) {
 | 
						|
            // Not expected to be called, just here for the closure.
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      // Use a weak reference, so we don't have to remove it...
 | 
						|
      Services.obs.addObserver(observer, "crash-report-status", true);
 | 
						|
      // ...alas, now we need something to hold a strong reference to prevent
 | 
						|
      // it from being GC. But I don't want to manually manage the reference's
 | 
						|
      // lifetime (which should be no greater than the page).
 | 
						|
      // Clever solution? Use a closue with an event listener on the document.
 | 
						|
      // When the doc goes away, so do the listener references and the closure.
 | 
						|
      doc.addEventListener("mozCleverClosureHack", observer, false);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document);
 | 
						|
    let notificationBox = gBrowser.getNotificationBox(browser);
 | 
						|
    let isShowing = false;
 | 
						|
 | 
						|
    if (plugin) {
 | 
						|
      // If there's no plugin (an <object> or <embed> element), this call is
 | 
						|
      // for a window-global plugin. In this case, there's no overlay to show.
 | 
						|
      isShowing = _setUpPluginOverlay.call(this, plugin, doPrompt, browser);
 | 
						|
    }
 | 
						|
 | 
						|
    if (isShowing) {
 | 
						|
      // If a previous plugin on the page was too small and resulted in adding a
 | 
						|
      // notification bar, then remove it because this plugin instance it big
 | 
						|
      // enough to serve as in-content notification.
 | 
						|
      hideNotificationBar();
 | 
						|
      doc.mozNoPluginCrashedNotification = true;
 | 
						|
    } else {
 | 
						|
      // If another plugin on the page was large enough to show our UI, we don't
 | 
						|
      // want to show a notification bar.
 | 
						|
      if (!doc.mozNoPluginCrashedNotification)
 | 
						|
        showNotificationBar(pluginDumpID, browserDumpID);
 | 
						|
    }
 | 
						|
 | 
						|
    function hideNotificationBar() {
 | 
						|
      let notification = notificationBox.getNotificationWithValue("plugin-crashed");
 | 
						|
      if (notification)
 | 
						|
        notificationBox.removeNotification(notification, true);
 | 
						|
    }
 | 
						|
 | 
						|
    function showNotificationBar(pluginDumpID, browserDumpID) {
 | 
						|
      // If there's already an existing notification bar, don't do anything.
 | 
						|
      let notification = notificationBox.getNotificationWithValue("plugin-crashed");
 | 
						|
      if (notification)
 | 
						|
        return;
 | 
						|
 | 
						|
      // Configure the notification bar
 | 
						|
      let priority = notificationBox.PRIORITY_WARNING_MEDIUM;
 | 
						|
      let iconURL = "chrome://mozapps/skin/plugins/notifyPluginCrashed.png";
 | 
						|
      let reloadLabel = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label");
 | 
						|
      let reloadKey   = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey");
 | 
						|
      let submitLabel = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.label");
 | 
						|
      let submitKey   = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.accesskey");
 | 
						|
 | 
						|
      let buttons = [{
 | 
						|
        label: reloadLabel,
 | 
						|
        accessKey: reloadKey,
 | 
						|
        popup: null,
 | 
						|
        callback: function() { browser.reload(); },
 | 
						|
      }];
 | 
						|
#ifdef MOZ_CRASHREPORTER
 | 
						|
      let submitButton = {
 | 
						|
        label: submitLabel,
 | 
						|
        accessKey: submitKey,
 | 
						|
        popup: null,
 | 
						|
          callback: function() { gPluginHandler.submitReport(pluginDumpID, browserDumpID); },
 | 
						|
      };
 | 
						|
      if (pluginDumpID)
 | 
						|
        buttons.push(submitButton);
 | 
						|
#endif
 | 
						|
 | 
						|
      let notification = notificationBox.appendNotification(messageString, "plugin-crashed",
 | 
						|
                                                            iconURL, priority, buttons);
 | 
						|
 | 
						|
      // Add the "learn more" link.
 | 
						|
      let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 | 
						|
      let link = notification.ownerDocument.createElementNS(XULNS, "label");
 | 
						|
      link.className = "text-link";
 | 
						|
      link.setAttribute("value", gNavigatorBundle.getString("crashedpluginsMessage.learnMore"));
 | 
						|
      let crashurl = formatURL("app.support.baseURL", true);
 | 
						|
      crashurl += "plugin-crashed-notificationbar";
 | 
						|
      link.href = crashurl;
 | 
						|
 | 
						|
      let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText");
 | 
						|
      description.appendChild(link);
 | 
						|
 | 
						|
      // Remove the notfication when the page is reloaded.
 | 
						|
      doc.defaultView.top.addEventListener("unload", function() {
 | 
						|
        notificationBox.removeNotification(notification);
 | 
						|
      }, false);
 | 
						|
    }
 | 
						|
 | 
						|
    // Configure the crashed-plugin placeholder.
 | 
						|
    // Returns true if the plugin overlay is visible.
 | 
						|
    function _setUpPluginOverlay(plugin, doPromptSubmit, browser) {
 | 
						|
      if (!plugin) {
 | 
						|
        return false;
 | 
						|
      }
 | 
						|
 | 
						|
      // Force a layout flush so the binding is attached.
 | 
						|
      plugin.clientTop;
 | 
						|
      let overlay = this.getPluginUI(plugin, "main");
 | 
						|
      let statusDiv = this.getPluginUI(plugin, "submitStatus");
 | 
						|
 | 
						|
      if (doPromptSubmit) {
 | 
						|
        this.getPluginUI(plugin, "submitButton").addEventListener("click",
 | 
						|
        function (event) {
 | 
						|
          if (event.button != 0 || !event.isTrusted)
 | 
						|
            return;
 | 
						|
          this.submitReport(pluginDumpID, browserDumpID, plugin);
 | 
						|
          pref.setBoolPref("", optInCB.checked);
 | 
						|
        }.bind(this));
 | 
						|
        let optInCB = this.getPluginUI(plugin, "submitURLOptIn");
 | 
						|
        let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL");
 | 
						|
        optInCB.checked = pref.getBoolPref("");
 | 
						|
      }
 | 
						|
 | 
						|
      statusDiv.setAttribute("status", status);
 | 
						|
 | 
						|
      let helpIcon = this.getPluginUI(plugin, "helpIcon");
 | 
						|
      this.addLinkClickCallback(helpIcon, "openHelpPage");
 | 
						|
 | 
						|
      let crashText = this.getPluginUI(plugin, "crashedText");
 | 
						|
      crashText.textContent = messageString;
 | 
						|
 | 
						|
      let link = this.getPluginUI(plugin, "reloadLink");
 | 
						|
      this.addLinkClickCallback(link, "reloadPage", browser);
 | 
						|
 | 
						|
      let isShowing = this.shouldShowOverlay(plugin, overlay);
 | 
						|
 | 
						|
      // Is the <object>'s size too small to hold what we want to show?
 | 
						|
      if (!isShowing) {
 | 
						|
        // First try hiding the crash report submission UI.
 | 
						|
        statusDiv.removeAttribute("status");
 | 
						|
 | 
						|
        isShowing = this.shouldShowOverlay(plugin, overlay);
 | 
						|
      }
 | 
						|
      this.setVisibility(plugin, overlay, isShowing);
 | 
						|
 | 
						|
      return isShowing;
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 |