Home | History | Annotate | Download | only in front_end
      1 /*
      2  * Copyright (C) 2012 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 /**
     32  * @constructor
     33  */
     34 WebInspector.OverridesSupport = function()
     35 {
     36     this._overridesActive = WebInspector.settings.enableOverridesOnStartup.get();
     37     this._updateAllOverrides();
     38 
     39     WebInspector.settings.overrideUserAgent.addChangeListener(this._userAgentChanged, this);
     40     WebInspector.settings.userAgent.addChangeListener(this._userAgentChanged, this);
     41 
     42     WebInspector.settings.overrideDeviceMetrics.addChangeListener(this._deviceMetricsChanged, this);
     43     WebInspector.settings.deviceMetrics.addChangeListener(this._deviceMetricsChanged, this);
     44     WebInspector.settings.deviceFitWindow.addChangeListener(this._deviceMetricsChanged, this);
     45 
     46     WebInspector.settings.overrideGeolocation.addChangeListener(this._geolocationPositionChanged, this);
     47     WebInspector.settings.geolocationOverride.addChangeListener(this._geolocationPositionChanged, this);
     48 
     49     WebInspector.settings.overrideDeviceOrientation.addChangeListener(this._deviceOrientationChanged, this);
     50     WebInspector.settings.deviceOrientationOverride.addChangeListener(this._deviceOrientationChanged, this);
     51 
     52     WebInspector.settings.emulateTouchEvents.addChangeListener(this._emulateTouchEventsChanged, this);
     53 
     54     WebInspector.settings.overrideCSSMedia.addChangeListener(this._cssMediaChanged, this);
     55     WebInspector.settings.emulatedCSSMedia.addChangeListener(this._cssMediaChanged, this);
     56 }
     57 
     58 /**
     59  * @constructor
     60  * @param {number} width
     61  * @param {number} height
     62  * @param {number} fontScaleFactor
     63  */
     64 WebInspector.OverridesSupport.DeviceMetrics = function(width, height, fontScaleFactor)
     65 {
     66     this.width = width;
     67     this.height = height;
     68     this.fontScaleFactor = fontScaleFactor;
     69 }
     70 
     71 /**
     72  * @return {WebInspector.OverridesSupport.DeviceMetrics}
     73  */
     74 WebInspector.OverridesSupport.DeviceMetrics.parseSetting = function(value)
     75 {
     76     if (value) {
     77         var splitMetrics = value.split("x");
     78         if (splitMetrics.length === 3)
     79             return new WebInspector.OverridesSupport.DeviceMetrics(parseInt(splitMetrics[0], 10), parseInt(splitMetrics[1], 10), parseFloat(splitMetrics[2]));
     80     }
     81     return new WebInspector.OverridesSupport.DeviceMetrics(0, 0, 1);
     82 }
     83 
     84 /**
     85  * @return {?WebInspector.OverridesSupport.DeviceMetrics}
     86  */
     87 WebInspector.OverridesSupport.DeviceMetrics.parseUserInput = function(widthString, heightString, fontScaleFactorString)
     88 {
     89     function isUserInputValid(value, isInteger)
     90     {
     91         if (!value)
     92             return true;
     93         return isInteger ? /^[0]*[1-9][\d]*$/.test(value) : /^[0]*([1-9][\d]*(\.\d+)?|\.\d+)$/.test(value);
     94     }
     95 
     96     if (!widthString ^ !heightString)
     97         return null;
     98 
     99     var isWidthValid = isUserInputValid(widthString, true);
    100     var isHeightValid = isUserInputValid(heightString, true);
    101     var isFontScaleFactorValid = isUserInputValid(fontScaleFactorString, false);
    102 
    103     if (!isWidthValid && !isHeightValid && !isFontScaleFactorValid)
    104         return null;
    105 
    106     var width = isWidthValid ? parseInt(widthString || "0", 10) : -1;
    107     var height = isHeightValid ? parseInt(heightString || "0", 10) : -1;
    108     var fontScaleFactor = isFontScaleFactorValid ? parseFloat(fontScaleFactorString) : -1;
    109 
    110     return new WebInspector.OverridesSupport.DeviceMetrics(width, height, fontScaleFactor);
    111 }
    112 
    113 WebInspector.OverridesSupport.DeviceMetrics.prototype = {
    114     /**
    115      * @return {boolean}
    116      */
    117     isValid: function()
    118     {
    119         return this.isWidthValid() && this.isHeightValid() && this.isFontScaleFactorValid();
    120     },
    121 
    122     /**
    123      * @return {boolean}
    124      */
    125     isWidthValid: function()
    126     {
    127         return this.width >= 0;
    128     },
    129 
    130     /**
    131      * @return {boolean}
    132      */
    133     isHeightValid: function()
    134     {
    135         return this.height >= 0;
    136     },
    137 
    138     /**
    139      * @return {boolean}
    140      */
    141     isFontScaleFactorValid: function()
    142     {
    143         return this.fontScaleFactor > 0;
    144     },
    145 
    146     /**
    147      * @return {string}
    148      */
    149     toSetting: function()
    150     {
    151         if (!this.isValid())
    152             return "";
    153 
    154         return this.width && this.height ? this.width + "x" + this.height + "x" + this.fontScaleFactor : "";
    155     },
    156 
    157     /**
    158      * @return {string}
    159      */
    160     widthToInput: function()
    161     {
    162         return this.isWidthValid() && this.width ? String(this.width) : "";
    163     },
    164 
    165     /**
    166      * @return {string}
    167      */
    168     heightToInput: function()
    169     {
    170         return this.isHeightValid() && this.height ? String(this.height) : "";
    171     },
    172 
    173     /**
    174      * @return {string}
    175      */
    176     fontScaleFactorToInput: function()
    177     {
    178         return this.isFontScaleFactorValid() && this.fontScaleFactor ? String(this.fontScaleFactor) : "";
    179     }
    180 }
    181 
    182 /**
    183  * @constructor
    184  * @param {number} latitude
    185  * @param {number} longitude
    186  */
    187 WebInspector.OverridesSupport.GeolocationPosition = function(latitude, longitude, error)
    188 {
    189     this.latitude = latitude;
    190     this.longitude = longitude;
    191     this.error = error;
    192 }
    193 
    194 WebInspector.OverridesSupport.GeolocationPosition.prototype = {
    195     /**
    196      * @return {string}
    197      */
    198     toSetting: function()
    199     {
    200         return (typeof this.latitude === "number" && typeof this.longitude === "number" && typeof this.error === "string") ? this.latitude + "@" + this.longitude + ":" + this.error : "";
    201     }
    202 }
    203 
    204 /**
    205  * @return {WebInspector.OverridesSupport.GeolocationPosition}
    206  */
    207 WebInspector.OverridesSupport.GeolocationPosition.parseSetting = function(value)
    208 {
    209     if (value) {
    210         var splitError = value.split(":");
    211         if (splitError.length === 2) {
    212             var splitPosition = splitError[0].split("@")
    213             if (splitPosition.length === 2)
    214                 return new WebInspector.OverridesSupport.GeolocationPosition(parseFloat(splitPosition[0]), parseFloat(splitPosition[1]), splitError[1]);
    215         }
    216     }
    217     return new WebInspector.OverridesSupport.GeolocationPosition(0, 0, "");
    218 }
    219 
    220 /**
    221  * @return {?WebInspector.OverridesSupport.GeolocationPosition}
    222  */
    223 WebInspector.OverridesSupport.GeolocationPosition.parseUserInput = function(latitudeString, longitudeString, errorStatus)
    224 {
    225     function isUserInputValid(value)
    226     {
    227         if (!value)
    228             return true;
    229         return /^[-]?[0-9]*[.]?[0-9]*$/.test(value);
    230     }
    231 
    232     if (!latitudeString ^ !latitudeString)
    233         return null;
    234 
    235     var isLatitudeValid = isUserInputValid(latitudeString);
    236     var isLongitudeValid = isUserInputValid(longitudeString);
    237 
    238     if (!isLatitudeValid && !isLongitudeValid)
    239         return null;
    240 
    241     var latitude = isLatitudeValid ? parseFloat(latitudeString) : -1;
    242     var longitude = isLongitudeValid ? parseFloat(longitudeString) : -1;
    243 
    244     return new WebInspector.OverridesSupport.GeolocationPosition(latitude, longitude, errorStatus ? "PositionUnavailable" : "");
    245 }
    246 
    247 WebInspector.OverridesSupport.GeolocationPosition.clearGeolocationOverride = function()
    248 {
    249     PageAgent.clearGeolocationOverride();
    250 }
    251 
    252 /**
    253  * @constructor
    254  * @param {number} alpha
    255  * @param {number} beta
    256  * @param {number} gamma
    257  */
    258 WebInspector.OverridesSupport.DeviceOrientation = function(alpha, beta, gamma)
    259 {
    260     this.alpha = alpha;
    261     this.beta = beta;
    262     this.gamma = gamma;
    263 }
    264 
    265 WebInspector.OverridesSupport.DeviceOrientation.prototype = {
    266     /**
    267      * @return {string}
    268      */
    269     toSetting: function()
    270     {
    271         return JSON.stringify(this);
    272     }
    273 }
    274 
    275 /**
    276  * @return {WebInspector.OverridesSupport.DeviceOrientation}
    277  */
    278 WebInspector.OverridesSupport.DeviceOrientation.parseSetting = function(value)
    279 {
    280     if (value) {
    281         var jsonObject = JSON.parse(value);
    282         return new WebInspector.OverridesSupport.DeviceOrientation(jsonObject.alpha, jsonObject.beta, jsonObject.gamma);
    283     }
    284     return new WebInspector.OverridesSupport.DeviceOrientation(0, 0, 0);
    285 }
    286 
    287 /**
    288  * @return {?WebInspector.OverridesSupport.DeviceOrientation}
    289  */
    290 WebInspector.OverridesSupport.DeviceOrientation.parseUserInput = function(alphaString, betaString, gammaString)
    291 {
    292     function isUserInputValid(value)
    293     {
    294         if (!value)
    295             return true;
    296         return /^[-]?[0-9]*[.]?[0-9]*$/.test(value);
    297     }
    298 
    299     if (!alphaString ^ !betaString ^ !gammaString)
    300         return null;
    301 
    302     var isAlphaValid = isUserInputValid(alphaString);
    303     var isBetaValid = isUserInputValid(betaString);
    304     var isGammaValid = isUserInputValid(gammaString);
    305 
    306     if (!isAlphaValid && !isBetaValid && !isGammaValid)
    307         return null;
    308 
    309     var alpha = isAlphaValid ? parseFloat(alphaString) : -1;
    310     var beta = isBetaValid ? parseFloat(betaString) : -1;
    311     var gamma = isGammaValid ? parseFloat(gammaString) : -1;
    312 
    313     return new WebInspector.OverridesSupport.DeviceOrientation(alpha, beta, gamma);
    314 }
    315 
    316 WebInspector.OverridesSupport.DeviceOrientation.clearDeviceOrientationOverride = function()
    317 {
    318     PageAgent.clearDeviceOrientationOverride();
    319 }
    320 
    321 WebInspector.OverridesSupport.prototype = {
    322     setOverridesActive: function(enabled)
    323     {
    324         if (this._overridesActive === enabled)
    325             return;
    326         this._overridesActive = enabled;
    327 
    328         this._updateAllOverrides();
    329     },
    330 
    331     _updateAllOverrides: function()
    332     {
    333         this._userAgentChanged();
    334         this._deviceMetricsChanged();
    335         this._deviceOrientationChanged();
    336         this._geolocationPositionChanged();
    337         this._emulateTouchEventsChanged();
    338         this._cssMediaChanged();
    339     },
    340 
    341     _userAgentChanged: function()
    342     {
    343         NetworkAgent.setUserAgentOverride(this._overridesActive && WebInspector.settings.overrideUserAgent.get() ? WebInspector.settings.userAgent.get() : "");
    344     },
    345 
    346     _deviceMetricsChanged: function()
    347     {
    348         var metrics = WebInspector.OverridesSupport.DeviceMetrics.parseSetting(this._overridesActive && WebInspector.settings.overrideDeviceMetrics.get() ? WebInspector.settings.deviceMetrics.get() : "");
    349         if (metrics.isValid())
    350             PageAgent.setDeviceMetricsOverride(metrics.width, metrics.height, metrics.fontScaleFactor, WebInspector.settings.deviceFitWindow.get());
    351     },
    352 
    353     _geolocationPositionChanged: function()
    354     {
    355         if (!this._overridesActive || !WebInspector.settings.overrideGeolocation.get()) {
    356             PageAgent.clearGeolocationOverride();
    357             return;
    358         }
    359         var geolocation = WebInspector.OverridesSupport.GeolocationPosition.parseSetting(WebInspector.settings.geolocationOverride.get());
    360         if (geolocation.error)
    361             PageAgent.setGeolocationOverride();
    362         else
    363             PageAgent.setGeolocationOverride(geolocation.latitude, geolocation.longitude, 150);
    364     },
    365 
    366     _deviceOrientationChanged: function()
    367     {
    368         if (!this._overridesActive || !WebInspector.settings.overrideDeviceOrientation.get()) {
    369             PageAgent.clearDeviceOrientationOverride();
    370             return;
    371         }
    372         var deviceOrientation = WebInspector.OverridesSupport.DeviceOrientation.parseSetting(WebInspector.settings.deviceOrientationOverride.get());
    373         PageAgent.setDeviceOrientationOverride(deviceOrientation.alpha, deviceOrientation.beta, deviceOrientation.gamma);
    374     },
    375 
    376     _emulateTouchEventsChanged: function()
    377     {
    378         WebInspector.domAgent.emulateTouchEventObjects(this._overridesActive && WebInspector.settings.emulateTouchEvents.get());
    379     },
    380 
    381     _cssMediaChanged: function()
    382     {
    383         PageAgent.setEmulatedMedia(this._overridesActive && WebInspector.settings.overrideCSSMedia.get() ? WebInspector.settings.emulatedCSSMedia.get() : "");
    384         WebInspector.cssModel.mediaQueryResultChanged();
    385     }
    386 }
    387 
    388 
    389 /**
    390  * @type {WebInspector.OverridesSupport}
    391  */
    392 WebInspector.overridesSupport;
    393