Bug 564991. Part 33: Copy data out of hashtable in DrawThebesLayer in case hashtable is modified during the method. r=tnikkel
authorRobert O'Callahan <robert@ocallahan.org>
Fri, 16 Jul 2010 09:08:10 +1200
changeset 47766 7ca67c5abe054ec8a68c38bf00583b75376a5e57
parent 47765 fa2e4fe69310b212b5c651cba35656e26549fb55
child 47767 1e2f6e38cd981923b9f8d6612ed9a170326dff85
push id14413
push userrocallahan@mozilla.com
push dateThu, 15 Jul 2010 21:12:02 +0000
treeherderautoland@e1d7fd5255fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs564991
milestone2.0b2pre
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 564991. Part 33: Copy data out of hashtable in DrawThebesLayer in case hashtable is modified during the method. r=tnikkel
layout/base/FrameLayerBuilder.cpp
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1226,38 +1226,47 @@ FrameLayerBuilder::HasDedicatedLayer(nsI
 FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer,
                                    gfxContext* aContext,
                                    const nsIntRegion& aRegionToDraw,
                                    const nsIntRegion& aRegionToInvalidate,
                                    void* aCallbackData)
 {
   nsDisplayListBuilder* builder = static_cast<nsDisplayListBuilder*>
     (aCallbackData);
-  ThebesLayerItemsEntry* entry =
-    builder->LayerBuilder()->mThebesLayerItems.GetEntry(aLayer);
-  NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!");
+  nsTArray<ClippedDisplayItem> items;
+  nsIFrame* containerLayerFrame;
+  {
+    ThebesLayerItemsEntry* entry =
+      builder->LayerBuilder()->mThebesLayerItems.GetEntry(aLayer);
+    NS_ASSERTION(entry, "We shouldn't be drawing into a layer with no items!");
+    items.SwapElements(entry->mItems);
+    containerLayerFrame = entry->mContainerLayerFrame;
+    // Later after this point, due to calls to DidEndTransaction
+    // for temporary layer managers, mThebesLayerItems can change,
+    // so 'entry' could become invalid.
+  }
 
   gfxMatrix transform;
   if (!aLayer->GetTransform().Is2D(&transform)) {
     NS_ERROR("non-2D transform in our Thebes layer!");
     return;
   }
   NS_ASSERTION(!transform.HasNonIntegerTranslation(),
                "Matrix not just an integer translation?");
   // make the origin of the context coincide with the origin of the
   // ThebesLayer
   gfxContextMatrixAutoSaveRestore saveMatrix(aContext); 
   aContext->Translate(-gfxPoint(transform.x0, transform.y0));
   nsIntPoint offset(PRInt32(transform.x0), PRInt32(transform.y0));
 
-  nsPresContext* presContext = entry->mContainerLayerFrame->PresContext();
+  nsPresContext* presContext = containerLayerFrame->PresContext();
   nscoord appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   nsRect r = (aRegionToInvalidate.GetBounds() + offset).
     ToAppUnits(appUnitsPerDevPixel);
-  entry->mContainerLayerFrame->Invalidate(r);
+  containerLayerFrame->Invalidate(r);
 
   // Our list may contain content with different prescontexts at
   // different zoom levels. 'rc' contains the nsIRenderingContext
   // used for the previous display item, and lastPresContext is the
   // prescontext for that item. We also cache the clip state for that
   // item.
   // XXX maybe we should stop that from being true by forcing content with
   // different zoom levels into different layers?
@@ -1271,18 +1280,18 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
   // because we may be asked to draw into part of a ThebesLayer that
   // isn't actually visible in the window (e.g., because a ThebesLayer
   // expanded its visible region to a rectangle internally), in which
   // case the mVisibleRect stored in the display item may be wrong.
   nsRegion visible = aRegionToDraw.ToAppUnits(appUnitsPerDevPixel);
   visible.MoveBy(NSIntPixelsToAppUnits(offset.x, appUnitsPerDevPixel),
                  NSIntPixelsToAppUnits(offset.y, appUnitsPerDevPixel));
 
-  for (i = entry->mItems.Length(); i > 0; --i) {
-    ClippedDisplayItem* cdi = &entry->mItems[i - 1];
+  for (i = items.Length(); i > 0; --i) {
+    ClippedDisplayItem* cdi = &items[i - 1];
 
     presContext = cdi->mItem->GetUnderlyingFrame()->PresContext();
     if (presContext->AppUnitsPerDevPixel() != appUnitsPerDevPixel) {
       // Some kind of zooming detected, just redraw the entire item
       nsRegion tmp(cdi->mItem->GetBounds(builder));
       cdi->mItem->RecomputeVisibility(builder, &tmp);
       continue;
     }
@@ -1303,18 +1312,18 @@ FrameLayerBuilder::DrawThebesLayer(Thebe
     nsRegion newVisible;
     newVisible.Sub(visible, removed);
     // Don't let the visible region get too complex.
     if (newVisible.GetNumRects() <= 15) {
       visible = newVisible;
     }
   }
 
-  for (i = 0; i < entry->mItems.Length(); ++i) {
-    ClippedDisplayItem* cdi = &entry->mItems[i];
+  for (i = 0; i < items.Length(); ++i) {
+    ClippedDisplayItem* cdi = &items[i];
 
     if (cdi->mItem->GetVisibleRect().IsEmpty())
       continue;
 
     presContext = cdi->mItem->GetUnderlyingFrame()->PresContext();
     // If the new desired clip state is different from the current state,
     // update the clip.
     if (setClipRect != cdi->mHasClipRect ||