/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 |