make the lineiterator interface for tables a little more sane bug 388700 r/sr=roc a=mtschrep
authorbmlk@gmx.de
Wed, 20 Feb 2008 12:22:18 -0800
changeset 11963 d9f5acbb461900c67ad34af735e3c2c16d0b9c4f
parent 11962 e42675262ed4916279739be947ececc7e56634f8
child 11964 8a433dfb5fa586be0b2936bb1de337dda832de38
push idunknown
push userunknown
push dateunknown
reviewersmtschrep
bugs388700
milestone1.9b4pre
make the lineiterator interface for tables a little more sane bug 388700 r/sr=roc a=mtschrep
layout/tables/nsTableRowGroupFrame.cpp
layout/tables/nsTableRowGroupFrame.h
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -1594,97 +1594,89 @@ void nsTableRowGroupFrame::SetContinuous
     case NS_SIDE_LEFT:
       mLeftContBorderWidth = aPixelValue;
       return;
     default:
       NS_ERROR("invalid NS_SIDE argument");
   }
 }
 
-//nsILineIterator methods for nsTableFrame
+//nsILineIterator methods
 NS_IMETHODIMP
 nsTableRowGroupFrame::GetNumLines(PRInt32* aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
   *aResult = GetRowCount();
-  return *aResult; // XXX should return NS_OK
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTableRowGroupFrame::GetDirection(PRBool* aIsRightToLeft)
 {
   NS_ENSURE_ARG_POINTER(aIsRightToLeft);
-  *aIsRightToLeft = PR_FALSE;
+  // rtl is table wide @see nsTableIterator
+  nsTableFrame* table = nsTableFrame::GetTableFrame(this);
+  *aIsRightToLeft = (NS_STYLE_DIRECTION_RTL ==
+                     table->GetStyleVisibility()->mDirection);
   return NS_OK;
 }
   
 NS_IMETHODIMP
 nsTableRowGroupFrame::GetLine(PRInt32    aLineNumber, 
                               nsIFrame** aFirstFrameOnLine, 
                               PRInt32*   aNumFramesOnLine,
                               nsRect&    aLineBounds, 
                               PRUint32*  aLineFlags)
 {
   NS_ENSURE_ARG_POINTER(aFirstFrameOnLine);
   NS_ENSURE_ARG_POINTER(aNumFramesOnLine);
   NS_ENSURE_ARG_POINTER(aLineFlags);
 
-  nsTableFrame* parentFrame = nsTableFrame::GetTableFrame(this);
-  if (!parentFrame)
-    return NS_ERROR_FAILURE;
-
-  nsTableCellMap* cellMap = parentFrame->GetCellMap();
-  if (!cellMap)
-     return NS_ERROR_FAILURE;
+  nsTableFrame* table = nsTableFrame::GetTableFrame(this);
+  nsTableCellMap* cellMap = table->GetCellMap();
 
-  if (aLineNumber >= cellMap->GetRowCount())
-    return NS_ERROR_INVALID_ARG;
+  *aLineFlags = 0;
+  *aFirstFrameOnLine = nsnull;
+  *aNumFramesOnLine = 0;
+  aLineBounds.SetRect(0, 0, 0, 0);
   
-  *aLineFlags = 0;/// should we fill these in later?
-  // not gonna touch aLineBounds right now
-
-  CellData* firstCellData = cellMap->GetDataAt(aLineNumber, 0);
-  if (!firstCellData)
-    return NS_ERROR_FAILURE;
+  if ((aLineNumber < 0) || (aLineNumber >=  GetRowCount())) {
+    return NS_OK;
+  }
+  aLineNumber += GetStartRowIndex(); 
 
   *aNumFramesOnLine = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
-  *aFirstFrameOnLine = (nsIFrame*)firstCellData->GetCellFrame();
-  if (!(*aFirstFrameOnLine))
-  {
-    while((aLineNumber > 0)&&(!(*aFirstFrameOnLine)))
-    {
-      aLineNumber--;
-      firstCellData = cellMap->GetDataAt(aLineNumber, 0);
-      *aFirstFrameOnLine = (nsIFrame*)firstCellData->GetCellFrame();
+  if (*aNumFramesOnLine == 0) {
+    return NS_OK;
+  }
+  for (PRInt32 i = 0; i < *aNumFramesOnLine; i++) {
+    CellData* data = cellMap->GetDataAt(aLineNumber, i);
+    if (data && data->IsOrig()) {
+      *aFirstFrameOnLine = (nsIFrame*)data->GetCellFrame();
+      nsIFrame* parent = (*aFirstFrameOnLine)->GetParent();
+      aLineBounds = parent->GetRect();
+      return NS_OK;
     }
   }
-  if  (!(*aFirstFrameOnLine)) {
-    NS_ERROR("Failed to find cell frame for cell data");
-    *aNumFramesOnLine = 0;
-  }
-  return NS_OK;
+  NS_ERROR("cellmap is lying");
+  return NS_ERROR_FAILURE;
 }
   
 NS_IMETHODIMP
 nsTableRowGroupFrame::FindLineContaining(nsIFrame* aFrame, 
                                          PRInt32*  aLineNumberResult)
 {
   NS_ENSURE_ARG_POINTER(aFrame);
   NS_ENSURE_ARG_POINTER(aLineNumberResult);
-
-  // make sure it is a rowFrame in the RowGroup
-  // - it should be, but we do not validate in every case (see bug 88849)
-  if (aFrame->GetType() != nsGkAtoms::tableRowFrame) {
-    NS_WARNING("RowGroup contains a frame that is not a row");
-    *aLineNumberResult = 0;
-    return NS_ERROR_FAILURE;
-  } 
+  
+  NS_ASSERTION((aFrame->GetType() == nsGkAtoms::tableRowFrame),
+               "RowGroup contains a frame that is not a row");
 
   nsTableRowFrame* rowFrame = (nsTableRowFrame*)aFrame;
-  *aLineNumberResult = rowFrame->GetRowIndex();
+  *aLineNumberResult = rowFrame->GetRowIndex() - GetStartRowIndex();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTableRowGroupFrame::FindLineAt(nscoord  aY, 
                                  PRInt32* aLineNumberResult)
 {
@@ -1706,78 +1698,89 @@ nsTableRowGroupFrame::CheckLineOrder(PRI
   
 NS_IMETHODIMP
 nsTableRowGroupFrame::FindFrameAt(PRInt32    aLineNumber, 
                                   nscoord    aX, 
                                   nsIFrame** aFrameFound,
                                   PRBool*    aXIsBeforeFirstFrame, 
                                   PRBool*    aXIsAfterLastFrame)
 {
-  PRInt32 colCount = 0;
-  CellData* cellData;
-  nsIFrame* tempFrame = nsnull;
-
-  nsTableFrame* parentFrame = nsTableFrame::GetTableFrame(this);
-  if (!parentFrame)
-    return NS_ERROR_FAILURE;
-
-  nsTableCellMap* cellMap = parentFrame->GetCellMap();
-  if (!cellMap)
-     return NS_ERROR_FAILURE;
-
-  colCount = cellMap->GetColCount();
-
-  *aXIsBeforeFirstFrame = PR_FALSE;
-  *aXIsAfterLastFrame = PR_FALSE;
-
-  PRBool gotParentRect = PR_FALSE;
-  for (PRInt32 i = 0; i < colCount; i++)
-  {
-    cellData = cellMap->GetDataAt(aLineNumber, i);
-    if (!cellData)
-      continue; // we hit a cellmap hole
-    if (!cellData->IsOrig())
-      continue;
-    tempFrame = (nsIFrame*)cellData->GetCellFrame();
+   nsTableFrame* table = nsTableFrame::GetTableFrame(this);
+   nsTableCellMap* cellMap = table->GetCellMap();
+   
+   *aFrameFound = nsnull;
+   *aXIsBeforeFirstFrame = PR_TRUE;
+   *aXIsAfterLastFrame = PR_FALSE;
 
-    if (!tempFrame)
-      continue;
-    
-    nsRect tempRect = tempFrame->GetRect();//offsetting x to be in row coordinates
-    if(!gotParentRect)
-    {//only do this once
-      nsIFrame* tempParentFrame = tempFrame->GetParent();
-      if(!tempParentFrame)
-        return NS_ERROR_FAILURE;
-
-      aX -= tempParentFrame->GetPosition().x;
-      gotParentRect = PR_TRUE;
-    }
-
-    if (i==0 &&(aX <= 0))//short circuit for negative x coords
-    {
-      *aXIsBeforeFirstFrame = PR_TRUE;
-      *aFrameFound = tempFrame;
-      return NS_OK;
-    }
-    if (aX < tempRect.x)
-    {
-      return NS_ERROR_FAILURE;
-    }
-    if(aX < tempRect.XMost())
-    {
-      *aFrameFound = tempFrame;
-      return NS_OK;
-    }
+   aLineNumber += GetStartRowIndex();
+   PRInt32 numCells = cellMap->GetNumCellsOriginatingInRow(aLineNumber);
+   if (numCells == 0) {
+     return NS_OK;
+   }
+  
+   nsIFrame* frame = nsnull;
+   for (PRInt32 i = 0; i < numCells; i++) {
+     CellData* data = cellMap->GetDataAt(aLineNumber, i);
+     if (data && data->IsOrig()) {
+       frame = (nsIFrame*)data->GetCellFrame();
+       break;
+     }
+   }
+   NS_ASSERTION(frame, "cellmap is lying");
+   PRBool isRTL = (NS_STYLE_DIRECTION_RTL ==
+                   table->GetStyleVisibility()->mDirection);
+   
+   nsIFrame* closestFromLeft = nsnull;
+   nsIFrame* closestFromRight = nsnull;
+   PRInt32 n = numCells;
+   nsIFrame* firstFrame = frame;
+   while (n--) {
+     nsRect rect = frame->GetRect();
+     if (rect.width > 0) {
+       // If aX is inside this frame - this is it
+       if (rect.x <= aX && rect.XMost() > aX) {
+         closestFromLeft = closestFromRight = frame;
+         break;
+       }
+       if (rect.x < aX) {
+         if (!closestFromLeft ||
+             rect.XMost() > closestFromLeft->GetRect().XMost())
+           closestFromLeft = frame;
+       }
+       else {
+         if (!closestFromRight ||
+             rect.x < closestFromRight->GetRect().x)
+           closestFromRight = frame;
+       }
+     }
+     frame = frame->GetNextSibling();
+   }
+   if (!closestFromLeft && !closestFromRight) {
+     // All frames were zero-width. Just take the first one.
+     closestFromLeft = closestFromRight = firstFrame;
+   }
+   *aXIsBeforeFirstFrame = isRTL ? !closestFromRight : !closestFromLeft;
+   *aXIsAfterLastFrame =   isRTL ? !closestFromLeft : !closestFromRight;
+   if (closestFromLeft == closestFromRight) {
+     *aFrameFound = closestFromLeft;
+   }
+   else if (!closestFromLeft) {
+     *aFrameFound = closestFromRight;
+   }
+   else if (!closestFromRight) {
+     *aFrameFound = closestFromLeft;
+   }
+   else { // we're between two frames
+     nscoord delta = closestFromRight->GetRect().x -
+                     closestFromLeft->GetRect().XMost();
+     if (aX < closestFromLeft->GetRect().XMost() + delta/2)
+       *aFrameFound = closestFromLeft;
+     else
+       *aFrameFound = closestFromRight;
   }
-  //x coord not found in frame, return last frame
-  *aXIsAfterLastFrame = PR_TRUE;
-  *aFrameFound = tempFrame;
-  if (!(*aFrameFound))
-    return NS_ERROR_FAILURE;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsTableRowGroupFrame::GetNextSiblingOnLine(nsIFrame*& aFrame, 
                                            PRInt32    aLineNumber)
 {
   NS_ENSURE_ARG_POINTER(aFrame);
--- a/layout/tables/nsTableRowGroupFrame.h
+++ b/layout/tables/nsTableRowGroupFrame.h
@@ -221,81 +221,65 @@ public:
                                       nscoord        aWidth);
 
 // nsILineIterator methods
 public:
   // The table row is the equivalent to a line in block layout. 
   // The nsILineIterator assumes that a line resides in a block, this role is
   // fullfilled by the row group. Rows in table are counted relative to the
   // table. The row index of row corresponds to the cellmap coordinates. The
-  // number of lines in a table might be greater than the number of rows in a
-  // single row group, as there might be multiple row groups.
+  // line index with respect to a row group can be computed by substracting the
+  // row index of the first row in the row group.
    
-  /** Get the number of rows in a table
-    * @param aResult - pointer that holds the number of lines in a table
-    *                  XXX this currently returns the number of rows in a
-    *                  rowgroup rather than that of the table.
+  /** Get the number of rows in a row group
+    * @param aResult - pointer that holds the number of lines in a row group
     */
   NS_IMETHOD GetNumLines(PRInt32* aResult);
 
   /** @see nsILineIterator.h GetDirection
     * @param aIsRightToLeft - true if the table is rtl
-    *                         XXX returns always false
     */
   NS_IMETHOD GetDirection(PRBool* aIsRightToLeft);
   
   /** Return structural information about a line. 
-    * @param aLineNumber       - the index of the row relative to the table
+    * @param aLineNumber       - the index of the row relative to the row group
     *                            If the line-number is invalid then
     *                            aFirstFrameOnLine will be nsnull and 
     *                            aNumFramesOnLine will be zero.
-    *                            XXX this is what nsLineIterator::GetLine does
-    *                            the code here currently returns 
-    *                            NS_ERROR_FAILURE without setting the params
-    *                            as required.
     * @param aFirstFrameOnLine - the first cell frame that originates in row
     *                            with a rowindex that matches a line number
-    *                            XXX now this goes up to the row with cell
-    *                            that spans into this row.
     * @param aNumFramesOnLine  - return the numbers of cells originating in
     *                            this row
     * @param aLineBounds       - rect of the row
-    *                            XXX currently not implemented, nothing
-    *                            is written to aLineBounds
     * @param aLineFlags        - unused set to 0
     */
   NS_IMETHOD GetLine(PRInt32 aLineNumber,
                      nsIFrame** aFirstFrameOnLine,
                      PRInt32* aNumFramesOnLine,
                      nsRect& aLineBounds,
                      PRUint32* aLineFlags);
   
   /** Given a frame that's a child of the rowgroup, find which line its on.
     * @param aFrame       - frame, should be a row
-    * @param aIndexResult - row index if this a row frame. aIndexResult will be
-    *                       set to -1 if the frame cannot be found.
-    *                       XXX currently aIndexResult is set to 0 if aFrame is
-    *                       not a row and a error code is returned to the caller
-    *                       instead.
+    * @param aIndexResult - row index relative to the row group if this a row
+    *                       frame. aIndexResult will be set to -1 if the frame
+    *                       cannot be found.
     */
   NS_IMETHOD FindLineContaining(nsIFrame* aFrame, PRInt32* aLineNumberResult);
   
   /** not implemented
     * the function is also not called in our tree
     */
   NS_IMETHOD FindLineAt(nscoord aY, PRInt32* aLineNumberResult);
 
   /** Find the orginating cell frame on a row that is the nearest to the
     * coordinate X.
-    * XXX the design is completely broken if aX points to a point between 
-    * cells or in a cell that spans from rows above, the function will return
-    * NS_ERROR_FAILURE in this case.
-    * @param aLineNumber          - the index of the row relative to the table
+    * @param aLineNumber          - the index of the row relative to the row group
     * @param aX                   - X coordinate in twips relative to the
-    *                               originof the rowgroup
+    *                               origin of the row group
     * @param aFrameFound          - pointer to the cellframe
     * @param aXIsBeforeFirstFrame - the point is before the first originating
     *                               cellframe
     * @param aXIsAfterLastFrame   - the point is after the last originating
     *                               cellframe
     */
   NS_IMETHOD FindFrameAt(PRInt32 aLineNumber,
                          nscoord aX,