mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			290 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			290 lines
		
	
	
	
		
			8.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Copyright 2012 Mozilla Foundation
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
 | 
						|
 | 
						|
const lazy = {};
 | 
						|
 | 
						|
ChromeUtils.defineESModuleGetters(lazy, {
 | 
						|
  NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
 | 
						|
  PdfJsTelemetry: "resource://pdf.js/PdfJsTelemetry.sys.mjs",
 | 
						|
  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
 | 
						|
  SetClipboardSearchString: "resource://gre/modules/Finder.sys.mjs",
 | 
						|
});
 | 
						|
 | 
						|
var Svc = {};
 | 
						|
XPCOMUtils.defineLazyServiceGetter(
 | 
						|
  Svc,
 | 
						|
  "mime",
 | 
						|
  "@mozilla.org/mime;1",
 | 
						|
  "nsIMIMEService"
 | 
						|
);
 | 
						|
 | 
						|
XPCOMUtils.defineLazyPreferenceGetter(
 | 
						|
  lazy,
 | 
						|
  "matchesCountLimit",
 | 
						|
  "accessibility.typeaheadfind.matchesCountLimit"
 | 
						|
);
 | 
						|
 | 
						|
let gFindTypes = [
 | 
						|
  "find",
 | 
						|
  "findagain",
 | 
						|
  "findhighlightallchange",
 | 
						|
  "findcasesensitivitychange",
 | 
						|
  "findbarclose",
 | 
						|
  "finddiacriticmatchingchange",
 | 
						|
];
 | 
						|
 | 
						|
export class PdfjsParent extends JSWindowActorParent {
 | 
						|
  constructor() {
 | 
						|
    super();
 | 
						|
    this._boundToFindbar = null;
 | 
						|
    this._findFailedString = null;
 | 
						|
  }
 | 
						|
 | 
						|
  didDestroy() {
 | 
						|
    this._removeEventListener();
 | 
						|
  }
 | 
						|
 | 
						|
  receiveMessage(aMsg) {
 | 
						|
    switch (aMsg.name) {
 | 
						|
      case "PDFJS:Parent:updateControlState":
 | 
						|
        return this._updateControlState(aMsg);
 | 
						|
      case "PDFJS:Parent:updateMatchesCount":
 | 
						|
        return this._updateMatchesCount(aMsg);
 | 
						|
      case "PDFJS:Parent:addEventListener":
 | 
						|
        return this._addEventListener();
 | 
						|
      case "PDFJS:Parent:saveURL":
 | 
						|
        return this._saveURL(aMsg);
 | 
						|
      case "PDFJS:Parent:recordExposure":
 | 
						|
        return this._recordExposure();
 | 
						|
      case "PDFJS:Parent:reportTelemetry":
 | 
						|
        return this._reportTelemetry(aMsg);
 | 
						|
    }
 | 
						|
    return undefined;
 | 
						|
  }
 | 
						|
 | 
						|
  /*
 | 
						|
   * Internal
 | 
						|
   */
 | 
						|
 | 
						|
  get browser() {
 | 
						|
    return this.browsingContext.top.embedderElement;
 | 
						|
  }
 | 
						|
 | 
						|
  _recordExposure() {
 | 
						|
    lazy.NimbusFeatures.pdfjs.recordExposureEvent({ once: true });
 | 
						|
  }
 | 
						|
 | 
						|
  _reportTelemetry(aMsg) {
 | 
						|
    lazy.PdfJsTelemetry.report(aMsg.data);
 | 
						|
  }
 | 
						|
 | 
						|
  _saveURL(aMsg) {
 | 
						|
    const data = aMsg.data;
 | 
						|
    this.browser.ownerGlobal.saveURL(
 | 
						|
      data.blobUrl /* aURL */,
 | 
						|
      data.originalUrl /* aOriginalURL */,
 | 
						|
      data.filename /* aFileName */,
 | 
						|
      null /* aFilePickerTitleKey */,
 | 
						|
      true /* aShouldBypassCache */,
 | 
						|
      false /* aSkipPrompt */,
 | 
						|
      null /* aReferrerInfo */,
 | 
						|
      null /* aCookieJarSettings*/,
 | 
						|
      null /* aSourceDocument */,
 | 
						|
      lazy.PrivateBrowsingUtils.isBrowserPrivate(
 | 
						|
        this.browser
 | 
						|
      ) /* aIsContentWindowPrivate */,
 | 
						|
      Services.scriptSecurityManager.getSystemPrincipal() /* aPrincipal */
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  _updateControlState(aMsg) {
 | 
						|
    let data = aMsg.data;
 | 
						|
    let browser = this.browser;
 | 
						|
    let tabbrowser = browser.getTabBrowser();
 | 
						|
    let tab = tabbrowser.getTabForBrowser(browser);
 | 
						|
    tabbrowser.getFindBar(tab).then(fb => {
 | 
						|
      if (!fb) {
 | 
						|
        // The tab or window closed.
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      fb.updateControlState(data.result, data.findPrevious);
 | 
						|
 | 
						|
      if (
 | 
						|
        data.result === Ci.nsITypeAheadFind.FIND_FOUND ||
 | 
						|
        data.result === Ci.nsITypeAheadFind.FIND_WRAPPED ||
 | 
						|
        (data.result === Ci.nsITypeAheadFind.FIND_PENDING &&
 | 
						|
          !this._findFailedString)
 | 
						|
      ) {
 | 
						|
        this._findFailedString = null;
 | 
						|
        lazy.SetClipboardSearchString(data.rawQuery);
 | 
						|
      } else if (!this._findFailedString) {
 | 
						|
        this._findFailedString = data.rawQuery;
 | 
						|
        lazy.SetClipboardSearchString(data.rawQuery);
 | 
						|
      }
 | 
						|
 | 
						|
      const matchesCount = this._requestMatchesCount(data.matchesCount);
 | 
						|
      fb.onMatchesCountResult(matchesCount);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  _updateMatchesCount(aMsg) {
 | 
						|
    let data = aMsg.data;
 | 
						|
    let browser = this.browser;
 | 
						|
    let tabbrowser = browser.getTabBrowser();
 | 
						|
    let tab = tabbrowser.getTabForBrowser(browser);
 | 
						|
    tabbrowser.getFindBar(tab).then(fb => {
 | 
						|
      if (!fb) {
 | 
						|
        // The tab or window closed.
 | 
						|
        return;
 | 
						|
      }
 | 
						|
      const matchesCount = this._requestMatchesCount(data);
 | 
						|
      fb.onMatchesCountResult(matchesCount);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  _requestMatchesCount(data) {
 | 
						|
    if (!data) {
 | 
						|
      return { current: 0, total: 0 };
 | 
						|
    }
 | 
						|
    let result = {
 | 
						|
      current: data.current,
 | 
						|
      total: data.total,
 | 
						|
      limit:
 | 
						|
        typeof lazy.matchesCountLimit === "number" ? lazy.matchesCountLimit : 0,
 | 
						|
    };
 | 
						|
    if (result.total > result.limit) {
 | 
						|
      result.total = -1;
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  handleEvent(aEvent) {
 | 
						|
    const type = aEvent.type;
 | 
						|
    // Handle the tab find initialized event specially:
 | 
						|
    if (type == "TabFindInitialized") {
 | 
						|
      let browser = aEvent.target.linkedBrowser;
 | 
						|
      this._hookupEventListeners(browser);
 | 
						|
      aEvent.target.removeEventListener(type, this);
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    if (type == "SwapDocShells") {
 | 
						|
      this._removeEventListener();
 | 
						|
      let newBrowser = aEvent.detail;
 | 
						|
      newBrowser.addEventListener(
 | 
						|
        "EndSwapDocShells",
 | 
						|
        () => {
 | 
						|
          this._hookupEventListeners(newBrowser);
 | 
						|
        },
 | 
						|
        { once: true }
 | 
						|
      );
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // Ignore events findbar events which arrive while the Pdfjs document is in
 | 
						|
    // the BFCache.
 | 
						|
    if (this.windowContext.isInBFCache) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // To avoid forwarding the message as a CPOW, create a structured cloneable
 | 
						|
    // version of the event for both performance, and ease of usage, reasons.
 | 
						|
    let detail = null;
 | 
						|
    if (type !== "findbarclose") {
 | 
						|
      detail = {
 | 
						|
        query: aEvent.detail.query,
 | 
						|
        caseSensitive: aEvent.detail.caseSensitive,
 | 
						|
        entireWord: aEvent.detail.entireWord,
 | 
						|
        highlightAll: aEvent.detail.highlightAll,
 | 
						|
        findPrevious: aEvent.detail.findPrevious,
 | 
						|
        matchDiacritics: aEvent.detail.matchDiacritics,
 | 
						|
      };
 | 
						|
    }
 | 
						|
 | 
						|
    let browser = aEvent.currentTarget.browser;
 | 
						|
    if (!this._boundToFindbar) {
 | 
						|
      throw new Error(
 | 
						|
        "FindEventManager was not bound for the current browser."
 | 
						|
      );
 | 
						|
    }
 | 
						|
    browser.sendMessageToActor(
 | 
						|
      "PDFJS:Child:handleEvent",
 | 
						|
      { type, detail },
 | 
						|
      "Pdfjs"
 | 
						|
    );
 | 
						|
    aEvent.preventDefault();
 | 
						|
  }
 | 
						|
 | 
						|
  _addEventListener() {
 | 
						|
    let browser = this.browser;
 | 
						|
    if (this._boundToFindbar) {
 | 
						|
      throw new Error(
 | 
						|
        "FindEventManager was bound 2nd time without unbinding it first."
 | 
						|
      );
 | 
						|
    }
 | 
						|
 | 
						|
    this._hookupEventListeners(browser);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Either hook up all the find event listeners if a findbar exists,
 | 
						|
   * or listen for a find bar being created and hook up event listeners
 | 
						|
   * when it does get created.
 | 
						|
   */
 | 
						|
  _hookupEventListeners(aBrowser) {
 | 
						|
    let tabbrowser = aBrowser.getTabBrowser();
 | 
						|
    let tab = tabbrowser.getTabForBrowser(aBrowser);
 | 
						|
    let findbar = tabbrowser.getCachedFindBar(tab);
 | 
						|
    if (findbar) {
 | 
						|
      // And we need to start listening to find events.
 | 
						|
      for (var i = 0; i < gFindTypes.length; i++) {
 | 
						|
        var type = gFindTypes[i];
 | 
						|
        findbar.addEventListener(type, this, true);
 | 
						|
      }
 | 
						|
      this._boundToFindbar = findbar;
 | 
						|
    } else {
 | 
						|
      tab.addEventListener("TabFindInitialized", this);
 | 
						|
    }
 | 
						|
    aBrowser.addEventListener("SwapDocShells", this);
 | 
						|
    return !!findbar;
 | 
						|
  }
 | 
						|
 | 
						|
  _removeEventListener() {
 | 
						|
    let browser = this.browser;
 | 
						|
 | 
						|
    // make sure the listener has been removed.
 | 
						|
    let findbar = this._boundToFindbar;
 | 
						|
    if (findbar) {
 | 
						|
      // No reason to listen to find events any longer.
 | 
						|
      for (var i = 0; i < gFindTypes.length; i++) {
 | 
						|
        var type = gFindTypes[i];
 | 
						|
        findbar.removeEventListener(type, this, true);
 | 
						|
      }
 | 
						|
    } else if (browser) {
 | 
						|
      // If we registered a `TabFindInitialized` listener which never fired,
 | 
						|
      // make sure we remove it.
 | 
						|
      let tabbrowser = browser.getTabBrowser();
 | 
						|
      let tab = tabbrowser.getTabForBrowser(browser);
 | 
						|
      tab?.removeEventListener("TabFindInitialized", this);
 | 
						|
    }
 | 
						|
 | 
						|
    this._boundToFindbar = null;
 | 
						|
 | 
						|
    // Clean up any SwapDocShells event listeners.
 | 
						|
    browser?.removeEventListener("SwapDocShells", this);
 | 
						|
  }
 | 
						|
}
 |