tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ClientWebGLContext.h (86897B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #ifndef CLIENTWEBGLCONTEXT_H_
      7 #define CLIENTWEBGLCONTEXT_H_
      8 
      9 #include <memory>
     10 #include <type_traits>
     11 #include <unordered_map>
     12 #include <unordered_set>
     13 #include <vector>
     14 
     15 #include "GLConsts.h"
     16 #include "WebGLCommandQueue.h"
     17 #include "WebGLStrongTypes.h"
     18 #include "WebGLTypes.h"
     19 #include "js/GCAPI.h"
     20 #include "mozilla/Logging.h"
     21 #include "mozilla/Range.h"
     22 #include "mozilla/RefCounted.h"
     23 #include "mozilla/StaticPrefs_webgl.h"
     24 #include "mozilla/WeakPtr.h"
     25 #include "mozilla/dom/BufferSourceBindingFwd.h"
     26 #include "mozilla/dom/ImageData.h"
     27 #include "mozilla/dom/TypedArray.h"
     28 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
     29 #include "mozilla/dom/WebGLRenderingContextBinding.h"
     30 #include "mozilla/layers/LayersSurfaces.h"
     31 #include "nsICanvasRenderingContextInternal.h"
     32 #include "nsWrapperCache.h"
     33 
     34 namespace mozilla {
     35 
     36 class ClientWebGLExtensionBase;
     37 class HostWebGLContext;
     38 
     39 template <typename MethodT, MethodT Method>
     40 size_t IdByMethod();
     41 
     42 namespace dom {
     43 class OwningHTMLCanvasElementOrOffscreenCanvas;
     44 class WebGLChild;
     45 }  // namespace dom
     46 
     47 namespace webgl {
     48 class AvailabilityRunnable;
     49 class TexUnpackBlob;
     50 class TexUnpackBytes;
     51 }  // namespace webgl
     52 
     53 ////////////////////////////////////
     54 
     55 class WebGLActiveInfoJS final : public RefCounted<WebGLActiveInfoJS> {
     56 public:
     57  MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLActiveInfoJS)
     58 
     59  const webgl::ActiveInfo mInfo;
     60 
     61  explicit WebGLActiveInfoJS(const webgl::ActiveInfo& info) : mInfo(info) {}
     62 
     63  virtual ~WebGLActiveInfoJS() = default;
     64 
     65  // -
     66  // WebIDL attributes
     67 
     68  GLint Size() const { return static_cast<GLint>(mInfo.elemCount); }
     69  GLenum Type() const { return mInfo.elemType; }
     70 
     71  void GetName(nsString& retval) const { CopyUTF8toUTF16(mInfo.name, retval); }
     72 
     73  bool WrapObject(JSContext*, JS::Handle<JSObject*>,
     74                  JS::MutableHandle<JSObject*>);
     75 };
     76 
     77 class WebGLShaderPrecisionFormatJS final
     78    : public RefCounted<WebGLShaderPrecisionFormatJS> {
     79 public:
     80  MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLShaderPrecisionFormatJS)
     81 
     82  const webgl::ShaderPrecisionFormat mInfo;
     83 
     84  explicit WebGLShaderPrecisionFormatJS(
     85      const webgl::ShaderPrecisionFormat& info)
     86      : mInfo(info) {}
     87 
     88  virtual ~WebGLShaderPrecisionFormatJS() = default;
     89 
     90  GLint RangeMin() const { return mInfo.rangeMin; }
     91  GLint RangeMax() const { return mInfo.rangeMax; }
     92  GLint Precision() const { return mInfo.precision; }
     93 
     94  bool WrapObject(JSContext*, JS::Handle<JSObject*>,
     95                  JS::MutableHandle<JSObject*>);
     96 };
     97 
     98 // -----------------------
     99 
    100 class ClientWebGLContext;
    101 class WebGLBufferJS;
    102 class WebGLFramebufferJS;
    103 class WebGLProgramJS;
    104 class WebGLQueryJS;
    105 class WebGLRenderbufferJS;
    106 class WebGLSamplerJS;
    107 class WebGLShaderJS;
    108 class WebGLTextureJS;
    109 class WebGLTransformFeedbackJS;
    110 class WebGLVertexArrayJS;
    111 
    112 namespace webgl {
    113 
    114 struct LinkResult;
    115 
    116 class ProgramKeepAlive final {
    117  friend class mozilla::WebGLProgramJS;
    118 
    119  WebGLProgramJS* mParent;
    120 
    121 public:
    122  explicit ProgramKeepAlive(WebGLProgramJS& parent) : mParent(&parent) {}
    123  ~ProgramKeepAlive();
    124 };
    125 
    126 class ShaderKeepAlive final {
    127  friend class mozilla::WebGLShaderJS;
    128 
    129  const WebGLShaderJS* mParent;
    130 
    131 public:
    132  explicit ShaderKeepAlive(const WebGLShaderJS& parent) : mParent(&parent) {}
    133  ~ShaderKeepAlive();
    134 };
    135 
    136 class ContextGenerationInfo final {
    137 public:
    138  webgl::ExtensionBits mEnabledExtensions;
    139  RefPtr<WebGLProgramJS> mCurrentProgram;
    140  std::shared_ptr<webgl::ProgramKeepAlive> mProgramKeepAlive;
    141  mutable std::shared_ptr<webgl::LinkResult> mActiveLinkResult;
    142 
    143  RefPtr<WebGLTransformFeedbackJS> mDefaultTfo;
    144  RefPtr<WebGLVertexArrayJS> mDefaultVao;
    145 
    146  std::unordered_map<GLenum, RefPtr<WebGLBufferJS>> mBoundBufferByTarget;
    147  std::vector<RefPtr<WebGLBufferJS>> mBoundUbos;
    148  RefPtr<WebGLFramebufferJS> mBoundDrawFb;
    149  RefPtr<WebGLFramebufferJS> mBoundReadFb;
    150  RefPtr<WebGLRenderbufferJS> mBoundRb;
    151  RefPtr<WebGLTransformFeedbackJS> mBoundTfo;
    152  RefPtr<WebGLVertexArrayJS> mBoundVao;
    153  std::unordered_map<GLenum, RefPtr<WebGLQueryJS>> mCurrentQueryByTarget;
    154 
    155  struct TexUnit final {
    156    RefPtr<WebGLSamplerJS> sampler;
    157    std::unordered_map<GLenum, RefPtr<WebGLTextureJS>> texByTarget;
    158  };
    159  uint32_t mActiveTexUnit = 0;
    160  std::vector<TexUnit> mTexUnits;
    161 
    162  bool mTfActiveAndNotPaused = false;
    163 
    164  std::vector<TypedQuad> mGenericVertexAttribs;
    165 
    166  std::array<int32_t, 4> mScissor = {};
    167  std::array<int32_t, 4> mViewport = {};
    168  std::array<float, 4> mClearColor = {{0, 0, 0, 0}};
    169  std::array<float, 4> mBlendColor = {{0, 0, 0, 0}};
    170  std::array<float, 2> mDepthRange = {{0, 1}};
    171  webgl::PixelPackingState mPixelPackState;
    172  webgl::PixelUnpackStateWebgl mPixelUnpackState;
    173 
    174  std::vector<GLenum> mCompressedTextureFormats;
    175 
    176  Maybe<uvec2> mDrawingBufferSize;
    177 
    178  webgl::ProvokingVertex mProvokingVertex = webgl::ProvokingVertex::LastVertex;
    179 
    180  mutable std::unordered_map<GLenum, bool> mIsEnabledMap;
    181 };
    182 
    183 // -
    184 
    185 // In the cross process case, the WebGL actor's ownership relationship looks
    186 // like this:
    187 // ---------------------------------------------------------------------
    188 // | ClientWebGLContext -> WebGLChild -> WebGLParent -> HostWebGLContext
    189 // ---------------------------------------------------------------------
    190 //
    191 // where 'A -> B' means "A owns B"
    192 
    193 struct NotLostData final : public SupportsWeakPtr, RefCounted<NotLostData> {
    194  MOZ_DECLARE_REFCOUNTED_TYPENAME(NotLostData)
    195 
    196  ClientWebGLContext& context;
    197  webgl::InitContextResult info;
    198 
    199  RefPtr<mozilla::dom::WebGLChild> outOfProcess;
    200  std::unique_ptr<HostWebGLContext> inProcess;
    201 
    202  webgl::ContextGenerationInfo state;
    203  std::array<RefPtr<ClientWebGLExtensionBase>,
    204             UnderlyingValue(WebGLExtensionID::Max)>
    205      extensions;
    206 
    207  RefPtr<layers::CanvasRenderer> mCanvasRenderer;
    208 
    209  explicit NotLostData(ClientWebGLContext& context);
    210  ~NotLostData();
    211 };
    212 
    213 // -
    214 
    215 class ObjectJS {
    216  friend ClientWebGLContext;
    217 
    218 public:
    219  const WeakPtr<NotLostData> mGeneration;
    220  const ObjectId mId;
    221 
    222 protected:
    223  bool mDeleteRequested = false;
    224 
    225  explicit ObjectJS(const ClientWebGLContext*);
    226  virtual ~ObjectJS() = default;
    227 
    228 public:
    229  ClientWebGLContext* Context() const {
    230    if (!mGeneration) return nullptr;
    231    return &(mGeneration->context);
    232  }
    233 
    234  ClientWebGLContext* GetParentObject() const { return Context(); }
    235 
    236  // A la carte:
    237  bool IsForContext(const ClientWebGLContext&) const;
    238  virtual bool IsDeleted() const { return mDeleteRequested; }
    239 
    240  bool IsUsable(const ClientWebGLContext& context) const {
    241    return IsForContext(context) && !IsDeleted();
    242  }
    243 
    244  // The workhorse:
    245  bool ValidateUsable(const ClientWebGLContext& context,
    246                      const char* const argName) const {
    247    if (MOZ_LIKELY(IsUsable(context))) return true;
    248    WarnInvalidUse(context, argName);
    249    return false;
    250  }
    251 
    252  // Use by DeleteFoo:
    253  bool ValidateForContext(const ClientWebGLContext& context,
    254                          const char* const argName) const;
    255 
    256 private:
    257  void WarnInvalidUse(const ClientWebGLContext&, const char* argName) const;
    258 
    259  // The enum is INVALID_VALUE for Program/Shader :(
    260  virtual GLenum ErrorOnDeleted() const { return LOCAL_GL_INVALID_OPERATION; }
    261 };
    262 
    263 }  // namespace webgl
    264 
    265 // -------------------------
    266 
    267 class WebGLBufferJS final : public nsWrapperCache, public webgl::ObjectJS {
    268  friend class ClientWebGLContext;
    269 
    270  webgl::BufferKind mKind =
    271      webgl::BufferKind::Undefined;  // !IsBuffer until Bind
    272 
    273 public:
    274  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBufferJS)
    275  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLBufferJS)
    276 
    277  explicit WebGLBufferJS(const ClientWebGLContext& webgl)
    278      : webgl::ObjectJS(&webgl) {}
    279 
    280 private:
    281  ~WebGLBufferJS();
    282 
    283 public:
    284  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    285 };
    286 
    287 // -
    288 
    289 class WebGLFramebufferJS final : public nsWrapperCache, public webgl::ObjectJS {
    290  friend class ClientWebGLContext;
    291 
    292 public:
    293  struct Attachment final {
    294    RefPtr<WebGLRenderbufferJS> rb;
    295    RefPtr<WebGLTextureJS> tex;
    296  };
    297 
    298 private:
    299  bool mHasBeenBound = false;  // !IsFramebuffer until Bind
    300  std::unordered_map<GLenum, Attachment> mAttachments;
    301 
    302 public:
    303  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebufferJS)
    304  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLFramebufferJS)
    305 
    306  explicit WebGLFramebufferJS(const ClientWebGLContext&, bool opaque = false);
    307 
    308  const bool mOpaque;
    309  bool mInOpaqueRAF = false;
    310 
    311 private:
    312  ~WebGLFramebufferJS();
    313 
    314  void EnsureColorAttachments();
    315 
    316 public:
    317  Attachment* GetAttachment(const GLenum slotEnum) {
    318    auto ret = MaybeFind(mAttachments, slotEnum);
    319    if (!ret) {
    320      EnsureColorAttachments();
    321      ret = MaybeFind(mAttachments, slotEnum);
    322    }
    323    return ret;
    324  }
    325 
    326  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    327 };
    328 
    329 // -
    330 
    331 class WebGLProgramJS final : public nsWrapperCache, public webgl::ObjectJS {
    332  friend class ClientWebGLContext;
    333 
    334 public:
    335  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgramJS)
    336  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLProgramJS)
    337  // Must come first!
    338  // If the REFCOUNTING macro isn't declared first, the AddRef at
    339  // mInnerRef->js will panic when REFCOUNTING's "owning thread" var is still
    340  // uninitialized.
    341 
    342  struct Attachment final {
    343    RefPtr<WebGLShaderJS> shader;
    344    std::shared_ptr<webgl::ShaderKeepAlive> keepAlive;
    345  };
    346 
    347 private:
    348  std::shared_ptr<webgl::ProgramKeepAlive> mKeepAlive;
    349  const std::weak_ptr<webgl::ProgramKeepAlive> mKeepAliveWeak;
    350 
    351  std::unordered_map<GLenum, Attachment> mNextLink_Shaders;
    352  bool mLastValidate = false;
    353  mutable std::shared_ptr<webgl::LinkResult>
    354      mResult;  // Never null, often defaulted.
    355 
    356  struct UniformLocInfo final {
    357    const uint32_t location;
    358    const GLenum elemType;
    359  };
    360 
    361  mutable Maybe<std::unordered_map<std::string, UniformLocInfo>>
    362      mUniformLocByName;
    363  mutable std::vector<uint32_t> mUniformBlockBindings;
    364 
    365  std::unordered_set<const WebGLTransformFeedbackJS*> mActiveTfos;
    366 
    367  explicit WebGLProgramJS(const ClientWebGLContext&);
    368 
    369  ~WebGLProgramJS() {
    370    mKeepAlive = nullptr;  // Try to delete.
    371 
    372    const auto& maybe = mKeepAliveWeak.lock();
    373    if (maybe) {
    374      maybe->mParent = nullptr;
    375    }
    376  }
    377 
    378 public:
    379  bool IsDeleted() const override { return !mKeepAliveWeak.lock(); }
    380  GLenum ErrorOnDeleted() const override { return LOCAL_GL_INVALID_VALUE; }
    381 
    382  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    383 };
    384 
    385 // -
    386 
    387 class WebGLQueryJS final : public nsWrapperCache,
    388                           public webgl::ObjectJS,
    389                           public SupportsWeakPtr {
    390  friend class ClientWebGLContext;
    391  friend class webgl::AvailabilityRunnable;
    392 
    393  GLenum mTarget = 0;  // !IsQuery until Bind
    394  bool mCanBeAvailable = false;
    395 
    396 public:
    397  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQueryJS)
    398  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLQueryJS)
    399 
    400  explicit WebGLQueryJS(const ClientWebGLContext* const webgl)
    401      : webgl::ObjectJS(webgl) {}
    402 
    403 private:
    404  ~WebGLQueryJS();
    405 
    406 public:
    407  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    408 };
    409 
    410 // -
    411 
    412 class WebGLRenderbufferJS final : public nsWrapperCache,
    413                                  public webgl::ObjectJS {
    414  friend class ClientWebGLContext;
    415 
    416 public:
    417  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbufferJS)
    418  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLRenderbufferJS)
    419 
    420 private:
    421  bool mHasBeenBound = false;  // !IsRenderbuffer until Bind
    422 
    423  explicit WebGLRenderbufferJS(const ClientWebGLContext& webgl)
    424      : webgl::ObjectJS(&webgl) {}
    425  ~WebGLRenderbufferJS();
    426 
    427 public:
    428  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    429 };
    430 
    431 // -
    432 
    433 class WebGLSamplerJS final : public nsWrapperCache, public webgl::ObjectJS {
    434  // IsSampler without Bind
    435 public:
    436  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSamplerJS)
    437  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSamplerJS)
    438 
    439  explicit WebGLSamplerJS(const ClientWebGLContext& webgl)
    440      : webgl::ObjectJS(&webgl) {}
    441 
    442 private:
    443  ~WebGLSamplerJS();
    444 
    445 public:
    446  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    447 };
    448 
    449 // -
    450 
    451 class WebGLShaderJS final : public nsWrapperCache, public webgl::ObjectJS {
    452  friend class ClientWebGLContext;
    453 
    454 public:
    455  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShaderJS)
    456  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLShaderJS)
    457 
    458 private:
    459  const GLenum mType;
    460  std::string mSource;
    461  std::shared_ptr<webgl::ShaderKeepAlive> mKeepAlive;
    462  const std::weak_ptr<webgl::ShaderKeepAlive> mKeepAliveWeak;
    463 
    464  mutable webgl::CompileResult mResult;
    465 
    466  WebGLShaderJS(const ClientWebGLContext&, GLenum type);
    467 
    468  ~WebGLShaderJS() {
    469    mKeepAlive = nullptr;  // Try to delete.
    470 
    471    const auto& maybe = mKeepAliveWeak.lock();
    472    if (maybe) {
    473      maybe->mParent = nullptr;
    474    }
    475  }
    476 
    477 public:
    478  bool IsDeleted() const override { return !mKeepAliveWeak.lock(); }
    479  GLenum ErrorOnDeleted() const override { return LOCAL_GL_INVALID_VALUE; }
    480 
    481  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    482 };
    483 
    484 // -
    485 
    486 class WebGLSyncJS final : public nsWrapperCache,
    487                          public webgl::ObjectJS,
    488                          public SupportsWeakPtr {
    489  friend class ClientWebGLContext;
    490  friend class webgl::AvailabilityRunnable;
    491 
    492  bool mCanBeAvailable = false;
    493  uint8_t mNumQueriesBeforeFirstFrameBoundary = 0;
    494  uint8_t mNumQueriesWithoutFlushCommandsBit = 0;
    495 
    496 public:
    497  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSyncJS)
    498  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSyncJS)
    499 
    500  explicit WebGLSyncJS(const ClientWebGLContext& webgl)
    501      : webgl::ObjectJS(&webgl) {}
    502 
    503 private:
    504  ~WebGLSyncJS();
    505 
    506 public:
    507  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    508 };
    509 
    510 // -
    511 
    512 class WebGLTextureJS final : public nsWrapperCache, public webgl::ObjectJS {
    513  friend class ClientWebGLContext;
    514 
    515  GLenum mTarget = 0;  // !IsTexture until Bind
    516 
    517 public:
    518  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTextureJS)
    519  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTextureJS)
    520 
    521  explicit WebGLTextureJS(const ClientWebGLContext& webgl)
    522      : webgl::ObjectJS(&webgl) {}
    523 
    524 private:
    525  ~WebGLTextureJS();
    526 
    527 public:
    528  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    529 };
    530 
    531 // -
    532 
    533 class WebGLTransformFeedbackJS final : public nsWrapperCache,
    534                                       public webgl::ObjectJS {
    535  friend class ClientWebGLContext;
    536 
    537  bool mHasBeenBound = false;  // !IsTransformFeedback until Bind
    538  bool mActiveOrPaused = false;
    539  std::vector<RefPtr<WebGLBufferJS>> mAttribBuffers;
    540  RefPtr<WebGLProgramJS> mActiveProgram;
    541  std::shared_ptr<webgl::ProgramKeepAlive> mActiveProgramKeepAlive;
    542 
    543 public:
    544  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedbackJS)
    545  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTransformFeedbackJS)
    546 
    547  explicit WebGLTransformFeedbackJS(const ClientWebGLContext&);
    548 
    549 private:
    550  ~WebGLTransformFeedbackJS();
    551 
    552 public:
    553  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    554 };
    555 
    556 // -
    557 
    558 std::array<uint16_t, 3> ValidUploadElemTypes(GLenum);
    559 
    560 class WebGLUniformLocationJS final : public nsWrapperCache,
    561                                     public webgl::ObjectJS {
    562  friend class ClientWebGLContext;
    563 
    564  const WeakPtr<webgl::LinkResult> mParent;
    565  const uint32_t mLocation;
    566  const std::array<uint16_t, 3> mValidUploadElemTypes;
    567 
    568 public:
    569  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocationJS)
    570  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLUniformLocationJS)
    571 
    572  WebGLUniformLocationJS(const ClientWebGLContext& webgl,
    573                         const WeakPtr<webgl::LinkResult>& parent, uint32_t loc,
    574                         GLenum elemType)
    575      : webgl::ObjectJS(&webgl),
    576        mParent(parent),
    577        mLocation(loc),
    578        mValidUploadElemTypes(ValidUploadElemTypes(elemType)) {}
    579 
    580 private:
    581  ~WebGLUniformLocationJS() = default;
    582 
    583 public:
    584  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    585 };
    586 
    587 // -
    588 
    589 class WebGLVertexArrayJS final : public nsWrapperCache, public webgl::ObjectJS {
    590  friend class ClientWebGLContext;
    591 
    592  bool mHasBeenBound = false;  // !IsVertexArray until Bind
    593  RefPtr<WebGLBufferJS> mIndexBuffer;
    594  std::vector<RefPtr<WebGLBufferJS>> mAttribBuffers;
    595 
    596 public:
    597  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArrayJS)
    598  NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLVertexArrayJS)
    599 
    600  explicit WebGLVertexArrayJS(const ClientWebGLContext*);
    601 
    602 private:
    603  ~WebGLVertexArrayJS();
    604 
    605 public:
    606  JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
    607 };
    608 
    609 ////////////////////////////////////
    610 
    611 using Float32ListU = dom::MaybeSharedFloat32ArrayOrUnrestrictedFloatSequence;
    612 using Int32ListU = dom::MaybeSharedInt32ArrayOrLongSequence;
    613 using Uint32ListU = dom::MaybeSharedUint32ArrayOrUnsignedLongSequence;
    614 
    615 template <typename Converter, typename T>
    616 inline bool ConvertSequence(const dom::Sequence<T>& sequence,
    617                            Converter&& converter) {
    618  // It's ok to GC here, but we need a common parameter list for
    619  // Converter with the typed array version.
    620  JS::AutoCheckCannotGC nogc;
    621  nogc.reset();
    622  return std::forward<Converter>(converter)(Span(sequence), std::move(nogc));
    623 }
    624 
    625 template <typename Converter>
    626 inline bool Convert(const Float32ListU& list, Converter&& converter) {
    627  if (list.IsFloat32Array()) {
    628    return list.GetAsFloat32Array().ProcessData(
    629        std::forward<Converter>(converter));
    630  }
    631 
    632  return ConvertSequence(list.GetAsUnrestrictedFloatSequence(),
    633                         std::forward<Converter>(converter));
    634 }
    635 
    636 template <typename Converter>
    637 inline bool Convert(const Int32ListU& list, Converter&& converter) {
    638  if (list.IsInt32Array()) {
    639    return list.GetAsInt32Array().ProcessData(
    640        std::forward<Converter>(converter));
    641  }
    642 
    643  return ConvertSequence(list.GetAsLongSequence(),
    644                         std::forward<Converter>(converter));
    645 }
    646 
    647 template <typename Converter>
    648 inline bool Convert(const Uint32ListU& list, Converter&& converter) {
    649  if (list.IsUint32Array()) {
    650    return list.GetAsUint32Array().ProcessData(
    651        std::forward<Converter>(converter));
    652  }
    653 
    654  return ConvertSequence(list.GetAsUnsignedLongSequence(),
    655                         std::forward<Converter>(converter));
    656 }
    657 
    658 template <typename T>
    659 inline Range<const uint8_t> MakeByteRange(const T& x) {
    660  const auto typed = MakeRange(x);
    661  return Range<const uint8_t>(
    662      reinterpret_cast<const uint8_t*>(typed.begin().get()),
    663      typed.length() * sizeof(typed[0]));
    664 }
    665 
    666 template <typename T>
    667 inline Range<const uint8_t> MakeByteRange(const Span<T>& x) {
    668  return AsBytes(x);
    669 }
    670 
    671 // -
    672 
    673 struct TexImageSourceAdapter final : public TexImageSource {
    674  TexImageSourceAdapter(const dom::Nullable<dom::ArrayBufferView>* maybeView,
    675                        ErrorResult*) {
    676    if (!maybeView->IsNull()) {
    677      mView = &(maybeView->Value());
    678    }
    679  }
    680 
    681  TexImageSourceAdapter(const dom::Nullable<dom::ArrayBufferView>* maybeView,
    682                        GLuint viewElemOffset) {
    683    if (!maybeView->IsNull()) {
    684      mView = &(maybeView->Value());
    685    }
    686    mViewElemOffset = viewElemOffset;
    687  }
    688 
    689  TexImageSourceAdapter(const dom::ArrayBufferView* view, ErrorResult*) {
    690    mView = view;
    691  }
    692 
    693  TexImageSourceAdapter(const dom::ArrayBufferView* view, GLuint viewElemOffset,
    694                        GLuint viewElemLengthOverride = 0) {
    695    mView = view;
    696    mViewElemOffset = viewElemOffset;
    697    mViewElemLengthOverride = viewElemLengthOverride;
    698  }
    699 
    700  explicit TexImageSourceAdapter(const WebGLintptr* pboOffset,
    701                                 GLuint ignored1 = 0, GLuint ignored2 = 0) {
    702    mPboOffset = pboOffset;
    703  }
    704 
    705  TexImageSourceAdapter(const WebGLintptr* pboOffset, ErrorResult* ignored) {
    706    mPboOffset = pboOffset;
    707  }
    708 
    709  TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap,
    710                        ErrorResult* out_error) {
    711    mImageBitmap = imageBitmap;
    712    mOut_error = out_error;
    713  }
    714 
    715  TexImageSourceAdapter(const dom::ImageData* imageData, ErrorResult*) {
    716    mImageData = imageData;
    717  }
    718 
    719  TexImageSourceAdapter(const dom::OffscreenCanvas* offscreenCanvas,
    720                        ErrorResult* const out_error) {
    721    mOffscreenCanvas = offscreenCanvas;
    722    mOut_error = out_error;
    723  }
    724 
    725  TexImageSourceAdapter(const dom::VideoFrame* videoFrame,
    726                        ErrorResult* const out_error) {
    727    mVideoFrame = videoFrame;
    728    mOut_error = out_error;
    729  }
    730 
    731  TexImageSourceAdapter(const dom::Element* domElem,
    732                        ErrorResult* const out_error) {
    733    mDomElem = domElem;
    734    mOut_error = out_error;
    735  }
    736 };
    737 
    738 /**
    739 * Base class for all IDL implementations of WebGLContext
    740 */
    741 class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
    742                                 public nsWrapperCache {
    743  friend class webgl::AvailabilityRunnable;
    744  friend class webgl::ObjectJS;
    745  friend class webgl::ProgramKeepAlive;
    746  friend class webgl::ShaderKeepAlive;
    747 
    748  // ----------------------------- Lifetime and DOM ---------------------------
    749 public:
    750  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
    751  NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ClientWebGLContext)
    752 
    753  JSObject* WrapObject(JSContext* cx,
    754                       JS::Handle<JSObject*> givenProto) override {
    755    if (mIsWebGL2) {
    756      return dom::WebGL2RenderingContext_Binding::Wrap(cx, this, givenProto);
    757    }
    758    return dom::WebGLRenderingContext_Binding::Wrap(cx, this, givenProto);
    759  }
    760 
    761  // -
    762 
    763 public:
    764  const bool mIsWebGL2;
    765 
    766 private:
    767  bool mIsCanvasDirty = false;
    768  uvec2 mRequestedSize = {};
    769 
    770 public:
    771  explicit ClientWebGLContext(bool webgl2);
    772 
    773 private:
    774  virtual ~ClientWebGLContext();
    775 
    776  const RefPtr<ClientWebGLExtensionLoseContext> mExtLoseContext;
    777 
    778  mutable RefPtr<webgl::NotLostData> mNotLost;
    779  mutable GLenum mNextError = 0;
    780  mutable webgl::LossStatus mLossStatus = webgl::LossStatus::Ready;
    781  mutable bool mAwaitingRestore = false;
    782  mutable webgl::ObjectId mLastId = 0;
    783 
    784 public:
    785  webgl::ObjectId NextId() const { return mLastId += 1; }
    786 
    787  // Holds Some Id if async present is used
    788  mutable Maybe<layers::RemoteTextureId> mLastRemoteTextureId;
    789  mutable Maybe<layers::RemoteTextureOwnerId> mRemoteTextureOwnerId;
    790  mutable RefPtr<layers::FwdTransactionTracker> mFwdTransactionTracker;
    791 
    792  // -
    793 
    794 public:
    795  const auto& Limits() const { return mNotLost->info.limits; }
    796  const auto& Vendor() const { return mNotLost->info.vendor; }
    797  // https://www.khronos.org/registry/webgl/specs/latest/1.0/#actual-context-parameters
    798  const WebGLContextOptions& ActualContextParameters() const {
    799    MOZ_ASSERT(mNotLost != nullptr);
    800    return mNotLost->info.options;
    801  }
    802 
    803  auto& State() { return mNotLost->state; }
    804  const auto& State() const {
    805    return const_cast<ClientWebGLContext*>(this)->State();
    806  }
    807 
    808  // -
    809 
    810 private:
    811  mutable RefPtr<webgl::AvailabilityRunnable> mAvailabilityRunnable;
    812 
    813 public:
    814  webgl::AvailabilityRunnable& EnsureAvailabilityRunnable() const;
    815 
    816  // -
    817 
    818 public:
    819  void EmulateLoseContext() const;
    820  void OnContextLoss(webgl::ContextLossReason) const;
    821  void RestoreContext(webgl::LossStatus requiredStatus) const;
    822 
    823 private:
    824  bool DispatchEvent(const nsAString&) const;
    825  void Event_webglcontextlost() const;
    826  void Event_webglcontextrestored() const;
    827 
    828  bool CreateHostContext(const uvec2& requestedSize);
    829  void ThrowEvent_WebGLContextCreationError(const std::string&) const;
    830 
    831  void UpdateCanvasParameters();
    832 
    833 public:
    834  void MarkCanvasDirty();
    835 
    836  void MarkContextClean() override {}
    837 
    838  void OnBeforePaintTransaction() override;
    839 
    840  mozilla::dom::WebGLChild* GetChild() const {
    841    if (!mNotLost) return nullptr;
    842    if (!mNotLost->outOfProcess) return nullptr;
    843    return mNotLost->outOfProcess.get();
    844  }
    845 
    846  // -------------------------------------------------------------------------
    847  // Client WebGL API call tracking and error message reporting
    848  // -------------------------------------------------------------------------
    849 public:
    850  // Remembers the WebGL function that is lowest on the stack for client-side
    851  // error generation.
    852  class FuncScope final {
    853   public:
    854    const ClientWebGLContext& mWebGL;
    855    const RefPtr<webgl::NotLostData> mKeepNotLostOrNull;
    856    const char* const mFuncName;
    857 
    858    FuncScope(const ClientWebGLContext& webgl, const char* funcName)
    859        : mWebGL(webgl),
    860          mKeepNotLostOrNull(webgl.mNotLost),
    861          mFuncName(funcName) {
    862      // Only set if an "outer" scope hasn't already been set.
    863      if (!mWebGL.mFuncScope) {
    864        mWebGL.mFuncScope = this;
    865      }
    866    }
    867 
    868    ~FuncScope() {
    869      if (this == mWebGL.mFuncScope) {
    870        mWebGL.mFuncScope = nullptr;
    871      }
    872    }
    873 
    874    FuncScope(const FuncScope&) = delete;
    875    FuncScope(FuncScope&&) = delete;
    876  };
    877 
    878 protected:
    879  // The scope of the function at the top of the current WebGL function call
    880  // stack
    881  mutable FuncScope* mFuncScope = nullptr;
    882 
    883  const char* FuncName() const {
    884    return mFuncScope ? mFuncScope->mFuncName : nullptr;
    885  }
    886 
    887 public:
    888  template <typename... Args>
    889  void EnqueueError(const GLenum error, const char* const format,
    890                    const Args&... args) const {
    891    MOZ_ASSERT(FuncName());
    892    nsCString text;
    893 
    894 #ifdef __clang__
    895 #  pragma clang diagnostic push
    896 #  pragma clang diagnostic ignored "-Wformat-security"
    897 #elif defined(__GNUC__)
    898 #  pragma GCC diagnostic push
    899 #  pragma GCC diagnostic ignored "-Wformat-security"
    900 #  pragma GCC diagnostic ignored "-Wformat-overflow"
    901 #endif
    902    text.AppendPrintf("WebGL warning: %s: ", FuncName());
    903    text.AppendPrintf(format, args...);
    904 #ifdef __clang__
    905 #  pragma clang diagnostic pop
    906 #elif defined(__GNUC__)
    907 #  pragma GCC diagnostic pop
    908 #endif
    909 
    910    EnqueueErrorImpl(error, text);
    911  }
    912 
    913  void EnqueueError(const webgl::ErrorInfo& info) const {
    914    EnqueueError(info.type, "%s", info.info.c_str());
    915  }
    916 
    917  template <typename... Args>
    918  void EnqueueWarning(const char* const format, const Args&... args) const {
    919    EnqueueError(0, format, args...);
    920  }
    921 
    922  template <typename... Args>
    923  void EnqueuePerfWarning(const char* const format, const Args&... args) const {
    924    EnqueueError(webgl::kErrorPerfWarning, format, args...);
    925  }
    926 
    927  void EnqueueError_ArgEnum(const char* argName,
    928                            GLenum val) const;  // Cold code.
    929 
    930 private:
    931  void EnqueueErrorImpl(GLenum errorOrZero, const nsACString&) const;
    932 
    933 public:
    934  Maybe<Span<uint8_t>> ValidateArrayBufferView(const Span<uint8_t>& bytes,
    935                                               size_t elemSize,
    936                                               GLuint elemOffset,
    937                                               GLuint elemCountOverride,
    938                                               const GLenum errorEnum) const;
    939 
    940 protected:
    941  template <typename T>
    942  bool ValidateNonNull(const char* const argName,
    943                       const dom::Nullable<T>& maybe) const {
    944    if (maybe.IsNull()) {
    945      EnqueueError(LOCAL_GL_INVALID_VALUE, "%s: Cannot be null.", argName);
    946      return false;
    947    }
    948    return true;
    949  }
    950 
    951  bool ValidateNonNegative(const char* argName, int64_t val) const {
    952    if (MOZ_UNLIKELY(val < 0)) {
    953      EnqueueError(LOCAL_GL_INVALID_VALUE, "`%s` must be non-negative.",
    954                   argName);
    955      return false;
    956    }
    957    return true;
    958  }
    959 
    960  bool ValidateViewType(GLenum unpackType, const TexImageSource& src) const;
    961 
    962  Maybe<uvec3> ValidateExtents(GLsizei width, GLsizei height, GLsizei depth,
    963                               GLint border) const;
    964 
    965  // -------------------------------------------------------------------------
    966  // nsICanvasRenderingContextInternal / nsAPostRefreshObserver
    967  // -------------------------------------------------------------------------
    968 public:
    969  bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder,
    970                                layers::CanvasRenderer* aRenderer) override;
    971 
    972  void MarkContextCleanForFrameCapture() override {
    973    mFrameCaptureState = FrameCaptureState::CLEAN;
    974  }
    975  // Note that 'clean' here refers to its invalidation state, not the
    976  // contents of the buffer.
    977  Watchable<FrameCaptureState>* GetFrameCaptureState() override {
    978    return &mFrameCaptureState;
    979  }
    980 
    981  void OnMemoryPressure() override;
    982  void SetContextOptions(const WebGLContextOptions& aOptions) {
    983    mInitialOptions.emplace(aOptions);
    984  }
    985  const WebGLContextOptions& GetContextOptions() const {
    986    return mInitialOptions.ref();
    987  }
    988  NS_IMETHOD
    989  SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options,
    990                    ErrorResult& aRvForDictionaryInit) override;
    991  NS_IMETHOD
    992  SetDimensions(int32_t width, int32_t height) override;
    993  bool UpdateWebRenderCanvasData(
    994      nsDisplayListBuilder* aBuilder,
    995      layers::WebRenderCanvasData* aCanvasData) override;
    996 
    997  // ------
    998 
    999  int32_t GetWidth() override { return AutoAssertCast(DrawingBufferSize().x); }
   1000  int32_t GetHeight() override { return AutoAssertCast(DrawingBufferSize().y); }
   1001 
   1002  NS_IMETHOD InitializeWithDrawTarget(nsIDocShell*,
   1003                                      NotNull<gfx::DrawTarget*>) override {
   1004    return NS_ERROR_NOT_IMPLEMENTED;
   1005  }
   1006 
   1007  void ResetBitmap() override;
   1008 
   1009  UniquePtr<uint8_t[]> GetImageBuffer(
   1010      mozilla::CanvasUtils::ImageExtraction aExtractionBehavior,
   1011      int32_t* out_format, gfx::IntSize* out_imageSize) override;
   1012  NS_IMETHOD GetInputStream(
   1013      const char* mimeType, const nsAString& encoderOptions,
   1014      mozilla::CanvasUtils::ImageExtraction extractionBehavior,
   1015      const nsACString& randomizationKey, nsIInputStream** out_stream) override;
   1016 
   1017  already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(
   1018      gfxAlphaType* out_alphaType) override;
   1019 
   1020  mozilla::ipc::IProtocol* SupportsSnapshotExternalCanvas() const override;
   1021 
   1022  void SetOpaqueValueFromOpaqueAttr(bool) override {};
   1023  bool GetIsOpaque() override { return !mInitialOptions->alpha; }
   1024 
   1025  /**
   1026   * An abstract base class to be implemented by callers wanting to be notified
   1027   * that a refresh has occurred. Callers must ensure an observer is removed
   1028   * before it is destroyed.
   1029   */
   1030  void DidRefresh() override;
   1031 
   1032  NS_IMETHOD Redraw(const gfxRect&) override {
   1033    return NS_ERROR_NOT_IMPLEMENTED;
   1034  }
   1035 
   1036  // ------
   1037 
   1038 protected:
   1039  layers::LayersBackend GetCompositorBackendType() const;
   1040 
   1041  Watchable<FrameCaptureState> mFrameCaptureState = {
   1042      FrameCaptureState::CLEAN, "ClientWebGLContext::mFrameCaptureState"};
   1043 
   1044  // -------------------------------------------------------------------------
   1045  // WebGLRenderingContext Basic Properties and Methods
   1046  // -------------------------------------------------------------------------
   1047 public:
   1048  dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
   1049  void Commit();
   1050  void GetCanvas(
   1051      dom::Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval);
   1052 
   1053  GLsizei DrawingBufferWidth() {
   1054    const FuncScope funcScope(*this, "drawingBufferWidth");
   1055    return AutoAssertCast(DrawingBufferSize().x);
   1056  }
   1057  GLsizei DrawingBufferHeight() {
   1058    const FuncScope funcScope(*this, "drawingBufferHeight");
   1059    return AutoAssertCast(DrawingBufferSize().y);
   1060  }
   1061 
   1062  // -
   1063 
   1064 private:
   1065  std::optional<dom::PredefinedColorSpace> mDrawingBufferColorSpace;
   1066  std::optional<dom::PredefinedColorSpace> mUnpackColorSpace;
   1067 
   1068 public:
   1069  auto DrawingBufferColorSpace() const {
   1070    return mDrawingBufferColorSpace ? *mDrawingBufferColorSpace
   1071                                    : dom::PredefinedColorSpace::Srgb;
   1072  }
   1073  void SetDrawingBufferColorSpace(dom::PredefinedColorSpace);
   1074 
   1075  auto UnpackColorSpace() const {
   1076    return mUnpackColorSpace ? *mUnpackColorSpace
   1077                             : dom::PredefinedColorSpace::Srgb;
   1078  }
   1079  void SetUnpackColorSpace(dom::PredefinedColorSpace);
   1080 
   1081  // -
   1082 
   1083  void GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);
   1084 
   1085 private:
   1086  webgl::SwapChainOptions PrepareAsyncSwapChainOptions(
   1087      WebGLFramebufferJS* fb, bool webvr,
   1088      const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
   1089 
   1090 public:
   1091  layers::TextureType GetTexTypeForSwapChain() const;
   1092  void Present(
   1093      WebGLFramebufferJS*, const bool webvr = false,
   1094      const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
   1095  void Present(
   1096      WebGLFramebufferJS*, layers::TextureType, const bool webvr = false,
   1097      const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
   1098  void CopyToSwapChain(
   1099      WebGLFramebufferJS*,
   1100      const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
   1101  void EndOfFrame();
   1102  Maybe<layers::SurfaceDescriptor> GetFrontBuffer(
   1103      WebGLFramebufferJS*, const bool webvr = false) override;
   1104  Maybe<layers::SurfaceDescriptor> PresentFrontBuffer(
   1105      WebGLFramebufferJS*, const bool webvr = false) override;
   1106  RefPtr<gfx::SourceSurface> GetFrontBufferSnapshot(
   1107      bool requireAlphaPremult = true) override;
   1108  already_AddRefed<layers::FwdTransactionTracker> UseCompositableForwarder(
   1109      layers::CompositableForwarder* aForwarder) override;
   1110  void OnDestroyChild(dom::WebGLChild* aChild);
   1111 
   1112  void ClearVRSwapChain();
   1113 
   1114 private:
   1115  RefPtr<gfx::DataSourceSurface> BackBufferSnapshot();
   1116  [[nodiscard]] bool DoReadPixels(const webgl::ReadPixelsDesc&,
   1117                                  Span<uint8_t>) const;
   1118  uvec2 DrawingBufferSize();
   1119 
   1120  // -
   1121 
   1122  mutable bool mAutoFlushPending = false;
   1123 
   1124  void AutoEnqueueFlush() const {
   1125    if (MOZ_LIKELY(mAutoFlushPending)) return;
   1126    mAutoFlushPending = true;
   1127 
   1128    const auto DeferredFlush = [weak =
   1129                                    WeakPtr<const ClientWebGLContext>(this)]() {
   1130      const auto strong = RefPtr<const ClientWebGLContext>(weak);
   1131      if (!strong) return;
   1132      if (!strong->mAutoFlushPending) return;
   1133      strong->mAutoFlushPending = false;
   1134 
   1135      if (!StaticPrefs::webgl_auto_flush()) return;
   1136      const bool flushGl = StaticPrefs::webgl_auto_flush_gl();
   1137      strong->Flush(flushGl);
   1138    };
   1139 
   1140    already_AddRefed<mozilla::CancelableRunnable> runnable =
   1141        NS_NewCancelableRunnableFunction("ClientWebGLContext::DeferredFlush",
   1142                                         DeferredFlush);
   1143    NS_DispatchToCurrentThread(std::move(runnable));
   1144  }
   1145 
   1146  void CancelAutoFlush() const { mAutoFlushPending = false; }
   1147 
   1148  // -
   1149 
   1150  void AfterDrawCall() {
   1151    if (!mNotLost) return;
   1152    const auto& state = State();
   1153    if (!state.mBoundDrawFb) {
   1154      MarkCanvasDirty();
   1155    }
   1156 
   1157    AutoEnqueueFlush();
   1158  }
   1159 
   1160  // -------------------------------------------------------------------------
   1161  // Client-side helper methods.  Dispatch to a Host method.
   1162  // -------------------------------------------------------------------------
   1163 
   1164  // ------------------------- GL State -------------------------
   1165 public:
   1166  bool IsContextLost() const { return !mNotLost; }
   1167 
   1168  void Disable(GLenum cap) const { SetEnabledI(cap, {}, false); }
   1169  void Enable(GLenum cap) const { SetEnabledI(cap, {}, true); }
   1170  void SetEnabledI(GLenum cap, Maybe<GLuint> i, bool val) const;
   1171 
   1172  bool IsEnabled(GLenum cap) const;
   1173 
   1174 private:
   1175  Maybe<double> GetNumber(GLenum pname);
   1176  Maybe<std::string> GetString(GLenum pname);
   1177 
   1178 public:
   1179  void GetParameter(JSContext* cx, GLenum pname,
   1180                    JS::MutableHandle<JS::Value> retval, ErrorResult& rv,
   1181                    bool debug = false);
   1182 
   1183  void GetBufferParameter(JSContext* cx, GLenum target, GLenum pname,
   1184                          JS::MutableHandle<JS::Value> retval) const;
   1185 
   1186  void GetFramebufferAttachmentParameter(JSContext* cx, GLenum target,
   1187                                         GLenum attachment, GLenum pname,
   1188                                         JS::MutableHandle<JS::Value> retval,
   1189                                         ErrorResult& rv) const;
   1190 
   1191  void GetRenderbufferParameter(JSContext* cx, GLenum target, GLenum pname,
   1192                                JS::MutableHandle<JS::Value> retval) const;
   1193 
   1194  void GetIndexedParameter(JSContext* cx, GLenum target, GLuint index,
   1195                           JS::MutableHandle<JS::Value> retval,
   1196                           ErrorResult& rv) const;
   1197 
   1198  already_AddRefed<WebGLShaderPrecisionFormatJS> GetShaderPrecisionFormat(
   1199      GLenum shadertype, GLenum precisiontype);
   1200 
   1201  void UseProgram(WebGLProgramJS*);
   1202  void ValidateProgram(WebGLProgramJS&) const;
   1203 
   1204  // -
   1205 
   1206  already_AddRefed<WebGLBufferJS> CreateBuffer() const;
   1207  already_AddRefed<WebGLFramebufferJS> CreateFramebuffer() const;
   1208  already_AddRefed<WebGLFramebufferJS> CreateOpaqueFramebuffer(
   1209      const webgl::OpaqueFramebufferOptions&) const;
   1210  already_AddRefed<WebGLProgramJS> CreateProgram() const;
   1211  already_AddRefed<WebGLQueryJS> CreateQuery() const;
   1212  already_AddRefed<WebGLRenderbufferJS> CreateRenderbuffer() const;
   1213  already_AddRefed<WebGLSamplerJS> CreateSampler() const;
   1214  already_AddRefed<WebGLShaderJS> CreateShader(GLenum type) const;
   1215  already_AddRefed<WebGLSyncJS> FenceSync(GLenum condition,
   1216                                          GLbitfield flags) const;
   1217  already_AddRefed<WebGLTextureJS> CreateTexture() const;
   1218  already_AddRefed<WebGLTransformFeedbackJS> CreateTransformFeedback() const;
   1219  already_AddRefed<WebGLVertexArrayJS> CreateVertexArray() const;
   1220 
   1221  void DeleteBuffer(WebGLBufferJS*);
   1222  void DeleteFramebuffer(WebGLFramebufferJS*, bool canDeleteOpaque = false);
   1223  void DeleteProgram(WebGLProgramJS*) const;
   1224  void DeleteQuery(WebGLQueryJS*);
   1225  void DeleteRenderbuffer(WebGLRenderbufferJS*);
   1226  void DeleteSampler(WebGLSamplerJS*);
   1227  void DeleteShader(WebGLShaderJS*) const;
   1228  void DeleteSync(WebGLSyncJS*) const;
   1229  void DeleteTexture(WebGLTextureJS*);
   1230  void DeleteTransformFeedback(WebGLTransformFeedbackJS*);
   1231  void DeleteVertexArray(WebGLVertexArrayJS*);
   1232 
   1233 private:
   1234  void DoDeleteProgram(WebGLProgramJS&) const;
   1235  void DoDeleteShader(const WebGLShaderJS&) const;
   1236 
   1237 public:
   1238  // -
   1239 
   1240  bool IsBuffer(const WebGLBufferJS*) const;
   1241  bool IsFramebuffer(const WebGLFramebufferJS*) const;
   1242  bool IsProgram(const WebGLProgramJS*) const;
   1243  bool IsQuery(const WebGLQueryJS*) const;
   1244  bool IsRenderbuffer(const WebGLRenderbufferJS*) const;
   1245  bool IsSampler(const WebGLSamplerJS*) const;
   1246  bool IsShader(const WebGLShaderJS*) const;
   1247  bool IsSync(const WebGLSyncJS*) const;
   1248  bool IsTexture(const WebGLTextureJS*) const;
   1249  bool IsTransformFeedback(const WebGLTransformFeedbackJS*) const;
   1250  bool IsVertexArray(const WebGLVertexArrayJS*) const;
   1251 
   1252  // -
   1253  // WebGLProgramJS
   1254 
   1255 private:
   1256  const webgl::LinkResult& GetLinkResult(const WebGLProgramJS&) const;
   1257 
   1258 public:
   1259  void AttachShader(WebGLProgramJS&, WebGLShaderJS&) const;
   1260  void BindAttribLocation(WebGLProgramJS&, GLuint location,
   1261                          const nsAString& name) const;
   1262  void DetachShader(WebGLProgramJS&, const WebGLShaderJS&) const;
   1263  void GetAttachedShaders(
   1264      const WebGLProgramJS&,
   1265      dom::Nullable<nsTArray<RefPtr<WebGLShaderJS>>>& retval) const;
   1266  void LinkProgram(WebGLProgramJS&) const;
   1267  void TransformFeedbackVaryings(WebGLProgramJS&,
   1268                                 const dom::Sequence<nsString>& varyings,
   1269                                 GLenum bufferMode) const;
   1270  void UniformBlockBinding(WebGLProgramJS&, GLuint blockIndex,
   1271                           GLuint blockBinding) const;
   1272 
   1273  // Link result reflection
   1274  already_AddRefed<WebGLActiveInfoJS> GetActiveAttrib(const WebGLProgramJS&,
   1275                                                      GLuint index);
   1276  already_AddRefed<WebGLActiveInfoJS> GetActiveUniform(const WebGLProgramJS&,
   1277                                                       GLuint index);
   1278  void GetActiveUniformBlockName(const WebGLProgramJS&,
   1279                                 GLuint uniformBlockIndex,
   1280                                 nsAString& retval) const;
   1281  void GetActiveUniformBlockParameter(JSContext* cx, const WebGLProgramJS&,
   1282                                      GLuint uniformBlockIndex, GLenum pname,
   1283                                      JS::MutableHandle<JS::Value> retval,
   1284                                      ErrorResult& rv);
   1285  void GetActiveUniforms(JSContext*, const WebGLProgramJS&,
   1286                         const dom::Sequence<GLuint>& uniformIndices,
   1287                         GLenum pname,
   1288                         JS::MutableHandle<JS::Value> retval) const;
   1289  GLint GetAttribLocation(const WebGLProgramJS&, const nsAString& name) const;
   1290  GLint GetFragDataLocation(const WebGLProgramJS&, const nsAString& name) const;
   1291  void GetProgramInfoLog(const WebGLProgramJS& prog, nsAString& retval) const;
   1292  void GetProgramParameter(JSContext*, const WebGLProgramJS&, GLenum pname,
   1293                           JS::MutableHandle<JS::Value> retval) const;
   1294  already_AddRefed<WebGLActiveInfoJS> GetTransformFeedbackVarying(
   1295      const WebGLProgramJS&, GLuint index);
   1296  GLuint GetUniformBlockIndex(const WebGLProgramJS&,
   1297                              const nsAString& uniformBlockName) const;
   1298  void GetUniformIndices(const WebGLProgramJS&,
   1299                         const dom::Sequence<nsString>& uniformNames,
   1300                         dom::Nullable<nsTArray<GLuint>>& retval) const;
   1301 
   1302  // WebGLUniformLocationJS
   1303  already_AddRefed<WebGLUniformLocationJS> GetUniformLocation(
   1304      const WebGLProgramJS&, const nsAString& name) const;
   1305  void GetUniform(JSContext*, const WebGLProgramJS&,
   1306                  const WebGLUniformLocationJS&,
   1307                  JS::MutableHandle<JS::Value> retval);
   1308 
   1309  // -
   1310  // WebGLShaderJS
   1311 
   1312 private:
   1313  const webgl::CompileResult& GetCompileResult(const WebGLShaderJS&) const;
   1314 
   1315 public:
   1316  void CompileShader(WebGLShaderJS&) const;
   1317  void GetShaderInfoLog(const WebGLShaderJS&, nsAString& retval) const;
   1318  void GetShaderParameter(JSContext*, const WebGLShaderJS&, GLenum pname,
   1319                          JS::MutableHandle<JS::Value> retval) const;
   1320  void GetShaderSource(const WebGLShaderJS&, nsAString& retval) const;
   1321  void GetTranslatedShaderSource(const WebGLShaderJS& shader,
   1322                                 nsAString& retval) const;
   1323  void ShaderSource(WebGLShaderJS&, const nsAString&) const;
   1324 
   1325  // -
   1326 
   1327  void BindFramebuffer(GLenum target, WebGLFramebufferJS*);
   1328 
   1329  void BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a);
   1330 
   1331  // -
   1332 
   1333  void BlendEquation(GLenum mode) { BlendEquationSeparate(mode, mode); }
   1334  void BlendFunc(GLenum sfactor, GLenum dfactor) {
   1335    BlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
   1336  }
   1337 
   1338  void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {
   1339    BlendEquationSeparateI({}, modeRGB, modeAlpha);
   1340  }
   1341  void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha,
   1342                         GLenum dstAlpha) {
   1343    BlendFuncSeparateI({}, srcRGB, dstRGB, srcAlpha, dstAlpha);
   1344  }
   1345 
   1346  void BlendEquationSeparateI(Maybe<GLuint> buf, GLenum modeRGB,
   1347                              GLenum modeAlpha);
   1348  void BlendFuncSeparateI(Maybe<GLuint> buf, GLenum srcRGB, GLenum dstRGB,
   1349                          GLenum srcAlpha, GLenum dstAlpha);
   1350 
   1351  // -
   1352 
   1353  GLenum CheckFramebufferStatus(GLenum target);
   1354 
   1355  void Clear(GLbitfield mask);
   1356 
   1357  // -
   1358 
   1359 private:
   1360  void ClearBufferTv(const GLenum buffer, const GLint drawBuffer,
   1361                     const webgl::AttribBaseType type,
   1362                     JS::AutoCheckCannotGC&& nogc,
   1363                     const Span<const uint8_t>& view,
   1364                     const GLuint srcElemOffset);
   1365 
   1366 public:
   1367  void ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32ListU& list,
   1368                     GLuint srcElemOffset) {
   1369    const FuncScope funcScope(*this, "clearBufferfv");
   1370    if (!Convert(list, [&](const Span<const float>& aData,
   1371                           JS::AutoCheckCannotGC&& nogc) {
   1372          ClearBufferTv(buffer, drawBuffer, webgl::AttribBaseType::Float,
   1373                        std::move(nogc), AsBytes(aData), srcElemOffset);
   1374          return true;
   1375        })) {
   1376      EnqueueError(LOCAL_GL_INVALID_VALUE, "`values` too small.");
   1377    }
   1378  }
   1379  void ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32ListU& list,
   1380                     GLuint srcElemOffset) {
   1381    const FuncScope funcScope(*this, "clearBufferiv");
   1382    if (!Convert(list, [&](const Span<const int32_t>& aData,
   1383                           JS::AutoCheckCannotGC&& nogc) {
   1384          ClearBufferTv(buffer, drawBuffer, webgl::AttribBaseType::Int,
   1385                        std::move(nogc), AsBytes(aData), srcElemOffset);
   1386          return true;
   1387        })) {
   1388      EnqueueError(LOCAL_GL_INVALID_VALUE, "`values` too small.");
   1389    }
   1390  }
   1391  void ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32ListU& list,
   1392                      GLuint srcElemOffset) {
   1393    const FuncScope funcScope(*this, "clearBufferuiv");
   1394    if (!Convert(list, [&](const Span<const uint32_t>& aData,
   1395                           JS::AutoCheckCannotGC&& nogc) {
   1396          ClearBufferTv(buffer, drawBuffer, webgl::AttribBaseType::Uint,
   1397                        std::move(nogc), AsBytes(aData), srcElemOffset);
   1398          return true;
   1399        })) {
   1400      EnqueueError(LOCAL_GL_INVALID_VALUE, "`values` too small.");
   1401    }
   1402  }
   1403 
   1404  // -
   1405 
   1406  void ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
   1407                     GLint stencil);
   1408 
   1409  void ClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a);
   1410 
   1411  void ClearDepth(GLclampf v);
   1412 
   1413  void ClearStencil(GLint v);
   1414 
   1415  void ColorMask(bool r, bool g, bool b, bool a) const {
   1416    ColorMaskI({}, r, g, b, a);
   1417  }
   1418  void ColorMaskI(Maybe<GLuint> buf, bool r, bool g, bool b, bool a) const;
   1419 
   1420  void CullFace(GLenum face);
   1421 
   1422  void DepthFunc(GLenum func);
   1423 
   1424  void DepthMask(WebGLboolean b);
   1425 
   1426  void DepthRange(GLclampf zNear, GLclampf zFar);
   1427 
   1428  void Flush(bool flushGl = true) const;
   1429 
   1430  void SyncSnapshot() override { Flush(); }
   1431 
   1432  void Finish();
   1433 
   1434  void FrontFace(GLenum mode);
   1435 
   1436  GLenum GetError();
   1437 
   1438  void Hint(GLenum target, GLenum mode);
   1439 
   1440  void LineWidth(GLfloat width);
   1441 
   1442  void PixelStorei(GLenum pname, GLint param);
   1443 
   1444  void PolygonOffset(GLfloat factor, GLfloat units);
   1445 
   1446  void SampleCoverage(GLclampf value, WebGLboolean invert);
   1447 
   1448  void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
   1449 
   1450  // -
   1451 
   1452  void StencilFunc(GLenum func, GLint ref, GLuint mask) {
   1453    StencilFuncSeparate(LOCAL_GL_FRONT_AND_BACK, func, ref, mask);
   1454  }
   1455  void StencilMask(GLuint mask) {
   1456    StencilMaskSeparate(LOCAL_GL_FRONT_AND_BACK, mask);
   1457  }
   1458  void StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) {
   1459    StencilOpSeparate(LOCAL_GL_FRONT_AND_BACK, sfail, dpfail, dppass);
   1460  }
   1461 
   1462  void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask);
   1463  void StencilMaskSeparate(GLenum face, GLuint mask);
   1464  void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
   1465                         GLenum dppass);
   1466 
   1467  // -
   1468 
   1469  void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
   1470 
   1471  // ------------------------- Buffer Objects -------------------------
   1472 public:
   1473  void BindBuffer(GLenum target, WebGLBufferJS*);
   1474 
   1475  // -
   1476 
   1477 private:
   1478  void BindBufferRangeImpl(const GLenum target, const GLuint index,
   1479                           WebGLBufferJS* const buffer, const uint64_t offset,
   1480                           const uint64_t size);
   1481 
   1482 public:
   1483  void BindBufferBase(const GLenum target, const GLuint index,
   1484                      WebGLBufferJS* const buffer) {
   1485    const FuncScope funcScope(*this, "bindBufferBase");
   1486    if (IsContextLost()) return;
   1487 
   1488    BindBufferRangeImpl(target, index, buffer, 0, 0);
   1489  }
   1490 
   1491  void BindBufferRange(const GLenum target, const GLuint index,
   1492                       WebGLBufferJS* const buffer, const WebGLintptr offset,
   1493                       const WebGLsizeiptr size) {
   1494    const FuncScope funcScope(*this, "bindBufferRange");
   1495    if (IsContextLost()) return;
   1496 
   1497    if (buffer) {
   1498      if (!ValidateNonNegative("offset", offset)) return;
   1499 
   1500      if (size < 1) {
   1501        EnqueueError(LOCAL_GL_INVALID_VALUE,
   1502                     "`size` must be positive for non-null `buffer`.");
   1503        return;
   1504      }
   1505    }
   1506 
   1507    BindBufferRangeImpl(target, index, buffer, static_cast<uint64_t>(offset),
   1508                        static_cast<uint64_t>(size));
   1509  }
   1510 
   1511  // -
   1512 
   1513  void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
   1514                         GLintptr readOffset, GLintptr writeOffset,
   1515                         GLsizeiptr size);
   1516 
   1517  void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
   1518  void BufferData(GLenum target,
   1519                  const dom::Nullable<dom::ArrayBuffer>& maybeSrc,
   1520                  GLenum usage);
   1521  void BufferData(GLenum target, const dom::ArrayBufferView& srcData,
   1522                  GLenum usage, GLuint srcElemOffset = 0,
   1523                  GLuint srcElemCountOverride = 0);
   1524 
   1525  void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
   1526                     const dom::ArrayBufferView& src, GLuint srcElemOffset = 0,
   1527                     GLuint srcElemCountOverride = 0);
   1528  void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
   1529                     const dom::ArrayBuffer& src);
   1530  void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset,
   1531                     const dom::AllowSharedBufferSource& src);
   1532 
   1533  void GetBufferSubData(GLenum target, GLintptr srcByteOffset,
   1534                        const dom::ArrayBufferView& dstData,
   1535                        GLuint dstElemOffset, GLuint dstElemCountOverride);
   1536 
   1537  // -------------------------- Framebuffer Objects --------------------------
   1538 
   1539  void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
   1540                       GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
   1541                       GLbitfield mask, GLenum filter);
   1542 
   1543  // -
   1544 
   1545 private:
   1546  // `bindTarget` if non-zero allows initializing the rb/tex with that target.
   1547  void FramebufferAttach(GLenum target, GLenum attachEnum, GLenum bindTarget,
   1548                         WebGLRenderbufferJS*, WebGLTextureJS*,
   1549                         uint32_t mipLevel, uint32_t zLayer,
   1550                         uint32_t numViewLayers) const;
   1551 
   1552 public:
   1553  void FramebufferRenderbuffer(GLenum target, GLenum attachSlot,
   1554                               GLenum rbTarget, WebGLRenderbufferJS* rb) const {
   1555    const FuncScope funcScope(*this, "framebufferRenderbuffer");
   1556    if (IsContextLost()) return;
   1557    if (rbTarget != LOCAL_GL_RENDERBUFFER) {
   1558      EnqueueError_ArgEnum("rbTarget", rbTarget);
   1559      return;
   1560    }
   1561    FramebufferAttach(target, attachSlot, rbTarget, rb, nullptr, 0, 0, 0);
   1562  }
   1563 
   1564  void FramebufferTexture2D(GLenum target, GLenum attachSlot,
   1565                            GLenum texImageTarget, WebGLTextureJS*,
   1566                            GLint mipLevel) const;
   1567 
   1568  void FramebufferTextureLayer(GLenum target, GLenum attachSlot,
   1569                               WebGLTextureJS* tex, GLint mipLevel,
   1570                               GLint zLayer) const {
   1571    const FuncScope funcScope(*this, "framebufferTextureLayer");
   1572    if (IsContextLost()) return;
   1573    FramebufferAttach(target, attachSlot, 0, nullptr, tex,
   1574                      static_cast<uint32_t>(mipLevel),
   1575                      static_cast<uint32_t>(zLayer), 0);
   1576  }
   1577 
   1578  void FramebufferTextureMultiview(GLenum target, GLenum attachSlot,
   1579                                   WebGLTextureJS* tex, GLint mipLevel,
   1580                                   GLint zLayerBase,
   1581                                   GLsizei numViewLayers) const {
   1582    const FuncScope funcScope(*this, "framebufferTextureMultiview");
   1583    if (IsContextLost()) return;
   1584    if (tex && numViewLayers < 1) {
   1585      EnqueueError(LOCAL_GL_INVALID_VALUE, "`numViewLayers` must be >=1.");
   1586      return;
   1587    }
   1588    FramebufferAttach(target, attachSlot, 0, nullptr, tex,
   1589                      static_cast<uint32_t>(mipLevel),
   1590                      static_cast<uint32_t>(zLayerBase),
   1591                      static_cast<uint32_t>(numViewLayers));
   1592  }
   1593 
   1594  // -
   1595 
   1596  void InvalidateFramebuffer(GLenum target,
   1597                             const dom::Sequence<GLenum>& attachments,
   1598                             ErrorResult& unused);
   1599  void InvalidateSubFramebuffer(GLenum target,
   1600                                const dom::Sequence<GLenum>& attachments,
   1601                                GLint x, GLint y, GLsizei width, GLsizei height,
   1602                                ErrorResult& unused);
   1603 
   1604  void ReadBuffer(GLenum mode);
   1605 
   1606  // ----------------------- Renderbuffer objects -----------------------
   1607  void GetInternalformatParameter(JSContext* cx, GLenum target,
   1608                                  GLenum internalformat, GLenum pname,
   1609                                  JS::MutableHandle<JS::Value> retval,
   1610                                  ErrorResult& rv);
   1611 
   1612  void BindRenderbuffer(GLenum target, WebGLRenderbufferJS*);
   1613 
   1614  void RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width,
   1615                           GLsizei height) const {
   1616    RenderbufferStorageMultisample(target, 0, internalFormat, width, height);
   1617  }
   1618 
   1619  void RenderbufferStorageMultisample(GLenum target, GLsizei samples,
   1620                                      GLenum internalFormat, GLsizei width,
   1621                                      GLsizei height) const;
   1622 
   1623  // --------------------------- Texture objects ---------------------------
   1624 
   1625  void ActiveTexture(GLenum texUnit);
   1626 
   1627  void BindTexture(GLenum texTarget, WebGLTextureJS*);
   1628 
   1629  void GenerateMipmap(GLenum texTarget) const;
   1630 
   1631  void GetTexParameter(JSContext* cx, GLenum texTarget, GLenum pname,
   1632                       JS::MutableHandle<JS::Value> retval) const;
   1633 
   1634  void TexParameterf(GLenum texTarget, GLenum pname, GLfloat param);
   1635  void TexParameteri(GLenum texTarget, GLenum pname, GLint param);
   1636 
   1637  // -
   1638 
   1639 private:
   1640  void TexStorage(uint8_t funcDims, GLenum target, GLsizei levels,
   1641                  GLenum internalFormat, const ivec3& size) const;
   1642 
   1643  // Primitive tex upload functions
   1644  void TexImage(uint8_t funcDims, GLenum target, GLint level,
   1645                GLenum respecFormat, const ivec3& offset,
   1646                const Maybe<ivec3>& size, GLint border,
   1647                const webgl::PackingInfo& pi, const TexImageSource& src) const;
   1648  void CompressedTexImage(bool sub, uint8_t funcDims, GLenum target,
   1649                          GLint level, GLenum format, const ivec3& offset,
   1650                          const ivec3& size, GLint border,
   1651                          const TexImageSource& src,
   1652                          GLsizei pboImageSize) const;
   1653  void CopyTexImage(uint8_t funcDims, GLenum target, GLint level,
   1654                    GLenum respecFormat, const ivec3& dstOffset,
   1655                    const ivec2& srcOffset, const ivec2& size,
   1656                    GLint border) const;
   1657 
   1658 public:
   1659  void TexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat,
   1660                    GLsizei width, GLsizei height) const {
   1661    TexStorage(2, target, levels, internalFormat, {width, height, 1});
   1662  }
   1663 
   1664  void TexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat,
   1665                    GLsizei width, GLsizei height, GLsizei depth) const {
   1666    TexStorage(3, target, levels, internalFormat, {width, height, depth});
   1667  }
   1668 
   1669  ////////////////////////////////////
   1670 
   1671  template <typename T>  // TexImageSource or WebGLintptr
   1672  void TexImage2D(GLenum target, GLint level, GLenum internalFormat,
   1673                  GLsizei width, GLsizei height, GLint border,
   1674                  GLenum unpackFormat, GLenum unpackType, const T& anySrc,
   1675                  ErrorResult& out_error) const {
   1676    const TexImageSourceAdapter src(&anySrc, &out_error);
   1677    TexImage(2, target, level, internalFormat, {0, 0, 0},
   1678             Some(ivec3{width, height, 1}), border, {unpackFormat, unpackType},
   1679             src);
   1680  }
   1681 
   1682  void TexImage2D(GLenum target, GLint level, GLenum internalFormat,
   1683                  GLsizei width, GLsizei height, GLint border,
   1684                  GLenum unpackFormat, GLenum unpackType,
   1685                  const dom::ArrayBufferView& view, GLuint viewElemOffset,
   1686                  ErrorResult&) const {
   1687    const TexImageSourceAdapter src(&view, viewElemOffset);
   1688    TexImage(2, target, level, internalFormat, {0, 0, 0},
   1689             Some(ivec3{width, height, 1}), border, {unpackFormat, unpackType},
   1690             src);
   1691  }
   1692 
   1693  // -
   1694 
   1695  template <typename T>  // TexImageSource or WebGLintptr
   1696  void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
   1697                     GLsizei width, GLsizei height, GLenum unpackFormat,
   1698                     GLenum unpackType, const T& anySrc,
   1699                     ErrorResult& out_error) const {
   1700    const TexImageSourceAdapter src(&anySrc, &out_error);
   1701    TexImage(2, target, level, 0, {xOffset, yOffset, 0},
   1702             Some(ivec3{width, height, 1}), 0, {unpackFormat, unpackType}, src);
   1703  }
   1704 
   1705  void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
   1706                     GLsizei width, GLsizei height, GLenum unpackFormat,
   1707                     GLenum unpackType, const dom::ArrayBufferView& view,
   1708                     GLuint viewElemOffset, ErrorResult&) const {
   1709    const TexImageSourceAdapter src(&view, viewElemOffset);
   1710    TexImage(2, target, level, 0, {xOffset, yOffset, 0},
   1711             Some(ivec3{width, height, 1}), 0, {unpackFormat, unpackType}, src);
   1712  }
   1713 
   1714  // -
   1715 
   1716  template <typename T>  // TexImageSource or WebGLintptr
   1717  void TexImage3D(GLenum target, GLint level, GLenum internalFormat,
   1718                  GLsizei width, GLsizei height, GLsizei depth, GLint border,
   1719                  GLenum unpackFormat, GLenum unpackType, const T& anySrc,
   1720                  ErrorResult& out_error) const {
   1721    const TexImageSourceAdapter src(&anySrc, &out_error);
   1722    TexImage(3, target, level, internalFormat, {0, 0, 0},
   1723             Some(ivec3{width, height, depth}), border,
   1724             {unpackFormat, unpackType}, src);
   1725  }
   1726 
   1727  void TexImage3D(GLenum target, GLint level, GLenum internalFormat,
   1728                  GLsizei width, GLsizei height, GLsizei depth, GLint border,
   1729                  GLenum unpackFormat, GLenum unpackType,
   1730                  const dom::ArrayBufferView& view, GLuint viewElemOffset,
   1731                  ErrorResult&) const {
   1732    const TexImageSourceAdapter src(&view, viewElemOffset);
   1733    TexImage(3, target, level, internalFormat, {0, 0, 0},
   1734             Some(ivec3{width, height, depth}), border,
   1735             {unpackFormat, unpackType}, src);
   1736  }
   1737 
   1738  // -
   1739 
   1740  template <typename T>  // TexImageSource or WebGLintptr
   1741  void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
   1742                     GLint zOffset, GLsizei width, GLsizei height,
   1743                     GLsizei depth, GLenum unpackFormat, GLenum unpackType,
   1744                     const T& anySrc, ErrorResult& out_error) const {
   1745    const TexImageSourceAdapter src(&anySrc, &out_error);
   1746    TexImage(3, target, level, 0, {xOffset, yOffset, zOffset},
   1747             Some(ivec3{width, height, depth}), 0, {unpackFormat, unpackType},
   1748             src);
   1749  }
   1750 
   1751  void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
   1752                     GLint zOffset, GLsizei width, GLsizei height,
   1753                     GLsizei depth, GLenum unpackFormat, GLenum unpackType,
   1754                     const dom::Nullable<dom::ArrayBufferView>& maybeSrcView,
   1755                     GLuint srcElemOffset, ErrorResult&) const {
   1756    const TexImageSourceAdapter src(&maybeSrcView, srcElemOffset);
   1757    TexImage(3, target, level, 0, {xOffset, yOffset, zOffset},
   1758             Some(ivec3{width, height, depth}), 0, {unpackFormat, unpackType},
   1759             src);
   1760  }
   1761 
   1762  ////////////////////////////////////
   1763 
   1764 public:
   1765  void CompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat,
   1766                            GLsizei width, GLsizei height, GLint border,
   1767                            GLsizei imageSize, WebGLintptr offset) const {
   1768    const TexImageSourceAdapter src(&offset);
   1769    CompressedTexImage(false, 2, target, level, internalFormat, {0, 0, 0},
   1770                       {width, height, 1}, border, src, imageSize);
   1771  }
   1772 
   1773  void CompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat,
   1774                            GLsizei width, GLsizei height, GLint border,
   1775                            const dom::ArrayBufferView& view,
   1776                            GLuint viewElemOffset = 0,
   1777                            GLuint viewElemLengthOverride = 0) const {
   1778    const TexImageSourceAdapter src(&view, viewElemOffset,
   1779                                    viewElemLengthOverride);
   1780    CompressedTexImage(false, 2, target, level, internalFormat, {0, 0, 0},
   1781                       {width, height, 1}, border, src, 0);
   1782  }
   1783 
   1784  // -
   1785 
   1786  void CompressedTexSubImage2D(GLenum target, GLint level, GLint xOffset,
   1787                               GLint yOffset, GLsizei width, GLsizei height,
   1788                               GLenum unpackFormat, GLsizei imageSize,
   1789                               WebGLintptr offset) const {
   1790    const TexImageSourceAdapter src(&offset);
   1791    CompressedTexImage(true, 2, target, level, unpackFormat,
   1792                       {xOffset, yOffset, 0}, {width, height, 1}, 0, src,
   1793                       imageSize);
   1794  }
   1795 
   1796  void CompressedTexSubImage2D(GLenum target, GLint level, GLint xOffset,
   1797                               GLint yOffset, GLsizei width, GLsizei height,
   1798                               GLenum unpackFormat,
   1799                               const dom::ArrayBufferView& view,
   1800                               GLuint viewElemOffset = 0,
   1801                               GLuint viewElemLengthOverride = 0) const {
   1802    const TexImageSourceAdapter src(&view, viewElemOffset,
   1803                                    viewElemLengthOverride);
   1804    CompressedTexImage(true, 2, target, level, unpackFormat,
   1805                       {xOffset, yOffset, 0}, {width, height, 1}, 0, src, 0);
   1806  }
   1807 
   1808  // -
   1809 
   1810  void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
   1811                            GLsizei width, GLsizei height, GLsizei depth,
   1812                            GLint border, GLsizei imageSize,
   1813                            WebGLintptr offset) const {
   1814    const TexImageSourceAdapter src(&offset);
   1815    CompressedTexImage(false, 3, target, level, internalFormat, {0, 0, 0},
   1816                       {width, height, depth}, border, src, imageSize);
   1817  }
   1818 
   1819  void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat,
   1820                            GLsizei width, GLsizei height, GLsizei depth,
   1821                            GLint border, const dom::ArrayBufferView& view,
   1822                            GLuint viewElemOffset = 0,
   1823                            GLuint viewElemLengthOverride = 0) const {
   1824    const TexImageSourceAdapter src(&view, viewElemOffset,
   1825                                    viewElemLengthOverride);
   1826    CompressedTexImage(false, 3, target, level, internalFormat, {0, 0, 0},
   1827                       {width, height, depth}, border, src, 0);
   1828  }
   1829 
   1830  // -
   1831 
   1832  void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset,
   1833                               GLint yOffset, GLint zOffset, GLsizei width,
   1834                               GLsizei height, GLsizei depth,
   1835                               GLenum unpackFormat, GLsizei imageSize,
   1836                               WebGLintptr offset) const {
   1837    const TexImageSourceAdapter src(&offset);
   1838    CompressedTexImage(true, 3, target, level, unpackFormat,
   1839                       {xOffset, yOffset, zOffset}, {width, height, depth}, 0,
   1840                       src, imageSize);
   1841  }
   1842 
   1843  void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset,
   1844                               GLint yOffset, GLint zOffset, GLsizei width,
   1845                               GLsizei height, GLsizei depth,
   1846                               GLenum unpackFormat,
   1847                               const dom::ArrayBufferView& view,
   1848                               GLuint viewElemOffset = 0,
   1849                               GLuint viewElemLengthOverride = 0) const {
   1850    const TexImageSourceAdapter src(&view, viewElemOffset,
   1851                                    viewElemLengthOverride);
   1852    CompressedTexImage(true, 3, target, level, unpackFormat,
   1853                       {xOffset, yOffset, zOffset}, {width, height, depth}, 0,
   1854                       src, 0);
   1855  }
   1856 
   1857  // --------------------
   1858 
   1859  void CopyTexImage2D(GLenum target, GLint level, GLenum internalFormat,
   1860                      GLint x, GLint y, GLsizei width, GLsizei height,
   1861                      GLint border) const {
   1862    CopyTexImage(2, target, level, internalFormat, {0, 0, 0}, {x, y},
   1863                 {width, height}, border);
   1864  }
   1865 
   1866  void CopyTexSubImage2D(GLenum target, GLint level, GLint xOffset,
   1867                         GLint yOffset, GLint x, GLint y, GLsizei width,
   1868                         GLsizei height) const {
   1869    CopyTexImage(2, target, level, 0, {xOffset, yOffset, 0}, {x, y},
   1870                 {width, height}, 0);
   1871  }
   1872 
   1873  void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset,
   1874                         GLint yOffset, GLint zOffset, GLint x, GLint y,
   1875                         GLsizei width, GLsizei height) const {
   1876    CopyTexImage(3, target, level, 0, {xOffset, yOffset, zOffset}, {x, y},
   1877                 {width, height}, 0);
   1878  }
   1879 
   1880  // -------------------
   1881  // legacy TexImageSource uploads without width/height.
   1882  // The width/height params are webgl2 only, and let you do subrect
   1883  // selection with e.g. width < UNPACK_ROW_LENGTH.
   1884 
   1885  template <typename TexImageSourceT>
   1886  void TexImage2D(GLenum target, GLint level, GLenum internalFormat,
   1887                  GLenum unpackFormat, GLenum unpackType,
   1888                  const TexImageSourceT& anySrc, ErrorResult& out_error) const {
   1889    const TexImageSourceAdapter src(&anySrc, &out_error);
   1890    TexImage(2, target, level, internalFormat, {}, {}, 0,
   1891             {unpackFormat, unpackType}, src);
   1892  }
   1893 
   1894  template <typename TexImageSourceT>
   1895  void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset,
   1896                     GLenum unpackFormat, GLenum unpackType,
   1897                     const TexImageSourceT& anySrc,
   1898                     ErrorResult& out_error) const {
   1899    const TexImageSourceAdapter src(&anySrc, &out_error);
   1900    TexImage(2, target, level, 0, {xOffset, yOffset, 0}, {}, 0,
   1901             {unpackFormat, unpackType}, src);
   1902  }
   1903 
   1904  // ------------------------ Uniforms and attributes ------------------------
   1905 
   1906 private:
   1907  Maybe<double> GetVertexAttribPriv(GLuint index, GLenum pname);
   1908 
   1909 public:
   1910  void GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
   1911                       JS::MutableHandle<JS::Value> retval, ErrorResult& rv);
   1912 
   1913 private:
   1914  const webgl::LinkResult* GetActiveLinkResult() const {
   1915    const auto& state = State();
   1916    if (state.mCurrentProgram) {
   1917      (void)GetLinkResult(*state.mCurrentProgram);
   1918    }
   1919    return state.mActiveLinkResult.get();
   1920  }
   1921 
   1922  // Used by callers that have a `nogc` token that ensures that no GC will
   1923  // happen while `bytes` is alive. Internally, the nogc range will be ended
   1924  // after `bytes` is used (either successfully but where the data are possibly
   1925  // sent over IPC which has a tendency to GC, or unsuccesfully in which case
   1926  // error handling can GC.)
   1927  void UniformData(GLenum funcElemType, const WebGLUniformLocationJS* const loc,
   1928                   bool transpose, const Range<const uint8_t>& bytes,
   1929                   JS::AutoCheckCannotGC&& nogc, GLuint elemOffset = 0,
   1930                   GLuint elemCountOverride = 0) const;
   1931 
   1932  // Used by callers that are not passing `bytes` that might be GC-controlled.
   1933  // This will create an artificial and unnecessary nogc region that should
   1934  // get optimized away to nothing.
   1935  void UniformData(GLenum funcElemType, const WebGLUniformLocationJS* const loc,
   1936                   bool transpose, const Range<const uint8_t>& bytes,
   1937                   GLuint elemOffset = 0, GLuint elemCountOverride = 0) const {
   1938    JS::AutoCheckCannotGC nogc;
   1939    UniformData(funcElemType, loc, transpose, bytes, std::move(nogc),
   1940                elemOffset, elemCountOverride);
   1941  }
   1942 
   1943  // -
   1944 
   1945  template <typename T>
   1946  Maybe<Range<T>> ValidateSubrange(const Range<T>& data, size_t elemOffset,
   1947                                   size_t elemLengthOverride = 0) const {
   1948    auto ret = data;
   1949    if (elemOffset > ret.length()) {
   1950      EnqueueError(LOCAL_GL_INVALID_VALUE,
   1951                   "`elemOffset` too large for `data`.");
   1952      return {};
   1953    }
   1954    ret = {ret.begin() + elemOffset, ret.end()};
   1955    if (elemLengthOverride) {
   1956      if (elemLengthOverride > ret.length()) {
   1957        EnqueueError(
   1958            LOCAL_GL_INVALID_VALUE,
   1959            "`elemLengthOverride` too large for `data` and `elemOffset`.");
   1960        return {};
   1961      }
   1962      ret = {ret.begin().get(), elemLengthOverride};
   1963    }
   1964    return Some(ret);
   1965  }
   1966 
   1967 public:
   1968 #define _(T, type_t, TYPE)                                                    \
   1969  void Uniform1##T(const WebGLUniformLocationJS* const loc, type_t x) const { \
   1970    const type_t arr[] = {x};                                                 \
   1971    UniformData(TYPE, loc, false, MakeByteRange(arr));                        \
   1972  }                                                                           \
   1973  void Uniform2##T(const WebGLUniformLocationJS* const loc, type_t x,         \
   1974                   type_t y) const {                                          \
   1975    const type_t arr[] = {x, y};                                              \
   1976    UniformData(TYPE##_VEC2, loc, false, MakeByteRange(arr));                 \
   1977  }                                                                           \
   1978  void Uniform3##T(const WebGLUniformLocationJS* const loc, type_t x,         \
   1979                   type_t y, type_t z) const {                                \
   1980    const type_t arr[] = {x, y, z};                                           \
   1981    UniformData(TYPE##_VEC3, loc, false, MakeByteRange(arr));                 \
   1982  }                                                                           \
   1983  void Uniform4##T(const WebGLUniformLocationJS* const loc, type_t x,         \
   1984                   type_t y, type_t z, type_t w) const {                      \
   1985    const type_t arr[] = {x, y, z, w};                                        \
   1986    UniformData(TYPE##_VEC4, loc, false, MakeByteRange(arr));                 \
   1987  }
   1988 
   1989  _(f, float, LOCAL_GL_FLOAT)
   1990  _(i, int32_t, LOCAL_GL_INT)
   1991  _(ui, uint32_t, LOCAL_GL_UNSIGNED_INT)
   1992 
   1993 #undef _
   1994 
   1995  // -
   1996 
   1997 #define _(NT, TypeListU, TYPE)                                             \
   1998  void Uniform##NT##v(const WebGLUniformLocationJS* const loc,             \
   1999                      const TypeListU& list, GLuint elemOffset = 0,        \
   2000                      GLuint elemCountOverride = 0) const {                \
   2001    Convert(list, [&](const auto& aData, JS::AutoCheckCannotGC&& nogc) {   \
   2002      UniformData(TYPE, loc, false, MakeByteRange(aData), std::move(nogc), \
   2003                  elemOffset, elemCountOverride);                          \
   2004      return true;                                                         \
   2005    });                                                                    \
   2006  }
   2007 
   2008  _(1f, Float32ListU, LOCAL_GL_FLOAT)
   2009  _(2f, Float32ListU, LOCAL_GL_FLOAT_VEC2)
   2010  _(3f, Float32ListU, LOCAL_GL_FLOAT_VEC3)
   2011  _(4f, Float32ListU, LOCAL_GL_FLOAT_VEC4)
   2012  _(1i, Int32ListU, LOCAL_GL_INT)
   2013  _(2i, Int32ListU, LOCAL_GL_INT_VEC2)
   2014  _(3i, Int32ListU, LOCAL_GL_INT_VEC3)
   2015  _(4i, Int32ListU, LOCAL_GL_INT_VEC4)
   2016  _(1ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT)
   2017  _(2ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT_VEC2)
   2018  _(3ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT_VEC3)
   2019  _(4ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT_VEC4)
   2020 
   2021 #undef _
   2022 
   2023  // -
   2024 
   2025 #define _(X)                                                                   \
   2026  void UniformMatrix##X##fv(const WebGLUniformLocationJS* loc, bool transpose, \
   2027                            const Float32ListU& list, GLuint elemOffset = 0,   \
   2028                            GLuint elemCountOverride = 0) const {              \
   2029    Convert(list, [&](const Span<const float>& aData,                          \
   2030                      JS::AutoCheckCannotGC&& nogc) {                          \
   2031      UniformData(LOCAL_GL_FLOAT_MAT##X, loc, transpose, MakeByteRange(aData), \
   2032                  std::move(nogc), elemOffset, elemCountOverride);             \
   2033      return true;                                                             \
   2034    });                                                                        \
   2035  }
   2036 
   2037  _(2)
   2038  _(2x3)
   2039  _(2x4)
   2040 
   2041  _(3x2)
   2042  _(3)
   2043  _(3x4)
   2044 
   2045  _(4x2)
   2046  _(4x3)
   2047  _(4)
   2048 
   2049 #undef _
   2050 
   2051  // -
   2052 
   2053  void EnableVertexAttribArray(GLuint index);
   2054 
   2055  void DisableVertexAttribArray(GLuint index);
   2056 
   2057  WebGLsizeiptr GetVertexAttribOffset(GLuint index, GLenum pname);
   2058 
   2059  // -
   2060 
   2061 private:
   2062  void VertexAttrib4Tv(GLuint index, webgl::AttribBaseType,
   2063                       const Range<const uint8_t>&);
   2064 
   2065 public:
   2066  void VertexAttrib1f(GLuint index, GLfloat x) {
   2067    VertexAttrib4f(index, x, 0, 0, 1);
   2068  }
   2069  void VertexAttrib2f(GLuint index, GLfloat x, GLfloat y) {
   2070    VertexAttrib4f(index, x, y, 0, 1);
   2071  }
   2072  void VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) {
   2073    VertexAttrib4f(index, x, y, z, 1);
   2074  }
   2075 
   2076  void VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z,
   2077                      GLfloat w) {
   2078    const float arr[4] = {x, y, z, w};
   2079    VertexAttrib4Tv(index, webgl::AttribBaseType::Float, MakeByteRange(arr));
   2080  }
   2081 
   2082  // -
   2083 
   2084  template <typename List, typename T, size_t N>
   2085  bool MakeArrayFromList(const List& list, T (&array)[N]) {
   2086    bool badLength = false;
   2087    if (!Convert(list, [&](const auto& aData, JS::AutoCheckCannotGC&&) {
   2088          static_assert(
   2089              std::is_same_v<std::remove_const_t<
   2090                                 std::remove_reference_t<decltype(aData[0])>>,
   2091                             T>);
   2092          if (N > aData.Length()) {
   2093            badLength = true;
   2094            return false;
   2095          }
   2096 
   2097          std::copy_n(aData.begin(), N, array);
   2098          return true;
   2099        })) {
   2100      EnqueueError(
   2101          LOCAL_GL_INVALID_VALUE,
   2102          badLength
   2103              ? nsPrintfCString("Length of `list` must be >=%zu.", N).get()
   2104              : "Conversion of `list` failed.");
   2105      return false;
   2106    }
   2107    return true;
   2108  }
   2109 
   2110  void VertexAttrib1fv(const GLuint index, const Float32ListU& list) {
   2111    const FuncScope funcScope(*this, "vertexAttrib1fv");
   2112    if (IsContextLost()) return;
   2113 
   2114    float arr[1];
   2115    if (!MakeArrayFromList(list, arr)) {
   2116      return;
   2117    }
   2118    VertexAttrib1f(index, arr[0]);
   2119  }
   2120 
   2121  void VertexAttrib2fv(const GLuint index, const Float32ListU& list) {
   2122    const FuncScope funcScope(*this, "vertexAttrib1fv");
   2123    if (IsContextLost()) return;
   2124 
   2125    float arr[2];
   2126    if (!MakeArrayFromList(list, arr)) {
   2127      return;
   2128    }
   2129    VertexAttrib2f(index, arr[0], arr[1]);
   2130  }
   2131 
   2132  void VertexAttrib3fv(const GLuint index, const Float32ListU& list) {
   2133    const FuncScope funcScope(*this, "vertexAttrib1fv");
   2134    if (IsContextLost()) return;
   2135 
   2136    float arr[3];
   2137    if (!MakeArrayFromList(list, arr)) {
   2138      return;
   2139    }
   2140    VertexAttrib3f(index, arr[0], arr[1], arr[2]);
   2141  }
   2142 
   2143  void VertexAttrib4fv(GLuint index, const Float32ListU& list) {
   2144    const FuncScope funcScope(*this, "vertexAttrib4fv");
   2145    float arr[4];
   2146    if (!MakeArrayFromList(list, arr)) {
   2147      return;
   2148    }
   2149    VertexAttrib4Tv(index, webgl::AttribBaseType::Float, MakeByteRange(arr));
   2150  }
   2151  void VertexAttribI4iv(GLuint index, const Int32ListU& list) {
   2152    const FuncScope funcScope(*this, "vertexAttribI4iv");
   2153    int32_t arr[4];
   2154    if (!MakeArrayFromList(list, arr)) {
   2155      return;
   2156    }
   2157    VertexAttrib4Tv(index, webgl::AttribBaseType::Int, MakeByteRange(arr));
   2158  }
   2159  void VertexAttribI4uiv(GLuint index, const Uint32ListU& list) {
   2160    const FuncScope funcScope(*this, "vertexAttribI4uiv");
   2161    uint32_t arr[4];
   2162    if (!MakeArrayFromList(list, arr)) {
   2163      return;
   2164    }
   2165    VertexAttrib4Tv(index, webgl::AttribBaseType::Uint, MakeByteRange(arr));
   2166  }
   2167 
   2168  void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) {
   2169    const int32_t arr[4] = {x, y, z, w};
   2170    VertexAttrib4Tv(index, webgl::AttribBaseType::Int, MakeByteRange(arr));
   2171  }
   2172  void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) {
   2173    const uint32_t arr[4] = {x, y, z, w};
   2174    VertexAttrib4Tv(index, webgl::AttribBaseType::Uint, MakeByteRange(arr));
   2175  }
   2176 
   2177 private:
   2178  void VertexAttribPointerImpl(bool isFuncInt, GLuint index, GLint size,
   2179                               GLenum type, WebGLboolean normalized,
   2180                               GLsizei iStride, WebGLintptr iByteOffset);
   2181 
   2182 public:
   2183  void VertexAttribIPointer(GLuint index, GLint size, GLenum type,
   2184                            GLsizei stride, WebGLintptr byteOffset) {
   2185    VertexAttribPointerImpl(true, index, size, type, false, stride, byteOffset);
   2186  }
   2187 
   2188  void VertexAttribPointer(GLuint index, GLint size, GLenum type,
   2189                           WebGLboolean normalized, GLsizei stride,
   2190                           WebGLintptr byteOffset) {
   2191    VertexAttribPointerImpl(false, index, size, type, normalized, stride,
   2192                            byteOffset);
   2193  }
   2194 
   2195  // -------------------------------- Drawing -------------------------------
   2196 public:
   2197  void DrawArrays(GLenum mode, GLint first, GLsizei count) {
   2198    DrawArraysInstanced(mode, first, count, 1);
   2199  }
   2200 
   2201  void DrawElements(GLenum mode, GLsizei count, GLenum type,
   2202                    WebGLintptr byteOffset) {
   2203    DrawElementsInstanced(mode, count, type, byteOffset, 1);
   2204  }
   2205 
   2206  void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count,
   2207                         GLenum type, WebGLintptr byteOffset) {
   2208    const FuncScope funcScope(*this, "drawRangeElements");
   2209    if (end < start) {
   2210      EnqueueError(LOCAL_GL_INVALID_VALUE, "end must be >= start.");
   2211      return;
   2212    }
   2213    DrawElementsInstanced(mode, count, type, byteOffset, 1);
   2214  }
   2215 
   2216  // ------------------------------ Readback -------------------------------
   2217 public:
   2218  void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
   2219                  GLenum format, GLenum type,
   2220                  const dom::Nullable<dom::ArrayBufferView>& maybeView,
   2221                  dom::CallerType aCallerType, ErrorResult& out_error) const {
   2222    const FuncScope funcScope(*this, "readPixels");
   2223    if (!ValidateNonNull("pixels", maybeView)) return;
   2224    ReadPixels(x, y, width, height, format, type, maybeView.Value(), 0,
   2225               aCallerType, out_error);
   2226  }
   2227 
   2228  void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
   2229                  GLenum format, GLenum type, WebGLsizeiptr offset,
   2230                  dom::CallerType aCallerType, ErrorResult& out_error) const;
   2231 
   2232  void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
   2233                  GLenum format, GLenum type,
   2234                  const dom::ArrayBufferView& dstData, GLuint dstElemOffset,
   2235                  dom::CallerType aCallerType, ErrorResult& out_error) const;
   2236 
   2237 protected:
   2238  bool ReadPixels_SharedPrecheck(GLenum* inout_readType,
   2239                                 dom::CallerType aCallerType,
   2240                                 ErrorResult& out_error) const;
   2241 
   2242  // ------------------------------ Vertex Array ------------------------------
   2243 public:
   2244  void BindVertexArray(WebGLVertexArrayJS*);
   2245 
   2246  void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count,
   2247                           GLsizei primcount);
   2248 
   2249  void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
   2250                             WebGLintptr offset, GLsizei primcount);
   2251 
   2252  void VertexAttribDivisor(GLuint index, GLuint divisor);
   2253 
   2254  // --------------------------------- GL Query
   2255  // ---------------------------------
   2256 public:
   2257  void GetQuery(JSContext*, GLenum target, GLenum pname,
   2258                JS::MutableHandle<JS::Value> retval) const;
   2259  void GetQueryParameter(JSContext*, WebGLQueryJS&, GLenum pname,
   2260                         JS::MutableHandle<JS::Value> retval) const;
   2261  void BeginQuery(GLenum target, WebGLQueryJS&);
   2262  void EndQuery(GLenum target);
   2263  void QueryCounter(WebGLQueryJS&, GLenum target) const;
   2264 
   2265  // -------------------------------- Sampler -------------------------------
   2266 
   2267  void GetSamplerParameter(JSContext*, const WebGLSamplerJS&, GLenum pname,
   2268                           JS::MutableHandle<JS::Value> retval) const;
   2269 
   2270  void BindSampler(GLuint unit, WebGLSamplerJS*);
   2271  void SamplerParameteri(WebGLSamplerJS&, GLenum pname, GLint param) const;
   2272  void SamplerParameterf(WebGLSamplerJS&, GLenum pname, GLfloat param) const;
   2273 
   2274  // ------------------------------- GL Sync ---------------------------------
   2275 
   2276  GLenum ClientWaitSync(WebGLSyncJS&, GLbitfield flags, GLuint64 timeout) const;
   2277  void GetSyncParameter(JSContext*, WebGLSyncJS&, GLenum pname,
   2278                        JS::MutableHandle<JS::Value> retval) const;
   2279  void WaitSync(const WebGLSyncJS&, GLbitfield flags, GLint64 timeout) const;
   2280 
   2281  mutable webgl::ObjectId mCompletedSyncId = 0;
   2282  void OnSyncComplete(webgl::ObjectId id) const {
   2283    if (mCompletedSyncId < id) {
   2284      mCompletedSyncId = id;
   2285    }
   2286  }
   2287 
   2288  // -------------------------- Transform Feedback ---------------------------
   2289 
   2290  void BindTransformFeedback(GLenum target, WebGLTransformFeedbackJS*);
   2291  void BeginTransformFeedback(GLenum primitiveMode);
   2292  void EndTransformFeedback();
   2293  void PauseTransformFeedback();
   2294  void ResumeTransformFeedback();
   2295 
   2296  // -------------------------- Opaque Framebuffers ---------------------------
   2297 
   2298  void SetFramebufferIsInOpaqueRAF(WebGLFramebufferJS*, bool);
   2299 
   2300  // ------------------------------ Extensions ------------------------------
   2301 public:
   2302  void GetSupportedExtensions(dom::Nullable<nsTArray<nsString>>& retval,
   2303                              dom::CallerType callerType) const;
   2304 
   2305  bool IsSupported(WebGLExtensionID, dom::CallerType callerType =
   2306                                         dom::CallerType::NonSystem) const;
   2307 
   2308  void GetExtension(JSContext* cx, const nsAString& name,
   2309                    JS::MutableHandle<JSObject*> retval,
   2310                    dom::CallerType callerType, ErrorResult& rv);
   2311 
   2312 protected:
   2313  bool IsExtensionForbiddenForCaller(const WebGLExtensionID ext,
   2314                                     const dom::CallerType callerType) const;
   2315 
   2316  RefPtr<ClientWebGLExtensionBase> GetExtension(WebGLExtensionID ext,
   2317                                                dom::CallerType callerType);
   2318  void RequestExtension(WebGLExtensionID) const;
   2319 
   2320 public:
   2321  bool IsExtensionEnabled(const WebGLExtensionID id) const {
   2322    return bool(mNotLost->extensions[UnderlyingValue(id)]);
   2323  }
   2324 
   2325  void AddCompressedFormat(GLenum);
   2326 
   2327  // ---------------------------- Misc Extensions ----------------------------
   2328 public:
   2329  void DrawBuffers(const dom::Sequence<GLenum>& buffers);
   2330 
   2331  void GetSupportedProfilesASTC(
   2332      dom::Nullable<nsTArray<nsString>>& retval) const;
   2333 
   2334  void MOZDebugGetParameter(JSContext* cx, GLenum pname,
   2335                            JS::MutableHandle<JS::Value> retval,
   2336                            ErrorResult& rv) {
   2337    GetParameter(cx, pname, retval, rv, true);
   2338  }
   2339 
   2340  void ProvokingVertex(GLenum rawMode) const;
   2341 
   2342  // -------------------------------------------------------------------------
   2343  // Client-side methods.  Calls in the Host are forwarded to the client.
   2344  // -------------------------------------------------------------------------
   2345 public:
   2346  void JsWarning(const std::string&) const;
   2347 
   2348  // -------------------------------------------------------------------------
   2349  // The cross-process communication mechanism
   2350  // -------------------------------------------------------------------------
   2351 protected:
   2352  // If we are running WebGL in this process then call the HostWebGLContext
   2353  // method directly.  Otherwise, dispatch over IPC.
   2354  template <typename MethodType, MethodType method, typename... CallerArgs>
   2355  void Run(const CallerArgs&... args) const {
   2356    const auto id = IdByMethod<MethodType, method>();
   2357    auto noNoGc = std::optional<JS::AutoCheckCannotGC>{};
   2358    Run_WithDestArgTypes_ConstnessHelper(std::move(noNoGc), method, id,
   2359                                         args...);
   2360  }
   2361 
   2362  // Same as above for use when using potentially GC-controlled data. The scope
   2363  // of `aNoGC` will be ended after the data is no longer needed.
   2364  template <typename MethodType, MethodType method, typename... CallerArgs>
   2365  void RunWithGCData(JS::AutoCheckCannotGC&& aNoGC,
   2366                     const CallerArgs&... aArgs) const {
   2367    const auto id = IdByMethod<MethodType, method>();
   2368    auto noGc = std::optional<JS::AutoCheckCannotGC>{std::move(aNoGC)};
   2369    Run_WithDestArgTypes_ConstnessHelper(std::move(noGc), method, id, aArgs...);
   2370  }
   2371 
   2372  // Because we're trying to explicitly pull `DestArgs` via `method`, we have
   2373  // one overload for mut-methods and one for const-methods.
   2374  template <typename... DestArgs>
   2375  void Run_WithDestArgTypes_ConstnessHelper(
   2376      std::optional<JS::AutoCheckCannotGC>&& noGc,
   2377      void (HostWebGLContext::*method)(DestArgs...), const size_t id,
   2378      const std::remove_reference_t<std::remove_const_t<DestArgs>>&... args)
   2379      const {
   2380    Run_WithDestArgTypes(std::move(noGc), method, id, args...);
   2381  }
   2382  template <typename... DestArgs>
   2383  void Run_WithDestArgTypes_ConstnessHelper(
   2384      std::optional<JS::AutoCheckCannotGC>&& noGc,
   2385      void (HostWebGLContext::*method)(DestArgs...) const, const size_t id,
   2386      const std::remove_reference_t<std::remove_const_t<DestArgs>>&... args)
   2387      const {
   2388    Run_WithDestArgTypes(std::move(noGc), method, id, args...);
   2389  }
   2390 
   2391  template <typename MethodT, typename... DestArgs>
   2392  void Run_WithDestArgTypes(std::optional<JS::AutoCheckCannotGC>&&, MethodT,
   2393                            const size_t id, const DestArgs&...) const;
   2394 
   2395  // -------------------------------------------------------------------------
   2396  // Helpers for DOM operations, composition, actors, etc
   2397  // -------------------------------------------------------------------------
   2398 
   2399 public:
   2400  // https://immersive-web.github.io/webxr/#xr-compatible
   2401  bool IsXRCompatible() const;
   2402  already_AddRefed<dom::Promise> MakeXRCompatible(ErrorResult& aRv);
   2403 
   2404 protected:
   2405  uint32_t GetPrincipalHashValue() const;
   2406 
   2407  // Prepare the context for capture before compositing
   2408  void BeginComposition();
   2409 
   2410  // Clean up the context after captured for compositing
   2411  void EndComposition();
   2412 
   2413  mozilla::dom::Document* GetOwnerDoc() const;
   2414 
   2415  mutable bool mResetLayer = true;
   2416  Maybe<const WebGLContextOptions> mInitialOptions;
   2417  bool mXRCompatible = false;
   2418 };
   2419 
   2420 // used by DOM bindings in conjunction with GetParentObject
   2421 inline nsISupports* ToSupports(ClientWebGLContext* webgl) {
   2422  return static_cast<nsICanvasRenderingContextInternal*>(webgl);
   2423 }
   2424 
   2425 const char* GetExtensionName(WebGLExtensionID);
   2426 
   2427 // -
   2428 
   2429 inline bool webgl::ObjectJS::IsForContext(
   2430    const ClientWebGLContext& context) const {
   2431  const auto& notLost = context.mNotLost;
   2432  if (!notLost) return false;
   2433  if (notLost != mGeneration) return false;
   2434  return true;
   2435 }
   2436 
   2437 void AutoJsWarning(const std::string& utf8);
   2438 
   2439 }  // namespace mozilla
   2440 
   2441 #endif  // CLIENTWEBGLCONTEXT_H_