forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			344 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "GridLines.h"
 | |
| 
 | |
| #include "GridDimension.h"
 | |
| #include "GridLine.h"
 | |
| #include "mozilla/dom/GridBinding.h"
 | |
| #include "nsGridContainerFrame.h"
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GridLines, mParent, mLines)
 | |
| NS_IMPL_CYCLE_COLLECTING_ADDREF(GridLines)
 | |
| NS_IMPL_CYCLE_COLLECTING_RELEASE(GridLines)
 | |
| NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GridLines)
 | |
|   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
 | |
|   NS_INTERFACE_MAP_ENTRY(nsISupports)
 | |
| NS_INTERFACE_MAP_END
 | |
| 
 | |
| GridLines::GridLines(GridDimension* aParent)
 | |
|   : mParent(aParent)
 | |
| {
 | |
|   MOZ_ASSERT(aParent,
 | |
|     "Should never be instantiated with a null GridDimension");
 | |
| }
 | |
| 
 | |
| GridLines::~GridLines()
 | |
| {
 | |
| }
 | |
| 
 | |
| JSObject*
 | |
| GridLines::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 | |
| {
 | |
|   return GridLines_Binding::Wrap(aCx, this, aGivenProto);
 | |
| }
 | |
| 
 | |
| uint32_t
 | |
| GridLines::Length() const
 | |
| {
 | |
|   return mLines.Length();
 | |
| }
 | |
| 
 | |
| GridLine*
 | |
| GridLines::Item(uint32_t aIndex)
 | |
| {
 | |
|   return mLines.SafeElementAt(aIndex);
 | |
| }
 | |
| 
 | |
| GridLine*
 | |
| GridLines::IndexedGetter(uint32_t aIndex,
 | |
|                          bool& aFound)
 | |
| {
 | |
|   aFound = aIndex < mLines.Length();
 | |
|   if (!aFound) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return mLines[aIndex];
 | |
| }
 | |
| 
 | |
| static void AddLineNameIfNotPresent(nsTArray<nsString>& aLineNames,
 | |
|                              const nsString& aName)
 | |
| {
 | |
|   if (!aLineNames.Contains(aName)) {
 | |
|     aLineNames.AppendElement(aName);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void AddLineNamesIfNotPresent(nsTArray<nsString>& aLineNames,
 | |
|                               const nsTArray<nsString>& aNames)
 | |
| {
 | |
|   for (const auto& name : aNames) {
 | |
|     AddLineNameIfNotPresent(aLineNames, name);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void
 | |
| GridLines::SetLineInfo(const ComputedGridTrackInfo* aTrackInfo,
 | |
|                        const ComputedGridLineInfo* aLineInfo,
 | |
|                        const nsTArray<RefPtr<GridArea>>& aAreas,
 | |
|                        bool aIsRow)
 | |
| {
 | |
|   MOZ_ASSERT(aLineInfo);
 | |
|   mLines.Clear();
 | |
| 
 | |
|   if (!aTrackInfo) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   uint32_t lineCount = aTrackInfo->mEndFragmentTrack -
 | |
|                        aTrackInfo->mStartFragmentTrack +
 | |
|                        1;
 | |
| 
 | |
|   // If there is at least one track, line count is one more
 | |
|   // than the number of tracks.
 | |
|   if (lineCount > 0) {
 | |
|     nscoord lastTrackEdge = 0;
 | |
|     nscoord startOfNextTrack;
 | |
|     uint32_t repeatIndex = 0;
 | |
|     uint32_t numRepeatTracks = aTrackInfo->mRemovedRepeatTracks.Length();
 | |
|     uint32_t numAddedLines = 0;
 | |
| 
 | |
|     // For the calculation of negative line numbers, we need to know
 | |
|     // the total number of leading implicit and explicit tracks.
 | |
|     // This might be different from the number of tracks sizes in
 | |
|     // aTrackInfo, because some of those tracks may be auto-fits that
 | |
|     // have been removed.
 | |
|     uint32_t leadingTrackCount = aTrackInfo->mNumLeadingImplicitTracks +
 | |
|                                  aTrackInfo->mNumExplicitTracks;
 | |
|     if (numRepeatTracks > 0) {
 | |
|       for (auto& removedTrack : aTrackInfo->mRemovedRepeatTracks) {
 | |
|         if (removedTrack) {
 | |
|           ++leadingTrackCount;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     for (uint32_t i = aTrackInfo->mStartFragmentTrack;
 | |
|          i < aTrackInfo->mEndFragmentTrack + 1;
 | |
|          i++) {
 | |
|       // Since line indexes are 1-based, calculate a 1-based value
 | |
|       // for this track to simplify some calculations.
 | |
|       const uint32_t line1Index = i + 1;
 | |
| 
 | |
|       startOfNextTrack = (i < aTrackInfo->mEndFragmentTrack) ?
 | |
|                          aTrackInfo->mPositions[i] :
 | |
|                          lastTrackEdge;
 | |
| 
 | |
|       // Get the line names for the current line. aLineInfo->mNames
 | |
|       // may contain duplicate names. This is intentional, since grid
 | |
|       // layout works fine with duplicate names, and we don't want to
 | |
|       // detect and remove duplicates in layout since it is an O(n^2)
 | |
|       // problem. We do the work here since this is only run when
 | |
|       // requested by devtools, and slowness here will not affect
 | |
|       // normal browsing.
 | |
|       const nsTArray<nsString>& possiblyDuplicateLineNames(
 | |
|         aLineInfo->mNames.SafeElementAt(i, nsTArray<nsString>()));
 | |
| 
 | |
|       nsTArray<nsString> lineNames;
 | |
|       AddLineNamesIfNotPresent(lineNames, possiblyDuplicateLineNames);
 | |
| 
 | |
|       // Add in names from grid areas where this line is used as a boundary.
 | |
|       for (auto area : aAreas) {
 | |
|         // We specifically ignore line names from implicitly named areas,
 | |
|         // because it can be confusing for designers who might naturally use
 | |
|         // a named line of "-start" or "-end" and create an implicit named
 | |
|         // area without meaning to.
 | |
|         if (area->Type() == GridDeclaration::Implicit) {
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         bool haveNameToAdd = false;
 | |
|         nsAutoString nameToAdd;
 | |
|         area->GetName(nameToAdd);
 | |
|         if (aIsRow) {
 | |
|           if (area->RowStart() == line1Index) {
 | |
|             haveNameToAdd = true;
 | |
|             nameToAdd.AppendLiteral("-start");
 | |
|           } else if (area->RowEnd() == line1Index) {
 | |
|             haveNameToAdd = true;
 | |
|             nameToAdd.AppendLiteral("-end");
 | |
|           }
 | |
|         } else {
 | |
|           if (area->ColumnStart() == line1Index) {
 | |
|             haveNameToAdd = true;
 | |
|             nameToAdd.AppendLiteral("-start");
 | |
|           } else if (area->ColumnEnd() == line1Index) {
 | |
|             haveNameToAdd = true;
 | |
|             nameToAdd.AppendLiteral("-end");
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         if (haveNameToAdd) {
 | |
|           AddLineNameIfNotPresent(lineNames, nameToAdd);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (i >= (aTrackInfo->mRepeatFirstTrack +
 | |
|                 aTrackInfo->mNumLeadingImplicitTracks) &&
 | |
|           repeatIndex < numRepeatTracks) {
 | |
|         numAddedLines += AppendRemovedAutoFits(aTrackInfo,
 | |
|                                                aLineInfo,
 | |
|                                                lastTrackEdge,
 | |
|                                                repeatIndex,
 | |
|                                                numRepeatTracks,
 | |
|                                                leadingTrackCount,
 | |
|                                                lineNames);
 | |
|       }
 | |
| 
 | |
|       // If this line is the one that ends a repeat, then add
 | |
|       // in the mNamesFollowingRepeat names from aLineInfo.
 | |
|       if (numRepeatTracks > 0 &&
 | |
|           i == (aTrackInfo->mRepeatFirstTrack +
 | |
|                 aTrackInfo->mNumLeadingImplicitTracks +
 | |
|                 numRepeatTracks - numAddedLines)) {
 | |
|         AddLineNamesIfNotPresent(lineNames,
 | |
|                                  aLineInfo->mNamesFollowingRepeat);
 | |
|       }
 | |
| 
 | |
|       RefPtr<GridLine> line = new GridLine(this);
 | |
|       mLines.AppendElement(line);
 | |
|       MOZ_ASSERT(line1Index > 0, "line1Index must be positive.");
 | |
|       bool isBeforeFirstExplicit =
 | |
|         (line1Index <= aTrackInfo->mNumLeadingImplicitTracks);
 | |
|       bool isAfterLastExplicit = line1Index > (leadingTrackCount + 1);
 | |
|       // Calculate an actionable line number for this line, that could be used
 | |
|       // in a css grid property to align a grid item or area at that line.
 | |
|       // For implicit lines that appear before line 1, report a number of 0.
 | |
|       // We can't report negative indexes, because those have a different
 | |
|       // meaning in the css grid spec (negative indexes are negative-1-based
 | |
|       // from the end of the grid decreasing towards the front).
 | |
|       uint32_t lineNumber = isBeforeFirstExplicit ? 0 :
 | |
|         (line1Index + numAddedLines - aTrackInfo->mNumLeadingImplicitTracks);
 | |
| 
 | |
|       // The negativeNumber is counted back from the leadingTrackCount.
 | |
|       int32_t lineNegativeNumber = isAfterLastExplicit ? 0 :
 | |
|         (line1Index + numAddedLines - (leadingTrackCount + 2));
 | |
|       GridDeclaration lineType =
 | |
|         (isBeforeFirstExplicit || isAfterLastExplicit)
 | |
|          ? GridDeclaration::Implicit
 | |
|          : GridDeclaration::Explicit;
 | |
|       line->SetLineValues(
 | |
|         lineNames,
 | |
|         nsPresContext::AppUnitsToDoubleCSSPixels(lastTrackEdge),
 | |
|         nsPresContext::AppUnitsToDoubleCSSPixels(startOfNextTrack -
 | |
|                                                  lastTrackEdge),
 | |
|         lineNumber,
 | |
|         lineNegativeNumber,
 | |
|         lineType
 | |
|       );
 | |
| 
 | |
|       if (i < aTrackInfo->mEndFragmentTrack) {
 | |
|         lastTrackEdge = aTrackInfo->mPositions[i] + aTrackInfo->mSizes[i];
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| uint32_t
 | |
| GridLines::AppendRemovedAutoFits(const ComputedGridTrackInfo* aTrackInfo,
 | |
|                                  const ComputedGridLineInfo* aLineInfo,
 | |
|                                  nscoord aLastTrackEdge,
 | |
|                                  uint32_t& aRepeatIndex,
 | |
|                                  uint32_t aNumRepeatTracks,
 | |
|                                  uint32_t aNumLeadingTracks,
 | |
|                                  nsTArray<nsString>& aLineNames)
 | |
| {
 | |
|   // Check to see if lineNames contains ALL of the before line names.
 | |
|   bool alreadyHasBeforeLineNames = true;
 | |
|   for (const auto& beforeName : aLineInfo->mNamesBefore) {
 | |
|     if (!aLineNames.Contains(beforeName)) {
 | |
|       alreadyHasBeforeLineNames = false;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   bool extractedExplicitLineNames = false;
 | |
|   nsTArray<nsString> explicitLineNames;
 | |
|   uint32_t linesAdded = 0;
 | |
|   while (aRepeatIndex < aNumRepeatTracks &&
 | |
|          aTrackInfo->mRemovedRepeatTracks[aRepeatIndex]) {
 | |
|     // If this is not the very first call to this function, and if we
 | |
|     // haven't already added a line this call, pull all the explicit
 | |
|     // names to pass along to the next line that will be added after
 | |
|     // this function completes.
 | |
|     if (aRepeatIndex > 0 &&
 | |
|         linesAdded == 0) {
 | |
|       // Find the names that didn't match the before or after names,
 | |
|       // and extract them.
 | |
|       for (const auto& name : aLineNames) {
 | |
|         if (!aLineInfo->mNamesBefore.Contains(name) &&
 | |
|             !aLineInfo->mNamesAfter.Contains(name)) {
 | |
|           explicitLineNames.AppendElement(name);
 | |
|         }
 | |
|       }
 | |
|       for (const auto& extractedName : explicitLineNames) {
 | |
|         aLineNames.RemoveElement(extractedName);
 | |
|       }
 | |
|       extractedExplicitLineNames = true;
 | |
|     }
 | |
| 
 | |
|     // If this is the second or later time through, or didn't already
 | |
|     // have before names, add them.
 | |
|     if (linesAdded > 0 || !alreadyHasBeforeLineNames) {
 | |
|       AddLineNamesIfNotPresent(aLineNames, aLineInfo->mNamesBefore);
 | |
|     }
 | |
| 
 | |
|     RefPtr<GridLine> line = new GridLine(this);
 | |
|     mLines.AppendElement(line);
 | |
| 
 | |
|     // Time to calculate the line numbers. For the positive numbers
 | |
|     // we count with a 1-based index from mRepeatFirstTrack. Although
 | |
|     // this number is the index of the first repeat track AFTER all
 | |
|     // the leading implicit tracks, that's still what we want since
 | |
|     // all those leading implicit tracks have line number 0.
 | |
|     uint32_t lineNumber = aTrackInfo->mRepeatFirstTrack +
 | |
|                           aRepeatIndex + 1;
 | |
| 
 | |
|     // The negative number does have to account for the leading
 | |
|     // implicit tracks. We've been passed aNumLeadingTracks which is
 | |
|     // the total of the leading implicit tracks plus the explicit
 | |
|     // tracks. So all we have to do is subtract that number plus one
 | |
|     // from the 0-based index of this track.
 | |
|     int32_t lineNegativeNumber = (aTrackInfo->mNumLeadingImplicitTracks +
 | |
|                                   aTrackInfo->mRepeatFirstTrack +
 | |
|                                   aRepeatIndex) - (aNumLeadingTracks + 1);
 | |
|     line->SetLineValues(
 | |
|       aLineNames,
 | |
|       nsPresContext::AppUnitsToDoubleCSSPixels(aLastTrackEdge),
 | |
|       nsPresContext::AppUnitsToDoubleCSSPixels(0),
 | |
|       lineNumber,
 | |
|       lineNegativeNumber,
 | |
|       GridDeclaration::Explicit
 | |
|     );
 | |
| 
 | |
|     // No matter what, the next line should have the after names associated
 | |
|     // with it. If we go through the loop again, the before names will also
 | |
|     // be added.
 | |
|     aLineNames = aLineInfo->mNamesAfter;
 | |
|     aRepeatIndex++;
 | |
| 
 | |
|     linesAdded++;
 | |
|   }
 | |
|   aRepeatIndex++;
 | |
| 
 | |
|   if (extractedExplicitLineNames) {
 | |
|     // Pass on the explicit names we saved to the next explicit line.
 | |
|     AddLineNamesIfNotPresent(aLineNames, explicitLineNames);
 | |
|   }
 | |
| 
 | |
|   if (alreadyHasBeforeLineNames && linesAdded > 0) {
 | |
|     // If we started with before names, pass them on to the next explicit
 | |
|     // line.
 | |
|     AddLineNamesIfNotPresent(aLineNames, aLineInfo->mNamesBefore);
 | |
|   }
 | |
|   return linesAdded;
 | |
| }
 | |
| 
 | |
| } // namespace dom
 | |
| } // namespace mozilla
 | 
