Example #1
0
nsresult
TableBackgroundPainter::PaintTableFrame(nsTableFrame*         aTableFrame,
                                        nsTableRowGroupFrame* aFirstRowGroup,
                                        nsTableRowGroupFrame* aLastRowGroup,
                                        const nsMargin&       aDeflate)
{
  NS_PRECONDITION(aTableFrame, "null frame");
  TableBackgroundData tableData;
  tableData.SetFull(aTableFrame);
  tableData.mRect.MoveTo(0,0); //using table's coords
  tableData.mRect.Deflate(aDeflate);
  if (mIsBorderCollapse && tableData.ShouldSetBCBorder()) {
    if (aFirstRowGroup && aLastRowGroup && mNumCols > 0) {
      //only handle non-degenerate tables; we need a more robust BC model
      //to make degenerate tables' borders reasonable to deal with
      nsMargin border, tempBorder;
      nsTableColFrame* colFrame = aTableFrame->GetColFrame(mNumCols - 1);
      if (colFrame) {
        colFrame->GetContinuousBCBorderWidth(tempBorder);
      }
      border.right = tempBorder.right;

      aLastRowGroup->GetContinuousBCBorderWidth(tempBorder);
      border.bottom = tempBorder.bottom;

      nsTableRowFrame* rowFrame = aFirstRowGroup->GetFirstRow();
      if (rowFrame) {
        rowFrame->GetContinuousBCBorderWidth(tempBorder);
        border.top = tempBorder.top;
      }

      border.left = aTableFrame->GetContinuousLeftBCBorderWidth();

      nsresult rv = tableData.SetBCBorder(border, this);
      if (NS_FAILED(rv)) {
        tableData.Destroy(mPresContext);
        return rv;
      }
    }
  }
  if (tableData.IsVisible()) {
    nsCSSRendering::PaintBackgroundWithSC(mPresContext, mRenderingContext,
                                          tableData.mFrame, mDirtyRect,
                                          tableData.mRect + mRenderPt,
                                          tableData.mFrame->StyleContext(),
                                          *tableData.mBorder,
                                          mBGPaintFlags);
  }
  tableData.Destroy(mPresContext);
  return NS_OK;
}
Example #2
0
DrawResult
TableBackgroundPainter::PaintRow(nsTableRowFrame* aFrame,
                                 const TableBackgroundData& aRowGroupBGData,
                                 TableBackgroundData aRowBGData,
                                 bool             aPassThrough)
{
  MOZ_ASSERT(aFrame, "null frame");

  /* Load row data */
  WritingMode wm = aFrame->GetWritingMode();
  if (aPassThrough) {
    aRowBGData.MakeInvisible();
  } else {
    if (mIsBorderCollapse && aRowBGData.ShouldSetBCBorder()) {
      LogicalMargin border(wm);
      nsTableRowFrame* nextRow = aFrame->GetNextRow();
      if (nextRow) { //outer bStart after us is inner bEnd for us
        border.BEnd(wm) = nextRow->GetOuterBStartContBCBorderWidth();
      }
      else { //acquire rg's bEnd border
        nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame->GetParent());
        rowGroup->GetContinuousBCBorderWidth(wm, border);
      }
      //get the rest of the borders; will overwrite all but bEnd
      aFrame->GetContinuousBCBorderWidth(wm, border);

      aRowBGData.SetBCBorder(border.GetPhysicalMargin(wm));
    }
    aPassThrough = !aRowBGData.IsVisible();
  }

  /* Translate */
  if (eOrigin_TableRow == mOrigin) {
    /* If we originate from the row, then make the row the origin. */
    aRowBGData.mRect.MoveTo(0, 0);
  }
  //else: Use row group's coord system -> no translation necessary

  DrawResult result = DrawResult::SUCCESS;

  for (nsTableCellFrame* cell = aFrame->GetFirstCell(); cell; cell = cell->GetNextCell()) {
    nsRect cellBGRect, rowBGRect, rowGroupBGRect, colBGRect;
    ComputeCellBackgrounds(cell, aRowGroupBGData, aRowBGData,
                           cellBGRect, rowBGRect,
                           rowGroupBGRect, colBGRect);

    // Find the union of all the cell background layers.
    nsRect combinedRect(cellBGRect);
    combinedRect.UnionRect(combinedRect, rowBGRect);
    combinedRect.UnionRect(combinedRect, rowGroupBGRect);
    combinedRect.UnionRect(combinedRect, colBGRect);

    if (combinedRect.Intersects(mDirtyRect)) {
      bool passCell = aPassThrough || cell->IsPseudoStackingContextFromStyle();
      DrawResult cellResult =
        PaintCell(cell, aRowGroupBGData, aRowBGData,
                  cellBGRect, rowBGRect, rowGroupBGRect, colBGRect, passCell);

      UpdateDrawResult(&result, cellResult);
    }
  }

  return result;
}
Example #3
0
DrawResult
TableBackgroundPainter::PaintRowGroup(nsTableRowGroupFrame* aFrame,
                                      TableBackgroundData   aRowGroupBGData,
                                      bool                  aPassThrough)
{
  MOZ_ASSERT(aFrame, "null frame");

  nsTableRowFrame* firstRow = aFrame->GetFirstRow();
  WritingMode wm = aFrame->GetWritingMode();

  /* Load row group data */
  if (aPassThrough) {
    aRowGroupBGData.MakeInvisible();
  } else {
    if (mIsBorderCollapse && aRowGroupBGData.ShouldSetBCBorder()) {
      LogicalMargin border(wm);
      if (firstRow) {
        //pick up first row's bstart border (= rg bstart border)
        firstRow->GetContinuousBCBorderWidth(wm, border);
        /* (row group doesn't store its bstart border) */
      }
      //overwrite sides+bottom borders with rg's own
      aFrame->GetContinuousBCBorderWidth(wm, border);
      aRowGroupBGData.SetBCBorder(border.GetPhysicalMargin(wm));
    }
    aPassThrough = !aRowGroupBGData.IsVisible();
  }

  /* translate everything into row group coord system*/
  if (eOrigin_TableRowGroup != mOrigin) {
    TranslateContext(aRowGroupBGData.mRect.x, aRowGroupBGData.mRect.y);
  }
  nsRect rgRect = aRowGroupBGData.mRect;
  aRowGroupBGData.mRect.MoveTo(0, 0);

  /* Find the right row to start with */

  // Note that mDirtyRect  - mRenderPt is guaranteed to be in the row
  // group's coordinate system here, so passing its .y to
  // GetFirstRowContaining is ok.
  nscoord overflowAbove;
  nsIFrame* cursor = aFrame->GetFirstRowContaining(mDirtyRect.y - mRenderPt.y, &overflowAbove);

  // Sadly, it seems like there may be non-row frames in there... or something?
  // There are certainly null-checks in GetFirstRow() and GetNextRow().  :(
  while (cursor && cursor->GetType() != nsGkAtoms::tableRowFrame) {
    cursor = cursor->GetNextSibling();
  }

  // It's OK if cursor is null here.
  nsTableRowFrame* row = static_cast<nsTableRowFrame*>(cursor);
  if (!row) {
    // No useful cursor; just start at the top.  Don't bother to set up a
    // cursor; if we've gotten this far then we've already built the display
    // list for the rowgroup, so not having a cursor means that there's some
    // good reason we don't have a cursor and we shouldn't create one here.
    row = firstRow;
  }

  DrawResult result = DrawResult::SUCCESS;

  /* Finally paint */
  for (; row; row = row->GetNextRow()) {
    TableBackgroundData rowBackgroundData(row);

    // Be sure to consider our positions both pre- and post-relative
    // positioning, since we potentially need to paint at both places.
    nscoord rowY = std::min(rowBackgroundData.mRect.y, row->GetNormalPosition().y);

    // Intersect wouldn't handle rowspans.
    if (cursor &&
        (mDirtyRect.YMost() - mRenderPt.y) <= (rowY - overflowAbove)) {
      // All done; cells originating in later rows can't intersect mDirtyRect.
      break;
    }

    DrawResult rowResult =
      PaintRow(row, aRowGroupBGData, rowBackgroundData,
               aPassThrough || row->IsPseudoStackingContextFromStyle());

    UpdateDrawResult(&result, rowResult);
  }

  /* translate back into table coord system */
  if (eOrigin_TableRowGroup != mOrigin) {
    TranslateContext(-rgRect.x, -rgRect.y);
  }

  return result;
}
Example #4
0
nsresult
TableBackgroundPainter::PaintTable(nsTableFrame*   aTableFrame,
                                   const nsMargin& aDeflate,
                                   bool            aPaintTableBackground)
{
  NS_PRECONDITION(aTableFrame, "null table frame");

  nsTableFrame::RowGroupArray rowGroups;
  aTableFrame->OrderRowGroups(rowGroups);

  if (rowGroups.Length() < 1) { //degenerate case
    if (aPaintTableBackground) {
      PaintTableFrame(aTableFrame, nullptr, nullptr, nsMargin(0,0,0,0));
    }
    /* No cells; nothing else to paint */
    return NS_OK;
  }

  if (aPaintTableBackground) {
    PaintTableFrame(aTableFrame, rowGroups[0], rowGroups[rowGroups.Length() - 1],
                    aDeflate);
  }

  /*Set up column background/border data*/
  if (mNumCols > 0) {
    nsFrameList& colGroupList = aTableFrame->GetColGroups();
    NS_ASSERTION(colGroupList.FirstChild(), "table should have at least one colgroup");

    mCols = new ColData[mNumCols];
    if (!mCols) return NS_ERROR_OUT_OF_MEMORY;

    TableBackgroundData* cgData = nullptr;
    nsMargin border;
    /* BC left borders aren't stored on cols, but the previous column's
       right border is the next one's left border.*/
    //Start with table's left border.
    nscoord lastLeftBorder = aTableFrame->GetContinuousLeftBCBorderWidth();
    for (nsTableColGroupFrame* cgFrame = static_cast<nsTableColGroupFrame*>(colGroupList.FirstChild());
         cgFrame; cgFrame = static_cast<nsTableColGroupFrame*>(cgFrame->GetNextSibling())) {

      if (cgFrame->GetColCount() < 1) {
        //No columns, no cells, so no need for data
        continue;
      }

      /*Create data struct for column group*/
      cgData = new TableBackgroundData;
      if (!cgData) return NS_ERROR_OUT_OF_MEMORY;
      cgData->SetFull(cgFrame);
      if (mIsBorderCollapse && cgData->ShouldSetBCBorder()) {
        border.left = lastLeftBorder;
        cgFrame->GetContinuousBCBorderWidth(border);
        nsresult rv = cgData->SetBCBorder(border, this);
        if (NS_FAILED(rv)) {
          cgData->Destroy(mPresContext);
          delete cgData;
          return rv;
        }
      }

      // Boolean that indicates whether mCols took ownership of cgData
      bool cgDataOwnershipTaken = false;
      
      /*Loop over columns in this colgroup*/
      for (nsTableColFrame* col = cgFrame->GetFirstColumn(); col;
           col = static_cast<nsTableColFrame*>(col->GetNextSibling())) {
        /*Create data struct for column*/
        uint32_t colIndex = col->GetColIndex();
        NS_ASSERTION(colIndex < mNumCols, "prevent array boundary violation");
        if (mNumCols <= colIndex)
          break;
        mCols[colIndex].mCol.SetFull(col);
        //Bring column mRect into table's coord system
        mCols[colIndex].mCol.mRect.MoveBy(cgData->mRect.x, cgData->mRect.y);
        //link to parent colgroup's data
        mCols[colIndex].mColGroup = cgData;
        cgDataOwnershipTaken = true;
        if (mIsBorderCollapse) {
          border.left = lastLeftBorder;
          lastLeftBorder = col->GetContinuousBCBorderWidth(border);
          if (mCols[colIndex].mCol.ShouldSetBCBorder()) {
            nsresult rv = mCols[colIndex].mCol.SetBCBorder(border, this);
            if (NS_FAILED(rv)) return rv;
          }
        }
      }

      if (!cgDataOwnershipTaken) {
        cgData->Destroy(mPresContext);
        delete cgData;
      }
    }
  }

  for (uint32_t i = 0; i < rowGroups.Length(); i++) {
    nsTableRowGroupFrame* rg = rowGroups[i];
    mRowGroup.SetFrame(rg);
    // Need to compute the right rect via GetOffsetTo, since the row
    // group may not be a child of the table.
    mRowGroup.mRect.MoveTo(rg->GetOffsetTo(aTableFrame));
    if (mRowGroup.mRect.Intersects(mDirtyRect - mRenderPt)) {
      nsresult rv = PaintRowGroup(rg, rg->IsPseudoStackingContextFromStyle());
      if (NS_FAILED(rv)) return rv;
    }
  }
  return NS_OK;
}