forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			196 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
	
		
			7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* 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/. */
 | |
| "use strict";
 | |
| 
 | |
| /*
 | |
|  * This test validates that an OTF font installed in a directory not
 | |
|  * accessible to content processes is rendered correctly by checking that
 | |
|  * content displayed never uses the OS fallback font "LastResort". When
 | |
|  * a content process renders a page with the fallback font, that is an
 | |
|  * indication the content process failed to read or load the computed font.
 | |
|  * The test uses a version of the Fira Sans font and depends on the font
 | |
|  * not being already installed and enabled.
 | |
|  */
 | |
| 
 | |
| const kPageURL =
 | |
|   "http://example.com/browser/security/sandbox/test/bug1393259.html";
 | |
| 
 | |
| // Parameters for running the python script that registers/unregisters fonts.
 | |
| const kPythonPath = "/usr/bin/python";
 | |
| const kFontInstallerPath = "browser/security/sandbox/test/mac_register_font.py";
 | |
| const kUninstallFlag = "-u";
 | |
| const kVerboseFlag = "-v";
 | |
| 
 | |
| // Where to find the font in the test environment.
 | |
| const kRepoFontPath = "browser/security/sandbox/test/FiraSans-Regular.otf";
 | |
| 
 | |
| // Font name strings to check for.
 | |
| const kLastResortFontName = "LastResort";
 | |
| const kTestFontName = "Fira Sans";
 | |
| 
 | |
| // Home-relative path to install a private font. Where a private font is
 | |
| // a font at a location not readable by content processes.
 | |
| const kPrivateFontSubPath = "/FiraSans-Regular.otf";
 | |
| 
 | |
| add_task(async function() {
 | |
|   await new Promise(resolve => waitForFocus(resolve, window));
 | |
| 
 | |
|   await BrowserTestUtils.withNewTab(
 | |
|     {
 | |
|       gBrowser,
 | |
|       url: kPageURL,
 | |
|     },
 | |
|     async function(aBrowser) {
 | |
|       function runProcess(aCmd, aArgs, blocking = true) {
 | |
|         let cmdFile = Cc["@mozilla.org/file/local;1"].createInstance(
 | |
|           Ci.nsIFile
 | |
|         );
 | |
|         cmdFile.initWithPath(aCmd);
 | |
| 
 | |
|         let process = Cc["@mozilla.org/process/util;1"].createInstance(
 | |
|           Ci.nsIProcess
 | |
|         );
 | |
|         process.init(cmdFile);
 | |
|         process.run(blocking, aArgs, aArgs.length);
 | |
|         return process.exitValue;
 | |
|       }
 | |
| 
 | |
|       // Register the font at path |fontPath| and wait
 | |
|       // for the browser to detect the change.
 | |
|       async function registerFont(fontPath) {
 | |
|         let fontRegistered = getFontNotificationPromise();
 | |
|         let exitCode = runProcess(kPythonPath, [
 | |
|           kFontInstallerPath,
 | |
|           kVerboseFlag,
 | |
|           fontPath,
 | |
|         ]);
 | |
|         Assert.ok(exitCode == 0, "registering font" + fontPath);
 | |
|         if (exitCode == 0) {
 | |
|           // Wait for the font registration to be detected by the browser.
 | |
|           await fontRegistered;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       // Unregister the font at path |fontPath|. If |waitForUnreg| is true,
 | |
|       // don't wait for the browser to detect the change and don't use
 | |
|       // the verbose arg for the unregister command.
 | |
|       async function unregisterFont(fontPath, waitForUnreg = true) {
 | |
|         let args = [kFontInstallerPath, kUninstallFlag];
 | |
|         let fontUnregistered;
 | |
| 
 | |
|         if (waitForUnreg) {
 | |
|           args.push(kVerboseFlag);
 | |
|           fontUnregistered = getFontNotificationPromise();
 | |
|         }
 | |
| 
 | |
|         let exitCode = runProcess(kPythonPath, args.concat(fontPath));
 | |
|         if (waitForUnreg) {
 | |
|           Assert.ok(exitCode == 0, "unregistering font" + fontPath);
 | |
|           if (exitCode == 0) {
 | |
|             await fontUnregistered;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       // Returns a promise that resolves when font info is changed.
 | |
|       let getFontNotificationPromise = () =>
 | |
|         new Promise(resolve => {
 | |
|           const kTopic = "font-info-updated";
 | |
|           function observe() {
 | |
|             Services.obs.removeObserver(observe, kTopic);
 | |
|             resolve();
 | |
|           }
 | |
| 
 | |
|           Services.obs.addObserver(observe, kTopic);
 | |
|         });
 | |
| 
 | |
|       let homeDir = Services.dirsvc.get("Home", Ci.nsIFile);
 | |
|       let privateFontPath = homeDir.path + kPrivateFontSubPath;
 | |
| 
 | |
|       registerCleanupFunction(function() {
 | |
|         unregisterFont(privateFontPath, /* waitForUnreg = */ false);
 | |
|         runProcess("/bin/rm", [privateFontPath], /* blocking = */ false);
 | |
|       });
 | |
| 
 | |
|       // Copy the font file to the private path.
 | |
|       runProcess("/bin/cp", [kRepoFontPath, privateFontPath]);
 | |
| 
 | |
|       // Cleanup previous aborted tests.
 | |
|       unregisterFont(privateFontPath, /* waitForUnreg = */ false);
 | |
| 
 | |
|       // Get the original width, using the fallback monospaced font
 | |
|       let origWidth = await SpecialPowers.spawn(aBrowser, [], async function() {
 | |
|         let window = content.window.wrappedJSObject;
 | |
|         let contentDiv = window.document.getElementById("content");
 | |
|         return contentDiv.offsetWidth;
 | |
|       });
 | |
| 
 | |
|       // Activate the font we want to test at a non-standard path.
 | |
|       await registerFont(privateFontPath);
 | |
| 
 | |
|       // Assign the new font to the content.
 | |
|       await SpecialPowers.spawn(aBrowser, [], async function() {
 | |
|         let window = content.window.wrappedJSObject;
 | |
|         let contentDiv = window.document.getElementById("content");
 | |
|         contentDiv.style.fontFamily = "'Fira Sans', monospace";
 | |
|       });
 | |
| 
 | |
|       // Wait until the width has changed, indicating the content process
 | |
|       // has recognized the newly-activated font.
 | |
|       while (true) {
 | |
|         let width = await SpecialPowers.spawn(aBrowser, [], async function() {
 | |
|           let window = content.window.wrappedJSObject;
 | |
|           let contentDiv = window.document.getElementById("content");
 | |
|           return contentDiv.offsetWidth;
 | |
|         });
 | |
|         if (width != origWidth) {
 | |
|           break;
 | |
|         }
 | |
|         // If the content wasn't ready yet, wait a little before re-checking.
 | |
|         // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
 | |
|         await new Promise(c => setTimeout(c, 100));
 | |
|       }
 | |
| 
 | |
|       // Get a list of fonts now being used to display the web content.
 | |
|       let fontList = await SpecialPowers.spawn(aBrowser, [], async function() {
 | |
|         let window = content.window.wrappedJSObject;
 | |
|         let range = window.document.createRange();
 | |
|         let contentDiv = window.document.getElementById("content");
 | |
|         range.selectNode(contentDiv);
 | |
|         let fonts = InspectorUtils.getUsedFontFaces(range);
 | |
| 
 | |
|         let fontList = [];
 | |
|         for (let i = 0; i < fonts.length; i++) {
 | |
|           fontList.push({ name: fonts[i].name });
 | |
|         }
 | |
|         return fontList;
 | |
|       });
 | |
| 
 | |
|       let lastResortFontUsed = false;
 | |
|       let testFontUsed = false;
 | |
| 
 | |
|       for (let font of fontList) {
 | |
|         // Did we fall back to the "LastResort" font?
 | |
|         if (!lastResortFontUsed && font.name.includes(kLastResortFontName)) {
 | |
|           lastResortFontUsed = true;
 | |
|           continue;
 | |
|         }
 | |
|         // Did we render using our test font as expected?
 | |
|         if (!testFontUsed && font.name.includes(kTestFontName)) {
 | |
|           testFontUsed = true;
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       Assert.ok(
 | |
|         !lastResortFontUsed,
 | |
|         `The ${kLastResortFontName} fallback font was not used`
 | |
|       );
 | |
| 
 | |
|       Assert.ok(testFontUsed, `The test font "${kTestFontName}" was used`);
 | |
| 
 | |
|       await unregisterFont(privateFontPath);
 | |
|     }
 | |
|   );
 | |
| });
 | 
