Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/VideoUtils.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=2 sw=2 sts=2 et cindent: */
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
#ifndef VideoUtils_h
8
#define VideoUtils_h
9
10
#include "AudioSampleFormat.h"
11
#include "MediaInfo.h"
12
#include "TimeUnits.h"
13
#include "VideoLimits.h"
14
#include "mozilla/gfx/Point.h" // for gfx::IntSize
15
#include "mozilla/AbstractThread.h"
16
#include "mozilla/Attributes.h"
17
#include "mozilla/CheckedInt.h"
18
#include "mozilla/MozPromise.h"
19
#include "mozilla/ReentrantMonitor.h"
20
#include "mozilla/RefPtr.h"
21
#include "mozilla/SharedThreadPool.h"
22
#include "mozilla/UniquePtr.h"
23
#include "nsAutoPtr.h"
24
#include "nsCOMPtr.h"
25
#include "nsINamed.h"
26
#include "nsIThread.h"
27
#include "nsITimer.h"
28
29
#include "nsThreadUtils.h"
30
#include "prtime.h"
31
32
using mozilla::CheckedInt64;
33
using mozilla::CheckedUint64;
34
using mozilla::CheckedInt32;
35
using mozilla::CheckedUint32;
36
37
// This file contains stuff we'd rather put elsewhere, but which is
38
// dependent on other changes which we don't want to wait for. We plan to
39
// remove this file in the near future.
40
41
42
// This belongs in xpcom/monitor/Monitor.h, once we've made
43
// mozilla::Monitor non-reentrant.
44
namespace mozilla {
45
46
class MediaContainerType;
47
48
// EME Key System String.
49
extern const nsLiteralCString kEMEKeySystemClearkey;
50
extern const nsLiteralCString kEMEKeySystemWidevine;
51
52
/**
53
 * ReentrantMonitorConditionallyEnter
54
 *
55
 * Enters the supplied monitor only if the conditional value |aEnter| is true.
56
 * E.g. Used to allow unmonitored read access on the decode thread,
57
 * and monitored access on all other threads.
58
 */
59
class MOZ_STACK_CLASS ReentrantMonitorConditionallyEnter
60
{
61
public:
62
  ReentrantMonitorConditionallyEnter(bool aEnter,
63
                                     ReentrantMonitor &aReentrantMonitor) :
64
    mReentrantMonitor(nullptr)
65
0
  {
66
0
    MOZ_COUNT_CTOR(ReentrantMonitorConditionallyEnter);
67
0
    if (aEnter) {
68
0
      mReentrantMonitor = &aReentrantMonitor;
69
0
      NS_ASSERTION(mReentrantMonitor, "null monitor");
70
0
      mReentrantMonitor->Enter();
71
0
    }
72
0
  }
73
  ~ReentrantMonitorConditionallyEnter(void)
74
0
  {
75
0
    if (mReentrantMonitor) {
76
0
      mReentrantMonitor->Exit();
77
0
    }
78
0
    MOZ_COUNT_DTOR(ReentrantMonitorConditionallyEnter);
79
0
  }
80
private:
81
  // Restrict to constructor and destructor defined above.
82
  ReentrantMonitorConditionallyEnter();
83
  ReentrantMonitorConditionallyEnter(const ReentrantMonitorConditionallyEnter&);
84
  ReentrantMonitorConditionallyEnter& operator =(const ReentrantMonitorConditionallyEnter&);
85
  static void* operator new(size_t) CPP_THROW_NEW;
86
  static void operator delete(void*);
87
88
  ReentrantMonitor* mReentrantMonitor;
89
};
90
91
// Shuts down a thread asynchronously.
92
class ShutdownThreadEvent : public Runnable
93
{
94
public:
95
  explicit ShutdownThreadEvent(nsIThread* aThread)
96
    : Runnable("ShutdownThreadEvent")
97
    , mThread(aThread)
98
  {
99
  }
100
  ~ShutdownThreadEvent() {}
101
  NS_IMETHOD Run() override {
102
    mThread->Shutdown();
103
    mThread = nullptr;
104
    return NS_OK;
105
  }
106
private:
107
  nsCOMPtr<nsIThread> mThread;
108
};
109
110
class MediaResource;
111
112
// Estimates the buffered ranges of a MediaResource using a simple
113
// (byteOffset/length)*duration method. Probably inaccurate, but won't
114
// do file I/O, and can be used when we don't have detailed knowledge
115
// of the byte->time mapping of a resource. aDurationUsecs is the duration
116
// of the media in microseconds. Estimated buffered ranges are stored in
117
// aOutBuffered. Ranges are 0-normalized, i.e. in the range of (0,duration].
118
media::TimeIntervals GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream,
119
                                                    int64_t aDurationUsecs);
120
121
// Converts from number of audio frames (aFrames) to microseconds, given
122
// the specified audio rate (aRate).
123
CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate);
124
// Converts from number of audio frames (aFrames) TimeUnit, given
125
// the specified audio rate (aRate).
126
media::TimeUnit FramesToTimeUnit(int64_t aFrames, uint32_t aRate);
127
// Perform aValue * aMul / aDiv, reducing the possibility of overflow due to
128
// aValue * aMul overflowing.
129
CheckedInt64 SaferMultDiv(int64_t aValue, uint64_t aMul, uint64_t aDiv);
130
131
// Converts from microseconds (aUsecs) to number of audio frames, given the
132
// specified audio rate (aRate). Stores the result in aOutFrames. Returns
133
// true if the operation succeeded, or false if there was an integer
134
// overflow while calulating the conversion.
135
CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate);
136
137
// Format TimeUnit as number of frames at given rate.
138
CheckedInt64 TimeUnitToFrames(const media::TimeUnit& aTime, uint32_t aRate);
139
140
// Converts milliseconds to seconds.
141
#define MS_TO_SECONDS(ms) ((double)(ms) / (PR_MSEC_PER_SEC))
142
143
// Converts seconds to milliseconds.
144
#define SECONDS_TO_MS(s) ((int)((s) * (PR_MSEC_PER_SEC)))
145
146
// Converts from seconds to microseconds. Returns failure if the resulting
147
// integer is too big to fit in an int64_t.
148
nsresult SecondsToUsecs(double aSeconds, int64_t& aOutUsecs);
149
150
// Scales the display rect aDisplay by aspect ratio aAspectRatio.
151
// Note that aDisplay must be validated by IsValidVideoRegion()
152
// before being used!
153
void
154
ScaleDisplayByAspectRatio(gfx::IntSize& aDisplay, float aAspectRatio);
155
156
// Downmix Stereo audio samples to Mono.
157
// Input are the buffer contains stereo data and the number of frames.
158
void DownmixStereoToMono(mozilla::AudioDataValue* aBuffer,
159
                         uint32_t aFrames);
160
161
// Decide the number of playback channels according to the
162
// given AudioInfo and the prefs that are being set.
163
uint32_t DecideAudioPlaybackChannels(const AudioInfo& info);
164
165
bool IsDefaultPlaybackDeviceMono();
166
167
bool IsVideoContentType(const nsCString& aContentType);
168
169
// Returns true if it's safe to use aPicture as the picture to be
170
// extracted inside a frame of size aFrame, and scaled up to and displayed
171
// at a size of aDisplay. You should validate the frame, picture, and
172
// display regions before using them to display video frames.
173
bool
174
IsValidVideoRegion(const gfx::IntSize& aFrame,
175
                   const gfx::IntRect& aPicture,
176
                   const gfx::IntSize& aDisplay);
177
178
// Template to automatically set a variable to a value on scope exit.
179
// Useful for unsetting flags, etc.
180
template<typename T>
181
class AutoSetOnScopeExit {
182
public:
183
  AutoSetOnScopeExit(T& aVar, T aValue)
184
    : mVar(aVar)
185
    , mValue(aValue)
186
  {}
187
  ~AutoSetOnScopeExit() {
188
    mVar = mValue;
189
  }
190
private:
191
  T& mVar;
192
  const T mValue;
193
};
194
195
enum class MediaThreadType {
196
  PLAYBACK, // MediaDecoderStateMachine and MediaFormatReader
197
  PLATFORM_DECODER, // MediaDataDecoder
198
  MSG_CONTROL,
199
  WEBRTC_DECODER
200
};
201
// Returns the thread pool that is shared amongst all decoder state machines
202
// for decoding streams.
203
already_AddRefed<SharedThreadPool> GetMediaThreadPool(MediaThreadType aType);
204
205
enum H264_PROFILE {
206
  H264_PROFILE_UNKNOWN                     = 0,
207
  H264_PROFILE_BASE                        = 0x42,
208
  H264_PROFILE_MAIN                        = 0x4D,
209
  H264_PROFILE_EXTENDED                    = 0x58,
210
  H264_PROFILE_HIGH                        = 0x64,
211
};
212
213
enum H264_LEVEL {
214
    H264_LEVEL_1         = 10,
215
    H264_LEVEL_1_b       = 11,
216
    H264_LEVEL_1_1       = 11,
217
    H264_LEVEL_1_2       = 12,
218
    H264_LEVEL_1_3       = 13,
219
    H264_LEVEL_2         = 20,
220
    H264_LEVEL_2_1       = 21,
221
    H264_LEVEL_2_2       = 22,
222
    H264_LEVEL_3         = 30,
223
    H264_LEVEL_3_1       = 31,
224
    H264_LEVEL_3_2       = 32,
225
    H264_LEVEL_4         = 40,
226
    H264_LEVEL_4_1       = 41,
227
    H264_LEVEL_4_2       = 42,
228
    H264_LEVEL_5         = 50,
229
    H264_LEVEL_5_1       = 51,
230
    H264_LEVEL_5_2       = 52
231
};
232
233
// Extracts the H.264/AVC profile and level from an H.264 codecs string.
234
// H.264 codecs parameters have a type defined as avc1.PPCCLL, where
235
// PP = profile_idc, CC = constraint_set flags, LL = level_idc.
236
// See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
237
// for more details.
238
// Returns false on failure.
239
bool
240
ExtractH264CodecDetails(const nsAString& aCodecs,
241
                        uint8_t& aProfile,
242
                        uint8_t& aConstraint,
243
                        uint8_t& aLevel);
244
245
struct VideoColorSpace
246
{
247
  // TODO: Define the value type as strong type enum
248
  // to better know the exact meaning corresponding to ISO/IEC 23001-8:2016.
249
  // Default value is listed https://www.webmproject.org/vp9/mp4/#optional-fields
250
  uint8_t mPrimaryId = 1; // Table 2
251
  uint8_t mTransferId = 1; // Table 3
252
  uint8_t mMatrixId = 1; // Table 4
253
  uint8_t mRangeId = 0;
254
};
255
256
// Extracts the VPX codecs parameter string.
257
// See https://www.webmproject.org/vp9/mp4/#codecs-parameter-string
258
// for more details.
259
// Returns false on failure.
260
bool
261
ExtractVPXCodecDetails(const nsAString& aCodec,
262
                       uint8_t& aProfile,
263
                       uint8_t& aLevel,
264
                       uint8_t& aBitDepth);
265
bool
266
ExtractVPXCodecDetails(const nsAString& aCodec,
267
                       uint8_t& aProfile,
268
                       uint8_t& aLevel,
269
                       uint8_t& aBitDepth,
270
                       uint8_t& aChromaSubsampling,
271
                       VideoColorSpace& aColorSpace);
272
273
// Use a cryptographic quality PRNG to generate raw random bytes
274
// and convert that to a base64 string.
275
nsresult
276
GenerateRandomName(nsCString& aOutSalt, uint32_t aLength);
277
278
// This version returns a string suitable for use as a file or URL
279
// path. This is based on code from nsExternalAppHandler::SetUpTempFile.
280
nsresult
281
GenerateRandomPathName(nsCString& aOutSalt, uint32_t aLength);
282
283
already_AddRefed<TaskQueue>
284
CreateMediaDecodeTaskQueue(const char* aName);
285
286
// Iteratively invokes aWork until aCondition returns true, or aWork returns false.
287
// Use this rather than a while loop to avoid bogarting the task queue.
288
template<class Work, class Condition>
289
RefPtr<GenericPromise> InvokeUntil(Work aWork, Condition aCondition) {
290
  RefPtr<GenericPromise::Private> p = new GenericPromise::Private(__func__);
291
292
  if (aCondition()) {
293
    p->Resolve(true, __func__);
294
  }
295
296
  struct Helper {
297
    static void Iteration(const RefPtr<GenericPromise::Private>& aPromise, Work aLocalWork, Condition aLocalCondition) {
298
      if (!aLocalWork()) {
299
        aPromise->Reject(NS_ERROR_FAILURE, __func__);
300
      } else if (aLocalCondition()) {
301
        aPromise->Resolve(true, __func__);
302
      } else {
303
        nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
304
          "InvokeUntil::Helper::Iteration",
305
          [aPromise, aLocalWork, aLocalCondition]() {
306
            Iteration(aPromise, aLocalWork, aLocalCondition);
307
          });
308
        AbstractThread::GetCurrent()->Dispatch(r.forget());
309
      }
310
    }
311
  };
312
313
  Helper::Iteration(p, aWork, aCondition);
314
  return p.forget();
315
}
316
317
// Simple timer to run a runnable after a timeout.
318
class SimpleTimer : public nsITimerCallback, public nsINamed
319
{
320
public:
321
  NS_DECL_ISUPPORTS
322
  NS_DECL_NSINAMED
323
324
  // Create a new timer to run aTask after aTimeoutMs milliseconds
325
  // on thread aTarget. If aTarget is null, task is run on the main thread.
326
  static already_AddRefed<SimpleTimer> Create(nsIRunnable* aTask,
327
                                              uint32_t aTimeoutMs,
328
                                              nsIEventTarget* aTarget = nullptr);
329
  void Cancel();
330
331
  NS_IMETHOD Notify(nsITimer *timer) override;
332
333
private:
334
  virtual ~SimpleTimer() {}
335
  nsresult Init(nsIRunnable* aTask, uint32_t aTimeoutMs, nsIEventTarget* aTarget);
336
337
  RefPtr<nsIRunnable> mTask;
338
  nsCOMPtr<nsITimer> mTimer;
339
};
340
341
void
342
LogToBrowserConsole(const nsAString& aMsg);
343
344
bool
345
ParseMIMETypeString(const nsAString& aMIMEType,
346
                    nsString& aOutContainerType,
347
                    nsTArray<nsString>& aOutCodecs);
348
349
bool
350
ParseCodecsString(const nsAString& aCodecs, nsTArray<nsString>& aOutCodecs);
351
352
bool
353
IsH264CodecString(const nsAString& aCodec);
354
355
bool
356
IsAACCodecString(const nsAString& aCodec);
357
358
bool
359
IsVP8CodecString(const nsAString& aCodec);
360
361
bool
362
IsVP9CodecString(const nsAString& aCodec);
363
364
bool
365
IsAV1CodecString(const nsAString& aCodec);
366
367
// Try and create a TrackInfo with a given codec MIME type.
368
UniquePtr<TrackInfo>
369
CreateTrackInfoWithMIMEType(const nsACString& aCodecMIMEType);
370
371
// Try and create a TrackInfo with a given codec MIME type, and optional extra
372
// parameters from a container type (its MIME type and codecs are ignored).
373
UniquePtr<TrackInfo>
374
CreateTrackInfoWithMIMETypeAndContainerTypeExtraParameters(
375
  const nsACString& aCodecMIMEType,
376
  const MediaContainerType& aContainerType);
377
378
namespace detail {
379
380
// aString should start with aMajor + '/'.
381
constexpr bool
382
StartsWithMIMETypeMajor(const char* aString,
383
                        const char* aMajor, size_t aMajorRemaining)
384
0
{
385
0
  return (aMajorRemaining == 0 && *aString == '/') ||
386
0
         (*aString == *aMajor && StartsWithMIMETypeMajor(aString + 1,
387
0
                                                         aMajor + 1,
388
0
                                                         aMajorRemaining - 1));
389
0
}
390
391
// aString should only contain [a-z0-9\-\.] and a final '\0'.
392
constexpr bool
393
EndsWithMIMESubtype(const char* aString, size_t aRemaining)
394
0
{
395
0
  return aRemaining == 0 ||
396
0
         (((*aString >= 'a' && *aString <= 'z') ||
397
0
           (*aString >= '0' && *aString <= '9') ||
398
0
           *aString == '-' ||
399
0
           *aString == '.') &&
400
0
          EndsWithMIMESubtype(aString + 1, aRemaining - 1));
401
0
}
402
403
// Simple MIME-type literal string checker with a given (major) type.
404
// Only accepts "{aMajor}/[a-z0-9\-\.]+".
405
template <size_t MajorLengthPlus1>
406
constexpr bool
407
IsMIMETypeWithMajor(const char* aString, size_t aLength,
408
                    const char (&aMajor)[MajorLengthPlus1])
409
0
{
410
0
  return aLength > MajorLengthPlus1 && // Major + '/' + at least 1 char
411
0
         StartsWithMIMETypeMajor(aString, aMajor, MajorLengthPlus1 - 1) &&
412
0
         EndsWithMIMESubtype(aString + MajorLengthPlus1,
413
0
                             aLength - MajorLengthPlus1);
414
0
}
Unexecuted instantiation: bool mozilla::detail::IsMIMETypeWithMajor<12ul>(char const*, unsigned long, char const (&) [12ul])
Unexecuted instantiation: bool mozilla::detail::IsMIMETypeWithMajor<6ul>(char const*, unsigned long, char const (&) [6ul])
415
416
} // namespace detail
417
418
// Simple MIME-type string checker.
419
// Only accepts lowercase "{application,audio,video}/[a-z0-9\-\.]+".
420
// Add more if necessary.
421
constexpr bool
422
IsMediaMIMEType(const char* aString, size_t aLength)
423
0
{
424
0
  return detail::IsMIMETypeWithMajor(aString, aLength, "application") ||
425
0
         detail::IsMIMETypeWithMajor(aString, aLength, "audio") ||
426
0
         detail::IsMIMETypeWithMajor(aString, aLength, "video");
427
0
}
428
429
// Simple MIME-type string literal checker.
430
// Only accepts lowercase "{application,audio,video}/[a-z0-9\-\.]+".
431
// Add more if necessary.
432
template <size_t LengthPlus1>
433
constexpr bool
434
IsMediaMIMEType(const char (&aString)[LengthPlus1])
435
0
{
436
0
  return IsMediaMIMEType(aString, LengthPlus1 - 1);
437
0
}
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<30ul>(char const (&) [30ul])
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<22ul>(char const (&) [22ul])
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<14ul>(char const (&) [14ul])
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<16ul>(char const (&) [16ul])
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<17ul>(char const (&) [17ul])
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<13ul>(char const (&) [13ul])
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<19ul>(char const (&) [19ul])
Unexecuted instantiation: bool mozilla::IsMediaMIMEType<15ul>(char const (&) [15ul])
438
439
// Simple MIME-type string checker.
440
// Only accepts lowercase "{application,audio,video}/[a-z0-9\-\.]+".
441
// Add more if necessary.
442
inline bool
443
IsMediaMIMEType(const nsACString& aString)
444
0
{
445
0
  return IsMediaMIMEType(aString.Data(), aString.Length());
446
0
}
447
448
enum class StringListRangeEmptyItems
449
{
450
  // Skip all empty items (empty string will process nothing)
451
  // E.g.: "a,,b" -> ["a", "b"], "" -> nothing
452
  Skip,
453
  // Process all, except if string is empty
454
  // E.g.: "a,,b" -> ["a", "", "b"], "" -> nothing
455
  ProcessEmptyItems,
456
  // Process all, including 1 empty item in an empty string
457
  // E.g.: "a,,b" -> ["a", "", "b"], "" -> [""]
458
  ProcessAll
459
};
460
461
template <typename String,
462
          StringListRangeEmptyItems empties = StringListRangeEmptyItems::Skip>
463
class StringListRange
464
{
465
  typedef typename String::char_type CharType;
466
  typedef const CharType* Pointer;
467
468
public:
469
  // Iterator into range, trims items and optionally skips empty items.
470
  class Iterator
471
  {
472
  public:
473
    bool operator!=(const Iterator& a) const
474
0
    {
475
0
      return mStart != a.mStart || mEnd != a.mEnd;
476
0
    }
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::Iterator::operator!=(mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::Iterator const&) const
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::Iterator::operator!=(mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::Iterator const&) const
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::Iterator::operator!=(mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::Iterator const&) const
477
    Iterator& operator++()
478
0
    {
479
0
      SearchItemAt(mComma + 1);
480
0
      return *this;
481
0
    }
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::Iterator::operator++()
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::Iterator::operator++()
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::Iterator::operator++()
482
    // DereferencedType should be 'const nsDependent[C]String' pointing into
483
    // mList (which is 'const ns[C]String&').
484
    typedef decltype(Substring(Pointer(), Pointer())) DereferencedType;
485
    DereferencedType operator*()
486
0
    {
487
0
      return Substring(mStart, mEnd);
488
0
    }
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::Iterator::operator*()
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::Iterator::operator*()
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::Iterator::operator*()
489
  private:
490
    friend class StringListRange;
491
    Iterator(const CharType* aRangeStart, uint32_t aLength)
492
      : mRangeEnd(aRangeStart + aLength)
493
      , mStart(nullptr)
494
      , mEnd(nullptr)
495
      , mComma(nullptr)
496
0
    {
497
0
      SearchItemAt(aRangeStart);
498
0
    }
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::Iterator::Iterator(char16_t const*, unsigned int)
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::Iterator::Iterator(char const*, unsigned int)
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::Iterator::Iterator(char16_t const*, unsigned int)
499
    void SearchItemAt(Pointer start)
500
0
    {
501
0
      // First, skip leading whitespace.
502
0
      for (Pointer p = start; ; ++p) {
503
0
        if (p >= mRangeEnd) {
504
0
          if (p > mRangeEnd
505
0
                  + (empties != StringListRangeEmptyItems::Skip ? 1 : 0)) {
506
0
            p = mRangeEnd
507
0
                + (empties != StringListRangeEmptyItems::Skip ? 1 : 0);
508
0
          }
509
0
          mStart = mEnd = mComma = p;
510
0
          return;
511
0
        }
512
0
        auto c = *p;
513
0
        if (c == CharType(',')) {
514
0
          // Comma -> Empty item -> Skip or process?
515
0
          if (empties != StringListRangeEmptyItems::Skip) {
516
0
            mStart = mEnd = mComma = p;
517
0
            return;
518
0
          }
519
0
        } else if (c != CharType(' ')) {
520
0
          mStart = p;
521
0
          break;
522
0
        }
523
0
      }
524
0
      // Find comma, recording start of trailing space.
525
0
      Pointer trailingWhitespace = nullptr;
526
0
      for (Pointer p = mStart + 1; ; ++p) {
527
0
        if (p >= mRangeEnd) {
528
0
          mEnd = trailingWhitespace ? trailingWhitespace : p;
529
0
          mComma = p;
530
0
          return;
531
0
        }
532
0
        auto c = *p;
533
0
        if (c == CharType(',')) {
534
0
          mEnd = trailingWhitespace ? trailingWhitespace : p;
535
0
          mComma = p;
536
0
          return;
537
0
        }
538
0
        if (c == CharType(' ')) {
539
0
          // Found a whitespace -> Record as trailing if not first one.
540
0
          if (!trailingWhitespace) {
541
0
            trailingWhitespace = p;
542
0
          }
543
0
        } else {
544
0
          // Found a non-whitespace -> Reset trailing whitespace if needed.
545
0
          if (trailingWhitespace) {
546
0
            trailingWhitespace = nullptr;
547
0
          }
548
0
        }
549
0
      }
550
0
    }
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::Iterator::SearchItemAt(char16_t const*)
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::Iterator::SearchItemAt(char const*)
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::Iterator::SearchItemAt(char16_t const*)
551
    const Pointer mRangeEnd;
552
    Pointer mStart;
553
    Pointer mEnd;
554
    Pointer mComma;
555
  };
556
557
0
  explicit StringListRange(const String& aList) : mList(aList) {}
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::StringListRange(nsTString<char16_t> const&)
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::StringListRange(nsTAutoStringN<char, 64ul> const&)
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::StringListRange(nsTSubstring<char16_t> const&)
558
  Iterator begin() const
559
0
  {
560
0
    return Iterator(
561
0
      mList.Data()
562
0
      + ((empties == StringListRangeEmptyItems::ProcessEmptyItems &&
563
0
          mList.Length() == 0)
564
0
          ? 1
565
0
          : 0),
566
0
      mList.Length());
567
0
  }
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::begin() const
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::begin() const
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::begin() const
568
  Iterator end() const
569
0
  {
570
0
    return Iterator(mList.Data() + mList.Length()
571
0
                    + (empties != StringListRangeEmptyItems::Skip ? 1 : 0),
572
0
                    0);
573
0
  }
Unexecuted instantiation: mozilla::StringListRange<nsTString<char16_t>, (mozilla::StringListRangeEmptyItems)1>::end() const
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0>::end() const
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0>::end() const
574
private:
575
  const String& mList;
576
};
577
578
template <StringListRangeEmptyItems empties = StringListRangeEmptyItems::Skip,
579
          typename String>
580
StringListRange<String, empties>
581
MakeStringListRange(const String& aList)
582
0
{
583
0
  return StringListRange<String, empties>(aList);
584
0
}
Unexecuted instantiation: mozilla::StringListRange<nsTAutoStringN<char, 64ul>, (mozilla::StringListRangeEmptyItems)0> mozilla::MakeStringListRange<(mozilla::StringListRangeEmptyItems)0, nsTAutoStringN<char, 64ul> >(nsTAutoStringN<char, 64ul> const&)
Unexecuted instantiation: mozilla::StringListRange<nsTSubstring<char16_t>, (mozilla::StringListRangeEmptyItems)0> mozilla::MakeStringListRange<(mozilla::StringListRangeEmptyItems)0, nsTSubstring<char16_t> >(nsTSubstring<char16_t> const&)
585
586
template <StringListRangeEmptyItems empties = StringListRangeEmptyItems::Skip,
587
          typename ListString, typename ItemString>
588
static bool
589
StringListContains(const ListString& aList, const ItemString& aItem)
590
0
{
591
0
  for (const auto& listItem : MakeStringListRange<empties>(aList)) {
592
0
    if (listItem.Equals(aItem)) {
593
0
      return true;
594
0
    }
595
0
  }
596
0
  return false;
597
0
}
Unexecuted instantiation: Unified_cpp_dom_media_doctor0.cpp:bool mozilla::StringListContains<(mozilla::StringListRangeEmptyItems)0, nsTSubstring<char16_t>, nsTString<char16_t> >(nsTSubstring<char16_t> const&, nsTString<char16_t> const&)
Unexecuted instantiation: Unified_cpp_dom_media_doctor0.cpp:bool mozilla::StringListContains<(mozilla::StringListRangeEmptyItems)0, nsTAutoStringN<char, 64ul>, char const*>(nsTAutoStringN<char, 64ul> const&, char const* const&)
Unexecuted instantiation: Unified_cpp_dom_media_doctor0.cpp:bool mozilla::StringListContains<(mozilla::StringListRangeEmptyItems)0, nsTAutoStringN<char, 64ul>, nsTString<char> >(nsTAutoStringN<char, 64ul> const&, nsTString<char> const&)
598
599
inline void
600
AppendStringIfNotEmpty(nsACString& aDest, nsACString&& aSrc)
601
{
602
  if (!aSrc.IsEmpty()) {
603
    aDest.Append(NS_LITERAL_CSTRING("\n"));
604
    aDest.Append(aSrc);
605
  }
606
}
607
608
} // end namespace mozilla
609
610
#endif