Bug 602757. Part 5: Change HasText to GetComponentAlphaBounds. r=tnikkel,sr=dbaron,a=blocking
authorRobert O'Callahan <robert@ocallahan.org>
Mon, 03 Jan 2011 14:48:09 +1300
changeset 59781 b804550e79d746172c578ea169f752f36f75abab
parent 59780 475fe8dd48a37963ce662e326a19fc815940c2f7
child 59782 836e01a2a6dc041d6d730f1fa3509284990816fd
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel, dbaron, blocking
bugs602757
milestone2.0b9pre
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 602757. Part 5: Change HasText to GetComponentAlphaBounds. r=tnikkel,sr=dbaron,a=blocking
layout/base/FrameLayerBuilder.cpp
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.h
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsBulletFrame.cpp
layout/generic/nsTextFrameThebes.cpp
layout/mathml/nsMathMLChar.cpp
layout/xul/base/src/nsTextBoxFrame.cpp
layout/xul/base/src/nsTextBoxFrame.h
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -894,17 +894,18 @@ ContainerState::PopThebesLayerData()
                                      data->mDrawRegion);
   }
 
   mThebesLayerDataStack.RemoveElementAt(lastIndex);
 }
 
 static PRBool
 SuppressComponentAlpha(nsDisplayListBuilder* aBuilder,
-                       nsDisplayItem* aItem)
+                       nsDisplayItem* aItem,
+                       const nsRect& aComponentAlphaBounds)
 {
   const nsRegion* windowTransparentRegion = aBuilder->GetFinalTransparentRegion();
   if (!windowTransparentRegion || windowTransparentRegion->IsEmpty())
     return PR_FALSE;
 
   // Suppress component alpha for items in the toplevel window that are over
   // the window translucent area
   nsIFrame* f = aItem->GetUnderlyingFrame();
@@ -912,17 +913,17 @@ SuppressComponentAlpha(nsDisplayListBuil
   if (f->PresContext() != ref->PresContext())
     return PR_FALSE;
 
   for (nsIFrame* t = f; t; t = t->GetParent()) {
     if (t->IsTransformed())
       return PR_FALSE;
   }
 
-  return windowTransparentRegion->Intersects(aItem->GetBounds(aBuilder));
+  return windowTransparentRegion->Intersects(aComponentAlphaBounds);
 }
 
 void
 ContainerState::ThebesLayerData::Accumulate(nsDisplayListBuilder* aBuilder,
                                             nsDisplayItem* aItem,
                                             const nsIntRect& aVisibleRect,
                                             const nsIntRect& aDrawRect,
                                             const FrameLayerBuilder::Clip& aClip)
@@ -963,19 +964,22 @@ ContainerState::ThebesLayerData::Accumul
       nsIntRect rect = aClip.ApproximateIntersect(*r).ToNearestPixels(appUnitsPerDevPixel);
       nsIntRegion tmp;
       tmp.Or(mOpaqueRegion, rect);
       if (tmp.GetNumRects() <= 4) {
         mOpaqueRegion = tmp;
       }
     }
   }
-  if (aItem->HasText()) {
-    if (!mOpaqueRegion.Contains(aVisibleRect)) {
-      if (SuppressComponentAlpha(aBuilder, aItem)) {
+  nsRect componentAlpha = aItem->GetComponentAlphaBounds(aBuilder);
+  componentAlpha.IntersectRect(componentAlpha, aItem->GetVisibleRect());
+  if (!componentAlpha.IsEmpty()) {
+    nscoord appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem);
+    if (!mOpaqueRegion.Contains(componentAlpha.ToOutsidePixels(appUnitsPerDevPixel))) {
+      if (SuppressComponentAlpha(aBuilder, aItem, componentAlpha)) {
         aItem->DisableComponentAlpha();
       } else {
         mNeedComponentAlpha = PR_TRUE;
       }
     }
   }
   mForceTransparentSurface = mForceTransparentSurface || forceTransparentSurface;
 }
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1372,24 +1372,23 @@ PRBool nsDisplayWrapList::ChildrenCanBeI
       nsDisplayList* list = i->GetList();
       if (list && !ChildrenCanBeInactive(aBuilder, aManager, *list, aActiveScrolledRoot))
         return PR_FALSE;
     }
   }
   return PR_TRUE;
 }
 
-PRBool nsDisplayWrapList::HasText()
+nsRect nsDisplayWrapList::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
 {
+  nsRect bounds;
   for (nsDisplayItem* i = mList.GetBottom(); i; i = i->GetAbove()) {
-    if (i->HasText()) {
-      return PR_TRUE;
-    }
+    bounds.UnionRect(bounds, i->GetComponentAlphaBounds(aBuilder));
   }
-  return PR_FALSE;
+  return bounds;
 }
 
 static nsresult
 WrapDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
                 nsDisplayList* aList, nsDisplayWrapper* aWrapper) {
   if (!aList->GetTop())
     return NS_OK;
   nsDisplayItem* item = aWrapper->WrapList(aBuilder, aFrame, aList);
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -705,20 +705,22 @@ public:
    * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame())
    */
   const nsPoint& ToReferenceFrame() {
     NS_ASSERTION(mFrame, "No frame?");
     return mToReferenceFrame;
   }
 
   /**
-   * Checks if this display item (or any children) contains text that might 
-   * be rendered with subpixel antialiasing.
+   * Checks if this display item (or any children) contains content that might
+   * be rendered with component alpha (e.g. subpixel antialiasing). Returns the
+   * bounds of the area that needs component alpha, or an empty rect if nothing
+   * in the item does.
    */
-  virtual PRBool HasText() { return PR_FALSE; }
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) { return nsRect(); }
 
   /**
    * Disable usage of component alpha. Currently only relevant for items that have text.
    */
   virtual void DisableComponentAlpha() {}
 
 protected:
   friend class nsDisplayList;
@@ -1185,23 +1187,22 @@ public:
   }
 #endif
   
   virtual void Paint(nsDisplayListBuilder* aBuilder, nsIRenderingContext* aCtx) {
     mPaint(mFrame, aCtx, mVisibleRect, ToReferenceFrame());
   }
   NS_DISPLAY_DECL_NAME(mName, mType)
 
-  virtual PRBool HasText() {
-    if (mType == nsDisplayItem::TYPE_HEADER_FOOTER) {
-      return PR_TRUE;
-    } else {
-      return PR_FALSE;
-    }
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) {
+    if (mType == nsDisplayItem::TYPE_HEADER_FOOTER)
+      return GetBounds(aBuilder);
+    return nsRect();
   }
+
 protected:
   PaintCallback mPaint;
 #ifdef DEBUG
   const char*   mName;
 #endif
   Type mType;
 };
 
@@ -1550,17 +1551,17 @@ public:
   virtual PRBool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion);
   virtual PRBool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) {
     NS_WARNING("This list should already have been flattened!!!");
     return PR_FALSE;
   }
   NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST)
 
-  virtual PRBool HasText();
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder);
                                     
   virtual nsDisplayList* GetList() { return &mList; }
   
   /**
    * This creates a copy of this item, but wrapping aItem instead of
    * our existing list. Only gets called if this item returned nsnull
    * for GetUnderlyingFrame(). aItem is guaranteed to return non-null from
    * GetUnderlyingFrame().
@@ -1838,17 +1839,22 @@ public:
   virtual ~nsDisplayTransform()
   {
     MOZ_COUNT_DTOR(nsDisplayTransform);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM);
 
-  virtual PRBool HasText() { return mStoredList.HasText(); }
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
+  {
+    if (mStoredList.GetComponentAlphaBounds(aBuilder).IsEmpty())
+      return nsRect();
+    return GetBounds(aBuilder);
+  }
 
 #ifdef NS_DEBUG
   nsDisplayWrapList* GetStoredList() { return &mStoredList; }
 #endif
 
   virtual void HitTest(nsDisplayListBuilder *aBuilder, const nsRect& aRect,
                        HitTestState *aState, nsTArray<nsIFrame*> *aOutFrames);
   virtual nsRect GetBounds(nsDisplayListBuilder *aBuilder);
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1646,31 +1646,35 @@ nsLayoutUtils::GetAllInFlowRectsUnion(ns
   RectAccumulator accumulator;
   GetAllInFlowRects(aFrame, aRelativeTo, &accumulator);
   return accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect
           : accumulator.mResultRect;
 }
 
 nsRect
 nsLayoutUtils::GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
-                                       nsIFrame* aFrame)
+                                       nsIFrame* aFrame,
+                                       PRUint32 aFlags)
 {
   const nsStyleText* textStyle = aFrame->GetStyleText();
   if (!textStyle->mTextShadow)
     return aTextAndDecorationsRect;
 
   nsRect resultRect = aTextAndDecorationsRect;
   PRInt32 A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
   for (PRUint32 i = 0; i < textStyle->mTextShadow->Length(); ++i) {
+    nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
+    nsMargin blur = nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D);
+    if ((aFlags & EXCLUDE_BLUR_SHADOWS) && blur != nsMargin(0, 0, 0, 0))
+      continue;
+
     nsRect tmpRect(aTextAndDecorationsRect);
-    nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
 
     tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
-    tmpRect.Inflate(
-      nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
+    tmpRect.Inflate(blur);
 
     resultRect.UnionRect(resultRect, tmpRect);
   }
   return resultRect;
 }
 
 nsresult
 nsLayoutUtils::GetFontMetricsForFrame(const nsIFrame* aFrame,
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -655,23 +655,27 @@ public:
                                 RectCallback* aCallback);
 
   /**
    * Computes the union of all rects returned by GetAllInFlowRects. If
    * the union is empty, returns the first rect.
    */
   static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo);
 
+  enum {
+    EXCLUDE_BLUR_SHADOWS = 0x01
+  };
   /**
    * Takes a text-shadow array from the style properties of a given nsIFrame and
    * computes the union of those shadows along with the given initial rect.
    * If there are no shadows, the initial rect is returned.
    */
   static nsRect GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
-                                        nsIFrame* aFrame);
+                                        nsIFrame* aFrame,
+                                        PRUint32 aFlags = 0);
 
   /**
    * Get the font metrics corresponding to the frame's style data.
    * @param aFrame the frame
    * @param aFontMetrics the font metrics result
    * @return success or failure code
    */
   static nsresult GetFontMetricsForFrame(const nsIFrame* aFrame,
--- a/layout/generic/nsBulletFrame.cpp
+++ b/layout/generic/nsBulletFrame.cpp
@@ -192,25 +192,32 @@ public:
     MOZ_COUNT_CTOR(nsDisplayBullet);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayBullet() {
     MOZ_COUNT_DTOR(nsDisplayBullet);
   }
 #endif
 
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder)
+  {
+    return mFrame->GetVisualOverflowRect() + ToReferenceFrame();
+  }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
     aOutFrames->AppendElement(mFrame);
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsIRenderingContext* aCtx);
   NS_DISPLAY_DECL_NAME("Bullet", TYPE_BULLET)
 
-  virtual PRBool HasText() { return PR_TRUE; }
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
+  {
+    return GetBounds(aBuilder);
+  }
 };
 
 void nsDisplayBullet::Paint(nsDisplayListBuilder* aBuilder,
                             nsIRenderingContext* aCtx)
 {
   static_cast<nsBulletFrame*>(mFrame)->
     PaintBullet(*aCtx, ToReferenceFrame(), mVisibleRect);
 }
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -4057,17 +4057,20 @@ public:
     if (nsRect(ToReferenceFrame(), mFrame->GetSize()).Intersects(aRect)) {
       aOutFrames->AppendElement(mFrame);
     }
   }
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsIRenderingContext* aCtx);
   NS_DISPLAY_DECL_NAME("Text", TYPE_TEXT)
 
-  virtual PRBool HasText() { return PR_TRUE; }
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
+  {
+    return GetBounds(aBuilder);
+  }
 
   virtual void DisableComponentAlpha() { mDisableSubpixelAA = PR_TRUE; }
 
   PRPackedBool mDisableSubpixelAA;
 };
 
 void
 nsDisplayText::Paint(nsDisplayListBuilder* aBuilder,
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -2011,17 +2011,20 @@ public:
                      nsIRenderingContext* aCtx)
   {
     mChar->PaintForeground(mFrame->PresContext(), *aCtx,
                            ToReferenceFrame(), mIsSelected);
   }
 
   NS_DISPLAY_DECL_NAME("MathMLCharForeground", TYPE_MATHML_CHAR_FOREGROUND)
 
-  virtual PRBool HasText() { return PR_TRUE; }
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
+  {
+    return GetBounds(aBuilder);
+  }
 
 private:
   nsMathMLChar* mChar;
   PRPackedBool  mIsSelected;
 };
 
 #ifdef NS_DEBUG
 class nsDisplayMathMLCharDebug : public nsDisplayItem {
--- a/layout/xul/base/src/nsTextBoxFrame.cpp
+++ b/layout/xul/base/src/nsTextBoxFrame.cpp
@@ -79,20 +79,16 @@
 #endif // IBMBIDI
 
 #define CROP_LEFT   "left"
 #define CROP_RIGHT  "right"
 #define CROP_CENTER "center"
 #define CROP_START  "start"
 #define CROP_END    "end"
 
-// It's not clear to me whether nsLeafBoxFrame also uses some of the
-// nsBoxFrame bits, so use NS_STATE_BOX_CHILD_RESERVED to be safe.
-#define NS_STATE_NEED_LAYOUT NS_STATE_BOX_CHILD_RESERVED
-
 class nsAccessKeyInfo
 {
 public:
     PRInt32 mAccesskeyIndex;
     nscoord mBeforeWidth, mAccessWidth, mAccessUnderlineSize, mAccessOffset;
 };
 
 
@@ -115,17 +111,16 @@ NS_NewTextBoxFrame (nsIPresShell* aPresS
 NS_IMPL_FRAMEARENA_HELPERS(nsTextBoxFrame)
 
 
 NS_IMETHODIMP
 nsTextBoxFrame::AttributeChanged(PRInt32         aNameSpaceID,
                                  nsIAtom*        aAttribute,
                                  PRInt32         aModType)
 {
-    mState |= NS_STATE_NEED_LAYOUT;
     PRBool aResize;
     PRBool aRedraw;
 
     UpdateAttributes(aAttribute, aResize, aRedraw);
 
     if (aResize) {
         PresContext()->PresShell()->
             FrameNeedsReflow(this, nsIPresShell::eStyleChange,
@@ -142,34 +137,32 @@ nsTextBoxFrame::AttributeChanged(PRInt32
 
     return NS_OK;
 }
 
 nsTextBoxFrame::nsTextBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext):
   nsLeafBoxFrame(aShell, aContext), mAccessKeyInfo(nsnull), mCropType(CropRight),
   mNeedsReflowCallback(PR_FALSE)
 {
-    mState |= NS_STATE_NEED_LAYOUT;
     MarkIntrinsicWidthsDirty();
 }
 
 nsTextBoxFrame::~nsTextBoxFrame()
 {
     delete mAccessKeyInfo;
 }
 
 
 NS_IMETHODIMP
 nsTextBoxFrame::Init(nsIContent*      aContent,
                      nsIFrame*        aParent,
                      nsIFrame*        aPrevInFlow)
 {
     nsTextBoxFrameSuper::Init(aContent, aParent, aPrevInFlow);
 
-    mState |= NS_STATE_NEED_LAYOUT;
     PRBool aResize;
     PRBool aRedraw;
     UpdateAttributes(nsnull, aResize, aRedraw); /* update all */
 
     // register access key
     RegUnregAccessKey(PR_TRUE);
 
     return NS_OK;
@@ -344,17 +337,17 @@ public:
   }
 #endif
 
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsIRenderingContext* aCtx);
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder);
   NS_DISPLAY_DECL_NAME("XULTextBox", TYPE_XUL_TEXT_BOX)
 
-  virtual PRBool HasText() { return PR_TRUE; }
+  virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder);
 
   virtual void DisableComponentAlpha() { mDisableSubpixelAA = PR_TRUE; }
 
   PRPackedBool mDisableSubpixelAA;
 };
 
 void
 nsDisplayXULTextBox::Paint(nsDisplayListBuilder* aBuilder,
@@ -366,16 +359,23 @@ nsDisplayXULTextBox::Paint(nsDisplayList
     PaintTitle(*aCtx, mVisibleRect, ToReferenceFrame());
 }
 
 nsRect
 nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) {
   return mFrame->GetVisualOverflowRect() + ToReferenceFrame();
 }
 
+nsRect
+nsDisplayXULTextBox::GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder)
+{
+  return static_cast<nsTextBoxFrame*>(mFrame)->GetComponentAlphaBounds() +
+      ToReferenceFrame();
+}
+
 NS_IMETHODIMP
 nsTextBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                  const nsRect&           aDirtyRect,
                                  const nsDisplayListSet& aLists)
 {
     if (!IsVisibleForPainting(aBuilder))
       return NS_OK;
 
@@ -389,17 +389,17 @@ nsTextBoxFrame::BuildDisplayList(nsDispl
 void
 nsTextBoxFrame::PaintTitle(nsIRenderingContext& aRenderingContext,
                            const nsRect&        aDirtyRect,
                            nsPoint              aPt)
 {
     if (mTitle.IsEmpty())
         return;
 
-    nsRect textRect(CalcTextRect(aRenderingContext, aPt));
+    nsRect textRect = mTextDrawRect + aPt;
 
     // Paint the text shadow before doing any foreground stuff
     const nsStyleText* textStyle = GetStyleText();
     if (textStyle->mTextShadow) {
       // Text shadow happens with the last value being painted at the back,
       // ie. it is painted first.
       for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
         PaintOneShadow(aRenderingContext.ThebesContext(),
@@ -621,35 +621,16 @@ void nsTextBoxFrame::PaintOneShadow(gfxC
   // Remember that the box blur context has a device offset on it, so we don't need to
   // translate any coordinates to fit on the surface.
   DrawText(*renderingContext, shadowRect, &shadowColor);
   contextBoxBlur.DoPaint();
   aCtx->Restore();
 }
 
 void
-nsTextBoxFrame::LayoutTitle(nsPresContext*      aPresContext,
-                            nsIRenderingContext& aRenderingContext,
-                            const nsRect&        aRect)
-{
-    // and do caculations if our size changed
-    if ((mState & NS_STATE_NEED_LAYOUT)) {
-
-        // determine (cropped) title which fits in aRect.width and its width
-        CalculateTitleForWidth(aPresContext, aRenderingContext, aRect.width);
-
-        // determine if and at which position to put the underline
-        UpdateAccessIndex();
-
-        // ok layout complete
-        mState &= ~NS_STATE_NEED_LAYOUT;
-    }
-}
-
-void
 nsTextBoxFrame::CalculateUnderline(nsIRenderingContext& aRenderingContext)
 {
     if (mAccessKeyInfo && mAccessKeyInfo->mAccesskeyIndex != kNotFound) {
          // Calculate all fields of mAccessKeyInfo which
          // are the same for both BiDi and non-BiDi frames.
          const PRUnichar *titleString = mCroppedTitle.get();
          aRenderingContext.SetTextRunRTL(PR_FALSE);
          aRenderingContext.GetWidth(titleString[mAccessKeyInfo->mAccesskeyIndex],
@@ -660,60 +641,59 @@ nsTextBoxFrame::CalculateUnderline(nsIRe
          aRenderingContext.GetFontMetrics(metrics);
          metrics->GetUnderline(offset, mAccessKeyInfo->mAccessUnderlineSize);
          metrics->GetMaxAscent(baseline);
          NS_RELEASE(metrics);
          mAccessKeyInfo->mAccessOffset = baseline - offset;
     }
 }
 
-void
+nscoord
 nsTextBoxFrame::CalculateTitleForWidth(nsPresContext*      aPresContext,
                                        nsIRenderingContext& aRenderingContext,
                                        nscoord              aWidth)
 {
     if (mTitle.IsEmpty())
-        return;
+        return 0;
 
     nsLayoutUtils::SetFontFromStyle(&aRenderingContext, GetStyleContext());
 
     // see if the text will completely fit in the width given
-    mTitleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
-                                                mTitle.get(), mTitle.Length());
+    nscoord titleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+                                                       mTitle.get(), mTitle.Length());
 
-    if (mTitleWidth <= aWidth) {
+    if (titleWidth <= aWidth) {
         mCroppedTitle = mTitle;
 #ifdef IBMBIDI
         if (HasRTLChars(mTitle)) {
             mState |= NS_FRAME_IS_BIDI;
         }
 #endif // IBMBIDI
-        return;  // fits, done.
+        return titleWidth;  // fits, done.
     }
 
     const nsDependentString& kEllipsis = nsContentUtils::GetLocalizedEllipsis();
     // start with an ellipsis
     mCroppedTitle.Assign(kEllipsis);
 
     // see if the width is even smaller than the ellipsis
     // if so, clear the text (XXX set as many '.' as we can?).
     aRenderingContext.SetTextRunRTL(PR_FALSE);
-    aRenderingContext.GetWidth(kEllipsis, mTitleWidth);
+    aRenderingContext.GetWidth(kEllipsis, titleWidth);
 
-    if (mTitleWidth > aWidth) {
+    if (titleWidth > aWidth) {
         mCroppedTitle.SetLength(0);
-        mTitleWidth = 0;
-        return;
+        return 0;
     }
 
     // if the ellipsis fits perfectly, no use in trying to insert
-    if (mTitleWidth == aWidth)
-        return;
+    if (titleWidth == aWidth)
+        return titleWidth;
 
-    aWidth -= mTitleWidth;
+    aWidth -= titleWidth;
 
     // XXX: This whole block should probably take surrogates into account
     // XXX and clusters!
     // ok crop things
     switch (mCropType)
     {
         case CropNone:
         case CropRight:
@@ -733,17 +713,17 @@ nsTextBoxFrame::CalculateTitleForWidth(n
 #ifdef IBMBIDI
                 if (UCS2_CHAR_IS_BIDI(ch) ) {
                   mState |= NS_FRAME_IS_BIDI;
                 }
 #endif // IBMBIDI
             }
 
             if (i == 0)
-                return;
+                return titleWidth;
 
             // insert what character we can in.
             nsAutoString title( mTitle );
             title.Truncate(i);
             mCroppedTitle.Insert(title, 0);
         }
         break;
 
@@ -763,17 +743,17 @@ nsTextBoxFrame::CalculateTitleForWidth(n
 #ifdef IBMBIDI
                 if (UCS2_CHAR_IS_BIDI(ch) ) {
                   mState |= NS_FRAME_IS_BIDI;
                 }
 #endif // IBMBIDI
             }
 
             if (i == length-1)
-                return;
+                return titleWidth;
 
             nsAutoString copy;
             mTitle.Right(copy, length-1-i);
             mCroppedTitle += copy;
         }
         break;
 
         case CropCenter:
@@ -833,18 +813,18 @@ nsTextBoxFrame::CalculateTitleForWidth(n
                 rightPos--;
             }
 
             mCroppedTitle = leftString + kEllipsis + rightString;
         }
         break;
     }
 
-    mTitleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
-                                                mCroppedTitle.get(), mCroppedTitle.Length());
+    return nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
+                                         mCroppedTitle.get(), mCroppedTitle.Length());
 }
 
 #define OLD_ELLIPSIS NS_LITERAL_STRING("...")
 
 // the following block is to append the accesskey to mTitle if there is an accesskey
 // but the mTitle doesn't have the character
 void
 nsTextBoxFrame::UpdateAccessTitle()
@@ -955,35 +935,42 @@ nsTextBoxFrame::DoLayout(nsBoxLayoutStat
     if (mNeedsReflowCallback) {
         nsIReflowCallback* cb = new nsAsyncAccesskeyUpdate(this);
         if (cb) {
             PresContext()->PresShell()->PostReflowCallback(cb);
         }
         mNeedsReflowCallback = PR_FALSE;
     }
 
-    mState |= NS_STATE_NEED_LAYOUT;
+    nsresult rv = nsLeafBoxFrame::DoLayout(aBoxLayoutState);
 
-    nsresult rv = nsLeafBoxFrame::DoLayout(aBoxLayoutState);
+    CalcDrawRect(*aBoxLayoutState.GetRenderingContext());
 
     const nsStyleText* textStyle = GetStyleText();
     if (textStyle->mTextShadow) {
       nsRect bounds(nsPoint(0, 0), GetSize());
       nsOverflowAreas overflow(bounds, bounds);
       // Our scrollable overflow is our bounds; our visual overflow may
       // extend beyond that.
       nsPoint origin(0,0);
-      nsRect textRect = CalcTextRect(*aBoxLayoutState.GetRenderingContext(), origin);
       nsRect &vis = overflow.VisualOverflow();
-      vis.UnionRect(vis, nsLayoutUtils::GetTextShadowRectsUnion(textRect, this));
+      vis.UnionRect(vis, nsLayoutUtils::GetTextShadowRectsUnion(mTextDrawRect, this));
       FinishAndStoreOverflow(overflow, GetSize());
     }
+
     return rv;
 }
 
+nsRect
+nsTextBoxFrame::GetComponentAlphaBounds()
+{
+  return nsLayoutUtils::GetTextShadowRectsUnion(mTextDrawRect, this,
+                                                nsLayoutUtils::EXCLUDE_BLUR_SHADOWS);
+}
+
 PRBool
 nsTextBoxFrame::ComputesOwnOverflowArea()
 {
     return PR_TRUE;
 }
 
 /* virtual */ void
 nsTextBoxFrame::MarkIntrinsicWidthsDirty()
@@ -1017,45 +1004,51 @@ nsTextBoxFrame::CalcTextSize(nsBoxLayout
             GetTextSize(presContext, *rendContext,
                         mTitle, size, mAscent);
             mTextSize = size;
             mNeedsRecalc = PR_FALSE;
         }
     }
 }
 
-nsRect
-nsTextBoxFrame::CalcTextRect(nsIRenderingContext &aRenderingContext, const nsPoint &aTextOrigin)
+void
+nsTextBoxFrame::CalcDrawRect(nsIRenderingContext &aRenderingContext)
 {
-    nsRect textRect(aTextOrigin, GetSize());
+    nsRect textRect(nsPoint(0, 0), GetSize());
     nsMargin borderPadding;
     GetBorderAndPadding(borderPadding);
     textRect.Deflate(borderPadding);
+
     // determine (cropped) title and underline position
     nsPresContext* presContext = PresContext();
-    LayoutTitle(presContext, aRenderingContext, textRect);
+    // determine (cropped) title which fits in aRect.width and its width
+    nscoord titleWidth =
+        CalculateTitleForWidth(presContext, aRenderingContext, textRect.width);
+    // determine if and at which position to put the underline
+    UpdateAccessIndex();
 
     // make the rect as small as our (cropped) text.
     nscoord outerWidth = textRect.width;
-    textRect.width = mTitleWidth;
+    textRect.width = titleWidth;
 
     // Align our text within the overall rect by checking our text-align property.
     const nsStyleVisibility* vis = GetStyleVisibility();
     const nsStyleText* textStyle = GetStyleText();
 
     if (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_CENTER)
       textRect.x += (outerWidth - textRect.width)/2;
     else if (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_RIGHT ||
              (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_DEFAULT &&
               vis->mDirection == NS_STYLE_DIRECTION_RTL) ||
              (textStyle->mTextAlign == NS_STYLE_TEXT_ALIGN_END &&
               vis->mDirection == NS_STYLE_DIRECTION_LTR)) {
       textRect.x += (outerWidth - textRect.width);
     }
-    return textRect;
+
+    mTextDrawRect = textRect;
 }
 
 /**
  * Ok return our dimensions
  */
 nsSize
 nsTextBoxFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState)
 {
--- a/layout/xul/base/src/nsTextBoxFrame.h
+++ b/layout/xul/base/src/nsTextBoxFrame.h
@@ -83,16 +83,18 @@ public:
                               const nsDisplayListSet& aLists);
 
   virtual ~nsTextBoxFrame();
 
   void PaintTitle(nsIRenderingContext& aRenderingContext,
                   const nsRect&        aDirtyRect,
                   nsPoint              aPt);
 
+  nsRect GetComponentAlphaBounds();
+
   virtual PRBool ComputesOwnOverflowArea();
 
 protected:
   friend class nsAsyncAccesskeyUpdate;
   // Should be called only by nsAsyncAccesskeyUpdate.
   // Returns PR_TRUE if accesskey was updated.
   PRBool UpdateAccesskey(nsWeakFrame& aWeakThis);
   void UpdateAccessTitle();
@@ -102,23 +104,23 @@ protected:
   void LayoutTitle(nsPresContext*      aPresContext,
                    nsIRenderingContext& aRenderingContext,
                    const nsRect&        aRect);
 
   void CalculateUnderline(nsIRenderingContext& aRenderingContext);
 
   void CalcTextSize(nsBoxLayoutState& aBoxLayoutState);
 
-  nsRect CalcTextRect(nsIRenderingContext &aRenderingContext, const nsPoint &aTextOrigin);
+  void CalcDrawRect(nsIRenderingContext &aRenderingContext);
 
   nsTextBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext);
 
-  void CalculateTitleForWidth(nsPresContext*      aPresContext,
-                              nsIRenderingContext& aRenderingContext,
-                              nscoord              aWidth);
+  nscoord CalculateTitleForWidth(nsPresContext*      aPresContext,
+                                 nsIRenderingContext& aRenderingContext,
+                                 nscoord              aWidth);
 
   void GetTextSize(nsPresContext*      aPresContext,
                    nsIRenderingContext& aRenderingContext,
                    const nsString&      aString,
                    nsSize&              aSize,
                    nscoord&             aAscent);
 
   nsresult RegUnregAccessKey(PRBool aDoReg);
@@ -137,20 +139,20 @@ private:
                       nsCSSShadowItem* aShadowDetails,
                       const nscolor&   aForegroundColor,
                       const nsRect&    aDirtyRect);
 
   nsString mTitle;
   nsString mCroppedTitle;
   nsString mAccessKey;
   nsSize mTextSize;
+  nsRect mTextDrawRect;
   nsAccessKeyInfo* mAccessKeyInfo;
 
   CroppingStyle mCropType;
-  nscoord mTitleWidth;
   nscoord mAscent;
   PRPackedBool mNeedsRecalc;
   PRPackedBool mNeedsReflowCallback;
 
   static PRBool gAlwaysAppendAccessKey;
   static PRBool gAccessKeyPrefInitialized;
   static PRBool gInsertSeparatorBeforeAccessKey;
   static PRBool gInsertSeparatorPrefInitialized;