/** * The first and last rows can be affected by <rows> tags with borders or margin * gets first and last rows and their indexes. * If it fails because there are no rows then: * FirstRow is nsnull * LastRow is nsnull * aFirstIndex = -1 * aLastIndex = -1 */ void nsGrid::GetFirstAndLastRow(nsBoxLayoutState& aState, PRInt32& aFirstIndex, PRInt32& aLastIndex, nsGridRow*& aFirstRow, nsGridRow*& aLastRow, bool aIsHorizontal) { aFirstRow = nsnull; aLastRow = nsnull; aFirstIndex = -1; aLastIndex = -1; PRInt32 count = GetRowCount(aIsHorizontal); if (count == 0) return; // We could have collapsed columns either before or after our index. // they should not count. So if we are the 5th row and the first 4 are // collaped we become the first row. Or if we are the 9th row and // 10 up to the last row are collapsed we then become the last. // see if we are first PRInt32 i; for (i=0; i < count; i++) { nsGridRow* row = GetRowAt(i,aIsHorizontal); if (!row->IsCollapsed(aState)) { aFirstIndex = i; aFirstRow = row; break; } } // see if we are last for (i=count-1; i >= 0; i--) { nsGridRow* row = GetRowAt(i,aIsHorizontal); if (!row->IsCollapsed(aState)) { aLastIndex = i; aLastRow = row; break; } } }
NS_IMETHODIMP nsARIAGridAccessible::UnselectRow(PRInt32 aRow) { if (IsDefunct()) return NS_ERROR_FAILURE; nsCOMPtr<nsIAccessible> row = GetRowAt(aRow); NS_ENSURE_ARG(row); return SetARIASelected(row, PR_FALSE); }
// Iterate over all valid rows in this batch void RowBatch::Iterate(CodeGen &codegen, RowBatch::IterateCallback &cb) { // The starting position in the batch llvm::Value *start = codegen.Const32(0); // The ending position in the batch llvm::Value *end = GetNumValidRows(codegen); // Generating the loop std::vector<lang::Loop::LoopVariable> loop_vars = { {"readIdx", start}, {"writeIdx", codegen.Const32(0)}}; llvm::Value *loop_cond = codegen->CreateICmpULT(start, end); lang::Loop batch_loop{codegen, loop_cond, loop_vars}; { // Pull out loop vars for convenience auto *batch_pos = batch_loop.GetLoopVar(0); auto *write_pos = batch_loop.GetLoopVar(1); // Create an output tracker to track the final position of the row OutputTracker tracker{GetSelectionVector(), write_pos}; // Get the current row RowBatch::Row row = GetRowAt(batch_pos, &tracker); // Invoke callback cb.ProcessRow(row); // The next read position is one next auto *next_read_pos = codegen->CreateAdd(batch_pos, codegen.Const32(1)); // The write position from the output track auto *next_write_pos = tracker.GetFinalOutputPos(); // Close up loop llvm::Value *loop_cond = codegen->CreateICmpULT(next_read_pos, end); batch_loop.LoopEnd(loop_cond, {next_read_pos, next_write_pos}); } // After the batch loop, we need to reset the size of the selection vector std::vector<llvm::Value *> final_vals; batch_loop.CollectFinalLoopVariables(final_vals); // Mark the last position in the batch UpdateWritePosition(final_vals[1]); }
NS_IMETHODIMP nsARIAGridAccessible::GetCellAt(PRInt32 aRowIndex, PRInt32 aColumnIndex, nsIAccessible **aAccessible) { NS_ENSURE_ARG_POINTER(aAccessible); *aAccessible = nsnull; if (IsDefunct()) return NS_ERROR_FAILURE; nsCOMPtr<nsIAccessible> row = GetRowAt(aRowIndex); NS_ENSURE_ARG(row); nsCOMPtr<nsIAccessible> cell = GetCellInRowAt(row, aColumnIndex); NS_ENSURE_ARG(cell); NS_ADDREF(*aAccessible = cell); return NS_OK; }
void nsGrid::PrintCellMap() { printf("-----Columns------\n"); for (int x=0; x < mColumnCount; x++) { nsGridRow* column = GetColumnAt(x); printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax); } printf("\n-----Rows------\n"); for (x=0; x < mRowCount; x++) { nsGridRow* column = GetRowAt(x); printf("%d(pf=%d, mn=%d, mx=%d) ", x, column->mPref, column->mMin, column->mMax); } printf("\n"); }
NS_IMETHODIMP nsARIAGridAccessible::IsRowSelected(PRInt32 aRow, PRBool *aIsSelected) { NS_ENSURE_ARG_POINTER(aIsSelected); *aIsSelected = PR_FALSE; if (IsDefunct()) return NS_ERROR_FAILURE; nsCOMPtr<nsIAccessible> row = GetRowAt(aRow); NS_ENSURE_ARG(row); if (!nsAccUtils::IsARIASelected(row)) { nsCOMPtr<nsIAccessible> cell; while ((cell = GetNextCellInRow(row, cell))) { if (!nsAccUtils::IsARIASelected(cell)) return NS_OK; } } *aIsSelected = PR_TRUE; return NS_OK; }
NS_IMETHODIMP nsARIAGridAccessible::IsCellSelected(PRInt32 aRow, PRInt32 aColumn, PRBool *aIsSelected) { NS_ENSURE_ARG_POINTER(aIsSelected); *aIsSelected = PR_FALSE; if (IsDefunct()) return NS_ERROR_FAILURE; nsCOMPtr<nsIAccessible> row(GetRowAt(aRow)); NS_ENSURE_ARG(row); if (!nsAccUtils::IsARIASelected(row)) { nsCOMPtr<nsIAccessible> cell(GetCellInRowAt(row, aColumn)); NS_ENSURE_ARG(cell); if (!nsAccUtils::IsARIASelected(cell)) return NS_OK; } *aIsSelected = PR_TRUE; return NS_OK; }
NS_IMETHODIMP nsARIAGridAccessible::IsRowSelected(PRInt32 aRow, PRBool *aIsSelected) { NS_ENSURE_ARG_POINTER(aIsSelected); *aIsSelected = PR_FALSE; if (IsDefunct()) return NS_ERROR_FAILURE; nsAccessible *row = GetRowAt(aRow); NS_ENSURE_ARG(row); if (!nsAccUtils::IsARIASelected(row)) { AccIterator cellIter(row, filters::GetCell); nsAccessible *cell = nsnull; while ((cell = cellIter.GetNext())) { if (!nsAccUtils::IsARIASelected(cell)) return NS_OK; } } *aIsSelected = PR_TRUE; return NS_OK; }
nscoord nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, PRInt32 aIndex, bool aIsHorizontal) { RebuildIfNeeded(); nsGridRow* row = GetRowAt(aIndex, aIsHorizontal); if (row->IsCollapsed(aState)) return 0; if (row->IsMaxSet()) return row->mMax; nsIBox* box = row->mBox; // set in CSS? if (box) { bool widthSet, heightSet; nsSize cssSize(-1, -1); nsIBox::AddCSSMaxSize(box, cssSize, widthSet, heightSet); row->mMax = GET_HEIGHT(cssSize, aIsHorizontal); // yep do nothing. if (row->mMax != -1) return row->mMax; } // get the offsets so they are cached. nscoord top; nscoord bottom; GetRowOffsets(aState, aIndex, top, bottom, aIsHorizontal); // is the row bogus? If so then just ask it for its size // it should not be affected by cells in the grid. if (row->mIsBogus) { nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE); if (box) { size = box->GetPrefSize(aState); nsBox::AddMargin(box, size); nsGridLayout2::AddOffset(aState, box, size); } row->mMax = GET_HEIGHT(size, aIsHorizontal); return row->mMax; } nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE); nsGridCell* child; PRInt32 count = GetColumnCount(aIsHorizontal); for (PRInt32 i=0; i < count; i++) { if (aIsHorizontal) child = GetCellAt(i,aIndex); else child = GetCellAt(aIndex,i); // ignore collapsed children if (!child->IsCollapsed(aState)) { nsSize min = child->GetMinSize(aState); nsSize childSize = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState)); nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal); } } row->mMax = GET_HEIGHT(size, aIsHorizontal) + top + bottom; return row->mMax; }
/** * A row can have a top and bottom offset. Usually this is just the top and bottom border/padding. * However if the row is the first or last it could be affected by the fact a column or columns could * have a top or bottom margin. */ void nsGrid::GetRowOffsets(nsBoxLayoutState& aState, PRInt32 aIndex, nscoord& aTop, nscoord& aBottom, bool aIsHorizontal) { RebuildIfNeeded(); nsGridRow* row = GetRowAt(aIndex, aIsHorizontal); if (row->IsOffsetSet()) { aTop = row->mTop; aBottom = row->mBottom; return; } // first get the rows top and bottom border and padding nsIBox* box = row->GetBox(); // add up all the padding nsMargin margin(0,0,0,0); nsMargin border(0,0,0,0); nsMargin padding(0,0,0,0); nsMargin totalBorderPadding(0,0,0,0); nsMargin totalMargin(0,0,0,0); // if there is a box and it's not bogus take its // borders padding into account if (box && !row->mIsBogus) { if (!box->IsCollapsed(aState)) { // get real border and padding. GetBorderAndPadding // is redefined on nsGridRowLeafFrame. If we called it here // we would be in finite recurson. box->GetBorder(border); box->GetPadding(padding); totalBorderPadding += border; totalBorderPadding += padding; } // if we are the first or last row // take into account <rows> tags around us // that could have borders or margins. // fortunately they only affect the first // and last row inside the <rows> tag totalMargin = GetBoxTotalMargin(box, aIsHorizontal); } if (aIsHorizontal) { row->mTop = totalBorderPadding.top; row->mBottom = totalBorderPadding.bottom; row->mTopMargin = totalMargin.top; row->mBottomMargin = totalMargin.bottom; } else { row->mTop = totalBorderPadding.left; row->mBottom = totalBorderPadding.right; row->mTopMargin = totalMargin.left; row->mBottomMargin = totalMargin.right; } // if we are the first or last row take into account the top and bottom borders // of each columns. // If we are the first row then get the largest top border/padding in // our columns. If that's larger than the rows top border/padding use it. // If we are the last row then get the largest bottom border/padding in // our columns. If that's larger than the rows bottom border/padding use it. PRInt32 firstIndex = 0; PRInt32 lastIndex = 0; nsGridRow* firstRow = nsnull; nsGridRow* lastRow = nsnull; GetFirstAndLastRow(aState, firstIndex, lastIndex, firstRow, lastRow, aIsHorizontal); if (aIndex == firstIndex || aIndex == lastIndex) { nscoord maxTop = 0; nscoord maxBottom = 0; // run through the columns. Look at each column // pick the largest top border or bottom border PRInt32 count = GetColumnCount(aIsHorizontal); for (PRInt32 i=0; i < count; i++) { nsMargin totalChildBorderPadding(0,0,0,0); nsGridRow* column = GetColumnAt(i,aIsHorizontal); nsIBox* box = column->GetBox(); if (box) { // ignore collapsed children if (!box->IsCollapsed(aState)) { // include the margin of the columns. To the row // at this point border/padding and margins all added // up to more needed space. margin = GetBoxTotalMargin(box, !aIsHorizontal); // get real border and padding. GetBorderAndPadding // is redefined on nsGridRowLeafFrame. If we called it here // we would be in finite recurson. box->GetBorder(border); box->GetPadding(padding); totalChildBorderPadding += border; totalChildBorderPadding += padding; totalChildBorderPadding += margin; } nscoord top; nscoord bottom; // pick the largest top margin if (aIndex == firstIndex) { if (aIsHorizontal) { top = totalChildBorderPadding.top; } else { top = totalChildBorderPadding.left; } if (top > maxTop) maxTop = top; } // pick the largest bottom margin if (aIndex == lastIndex) { if (aIsHorizontal) { bottom = totalChildBorderPadding.bottom; } else { bottom = totalChildBorderPadding.right; } if (bottom > maxBottom) maxBottom = bottom; } } // If the biggest top border/padding the columns is larger than this rows top border/padding // the use it. if (aIndex == firstIndex) { if (maxTop > (row->mTop + row->mTopMargin)) row->mTop = maxTop - row->mTopMargin; } // If the biggest bottom border/padding the columns is larger than this rows bottom border/padding // the use it. if (aIndex == lastIndex) { if (maxBottom > (row->mBottom + row->mBottomMargin)) row->mBottom = maxBottom - row->mBottomMargin; } } } aTop = row->mTop; aBottom = row->mBottom; }
nsGridRow* nsGrid::GetColumnAt(PRInt32 aIndex, bool aIsHorizontal) { return GetRowAt(aIndex, !aIsHorizontal); }
/** * This get the flexibilty of the row at aIndex. It's not trivial. There are a few * things we need to look at. Specifically we need to see if any <rows> or <columns> * tags are around us. Their flexibilty will affect ours. */ nscoord nsGrid::GetRowFlex(nsBoxLayoutState& aState, PRInt32 aIndex, bool aIsHorizontal) { RebuildIfNeeded(); nsGridRow* row = GetRowAt(aIndex, aIsHorizontal); if (row->IsFlexSet()) return row->mFlex; nsIBox* box = row->mBox; row->mFlex = 0; if (box) { // We need our flex but a inflexible row could be around us. If so // neither are we. However if its the row tag just inside the grid it won't // affect us. We need to do this for this case: // <grid> // <rows> // <rows> // this is not flexible. So our children should not be flexible // <row flex="1"/> // <row flex="1"/> // </rows> // <row/> // </rows> // </grid> // // or.. // // <grid> // <rows> // <rows> // this is not flexible. So our children should not be flexible // <rows flex="1"> // <row flex="1"/> // <row flex="1"/> // </rows> // <row/> // </rows> // </row> // </grid> // So here is how it looks // // <grid> // <rows> // parentsParent // <rows> // parent // <row flex="1"/> // <row flex="1"/> // </rows> // <row/> // </rows> // </grid> // so the answer is simple: 1) Walk our parent chain. 2) If we find // someone who is not flexible and they aren't the rows immediately in // the grid. 3) Then we are not flexible box = GetScrollBox(box); nsIBox* parent = box->GetParentBox(); nsIBox* parentsParent=nsnull; while(parent) { parent = GetScrollBox(parent); parentsParent = parent->GetParentBox(); // if our parents parent is not a grid // the get its flex. If its 0 then we are // not flexible. if (parentsParent) { if (!IsGrid(parentsParent)) { nscoord flex = parent->GetFlex(aState); nsIBox::AddCSSFlex(aState, parent, flex); if (flex == 0) { row->mFlex = 0; return row->mFlex; } } else break; } parent = parentsParent; } // get the row flex. row->mFlex = box->GetFlex(aState); nsIBox::AddCSSFlex(aState, box, row->mFlex); } return row->mFlex; }