For continuous background inlines, apply the background image to bidi continuations in visual order, and for RTL blocks, in RTL order. bug=412093 r+sr+a1.9=roc
authoruriber@gmail.com
Tue, 22 Jan 2008 12:37:49 -0800
changeset 10539 55f9b8363bb3e81823d824cbed0ab5051b9d9522
parent 10538 45d7c1de55f56029b942c90454767f59b9cc35d6
child 10540 fc58d4552cf0bd2da9d96a7c2455cf13db130fd0
push id1
push userbsmedberg@mozilla.com
push dateThu, 20 Mar 2008 16:49:24 +0000
treeherdermozilla-central@61007906a1f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs412093
milestone1.9b3pre
For continuous background inlines, apply the background image to bidi continuations in visual order, and for RTL blocks, in RTL order. bug=412093 r+sr+a1.9=roc
layout/base/nsCSSRendering.cpp
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -64,16 +64,17 @@
 #include "nsCSSColorUtils.h"
 #include "nsITheme.h"
 #include "nsThemeConstants.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsLayoutUtils.h"
 #include "nsINameSpaceManager.h"
+#include "nsBlockFrame.h"
 
 #include "gfxContext.h"
 
 #define BORDER_FULL    0        //entire side
 #define BORDER_INSIDE  1        //inside half
 #define BORDER_OUTSIDE 2        //outside half
 
 //thickness of dashed line relative to dotted line
@@ -101,39 +102,85 @@ enum ePathTypes{
 
 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
 // recalculating this for each frame in a continuation (perf), hold
 // a cache of various coordinate information that we need in order
 // to paint inline backgrounds.
 struct InlineBackgroundData
 {
   InlineBackgroundData()
-      : mFrame(nsnull)
+      : mFrame(nsnull), mBlockFrame(nsnull)
   {
   }
 
   ~InlineBackgroundData()
   {
   }
 
   void Reset()
   {
     mBoundingBox.SetRect(0,0,0,0);
-    mContinuationPoint = mUnbrokenWidth = 0;
-    mFrame = nsnull;    
+    mContinuationPoint = mLineContinuationPoint = mUnbrokenWidth = 0;
+    mFrame = mBlockFrame = nsnull;
   }
 
   nsRect GetContinuousRect(nsIFrame* aFrame)
   {
     SetFrame(aFrame);
 
+    nscoord x;
+    if (mBidiEnabled) {
+      x = mLineContinuationPoint;
+
+      // Scan continuations on the same line as aFrame and accumulate the widths
+      // of frames that are to the left (if this is an LTR block) or right 
+      // (if it's RTL) of the current one.
+      PRBool isRtlBlock = (mBlockFrame->GetStyleVisibility()->mDirection ==
+                           NS_STYLE_DIRECTION_RTL);      
+      nscoord curOffset = aFrame->GetOffsetTo(mBlockFrame).x;
+
+      nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
+      // If the continuation is fluid we know inlineFrame is not on the same line.
+      // If it's not fluid, we need to test furhter to be sure.
+      while (inlineFrame && !inlineFrame->GetNextInFlow() &&
+             AreOnSameLine(aFrame, inlineFrame)) {
+        nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x;
+        if((isRtlBlock && frameXOffset >= curOffset) ||
+           (!isRtlBlock && frameXOffset < curOffset)) {
+          x += inlineFrame->GetSize().width;
+        }
+        inlineFrame = inlineFrame->GetPrevContinuation();
+      }
+
+      inlineFrame = aFrame->GetNextContinuation();
+      while (inlineFrame && !inlineFrame->GetPrevInFlow() &&
+             AreOnSameLine(aFrame, inlineFrame)) {
+        nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x;
+        if((isRtlBlock && frameXOffset >= curOffset) ||
+           (!isRtlBlock && frameXOffset < curOffset)) {
+          x += inlineFrame->GetSize().width;
+        }
+        inlineFrame = inlineFrame->GetNextContinuation();
+      }
+      if (isRtlBlock) {
+        // aFrame itself is also to the right of its left edge, so add its width.
+        x += aFrame->GetSize().width;
+        // x is now the distance from the left edge of aFrame to the right edge
+        // of the unbroken content. Change it to indicate the distance from the
+        // left edge of the unbroken content to the left edge of aFrame.
+        x = mUnbrokenWidth - x;
+      }
+    } else {
+      x = mContinuationPoint;
+    }
+
     // Assume background-origin: border and return a rect with offsets
     // relative to (0,0).  If we have a different background-origin,
     // then our rect should be deflated appropriately by our caller.
-    return nsRect(-mContinuationPoint, 0, mUnbrokenWidth, mFrame->GetSize().height);
+    return nsRect(-x, 0, mUnbrokenWidth, mFrame->GetSize().height);
   }
 
   nsRect GetBoundingRect(nsIFrame* aFrame)
   {
     SetFrame(aFrame);
 
     // Move the offsets relative to (0,0) which puts the bounding box into
     // our coordinate system rather than our parent's.  We do this by
@@ -148,16 +195,20 @@ struct InlineBackgroundData
   }
 
 protected:
   nsIFrame*     mFrame;
   nscoord       mContinuationPoint;
   nscoord       mUnbrokenWidth;
   nsRect        mBoundingBox;
 
+  PRBool        mBidiEnabled;
+  nsBlockFrame* mBlockFrame;
+  nscoord       mLineContinuationPoint;
+  
   void SetFrame(nsIFrame* aFrame)
   {
     NS_PRECONDITION(aFrame, "Need a frame");
 
     nsIFrame *prevContinuation = aFrame->GetPrevContinuation();
 
     if (!prevContinuation || mFrame != prevContinuation) {
       // Ok, we've got the wrong frame.  We have to start from scratch.
@@ -165,16 +216,22 @@ protected:
       Init(aFrame);
       return;
     }
 
     // Get our last frame's size and add its width to our continuation
     // point before we cache the new frame.
     mContinuationPoint += mFrame->GetSize().width;
 
+    // If this a new line, update mLineContinuationPoint.
+    if (mBidiEnabled &&
+        (aFrame->GetPrevInFlow() || !AreOnSameLine(mFrame, aFrame))) {
+       mLineContinuationPoint = mContinuationPoint;
+    }
+    
     mFrame = aFrame;
   }
 
   void Init(nsIFrame* aFrame)
   {    
     // Start with the previous flow frame as our continuation point
     // is the total of the widths of the previous frames.
     nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
@@ -193,16 +250,39 @@ protected:
     while (inlineFrame) {
       nsRect rect = inlineFrame->GetRect();
       mUnbrokenWidth += rect.width;
       mBoundingBox.UnionRect(mBoundingBox, rect);
       inlineFrame = inlineFrame->GetNextContinuation();
     }
 
     mFrame = aFrame;
+
+    mBidiEnabled = aFrame->PresContext()->BidiEnabled();
+    if (mBidiEnabled) {
+      // Find the containing block frame
+      nsIFrame* frame = aFrame;
+      nsresult rv = NS_ERROR_FAILURE;
+      while (frame &&
+             frame->IsFrameOfType(nsIFrame::eLineParticipant) &&
+             NS_FAILED(rv)) {
+        frame = frame->GetParent();
+        rv = frame->QueryInterface(kBlockFrameCID, (void**)&mBlockFrame);
+      }
+      NS_ASSERTION(NS_SUCCEEDED(rv) && mBlockFrame, "Cannot find containing block.");
+
+      mLineContinuationPoint = mContinuationPoint;
+    }
+  }
+  
+  PRBool AreOnSameLine(nsIFrame* aFrame1, nsIFrame* aFrame2) {
+    // Assumes that aFrame1 and aFrame2 are both decsendants of mBlockFrame.
+    nsBlockInFlowLineIterator it1(mBlockFrame, aFrame1);
+    nsBlockInFlowLineIterator it2(mBlockFrame, aFrame2);
+    return it1.GetLine() == it2.GetLine();
   }
 };
 
 static InlineBackgroundData* gInlineBGData = nsnull;
 
 // FillRect or InvertRect depending on the renderingaInvert parameter
 static void FillOrInvertRect(nsIRenderingContext& aRC,nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight, PRBool aInvert);
 static void FillOrInvertRect(nsIRenderingContext& aRC,const nsRect& aRect, PRBool aInvert);