tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GridLines.cpp (14816B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "GridLines.h"
      8 
      9 #include "GridDimension.h"
     10 #include "GridLine.h"
     11 #include "mozilla/dom/GridArea.h"
     12 #include "mozilla/dom/GridBinding.h"
     13 #include "nsGridContainerFrame.h"
     14 
     15 namespace mozilla::dom {
     16 
     17 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridLines, mParent, mLines)
     18 NS_IMPL_CYCLE_COLLECTING_ADDREF(GridLines)
     19 NS_IMPL_CYCLE_COLLECTING_RELEASE(GridLines)
     20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridLines)
     21  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     22  NS_INTERFACE_MAP_ENTRY(nsISupports)
     23 NS_INTERFACE_MAP_END
     24 
     25 GridLines::GridLines(GridDimension* aParent) : mParent(aParent) {
     26  MOZ_ASSERT(aParent, "Should never be instantiated with a null GridDimension");
     27 }
     28 
     29 GridLines::~GridLines() = default;
     30 
     31 JSObject* GridLines::WrapObject(JSContext* aCx,
     32                                JS::Handle<JSObject*> aGivenProto) {
     33  return GridLines_Binding::Wrap(aCx, this, aGivenProto);
     34 }
     35 
     36 uint32_t GridLines::Length() const { return mLines.Length(); }
     37 
     38 GridLine* GridLines::Item(uint32_t aIndex) {
     39  return mLines.SafeElementAt(aIndex);
     40 }
     41 
     42 GridLine* GridLines::IndexedGetter(uint32_t aIndex, bool& aFound) {
     43  aFound = aIndex < mLines.Length();
     44  if (!aFound) {
     45    return nullptr;
     46  }
     47  return mLines[aIndex];
     48 }
     49 
     50 static void AddLineNameIfNotPresent(nsTArray<RefPtr<nsAtom>>& aLineNames,
     51                                    nsAtom* aName) {
     52  if (!aLineNames.Contains(aName)) {
     53    aLineNames.AppendElement(aName);
     54  }
     55 }
     56 
     57 static void AddLineNamesIfNotPresent(nsTArray<RefPtr<nsAtom>>& aLineNames,
     58                                     const nsTArray<RefPtr<nsAtom>>& aNames) {
     59  for (const auto& name : aNames) {
     60    AddLineNameIfNotPresent(aLineNames, name);
     61  }
     62 }
     63 
     64 void GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
     65                            const ComputedGridLineInfo* aLineInfo,
     66                            const nsTArray<RefPtr<GridArea>>& aAreas,
     67                            bool aIsRow) {
     68  MOZ_ASSERT(aLineInfo);
     69  mLines.Clear();
     70 
     71  if (!aTrackInfo) {
     72    return;
     73  }
     74 
     75  uint32_t lineCount =
     76      aTrackInfo->mEndFragmentTrack - aTrackInfo->mStartFragmentTrack + 1;
     77 
     78  // If there is at least one track, line count is one more
     79  // than the number of tracks.
     80  if (lineCount > 0) {
     81    nscoord lastTrackEdge = 0;
     82    nscoord startOfNextTrack;
     83    uint32_t repeatIndex = 0;
     84    uint32_t numRepeatTracks = aTrackInfo->mRemovedRepeatTracks.Length();
     85    uint32_t numAddedLines = 0;
     86 
     87    // For the calculation of negative line numbers, we need to know
     88    // the total number of leading implicit and explicit tracks.
     89    // This might be different from the number of tracks sizes in
     90    // aTrackInfo, because some of those tracks may be auto-fits that
     91    // have been removed.
     92    uint32_t leadingTrackCount =
     93        aTrackInfo->mNumLeadingImplicitTracks + aTrackInfo->mNumExplicitTracks;
     94    if (numRepeatTracks > 0) {
     95      for (auto& removedTrack : aTrackInfo->mRemovedRepeatTracks) {
     96        if (removedTrack) {
     97          ++leadingTrackCount;
     98        }
     99      }
    100    }
    101 
    102    for (uint32_t i = aTrackInfo->mStartFragmentTrack;
    103         i < aTrackInfo->mEndFragmentTrack + 1; i++) {
    104      // Since line indexes are 1-based, calculate a 1-based value
    105      // for this track to simplify some calculations.
    106      const uint32_t line1Index = i + 1;
    107 
    108      startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack)
    109                             ? aTrackInfo->mPositions[i]
    110                             : lastTrackEdge;
    111 
    112      // Get the line names for the current line. aLineInfo->mNames
    113      // may contain duplicate names. This is intentional, since grid
    114      // layout works fine with duplicate names, and we don't want to
    115      // detect and remove duplicates in layout since it is an O(n^2)
    116      // problem. We do the work here since this is only run when
    117      // requested by devtools, and slowness here will not affect
    118      // normal browsing.
    119      nsTArray<RefPtr<nsAtom>> empty{};
    120      const nsTArray<RefPtr<nsAtom>>& possiblyDuplicateLineNames(
    121          aLineInfo->mNames.SafeElementAt(i, empty));
    122 
    123      nsTArray<RefPtr<nsAtom>> lineNames;
    124      AddLineNamesIfNotPresent(lineNames, possiblyDuplicateLineNames);
    125 
    126      // Add in names from grid areas where this line is used as a boundary.
    127      for (auto area : aAreas) {
    128        // We specifically ignore line names from implicitly named areas,
    129        // because it can be confusing for designers who might naturally use
    130        // a named line of "-start" or "-end" and create an implicit named
    131        // area without meaning to.
    132        if (area->Type() == GridDeclaration::Implicit) {
    133          continue;
    134        }
    135 
    136        bool haveNameToAdd = false;
    137        nsAutoString nameToAdd;
    138        area->GetName(nameToAdd);
    139        if (aIsRow) {
    140          if (area->RowStart() == line1Index) {
    141            haveNameToAdd = true;
    142            nameToAdd.AppendLiteral("-start");
    143          } else if (area->RowEnd() == line1Index) {
    144            haveNameToAdd = true;
    145            nameToAdd.AppendLiteral("-end");
    146          }
    147        } else {
    148          if (area->ColumnStart() == line1Index) {
    149            haveNameToAdd = true;
    150            nameToAdd.AppendLiteral("-start");
    151          } else if (area->ColumnEnd() == line1Index) {
    152            haveNameToAdd = true;
    153            nameToAdd.AppendLiteral("-end");
    154          }
    155        }
    156 
    157        if (haveNameToAdd) {
    158          RefPtr<nsAtom> name = NS_Atomize(nameToAdd);
    159          AddLineNameIfNotPresent(lineNames, name);
    160        }
    161      }
    162 
    163      if (i >= (aTrackInfo->mRepeatFirstTrack +
    164                aTrackInfo->mNumLeadingImplicitTracks) &&
    165          repeatIndex < numRepeatTracks) {
    166        numAddedLines += AppendRemovedAutoFits(
    167            aTrackInfo, aLineInfo, lastTrackEdge, repeatIndex, numRepeatTracks,
    168            leadingTrackCount, lineNames);
    169      }
    170 
    171      // If this line is the one that ends a repeat, then add
    172      // in the mNamesFollowingRepeat names from aLineInfo.
    173      if (numRepeatTracks > 0 && i == (aTrackInfo->mRepeatFirstTrack +
    174                                       aTrackInfo->mNumLeadingImplicitTracks +
    175                                       numRepeatTracks - numAddedLines)) {
    176        AddLineNamesIfNotPresent(lineNames, aLineInfo->mNamesFollowingRepeat);
    177      }
    178 
    179      RefPtr<GridLine> line = new GridLine(this);
    180      mLines.AppendElement(line);
    181      MOZ_ASSERT(line1Index > 0, "line1Index must be positive.");
    182      bool isBeforeFirstExplicit =
    183          (line1Index <= aTrackInfo->mNumLeadingImplicitTracks);
    184      bool isAfterLastExplicit = line1Index > (leadingTrackCount + 1);
    185      // Calculate an actionable line number for this line, that could be used
    186      // in a css grid property to align a grid item or area at that line.
    187      // For implicit lines that appear before line 1, report a number of 0.
    188      // We can't report negative indexes, because those have a different
    189      // meaning in the css grid spec (negative indexes are negative-1-based
    190      // from the end of the grid decreasing towards the front).
    191      uint32_t lineNumber = isBeforeFirstExplicit
    192                                ? 0
    193                                : (line1Index + numAddedLines -
    194                                   aTrackInfo->mNumLeadingImplicitTracks);
    195 
    196      // The negativeNumber is counted back from the leadingTrackCount.
    197      int32_t lineNegativeNumber =
    198          isAfterLastExplicit
    199              ? 0
    200              : (line1Index + numAddedLines - (leadingTrackCount + 2));
    201      GridDeclaration lineType = (isBeforeFirstExplicit || isAfterLastExplicit)
    202                                     ? GridDeclaration::Implicit
    203                                     : GridDeclaration::Explicit;
    204      line->SetLineValues(
    205          lineNames, nsPresContext::AppUnitsToDoubleCSSPixels(lastTrackEdge),
    206          nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack -
    207                                                   lastTrackEdge),
    208          lineNumber, lineNegativeNumber, lineType);
    209 
    210      if (i < aTrackInfo->mEndFragmentTrack) {
    211        lastTrackEdge = aTrackInfo->mPositions[i] + aTrackInfo->mSizes[i];
    212      }
    213    }
    214 
    215    // Define a function that gets the mLines index for a given line number.
    216    // This is necessary since it's possible for a line number to not be
    217    // represented in mLines. If this is the case, then return  -1.
    218    const int32_t lineCount = mLines.Length();
    219    const uint32_t lastLineNumber = mLines[lineCount - 1]->Number();
    220    auto IndexForLineNumber =
    221        [lineCount, lastLineNumber](uint32_t aLineNumber) -> int32_t {
    222      if (lastLineNumber == 0) {
    223        // None of the lines have addressable numbers, so none of them can have
    224        // aLineNumber
    225        return -1;
    226      }
    227 
    228      int32_t possibleIndex = (int32_t)aLineNumber - 1;
    229      if (possibleIndex < 0 || possibleIndex > lineCount - 1) {
    230        // aLineNumber is not represented in mLines.
    231        return -1;
    232      }
    233 
    234      return possibleIndex;
    235    };
    236 
    237    // Post-processing loop for implicit grid areas.
    238    for (const auto& area : aAreas) {
    239      if (area->Type() == GridDeclaration::Implicit) {
    240        // Get the appropriate indexes for the area's start and end lines as
    241        // they are represented in mLines.
    242        int32_t startIndex =
    243            IndexForLineNumber(aIsRow ? area->RowStart() : area->ColumnStart());
    244        int32_t endIndex =
    245            IndexForLineNumber(aIsRow ? area->RowEnd() : area->ColumnEnd());
    246 
    247        // If both start and end indexes are -1, then stop here since we cannot
    248        // reason about the naming for either lines.
    249        if (startIndex < 0 && endIndex < 0) {
    250          break;
    251        }
    252 
    253        // Get the "-start" and "-end" line names of the grid area.
    254        nsAutoString startLineName;
    255        area->GetName(startLineName);
    256        startLineName.AppendLiteral("-start");
    257        nsAutoString endLineName;
    258        area->GetName(endLineName);
    259        endLineName.AppendLiteral("-end");
    260 
    261        // Get the list of existing line names for the start and end of the grid
    262        // area. In the case where one of the start or end indexes are -1, use a
    263        // dummy line as a substitute for the start/end line.
    264        RefPtr<GridLine> dummyLine = new GridLine(this);
    265        RefPtr<GridLine> areaStartLine =
    266            startIndex > -1 ? mLines[startIndex] : dummyLine;
    267        nsTArray<RefPtr<nsAtom>> startLineNames(areaStartLine->Names().Clone());
    268 
    269        RefPtr<GridLine> areaEndLine =
    270            endIndex > -1 ? mLines[endIndex] : dummyLine;
    271        nsTArray<RefPtr<nsAtom>> endLineNames(areaEndLine->Names().Clone());
    272 
    273        RefPtr<nsAtom> start = NS_Atomize(startLineName);
    274        RefPtr<nsAtom> end = NS_Atomize(endLineName);
    275        if (startLineNames.Contains(end) || endLineNames.Contains(start)) {
    276          // Add the reversed line names.
    277          AddLineNameIfNotPresent(startLineNames, end);
    278          AddLineNameIfNotPresent(endLineNames, start);
    279        } else {
    280          // Add the normal line names.
    281          AddLineNameIfNotPresent(startLineNames, start);
    282          AddLineNameIfNotPresent(endLineNames, end);
    283        }
    284 
    285        areaStartLine->SetLineNames(startLineNames);
    286        areaEndLine->SetLineNames(endLineNames);
    287      }
    288    }
    289  }
    290 }
    291 
    292 uint32_t GridLines::AppendRemovedAutoFits(
    293    const ComputedGridTrackInfo* aTrackInfo,
    294    const ComputedGridLineInfo* aLineInfo, nscoord aLastTrackEdge,
    295    uint32_t& aRepeatIndex, uint32_t aNumRepeatTracks,
    296    uint32_t aNumLeadingTracks, nsTArray<RefPtr<nsAtom>>& aLineNames) {
    297  bool extractedExplicitLineNames = false;
    298  nsTArray<RefPtr<nsAtom>> explicitLineNames;
    299  uint32_t linesAdded = 0;
    300  while (aRepeatIndex < aNumRepeatTracks &&
    301         aTrackInfo->mRemovedRepeatTracks[aRepeatIndex]) {
    302    // If this is not the very first call to this function, and if we
    303    // haven't already added a line this call, pull all the explicit
    304    // names to pass along to the next line that will be added after
    305    // this function completes.
    306    if (aRepeatIndex > 0 && linesAdded == 0) {
    307      // Find the names that didn't match the before or after names,
    308      // and extract them.
    309      for (const auto& name : aLineNames) {
    310        if (!aLineInfo->mNamesBefore.Contains(name) &&
    311            !aLineInfo->mNamesAfter.Contains(name)) {
    312          explicitLineNames.AppendElement(name);
    313        }
    314      }
    315      for (const auto& extractedName : explicitLineNames) {
    316        aLineNames.RemoveElement(extractedName);
    317      }
    318      extractedExplicitLineNames = true;
    319    }
    320 
    321    AddLineNamesIfNotPresent(aLineNames, aLineInfo->mNamesBefore);
    322 
    323    RefPtr<GridLine> line = new GridLine(this);
    324    mLines.AppendElement(line);
    325 
    326    // Time to calculate the line numbers. For the positive numbers
    327    // we count with a 1-based index from mRepeatFirstTrack. Although
    328    // this number is the index of the first repeat track AFTER all
    329    // the leading implicit tracks, that's still what we want since
    330    // all those leading implicit tracks have line number 0.
    331    uint32_t lineNumber = aTrackInfo->mRepeatFirstTrack + aRepeatIndex + 1;
    332 
    333    // The negative number does have to account for the leading
    334    // implicit tracks. We've been passed aNumLeadingTracks which is
    335    // the total of the leading implicit tracks plus the explicit
    336    // tracks. So all we have to do is subtract that number plus one
    337    // from the 0-based index of this track.
    338    int32_t lineNegativeNumber =
    339        (aTrackInfo->mNumLeadingImplicitTracks + aTrackInfo->mRepeatFirstTrack +
    340         aRepeatIndex) -
    341        (aNumLeadingTracks + 1);
    342    line->SetLineValues(
    343        aLineNames, nsPresContext::AppUnitsToDoubleCSSPixels(aLastTrackEdge),
    344        nsPresContext::AppUnitsToDoubleCSSPixels(0), lineNumber,
    345        lineNegativeNumber, GridDeclaration::Explicit);
    346 
    347    // No matter what, the next line should have the after names associated
    348    // with it. If we go through the loop again, the before names will also
    349    // be added.
    350    aLineNames = aLineInfo->mNamesAfter.Clone();
    351    aRepeatIndex++;
    352 
    353    linesAdded++;
    354  }
    355 
    356  aRepeatIndex++;
    357 
    358  if (extractedExplicitLineNames) {
    359    // Pass on the explicit names we saved to the next explicit line.
    360    AddLineNamesIfNotPresent(aLineNames, explicitLineNames);
    361  }
    362 
    363  // If we haven't finished adding auto-repeated tracks, then we need to put
    364  // back the before names, in case we cleared them above.
    365  if (aRepeatIndex < aNumRepeatTracks) {
    366    AddLineNamesIfNotPresent(aLineNames, aLineInfo->mNamesBefore);
    367  }
    368 
    369  return linesAdded;
    370 }
    371 
    372 }  // namespace mozilla::dom