Merge m-c to inbound on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Wed, 26 Feb 2014 18:31:11 -0800
changeset 171219 75e7fb569d74a41e863d6e1c69b2199aa79dbcf5
parent 171194 782acfe6edfdd423376d514179764fccbc8c3803 (current diff)
parent 171218 de2ce8226ca8b1852486da1b7d861ab46caed020 (diff)
child 171220 f8054c8163298a17c57b3407dd1a0928f707c623
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
milestone30.0a1
Merge m-c to inbound on a CLOSED TREE
b2g/config/emulator-ics/sources.xml
b2g/config/emulator-jb/sources.xml
b2g/config/emulator/sources.xml
b2g/config/gaia.json
b2g/config/hamachi/sources.xml
b2g/config/helix/sources.xml
b2g/config/inari/sources.xml
b2g/config/leo/sources.xml
b2g/config/mako/sources.xml
b2g/config/wasabi/sources.xml
gfx/layers/client/ClientCanvasLayer.h
gfx/layers/client/TextureClient.cpp
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -718,8 +718,12 @@ SettingsListener.observe('layers.enable-
 SettingsListener.observe('layers.progressive-paint', false, function(value) {
   Services.prefs.setBoolPref('layers.progressive-paint', value);
 });
 
 SettingsListener.observe('layers.draw-tile-borders', false, function(value) {
   Services.prefs.setBoolPref('layers.draw-tile-borders', value);
 });
 
+SettingsListener.observe('layers.dump', false, function(value) {
+  Services.prefs.setBoolPref('layers.dump', value);
+});
+
--- a/b2g/chrome/content/shell.css
+++ b/b2g/chrome/content/shell.css
@@ -9,9 +9,10 @@ html {
   height: 100%;
   padding: 0 !important;
 }
 
 body {
   margin: 0;
   width: 100%;
   height: 100%;
+  overflow: hidden;
 }
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -4796,33 +4796,31 @@ const nodeToShortcutMap = {
 #ifdef XP_MACOSX
   "print-button": "printKb",
 #endif
   "new-window-button": "key_newNavigator",
   "fullscreen-button": "key_fullScreen",
   "tabview-button": "key_tabview",
 };
 const gDynamicTooltipCache = new Map();
-function UpdateDynamicShortcutTooltipText(popupTriggerNode) {
-  let label = document.getElementById("dynamic-shortcut-tooltip-label");
-  let nodeId = popupTriggerNode.id;
+function UpdateDynamicShortcutTooltipText(aTooltip) {
+  let nodeId = aTooltip.triggerNode.id;
   if (!gDynamicTooltipCache.has(nodeId) && nodeId in nodeToTooltipMap) {
     let strId = nodeToTooltipMap[nodeId];
     let args = [];
     if (nodeId in nodeToShortcutMap) {
       let shortcutId = nodeToShortcutMap[nodeId];
       let shortcut = document.getElementById(shortcutId);
       if (shortcut) {
         args.push(ShortcutUtils.prettifyShortcut(shortcut));
       }
     }
     gDynamicTooltipCache.set(nodeId, gNavigatorBundle.getFormattedString(strId, args));
   }
-  let desiredLabel = gDynamicTooltipCache.get(nodeId);
-  label.setAttribute("value", desiredLabel);
+  aTooltip.setAttribute("label", gDynamicTooltipCache.get(nodeId));
 }
 
 /**
  * Gets the selected text in the active browser. Leading and trailing
  * whitespace is removed, and consecutive whitespace is replaced by a single
  * space. A maximum of 150 characters will be returned, regardless of the value
  * of aCharLen.
  *
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -471,19 +471,17 @@
 
     <hbox id="bookmarked-notification-container" mousethrough="always">
       <vbox id="bookmarked-notification-anchor">
         <vbox id="bookmarked-notification"/>
       </vbox>
     </hbox>
 
     <tooltip id="dynamic-shortcut-tooltip"
-             onpopupshowing="UpdateDynamicShortcutTooltipText(this.triggerNode)">
-      <label id="dynamic-shortcut-tooltip-label"/>
-    </tooltip>
+             onpopupshowing="UpdateDynamicShortcutTooltipText(this);"/>
   </popupset>
 
 #ifdef CAN_DRAW_IN_TITLEBAR
 <vbox id="titlebar">
   <hbox id="titlebar-content">
     <spacer id="titlebar-spacer" flex="1"/>
     <hbox id="titlebar-buttonbox-container">
       <hbox id="titlebar-buttonbox">
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -1053,21 +1053,23 @@ nsDOMCameraControl::OnRecorderStateChang
 
   switch (aState) {
     case CameraControlListener::kRecorderStarted:
       if (mStartRecordingOnSuccessCb) {
         nsCOMPtr<CameraStartRecordingCallback> cb = mStartRecordingOnSuccessCb.forget();
         mStartRecordingOnErrorCb = nullptr;
         cb->Call(ignored);
       }
-      return;
+      state = NS_LITERAL_STRING("Started");
+      break;
 
     case CameraControlListener::kRecorderStopped:
       NotifyRecordingStatusChange(NS_LITERAL_STRING("shutdown"));
-      return;
+      state = NS_LITERAL_STRING("Stopped");
+      break;
 
 #ifdef MOZ_B2G_CAMERA
     case CameraControlListener::kFileSizeLimitReached:
       state = NS_LITERAL_STRING("FileSizeLimitReached");
       break;
 
     case CameraControlListener::kVideoLengthLimitReached:
       state = NS_LITERAL_STRING("VideoLengthLimitReached");
--- a/gfx/layers/client/CanvasClient.h
+++ b/gfx/layers/client/CanvasClient.h
@@ -52,16 +52,18 @@ public:
   CanvasClient(CompositableForwarder* aFwd, TextureFlags aFlags)
     : CompositableClient(aFwd)
   {
     mTextureInfo.mTextureFlags = aFlags;
   }
 
   virtual ~CanvasClient() {}
 
+  virtual void Clear() {};
+
   virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) = 0;
 
   virtual void Updated() { }
 
 protected:
   TextureInfo mTextureInfo;
 };
 
@@ -75,16 +77,21 @@ public:
   {
   }
 
   TextureInfo GetTextureInfo() const
   {
     return TextureInfo(COMPOSITABLE_IMAGE);
   }
 
+  virtual void Clear() MOZ_OVERRIDE
+  {
+    mBuffer = nullptr;
+  }
+
   virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
 
   virtual bool AddTextureClient(TextureClient* aTexture) MOZ_OVERRIDE
   {
     MOZ_ASSERT((mTextureInfo.mTextureFlags & aTexture->GetFlags()) == mTextureInfo.mTextureFlags);
     return CompositableClient::AddTextureClient(aTexture);
   }
 
@@ -108,16 +115,21 @@ class CanvasClientSurfaceStream : public
 public:
   CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder, TextureFlags aFlags);
 
   TextureInfo GetTextureInfo() const
   {
     return TextureInfo(COMPOSITABLE_IMAGE);
   }
 
+  virtual void Clear() MOZ_OVERRIDE
+  {
+    mBuffer = nullptr;
+  }
+
   virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
 
   virtual void OnDetach() MOZ_OVERRIDE
   {
     mBuffer = nullptr;
   }
 
 private:
--- a/gfx/layers/client/ClientCanvasLayer.h
+++ b/gfx/layers/client/ClientCanvasLayer.h
@@ -51,16 +51,23 @@ public:
                  "Can only set properties in construction phase");
     CanvasLayer::SetVisibleRegion(aRegion);
   }
 
   virtual void Initialize(const Data& aData);
 
   virtual void RenderLayer();
 
+  virtual void ClearCachedResources()
+  {
+    if (mCanvasClient) {
+      mCanvasClient->Clear();
+    }
+  }
+
   virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
   {
     aAttrs = CanvasLayerAttributes(mFilter, mBounds);
   }
 
   virtual Layer* AsLayer() { return this; }
   virtual ShadowableLayer* AsShadowableLayer() { return this; }
 
--- a/gfx/layers/client/ContentClient.h
+++ b/gfx/layers/client/ContentClient.h
@@ -201,17 +201,22 @@ public:
     , mIsNewBuffer(false)
     , mFrontAndBackBufferDiffer(false)
     , mSurfaceFormat(gfx::SurfaceFormat::B8G8R8A8)
   {}
 
   typedef RotatedContentBuffer::PaintState PaintState;
   typedef RotatedContentBuffer::ContentType ContentType;
 
-  virtual void Clear() { RotatedContentBuffer::Clear(); }
+  virtual void Clear()
+  {
+    RotatedContentBuffer::Clear();
+    mTextureClient = nullptr;
+    mTextureClientOnWhite = nullptr;
+  }
 
   virtual PaintState BeginPaintBuffer(ThebesLayer* aLayer,
                                       uint32_t aFlags) MOZ_OVERRIDE
   {
     return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
   }
   virtual gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
                                                        const PaintState& aPaintState) MOZ_OVERRIDE
@@ -419,16 +424,23 @@ class ContentClientDoubleBuffered : publ
 public:
   ContentClientDoubleBuffered(CompositableForwarder* aFwd)
     : ContentClientRemoteBuffer(aFwd)
   {
     mTextureInfo.mCompositableType = COMPOSITABLE_CONTENT_DOUBLE;
   }
   virtual ~ContentClientDoubleBuffered() {}
 
+  virtual void Clear() MOZ_OVERRIDE
+  {
+    ContentClientRemoteBuffer::Clear();
+    mFrontClient = nullptr;
+    mFrontClientOnWhite = nullptr;
+  }
+
   virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) MOZ_OVERRIDE;
 
   virtual void PrepareFrame() MOZ_OVERRIDE;
 
   virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) MOZ_OVERRIDE;
 
 protected:
   virtual void CreateFrontBuffer(const nsIntRect& aBufferRect) MOZ_OVERRIDE;
--- a/gfx/layers/client/TextureClient.cpp
+++ b/gfx/layers/client/TextureClient.cpp
@@ -300,18 +300,19 @@ void
 TextureClient::Finalize()
 {
   // Always make a temporary strong reference to the actor before we use it,
   // in case TextureChild::ActorDestroy might null mActor concurrently.
   RefPtr<TextureChild> actor = mActor;
 
   if (actor) {
     // this will call ForceRemove in the right thread, using a sync proxy if needed
-    actor->GetForwarder()->RemoveTexture(this);
-
+    if (actor->GetForwarder()) {
+      actor->GetForwarder()->RemoveTexture(this);
+    }
     // The actor has a raw pointer to us, actor->mTextureClient. Null it before we die.
     actor->mTextureClient = nullptr;
   }
 }
 
 bool
 TextureClient::ShouldDeallocateInDestructor() const
 {
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2096,26 +2096,27 @@ InitLayersAccelerationPrefs()
 
     sPrefLayersOffMainThreadCompositionEnabled = Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
     sPrefLayersOffMainThreadCompositionTestingEnabled = Preferences::GetBool("layers.offmainthreadcomposition.testing.enabled", false);
     sPrefLayersOffMainThreadCompositionForceEnabled = Preferences::GetBool("layers.offmainthreadcomposition.force-enabled", false);
     sPrefLayersAccelerationForceEnabled = Preferences::GetBool("layers.acceleration.force-enabled", false);
     sPrefLayersAccelerationDisabled = Preferences::GetBool("layers.acceleration.disabled", false);
     sPrefLayersPreferOpenGL = Preferences::GetBool("layers.prefer-opengl", false);
     sPrefLayersPreferD3D9 = Preferences::GetBool("layers.prefer-d3d9", false);
-    sPrefLayersDrawFPS = Preferences::GetBool("layers.acceleration.draw-fps", false);
     sPrefLayersDump = Preferences::GetBool("layers.dump", false);
     sPrefLayersScrollGraph = Preferences::GetBool("layers.scroll-graph", false);
     sPrefLayersEnableTiles = Preferences::GetBool("layers.enable-tiles", false);
     sPrefLayoutFrameRate = Preferences::GetInt("layout.frame_rate", -1);
     sPrefLayersCompositionFrameRate = Preferences::GetInt("layers.offmainthreadcomposition.frame-rate", -1);
     sBufferRotationEnabled = Preferences::GetBool("layers.bufferrotation.enabled", true);
     sComponentAlphaEnabled = Preferences::GetBool("layers.componentalpha.enabled", true);
     sPrefBrowserTabsRemoteAutostart = Preferences::GetBool("browser.tabs.remote.autostart", false);
 
+    Preferences::AddBoolVarCache(&sPrefLayersDrawFPS, "layers.acceleration.draw-fps", false);
+
 #ifdef XP_WIN
     if (sPrefLayersAccelerationForceEnabled) {
       sLayersSupportsD3D9 = true;
     } else {
       nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
       if (gfxInfo) {
         int32_t status;
         if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_9_LAYERS, &status))) {
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -69,16 +69,22 @@ public class Tab {
     private static final int MAX_HISTORY_LIST_SIZE = 50;
     private int mLoadProgress;
 
     public static final int STATE_DELAYED = 0;
     public static final int STATE_LOADING = 1;
     public static final int STATE_SUCCESS = 2;
     public static final int STATE_ERROR = 3;
 
+    public static final int LOAD_PROGRESS_INIT = 10;
+    public static final int LOAD_PROGRESS_START = 20;
+    public static final int LOAD_PROGRESS_LOCATION_CHANGE = 60;
+    public static final int LOAD_PROGRESS_LOADED = 80;
+    public static final int LOAD_PROGRESS_STOP = 100;
+
     private static final int DEFAULT_BACKGROUND_COLOR = Color.WHITE;
 
     public enum ErrorType {
         CERT_ERROR,  // Pages with certificate problems
         BLOCKED,     // Pages blocked for phishing or malware warnings
         NET_ERROR,   // All other types of error
         NONE         // Non error pages
     }
@@ -107,16 +113,17 @@ public class Tab {
         mBookmark = false;
         mReadingListItem = false;
         mFaviconLoadId = 0;
         mContentType = "";
         mZoomConstraints = new ZoomConstraints(false);
         mPluginViews = new ArrayList<View>();
         mPluginLayers = new HashMap<Object, Layer>();
         mState = shouldShowProgress(url) ? STATE_SUCCESS : STATE_LOADING;
+        mLoadProgress = LOAD_PROGRESS_INIT;
 
         // At startup, the background is set to a color specified by LayerView
         // when the LayerView is created. Shortly after, this background color
         // will be used before the tab's content is shown.
         mBackgroundColor = DEFAULT_BACKGROUND_COLOR;
 
         updateBookmark();
     }
@@ -623,48 +630,55 @@ public class Tab {
         setHasFeeds(false);
         setHasOpenSearch(false);
         updateIdentityData(null);
         setReaderEnabled(false);
         setZoomConstraints(new ZoomConstraints(true));
         setHasTouchListeners(false);
         setBackgroundColor(DEFAULT_BACKGROUND_COLOR);
         setErrorType(ErrorType.NONE);
+        setLoadProgress(LOAD_PROGRESS_LOCATION_CHANGE);
 
         Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, oldUrl);
     }
 
     private static boolean shouldShowProgress(final String url) {
         return AboutPages.isAboutHome(url) ||
                AboutPages.isAboutReader(url) ||
                AboutPages.isAboutPrivateBrowsing(url);
     }
 
     void handleDocumentStart(boolean showProgress, String url) {
+        setLoadProgress(LOAD_PROGRESS_START);
         setState(showProgress ? STATE_LOADING : STATE_SUCCESS);
         updateIdentityData(null);
         setReaderEnabled(false);
     }
 
     void handleDocumentStop(boolean success) {
         setState(success ? STATE_SUCCESS : STATE_ERROR);
 
         final String oldURL = getURL();
         final Tab tab = this;
+        tab.setLoadProgress(LOAD_PROGRESS_STOP);
         ThreadUtils.getBackgroundHandler().postDelayed(new Runnable() {
             @Override
             public void run() {
                 // tab.getURL() may return null
                 if (!TextUtils.equals(oldURL, getURL()))
                     return;
 
                 ThumbnailHelper.getInstance().getAndProcessThumbnailFor(tab);
             }
         }, 500);
-     }
+    }
+
+    void handleContentLoaded() {
+        setLoadProgress(LOAD_PROGRESS_LOADED);
+    }
 
     protected void saveThumbnailToDB() {
         try {
             String url = getURL();
             if (url == null)
                 return;
 
             BrowserDB.updateThumbnailForUrl(getContentResolver(), url, mThumbnail);
--- a/mobile/android/base/Tabs.java
+++ b/mobile/android/base/Tabs.java
@@ -46,21 +46,16 @@ public class Tabs implements GeckoEventL
     private volatile Tab mSelectedTab;
 
     // All accesses to mTabs must be synchronized on the Tabs instance.
     private final HashMap<Integer, Tab> mTabs = new HashMap<Integer, Tab>();
 
     private AccountManager mAccountManager;
     private OnAccountsUpdateListener mAccountListener = null;
 
-    private static final int LOAD_PROGRESS_START = 20;
-    private static final int LOAD_PROGRESS_LOCATION_CHANGE = 60;
-    private static final int LOAD_PROGRESS_LOADED = 80;
-    private static final int LOAD_PROGRESS_STOP = 100;
-
     public static final int LOADURL_NONE         = 0;
     public static final int LOADURL_NEW_TAB      = 1 << 0;
     public static final int LOADURL_USER_ENTERED = 1 << 1;
     public static final int LOADURL_PRIVATE      = 1 << 2;
     public static final int LOADURL_PINNED       = 1 << 3;
     public static final int LOADURL_DELAY_LOAD   = 1 << 4;
     public static final int LOADURL_DESKTOP      = 1 << 5;
     public static final int LOADURL_BACKGROUND   = 1 << 6;
@@ -435,53 +430,50 @@ public class Tabs implements GeckoEventL
             if (event.startsWith("SessionHistory:")) {
                 event = event.substring("SessionHistory:".length());
                 tab.handleSessionHistoryMessage(event, message);
             } else if (event.equals("Tab:Close")) {
                 closeTab(tab);
             } else if (event.equals("Tab:Select")) {
                 selectTab(tab.getId());
             } else if (event.equals("Content:LocationChange")) {
-                tab.setLoadProgress(LOAD_PROGRESS_LOCATION_CHANGE);
                 tab.handleLocationChange(message);
             } else if (event.equals("Content:SecurityChange")) {
                 tab.updateIdentityData(message.getJSONObject("identity"));
                 notifyListeners(tab, TabEvents.SECURITY_CHANGE);
             } else if (event.equals("Content:ReaderEnabled")) {
                 tab.setReaderEnabled(true);
                 notifyListeners(tab, TabEvents.READER_ENABLED);
             } else if (event.equals("Content:StateChange")) {
                 int state = message.getInt("state");
                 if ((state & GeckoAppShell.WPL_STATE_IS_NETWORK) != 0) {
                     if ((state & GeckoAppShell.WPL_STATE_START) != 0) {
                         boolean showProgress = message.getBoolean("showProgress");
                         tab.handleDocumentStart(showProgress, message.getString("uri"));
-                        tab.setLoadProgress(LOAD_PROGRESS_START);
                         notifyListeners(tab, Tabs.TabEvents.START);
                     } else if ((state & GeckoAppShell.WPL_STATE_STOP) != 0) {
                         tab.handleDocumentStop(message.getBoolean("success"));
-                        tab.setLoadProgress(LOAD_PROGRESS_STOP);
                         notifyListeners(tab, Tabs.TabEvents.STOP);
                     }
                 }
             } else if (event.equals("Content:LoadError")) {
-                tab.setLoadProgress(LOAD_PROGRESS_LOADED);
+                tab.handleContentLoaded();
                 notifyListeners(tab, Tabs.TabEvents.LOAD_ERROR);
             } else if (event.equals("Content:PageShow")) {
                 notifyListeners(tab, TabEvents.PAGE_SHOW);
             } else if (event.equals("DOMContentLoaded")) {
+                tab.handleContentLoaded();
                 String backgroundColor = message.getString("bgColor");
                 if (backgroundColor != null) {
                     tab.setBackgroundColor(backgroundColor);
                 } else {
                     // Default to white if no color is given
                     tab.setBackgroundColor(Color.WHITE);
                 }
                 tab.setErrorType(message.optString("errorType"));
-                tab.setLoadProgress(LOAD_PROGRESS_LOADED);
                 notifyListeners(tab, Tabs.TabEvents.LOADED);
             } else if (event.equals("DOMTitleChanged")) {
                 tab.updateTitle(message.getString("title"));
             } else if (event.equals("Link:Favicon")) {
                 tab.updateFaviconURL(message.getString("href"), message.getInt("size"));
                 notifyListeners(tab, TabEvents.LINK_FAVICON);
             } else if (event.equals("Link:Feed")) {
                 tab.setHasFeeds(true);
--- a/mobile/android/base/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/toolbar/BrowserToolbar.java
@@ -465,18 +465,19 @@ public class BrowserToolbar extends Geck
         }
 
         if (tabs.isSelectedTab(tab)) {
             final EnumSet<UpdateFlags> flags = EnumSet.noneOf(UpdateFlags.class);
 
             // Progress-related handling
             switch (msg) {
                 case START:
-                    updateProgressVisibility(tab, 0);
+                    updateProgressVisibility(tab, Tab.LOAD_PROGRESS_INIT);
                     // Fall through.
+                case ADDED:
                 case LOCATION_CHANGE:
                 case LOAD_ERROR:
                 case LOADED:
                 case STOP:
                     flags.add(UpdateFlags.PROGRESS);
                     if (mProgressBar.getVisibility() == View.VISIBLE) {
                         mProgressBar.animateProgress(tab.getLoadProgress());
                     }