Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / canvas / QueueParamTraits.h
blobd83f6ac456d0b2282bd624071111f8843cecbe25
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=4 et :
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #ifndef _QUEUEPARAMTRAITS_H_
9 #define _QUEUEPARAMTRAITS_H_ 1
11 #include "ipc/EnumSerializer.h"
12 #include "mozilla/gfx/2D.h"
13 #include "mozilla/Assertions.h"
14 #include "mozilla/IntegerRange.h"
15 #include "mozilla/ipc/ProtocolUtils.h"
16 #include "mozilla/ipc/SharedMemory.h"
17 #include "mozilla/Logging.h"
18 #include "mozilla/TimeStamp.h"
19 #include "nsExceptionHandler.h"
20 #include "nsString.h"
21 #include "WebGLTypes.h"
23 #include <optional>
25 namespace mozilla::webgl {
27 template <typename T>
28 struct RemoveCVR {
29 using Type =
30 typename std::remove_reference<typename std::remove_cv<T>::type>::type;
33 /**
34 * QueueParamTraits provide the user with a way to implement PCQ argument
35 * (de)serialization. It uses a PcqView, which permits the system to
36 * abandon all changes to the underlying PCQ if any operation fails.
38 * The transactional nature of PCQ operations make the ideal behavior a bit
39 * complex. Since the PCQ has a fixed amount of memory available to it,
40 * TryInsert operations operations are expected to sometimes fail and be
41 * re-issued later. We want these failures to be inexpensive. The same
42 * goes for TryRemove, which fails when there isn't enough data in
43 * the queue yet for them to complete.
45 * Their expected interface is:
47 * template<> struct QueueParamTraits<typename RemoveCVR<Arg>::Type> {
48 * // Write data from aArg into the PCQ.
49 * static QueueStatus Write(ProducerView& aProducerView, const Arg& aArg)
50 * {...};
52 * // Read data from the PCQ into aArg, or just skip the data if aArg is null.
53 * static QueueStatus Read(ConsumerView& aConsumerView, Arg* aArg) {...}
54 * };
56 template <typename Arg>
57 struct QueueParamTraits; // Todo: s/QueueParamTraits/SizedParamTraits/
59 template <typename T>
60 inline Range<T> AsRange(T* const begin, T* const end) {
61 const auto size = MaybeAs<size_t>(end - begin);
62 MOZ_RELEASE_ASSERT(size);
63 return {begin, *size};
66 // -
67 // BytesAlwaysValidT
69 template <class T>
70 struct BytesAlwaysValidT {
71 using non_cv = typename std::remove_cv<T>::type;
72 static constexpr bool value =
73 std::is_arithmetic<T>::value && !std::is_same<non_cv, bool>::value;
75 static_assert(BytesAlwaysValidT<float>::value);
76 static_assert(!BytesAlwaysValidT<bool>::value);
77 static_assert(!BytesAlwaysValidT<const bool>::value);
78 static_assert(!BytesAlwaysValidT<int*>::value);
79 static_assert(BytesAlwaysValidT<intptr_t>::value);
81 template <class T, size_t N>
82 struct BytesAlwaysValidT<std::array<T, N>> {
83 static constexpr bool value = BytesAlwaysValidT<T>::value;
85 static_assert(BytesAlwaysValidT<std::array<int, 4>>::value);
86 static_assert(!BytesAlwaysValidT<std::array<bool, 4>>::value);
88 template <class T, size_t N>
89 struct BytesAlwaysValidT<T[N]> {
90 static constexpr bool value = BytesAlwaysValidT<T>::value;
92 static_assert(BytesAlwaysValidT<int[4]>::value);
93 static_assert(!BytesAlwaysValidT<bool[4]>::value);
95 // -
97 template <>
98 struct BytesAlwaysValidT<webgl::UniformDataVal> {
99 static constexpr bool value = true;
101 template <>
102 struct BytesAlwaysValidT<const webgl::UniformDataVal> {
103 static constexpr bool value = true;
106 // -
109 * Used to give QueueParamTraits a way to write to the Producer without
110 * actually altering it, in case the transaction fails.
111 * THis object maintains the error state of the transaction and
112 * discards commands issued after an error is encountered.
114 template <typename _Producer>
115 class ProducerView {
116 public:
117 using Producer = _Producer;
119 explicit ProducerView(Producer* aProducer) : mProducer(aProducer) {}
121 template <typename T>
122 bool WriteFromRange(const Range<const T>& src) {
123 static_assert(BytesAlwaysValidT<T>::value);
124 if (MOZ_LIKELY(mOk)) {
125 mOk &= mProducer->WriteFromRange(src);
127 return mOk;
131 * Copy bytes from aBuffer to the producer if there is enough room.
132 * aBufferSize must not be 0.
134 template <typename T>
135 inline bool Write(const T* begin, const T* end) {
136 MOZ_RELEASE_ASSERT(begin <= end);
137 return WriteFromRange(AsRange(begin, end));
141 * Serialize aArg using Arg's QueueParamTraits.
143 template <typename Arg>
144 bool WriteParam(const Arg& aArg) {
145 return mozilla::webgl::QueueParamTraits<
146 typename RemoveCVR<Arg>::Type>::Write(*this, aArg);
149 bool Ok() const { return mOk; }
151 private:
152 Producer* const mProducer;
153 bool mOk = true;
157 * Used to give QueueParamTraits a way to read from the Consumer without
158 * actually altering it, in case the transaction fails.
160 template <typename _Consumer>
161 class ConsumerView {
162 public:
163 using Consumer = _Consumer;
165 explicit ConsumerView(Consumer* aConsumer) : mConsumer(aConsumer) {}
168 * Read bytes from the consumer if there is enough data. aBuffer may
169 * be null (in which case the data is skipped)
171 template <typename T>
172 inline bool Read(T* const destBegin, T* const destEnd) {
173 MOZ_ASSERT(destBegin);
174 MOZ_RELEASE_ASSERT(destBegin <= destEnd);
176 const auto dest = AsRange(destBegin, destEnd);
177 const auto view = ReadRange<T>(dest.length());
178 if (MOZ_LIKELY(view)) {
179 const auto byteSize = ByteSize(dest);
180 if (MOZ_LIKELY(byteSize)) {
181 memcpy(dest.begin().get(), view->begin().get(), byteSize);
184 return mOk;
187 /// Return a view wrapping the shmem.
188 template <typename T>
189 inline Maybe<Range<const T>> ReadRange(const size_t elemCount) {
190 static_assert(BytesAlwaysValidT<T>::value);
191 if (MOZ_UNLIKELY(!mOk)) return {};
192 const auto view = mConsumer->template ReadRange<T>(elemCount);
193 mOk &= bool(view);
194 return view;
198 * Deserialize aArg using Arg's QueueParamTraits.
199 * If the return value is not Success then aArg is not changed.
201 template <typename Arg>
202 bool ReadParam(Arg* aArg) {
203 MOZ_ASSERT(aArg);
204 return mozilla::webgl::QueueParamTraits<std::remove_cv_t<Arg>>::Read(*this,
205 aArg);
208 bool Ok() const { return mOk; }
210 private:
211 Consumer* const mConsumer;
212 bool mOk = true;
215 // -
217 template <typename Arg>
218 struct QueueParamTraits {
219 template <typename ProducerView>
220 static bool Write(ProducerView& aProducerView, const Arg& aArg) {
221 static_assert(BytesAlwaysValidT<Arg>::value,
222 "No QueueParamTraits specialization was found for this type "
223 "and it does not satisfy BytesAlwaysValid.");
224 // Write self as binary
225 const auto pArg = &aArg;
226 return aProducerView.Write(pArg, pArg + 1);
229 template <typename ConsumerView>
230 static bool Read(ConsumerView& aConsumerView, Arg* aArg) {
231 static_assert(BytesAlwaysValidT<Arg>::value,
232 "No QueueParamTraits specialization was found for this type "
233 "and it does not satisfy BytesAlwaysValid.");
234 // Read self as binary
235 return aConsumerView.Read(aArg, aArg + 1);
239 // ---------------------------------------------------------------
241 template <>
242 struct QueueParamTraits<bool> {
243 using ParamType = bool;
245 template <typename U>
246 static auto Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
247 uint8_t temp = aArg ? 1 : 0;
248 return aProducerView.WriteParam(temp);
251 template <typename U>
252 static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
253 uint8_t temp;
254 if (aConsumerView.ReadParam(&temp)) {
255 MOZ_ASSERT(temp == 1 || temp == 0);
256 *aArg = temp ? true : false;
258 return aConsumerView.Ok();
262 // ---------------------------------------------------------------
264 template <class T>
265 struct QueueParamTraits_IsEnumCase {
266 template <typename ProducerView>
267 static bool Write(ProducerView& aProducerView, const T& aArg) {
268 MOZ_ASSERT(IsEnumCase(aArg));
269 const auto shadow = static_cast<std::underlying_type_t<T>>(aArg);
270 aProducerView.WriteParam(shadow);
271 return true;
274 template <typename ConsumerView>
275 static bool Read(ConsumerView& aConsumerView, T* aArg) {
276 auto shadow = std::underlying_type_t<T>{};
277 aConsumerView.ReadParam(&shadow);
278 const auto e = AsEnumCase<T>(shadow);
279 if (!e) return false;
280 *aArg = *e;
281 return true;
285 // ---------------------------------------------------------------
287 // We guarantee our robustness via these requirements:
288 // * Object.MutTiedFields() gives us a tuple,
289 // * where the combined sizeofs all field types sums to sizeof(Object),
290 // * (thus we know we are exhaustively listing all fields)
291 // * where feeding each field back into ParamTraits succeeds,
292 // * and ParamTraits is only automated for BytesAlwaysValidT<T> types.
293 // (BytesAlwaysValidT rejects bool and enum types, and only accepts int/float
294 // types, or array or std::arrays of such types)
295 // (Yes, bit-field fields are rejected by MutTiedFields too)
297 template <class T>
298 struct QueueParamTraits_TiedFields {
299 template <typename ProducerView>
300 static bool Write(ProducerView& aProducerView, const T& aArg) {
301 const auto fields = TiedFields(aArg);
302 static_assert(AreAllBytesTiedFields<T>(),
303 "Are there missing fields or padding between fields?");
305 bool ok = true;
306 MapTuple(fields, [&](const auto& field) {
307 ok &= aProducerView.WriteParam(field);
308 return true;
310 return ok;
313 template <typename ConsumerView>
314 static bool Read(ConsumerView& aConsumerView, T* aArg) {
315 const auto fields = TiedFields(*aArg);
316 static_assert(AreAllBytesTiedFields<T>());
318 bool ok = true;
319 MapTuple(fields, [&](auto& field) {
320 ok &= aConsumerView.ReadParam(&field);
321 return true;
323 return ok;
327 // ---------------------------------------------------------------
329 // Adapted from IPC::EnumSerializer, this class safely handles enum values,
330 // validating that they are in range using the same EnumValidators as IPDL
331 // (namely ContiguousEnumValidator and ContiguousEnumValidatorInclusive).
332 template <typename E, typename EnumValidator>
333 struct EnumSerializer {
334 using ParamType = E;
335 using DataType = typename std::underlying_type<E>::type;
337 template <typename U>
338 static auto Write(ProducerView<U>& aProducerView, const ParamType& aValue) {
339 MOZ_RELEASE_ASSERT(
340 EnumValidator::IsLegalValue(static_cast<DataType>(aValue)));
341 return aProducerView.WriteParam(DataType(aValue));
344 template <typename U>
345 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aResult) {
346 DataType value;
347 if (!aConsumerView.ReadParam(&value)) {
348 CrashReporter::RecordAnnotationCString(
349 CrashReporter::Annotation::IPCReadErrorReason, "Bad iter");
350 return false;
352 if (!EnumValidator::IsLegalValue(static_cast<DataType>(value))) {
353 CrashReporter::RecordAnnotationCString(
354 CrashReporter::Annotation::IPCReadErrorReason, "Illegal value");
355 return false;
358 *aResult = ParamType(value);
359 return true;
363 using IPC::ContiguousEnumValidator;
364 using IPC::ContiguousEnumValidatorInclusive;
366 template <typename E, E MinLegal, E HighBound>
367 struct ContiguousEnumSerializer
368 : EnumSerializer<E, ContiguousEnumValidator<E, MinLegal, HighBound>> {};
370 template <typename E, E MinLegal, E MaxLegal>
371 struct ContiguousEnumSerializerInclusive
372 : EnumSerializer<E,
373 ContiguousEnumValidatorInclusive<E, MinLegal, MaxLegal>> {
376 // ---------------------------------------------------------------
378 template <>
379 struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
380 using ParamType = webgl::TexUnpackBlobDesc;
382 template <typename U>
383 static bool Write(ProducerView<U>& view, const ParamType& in) {
384 MOZ_RELEASE_ASSERT(!in.image);
385 MOZ_RELEASE_ASSERT(!in.sd);
386 const bool isDataSurf = bool(in.dataSurf);
387 if (!view.WriteParam(in.imageTarget) || !view.WriteParam(in.size) ||
388 !view.WriteParam(in.srcAlphaType) || !view.WriteParam(in.unpacking) ||
389 !view.WriteParam(in.cpuData) || !view.WriteParam(in.pboOffset) ||
390 !view.WriteParam(in.structuredSrcSize) ||
391 !view.WriteParam(in.applyUnpackTransforms) ||
392 !view.WriteParam(isDataSurf)) {
393 return false;
395 if (isDataSurf) {
396 const auto& surf = in.dataSurf;
397 gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::READ);
398 if (!map.IsMapped()) {
399 return false;
401 const auto& surfSize = surf->GetSize();
402 const auto stride = *MaybeAs<size_t>(map.GetStride());
403 if (!view.WriteParam(surfSize) || !view.WriteParam(surf->GetFormat()) ||
404 !view.WriteParam(stride)) {
405 return false;
408 const size_t dataSize = stride * surfSize.height;
409 const auto& begin = map.GetData();
410 const auto range = Range<const uint8_t>{begin, dataSize};
411 if (!view.WriteFromRange(range)) {
412 return false;
415 return true;
418 template <typename U>
419 static bool Read(ConsumerView<U>& view, ParamType* const out) {
420 bool isDataSurf;
421 if (!view.ReadParam(&out->imageTarget) || !view.ReadParam(&out->size) ||
422 !view.ReadParam(&out->srcAlphaType) ||
423 !view.ReadParam(&out->unpacking) || !view.ReadParam(&out->cpuData) ||
424 !view.ReadParam(&out->pboOffset) ||
425 !view.ReadParam(&out->structuredSrcSize) ||
426 !view.ReadParam(&out->applyUnpackTransforms) ||
427 !view.ReadParam(&isDataSurf)) {
428 return false;
430 if (isDataSurf) {
431 gfx::IntSize surfSize;
432 gfx::SurfaceFormat format;
433 size_t stride;
434 if (!view.ReadParam(&surfSize) || !view.ReadParam(&format) ||
435 !view.ReadParam(&stride)) {
436 return false;
438 const size_t dataSize = stride * surfSize.height;
439 const auto range = view.template ReadRange<uint8_t>(dataSize);
440 if (!range) return false;
442 // DataSourceSurface demands pointer-to-mutable.
443 const auto bytes = const_cast<uint8_t*>(range->begin().get());
444 out->dataSurf = gfx::Factory::CreateWrappingDataSourceSurface(
445 bytes, stride, surfSize, format);
446 MOZ_ASSERT(out->dataSurf);
448 return true;
452 // ---------------------------------------------------------------
454 template <>
455 struct QueueParamTraits<nsACString> {
456 using ParamType = nsACString;
458 template <typename U>
459 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
460 if ((!aProducerView.WriteParam(aArg.IsVoid())) || aArg.IsVoid()) {
461 return false;
464 uint32_t len = aArg.Length();
465 if ((!aProducerView.WriteParam(len)) || (len == 0)) {
466 return false;
469 return aProducerView.Write(aArg.BeginReading(), len);
472 template <typename U>
473 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
474 bool isVoid = false;
475 if (!aConsumerView.ReadParam(&isVoid)) {
476 return false;
478 aArg->SetIsVoid(isVoid);
479 if (isVoid) {
480 return true;
483 uint32_t len = 0;
484 if (!aConsumerView.ReadParam(&len)) {
485 return false;
488 if (len == 0) {
489 *aArg = "";
490 return true;
493 char* buf = new char[len + 1];
494 if (!buf) {
495 return false;
497 if (!aConsumerView.Read(buf, len)) {
498 return false;
500 buf[len] = '\0';
501 aArg->Adopt(buf, len);
502 return true;
506 template <>
507 struct QueueParamTraits<nsAString> {
508 using ParamType = nsAString;
510 template <typename U>
511 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
512 if ((!aProducerView.WriteParam(aArg.IsVoid())) || (aArg.IsVoid())) {
513 return false;
515 // DLP: No idea if this includes null terminator
516 uint32_t len = aArg.Length();
517 if ((!aProducerView.WriteParam(len)) || (len == 0)) {
518 return false;
520 constexpr const uint32_t sizeofchar = sizeof(typename ParamType::char_type);
521 return aProducerView.Write(aArg.BeginReading(), len * sizeofchar);
524 template <typename U>
525 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
526 bool isVoid = false;
527 if (!aConsumerView.ReadParam(&isVoid)) {
528 return false;
530 aArg->SetIsVoid(isVoid);
531 if (isVoid) {
532 return true;
535 // DLP: No idea if this includes null terminator
536 uint32_t len = 0;
537 if (!aConsumerView.ReadParam(&len)) {
538 return false;
541 if (len == 0) {
542 *aArg = nsString();
543 return true;
546 uint32_t sizeofchar = sizeof(typename ParamType::char_type);
547 typename ParamType::char_type* buf = nullptr;
548 buf = static_cast<typename ParamType::char_type*>(
549 malloc((len + 1) * sizeofchar));
550 if (!buf) {
551 return false;
554 if (!aConsumerView.Read(buf, len * sizeofchar)) {
555 return false;
558 buf[len] = L'\0';
559 aArg->Adopt(buf, len);
560 return true;
564 template <>
565 struct QueueParamTraits<nsCString> : public QueueParamTraits<nsACString> {
566 using ParamType = nsCString;
569 template <>
570 struct QueueParamTraits<nsString> : public QueueParamTraits<nsAString> {
571 using ParamType = nsString;
574 // ---------------------------------------------------------------
576 template <typename NSTArrayType,
577 bool = BytesAlwaysValidT<typename NSTArrayType::value_type>::value>
578 struct NSArrayQueueParamTraits;
580 // For ElementTypes that are !BytesAlwaysValidT
581 template <typename _ElementType>
582 struct NSArrayQueueParamTraits<nsTArray<_ElementType>, false> {
583 using ElementType = _ElementType;
584 using ParamType = nsTArray<ElementType>;
586 template <typename U>
587 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
588 aProducerView.WriteParam(aArg.Length());
589 for (auto& elt : aArg) {
590 aProducerView.WriteParam(elt);
592 return true;
595 template <typename U>
596 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
597 size_t arrayLen;
598 if (!aConsumerView.ReadParam(&arrayLen)) {
599 return false;
602 if (!aArg->AppendElements(arrayLen, fallible)) {
603 return false;
606 for (auto i : IntegerRange(arrayLen)) {
607 ElementType& elt = aArg->ElementAt(i);
608 aConsumerView.ReadParam(elt);
610 return aConsumerView.Ok();
614 // For ElementTypes that are BytesAlwaysValidT
615 template <typename _ElementType>
616 struct NSArrayQueueParamTraits<nsTArray<_ElementType>, true> {
617 using ElementType = _ElementType;
618 using ParamType = nsTArray<ElementType>;
620 // TODO: Are there alignment issues?
621 template <typename U>
622 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
623 size_t arrayLen = aArg.Length();
624 aProducerView.WriteParam(arrayLen);
625 return aProducerView.Write(&aArg[0], aArg.Length() * sizeof(ElementType));
628 template <typename U>
629 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
630 size_t arrayLen;
631 if (!aConsumerView.ReadParam(&arrayLen)) {
632 return false;
635 if (!aArg->AppendElements(arrayLen, fallible)) {
636 return false;
639 return aConsumerView.Read(aArg->Elements(), arrayLen * sizeof(ElementType));
643 template <typename ElementType>
644 struct QueueParamTraits<nsTArray<ElementType>>
645 : public NSArrayQueueParamTraits<nsTArray<ElementType>> {
646 using ParamType = nsTArray<ElementType>;
649 // ---------------------------------------------------------------
651 template <typename ArrayType,
652 bool = BytesAlwaysValidT<typename ArrayType::ElementType>::value>
653 struct ArrayQueueParamTraits;
655 // For ElementTypes that are !BytesAlwaysValidT
656 template <typename _ElementType, size_t Length>
657 struct ArrayQueueParamTraits<Array<_ElementType, Length>, false> {
658 using ElementType = _ElementType;
659 using ParamType = Array<ElementType, Length>;
661 template <typename U>
662 static auto Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
663 for (const auto& elt : aArg) {
664 aProducerView.WriteParam(elt);
666 return aProducerView.Ok();
669 template <typename U>
670 static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
671 for (auto& elt : *aArg) {
672 aConsumerView.ReadParam(elt);
674 return aConsumerView.Ok();
678 // For ElementTypes that are BytesAlwaysValidT
679 template <typename _ElementType, size_t Length>
680 struct ArrayQueueParamTraits<Array<_ElementType, Length>, true> {
681 using ElementType = _ElementType;
682 using ParamType = Array<ElementType, Length>;
684 template <typename U>
685 static auto Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
686 return aProducerView.Write(aArg.begin(), sizeof(ElementType[Length]));
689 template <typename U>
690 static auto Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
691 return aConsumerView.Read(aArg->begin(), sizeof(ElementType[Length]));
695 template <typename ElementType, size_t Length>
696 struct QueueParamTraits<Array<ElementType, Length>>
697 : public ArrayQueueParamTraits<Array<ElementType, Length>> {
698 using ParamType = Array<ElementType, Length>;
701 // ---------------------------------------------------------------
703 template <typename ElementType>
704 struct QueueParamTraits<Maybe<ElementType>> {
705 using ParamType = Maybe<ElementType>;
707 template <typename U>
708 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
709 aProducerView.WriteParam(static_cast<bool>(aArg));
710 if (aArg) {
711 aProducerView.WriteParam(aArg.ref());
713 return aProducerView.Ok();
716 template <typename U>
717 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
718 bool isSome;
719 if (!aConsumerView.ReadParam(&isSome)) {
720 return false;
723 if (!isSome) {
724 aArg->reset();
725 return true;
728 aArg->emplace();
729 return aConsumerView.ReadParam(aArg->ptr());
733 // ---------------------------------------------------------------
735 template <typename TypeA, typename TypeB>
736 struct QueueParamTraits<std::pair<TypeA, TypeB>> {
737 using ParamType = std::pair<TypeA, TypeB>;
739 template <typename U>
740 static bool Write(ProducerView<U>& aProducerView, const ParamType& aArg) {
741 aProducerView.WriteParam(aArg.first());
742 return aProducerView.WriteParam(aArg.second());
745 template <typename U>
746 static bool Read(ConsumerView<U>& aConsumerView, ParamType* aArg) {
747 aConsumerView.ReadParam(aArg->first());
748 return aConsumerView.ReadParam(aArg->second());
752 } // namespace mozilla::webgl
754 #endif // _QUEUEPARAMTRAITS_H_