b2g/chrome/content/screen.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 // screen.js:
     2 // Set the screen size, pixel density and scaling of the b2g client screen
     3 // based on the --screen command-line option, if there is one.
     4 // 
     5 // TODO: support multiple device pixels per CSS pixel
     6 // 
     8 // We do this on ContentStart because querying the displayDPI fails otherwise.
     9 window.addEventListener('ContentStart', function() {
    10   // This is the toplevel <window> element
    11   let shell = document.getElementById('shell');
    13   // The <browser> element inside it
    14   let browser = document.getElementById('systemapp');
    16   // Figure out the native resolution of the screen
    17   let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
    18     .getInterface(Components.interfaces.nsIDOMWindowUtils);
    19   let hostDPI = windowUtils.displayDPI;
    21   let DEFAULT_SCREEN = '320x480';
    23   // This is a somewhat random selection of named screens.
    24   // Add more to this list when we support more hardware.
    25   // Data from: http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density
    26   let screens = {
    27     iphone: {
    28       name: 'Apple iPhone', width:320, height:480,  dpi:163
    29     },
    30     ipad: {
    31       name: 'Apple iPad', width:1024, height:768,  dpi:132
    32     },
    33     nexus_s: {
    34       name: 'Samsung Nexus S', width:480, height:800, dpi:235
    35     },
    36     galaxy_s2: {
    37       name: 'Samsung Galaxy SII (I9100)', width:480, height:800, dpi:219
    38     },
    39     galaxy_nexus: {
    40       name: 'Samsung Galaxy Nexus', width:720, height:1280, dpi:316
    41     },
    42     galaxy_tab: {
    43       name: 'Samsung Galaxy Tab 10.1', width:800, height:1280, dpi:149
    44     },
    45     wildfire: {
    46       name: 'HTC Wildfire', width:240, height:320, dpi:125
    47     },
    48     tattoo: {
    49       name: 'HTC Tattoo', width:240, height:320, dpi:143
    50     },
    51     salsa: {
    52       name: 'HTC Salsa', width:320, height:480, dpi:170
    53     },
    54     chacha: {
    55       name: 'HTC ChaCha', width:320, height:480, dpi:222
    56     },
    57   };
    59   // Get the command line arguments that were passed to the b2g client
    60   let args;
    61   try {
    62     // On Firefox Mulet, we don't always have a command line argument
    63     args = window.arguments[0].QueryInterface(Ci.nsICommandLine);
    64   } catch(e) {}
    66   let screenarg = null;
    68   // Get the --screen argument from the command line
    69   try {
    70     if (args) {
    71       screenarg = args.handleFlagWithParam('screen', false);
    72     }
    74     // If there isn't one, use the default screen
    75     if (screenarg === null)
    76       screenarg = DEFAULT_SCREEN;
    78     // With no value, tell the user how to use it
    79     if (screenarg == '')
    80       usage();
    81   }
    82   catch(e) {
    83     // If getting the argument value fails, its an error
    84     usage();
    85   }
    87   // Special case --screen=full goes into fullscreen mode
    88   if (screenarg === 'full') {
    89     shell.setAttribute('sizemode', 'fullscreen');
    90     return;
    91   } 
    93   let rescale = false;
    95   // If the value of --screen ends with !, we'll be scaling the output
    96   if (screenarg[screenarg.length - 1] === '!') {
    97     rescale = true;
    98     screenarg = screenarg.substring(0, screenarg.length-1);
    99   }
   101   let width, height, dpi;
   103   if (screenarg in screens) {
   104     // If this is a named screen, get its data
   105     let screen = screens[screenarg];
   106     width = screen.width;
   107     height = screen.height;
   108     dpi = screen.dpi;
   109   } else {
   110     // Otherwise, parse the resolution and density from the --screen value.
   111     // The supported syntax is WIDTHxHEIGHT[@DPI]
   112     let match = screenarg.match(/^(\d+)x(\d+)(@(\d+))?$/);
   114     // Display usage information on syntax errors
   115     if (match == null)
   116       usage();
   118     // Convert strings to integers
   119     width = parseInt(match[1], 10);
   120     height = parseInt(match[2], 10);
   121     if (match[4])
   122       dpi = parseInt(match[4], 10);
   123     else    // If no DPI, use the actual dpi of the host screen
   124       dpi = hostDPI;
   126     // If any of the values came out 0 or NaN or undefined, display usage
   127     if (!width || !height || !dpi)
   128       usage();
   129   }
   131   Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm");
   132   function resize(width, height, dpi, shouldFlip) {
   133     GlobalSimulatorScreen.width = width;
   134     GlobalSimulatorScreen.height = height;
   136     // In order to do rescaling, we set the <browser> tag to the specified
   137     // width and height, and then use a CSS transform to scale it so that
   138     // it appears at the correct size on the host display.  We also set
   139     // the size of the <window> element to that scaled target size.
   140     let scale = rescale ? hostDPI / dpi : 1;
   142     // Set the window width and height to desired size plus chrome
   143     // Include the size of the toolbox displayed under the system app
   144     let controls = document.getElementById('controls');
   145     let controlsHeight = 0;
   146     if (controls) {
   147       controlsHeight = controls.getBoundingClientRect().height;
   148     }
   149     let chromewidth = window.outerWidth - window.innerWidth;
   150     let chromeheight = window.outerHeight - window.innerHeight + controlsHeight;
   151     window.resizeTo(Math.round(width * scale) + chromewidth,
   152                     Math.round(height * scale) + chromeheight);
   154     let frameWidth = width, frameHeight = height;
   155     if (shouldFlip) {
   156       frameWidth = height;
   157       frameHeight = width;
   158     }
   160     // Set the browser element to the full unscaled size of the screen
   161     let style = browser.style;
   162     style.width = style.minWidth = style.maxWidth =
   163       frameWidth + 'px';
   164     style.height = style.minHeight = style.maxHeight =
   165       frameHeight + 'px';
   166     browser.setAttribute('flex', '0');  // Don't let it stretch
   168     style.transformOrigin = '';
   169     style.transform = '';
   171     // Now scale the browser element as needed
   172     if (scale !== 1) {
   173       style.transformOrigin = 'top left';
   174       style.transform += ' scale(' + scale + ',' + scale + ')';
   175     }
   177     if (shouldFlip) {
   178       // Display the system app with a 90° clockwise rotation
   179       let shift = Math.floor(Math.abs(frameWidth-frameHeight) / 2);
   180       style.transform +=
   181         ' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)';
   182     }
   184     // Set the pixel density that we want to simulate.
   185     // This doesn't change the on-screen size, but makes
   186     // CSS media queries and mozmm units work right.
   187     Services.prefs.setIntPref('layout.css.dpi', dpi);
   188   }
   190   // Resize on startup
   191   resize(width, height, dpi, false);
   193   let defaultOrientation = width < height ? 'portrait' : 'landscape';
   195   // Then resize on each rotation button click,
   196   // or when the system app lock/unlock the orientation
   197   Services.obs.addObserver(function orientationChangeListener(subject) {
   198     let screen = subject.wrappedJSObject;
   199     let { mozOrientation, screenOrientation } = screen;
   201     let newWidth = width;
   202     let newHeight = height;
   203     // If we have an orientation different than the startup one,
   204     // we switch the sizes
   205     if (screenOrientation != defaultOrientation) {
   206       newWidth = height;
   207       newHeight = width;
   208     }
   210     // If the current app doesn't supports the current screen orientation
   211     // still resize the window, but rotate its frame so that
   212     // it is displayed rotated on the side
   213     let shouldFlip = mozOrientation != screenOrientation;
   215     resize(newWidth, newHeight, dpi, shouldFlip);
   216   }, 'simulator-adjust-window-size', false);
   218   // A utility function like console.log() for printing to the terminal window
   219   // Uses dump(), but enables it first, if necessary
   220   function print() {
   221     let dump_enabled =
   222       Services.prefs.getBoolPref('browser.dom.window.dump.enabled');
   224     if (!dump_enabled)
   225       Services.prefs.setBoolPref('browser.dom.window.dump.enabled', true);
   227     dump(Array.prototype.join.call(arguments, ' ') + '\n');
   229     if (!dump_enabled) 
   230       Services.prefs.setBoolPref('browser.dom.window.dump.enabled', false);
   231   }
   233   // Print usage info for --screen and exit
   234   function usage() {
   235     // Documentation for the --screen argument
   236     let msg = 
   237       'The --screen argument specifies the desired resolution and\n' +
   238       'pixel density of the simulated device screen. Use it like this:\n' +
   239       '\t--screen=WIDTHxHEIGHT\t\t\t// E.g.: --screen=320x480\n' +
   240       '\t--screen=WIDTHxHEIGHT@DOTS_PER_INCH\t// E.g.: --screen=480x800@250\n' +
   241       '\t--screen=full\t\t\t\t// run in fullscreen mode\n' +
   242       '\nYou can also specify certain device names:\n';
   243     for(let p in screens)
   244       msg += '\t--screen=' + p + '\t// ' + screens[p].name + '\n';
   245     msg += 
   246       '\nAdd a ! to the end of a screen specification to rescale the\n' +
   247       'screen so that it is shown at actual size on your monitor:\n' +
   248       '\t--screen=nexus_s!\n' +
   249       '\t--screen=320x480@200!\n'
   250     ;
   252     // Display the usage message
   253     print(msg);
   255     // Exit the b2g client
   256     Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit);
   257   }
   258 });

mercurial