Coverage Report

Created: 2018-09-25 14:53

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