Merge b2g-inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 16 Oct 2013 17:01:40 -0400
changeset 164844 66af8b3096a61f6eb95059817eb0de629d0c187b
parent 164809 b0d5cef2c4271b4fd5a0c597a2f828257b0f2887 (current diff)
parent 164843 188b4ec27f65429d6405983487cbb434385d8a8d (diff)
child 164845 423b9c30c73d12176db4bd80d38206eaa5032767
child 164847 546865ba2487a00e579875dfacd4bf9a56835293
child 164859 85fc49eda28abe327690b2318cd1b0126c5e7742
child 164893 1496fdb1d4b5f7141e37045e0b85f6dee11bbce5
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone27.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
Merge b2g-inbound to m-c.
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -797,20 +797,17 @@ pref("dom.promise.enabled", false);
 // Enable dataStore
 #ifdef RELEASE_BUILD
 pref("dom.datastore.enabled", false);
 #else
 pref("dom.datastore.enabled", true);
 #endif
 
 // DOM Inter-App Communication API.
-#ifdef MOZ_WIDGET_GONK
-// Enable this only for gonk-specific build but not for desktop build.
 pref("dom.inter-app-communication-api.enabled", true);
-#endif
 
 // Allow ADB to run for this many hours before disabling
 // (only applies when marionette is disabled)
 // 0 disables the timer.
 pref("b2g.adb.timeout-hours", 12);
 
 // InputMethod so we can do soft keyboards
 pref("dom.mozInputMethod.enabled", true);
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "36aa3e5d226a844b07b3e4b2219f54b549456ec1", 
+    "revision": "86e06b1db110e34eb66826d3b1bdee3a5d57b3a7", 
     "repo_path": "/integration/gaia-central"
 }
--- a/dom/camera/DOMCameraManager.cpp
+++ b/dom/camera/DOMCameraManager.cpp
@@ -61,17 +61,19 @@ nsDOMCameraManager::nsDOMCameraManager(n
   SetIsDOMBinding();
 }
 
 nsDOMCameraManager::~nsDOMCameraManager()
 {
   /* destructor code */
   DOM_CAMERA_LOGT("%s:%d : this=%p\n", __func__, __LINE__, this);
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
-  obs->RemoveObserver(this, "xpcom-shutdown");
+  if (obs) {
+    obs->RemoveObserver(this, "xpcom-shutdown");
+  }
 }
 
 bool
 nsDOMCameraManager::CheckPermission(nsPIDOMWindow* aWindow)
 {
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, false);
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -1057,16 +1057,33 @@ ContactDB.prototype = {
           let substringRequest = index.mozGetAll(substring, limit);
 
           substringRequest.onsuccess = function (event) {
             if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
             for (let i in event.target.result) {
               substringResult[event.target.result[i].id] = event.target.result[i];
             }
           }.bind(this);
+        } else if (normalized[0] !== "+") {
+          // We might have an international prefix like '00'
+          let parsed = PhoneNumberUtils.parse(normalized);
+          if (parsed && parsed.internationalNumber &&
+              parsed.nationalNumber  &&
+              parsed.nationalNumber !== normalized &&
+              parsed.internationalNumber !== normalized) {
+            if (DEBUG) debug("Search with " + parsed.internationalNumber);
+            let prefixRequest = index.mozGetAll(parsed.internationalNumber, limit);
+
+            prefixRequest.onsuccess = function (event) {
+              if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
+              for (let i in event.target.result) {
+                substringResult[event.target.result[i].id] = event.target.result[i];
+              }
+            }.bind(this);
+          }
         }
 
         request = index.mozGetAll(normalized, limit);
       } else {
         // XXX: "contains" should be handled separately, this is "startsWith"
         if (options.filterOp === 'contains' && key !== 'tel') {
           dump("ContactDB: 'contains' only works for 'tel'. Falling back " +
                "to 'startsWith'.\n");
--- a/dom/contacts/tests/test_contacts_international.html
+++ b/dom/contacts/tests/test_contacts_international.html
@@ -56,16 +56,26 @@ var properties1 = {
 };
 
 var shortNumber = "888";
 var properties2 = {
   name: "Testname2",
   tel: [{type: ["work"], value: shortNumber, carrier: "testCarrier"}]
 };
 
+var number3 = {
+  international1: "0041557932012345",
+  international2: "+557932012345"
+};
+
+var properties3 = {
+  name: "Testname2",
+  tel: [{value: number3.international2}]
+};
+
 var req;
 var index = 0;
 var createResult1;
 var findResult1;
 var sample_id1;
 
 var mozContacts = window.navigator.mozContacts;
 
@@ -233,16 +243,51 @@ var steps = [
     req = mozContacts.clear();
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     }
     req.onerror = onFailure;
   },
   function () {
+    ok(true, "Adding a new contact with country code");
+    createResult1 = new mozContact();
+    createResult1.init(properties3);
+    req = navigator.mozContacts.save(createResult1);
+    req.onsuccess = function () {
+      ok(createResult1.id, "The contact now has an ID.");
+      sample_id1 = createResult1.id;
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Searching for international number with prefix");
+    var options = {filterBy: ["tel"],
+                   filterOp: "match",
+                   filterValue: number3.international1};
+    req = mozContacts.find(options);
+    req.onsuccess = function () {
+      ok(req.result.length == 1, "Found exactly 1 contact.");
+      findResult1 = req.result[0];
+      ok(findResult1.id == sample_id1, "Same ID");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "Deleting database");
+    req = mozContacts.clear();
+    req.onsuccess = function () {
+      ok(true, "Deleted the database");
+      next();
+    }
+    req.onerror = onFailure;
+  },
+  function () {
     ok(true, "all done!\n");
     SimpleTest.finish();
   }
 ];
 
 function next() {
   ok(true, "Begin!");
   if (index >= steps.length) {
--- a/dom/datastore/tests/file_arrays.html
+++ b/dom/datastore/tests/file_arrays.html
@@ -40,42 +40,44 @@
       ok("clear" in store, "store.clear exists");
 
       gStore = stores[0];
 
       runTest();
     }, cbError);
   }
 
+  var itemNumber = 60;
+
   function testStoreAdd() {
     var objects = [];
-    for (var i = 0; i < 300; ++i) {
+    for (var i = 0; i < itemNumber; ++i) {
       objects.push(i);
     }
 
     function testStoreAddInternal() {
       if (!objects.length) {
-        ok(true, "We inserted 300 items");
+        ok(true, "We inserted " + itemNumber + " items");
         runTest();
         return;
       }
 
       var obj = objects.shift();
       gStore.add(obj).then(function() {
         ok(true, "We inserted a new item!");
         testStoreAddInternal();
       }, cbError);
     }
 
     testStoreAddInternal();
   }
 
   function testStoreGet() {
     var objects = [];
-    for (var i = 1; i <= 300; ++i) {
+    for (var i = 1; i <= itemNumber; ++i) {
       objects.push(i);
     }
 
     gStore.get(objects).then(function(data) {
        is(data.length, objects.length, "Get - Data matches");
        for (var i = 0; i < data.length; ++i) {
          is(data[i], objects[i] - 1, "Get - Data matches: " + i + " " + data[i] + " == " + objects[i]);
        }
--- a/dom/messages/SystemMessageManager.js
+++ b/dom/messages/SystemMessageManager.js
@@ -131,16 +131,17 @@ SystemMessageManager.prototype = {
       delete dispatchers[aType];
       return;
     }
 
     // Last registered handler wins.
     dispatchers[aType] = { handler: aHandler, messages: [], isHandling: false };
 
     // Ask for the list of currently pending messages.
+    this.addMessageListeners("SystemMessageManager:GetPendingMessages:Return");
     cpmm.sendAsyncMessage("SystemMessageManager:GetPendingMessages",
                           { type: aType,
                             uri: this._uri,
                             manifest: this._manifest });
   },
 
   mozHasPendingMessage: function sysMessMgr_hasPendingMessage(aType) {
     debug("asking pending message for [" + aType + "]");
@@ -209,16 +210,18 @@ SystemMessageManager.prototype = {
     if (aMessage.name == "SystemMessageManager:Message") {
       // Send an acknowledgement to parent to clean up the pending message,
       // so a re-launched app won't handle it again, which is redundant.
       cpmm.sendAsyncMessage("SystemMessageManager:Message:Return:OK",
                             { type: msg.type,
                               manifest: this._manifest,
                               uri: this._uri,
                               msgID: msg.msgID });
+    } else if (aMessage.name == "SystemMessageManager:GetPendingMessages:Return") {
+      this.removeMessageListeners(aMessage.name);
     }
 
     let messages = (aMessage.name == "SystemMessageManager:Message")
                    ? [msg.msg]
                    : msg.msgQueue;
 
     // We only dispatch messages when a handler is registered.
     let dispatcher = this._dispatchers[msg.type];
@@ -243,18 +246,17 @@ SystemMessageManager.prototype = {
                                    "handle-system-messages-done",
                                    /* aData */ null);
     }
   },
 
   // nsIDOMGlobalPropertyInitializer implementation.
   init: function sysMessMgr_init(aWindow) {
     debug("init");
-    this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message",
-                              "SystemMessageManager:GetPendingMessages:Return"]);
+    this.initDOMRequestHelper(aWindow, ["SystemMessageManager:Message"]);
 
     let principal = aWindow.document.nodePrincipal;
     this._isInBrowserElement = principal.isInBrowserElement;
     this._uri = principal.URI.spec;
 
     let appsService = Cc["@mozilla.org/AppsService;1"]
                         .getService(Ci.nsIAppsService);
     this._manifest = appsService.getManifestURLByLocalId(principal.appId);
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -1147,38 +1147,42 @@ this.STK_SUPPORTED_TERMINAL_PROFILE = [
  *
  * @see 3GPP TS 51.011 10.3.7 (SIM) and 3GPP TS 31.102 4.2.8 (USIM).
  */
 this.GECKO_ICC_SERVICES = {
   sim: {
     ADN: 2,
     FDN: 3,
     PLMNSEL: 7,
+    MSISDN: 9,
     CBMI: 14,
     SPN: 17,
     SDN: 18,
     DATA_DOWNLOAD_SMS_CB: 25,
     DATA_DOWNLOAD_SMS_PP: 26,
     CBMIR: 30,
     BDN: 31,
     PNN: 51,
     OPL: 52,
+    MDN: 53,
     SPDI: 56
   },
   usim: {
     FDN: 2,
     SDN: 4,
     BDN: 6,
     CBMI: 15,
     CBMIR: 16,
     SPN: 19,
+    MSISDN: 21,
     DATA_DOWNLOAD_SMS_PP: 28,
     DATA_DOWNLOAD_SMS_CB: 29,
     PNN: 45,
     OPL: 46,
+    MDN: 47,
     SPDI: 51
   },
   ruim: {
     ENHANCED_PHONEBOOK: 6,
     SPN: 17
   }
 };
 
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -10990,20 +10990,18 @@ ICCIOHelper[ICC_COMMAND_UPDATE_RECORD] =
  */
 let ICCRecordHelper = {
   /**
    * Fetch ICC records.
    */
   fetchICCRecords: function fetchICCRecords() {
     this.readICCID();
     RIL.getIMSI();
-    this.readMSISDN();
     this.readAD();
     this.readSST();
-    this.readMBDN();
   },
 
   /**
    * Read EF_phase.
    * This EF is only available in SIM.
    */
   readICCPhase: function readICCPhase() {
     function callback() {
@@ -11138,24 +11136,38 @@ let ICCRecordHelper = {
       if (DEBUG) {
         let str = "";
         for (let i = 0; i < sst.length; i++) {
           str += sst[i] + ", ";
         }
         debug("SST: " + str);
       }
 
+      if (ICCUtilsHelper.isICCServiceAvailable("MSISDN")) {
+        if (DEBUG) debug("MSISDN: MSISDN is available");
+        this.readMSISDN();
+      } else {
+        if (DEBUG) debug("MSISDN: MSISDN service is not available");
+      }
+
       // Fetch SPN and PLMN list, if some of them are available.
       if (ICCUtilsHelper.isICCServiceAvailable("SPN")) {
         if (DEBUG) debug("SPN: SPN is available");
         this.readSPN();
       } else {
         if (DEBUG) debug("SPN: SPN service is not available");
       }
 
+      if (ICCUtilsHelper.isICCServiceAvailable("MDN")) {
+        if (DEBUG) debug("MDN: MDN available.");
+        this.readMBDN();
+      } else {
+        if (DEBUG) debug("MDN: MDN service is not available");
+      }
+
       if (ICCUtilsHelper.isICCServiceAvailable("SPDI")) {
         if (DEBUG) debug("SPDI: SPDI available.");
         this.readSPDI();
       } else {
         if (DEBUG) debug("SPDI: SPDI service is not available");
       }
 
       if (ICCUtilsHelper.isICCServiceAvailable("PNN")) {
--- a/dom/system/gonk/tests/test_ril_worker_icc.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc.js
@@ -1890,8 +1890,91 @@ add_test(function test_reading_ad_and_pa
 
   do_test(undefined, "466923202422409", "466", "92" );
   do_test(0x03,      "466923202422409", "466", "923");
   do_test(undefined, "310260542718417", "310", "260");
   do_test(0x02,      "310260542718417", "310", "26" );
 
   run_next_test();
 });
+
+add_test(function test_reading_optional_efs() {
+  let worker = newUint8Worker();
+  let record = worker.ICCRecordHelper;
+  let gsmPdu = worker.GsmPDUHelper;
+  let ril    = worker.RIL;
+  let buf    = worker.Buf;
+  let io     = worker.ICCIOHelper;
+
+  function buildSST(supportedEf) {
+    let sst = [];
+    let len = supportedEf.length;
+    for (let i = 0; i < len; i++) {
+      let index, bitmask, iccService;
+      if (ril.appType === CARD_APPTYPE_SIM) {
+        iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]];
+        iccService -= 1;
+        index = Math.floor(iccService / 4);
+        bitmask = 2 << ((iccService % 4) << 1);
+      } else if (ril.appType === CARD_APPTYPE_USIM){
+        iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]];
+        iccService -= 1;
+        index = Math.floor(iccService / 8);
+        bitmask = 1 << ((iccService % 8) << 0);
+      }
+
+      if (sst) {
+        sst[index] |= bitmask;
+      }
+    }
+    return sst;
+  }
+
+  ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() {
+    // Ignore updateCellBroadcastConfig after reading SST
+  };
+
+  function do_test(sst, supportedEf) {
+    // Clone supportedEf to local array for testing
+    let testEf = supportedEf.slice(0);
+
+    record.readMSISDN = function fakeReadMSISDN() {
+      testEf.splice(testEf.indexOf("MSISDN"), 1);
+    };
+
+    record.readMBDN = function fakeReadMBDN() {
+      testEf.splice(testEf.indexOf("MDN"), 1);
+    };
+
+    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+      // Write data size
+      buf.writeInt32(sst.length * 2);
+
+      // Write data
+      for (let i = 0; i < sst.length; i++) {
+         gsmPdu.writeHexOctet(sst[i] || 0);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(sst.length * 2);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+
+      if (testEf.length !== 0) {
+        do_print("Un-handled EF: " + JSON.stringify(testEf));
+        do_check_true(false);
+      }
+    };
+
+    record.readSST();
+  }
+
+  // TODO: Add all necessary optional EFs eventually
+  let supportedEf = ["MSISDN", "MDN"];
+  ril.appType = CARD_APPTYPE_SIM;
+  do_test(buildSST(supportedEf), supportedEf);
+  ril.appType = CARD_APPTYPE_USIM;
+  do_test(buildSST(supportedEf), supportedEf);
+
+  run_next_test();
+});
--- a/gfx/layers/composite/ContainerLayerComposite.cpp
+++ b/gfx/layers/composite/ContainerLayerComposite.cpp
@@ -193,17 +193,23 @@ ContainerRender(ContainerT* aContainer,
     }
 
     nsIntRect clipRect = layerToRender->GetLayer()->
         CalculateScissorRect(aClipRect, &aManager->GetWorldTransform());
     if (clipRect.IsEmpty()) {
       continue;
     }
 
-    layerToRender->RenderLayer(childOffset, clipRect);
+    if (layerToRender->HasLayerBeenComposited()) {
+      // Composer2D will compose this layer so skip GPU composition
+      // this time & reset composition flag for next composition phase
+      layerToRender->SetLayerComposited(false);
+    } else {
+      layerToRender->RenderLayer(childOffset, clipRect);
+    }
     // invariant: our GL context should be current here, I don't think we can
     // assert it though
   }
 
   if (needsSurface) {
     // Unbind the current surface and rebind the previous one.
 #ifdef MOZ_DUMP_PAINTING
     if (gfxUtils::sDumpPainting) {
--- a/gfx/layers/composite/LayerManagerComposite.cpp
+++ b/gfx/layers/composite/LayerManagerComposite.cpp
@@ -721,16 +721,17 @@ LayerManagerComposite::CreateDrawTarget(
 
 LayerComposite::LayerComposite(LayerManagerComposite *aManager)
   : mCompositeManager(aManager)
   , mCompositor(aManager->GetCompositor())
   , mShadowOpacity(1.0)
   , mUseShadowClipRect(false)
   , mShadowTransformSetByAnimation(false)
   , mDestroyed(false)
+  , mLayerComposited(false)
 { }
 
 LayerComposite::~LayerComposite()
 {
 }
 
 void
 LayerComposite::Destroy()
--- a/gfx/layers/composite/LayerManagerComposite.h
+++ b/gfx/layers/composite/LayerManagerComposite.h
@@ -376,32 +376,39 @@ public:
   {
     mShadowTransform = aMatrix;
   }
   void SetShadowTransformSetByAnimation(bool aSetByAnimation)
   {
     mShadowTransformSetByAnimation = aSetByAnimation;
   }
 
+  void SetLayerComposited(bool value)
+  {
+    mLayerComposited = value;
+  }
+
   // These getters can be used anytime.
   float GetShadowOpacity() { return mShadowOpacity; }
   const nsIntRect* GetShadowClipRect() { return mUseShadowClipRect ? &mShadowClipRect : nullptr; }
   const nsIntRegion& GetShadowVisibleRegion() { return mShadowVisibleRegion; }
   const gfx3DMatrix& GetShadowTransform() { return mShadowTransform; }
   bool GetShadowTransformSetByAnimation() { return mShadowTransformSetByAnimation; }
+  bool HasLayerBeenComposited() { return mLayerComposited; }
 
 protected:
   gfx3DMatrix mShadowTransform;
   nsIntRegion mShadowVisibleRegion;
   nsIntRect mShadowClipRect;
   LayerManagerComposite* mCompositeManager;
   RefPtr<Compositor> mCompositor;
   float mShadowOpacity;
   bool mUseShadowClipRect;
   bool mShadowTransformSetByAnimation;
   bool mDestroyed;
+  bool mLayerComposited;
 };
 
 
 } /* layers */
 } /* mozilla */
 
 #endif /* GFX_LayerManagerComposite_H */
--- a/widget/gonk/HwcComposer2D.cpp
+++ b/widget/gonk/HwcComposer2D.cpp
@@ -152,21 +152,23 @@ HwcComposer2D::PrepareLayerList(Layer* a
 
     bool fillColor = false;
 
     const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
     if (visibleRegion.IsEmpty()) {
         return true;
     }
 
-    float opacity = aLayer->GetEffectiveOpacity();
-    if (opacity < 1) {
+    uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0));
+#if ANDROID_VERSION < 18
+    if (opacity < 0xFF) {
         LOGD("%s Layer has planar semitransparency which is unsupported", aLayer->Name());
         return false;
     }
+#endif
 
     nsIntRect clip;
     if (!HwcUtils::CalculateClipRect(aParentTransform * aGLWorldTransform,
                                      aLayer->GetEffectiveClipRect(),
                                      aClip,
                                      &clip))
     {
         LOGD("%s Clip rect is empty. Skip layer", aLayer->Name());
@@ -271,17 +273,17 @@ HwcComposer2D::PrepareLayerList(Layer* a
     hwcLayer.flags = 0;
     hwcLayer.hints = 0;
     hwcLayer.blending = HWC_BLENDING_PREMULT;
 #if ANDROID_VERSION >= 18
     hwcLayer.compositionType = HWC_FRAMEBUFFER;
 
     hwcLayer.acquireFenceFd = -1;
     hwcLayer.releaseFenceFd = -1;
-    hwcLayer.planeAlpha = 0xFF; // Until plane alpha is enabled
+    hwcLayer.planeAlpha = opacity;
 #else
     hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT;
 #endif
 
     if (!fillColor) {
         if (state.FormatRBSwapped()) {
             if (!mRBSwapSupport) {
                 LOGD("No R/B swap support in H/W Composer");
@@ -429,16 +431,17 @@ HwcComposer2D::PrepareLayerList(Layer* a
         ColorLayer* colorLayer = aLayer->AsColorLayer();
         if (colorLayer->GetColor().a < 1.0) {
             LOGD("Color layer has semitransparency which is unsupported");
             return false;
         }
         hwcLayer.transform = colorLayer->GetColor().Packed();
     }
 
+    mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData()));
     mList->numHwLayers++;
     return true;
 }
 
 
 #if ANDROID_VERSION >= 18
 bool
 HwcComposer2D::TryHwComposition()
@@ -456,23 +459,39 @@ HwcComposer2D::TryHwComposition()
         if (!ReallocLayerList() || idx >= mMaxLayerCount) {
             LOGE("TryHwComposition failed! Could not add FB layer");
             return false;
         }
     }
 
     Prepare(fbsurface->lastHandle, -1);
 
+    bool fullHwcComposite = true;
     for (int j = 0; j < idx; j++) {
         if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER) {
+            // After prepare, if there is an HWC_FRAMEBUFFER layer,
+            // it means full HWC Composition is not possible this time
             LOGD("GPU or Partial HWC Composition");
-            return false;
+            fullHwcComposite = false;
+            break;
         }
     }
 
+    if (!fullHwcComposite) {
+        for (int k=0; k < idx; k++) {
+            if (mList->hwLayers[k].compositionType == HWC_OVERLAY) {
+                // HWC will compose HWC_OVERLAY layers in partial
+                // HWC Composition, so set layer composition flag
+                // on mapped LayerComposite to skip GPU composition
+                mHwcLayerMap[k]->SetLayerComposited(true);
+            }
+        }
+        return false;
+    }
+
     // Full HWC Composition
     Commit();
 
     // No composition on FB layer, so closing releaseFenceFd
     close(mList->hwLayers[idx].releaseFenceFd);
     mList->hwLayers[idx].releaseFenceFd = -1;
     mList->numHwLayers = 0;
     return true;
@@ -549,38 +568,36 @@ HwcComposer2D::Prepare(buffer_handle_t f
 bool
 HwcComposer2D::Commit()
 {
     hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr };
     displays[HWC_DISPLAY_PRIMARY] = mList;
 
     int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays);
 
-    for (int i = 0; i <= MAX_HWC_LAYERS; i++) {
-        if (mPrevRelFd[i] <= 0) {
-            break;
+    if (!mPrevReleaseFds.IsEmpty()) {
+        // Wait for previous retire Fence to signal.
+        // Denotes contents on display have been replaced.
+        // For buffer-sync, framework should not over-write
+        // prev buffers until we close prev releaseFenceFds
+        sp<Fence> fence = new Fence(mPrevReleaseFds[0]);
+        if (fence->wait(1000) == -ETIME) {
+            LOGE("Wait timed-out for retireFenceFd %d", mPrevReleaseFds[0]);
         }
-        if (!i) {
-            // Wait for previous retire Fence to signal.
-            // Denotes contents on display have been replaced.
-            // For buffer-sync, framework should not over-write
-            // prev buffers until we close prev releaseFenceFds
-            sp<Fence> fence = new Fence(mPrevRelFd[i]);
-            if (fence->wait(1000) == -ETIME) {
-                LOGE("Wait timed-out for retireFenceFd %d", mPrevRelFd[i]);
-            }
+
+        for (int i = 0; i < mPrevReleaseFds.Length(); i++) {
+            close(mPrevReleaseFds[i]);
         }
-        close(mPrevRelFd[i]);
-        mPrevRelFd[i] = -1;
+        mPrevReleaseFds.Clear();
     }
 
-    mPrevRelFd[0] = mList->retireFenceFd;
-    for (uint32_t j = 0; j < (mList->numHwLayers - 1); j++) {
+    mPrevReleaseFds.AppendElement(mList->retireFenceFd);
+    for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) {
         if (mList->hwLayers[j].compositionType == HWC_OVERLAY) {
-            mPrevRelFd[j + 1] = mList->hwLayers[j].releaseFenceFd;
+            mPrevReleaseFds.AppendElement(mList->hwLayers[j].releaseFenceFd);
             mList->hwLayers[j].releaseFenceFd = -1;
         }
     }
 
     mList->retireFenceFd = -1;
     return !err;
 }
 #else
@@ -604,22 +621,24 @@ HwcComposer2D::TryRender(Layer* aRoot,
     if (!aGLWorldTransform.PreservesAxisAlignedRectangles()) {
         LOGD("Render aborted. World transform has non-square angle rotation");
         return false;
     }
 
     MOZ_ASSERT(Initialized());
     if (mList) {
         mList->numHwLayers = 0;
+        mHwcLayerMap.Clear();
     }
 
     // XXX: The clear() below means all rect vectors will be have to be
     // reallocated. We may want to avoid this if possible
     mVisibleRegions.clear();
 
+    MOZ_ASSERT(mHwcLayerMap.IsEmpty());
     if (!PrepareLayerList(aRoot,
                           mScreenRect,
                           gfxMatrix(),
                           aGLWorldTransform))
     {
         LOGD("Render aborted. Nothing was drawn to the screen");
         if (mList) {
            mList->numHwLayers = 0;
--- a/widget/gonk/HwcComposer2D.h
+++ b/widget/gonk/HwcComposer2D.h
@@ -19,18 +19,16 @@
 
 #include "Composer2D.h"
 #include "Layers.h"
 #include <vector>
 #include <list>
 
 #include <hardware/hwcomposer.h>
 
-#define MAX_HWC_LAYERS 15
-
 namespace mozilla {
 
 namespace layers {
 class ContainerLayer;
 class Layer;
 }
 
 //Holds a dynamically allocated vector of rectangles
@@ -78,14 +76,15 @@ private:
     hwc_surface_t           mSur;
     nsIntRect               mScreenRect;
     int                     mMaxLayerCount;
     bool                    mColorFill;
     bool                    mRBSwapSupport;
     //Holds all the dynamically allocated RectVectors needed
     //to render the current frame
     std::list<RectVector>   mVisibleRegions;
-    int                     mPrevRelFd[MAX_HWC_LAYERS + 1];
+    nsTArray<int>           mPrevReleaseFds;
+    nsTArray<layers::LayerComposite*> mHwcLayerMap;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_HwcComposer2D