Bug 990608 - Make tile size configurable. r=tn,nical,bgirard
authorChris Lord <chrislord.net@gmail.com>
Fri, 04 Apr 2014 18:42:44 +0100
changeset 195800 efd2b6b51237e5017967b5e6e5b8db342881f3c1
parent 195799 0ac3e117921102e3a80102032c5ba9d07a252717
child 195801 2b3cf40ab7d3dd670e679e6d354181d2ffe73682
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn, nical, bgirard
bugs990608
milestone31.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 990608 - Make tile size configurable. r=tn,nical,bgirard
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
gfx/gl/GfxTexturesReporter.cpp
gfx/gl/GfxTexturesReporter.h
gfx/layers/TiledLayerBuffer.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/SimpleTiledContentClient.cpp
gfx/layers/client/TiledContentClient.cpp
gfx/layers/composite/TiledContentHost.cpp
gfx/layers/opengl/TextureHostOGL.cpp
gfx/tests/gtest/TestTiledLayerBuffer.cpp
gfx/thebes/gfxPrefs.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
widget/xpwidgets/APZCCallbackHelper.cpp
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -401,17 +401,18 @@ nsDOMWindowUtils::SetDisplayPortForEleme
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SetDisplayPortMarginsForElement(float aLeftMargin,
                                                   float aTopMargin,
                                                   float aRightMargin,
                                                   float aBottomMargin,
-                                                  uint32_t aAlignment,
+                                                  uint32_t aAlignmentX,
+                                                  uint32_t aAlignmentY,
                                                   nsIDOMElement* aElement,
                                                   uint32_t aPriority)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   nsIPresShell* presShell = GetPresShell();
@@ -442,17 +443,17 @@ nsDOMWindowUtils::SetDisplayPortMarginsF
   // Note order change of arguments between our function signature and
   // LayerMargin constructor.
   LayerMargin displayportMargins(aTopMargin,
                                  aRightMargin,
                                  aBottomMargin,
                                  aLeftMargin);
 
   content->SetProperty(nsGkAtoms::DisplayPortMargins,
-                       new DisplayPortMarginsPropertyData(displayportMargins, aAlignment, aPriority),
+                       new DisplayPortMarginsPropertyData(displayportMargins, aAlignmentX, aAlignmentY, aPriority),
                        nsINode::DeleteProperty<DisplayPortMarginsPropertyData>);
 
   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
   if (rootScrollFrame && content == rootScrollFrame->GetContent()) {
     // We are setting a root displayport for a document.
     // The pres shell needs a special flag set.
     presShell->SetIgnoreViewportScrolling(true);
   }
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -171,17 +171,18 @@ interface nsIDOMWindowUtils : nsISupport
    * Note that both the margin values and alignment are treated as values in
    * LayerPixels. Refer to layout/base/Units.h for a description of this unit.
    * The base rect values are in app units.
    */
   void setDisplayPortMarginsForElement(in float aLeftMargin,
                                        in float aTopMargin,
                                        in float aRightMargin,
                                        in float aBottomMargin,
-                                       in uint32_t aAlignment,
+                                       in uint32_t aAlignmentX,
+                                       in uint32_t aAlignmentY,
                                        in nsIDOMElement aElement,
                                        in uint32_t aPriority);
 
   void setDisplayPortBaseForElement(in int32_t aX,
                                     in int32_t aY,
                                     in int32_t aWidth,
                                     in int32_t aHeight,
                                     in nsIDOMElement aElement);
--- a/gfx/gl/GfxTexturesReporter.cpp
+++ b/gfx/gl/GfxTexturesReporter.cpp
@@ -70,18 +70,19 @@ GetBitsPerTexel(GLenum format, GLenum ty
     }
 
     MOZ_ASSERT(false);
     return 0;
 }
 
 /* static */ void
 GfxTexturesReporter::UpdateAmount(MemoryUse action, GLenum format,
-                                  GLenum type, uint16_t tileSize)
+                                  GLenum type, int32_t tileWidth,
+                                  int32_t tileHeight)
 {
     int64_t bitsPerTexel = GetBitsPerTexel(format, type);
-    int64_t bytes = int64_t(tileSize) * int64_t(tileSize) * bitsPerTexel/8;
+    int64_t bytes = int64_t(tileWidth) * int64_t(tileHeight) * bitsPerTexel/8;
     if (action == MemoryFreed) {
         sAmount -= bytes;
     } else {
         sAmount += bytes;
     }
 }
--- a/gfx/gl/GfxTexturesReporter.h
+++ b/gfx/gl/GfxTexturesReporter.h
@@ -34,17 +34,17 @@ public:
         MemoryAllocated,
         // when memory being freed is reported to a memory reporter
         MemoryFreed
     };
 
     // When memory is used/freed for tile textures, call this method to update
     // the value reported by this memory reporter.
     static void UpdateAmount(MemoryUse action, GLenum format, GLenum type,
-                             uint16_t tileSize);
+                             int32_t tileWidth, int32_t tileHeight);
 
     NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
                               nsISupports* aData)
     {
         return MOZ_COLLECT_REPORT(
             "gfx-textures", KIND_OTHER, UNITS_BYTES, sAmount,
             "Memory used for storing GL textures.");
     }
--- a/gfx/layers/TiledLayerBuffer.h
+++ b/gfx/layers/TiledLayerBuffer.h
@@ -1,23 +1,22 @@
 /* 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/. */
 
 #ifndef GFX_TILEDLAYERBUFFER_H
 #define GFX_TILEDLAYERBUFFER_H
 
-#define TILEDLAYERBUFFER_TILE_SIZE 256
-
 // Debug defines
 //#define GFX_TILEDLAYER_DEBUG_OVERLAY
 //#define GFX_TILEDLAYER_PREF_WARNINGS
 
 #include <stdint.h>                     // for uint16_t, uint32_t
 #include <sys/types.h>                  // for int32_t
+#include "gfxPrefs.h"                   // for gfxPrefs::LayersTileWidth/Height
 #include "nsDebug.h"                    // for NS_ABORT_IF_FALSE
 #include "nsPoint.h"                    // for nsIntPoint
 #include "nsRect.h"                     // for nsIntRect
 #include "nsRegion.h"                   // for nsIntRegion
 #include "nsTArray.h"                   // for nsTArray
 
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
 #include <ui/Fence.h>
@@ -27,18 +26,18 @@ namespace mozilla {
 namespace layers {
 
 // An abstract implementation of a tile buffer. This code covers the logic of
 // moving and reusing tiles and leaves the validation up to the implementor. To
 // avoid the overhead of virtual dispatch, we employ the curiously recurring
 // template pattern.
 //
 // Tiles are aligned to a grid with one of the grid points at (0,0) and other
-// grid points spaced evenly in the x- and y-directions by GetTileLength()
-// multiplied by mResolution. GetScaledTileLength() provides convenience for
+// grid points spaced evenly in the x- and y-directions by GetTileSize()
+// multiplied by mResolution. GetScaledTileSize() provides convenience for
 // accessing these values.
 //
 // This tile buffer stores a valid region, which defines the areas that have
 // up-to-date content. The contents of tiles within this region will be reused
 // from paint to paint. It also stores the region that was modified in the last
 // paint operation; this is useful when one tiled layer buffer shadows another
 // (as in an off-main-thread-compositing scenario), so that the shadow tiled
 // layer buffer can correctly reflect the updates of the master layer buffer.
@@ -80,66 +79,64 @@ namespace layers {
 template<typename Derived, typename Tile>
 class TiledLayerBuffer
 {
 public:
   TiledLayerBuffer()
     : mRetainedWidth(0)
     , mRetainedHeight(0)
     , mResolution(1)
+    , mTileSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight())
   {}
 
   ~TiledLayerBuffer() {}
 
-  // Given a tile origin aligned to a multiple of GetScaledTileLength,
+  // Given a tile origin aligned to a multiple of GetScaledTileSize,
   // return the tile that describes that region.
   // NOTE: To get the valid area of that tile you must intersect
   //       (aTileOrigin.x, aTileOrigin.y,
-  //        GetScaledTileLength(), GetScaledTileLength())
+  //        GetScaledTileSize().width, GetScaledTileSize().height)
   //       and GetValidRegion() to get the area of the tile that is valid.
   Tile GetTile(const nsIntPoint& aTileOrigin) const;
 
   // Given a tile x, y relative to the top left of the layer, this function
   // will return the tile for
-  // (x*GetScaledTileLength(), y*GetScaledTileLength(),
-  //  GetScaledTileLength(), GetScaledTileLength())
+  // (x*GetScaledTileSize().width, y*GetScaledTileSize().height,
+  //  GetScaledTileSize().width, GetScaledTileSize().height)
   Tile GetTile(int x, int y) const;
 
   // This operates the same as GetTile(aTileOrigin), but will also replace the
   // specified tile with the placeholder tile. This does not call ReleaseTile
   // on the removed tile.
   bool RemoveTile(const nsIntPoint& aTileOrigin, Tile& aRemovedTile);
 
   // This operates the same as GetTile(x, y), but will also replace the
   // specified tile with the placeholder tile. This does not call ReleaseTile
   // on the removed tile.
   bool RemoveTile(int x, int y, Tile& aRemovedTile);
 
-  uint16_t GetTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE; }
+  const gfx::IntSize& GetTileSize() const { return mTileSize; }
 
-#ifdef MOZ_WIDGET_ANDROID
-  MOZ_NEVER_INLINE // bug 881018 causes wrong results when GetScaledTileLength is inlined
-#endif
-  uint32_t GetScaledTileLength() const { return TILEDLAYERBUFFER_TILE_SIZE / mResolution; }
+  gfx::IntSize GetScaledTileSize() const { return RoundedToInt(gfx::Size(mTileSize) / mResolution); }
 
   unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
 
   const nsIntRegion& GetValidRegion() const { return mValidRegion; }
   const nsIntRegion& GetPaintedRegion() const { return mPaintedRegion; }
   void ClearPaintedRegion() { mPaintedRegion.SetEmpty(); }
 
   // Given a position i, this function returns the position inside the current tile.
-  int GetTileStart(int i) const {
-    return (i >= 0) ? (i % GetScaledTileLength())
-                    : ((GetScaledTileLength() - (-i % GetScaledTileLength())) %
-                       GetScaledTileLength());
+  int GetTileStart(int i, int aTileLength) const {
+    return (i >= 0) ? (i % aTileLength)
+                    : ((aTileLength - (-i % aTileLength)) %
+                       aTileLength);
   }
 
   // Rounds the given coordinate down to the nearest tile boundary.
-  int RoundDownToTileEdge(int aX) const { return aX - GetTileStart(aX); }
+  int RoundDownToTileEdge(int aX, int aTileLength) const { return aX - GetTileStart(aX, aTileLength); }
 
   // Get and set draw scaling. mResolution affects the resolution at which the
   // contents of the buffer are drawn. mResolution has no effect on the
   // coordinate space of the valid region, but does affect the size of an
   // individual tile's rect in relation to the valid region.
   // Setting the resolution will invalidate the buffer.
   float GetResolution() const { return mResolution; }
   void SetResolution(float aResolution) {
@@ -173,16 +170,17 @@ protected:
    * Only the region intersecting with mValidRegion should be read from a tile,
    * another other region is assumed to be uninitialized. The contents of the
    * tiles is scaled by mResolution.
    */
   nsTArray<Tile>  mRetainedTiles;
   int             mRetainedWidth;  // in tiles
   int             mRetainedHeight; // in tiles
   float           mResolution;
+  gfx::IntSize    mTileSize;
 
 private:
   const Derived& AsDerived() const { return *static_cast<const Derived*>(this); }
   Derived& AsDerived() { return *static_cast<Derived*>(this); }
 
   bool IsPlaceholder(Tile aTile) const { return aTile == AsDerived().GetPlaceholderTile(); }
 };
 
@@ -239,37 +237,39 @@ static inline int floor_div(int a, int b
 }
 
 template<typename Derived, typename Tile> Tile
 TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin) const
 {
   // TODO Cache firstTileOriginX/firstTileOriginY
   // Find the tile x/y of the first tile and the target tile relative to the (0, 0)
   // origin, the difference is the tile x/y relative to the start of the tile buffer.
-  int firstTileX = floor_div(mValidRegion.GetBounds().x, GetScaledTileLength());
-  int firstTileY = floor_div(mValidRegion.GetBounds().y, GetScaledTileLength());
-  return GetTile(floor_div(aTileOrigin.x, GetScaledTileLength()) - firstTileX,
-                 floor_div(aTileOrigin.y, GetScaledTileLength()) - firstTileY);
+  gfx::IntSize scaledTileSize = GetScaledTileSize();
+  int firstTileX = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
+  int firstTileY = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
+  return GetTile(floor_div(aTileOrigin.x, scaledTileSize.width) - firstTileX,
+                 floor_div(aTileOrigin.y, scaledTileSize.height) - firstTileY);
 }
 
 template<typename Derived, typename Tile> Tile
 TiledLayerBuffer<Derived, Tile>::GetTile(int x, int y) const
 {
   int index = x * mRetainedHeight + y;
   return mRetainedTiles.SafeElementAt(index, AsDerived().GetPlaceholderTile());
 }
 
 template<typename Derived, typename Tile> bool
 TiledLayerBuffer<Derived, Tile>::RemoveTile(const nsIntPoint& aTileOrigin,
                                             Tile& aRemovedTile)
 {
-  int firstTileX = floor_div(mValidRegion.GetBounds().x, GetScaledTileLength());
-  int firstTileY = floor_div(mValidRegion.GetBounds().y, GetScaledTileLength());
-  return RemoveTile(floor_div(aTileOrigin.x, GetScaledTileLength()) - firstTileX,
-                    floor_div(aTileOrigin.y, GetScaledTileLength()) - firstTileY,
+  gfx::IntSize scaledTileSize = GetScaledTileSize();
+  int firstTileX = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
+  int firstTileY = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
+  return RemoveTile(floor_div(aTileOrigin.x, scaledTileSize.width) - firstTileX,
+                    floor_div(aTileOrigin.y, scaledTileSize.height) - firstTileY,
                     aRemovedTile);
 }
 
 template<typename Derived, typename Tile> bool
 TiledLayerBuffer<Derived, Tile>::RemoveTile(int x, int y, Tile& aRemovedTile)
 {
   int index = x * mRetainedHeight + y;
   const Tile& tileToRemove = mRetainedTiles.SafeElementAt(index, AsDerived().GetPlaceholderTile());
@@ -280,59 +280,61 @@ TiledLayerBuffer<Derived, Tile>::RemoveT
   }
   return false;
 }
 
 template<typename Derived, typename Tile> void
 TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& aNewValidRegion,
                                         const nsIntRegion& aPaintRegion)
 {
+  gfx::IntSize scaledTileSize = GetScaledTileSize();
+
   nsTArray<Tile>  newRetainedTiles;
   nsTArray<Tile>& oldRetainedTiles = mRetainedTiles;
   const nsIntRect oldBound = mValidRegion.GetBounds();
   const nsIntRect newBound = aNewValidRegion.GetBounds();
-  const nsIntPoint oldBufferOrigin(RoundDownToTileEdge(oldBound.x),
-                                   RoundDownToTileEdge(oldBound.y));
-  const nsIntPoint newBufferOrigin(RoundDownToTileEdge(newBound.x),
-                                   RoundDownToTileEdge(newBound.y));
+  const nsIntPoint oldBufferOrigin(RoundDownToTileEdge(oldBound.x, scaledTileSize.width),
+                                   RoundDownToTileEdge(oldBound.y, scaledTileSize.height));
+  const nsIntPoint newBufferOrigin(RoundDownToTileEdge(newBound.x, scaledTileSize.width),
+                                   RoundDownToTileEdge(newBound.y, scaledTileSize.height));
   const nsIntRegion& oldValidRegion = mValidRegion;
   const nsIntRegion& newValidRegion = aNewValidRegion;
   const int oldRetainedHeight = mRetainedHeight;
 
   // Pass 1: Recycle valid content from the old buffer
   // Recycle tiles from the old buffer that contain valid regions.
   // Insert placeholders tiles if we have no valid area for that tile
   // which we will allocate in pass 2.
   // TODO: Add a tile pool to reduce new allocation
   int tileX = 0;
   int tileY = 0;
   int tilesMissing = 0;
   // Iterate over the new drawing bounds in steps of tiles.
   for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
     // Compute tileRect(x,y,width,height) in layer space coordinate
     // giving us the rect of the tile that hits the newBounds.
-    int width = GetScaledTileLength() - GetTileStart(x);
+    int width = scaledTileSize.width - GetTileStart(x, scaledTileSize.width);
     if (x + width > newBound.XMost()) {
       width = newBound.x + newBound.width - x;
     }
 
     tileY = 0;
     for (int32_t y = newBound.y; y < newBound.YMost(); tileY++) {
-      int height = GetScaledTileLength() - GetTileStart(y);
+      int height = scaledTileSize.height - GetTileStart(y, scaledTileSize.height);
       if (y + height > newBound.y + newBound.height) {
         height = newBound.y + newBound.height - y;
       }
 
       const nsIntRect tileRect(x,y,width,height);
       if (oldValidRegion.Intersects(tileRect) && newValidRegion.Intersects(tileRect)) {
         // This old tiles contains some valid area so move it to the new tile
         // buffer. Replace the tile in the old buffer with a placeholder
         // to leave the old buffer index unaffected.
-        int tileX = floor_div(x - oldBufferOrigin.x, GetScaledTileLength());
-        int tileY = floor_div(y - oldBufferOrigin.y, GetScaledTileLength());
+        int tileX = floor_div(x - oldBufferOrigin.x, scaledTileSize.width);
+        int tileY = floor_div(y - oldBufferOrigin.y, scaledTileSize.height);
         int index = tileX * oldRetainedHeight + tileY;
 
         // The tile may have been removed, skip over it in this case.
         if (IsPlaceholder(oldRetainedTiles.
                           SafeElementAt(index, AsDerived().GetPlaceholderTile()))) {
           newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
         } else {
           Tile tileWithPartialValidContent = oldRetainedTiles[index];
@@ -404,53 +406,53 @@ TiledLayerBuffer<Derived, Tile>::Update(
   // allocated.
   tileX = 0;
 #ifdef GFX_TILEDLAYER_PREF_WARNINGS
   printf_stderr("Update %i, %i, %i, %i\n", newBound.x, newBound.y, newBound.width, newBound.height);
 #endif
   for (int x = newBound.x; x < newBound.x + newBound.width; tileX++) {
     // Compute tileRect(x,y,width,height) in layer space coordinate
     // giving us the rect of the tile that hits the newBounds.
-    int tileStartX = RoundDownToTileEdge(x);
-    int width = GetScaledTileLength() - GetTileStart(x);
+    int tileStartX = RoundDownToTileEdge(x, scaledTileSize.width);
+    int width = scaledTileSize.width - GetTileStart(x, scaledTileSize.width);
     if (x + width > newBound.XMost())
       width = newBound.XMost() - x;
 
     tileY = 0;
     for (int y = newBound.y; y < newBound.y + newBound.height; tileY++) {
-      int tileStartY = RoundDownToTileEdge(y);
-      int height = GetScaledTileLength() - GetTileStart(y);
+      int tileStartY = RoundDownToTileEdge(y, scaledTileSize.height);
+      int height = scaledTileSize.height - GetTileStart(y, scaledTileSize.height);
       if (y + height > newBound.YMost()) {
         height = newBound.YMost() - y;
       }
 
       const nsIntRect tileRect(x, y, width, height);
 
       nsIntRegion tileDrawRegion;
       tileDrawRegion.And(tileRect, regionToPaint);
 
       if (tileDrawRegion.IsEmpty()) {
         // We have a tile but it doesn't hit the draw region
         // because we can reuse all of the content from the
         // previous buffer.
 #ifdef DEBUG
-        int currTileX = floor_div(x - newBufferOrigin.x, GetScaledTileLength());
-        int currTileY = floor_div(y - newBufferOrigin.y, GetScaledTileLength());
+        int currTileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
+        int currTileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
         int index = currTileX * mRetainedHeight + currTileY;
         NS_ABORT_IF_FALSE(!newValidRegion.Intersects(tileRect) ||
                           !IsPlaceholder(newRetainedTiles.
                                          SafeElementAt(index, AsDerived().GetPlaceholderTile())),
                           "If we don't draw a tile we shouldn't have a placeholder there.");
 #endif
         y += height;
         continue;
       }
 
-      int tileX = floor_div(x - newBufferOrigin.x, GetScaledTileLength());
-      int tileY = floor_div(y - newBufferOrigin.y, GetScaledTileLength());
+      int tileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
+      int tileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
       int index = tileX * mRetainedHeight + tileY;
       NS_ABORT_IF_FALSE(index >= 0 &&
                         static_cast<unsigned>(index) < newRetainedTiles.Length(),
                         "index out of range");
 
       Tile newTile = newRetainedTiles[index];
 
       // Try to reuse a tile from the old retained tiles that had no partially
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -2,16 +2,17 @@
  * 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/. */
 
 #include "ClientLayerManager.h"
 #include "CompositorChild.h"            // for CompositorChild
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "gfxASurface.h"                // for gfxASurface, etc
+#include "gfxPrefs.h"                   // for gfxPrefs::LayersTileWidth/Height
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT, etc
 #include "mozilla/Hal.h"
 #include "mozilla/dom/ScreenOrientation.h"  // for ScreenOrientation
 #include "mozilla/dom/TabChild.h"       // for TabChild
 #include "mozilla/hal_sandbox/PHal.h"   // for ScreenConfiguration
 #include "mozilla/layers/CompositableClient.h"  // for CompositableChild, etc
 #include "mozilla/layers/ContentClient.h"  // for ContentClientRemote
 #include "mozilla/layers/ISurfaceAllocator.h"
@@ -451,32 +452,32 @@ ClientLayerManager::GetTexturePool(Surfa
 {
   for (size_t i = 0; i < mTexturePools.Length(); i++) {
     if (mTexturePools[i]->GetFormat() == aFormat) {
       return mTexturePools[i];
     }
   }
 
   mTexturePools.AppendElement(
-      new TextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE,
-                                             TILEDLAYERBUFFER_TILE_SIZE),
+      new TextureClientPool(aFormat, IntSize(gfxPrefs::LayersTileWidth(),
+                                             gfxPrefs::LayersTileHeight()),
                             mForwarder));
 
   return mTexturePools.LastElement();
 }
 
 SimpleTextureClientPool*
 ClientLayerManager::GetSimpleTileTexturePool(SurfaceFormat aFormat)
 {
   int index = (int) aFormat;
   mSimpleTilePools.EnsureLengthAtLeast(index+1);
 
   if (mSimpleTilePools[index].get() == nullptr) {
-    mSimpleTilePools[index] = new SimpleTextureClientPool(aFormat, IntSize(TILEDLAYERBUFFER_TILE_SIZE,
-                                                                           TILEDLAYERBUFFER_TILE_SIZE),
+    mSimpleTilePools[index] = new SimpleTextureClientPool(aFormat, IntSize(gfxPrefs::LayersTileWidth(),
+                                                                           gfxPrefs::LayersTileHeight()),
                                                           mForwarder);
   }
 
   return mSimpleTilePools[index];
 }
 
 void
 ClientLayerManager::ClearCachedResources(Layer* aSubtree)
--- a/gfx/layers/client/SimpleTiledContentClient.cpp
+++ b/gfx/layers/client/SimpleTiledContentClient.cpp
@@ -9,16 +9,17 @@
 #include "ClientTiledThebesLayer.h"     // for ClientTiledThebesLayer
 #include "GeckoProfiler.h"              // for PROFILER_LABEL
 #include "Units.h"                      // for ScreenIntRect, CSSPoint, etc
 #include "UnitTransforms.h"             // for TransformTo
 #include "ClientLayerManager.h"         // for ClientLayerManager
 #include "CompositorChild.h"            // for CompositorChild
 #include "gfxContext.h"                 // for gfxContext, etc
 #include "gfxPlatform.h"                // for gfxPlatform
+#include "gfxPrefs.h"                   // for gfxPrefs::LayersTileWidth/Height
 #include "gfxRect.h"                    // for gfxRect
 #include "mozilla/Attributes.h"         // for MOZ_THIS_IN_INITIALIZER_LIST
 #include "mozilla/MathAlgorithms.h"     // for Abs
 #include "mozilla/gfx/Point.h"          // for IntSize
 #include "mozilla/gfx/Rect.h"           // for Rect
 #include "mozilla/layers/CompositableForwarder.h"
 #include "mozilla/layers/ShadowLayers.h"  // for ShadowLayerForwarder
 #include "SimpleTextureClientPool.h"
@@ -69,17 +70,17 @@ SimpleTiledLayerBuffer::PaintThebes(cons
 }
 
 SimpleTiledLayerTile
 SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile,
                                      const nsIntPoint& aTileOrigin,
                                      const nsIntRegion& aDirtyRegion)
 {
   PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile");
-  static gfx::IntSize kTileSize(TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
+  static gfx::IntSize kTileSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight());
 
   gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType());
 
   // if this is true, we're using a separate buffer to do our drawing first
   bool doBufferedDrawing = true;
   bool fullPaint = false;
 
   RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle();
@@ -124,17 +125,17 @@ SimpleTiledLayerBuffer::ValidateTile(Sim
       bufferData = (unsigned char*) aTile.mCachedBuffer->Data();
 
       drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData,
                                                                        kTileSize,
                                                                        bufferStride,
                                                                        tileFormat);
 
       if (fullPaint) {
-        drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength());
+        drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
         drawRegion = nsIntRegion(drawBounds);
       } else {
         drawBounds = aDirtyRegion.GetBounds();
         drawRegion = nsIntRegion(drawBounds);
         if (GetContentType() == gfxContentType::COLOR_ALPHA)
           drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y,
                                      drawBounds.width, drawBounds.height));
       }
@@ -144,17 +145,17 @@ SimpleTiledLayerBuffer::ValidateTile(Sim
     }
   }
 
   // this might get set above if we couldn't extract out a buffer
   if (!doBufferedDrawing) {
     drawTarget = textureClient->AsTextureClientDrawTarget()->GetAsDrawTarget();
 
     fullPaint = true;
-    drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileLength(), GetScaledTileLength());
+    drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
     drawRegion = nsIntRegion(drawBounds);
 
     if (GetContentType() == gfxContentType::COLOR_ALPHA)
       drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height));
   }
 
   // do the drawing
   RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);
--- a/gfx/layers/client/TiledContentClient.cpp
+++ b/gfx/layers/client/TiledContentClient.cpp
@@ -24,17 +24,17 @@
 #include "nsSize.h"                     // for nsIntSize
 #include "gfxReusableSharedImageSurfaceWrapper.h"
 #include "nsMathUtils.h"               // for NS_roundf
 #include "gfx2DGlue.h"
 
 // This is the minimum area that we deem reasonable to copy from the front buffer to the
 // back buffer on tile updates. If the valid region is smaller than this, we just
 // redraw it and save on the copy (and requisite surface-locking involved).
-#define MINIMUM_TILE_COPY_AREA ((TILEDLAYERBUFFER_TILE_SIZE * TILEDLAYERBUFFER_TILE_SIZE)/16)
+#define MINIMUM_TILE_COPY_AREA (1.f/16.f)
 
 #ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
 #include "cairo.h"
 #include <sstream>
 using mozilla::layers::Layer;
 static void DrawDebugOverlay(mozilla::gfx::DrawTarget* dt, int x, int y, int width, int height)
 {
   gfxContext c(dt);
@@ -418,31 +418,32 @@ TileClient::Flip()
   mInvalidBack = invalidFront;
 }
 
 void
 TileClient::ValidateBackBufferFromFront(const nsIntRegion& aDirtyRegion,
                                         bool aCanRerasterizeValidRegion)
 {
   if (mBackBuffer && mFrontBuffer) {
-    const nsIntRect tileRect = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
+    gfx::IntSize tileSize = mFrontBuffer->GetSize();
+    const nsIntRect tileRect = nsIntRect(0, 0, tileSize.width, tileSize.height);
 
     if (aDirtyRegion.Contains(tileRect)) {
       // The dirty region means that we no longer need the front buffer, so
       // discard it.
       DiscardFrontBuffer();
     } else {
       // Region that needs copying.
       nsIntRegion regionToCopy = mInvalidBack;
 
       regionToCopy.Sub(regionToCopy, aDirtyRegion);
 
       if (regionToCopy.IsEmpty() ||
           (aCanRerasterizeValidRegion &&
-           regionToCopy.Area() < MINIMUM_TILE_COPY_AREA)) {
+           regionToCopy.Area() < tileSize.width * tileSize.height * MINIMUM_TILE_COPY_AREA)) {
         // Just redraw it all.
         return;
       }
 
       if (!mFrontBuffer->Lock(OPEN_READ)) {
         NS_WARNING("Failed to lock the tile's front buffer");
         return;
       }
@@ -521,17 +522,17 @@ TileClient::GetBackBuffer(const nsIntReg
       mBackLock = new gfxMemorySharedReadLock();
     } else {
       mBackLock = new gfxShmSharedReadLock(mManager->AsShadowForwarder());
     }
 
     MOZ_ASSERT(mBackLock->IsValid());
 
     *aCreatedTextureClient = true;
-    mInvalidBack = nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE);
+    mInvalidBack = nsIntRect(0, 0, mBackBuffer->GetSize().width, mBackBuffer->GetSize().height);
   }
 
   ValidateBackBufferFromFront(aDirtyRegion, aCanRerasterizeValidRegion);
 
   return mBackBuffer;
 }
 
 TileDescriptor
@@ -777,23 +778,23 @@ ClientTiledLayerBuffer::ValidateTile(Til
       gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
       drawTarget->CopySurface(source, copyRect, copyTarget);
 
       // Mark the newly updated area as invalid in the front buffer
       aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
     }
 
     // The new buffer is now validated, remove the dirty region from it.
-    aTile.mInvalidBack.Sub(nsIntRect(0, 0, TILEDLAYERBUFFER_TILE_SIZE, TILEDLAYERBUFFER_TILE_SIZE),
+    aTile.mInvalidBack.Sub(nsIntRect(0, 0, GetTileSize().width, GetTileSize().height),
                            offsetScaledDirtyRegion);
   } else {
     // Area of the full tile...
     nsIntRegion tileRegion =
       nsIntRect(aTileOrigin.x, aTileOrigin.y,
-                GetScaledTileLength(), GetScaledTileLength());
+                GetScaledTileSize().width, GetScaledTileSize().height);
 
     // Intersect this area with the portion that's dirty.
     tileRegion = tileRegion.Intersect(aDirtyRegion);
 
     // Add the resolution scale to store the dirty region.
     nsIntPoint unscaledTileOrigin = nsIntPoint(aTileOrigin.x * mResolution,
                                                aTileOrigin.y * mResolution);
     nsIntRegion unscaledTileRegion(tileRegion);
@@ -992,35 +993,35 @@ ClientTiledLayerBuffer::ComputeProgressi
   bool paintInSingleTransaction = paintVisible && (drawingStale || aPaintData->mFirstPaint);
 
   // The following code decides what order to draw tiles in, based on the
   // current scroll direction of the primary scrollable layer.
   NS_ASSERTION(!aRegionToPaint.IsEmpty(), "Unexpectedly empty paint region!");
   nsIntRect paintBounds = aRegionToPaint.GetBounds();
 
   int startX, incX, startY, incY;
-  int tileLength = GetScaledTileLength();
+  gfx::IntSize scaledTileSize = GetScaledTileSize();
   if (aPaintData->mScrollOffset.x >= aPaintData->mLastScrollOffset.x) {
-    startX = RoundDownToTileEdge(paintBounds.x);
-    incX = tileLength;
+    startX = RoundDownToTileEdge(paintBounds.x, scaledTileSize.width);
+    incX = scaledTileSize.width;
   } else {
-    startX = RoundDownToTileEdge(paintBounds.XMost() - 1);
-    incX = -tileLength;
+    startX = RoundDownToTileEdge(paintBounds.XMost() - 1, scaledTileSize.width);
+    incX = -scaledTileSize.width;
   }
 
   if (aPaintData->mScrollOffset.y >= aPaintData->mLastScrollOffset.y) {
-    startY = RoundDownToTileEdge(paintBounds.y);
-    incY = tileLength;
+    startY = RoundDownToTileEdge(paintBounds.y, scaledTileSize.height);
+    incY = scaledTileSize.height;
   } else {
-    startY = RoundDownToTileEdge(paintBounds.YMost() - 1);
-    incY = -tileLength;
+    startY = RoundDownToTileEdge(paintBounds.YMost() - 1, scaledTileSize.height);
+    incY = -scaledTileSize.height;
   }
 
   // Find a tile to draw.
-  nsIntRect tileBounds(startX, startY, tileLength, tileLength);
+  nsIntRect tileBounds(startX, startY, scaledTileSize.width, scaledTileSize.height);
   int32_t scrollDiffX = aPaintData->mScrollOffset.x - aPaintData->mLastScrollOffset.x;
   int32_t scrollDiffY = aPaintData->mScrollOffset.y - aPaintData->mLastScrollOffset.y;
   // This loop will always terminate, as there is at least one tile area
   // along the first/last row/column intersecting with regionToPaint, or its
   // bounds would have been smaller.
   while (true) {
     aRegionToPaint.And(aInvalidRegion, tileBounds);
     if (!aRegionToPaint.IsEmpty()) {
--- a/gfx/layers/composite/TiledContentHost.cpp
+++ b/gfx/layers/composite/TiledContentHost.cpp
@@ -424,47 +424,48 @@ TiledContentHost::RenderLayerBuffer(Tile
   // Make sure the resolution and difference in frame resolution are accounted
   // for in the layer transform.
   aTransform.Scale(1/(resolution * layerScale.width),
                    1/(resolution * layerScale.height), 1);
 
   uint32_t rowCount = 0;
   uint32_t tileX = 0;
   nsIntRect visibleRect = aVisibleRegion.GetBounds();
+  gfx::IntSize scaledTileSize = aLayerBuffer.GetScaledTileSize();
   for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
     rowCount++;
-    int32_t tileStartX = aLayerBuffer.GetTileStart(x);
-    int32_t w = aLayerBuffer.GetScaledTileLength() - tileStartX;
+    int32_t tileStartX = aLayerBuffer.GetTileStart(x, scaledTileSize.width);
+    int32_t w = scaledTileSize.width - tileStartX;
     if (x + w > visibleRect.x + visibleRect.width) {
       w = visibleRect.x + visibleRect.width - x;
     }
     int tileY = 0;
     for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
-      int32_t tileStartY = aLayerBuffer.GetTileStart(y);
-      int32_t h = aLayerBuffer.GetScaledTileLength() - tileStartY;
+      int32_t tileStartY = aLayerBuffer.GetTileStart(y, scaledTileSize.height);
+      int32_t h = scaledTileSize.height - tileStartY;
       if (y + h > visibleRect.y + visibleRect.height) {
         h = visibleRect.y + visibleRect.height - y;
       }
 
       TileHost tileTexture = aLayerBuffer.
-        GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x),
-                           aLayerBuffer.RoundDownToTileEdge(y)));
+        GetTile(nsIntPoint(aLayerBuffer.RoundDownToTileEdge(x, scaledTileSize.width),
+                           aLayerBuffer.RoundDownToTileEdge(y, scaledTileSize.height)));
       if (tileTexture != aLayerBuffer.GetPlaceholderTile()) {
         nsIntRegion tileDrawRegion;
         tileDrawRegion.And(nsIntRect(x, y, w, h), aLayerBuffer.GetValidRegion());
         tileDrawRegion.And(tileDrawRegion, aVisibleRegion);
         tileDrawRegion.Sub(tileDrawRegion, maskRegion);
 
         if (!tileDrawRegion.IsEmpty()) {
           tileDrawRegion.ScaleRoundOut(resolution, resolution);
           nsIntPoint tileOffset((x - tileStartX) * resolution,
                                 (y - tileStartY) * resolution);
-          uint32_t tileSize = aLayerBuffer.GetTileLength();
+          gfx::IntSize tileSize = aLayerBuffer.GetTileSize();
           RenderTile(tileTexture, aEffectChain, aOpacity, aTransform, aFilter, aClipRect, tileDrawRegion,
-                     tileOffset, nsIntSize(tileSize, tileSize));
+                     tileOffset, nsIntSize(tileSize.width, tileSize.height));
         }
       }
       tileY++;
       y += h;
     }
     tileX++;
     x += w;
   }
--- a/gfx/layers/opengl/TextureHostOGL.cpp
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -8,17 +8,16 @@
 #include "GLSharedHandleHelpers.h"
 #include "GLUploadHelpers.h"
 #include "GLReadTexImageHelper.h"
 #include "SharedSurface.h"              // for SharedSurface
 #include "SharedSurfaceEGL.h"           // for SharedSurface_EGLImage
 #include "SharedSurfaceGL.h"            // for SharedSurface_GLTexture, etc
 #include "SurfaceStream.h"              // for SurfaceStream
 #include "SurfaceTypes.h"               // for SharedSurfaceType, etc
-#include "TiledLayerBuffer.h"           // for TILEDLAYERBUFFER_TILE_SIZE
 #include "gfx2DGlue.h"                  // for ContentForFormat, etc
 #include "gfxImageSurface.h"            // for gfxImageSurface
 #include "gfxReusableSurfaceWrapper.h"  // for gfxReusableSurfaceWrapper
 #include "mozilla/gfx/2D.h"             // for DataSourceSurface
 #include "mozilla/gfx/BaseSize.h"       // for BaseSize
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #ifdef MOZ_WIDGET_GONK
 # include "GrallocImages.h"  // for GrallocImage
--- a/gfx/tests/gtest/TestTiledLayerBuffer.cpp
+++ b/gfx/tests/gtest/TestTiledLayerBuffer.cpp
@@ -56,18 +56,18 @@ public:
 
 TEST(TiledLayerBuffer, TileConstructor) {
   TestTiledLayerBuffer buffer;
 }
 
 TEST(TiledLayerBuffer, TileStart) {
   TestTiledLayerBuffer buffer;
 
-  ASSERT_EQ(buffer.RoundDownToTileEdge(10), 0);
-  ASSERT_EQ(buffer.RoundDownToTileEdge(-10), -256);
+  ASSERT_EQ(buffer.RoundDownToTileEdge(10, 256), 0);
+  ASSERT_EQ(buffer.RoundDownToTileEdge(-10, 256), -256);
 }
 
 TEST(TiledLayerBuffer, EmptyUpdate) {
   TestTiledLayerBuffer buffer;
 
   nsIntRegion validRegion(nsIntRect(0, 0, 10, 10));
   buffer.TestUpdate(validRegion, validRegion);
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -174,16 +174,21 @@ private:
   DECL_GFX_PREF(Live, "layers.draw-borders",                   DrawLayerBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-tile-borders",              DrawTileBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.flash-borders",                  FlashLayerBorders, bool, false);
   DECL_GFX_PREF(Live, "layers.draw-layer-info",                DrawLayerInfo, bool, false);
   DECL_GFX_PREF(Once, "layers.dump",                           LayersDump, bool, false);
   DECL_GFX_PREF(Once, "layers.enable-tiles",                   LayersTilesEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.simple-tiles",                   LayersUseSimpleTiles, bool, false);
   DECL_GFX_PREF(Once, "layers.force-per-tile-drawing",         PerTileDrawing, bool, false);
+  // We allow for configurable and rectangular tile size to avoid wasting memory on devices whose
+  // screen size does not align nicely to the default tile size. Although layers can be any size,
+  // they are often the same size as the screen, especially for width.
+  DECL_GFX_PREF(Once, "layers.tile-width",                     LayersTileWidth, int32_t, 256);
+  DECL_GFX_PREF(Once, "layers.tile-height",                    LayersTileHeight, int32_t, 256);
   DECL_GFX_PREF(Once, "layers.overzealous-gralloc-unlocking",  OverzealousGrallocUnlocking, bool, false);
   DECL_GFX_PREF(Once, "layers.force-shmem-tiles",              ForceShmemTiles, bool, false);
   DECL_GFX_PREF(Live, "layers.frame-counter",                  DrawFrameCounter, bool, false);
   DECL_GFX_PREF(Live, "layers.low-precision-buffer",           UseLowPrecisionBuffer, bool, false);
   DECL_GFX_PREF(Live, "layers.low-precision-resolution",       LowPrecisionResolution, int32_t, 250);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.enabled", LayersOffMainThreadCompositionEnabled, bool, false);
   DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
   DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-enabled", LayersOffMainThreadCompositionForceEnabled, bool, false);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -720,36 +720,36 @@ nsLayoutUtils::GetDisplayPort(nsIContent
         rect.height =
           parentRes.height * NSAppUnitsToFloatPixels(base.height, auPerDevPixel);
 
         rect.Inflate(marginsData->mMargins);
 
         nsIScrollableFrame* scrollableFrame = frame->GetScrollTargetFrame();
         nsPoint scrollPos(
           scrollableFrame ? scrollableFrame->GetScrollPosition() : nsPoint(0,0));
-        if (marginsData->mAlignment > 0) {
+        if (marginsData->mAlignmentX > 0 || marginsData->mAlignmentY > 0) {
           LayerPoint scrollPosLayer(
             res.width * NSAppUnitsToFloatPixels(scrollPos.x, auPerDevPixel),
             res.height * NSAppUnitsToFloatPixels(scrollPos.y, auPerDevPixel));
           rect += scrollPosLayer;
 
           // Inflate the rectangle by 1 so that we always push to the next tile
           // boundary. This is desirable to stop from having a rectangle with a
           // moving origin occasionally being smaller when it coincidentally lines
           // up to tile boundaries.
           rect.Inflate(1);
 
           float left =
-            marginsData->mAlignment * floor(rect.x / marginsData->mAlignment);
+            marginsData->mAlignmentX * floor(rect.x / marginsData->mAlignmentX);
           float top =
-            marginsData->mAlignment * floor(rect.y / marginsData->mAlignment);
+            marginsData->mAlignmentY * floor(rect.y / marginsData->mAlignmentY);
           float right =
-            marginsData->mAlignment * ceil(rect.XMost() / marginsData->mAlignment);
+            marginsData->mAlignmentX * ceil(rect.XMost() / marginsData->mAlignmentX);
           float bottom =
-            marginsData->mAlignment * ceil(rect.YMost() / marginsData->mAlignment);
+            marginsData->mAlignmentY * ceil(rect.YMost() / marginsData->mAlignmentY);
           rect = LayerRect(left, top, right - left, bottom - top);
           rect -= scrollPosLayer;
         }
 
         nsRect result;
         result.x = NSFloatPixelsToAppUnits(rect.x / res.width, auPerDevPixel);
         result.y = NSFloatPixelsToAppUnits(rect.y / res.height, auPerDevPixel);
         result.width =
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -82,23 +82,26 @@ struct DisplayPortPropertyData {
     , mPriority(aPriority)
   {}
   nsRect mRect;
   uint32_t mPriority;
 };
 
 struct DisplayPortMarginsPropertyData {
   DisplayPortMarginsPropertyData(const LayerMargin& aMargins,
-                                 uint32_t aAlignment, uint32_t aPriority)
+                                 uint32_t aAlignmentX, uint32_t aAlignmentY,
+                                 uint32_t aPriority)
     : mMargins(aMargins)
-    , mAlignment(aAlignment)
+    , mAlignmentX(aAlignmentX)
+    , mAlignmentY(aAlignmentY)
     , mPriority(aPriority)
   {}
   LayerMargin mMargins;
-  uint32_t mAlignment;
+  uint32_t mAlignmentX;
+  uint32_t mAlignmentY;
   uint32_t mPriority;
 };
 
 template <class AnimationsOrTransitions>
 extern AnimationsOrTransitions* HasAnimationOrTransition(nsIContent* aContent,
                                                          nsIAtom* aAnimationProperty,
                                                          nsCSSProperty aProperty);
 
--- a/widget/xpwidgets/APZCCallbackHelper.cpp
+++ b/widget/xpwidgets/APZCCallbackHelper.cpp
@@ -1,21 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/. */
 
 #include "APZCCallbackHelper.h"
-#include "gfxPrefs.h" // For gfxPrefs::LayersTilesEnabled
+#include "gfxPrefs.h" // For gfxPrefs::LayersTilesEnabled, LayersTileWidth/Height
 #include "mozilla/Preferences.h"
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIInterfaceRequestorUtils.h"
-#include "TiledLayerBuffer.h" // For TILEDLAYERBUFFER_TILE_SIZE
 
 namespace mozilla {
 namespace widget {
 
 bool
 APZCCallbackHelper::HasValidPresShellId(nsIDOMWindowUtils* aUtils,
                                         const FrameMetrics& aMetrics)
 {
@@ -41,24 +40,22 @@ static CSSRect ExpandDisplayPortToTileBo
 
   // Inflate the rectangle by 1 so that we always push to the next tile
   // boundary. This is desirable to stop from having a rectangle with a
   // moving origin occasionally being smaller when it coincidentally lines
   // up to tile boundaries.
   displayPortInLayerSpace.Inflate(1);
 
   // Now nudge the rectangle to the nearest equal or larger tile boundary.
-  gfxFloat left = TILEDLAYERBUFFER_TILE_SIZE
-    * floor(displayPortInLayerSpace.x / TILEDLAYERBUFFER_TILE_SIZE);
-  gfxFloat top = TILEDLAYERBUFFER_TILE_SIZE
-    * floor(displayPortInLayerSpace.y / TILEDLAYERBUFFER_TILE_SIZE);
-  gfxFloat right = TILEDLAYERBUFFER_TILE_SIZE
-    * ceil(displayPortInLayerSpace.XMost() / TILEDLAYERBUFFER_TILE_SIZE);
-  gfxFloat bottom = TILEDLAYERBUFFER_TILE_SIZE
-    * ceil(displayPortInLayerSpace.YMost() / TILEDLAYERBUFFER_TILE_SIZE);
+  int32_t tileWidth = gfxPrefs::LayersTileWidth();
+  int32_t tileHeight = gfxPrefs::LayersTileHeight();
+  gfxFloat left = tileWidth * floor(displayPortInLayerSpace.x / tileWidth);
+  gfxFloat right = tileWidth * ceil(displayPortInLayerSpace.XMost() / tileWidth);
+  gfxFloat top = tileHeight * floor(displayPortInLayerSpace.y / tileHeight);
+  gfxFloat bottom = tileHeight * ceil(displayPortInLayerSpace.YMost() / tileHeight);
 
   displayPortInLayerSpace = LayerRect(left, top, right - left, bottom - top);
   CSSRect displayPort = displayPortInLayerSpace / aLayerPixelsPerCSSPixel;
 
   return displayPort;
 }
 
 static void
@@ -226,24 +223,26 @@ APZCCallbackHelper::UpdateRootFrame(nsID
     }
     if (!aMetrics.GetUseDisplayPortMargins()) {
         aUtils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
                                          aMetrics.mDisplayPort.y,
                                          aMetrics.mDisplayPort.width,
                                          aMetrics.mDisplayPort.height,
                                          element, 0);
     } else {
-        uint32_t alignment = gfxPrefs::LayersTilesEnabled()
-            ? TILEDLAYERBUFFER_TILE_SIZE : 1;
+        gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled()
+            ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) :
+              gfx::IntSize(1, 1);
         LayerMargin margins = aMetrics.GetDisplayPortMargins();
         aUtils->SetDisplayPortMarginsForElement(margins.left,
                                                 margins.top,
                                                 margins.right,
                                                 margins.bottom,
-                                                alignment,
+                                                alignment.width,
+                                                alignment.height,
                                                 element, 0);
         CSSRect baseCSS = aMetrics.mCompositionBounds / aMetrics.GetZoomToParent();
         nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(),
                     baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(),
                     baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
                     baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
         nsLayoutUtils::SetDisplayPortBase(content, base);
     }
@@ -279,24 +278,26 @@ APZCCallbackHelper::UpdateSubFrame(nsICo
         MaybeAlignAndClampDisplayPort(aMetrics, actualScrollOffset);
         if (!aMetrics.GetUseDisplayPortMargins()) {
             utils->SetDisplayPortForElement(aMetrics.mDisplayPort.x,
                                             aMetrics.mDisplayPort.y,
                                             aMetrics.mDisplayPort.width,
                                             aMetrics.mDisplayPort.height,
                                             element, 0);
         } else {
-            uint32_t alignment = gfxPrefs::LayersTilesEnabled()
-                ? TILEDLAYERBUFFER_TILE_SIZE : 1;
+            gfx::IntSize alignment = gfxPrefs::LayersTilesEnabled()
+                ? gfx::IntSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight()) :
+                  gfx::IntSize(1, 1);
             LayerMargin margins = aMetrics.GetDisplayPortMargins();
             utils->SetDisplayPortMarginsForElement(margins.left,
                                                    margins.top,
                                                    margins.right,
                                                    margins.bottom,
-                                                   alignment,
+                                                   alignment.width,
+                                                   alignment.height,
                                                    element, 0);
             CSSRect baseCSS = aMetrics.mCompositionBounds / aMetrics.GetZoomToParent();
             nsRect base(baseCSS.x * nsPresContext::AppUnitsPerCSSPixel(),
                         baseCSS.y * nsPresContext::AppUnitsPerCSSPixel(),
                         baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(),
                         baseCSS.height * nsPresContext::AppUnitsPerCSSPixel());
             nsLayoutUtils::SetDisplayPortBase(aContent, base);
         }