From: Ian Moody <moz-ian@perix.co.uk>

Bug 662324 - Add "Fill" and "Fit" position support for "Set As Desktop Background..."

diff --git a/browser/components/shell/content/setDesktopBackground.js b/browser/components/shell/content/setDesktopBackground.js
--- a/browser/components/shell/content/setDesktopBackground.js
+++ b/browser/components/shell/content/setDesktopBackground.js
@@ -63,16 +63,28 @@ var gSetBackground = {
     this._screenWidth = screen.width;
     this._screenHeight = screen.height;
 #ifdef XP_MACOSX
     document.documentElement.getButton("accept").hidden = true;
 #endif
     if (this._screenWidth / this._screenHeight >= 1.6)
       document.getElementById("monitor").setAttribute("aspectratio", "16:10");
 
+#ifdef XP_WIN
+    // hide fill + fit options if <win7 since don't work 
+    var version = Components.classes["@mozilla.org/system-info;1"]
+                  .getService(Ci.nsIPropertyBag2)
+                  .getProperty("version");
+    var isWindows7OrHigher = (parseFloat(version) >= 6.1);
+    if (!isWindows7OrHigher) {
+      document.getElementById("fillPosition").hidden = true;
+      document.getElementById("fitPosition").hidden = true;
+    }
+#endif
+
     // make sure that the correct dimensions will be used
     setTimeout(function(self) {
       self.init(window.arguments[0]);
     }, 0, this);
   },
 
   init: function (aImage)
   {
@@ -193,11 +205,44 @@ var gSetBackground = {
         break;
       case "STRETCH":
         ctx.drawImage(this._image, 0, 0, this._screenWidth, this._screenHeight);
         break;
       case "CENTER":
         var x = (this._screenWidth - this._image.naturalWidth) / 2;
         var y = (this._screenHeight - this._image.naturalHeight) / 2;
         ctx.drawImage(this._image, x, y);
+        break;
+      case "FILL":
+        //Try maxing width first, overflow height
+        var widthRatio = this._screenWidth / this._image.naturalWidth;
+        var width = this._image.naturalWidth * widthRatio;
+        var height = this._image.naturalHeight * widthRatio;
+        if (height < this._screenHeight) {
+          //height less than screen, max height and overflow width
+          var heightRatio = this._screenHeight / this._image.naturalHeight;
+          width = this._image.naturalWidth * heightRatio;
+          height = this._image.naturalHeight * heightRatio;
+        }
+        var x = (this._screenWidth - width) / 2;
+        var y = (this._screenHeight - height) / 2;
+        ctx.drawImage(this._image, x, y, width, height);
+        break;
+      case "FIT":
+        //Try maxing width first, top and bottom borders
+        var widthRatio = this._screenWidth / this._image.naturalWidth;
+        var width = this._image.naturalWidth * widthRatio;
+        var height = this._image.naturalHeight * widthRatio;
+        var x = 0;
+        var y = (this._screenHeight - height) / 2;
+        if (height > this._screenHeight) {
+          //height overflow, maximise height, side borders
+          var heightRatio = this._screenHeight / this._image.naturalHeight;
+          width = this._image.naturalWidth * heightRatio;
+          height = this._image.naturalHeight * heightRatio;
+          x = (this._screenWidth - width) / 2;
+          y = 0;
+        }
+        ctx.drawImage(this._image, x, y, width, height);
+        break;      
     }
   }
 };
diff --git a/browser/components/shell/content/setDesktopBackground.xul b/browser/components/shell/content/setDesktopBackground.xul
--- a/browser/components/shell/content/setDesktopBackground.xul
+++ b/browser/components/shell/content/setDesktopBackground.xul
@@ -73,16 +73,18 @@
       <label value="&position.label;"/>
       <menulist id="menuPosition"
                 label="&position.label;" 
                 oncommand="gSetBackground.updatePosition();">
         <menupopup>
           <menuitem label="&center.label;"  value="CENTER"/>
           <menuitem label="&tile.label;"    value="TILE"/>
           <menuitem label="&stretch.label;" value="STRETCH"/>
+          <menuitem label="&fill.label;"    value="FILL" id="fillPosition"/>
+          <menuitem label="&fit.label;"     value="FIT"  id="fitPosition"/>
         </menupopup>
       </menulist>
       <spacer flex="1"/>
       <label value="&color.label;"/>
       <colorpicker id="desktopColor"
                    type="button" 
                    onchange="gSetBackground.updateColor(this.color);"/> 
     </hbox>
diff --git a/browser/components/shell/public/nsIShellService.idl b/browser/components/shell/public/nsIShellService.idl
--- a/browser/components/shell/public/nsIShellService.idl
+++ b/browser/components/shell/public/nsIShellService.idl
@@ -76,16 +76,17 @@ interface nsIShellService : nsISupports
 
   /** 
    * Flags for positioning/sizing of the Desktop Background image.
    */
   const long BACKGROUND_TILE      = 1;
   const long BACKGROUND_STRETCH   = 2;
   const long BACKGROUND_CENTER    = 3;
   const long BACKGROUND_FILL      = 4;
+  const long BACKGROUND_FIT       = 5;
 
     /**
      * Sets the desktop background image using either the HTML <IMG> 
      * element supplied or the background image of the element supplied.
      *
      * @param aImageElement Either a HTML <IMG> element or an element with
      *                      a background image from which to source the
      *                      background image. 
diff --git a/browser/components/shell/src/nsGNOMEShellService.cpp b/browser/components/shell/src/nsGNOMEShellService.cpp
--- a/browser/components/shell/src/nsGNOMEShellService.cpp
+++ b/browser/components/shell/src/nsGNOMEShellService.cpp
@@ -422,16 +422,20 @@ nsGNOMEShellService::SetDesktopBackgroun
   if (!container) return rv;
 
   // Set desktop wallpaper filling style
   nsCAutoString options;
   if (aPosition == BACKGROUND_TILE)
     options.Assign("wallpaper");
   else if (aPosition == BACKGROUND_STRETCH)
     options.Assign("stretched");
+  else if (aPosition == BACKGROUND_FILL)
+    options.Assign("zoom");
+  else if (aPosition == BACKGROUND_FIT)
+    options.Assign("scaled");
   else
     options.Assign("centered");
 
   // Write the background file to the home directory.
   nsCAutoString filePath(PR_GetEnv("HOME"));
 
   // get the product brand name from localized strings
   nsString brandName;
diff --git a/browser/components/shell/src/nsWindowsShellService.cpp b/browser/components/shell/src/nsWindowsShellService.cpp
--- a/browser/components/shell/src/nsWindowsShellService.cpp
+++ b/browser/components/shell/src/nsWindowsShellService.cpp
@@ -635,16 +635,24 @@ nsWindowsShellService::SetDesktopBackgro
       case BACKGROUND_CENTER:
         style.AssignLiteral("0");
         tile.AssignLiteral("0");
         break;
       case BACKGROUND_STRETCH:
         style.AssignLiteral("2");
         tile.AssignLiteral("0");
         break;
+      case BACKGROUND_FILL:
+        style.AssignLiteral("10");
+        tile.AssignLiteral("0");
+        break;
+      case BACKGROUND_FIT:
+        style.AssignLiteral("6");
+        tile.AssignLiteral("0");
+        break;
     }
 
     rv = regKey->WriteStringValue(NS_LITERAL_STRING("TileWallpaper"), tile);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = regKey->WriteStringValue(NS_LITERAL_STRING("WallpaperStyle"), style);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = regKey->Close();
     NS_ENSURE_SUCCESS(rv, rv);
diff --git a/browser/components/shell/test/browser_420786.js b/browser/components/shell/test/browser_420786.js
--- a/browser/components/shell/test/browser_420786.js
+++ b/browser/components/shell/test/browser_420786.js
@@ -48,16 +48,17 @@ function onPageLoad() {
     is(gconf.getString(DG_OPTION_KEY), expectedGConfPosition,
        "Wallpaper position GConf key is correct");
   }
 
   checkWallpaper(Ci.nsIShellService.BACKGROUND_TILE, "wallpaper");
   checkWallpaper(Ci.nsIShellService.BACKGROUND_STRETCH, "stretched");
   checkWallpaper(Ci.nsIShellService.BACKGROUND_CENTER, "centered");
-  checkWallpaper(Ci.nsIShellService.BACKGROUND_FILL, "centered");
+  checkWallpaper(Ci.nsIShellService.BACKGROUND_FILL, "zoom");
+  checkWallpaper(Ci.nsIShellService.BACKGROUND_FIT, "scaled");
 
   // Restore GConf and wallpaper
 
   gconf.setString(DG_IMAGE_KEY, prevImageKey);
   gconf.setString(DG_OPTION_KEY, prevOptionKey);
   gconf.setBool(DG_DRAW_BG_KEY, prevDrawBgKey);
 
   wpFile.remove(false);
diff --git a/browser/locales/en-US/chrome/browser/setDesktopBackground.dtd b/browser/locales/en-US/chrome/browser/setDesktopBackground.dtd
--- a/browser/locales/en-US/chrome/browser/setDesktopBackground.dtd
+++ b/browser/locales/en-US/chrome/browser/setDesktopBackground.dtd
@@ -1,9 +1,11 @@
 <!ENTITY position.label             "Position:">
 <!ENTITY tile.label                 "Tile">
 <!ENTITY center.label               "Center">
 <!ENTITY stretch.label              "Stretch">
+<!ENTITY fill.label                 "Fill">
+<!ENTITY fit.label                  "Fit">
 <!ENTITY preview.label              "Preview">
 <!ENTITY color.label                "Color:">
 <!ENTITY setDesktopBackground.title "Set Desktop Background">
 <!ENTITY openDesktopPrefs.label     "Open Desktop Preferences">
 <!ENTITY closeWindow.key            "w">
