1 /*
2  * Copyright (C) 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h"
27 
28 #include <memory>
29 #include <utility>
30 
31 #include "base/feature_list.h"
32 #include "base/numerics/checked_math.h"
33 #include "base/stl_util.h"
34 #include "build/build_config.h"
35 #include "gpu/GLES2/gl2extchromium.h"
36 #include "gpu/command_buffer/client/gles2_interface.h"
37 #include "gpu/command_buffer/common/capabilities.h"
38 #include "gpu/config/gpu_feature_info.h"
39 #include "third_party/blink/public/common/features.h"
40 #include "third_party/blink/public/common/privacy_budget/identifiability_metric_builder.h"
41 #include "third_party/blink/public/common/privacy_budget/identifiability_study_settings.h"
42 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
43 #include "third_party/blink/public/mojom/gpu/gpu.mojom-blink.h"
44 #include "third_party/blink/public/platform/platform.h"
45 #include "third_party/blink/public/platform/task_type.h"
46 #include "third_party/blink/renderer/bindings/modules/v8/html_canvas_element_or_offscreen_canvas.h"
47 #include "third_party/blink/renderer/bindings/modules/v8/webgl_any.h"
48 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
49 #include "third_party/blink/renderer/core/frame/dactyloscoper.h"
50 #include "third_party/blink/renderer/core/frame/local_frame.h"
51 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
52 #include "third_party/blink/renderer/core/frame/settings.h"
53 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h"
54 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
55 #include "third_party/blink/renderer/core/html/canvas/image_data.h"
56 #include "third_party/blink/renderer/core/html/html_image_element.h"
57 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
58 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
59 #include "third_party/blink/renderer/core/inspector/console_message.h"
60 #include "third_party/blink/renderer/core/layout/layout_box.h"
61 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
62 #include "third_party/blink/renderer/core/probe/core_probes.h"
63 #include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
64 #include "third_party/blink/renderer/core/typed_arrays/array_buffer/array_buffer_contents.h"
65 #include "third_party/blink/renderer/core/typed_arrays/array_buffer_view_helpers.h"
66 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
67 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
68 #include "third_party/blink/renderer/core/typed_arrays/flexible_array_buffer_view.h"
69 #include "third_party/blink/renderer/modules/webgl/angle_instanced_arrays.h"
70 #include "third_party/blink/renderer/modules/webgl/ext_blend_min_max.h"
71 #include "third_party/blink/renderer/modules/webgl/ext_frag_depth.h"
72 #include "third_party/blink/renderer/modules/webgl/ext_shader_texture_lod.h"
73 #include "third_party/blink/renderer/modules/webgl/ext_texture_filter_anisotropic.h"
74 #include "third_party/blink/renderer/modules/webgl/gl_string_query.h"
75 #include "third_party/blink/renderer/modules/webgl/oes_element_index_uint.h"
76 #include "third_party/blink/renderer/modules/webgl/oes_standard_derivatives.h"
77 #include "third_party/blink/renderer/modules/webgl/oes_texture_float.h"
78 #include "third_party/blink/renderer/modules/webgl/oes_texture_float_linear.h"
79 #include "third_party/blink/renderer/modules/webgl/oes_texture_half_float.h"
80 #include "third_party/blink/renderer/modules/webgl/oes_texture_half_float_linear.h"
81 #include "third_party/blink/renderer/modules/webgl/oes_vertex_array_object.h"
82 #include "third_party/blink/renderer/modules/webgl/webgl_active_info.h"
83 #include "third_party/blink/renderer/modules/webgl/webgl_buffer.h"
84 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_astc.h"
85 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc.h"
86 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_etc1.h"
87 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_pvrtc.h"
88 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc.h"
89 #include "third_party/blink/renderer/modules/webgl/webgl_compressed_texture_s3tc_srgb.h"
90 #include "third_party/blink/renderer/modules/webgl/webgl_context_attribute_helpers.h"
91 #include "third_party/blink/renderer/modules/webgl/webgl_context_event.h"
92 #include "third_party/blink/renderer/modules/webgl/webgl_context_group.h"
93 #include "third_party/blink/renderer/modules/webgl/webgl_debug_renderer_info.h"
94 #include "third_party/blink/renderer/modules/webgl/webgl_debug_shaders.h"
95 #include "third_party/blink/renderer/modules/webgl/webgl_depth_texture.h"
96 #include "third_party/blink/renderer/modules/webgl/webgl_draw_buffers.h"
97 #include "third_party/blink/renderer/modules/webgl/webgl_framebuffer.h"
98 #include "third_party/blink/renderer/modules/webgl/webgl_lose_context.h"
99 #include "third_party/blink/renderer/modules/webgl/webgl_program.h"
100 #include "third_party/blink/renderer/modules/webgl/webgl_renderbuffer.h"
101 #include "third_party/blink/renderer/modules/webgl/webgl_shader.h"
102 #include "third_party/blink/renderer/modules/webgl/webgl_shader_precision_format.h"
103 #include "third_party/blink/renderer/modules/webgl/webgl_uniform_location.h"
104 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object.h"
105 #include "third_party/blink/renderer/modules/webgl/webgl_vertex_array_object_oes.h"
106 #include "third_party/blink/renderer/modules/webgl/webgl_video_texture.h"
107 #include "third_party/blink/renderer/modules/webgl/webgl_video_texture_enum.h"
108 #include "third_party/blink/renderer/modules/xr/xr_system.h"
109 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
110 #include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
111 #include "third_party/blink/renderer/platform/geometry/int_size.h"
112 #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
113 #include "third_party/blink/renderer/platform/graphics/canvas_2d_layer_bridge.h"
114 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
115 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
116 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
117 #include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_util.h"
118 #include "third_party/blink/renderer/platform/heap/heap.h"
119 #include "third_party/blink/renderer/platform/privacy_budget/identifiability_digest_helpers.h"
120 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
121 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
122 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
123 #include "third_party/blink/renderer/platform/wtf/functional.h"
124 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
125 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
126 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
127 
128 namespace blink {
129 
130 bool WebGLRenderingContextBase::webgl_context_limits_initialized_ = false;
131 unsigned WebGLRenderingContextBase::max_active_webgl_contexts_ = 0;
132 unsigned WebGLRenderingContextBase::max_active_webgl_contexts_on_worker_ = 0;
133 
134 namespace {
135 
136 constexpr base::TimeDelta kDurationBetweenRestoreAttempts =
137     base::TimeDelta::FromSeconds(1);
138 const int kMaxGLErrorsAllowedToConsole = 256;
139 
WebGLContextLimitMutex()140 Mutex& WebGLContextLimitMutex() {
141   DEFINE_THREAD_SAFE_STATIC_LOCAL(Mutex, mutex, ());
142   return mutex;
143 }
144 
145 using WebGLRenderingContextBaseSet =
146     HeapHashSet<WeakMember<WebGLRenderingContextBase>>;
ActiveContexts()147 WebGLRenderingContextBaseSet& ActiveContexts() {
148   DEFINE_THREAD_SAFE_STATIC_LOCAL(
149       ThreadSpecific<Persistent<WebGLRenderingContextBaseSet>>, active_contexts,
150       ());
151   Persistent<WebGLRenderingContextBaseSet>& active_contexts_persistent =
152       *active_contexts;
153   if (!active_contexts_persistent) {
154     active_contexts_persistent =
155         MakeGarbageCollected<WebGLRenderingContextBaseSet>();
156     active_contexts_persistent.RegisterAsStaticReference();
157   }
158   return *active_contexts_persistent;
159 }
160 
161 using WebGLRenderingContextBaseMap =
162     HeapHashMap<WeakMember<WebGLRenderingContextBase>, int>;
ForciblyEvictedContexts()163 WebGLRenderingContextBaseMap& ForciblyEvictedContexts() {
164   DEFINE_THREAD_SAFE_STATIC_LOCAL(
165       ThreadSpecific<Persistent<WebGLRenderingContextBaseMap>>,
166       forcibly_evicted_contexts, ());
167   Persistent<WebGLRenderingContextBaseMap>&
168       forcibly_evicted_contexts_persistent = *forcibly_evicted_contexts;
169   if (!forcibly_evicted_contexts_persistent) {
170     forcibly_evicted_contexts_persistent =
171         MakeGarbageCollected<WebGLRenderingContextBaseMap>();
172     forcibly_evicted_contexts_persistent.RegisterAsStaticReference();
173   }
174   return *forcibly_evicted_contexts_persistent;
175 }
176 
177 }  // namespace
178 
ScopedRGBEmulationColorMask(WebGLRenderingContextBase * context,GLboolean * color_mask,DrawingBuffer * drawing_buffer)179 ScopedRGBEmulationColorMask::ScopedRGBEmulationColorMask(
180     WebGLRenderingContextBase* context,
181     GLboolean* color_mask,
182     DrawingBuffer* drawing_buffer)
183     : context_(context),
184       requires_emulation_(drawing_buffer->RequiresAlphaChannelToBePreserved()) {
185   if (requires_emulation_) {
186     context_->active_scoped_rgb_emulation_color_masks_++;
187     memcpy(color_mask_, color_mask, 4 * sizeof(GLboolean));
188     context_->ContextGL()->ColorMask(color_mask_[0], color_mask_[1],
189                                      color_mask_[2], false);
190   }
191 }
192 
~ScopedRGBEmulationColorMask()193 ScopedRGBEmulationColorMask::~ScopedRGBEmulationColorMask() {
194   if (requires_emulation_) {
195     DCHECK(context_->active_scoped_rgb_emulation_color_masks_);
196     context_->active_scoped_rgb_emulation_color_masks_--;
197     context_->ContextGL()->ColorMask(color_mask_[0], color_mask_[1],
198                                      color_mask_[2], color_mask_[3]);
199   }
200 }
201 
InitializeWebGLContextLimits(WebGraphicsContext3DProvider * context_provider)202 void WebGLRenderingContextBase::InitializeWebGLContextLimits(
203     WebGraphicsContext3DProvider* context_provider) {
204   MutexLocker locker(WebGLContextLimitMutex());
205   if (!webgl_context_limits_initialized_) {
206     // These do not change over the lifetime of the browser.
207     auto webgl_preferences = context_provider->GetWebglPreferences();
208     max_active_webgl_contexts_ = webgl_preferences.max_active_webgl_contexts;
209     max_active_webgl_contexts_on_worker_ =
210         webgl_preferences.max_active_webgl_contexts_on_worker;
211     webgl_context_limits_initialized_ = true;
212   }
213 }
214 
CurrentMaxGLContexts()215 unsigned WebGLRenderingContextBase::CurrentMaxGLContexts() {
216   MutexLocker locker(WebGLContextLimitMutex());
217   DCHECK(webgl_context_limits_initialized_);
218   return IsMainThread() ? max_active_webgl_contexts_
219                         : max_active_webgl_contexts_on_worker_;
220 }
221 
ForciblyLoseOldestContext(const String & reason)222 void WebGLRenderingContextBase::ForciblyLoseOldestContext(
223     const String& reason) {
224   WebGLRenderingContextBase* candidate = OldestContext();
225   if (!candidate)
226     return;
227 
228   candidate->PrintWarningToConsole(reason);
229   probe::DidFireWebGLWarning(candidate->canvas());
230 
231   // This will call deactivateContext once the context has actually been lost.
232   candidate->ForceLostContext(WebGLRenderingContextBase::kSyntheticLostContext,
233                               WebGLRenderingContextBase::kWhenAvailable);
234 }
235 
OldestContext()236 WebGLRenderingContextBase* WebGLRenderingContextBase::OldestContext() {
237   if (ActiveContexts().IsEmpty())
238     return nullptr;
239 
240   WebGLRenderingContextBase* candidate = *(ActiveContexts().begin());
241   DCHECK(!candidate->isContextLost());
242   for (WebGLRenderingContextBase* context : ActiveContexts()) {
243     DCHECK(!context->isContextLost());
244     if (context->ContextGL()->GetLastFlushIdCHROMIUM() <
245         candidate->ContextGL()->GetLastFlushIdCHROMIUM()) {
246       candidate = context;
247     }
248   }
249 
250   return candidate;
251 }
252 
OldestEvictedContext()253 WebGLRenderingContextBase* WebGLRenderingContextBase::OldestEvictedContext() {
254   if (ForciblyEvictedContexts().IsEmpty())
255     return nullptr;
256 
257   WebGLRenderingContextBase* candidate = nullptr;
258   int generation = -1;
259   for (WebGLRenderingContextBase* context : ForciblyEvictedContexts().Keys()) {
260     if (!candidate || ForciblyEvictedContexts().at(context) < generation) {
261       candidate = context;
262       generation = ForciblyEvictedContexts().at(context);
263     }
264   }
265 
266   return candidate;
267 }
268 
ActivateContext(WebGLRenderingContextBase * context)269 void WebGLRenderingContextBase::ActivateContext(
270     WebGLRenderingContextBase* context) {
271   unsigned max_gl_contexts = CurrentMaxGLContexts();
272   unsigned removed_contexts = 0;
273   while (ActiveContexts().size() >= max_gl_contexts &&
274          removed_contexts < max_gl_contexts) {
275     ForciblyLoseOldestContext(
276         "WARNING: Too many active WebGL contexts. Oldest context will be "
277         "lost.");
278     removed_contexts++;
279   }
280 
281   DCHECK(!context->isContextLost());
282   ActiveContexts().insert(context);
283 }
284 
DeactivateContext(WebGLRenderingContextBase * context)285 void WebGLRenderingContextBase::DeactivateContext(
286     WebGLRenderingContextBase* context) {
287   ActiveContexts().erase(context);
288 }
289 
AddToEvictedList(WebGLRenderingContextBase * context)290 void WebGLRenderingContextBase::AddToEvictedList(
291     WebGLRenderingContextBase* context) {
292   static int generation = 0;
293   ForciblyEvictedContexts().Set(context, generation++);
294 }
295 
RemoveFromEvictedList(WebGLRenderingContextBase * context)296 void WebGLRenderingContextBase::RemoveFromEvictedList(
297     WebGLRenderingContextBase* context) {
298   ForciblyEvictedContexts().erase(context);
299 }
300 
RestoreEvictedContext(WebGLRenderingContextBase * context)301 void WebGLRenderingContextBase::RestoreEvictedContext(
302     WebGLRenderingContextBase* context) {
303   // These two sets keep weak references to their contexts;
304   // verify that the GC already removed the |context| entries.
305   DCHECK(!ForciblyEvictedContexts().Contains(context));
306   DCHECK(!ActiveContexts().Contains(context));
307 
308   unsigned max_gl_contexts = CurrentMaxGLContexts();
309   // Try to re-enable the oldest inactive contexts.
310   while (ActiveContexts().size() < max_gl_contexts &&
311          ForciblyEvictedContexts().size()) {
312     WebGLRenderingContextBase* evicted_context = OldestEvictedContext();
313     if (!evicted_context->restore_allowed_) {
314       ForciblyEvictedContexts().erase(evicted_context);
315       continue;
316     }
317 
318     IntSize desired_size = DrawingBuffer::AdjustSize(
319         evicted_context->ClampedCanvasSize(), IntSize(),
320         evicted_context->max_texture_size_);
321 
322     // If there's room in the pixel budget for this context, restore it.
323     if (!desired_size.IsEmpty()) {
324       ForciblyEvictedContexts().erase(evicted_context);
325       evicted_context->ForceRestoreContext();
326     }
327     break;
328   }
329 }
330 
331 namespace {
332 
Clamp(GLint value,GLint min,GLint max)333 GLint Clamp(GLint value, GLint min, GLint max) {
334   if (value < min)
335     value = min;
336   if (value > max)
337     value = max;
338   return value;
339 }
340 
341 // Strips comments from shader text. This allows non-ASCII characters
342 // to be used in comments without potentially breaking OpenGL
343 // implementations not expecting characters outside the GLSL ES set.
344 class StripComments {
345  public:
StripComments(const String & str)346   StripComments(const String& str)
347       : parse_state_(kBeginningOfLine),
348         source_string_(str),
349         length_(str.length()),
350         position_(0) {
351     Parse();
352   }
353 
Result()354   String Result() { return builder_.ToString(); }
355 
356  private:
HasMoreCharacters() const357   bool HasMoreCharacters() const { return (position_ < length_); }
358 
Parse()359   void Parse() {
360     while (HasMoreCharacters()) {
361       Process(Current());
362       // process() might advance the position.
363       if (HasMoreCharacters())
364         Advance();
365     }
366   }
367 
368   void Process(UChar);
369 
Peek(UChar & character) const370   bool Peek(UChar& character) const {
371     if (position_ + 1 >= length_)
372       return false;
373     character = source_string_[position_ + 1];
374     return true;
375   }
376 
Current()377   UChar Current() {
378     SECURITY_DCHECK(position_ < length_);
379     return source_string_[position_];
380   }
381 
Advance()382   void Advance() { ++position_; }
383 
IsNewline(UChar character)384   static bool IsNewline(UChar character) {
385     // Don't attempt to canonicalize newline related characters.
386     return (character == '\n' || character == '\r');
387   }
388 
Emit(UChar character)389   void Emit(UChar character) { builder_.Append(character); }
390 
391   enum ParseState {
392     // Have not seen an ASCII non-whitespace character yet on
393     // this line. Possible that we might see a preprocessor
394     // directive.
395     kBeginningOfLine,
396 
397     // Have seen at least one ASCII non-whitespace character
398     // on this line.
399     kMiddleOfLine,
400 
401     // Handling a preprocessor directive. Passes through all
402     // characters up to the end of the line. Disables comment
403     // processing.
404     kInPreprocessorDirective,
405 
406     // Handling a single-line comment. The comment text is
407     // replaced with a single space.
408     kInSingleLineComment,
409 
410     // Handling a multi-line comment. Newlines are passed
411     // through to preserve line numbers.
412     kInMultiLineComment
413   };
414 
415   ParseState parse_state_;
416   String source_string_;
417   unsigned length_;
418   unsigned position_;
419   StringBuilder builder_;
420 };
421 
Process(UChar c)422 void StripComments::Process(UChar c) {
423   if (IsNewline(c)) {
424     // No matter what state we are in, pass through newlines
425     // so we preserve line numbers.
426     Emit(c);
427 
428     if (parse_state_ != kInMultiLineComment)
429       parse_state_ = kBeginningOfLine;
430 
431     return;
432   }
433 
434   UChar temp = 0;
435   switch (parse_state_) {
436     case kBeginningOfLine:
437       if (WTF::IsASCIISpace(c)) {
438         Emit(c);
439         break;
440       }
441 
442       if (c == '#') {
443         parse_state_ = kInPreprocessorDirective;
444         Emit(c);
445         break;
446       }
447 
448       // Transition to normal state and re-handle character.
449       parse_state_ = kMiddleOfLine;
450       Process(c);
451       break;
452 
453     case kMiddleOfLine:
454     case kInPreprocessorDirective:
455       if (c == '/' && Peek(temp)) {
456         if (temp == '/') {
457           parse_state_ = kInSingleLineComment;
458           Emit(' ');
459           Advance();
460           break;
461         }
462 
463         if (temp == '*') {
464           parse_state_ = kInMultiLineComment;
465           // Emit the comment start in case the user has
466           // an unclosed comment and we want to later
467           // signal an error.
468           Emit('/');
469           Emit('*');
470           Advance();
471           break;
472         }
473       }
474 
475       Emit(c);
476       break;
477 
478     case kInSingleLineComment:
479       // Line-continuation characters are processed before comment processing.
480       // Advance string if a new line character is immediately behind
481       // line-continuation character.
482       if (c == '\\') {
483         if (Peek(temp) && IsNewline(temp))
484           Advance();
485       }
486 
487       // The newline code at the top of this function takes care
488       // of resetting our state when we get out of the
489       // single-line comment. Swallow all other characters.
490       break;
491 
492     case kInMultiLineComment:
493       if (c == '*' && Peek(temp) && temp == '/') {
494         Emit('*');
495         Emit('/');
496         parse_state_ = kMiddleOfLine;
497         Advance();
498         break;
499       }
500 
501       // Swallow all other characters. Unclear whether we may
502       // want or need to just emit a space per character to try
503       // to preserve column numbers for debugging purposes.
504       break;
505   }
506 }
507 
508 static bool g_should_fail_context_creation_for_testing = false;
509 }  // namespace
510 
511 class ScopedTexture2DRestorer {
512   STACK_ALLOCATED();
513 
514  public:
ScopedTexture2DRestorer(WebGLRenderingContextBase * context)515   explicit ScopedTexture2DRestorer(WebGLRenderingContextBase* context)
516       : context_(context) {}
517 
~ScopedTexture2DRestorer()518   ~ScopedTexture2DRestorer() { context_->RestoreCurrentTexture2D(); }
519 
520  private:
521   WebGLRenderingContextBase* context_;
522 };
523 
524 class ScopedFramebufferRestorer {
525   STACK_ALLOCATED();
526 
527  public:
ScopedFramebufferRestorer(WebGLRenderingContextBase * context)528   explicit ScopedFramebufferRestorer(WebGLRenderingContextBase* context)
529       : context_(context) {}
530 
~ScopedFramebufferRestorer()531   ~ScopedFramebufferRestorer() { context_->RestoreCurrentFramebuffer(); }
532 
533  private:
534   WebGLRenderingContextBase* context_;
535 };
536 
537 class ScopedUnpackParametersResetRestore {
538   STACK_ALLOCATED();
539 
540  public:
ScopedUnpackParametersResetRestore(WebGLRenderingContextBase * context,bool enabled=true)541   explicit ScopedUnpackParametersResetRestore(
542       WebGLRenderingContextBase* context,
543       bool enabled = true)
544       : context_(context), enabled_(enabled) {
545     if (enabled)
546       context_->ResetUnpackParameters();
547   }
548 
~ScopedUnpackParametersResetRestore()549   ~ScopedUnpackParametersResetRestore() {
550     if (enabled_)
551       context_->RestoreUnpackParameters();
552   }
553 
554  private:
555   WebGLRenderingContextBase* context_;
556   bool enabled_;
557 };
558 
FormatWebGLStatusString(const StringView & gl_info,const StringView & info_string,StringBuilder & builder)559 static void FormatWebGLStatusString(const StringView& gl_info,
560                                     const StringView& info_string,
561                                     StringBuilder& builder) {
562   if (info_string.IsEmpty())
563     return;
564   builder.Append(", ");
565   builder.Append(gl_info);
566   builder.Append(" = ");
567   builder.Append(info_string);
568 }
569 
ExtractWebGLContextCreationError(const Platform::GraphicsInfo & info)570 static String ExtractWebGLContextCreationError(
571     const Platform::GraphicsInfo& info) {
572   StringBuilder builder;
573   builder.Append("Could not create a WebGL context");
574   FormatWebGLStatusString(
575       "VENDOR",
576       info.vendor_id ? String::Format("0x%04x", info.vendor_id) : "0xffff",
577       builder);
578   FormatWebGLStatusString(
579       "DEVICE",
580       info.device_id ? String::Format("0x%04x", info.device_id) : "0xffff",
581       builder);
582   FormatWebGLStatusString("GL_VENDOR", info.vendor_info, builder);
583   FormatWebGLStatusString("GL_RENDERER", info.renderer_info, builder);
584   FormatWebGLStatusString("GL_VERSION", info.driver_version, builder);
585   FormatWebGLStatusString("Sandboxed", info.sandboxed ? "yes" : "no", builder);
586   FormatWebGLStatusString("Optimus", info.optimus ? "yes" : "no", builder);
587   FormatWebGLStatusString("AMD switchable", info.amd_switchable ? "yes" : "no",
588                           builder);
589   FormatWebGLStatusString(
590       "Reset notification strategy",
591       String::Format("0x%04x", info.reset_notification_strategy).Utf8().c_str(),
592       builder);
593   FormatWebGLStatusString("ErrorMessage", info.error_message.Utf8().c_str(),
594                           builder);
595   builder.Append('.');
596   return builder.ToString();
597 }
598 
SupportOwnOffscreenSurface(ExecutionContext * execution_context)599 bool WebGLRenderingContextBase::SupportOwnOffscreenSurface(
600     ExecutionContext* execution_context) {
601   // Using an own offscreen surface disables virtualized contexts, and this
602   // doesn't currently work properly, see https://crbug.com/691102.
603   // TODO(https://crbug.com/791755): Remove this function and related code once
604   // the replacement is ready.
605   return false;
606 }
607 
608 std::unique_ptr<WebGraphicsContext3DProvider>
CreateContextProviderInternal(CanvasRenderingContextHost * host,const CanvasContextCreationAttributesCore & attributes,Platform::ContextType context_type,bool * using_gpu_compositing)609 WebGLRenderingContextBase::CreateContextProviderInternal(
610     CanvasRenderingContextHost* host,
611     const CanvasContextCreationAttributesCore& attributes,
612     Platform::ContextType context_type,
613     bool* using_gpu_compositing) {
614   DCHECK(host);
615   ExecutionContext* execution_context = host->GetTopExecutionContext();
616   DCHECK(execution_context);
617 
618   Platform::ContextAttributes context_attributes = ToPlatformContextAttributes(
619       attributes, context_type, SupportOwnOffscreenSurface(execution_context));
620 
621   Platform::GraphicsInfo gl_info;
622   std::unique_ptr<WebGraphicsContext3DProvider> context_provider;
623   const auto& url = execution_context->Url();
624   if (IsMainThread()) {
625     // Ask for gpu compositing mode when making the context. The context will be
626     // lost if the mode changes.
627     *using_gpu_compositing = !Platform::Current()->IsGpuCompositingDisabled();
628     context_provider =
629         Platform::Current()->CreateOffscreenGraphicsContext3DProvider(
630             context_attributes, url, &gl_info);
631   } else {
632     context_provider = CreateContextProviderOnWorkerThread(
633         context_attributes, &gl_info, using_gpu_compositing, url);
634   }
635   if (context_provider && !context_provider->BindToCurrentThread()) {
636     context_provider = nullptr;
637     gl_info.error_message =
638         String("bindToCurrentThread failed: " + String(gl_info.error_message));
639   }
640   if (!context_provider || g_should_fail_context_creation_for_testing) {
641     g_should_fail_context_creation_for_testing = false;
642     host->HostDispatchEvent(
643         WebGLContextEvent::Create(event_type_names::kWebglcontextcreationerror,
644                                   ExtractWebGLContextCreationError(gl_info)));
645     return nullptr;
646   }
647   gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
648   if (!String(gl->GetString(GL_EXTENSIONS))
649            .Contains("GL_OES_packed_depth_stencil")) {
650     host->HostDispatchEvent(WebGLContextEvent::Create(
651         event_type_names::kWebglcontextcreationerror,
652         "OES_packed_depth_stencil support is required."));
653     return nullptr;
654   }
655   return context_provider;
656 }
657 
658 std::unique_ptr<WebGraphicsContext3DProvider>
CreateWebGraphicsContext3DProvider(CanvasRenderingContextHost * host,const CanvasContextCreationAttributesCore & attributes,Platform::ContextType context_type,bool * using_gpu_compositing)659 WebGLRenderingContextBase::CreateWebGraphicsContext3DProvider(
660     CanvasRenderingContextHost* host,
661     const CanvasContextCreationAttributesCore& attributes,
662     Platform::ContextType context_type,
663     bool* using_gpu_compositing) {
664   // The host might block creation of a new WebGL context despite the
665   // page settings; in particular, if WebGL contexts were lost one or
666   // more times via the GL_ARB_robustness extension.
667   if (host->IsWebGLBlocked()) {
668     host->SetContextCreationWasBlocked();
669     host->HostDispatchEvent(WebGLContextEvent::Create(
670         event_type_names::kWebglcontextcreationerror,
671         "Web page caused context loss and was blocked"));
672     return nullptr;
673   }
674   if ((context_type == Platform::kWebGL1ContextType &&
675        !host->IsWebGL1Enabled()) ||
676       (context_type == Platform::kWebGL2ContextType &&
677        !host->IsWebGL2Enabled())) {
678     host->HostDispatchEvent(WebGLContextEvent::Create(
679         event_type_names::kWebglcontextcreationerror,
680         "disabled by enterprise policy or commandline switch"));
681     return nullptr;
682   }
683 
684   return CreateContextProviderInternal(host, attributes, context_type,
685                                        using_gpu_compositing);
686 }
687 
ForceNextWebGLContextCreationToFail()688 void WebGLRenderingContextBase::ForceNextWebGLContextCreationToFail() {
689   g_should_fail_context_creation_for_testing = true;
690 }
691 
TransferToImageBitmapBase(ScriptState * script_state)692 ImageBitmap* WebGLRenderingContextBase::TransferToImageBitmapBase(
693     ScriptState* script_state) {
694   WebFeature feature = WebFeature::kOffscreenCanvasTransferToImageBitmapWebGL;
695   UseCounter::Count(ExecutionContext::From(script_state), feature);
696   return MakeGarbageCollected<ImageBitmap>(
697       GetDrawingBuffer()->TransferToStaticBitmapImage());
698 }
699 
commit()700 void WebGLRenderingContextBase::commit() {
701   if (!GetDrawingBuffer() || (Host() && Host()->IsOffscreenCanvas()))
702     return;
703 
704   int width = GetDrawingBuffer()->Size().Width();
705   int height = GetDrawingBuffer()->Size().Height();
706 
707   if (PaintRenderingResultsToCanvas(kBackBuffer)) {
708     if (Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU)) {
709       Host()->Commit(Host()->ResourceProvider()->ProduceCanvasResource(),
710                      SkIRect::MakeWH(width, height));
711     }
712   }
713   MarkLayerComposited();
714 }
715 
GetImage()716 scoped_refptr<StaticBitmapImage> WebGLRenderingContextBase::GetImage() {
717   if (!GetDrawingBuffer())
718     return nullptr;
719 
720   ScopedFramebufferRestorer fbo_restorer(this);
721   GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
722   // Use the drawing buffer size here instead of the canvas size to ensure that
723   // sizing is consistent. The forced downsizing logic in Reshape() can lead to
724   // the drawing buffer being smaller than the canvas size.
725   // See https://crbug.com/845742.
726   IntSize size = GetDrawingBuffer()->Size();
727   // Since we are grabbing a snapshot that is not for compositing, we use a
728   // custom resource provider. This avoids consuming compositing-specific
729   // resources (e.g. GpuMemoryBuffer)
730   auto color_params = ColorParams();
731   std::unique_ptr<CanvasResourceProvider> resource_provider =
732       CanvasResourceProvider::CreateSharedImageProvider(
733           size, GetDrawingBuffer()->FilterQuality(), color_params,
734           CanvasResourceProvider::ShouldInitialize::kNo,
735           SharedGpuContext::ContextProviderWrapper(), RasterMode::kGPU,
736           is_origin_top_left_, 0u /*shared_image_usage_flags*/);
737   // todo(bug 1090962) This CPU fallback is needed as it would break
738   // webgl_conformance_gles_passthrough_tests on Android FYI for Nexus 5x.
739   if (!resource_provider || !resource_provider->IsValid()) {
740     resource_provider = CanvasResourceProvider::CreateBitmapProvider(
741         size, GetDrawingBuffer()->FilterQuality(), color_params,
742         CanvasResourceProvider::ShouldInitialize::kNo);
743   }
744 
745   if (!resource_provider || !resource_provider->IsValid())
746     return nullptr;
747 
748   if (!CopyRenderingResultsFromDrawingBuffer(resource_provider.get(),
749                                              kBackBuffer)) {
750     // CopyRenderingResultsFromDrawingBuffer will handle both CPU and GPU cases.
751     NOTREACHED();
752     return nullptr;
753   }
754   return resource_provider->Snapshot();
755 }
756 
makeXRCompatible(ScriptState * script_state,ExceptionState & exception_state)757 ScriptPromise WebGLRenderingContextBase::makeXRCompatible(
758     ScriptState* script_state,
759     ExceptionState& exception_state) {
760   if (isContextLost()) {
761     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
762                                       "Context lost.");
763     return ScriptPromise();
764   }
765 
766   // Return a resolved promise if we're already xr compatible. Once we're
767   // compatible, we should always be compatible unless a context lost occurs.
768   // DispatchContextLostEvent() resets this flag to false.
769   if (xr_compatible_)
770     return ScriptPromise::CastUndefined(script_state);
771 
772   if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled()) {
773     xr_compatible_ = true;
774     return ScriptPromise::CastUndefined(script_state);
775   }
776 
777   // If there's a request currently in progress, return the same promise.
778   if (make_xr_compatible_resolver_)
779     return make_xr_compatible_resolver_->Promise();
780 
781   make_xr_compatible_resolver_ =
782       MakeGarbageCollected<ScriptPromiseResolver>(script_state);
783   ScriptPromise promise = make_xr_compatible_resolver_->Promise();
784 
785   MakeXrCompatibleAsync();
786 
787   return promise;
788 }
789 
IsXRCompatible() const790 bool WebGLRenderingContextBase::IsXRCompatible() const {
791   return xr_compatible_;
792 }
793 
IsXrCompatibleFromResult(device::mojom::blink::XrCompatibleResult result)794 bool WebGLRenderingContextBase::IsXrCompatibleFromResult(
795     device::mojom::blink::XrCompatibleResult result) {
796   return result ==
797              device::mojom::blink::XrCompatibleResult::kAlreadyCompatible ||
798          result ==
799              device::mojom::blink::XrCompatibleResult::kCompatibleAfterRestart;
800 }
801 
DidGpuRestart(device::mojom::blink::XrCompatibleResult result)802 bool WebGLRenderingContextBase::DidGpuRestart(
803     device::mojom::blink::XrCompatibleResult result) {
804   return result == device::mojom::blink::XrCompatibleResult::
805                        kCompatibleAfterRestart ||
806          result == device::mojom::blink::XrCompatibleResult::
807                        kNotCompatibleAfterRestart;
808 }
809 
MakeXrCompatibleSync(CanvasRenderingContextHost * host)810 bool WebGLRenderingContextBase::MakeXrCompatibleSync(
811     CanvasRenderingContextHost* host) {
812   if (!RuntimeEnabledFeatures::WebXRMultiGpuEnabled())
813     return true;
814 
815   device::mojom::blink::XrCompatibleResult xr_compatible_result =
816       device::mojom::blink::XrCompatibleResult::kNoDeviceAvailable;
817 
818   if (!host->IsOffscreenCanvas()) {
819     HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(host);
820     if (XRSystem* xr = XRSystem::From(canvas->GetDocument()))
821       xr->MakeXrCompatibleSync(&xr_compatible_result);
822   }
823 
824   return IsXrCompatibleFromResult(xr_compatible_result);
825 }
826 
MakeXrCompatibleAsync()827 void WebGLRenderingContextBase::MakeXrCompatibleAsync() {
828   if (!canvas()) {
829     xr_compatible_ = false;
830     CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
831     return;
832   }
833 
834   XRSystem* xr = XRSystem::From(canvas()->GetDocument());
835   if (!xr) {
836     xr_compatible_ = false;
837     CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
838     return;
839   }
840 
841   // The promise will be completed on the callback.
842   xr->MakeXrCompatibleAsync(
843       WTF::Bind(&WebGLRenderingContextBase::OnMakeXrCompatibleFinished,
844                 WrapWeakPersistent(this)));
845 }
846 
OnMakeXrCompatibleFinished(device::mojom::blink::XrCompatibleResult xr_compatible_result)847 void WebGLRenderingContextBase::OnMakeXrCompatibleFinished(
848     device::mojom::blink::XrCompatibleResult xr_compatible_result) {
849   xr_compatible_ = IsXrCompatibleFromResult(xr_compatible_result);
850 
851   // If the gpu process is restarted, MaybeRestoreContext will resolve the
852   // promise on the subsequent restore.
853   if (!DidGpuRestart(xr_compatible_result)) {
854     DOMExceptionCode exception_code = DOMExceptionCode::kUnknownError;
855     switch (xr_compatible_result) {
856       case device::mojom::blink::XrCompatibleResult::kAlreadyCompatible:
857         exception_code = DOMExceptionCode::kNoError;
858         break;
859       case device::mojom::blink::XrCompatibleResult::kNoDeviceAvailable:
860         // Per WebXR spec, reject with an InvalidStateError if device is null.
861         exception_code = DOMExceptionCode::kInvalidStateError;
862         break;
863       case device::mojom::blink::XrCompatibleResult::kWebXrFeaturePolicyBlocked:
864         exception_code = DOMExceptionCode::kSecurityError;
865         break;
866       case device::mojom::blink::XrCompatibleResult::kCompatibleAfterRestart:
867       case device::mojom::blink::XrCompatibleResult::kNotCompatibleAfterRestart:
868         NOTREACHED();
869     }
870     CompleteXrCompatiblePromiseIfPending(exception_code);
871   }
872 }
873 
CompleteXrCompatiblePromiseIfPending(DOMExceptionCode exception_code)874 void WebGLRenderingContextBase::CompleteXrCompatiblePromiseIfPending(
875     DOMExceptionCode exception_code) {
876   if (make_xr_compatible_resolver_) {
877     if (xr_compatible_) {
878       DCHECK(exception_code == DOMExceptionCode::kNoError);
879       make_xr_compatible_resolver_->Resolve();
880     } else {
881       DCHECK(exception_code != DOMExceptionCode::kNoError);
882       make_xr_compatible_resolver_->Reject(
883           MakeGarbageCollected<DOMException>(exception_code));
884     }
885 
886     make_xr_compatible_resolver_ = nullptr;
887 
888     if (IdentifiabilityStudySettings::Get()->ShouldSample(
889             IdentifiableSurface::FromTypeAndToken(
890                 IdentifiableSurface::Type::kWebFeature,
891                 WebFeature::kWebGLRenderingContextMakeXRCompatible))) {
892       const auto& ukm_params = GetUkmParameters();
893       IdentifiabilityMetricBuilder(ukm_params.source_id)
894           .SetWebfeature(WebFeature::kWebGLRenderingContextMakeXRCompatible,
895                          exception_code == DOMExceptionCode::kNoError)
896           .Record(ukm_params.ukm_recorder);
897     }
898   }
899 }
900 
901 void WebGLRenderingContextBase::
UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta)902     UpdateNumberOfUserAllocatedMultisampledRenderbuffers(int delta) {
903   DCHECK(delta >= -1 && delta <= 1);
904   number_of_user_allocated_multisampled_renderbuffers_ += delta;
905   DCHECK_GE(number_of_user_allocated_multisampled_renderbuffers_, 0);
906 }
907 
908 namespace {
909 
910 // Exposed by GL_ANGLE_depth_texture
911 static const GLenum kSupportedInternalFormatsOESDepthTex[] = {
912     GL_DEPTH_COMPONENT,
913     GL_DEPTH_STENCIL,
914 };
915 
916 // Exposed by GL_EXT_sRGB
917 static const GLenum kSupportedInternalFormatsEXTsRGB[] = {
918     GL_SRGB,
919     GL_SRGB_ALPHA_EXT,
920 };
921 
922 // ES3 enums supported by both CopyTexImage and TexImage.
923 static const GLenum kSupportedInternalFormatsES3[] = {
924     GL_R8,           GL_RG8,      GL_RGB565,   GL_RGB8,       GL_RGBA4,
925     GL_RGB5_A1,      GL_RGBA8,    GL_RGB10_A2, GL_RGB10_A2UI, GL_SRGB8,
926     GL_SRGB8_ALPHA8, GL_R8I,      GL_R8UI,     GL_R16I,       GL_R16UI,
927     GL_R32I,         GL_R32UI,    GL_RG8I,     GL_RG8UI,      GL_RG16I,
928     GL_RG16UI,       GL_RG32I,    GL_RG32UI,   GL_RGBA8I,     GL_RGBA8UI,
929     GL_RGBA16I,      GL_RGBA16UI, GL_RGBA32I,  GL_RGBA32UI,   GL_RGB32I,
930     GL_RGB32UI,      GL_RGB8I,    GL_RGB8UI,   GL_RGB16I,     GL_RGB16UI,
931 };
932 
933 // ES3 enums only supported by TexImage
934 static const GLenum kSupportedInternalFormatsTexImageES3[] = {
935     GL_R8_SNORM,
936     GL_R16F,
937     GL_R32F,
938     GL_RG8_SNORM,
939     GL_RG16F,
940     GL_RG32F,
941     GL_RGB8_SNORM,
942     GL_R11F_G11F_B10F,
943     GL_RGB9_E5,
944     GL_RGB16F,
945     GL_RGB32F,
946     GL_RGBA8_SNORM,
947     GL_RGBA16F,
948     GL_RGBA32F,
949     GL_DEPTH_COMPONENT16,
950     GL_DEPTH_COMPONENT24,
951     GL_DEPTH_COMPONENT32F,
952     GL_DEPTH24_STENCIL8,
953     GL_DEPTH32F_STENCIL8,
954 };
955 
956 // Exposed by EXT_texture_norm16
957 static constexpr GLenum kSupportedInternalFormatsEXTTextureNorm16ES3[] = {
958     GL_R16_EXT,         GL_RG16_EXT,        GL_RGB16_EXT,
959     GL_RGBA16_EXT,      GL_R16_SNORM_EXT,   GL_RG16_SNORM_EXT,
960     GL_RGB16_SNORM_EXT, GL_RGBA16_SNORM_EXT};
961 
962 static constexpr GLenum kSupportedFormatsEXTTextureNorm16ES3[] = {GL_RED,
963                                                                   GL_RG};
964 
965 static constexpr GLenum kSupportedTypesEXTTextureNorm16ES3[] = {
966     GL_SHORT, GL_UNSIGNED_SHORT};
967 
968 // Exposed by EXT_color_buffer_float
969 static const GLenum kSupportedInternalFormatsCopyTexImageFloatES3[] = {
970     GL_R16F,   GL_R32F,    GL_RG16F,   GL_RG32F,         GL_RGB16F,
971     GL_RGB32F, GL_RGBA16F, GL_RGBA32F, GL_R11F_G11F_B10F};
972 
973 // Exposed by EXT_color_buffer_half_float
974 static const GLenum kSupportedInternalFormatsCopyTexImageHalfFloatES3[] = {
975     GL_R16F,
976     GL_RG16F,
977     GL_RGB16F,
978     GL_RGBA16F,
979 };
980 
981 // ES3 enums supported by TexImageSource
982 static const GLenum kSupportedInternalFormatsTexImageSourceES3[] = {
983     GL_R8,      GL_R16F,           GL_R32F,         GL_R8UI,     GL_RG8,
984     GL_RG16F,   GL_RG32F,          GL_RG8UI,        GL_RGB8,     GL_SRGB8,
985     GL_RGB565,  GL_R11F_G11F_B10F, GL_RGB9_E5,      GL_RGB16F,   GL_RGB32F,
986     GL_RGB8UI,  GL_RGBA8,          GL_SRGB8_ALPHA8, GL_RGB5_A1,  GL_RGBA4,
987     GL_RGBA16F, GL_RGBA32F,        GL_RGBA8UI,      GL_RGB10_A2,
988 };
989 
990 // ES2 enums
991 // Internalformat must equal format in ES2.
992 static const GLenum kSupportedFormatsES2[] = {
993     GL_RGB, GL_RGBA, GL_LUMINANCE_ALPHA, GL_LUMINANCE, GL_ALPHA,
994 };
995 
996 // Exposed by GL_ANGLE_depth_texture
997 static const GLenum kSupportedFormatsOESDepthTex[] = {
998     GL_DEPTH_COMPONENT,
999     GL_DEPTH_STENCIL,
1000 };
1001 
1002 // Exposed by GL_EXT_sRGB
1003 static const GLenum kSupportedFormatsEXTsRGB[] = {
1004     GL_SRGB,
1005     GL_SRGB_ALPHA_EXT,
1006 };
1007 
1008 // ES3 enums
1009 static const GLenum kSupportedFormatsES3[] = {
1010     GL_RED,           GL_RED_INTEGER,  GL_RG,
1011     GL_RG_INTEGER,    GL_RGB,          GL_RGB_INTEGER,
1012     GL_RGBA,          GL_RGBA_INTEGER, GL_DEPTH_COMPONENT,
1013     GL_DEPTH_STENCIL,
1014 };
1015 
1016 // ES3 enums supported by TexImageSource
1017 static const GLenum kSupportedFormatsTexImageSourceES3[] = {
1018     GL_RED, GL_RED_INTEGER, GL_RG,   GL_RG_INTEGER,
1019     GL_RGB, GL_RGB_INTEGER, GL_RGBA, GL_RGBA_INTEGER,
1020 };
1021 
1022 // ES2 enums
1023 static const GLenum kSupportedTypesES2[] = {
1024     GL_UNSIGNED_BYTE,
1025     GL_UNSIGNED_SHORT_5_6_5,
1026     GL_UNSIGNED_SHORT_4_4_4_4,
1027     GL_UNSIGNED_SHORT_5_5_5_1,
1028 };
1029 
1030 // Exposed by GL_OES_texture_float
1031 static const GLenum kSupportedTypesOESTexFloat[] = {
1032     GL_FLOAT,
1033 };
1034 
1035 // Exposed by GL_OES_texture_half_float
1036 static const GLenum kSupportedTypesOESTexHalfFloat[] = {
1037     GL_HALF_FLOAT_OES,
1038 };
1039 
1040 // Exposed by GL_ANGLE_depth_texture
1041 static const GLenum kSupportedTypesOESDepthTex[] = {
1042     GL_UNSIGNED_SHORT,
1043     GL_UNSIGNED_INT,
1044     GL_UNSIGNED_INT_24_8,
1045 };
1046 
1047 // ES3 enums
1048 static const GLenum kSupportedTypesES3[] = {
1049     GL_BYTE,
1050     GL_UNSIGNED_SHORT,
1051     GL_SHORT,
1052     GL_UNSIGNED_INT,
1053     GL_INT,
1054     GL_HALF_FLOAT,
1055     GL_FLOAT,
1056     GL_UNSIGNED_INT_2_10_10_10_REV,
1057     GL_UNSIGNED_INT_10F_11F_11F_REV,
1058     GL_UNSIGNED_INT_5_9_9_9_REV,
1059     GL_UNSIGNED_INT_24_8,
1060     GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
1061 };
1062 
1063 // ES3 enums supported by TexImageSource
1064 static const GLenum kSupportedTypesTexImageSourceES3[] = {
1065     GL_HALF_FLOAT,
1066     GL_FLOAT,
1067     GL_UNSIGNED_INT_10F_11F_11F_REV,
1068     GL_UNSIGNED_INT_2_10_10_10_REV,
1069 };
1070 
1071 }  // namespace
1072 
WebGLRenderingContextBase(CanvasRenderingContextHost * host,std::unique_ptr<WebGraphicsContext3DProvider> context_provider,bool using_gpu_compositing,const CanvasContextCreationAttributesCore & requested_attributes,Platform::ContextType version)1073 WebGLRenderingContextBase::WebGLRenderingContextBase(
1074     CanvasRenderingContextHost* host,
1075     std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
1076     bool using_gpu_compositing,
1077     const CanvasContextCreationAttributesCore& requested_attributes,
1078     Platform::ContextType version)
1079     : WebGLRenderingContextBase(
1080           host,
1081           host->GetTopExecutionContext()->GetTaskRunner(TaskType::kWebGL),
1082           std::move(context_provider),
1083           using_gpu_compositing,
1084           requested_attributes,
1085           version) {}
1086 
WebGLRenderingContextBase(CanvasRenderingContextHost * host,scoped_refptr<base::SingleThreadTaskRunner> task_runner,std::unique_ptr<WebGraphicsContext3DProvider> context_provider,bool using_gpu_compositing,const CanvasContextCreationAttributesCore & requested_attributes,Platform::ContextType context_type)1087 WebGLRenderingContextBase::WebGLRenderingContextBase(
1088     CanvasRenderingContextHost* host,
1089     scoped_refptr<base::SingleThreadTaskRunner> task_runner,
1090     std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
1091     bool using_gpu_compositing,
1092     const CanvasContextCreationAttributesCore& requested_attributes,
1093     Platform::ContextType context_type)
1094     : CanvasRenderingContext(host, requested_attributes),
1095       context_group_(MakeGarbageCollected<WebGLContextGroup>()),
1096       dispatch_context_lost_event_timer_(
1097           task_runner,
1098           this,
1099           &WebGLRenderingContextBase::DispatchContextLostEvent),
1100       restore_timer_(task_runner,
1101                      this,
1102                      &WebGLRenderingContextBase::MaybeRestoreContext),
1103       task_runner_(task_runner),
1104       num_gl_errors_to_console_allowed_(kMaxGLErrorsAllowedToConsole),
1105       context_type_(context_type),
1106       program_completion_queries_(
1107           base::MRUCache<WebGLProgram*, GLuint>::NO_AUTO_EVICT),
1108       number_of_user_allocated_multisampled_renderbuffers_(0) {
1109   DCHECK(context_provider);
1110 
1111   xr_compatible_ = requested_attributes.xr_compatible;
1112 
1113   context_group_->AddContext(this);
1114 
1115   max_viewport_dims_[0] = max_viewport_dims_[1] = 0;
1116   context_provider->ContextGL()->GetIntegerv(GL_MAX_VIEWPORT_DIMS,
1117                                              max_viewport_dims_);
1118   InitializeWebGLContextLimits(context_provider.get());
1119 
1120   scoped_refptr<DrawingBuffer> buffer;
1121   buffer =
1122       CreateDrawingBuffer(std::move(context_provider), using_gpu_compositing);
1123   if (!buffer) {
1124     context_lost_mode_ = kSyntheticLostContext;
1125     return;
1126   }
1127 
1128   drawing_buffer_ = std::move(buffer);
1129   GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
1130   SetupFlags();
1131 
1132   String disabled_webgl_extensions(GetDrawingBuffer()
1133                                        ->ContextProvider()
1134                                        ->GetGpuFeatureInfo()
1135                                        .disabled_webgl_extensions.c_str());
1136   Vector<String> disabled_extension_list;
1137   disabled_webgl_extensions.Split(' ', disabled_extension_list);
1138   for (const auto& entry : disabled_extension_list) {
1139     disabled_extensions_.insert(entry);
1140   }
1141 
1142 #define ADD_VALUES_TO_SET(set, values)              \
1143   for (size_t i = 0; i < base::size(values); ++i) { \
1144     set.insert(values[i]);                          \
1145   }
1146 
1147   ADD_VALUES_TO_SET(supported_internal_formats_, kSupportedFormatsES2);
1148   ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
1149                     kSupportedFormatsES2);
1150   ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
1151                     kSupportedFormatsES2);
1152   ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsES2);
1153   ADD_VALUES_TO_SET(supported_tex_image_source_formats_, kSupportedFormatsES2);
1154   ADD_VALUES_TO_SET(supported_types_, kSupportedTypesES2);
1155   ADD_VALUES_TO_SET(supported_tex_image_source_types_, kSupportedTypesES2);
1156 }
1157 
CreateDrawingBuffer(std::unique_ptr<WebGraphicsContext3DProvider> context_provider,bool using_gpu_compositing)1158 scoped_refptr<DrawingBuffer> WebGLRenderingContextBase::CreateDrawingBuffer(
1159     std::unique_ptr<WebGraphicsContext3DProvider> context_provider,
1160     bool using_gpu_compositing) {
1161   const CanvasContextCreationAttributesCore& attrs = CreationAttributes();
1162   bool premultiplied_alpha = attrs.premultiplied_alpha;
1163   bool want_alpha_channel = attrs.alpha;
1164   bool want_depth_buffer = attrs.depth;
1165   bool want_stencil_buffer = attrs.stencil;
1166   bool want_antialiasing = attrs.antialias;
1167   DrawingBuffer::PreserveDrawingBuffer preserve = attrs.preserve_drawing_buffer
1168                                                       ? DrawingBuffer::kPreserve
1169                                                       : DrawingBuffer::kDiscard;
1170   DrawingBuffer::WebGLVersion web_gl_version = DrawingBuffer::kWebGL1;
1171   if (context_type_ == Platform::kWebGL1ContextType) {
1172     web_gl_version = DrawingBuffer::kWebGL1;
1173   } else if (context_type_ == Platform::kWebGL2ContextType) {
1174     web_gl_version = DrawingBuffer::kWebGL2;
1175   } else {
1176     NOTREACHED();
1177   }
1178 
1179   // On Mac OS, DrawingBuffer is using an IOSurface as its backing storage, this
1180   // allows WebGL-rendered canvases to be composited by the OS rather than
1181   // Chrome.
1182   // IOSurfaces are only compatible with the GL_TEXTURE_RECTANGLE_ARB binding
1183   // target. So to avoid the knowledge of GL_TEXTURE_RECTANGLE_ARB type textures
1184   // being introduced into more areas of the code, we use the code path of
1185   // non-WebGLImageChromium for OffscreenCanvas.
1186   // See detailed discussion in crbug.com/649668.
1187   DrawingBuffer::ChromiumImageUsage chromium_image_usage =
1188       Host()->IsOffscreenCanvas() ? DrawingBuffer::kDisallowChromiumImage
1189                                   : DrawingBuffer::kAllowChromiumImage;
1190 
1191   bool using_swap_chain =
1192       base::FeatureList::IsEnabled(features::kLowLatencyWebGLSwapChain) &&
1193       context_provider->GetCapabilities().shared_image_swap_chain &&
1194       attrs.desynchronized;
1195 
1196   return DrawingBuffer::Create(
1197       std::move(context_provider), using_gpu_compositing, using_swap_chain,
1198       this, ClampedCanvasSize(), premultiplied_alpha, want_alpha_channel,
1199       want_depth_buffer, want_stencil_buffer, want_antialiasing, preserve,
1200       web_gl_version, chromium_image_usage, Host()->FilterQuality(),
1201       ColorParams(), PowerPreferenceToGpuPreference(attrs.power_preference));
1202 }
1203 
InitializeNewContext()1204 void WebGLRenderingContextBase::InitializeNewContext() {
1205   DCHECK(!isContextLost());
1206   DCHECK(GetDrawingBuffer());
1207 
1208   marked_canvas_dirty_ = false;
1209   must_paint_to_canvas_ = false;
1210   active_texture_unit_ = 0;
1211   pack_alignment_ = 4;
1212   unpack_alignment_ = 4;
1213   unpack_flip_y_ = false;
1214   unpack_premultiply_alpha_ = false;
1215   unpack_colorspace_conversion_ = GC3D_BROWSER_DEFAULT_WEBGL;
1216   bound_array_buffer_ = nullptr;
1217   current_program_ = nullptr;
1218   framebuffer_binding_ = nullptr;
1219   renderbuffer_binding_ = nullptr;
1220   depth_mask_ = true;
1221   stencil_enabled_ = false;
1222   stencil_mask_ = 0xFFFFFFFF;
1223   stencil_mask_back_ = 0xFFFFFFFF;
1224   stencil_func_ref_ = 0;
1225   stencil_func_ref_back_ = 0;
1226   stencil_func_mask_ = 0xFFFFFFFF;
1227   stencil_func_mask_back_ = 0xFFFFFFFF;
1228   num_gl_errors_to_console_allowed_ = kMaxGLErrorsAllowedToConsole;
1229 
1230   clear_color_[0] = clear_color_[1] = clear_color_[2] = clear_color_[3] = 0;
1231   scissor_enabled_ = false;
1232   clear_depth_ = 1;
1233   clear_stencil_ = 0;
1234   color_mask_[0] = color_mask_[1] = color_mask_[2] = color_mask_[3] = true;
1235 
1236   GLint num_combined_texture_image_units = 0;
1237   ContextGL()->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
1238                            &num_combined_texture_image_units);
1239   texture_units_.clear();
1240   texture_units_.resize(num_combined_texture_image_units);
1241 
1242   GLint num_vertex_attribs = 0;
1243   ContextGL()->GetIntegerv(GL_MAX_VERTEX_ATTRIBS, &num_vertex_attribs);
1244   max_vertex_attribs_ = num_vertex_attribs;
1245 
1246   max_texture_size_ = 0;
1247   ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
1248   max_texture_level_ =
1249       WebGLTexture::ComputeLevelCount(max_texture_size_, max_texture_size_, 1);
1250   max_cube_map_texture_size_ = 0;
1251   ContextGL()->GetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE,
1252                            &max_cube_map_texture_size_);
1253   max3d_texture_size_ = 0;
1254   max3d_texture_level_ = 0;
1255   max_array_texture_layers_ = 0;
1256   if (IsWebGL2()) {
1257     ContextGL()->GetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3d_texture_size_);
1258     max3d_texture_level_ = WebGLTexture::ComputeLevelCount(
1259         max3d_texture_size_, max3d_texture_size_, max3d_texture_size_);
1260     ContextGL()->GetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS,
1261                              &max_array_texture_layers_);
1262   }
1263   max_cube_map_texture_level_ = WebGLTexture::ComputeLevelCount(
1264       max_cube_map_texture_size_, max_cube_map_texture_size_, 1);
1265   max_renderbuffer_size_ = 0;
1266   ContextGL()->GetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &max_renderbuffer_size_);
1267 
1268   // These two values from EXT_draw_buffers are lazily queried.
1269   max_draw_buffers_ = 0;
1270   max_color_attachments_ = 0;
1271 
1272   back_draw_buffer_ = GL_BACK;
1273 
1274   read_buffer_of_default_framebuffer_ = GL_BACK;
1275 
1276   default_vertex_array_object_ = MakeGarbageCollected<WebGLVertexArrayObject>(
1277       this, WebGLVertexArrayObjectBase::kVaoTypeDefault);
1278 
1279   bound_vertex_array_object_ = default_vertex_array_object_;
1280 
1281   vertex_attrib_type_.resize(max_vertex_attribs_);
1282 
1283   ContextGL()->Viewport(0, 0, drawingBufferWidth(), drawingBufferHeight());
1284   scissor_box_[0] = scissor_box_[1] = 0;
1285   scissor_box_[2] = drawingBufferWidth();
1286   scissor_box_[3] = drawingBufferHeight();
1287   ContextGL()->Scissor(scissor_box_[0], scissor_box_[1], scissor_box_[2],
1288                        scissor_box_[3]);
1289 
1290   GetDrawingBuffer()->ContextProvider()->SetLostContextCallback(
1291       WTF::BindRepeating(&WebGLRenderingContextBase::ForceLostContext,
1292                          WrapWeakPersistent(this),
1293                          WebGLRenderingContextBase::kRealLostContext,
1294                          WebGLRenderingContextBase::kAuto));
1295   GetDrawingBuffer()->ContextProvider()->SetErrorMessageCallback(
1296       WTF::BindRepeating(&WebGLRenderingContextBase::OnErrorMessage,
1297                          WrapWeakPersistent(this)));
1298 
1299   // If the context has the flip_y extension, it will behave as having the
1300   // origin of coordinates on the top left.
1301   is_origin_top_left_ = GetDrawingBuffer()
1302                             ->ContextProvider()
1303                             ->GetCapabilities()
1304                             .mesa_framebuffer_flip_y;
1305 
1306   // If WebGL 2, the PRIMITIVE_RESTART_FIXED_INDEX should be always enabled.
1307   // See the section <Primitive Restart is Always Enabled> in WebGL 2 spec:
1308   // https://www.khronos.org/registry/webgl/specs/latest/2.0/#4.1.4
1309   if (IsWebGL2())
1310     ContextGL()->Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
1311 
1312   // This ensures that the context has a valid "lastFlushID" and won't be
1313   // mistakenly identified as the "least recently used" context.
1314   ContextGL()->Flush();
1315 
1316   for (int i = 0; i < kWebGLExtensionNameCount; ++i)
1317     extension_enabled_[i] = false;
1318 
1319   // This limits the count of threads if the extension is yet to be requested.
1320   if (String(ContextGL()->GetString(GL_EXTENSIONS))
1321           .Contains("GL_KHR_parallel_shader_compile")) {
1322     ContextGL()->MaxShaderCompilerThreadsKHR(2);
1323   }
1324   is_web_gl2_formats_types_added_ = false;
1325   is_web_gl2_tex_image_source_formats_types_added_ = false;
1326   is_web_gl2_internal_formats_copy_tex_image_added_ = false;
1327   is_oes_texture_float_formats_types_added_ = false;
1328   is_oes_texture_half_float_formats_types_added_ = false;
1329   is_web_gl_depth_texture_formats_types_added_ = false;
1330   is_ext_srgb_formats_types_added_ = false;
1331   is_ext_color_buffer_float_formats_added_ = false;
1332   is_ext_color_buffer_half_float_formats_added_ = false;
1333   is_ext_texture_norm16_added_ = false;
1334 
1335   supported_internal_formats_.clear();
1336   ADD_VALUES_TO_SET(supported_internal_formats_, kSupportedFormatsES2);
1337   supported_tex_image_source_internal_formats_.clear();
1338   ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
1339                     kSupportedFormatsES2);
1340   supported_internal_formats_copy_tex_image_.clear();
1341   ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
1342                     kSupportedFormatsES2);
1343   supported_formats_.clear();
1344   ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsES2);
1345   supported_tex_image_source_formats_.clear();
1346   ADD_VALUES_TO_SET(supported_tex_image_source_formats_, kSupportedFormatsES2);
1347   supported_types_.clear();
1348   ADD_VALUES_TO_SET(supported_types_, kSupportedTypesES2);
1349   supported_tex_image_source_types_.clear();
1350   ADD_VALUES_TO_SET(supported_tex_image_source_types_, kSupportedTypesES2);
1351 
1352   number_of_user_allocated_multisampled_renderbuffers_ = 0;
1353 
1354   // The DrawingBuffer was unable to store the state that dirtied when it was
1355   // initialized. Restore it now.
1356   GetDrawingBuffer()->RestoreAllState();
1357   ActivateContext(this);
1358 }
1359 
SetupFlags()1360 void WebGLRenderingContextBase::SetupFlags() {
1361   DCHECK(GetDrawingBuffer());
1362   if (canvas()) {
1363     synthesized_errors_to_console_ =
1364         canvas()->GetSettings()->GetWebGLErrorsToConsoleEnabled();
1365   }
1366 
1367   is_depth_stencil_supported_ =
1368       ExtensionsUtil()->IsExtensionEnabled("GL_OES_packed_depth_stencil");
1369 }
1370 
AddCompressedTextureFormat(GLenum format)1371 void WebGLRenderingContextBase::AddCompressedTextureFormat(GLenum format) {
1372   if (!compressed_texture_formats_.Contains(format))
1373     compressed_texture_formats_.push_back(format);
1374 }
1375 
RemoveAllCompressedTextureFormats()1376 void WebGLRenderingContextBase::RemoveAllCompressedTextureFormats() {
1377   compressed_texture_formats_.clear();
1378 }
1379 
1380 // Helper function for V8 bindings to identify what version of WebGL a
1381 // CanvasRenderingContext supports.
GetWebGLVersion(const CanvasRenderingContext * context)1382 unsigned WebGLRenderingContextBase::GetWebGLVersion(
1383     const CanvasRenderingContext* context) {
1384   if (!context->Is3d())
1385     return 0;
1386   return static_cast<const WebGLRenderingContextBase*>(context)->ContextType();
1387 }
1388 
~WebGLRenderingContextBase()1389 WebGLRenderingContextBase::~WebGLRenderingContextBase() {
1390   // It's forbidden to refer to other GC'd objects in a GC'd object's
1391   // destructor. It's useful for DrawingBuffer to guarantee that it
1392   // calls its DrawingBufferClient during its own destruction, but if
1393   // the WebGL context is also being destroyed, then it's essential
1394   // that the DrawingBufferClient methods not try to touch other
1395   // objects like WebGLTextures that were previously hooked into the
1396   // context state.
1397   destruction_in_progress_ = true;
1398 
1399   // Now that the context and context group no longer hold on to the
1400   // objects they create, and now that the objects are eagerly finalized
1401   // rather than the context, there is very little useful work that this
1402   // destructor can do, since it's not allowed to touch other on-heap
1403   // objects. All it can do is destroy its underlying context, which, if
1404   // there are no other contexts in the same share group, will cause all of
1405   // the underlying graphics resources to be deleted. (Currently, it's
1406   // always the case that there are no other contexts in the same share
1407   // group -- resource sharing between WebGL contexts is not yet
1408   // implemented, and due to its complex semantics, it's doubtful that it
1409   // ever will be.)
1410   DestroyContext();
1411 
1412   // Now that this context is destroyed, see if there's a
1413   // previously-evicted one that should be restored.
1414   RestoreEvictedContext(this);
1415 }
1416 
DestroyContext()1417 void WebGLRenderingContextBase::DestroyContext() {
1418   if (!GetDrawingBuffer())
1419     return;
1420 
1421   clearProgramCompletionQueries();
1422 
1423   extensions_util_.reset();
1424 
1425   base::RepeatingClosure null_closure;
1426   base::RepeatingCallback<void(const char*, int32_t)> null_function;
1427   GetDrawingBuffer()->ContextProvider()->SetLostContextCallback(
1428       std::move(null_closure));
1429   GetDrawingBuffer()->ContextProvider()->SetErrorMessageCallback(
1430       std::move(null_function));
1431 
1432   DCHECK(GetDrawingBuffer());
1433   drawing_buffer_->BeginDestruction();
1434   drawing_buffer_ = nullptr;
1435 }
1436 
MarkContextChanged(ContentChangeType change_type)1437 void WebGLRenderingContextBase::MarkContextChanged(
1438     ContentChangeType change_type) {
1439   if (isContextLost())
1440     return;
1441 
1442   if (framebuffer_binding_) {
1443     framebuffer_binding_->SetContentsChanged(true);
1444     return;
1445   }
1446 
1447   // Regardless of whether dirty propagations are optimized away, the back
1448   // buffer is now out of sync with respect to the canvas's internal backing
1449   // store -- which is only used for certain purposes, like printing.
1450   must_paint_to_canvas_ = true;
1451 
1452   if (!GetDrawingBuffer()->MarkContentsChanged() && marked_canvas_dirty_) {
1453     return;
1454   }
1455 
1456   if (Host()->IsOffscreenCanvas()) {
1457     marked_canvas_dirty_ = true;
1458     DidDraw();
1459     return;
1460   }
1461 
1462   if (!canvas())
1463     return;
1464 
1465   if (!marked_canvas_dirty_) {
1466     marked_canvas_dirty_ = true;
1467     LayoutBox* layout_box = canvas()->GetLayoutBox();
1468     auto* settings = canvas()->GetDocument().GetSettings();
1469     if (layout_box && settings->GetAcceleratedCompositingEnabled())
1470       layout_box->ContentChanged(change_type);
1471     IntSize canvas_size = ClampedCanvasSize();
1472     DidDraw(SkIRect::MakeXYWH(0, 0, canvas_size.Width(), canvas_size.Height()));
1473   }
1474 }
1475 
1476 scoped_refptr<base::SingleThreadTaskRunner>
GetContextTaskRunner()1477 WebGLRenderingContextBase::GetContextTaskRunner() {
1478   return task_runner_;
1479 }
1480 
DidDraw(const SkIRect & dirty_rect)1481 void WebGLRenderingContextBase::DidDraw(const SkIRect& dirty_rect) {
1482   MarkContextChanged(kCanvasChanged);
1483   CanvasRenderingContext::DidDraw(dirty_rect);
1484 }
1485 
DidDraw()1486 void WebGLRenderingContextBase::DidDraw() {
1487   MarkContextChanged(kCanvasChanged);
1488   CanvasRenderingContext::DidDraw();
1489 }
1490 
PushFrame()1491 bool WebGLRenderingContextBase::PushFrame() {
1492   int submitted_frame = false;
1493   if (PaintRenderingResultsToCanvas(kBackBuffer)) {
1494     if (Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU)) {
1495       int width = GetDrawingBuffer()->Size().Width();
1496       int height = GetDrawingBuffer()->Size().Height();
1497       submitted_frame =
1498           Host()->PushFrame(Host()->ResourceProvider()->ProduceCanvasResource(),
1499                             SkIRect::MakeWH(width, height));
1500     }
1501   }
1502   MarkLayerComposited();
1503   return submitted_frame;
1504 }
1505 
FinalizeFrame()1506 void WebGLRenderingContextBase::FinalizeFrame() {
1507   if (Host()->LowLatencyEnabled()) {
1508     // PaintRenderingResultsToCanvas will export drawing buffer if the resource
1509     // provider is single buffered.  Otherwise it will copy the drawing buffer.
1510     PaintRenderingResultsToCanvas(kBackBuffer);
1511   }
1512   marked_canvas_dirty_ = false;
1513 }
1514 
OnErrorMessage(const char * message,int32_t id)1515 void WebGLRenderingContextBase::OnErrorMessage(const char* message,
1516                                                int32_t id) {
1517   if (synthesized_errors_to_console_)
1518     PrintGLErrorToConsole(message);
1519   NotifyWebGLErrorOrWarning(message);
1520 }
1521 
1522 WebGLRenderingContextBase::HowToClear
ClearIfComposited(GLbitfield mask)1523 WebGLRenderingContextBase::ClearIfComposited(GLbitfield mask) {
1524   if (isContextLost())
1525     return kSkipped;
1526 
1527   GLbitfield buffers_needing_clearing =
1528       GetDrawingBuffer()->GetBuffersToAutoClear();
1529 
1530   if (buffers_needing_clearing == 0 || (mask && framebuffer_binding_))
1531     return kSkipped;
1532 
1533   if (isContextLost()) {
1534     // Unlikely, but context was lost.
1535     return kSkipped;
1536   }
1537 
1538   // Determine if it's possible to combine the clear the user asked for and this
1539   // clear.
1540   bool combined_clear = mask && !scissor_enabled_;
1541 
1542   ContextGL()->Disable(GL_SCISSOR_TEST);
1543   if (combined_clear && (mask & GL_COLOR_BUFFER_BIT)) {
1544     ContextGL()->ClearColor(color_mask_[0] ? clear_color_[0] : 0,
1545                             color_mask_[1] ? clear_color_[1] : 0,
1546                             color_mask_[2] ? clear_color_[2] : 0,
1547                             color_mask_[3] ? clear_color_[3] : 0);
1548   } else {
1549     ContextGL()->ClearColor(0, 0, 0, 0);
1550   }
1551   ContextGL()->ColorMask(
1552       true, true, true,
1553       !GetDrawingBuffer()->RequiresAlphaChannelToBePreserved());
1554   GLbitfield clear_mask = GL_COLOR_BUFFER_BIT;
1555 
1556   const bool has_depth =
1557       CreationAttributes().depth && GetDrawingBuffer()->HasDepthBuffer();
1558   const bool has_stencil =
1559       CreationAttributes().stencil && GetDrawingBuffer()->HasStencilBuffer();
1560 
1561   if (has_depth) {
1562     if (!combined_clear || !depth_mask_ || !(mask & GL_DEPTH_BUFFER_BIT))
1563       ContextGL()->ClearDepthf(1.0f);
1564     clear_mask |= GL_DEPTH_BUFFER_BIT;
1565     ContextGL()->DepthMask(true);
1566   }
1567   if (has_stencil || GetDrawingBuffer()->HasImplicitStencilBuffer()) {
1568     if (combined_clear && (mask & GL_STENCIL_BUFFER_BIT))
1569       ContextGL()->ClearStencil(clear_stencil_ & stencil_mask_);
1570     else
1571       ContextGL()->ClearStencil(0);
1572     clear_mask |= GL_STENCIL_BUFFER_BIT;
1573     ContextGL()->StencilMaskSeparate(GL_FRONT, 0xFFFFFFFF);
1574   }
1575 
1576   ContextGL()->ColorMask(
1577       true, true, true,
1578       !GetDrawingBuffer()->DefaultBufferRequiresAlphaChannelToBePreserved());
1579   // If the WebGL 2.0 clearBuffer APIs already have been used to
1580   // selectively clear some of the buffers, don't destroy those
1581   // results.
1582   GetDrawingBuffer()->ClearFramebuffers(clear_mask & buffers_needing_clearing);
1583 
1584   // Call the DrawingBufferClient method to restore scissor test, mask, and
1585   // clear values, because we dirtied them above.
1586   DrawingBufferClientRestoreScissorTest();
1587   DrawingBufferClientRestoreMaskAndClearValues();
1588 
1589   GetDrawingBuffer()->SetBuffersToAutoClear(0);
1590 
1591   return combined_clear ? kCombinedClear : kJustClear;
1592 }
1593 
RestoreScissorEnabled()1594 void WebGLRenderingContextBase::RestoreScissorEnabled() {
1595   if (isContextLost())
1596     return;
1597 
1598   if (scissor_enabled_) {
1599     ContextGL()->Enable(GL_SCISSOR_TEST);
1600   } else {
1601     ContextGL()->Disable(GL_SCISSOR_TEST);
1602   }
1603 }
1604 
RestoreScissorBox()1605 void WebGLRenderingContextBase::RestoreScissorBox() {
1606   if (isContextLost())
1607     return;
1608 
1609   ContextGL()->Scissor(scissor_box_[0], scissor_box_[1], scissor_box_[2],
1610                        scissor_box_[3]);
1611 }
1612 
RestoreClearColor()1613 void WebGLRenderingContextBase::RestoreClearColor() {
1614   if (isContextLost())
1615     return;
1616 
1617   ContextGL()->ClearColor(clear_color_[0], clear_color_[1], clear_color_[2],
1618                           clear_color_[3]);
1619 }
1620 
RestoreColorMask()1621 void WebGLRenderingContextBase::RestoreColorMask() {
1622   if (isContextLost())
1623     return;
1624 
1625   ContextGL()->ColorMask(color_mask_[0], color_mask_[1], color_mask_[2],
1626                          color_mask_[3]);
1627 }
1628 
MarkLayerComposited()1629 void WebGLRenderingContextBase::MarkLayerComposited() {
1630   if (!isContextLost())
1631     GetDrawingBuffer()->ResetBuffersToAutoClear();
1632 }
1633 
UsingSwapChain() const1634 bool WebGLRenderingContextBase::UsingSwapChain() const {
1635   return GetDrawingBuffer() && GetDrawingBuffer()->UsingSwapChain();
1636 }
1637 
IsOriginTopLeft() const1638 bool WebGLRenderingContextBase::IsOriginTopLeft() const {
1639   if (isContextLost())
1640     return false;
1641   return is_origin_top_left_;
1642 }
1643 
SetIsInHiddenPage(bool hidden)1644 void WebGLRenderingContextBase::SetIsInHiddenPage(bool hidden) {
1645   is_hidden_ = hidden;
1646   if (GetDrawingBuffer())
1647     GetDrawingBuffer()->SetIsInHiddenPage(hidden);
1648 
1649   if (!hidden && isContextLost() && restore_allowed_ &&
1650       auto_recovery_method_ == kAuto && !restore_timer_.IsActive()) {
1651     restore_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
1652   }
1653 }
1654 
PaintRenderingResultsToCanvas(SourceDrawingBuffer source_buffer)1655 bool WebGLRenderingContextBase::PaintRenderingResultsToCanvas(
1656     SourceDrawingBuffer source_buffer) {
1657   if (isContextLost() || !GetDrawingBuffer())
1658     return false;
1659 
1660   bool must_clear_now = ClearIfComposited() != kSkipped;
1661   if (!must_paint_to_canvas_ && !must_clear_now)
1662     return false;
1663 
1664   must_paint_to_canvas_ = false;
1665 
1666   if (Host()->ResourceProvider() &&
1667       Host()->ResourceProvider()->Size() != GetDrawingBuffer()->Size()) {
1668     Host()->DiscardResourceProvider();
1669   }
1670 
1671   CanvasResourceProvider* resource_provider =
1672       Host()->GetOrCreateCanvasResourceProvider(RasterModeHint::kPreferGPU);
1673   if (!resource_provider)
1674     return false;
1675 
1676   if (Host()->LowLatencyEnabled() &&
1677       resource_provider->SupportsSingleBuffering()) {
1678     // It's possible single buffering isn't enabled yet because we haven't
1679     // finished the first frame e.g. this gets called first due to drawImage.
1680     resource_provider->TryEnableSingleBuffering();
1681     DCHECK(resource_provider->IsSingleBuffered());
1682     // Single buffered passthrough resource provider doesn't have backing
1683     // texture. We need to export the backbuffer mailbox directly without
1684     // copying.
1685     if (!resource_provider->ImportResource(GetDrawingBuffer()->AsCanvasResource(
1686             resource_provider->CreateWeakPtr()))) {
1687       // This isn't expected to fail for single buffered resource provider.
1688       NOTREACHED();
1689       return false;
1690     }
1691     return true;
1692   }
1693 
1694   ScopedTexture2DRestorer restorer(this);
1695   ScopedFramebufferRestorer fbo_restorer(this);
1696 
1697   GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
1698   if (!CopyRenderingResultsFromDrawingBuffer(Host()->ResourceProvider(),
1699                                              source_buffer)) {
1700     // Currently, CopyRenderingResultsFromDrawingBuffer is expected to always
1701     // succeed because cases where canvas()-buffer() is not accelerated are
1702     // handled before reaching this point.  If that assumption ever stops
1703     // holding true, we may need to implement a fallback right here.
1704     NOTREACHED();
1705     return false;
1706   }
1707   return true;
1708 }
1709 
CopyRenderingResultsFromDrawingBuffer(CanvasResourceProvider * resource_provider,SourceDrawingBuffer source_buffer)1710 bool WebGLRenderingContextBase::CopyRenderingResultsFromDrawingBuffer(
1711     CanvasResourceProvider* resource_provider,
1712     SourceDrawingBuffer source_buffer) {
1713   DCHECK(drawing_buffer_);
1714   DCHECK(resource_provider);
1715   DCHECK(!resource_provider->IsSingleBuffered());
1716   if (resource_provider->IsAccelerated()) {
1717     base::WeakPtr<WebGraphicsContext3DProviderWrapper> shared_context_wrapper =
1718         SharedGpuContext::ContextProviderWrapper();
1719     if (!shared_context_wrapper || !shared_context_wrapper->ContextProvider())
1720       return false;
1721     gpu::raster::RasterInterface* raster_interface =
1722         shared_context_wrapper->ContextProvider()->RasterInterface();
1723     const gpu::Mailbox& mailbox =
1724         resource_provider->GetBackingMailboxForOverwrite(
1725             MailboxSyncMode::kOrderingBarrier);
1726     GLenum texture_target = resource_provider->GetBackingTextureTarget();
1727     if (mailbox.IsZero())
1728       return false;
1729 
1730     // TODO(xlai): Flush should not be necessary if the synchronization in
1731     // CopyToPlatformTexture is done correctly. See crbug.com/794706.
1732     raster_interface->Flush();
1733 
1734     bool flip_y = IsOriginTopLeft() != resource_provider->IsOriginTopLeft();
1735     return drawing_buffer_->CopyToPlatformMailbox(
1736         raster_interface, mailbox, texture_target, flip_y, IntPoint(0, 0),
1737         IntRect(IntPoint(0, 0), drawing_buffer_->Size()), source_buffer);
1738   }
1739 
1740   // Note: This code path could work for all cases. The only reason there
1741   // is a separate path for the accelerated case is that we assume texture
1742   // copying is faster than drawImage.
1743   scoped_refptr<StaticBitmapImage> image = GetImage();
1744   if (!image || !image->PaintImageForCurrentFrame())
1745     return false;
1746   cc::PaintFlags paint_flags;
1747   paint_flags.setBlendMode(SkBlendMode::kSrc);
1748   resource_provider->Canvas()->drawImage(image->PaintImageForCurrentFrame(), 0,
1749                                          0, &paint_flags);
1750   return true;
1751 }
1752 
DrawingBufferSize() const1753 IntSize WebGLRenderingContextBase::DrawingBufferSize() const {
1754   if (isContextLost())
1755     return IntSize(0, 0);
1756   return GetDrawingBuffer()->Size();
1757 }
1758 
PaintRenderingResultsToDataArray(SourceDrawingBuffer source_buffer)1759 sk_sp<SkData> WebGLRenderingContextBase::PaintRenderingResultsToDataArray(
1760     SourceDrawingBuffer source_buffer) {
1761   if (isContextLost())
1762     return nullptr;
1763   ClearIfComposited();
1764   GetDrawingBuffer()->ResolveAndBindForReadAndDraw();
1765   ScopedFramebufferRestorer restorer(this);
1766   return GetDrawingBuffer()->PaintRenderingResultsToDataArray(source_buffer);
1767 }
1768 
Reshape(int width,int height)1769 void WebGLRenderingContextBase::Reshape(int width, int height) {
1770   if (isContextLost())
1771     return;
1772 
1773   GLint buffer = 0;
1774   if (IsWebGL2()) {
1775     // This query returns client side cached binding, so it's trivial.
1776     // If it changes in the future, such query is heavy and should be avoided.
1777     ContextGL()->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &buffer);
1778     if (buffer) {
1779       ContextGL()->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1780     }
1781   }
1782 
1783   // This is an approximation because at WebGLRenderingContextBase level we
1784   // don't know if the underlying FBO uses textures or renderbuffers.
1785   GLint max_size = std::min(max_texture_size_, max_renderbuffer_size_);
1786   GLint max_width = std::min(max_size, max_viewport_dims_[0]);
1787   GLint max_height = std::min(max_size, max_viewport_dims_[1]);
1788   width = Clamp(width, 1, max_width);
1789   height = Clamp(height, 1, max_height);
1790 
1791   // Limit drawing buffer area to the resolution of an 8K monitor to avoid
1792   // memory exhaustion.  Width or height may be larger than that size as long as
1793   // it's within the max viewport dimensions and total area remains within the
1794   // limit. For example: 7680x4320 should be fine.
1795   const int kMaxArea = 5760 * 5760;
1796   int current_area = width * height;
1797   if (current_area > kMaxArea) {
1798     // If we've exceeded the area limit scale the buffer down, preserving
1799     // ascpect ratio, until it fits.
1800     float scale_factor =
1801         sqrtf(static_cast<float>(kMaxArea) / static_cast<float>(current_area));
1802     width = std::max(1, static_cast<int>(width * scale_factor));
1803     height = std::max(1, static_cast<int>(height * scale_factor));
1804   }
1805 
1806   // We don't have to mark the canvas as dirty, since the newly created image
1807   // buffer will also start off clear (and this matches what reshape will do).
1808   GetDrawingBuffer()->Resize(IntSize(width, height));
1809 
1810   if (buffer) {
1811     ContextGL()->BindBuffer(GL_PIXEL_UNPACK_BUFFER,
1812                             static_cast<GLuint>(buffer));
1813   }
1814 }
1815 
drawingBufferWidth() const1816 int WebGLRenderingContextBase::drawingBufferWidth() const {
1817   return isContextLost() ? 0 : GetDrawingBuffer()->Size().Width();
1818 }
1819 
drawingBufferHeight() const1820 int WebGLRenderingContextBase::drawingBufferHeight() const {
1821   return isContextLost() ? 0 : GetDrawingBuffer()->Size().Height();
1822 }
1823 
activeTexture(GLenum texture)1824 void WebGLRenderingContextBase::activeTexture(GLenum texture) {
1825   if (isContextLost())
1826     return;
1827   if (texture - GL_TEXTURE0 >= texture_units_.size()) {
1828     SynthesizeGLError(GL_INVALID_ENUM, "activeTexture",
1829                       "texture unit out of range");
1830     return;
1831   }
1832   active_texture_unit_ = texture - GL_TEXTURE0;
1833   ContextGL()->ActiveTexture(texture);
1834 }
1835 
attachShader(WebGLProgram * program,WebGLShader * shader)1836 void WebGLRenderingContextBase::attachShader(WebGLProgram* program,
1837                                              WebGLShader* shader) {
1838   if (!ValidateWebGLProgramOrShader("attachShader", program) ||
1839       !ValidateWebGLProgramOrShader("attachShader", shader))
1840     return;
1841   if (!program->AttachShader(shader)) {
1842     SynthesizeGLError(GL_INVALID_OPERATION, "attachShader",
1843                       "shader attachment already has shader");
1844     return;
1845   }
1846   ContextGL()->AttachShader(ObjectOrZero(program), ObjectOrZero(shader));
1847   shader->OnAttached();
1848 }
1849 
bindAttribLocation(WebGLProgram * program,GLuint index,const String & name)1850 void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program,
1851                                                    GLuint index,
1852                                                    const String& name) {
1853   if (!ValidateWebGLProgramOrShader("bindAttribLocation", program))
1854     return;
1855   if (!ValidateLocationLength("bindAttribLocation", name))
1856     return;
1857   if (IsPrefixReserved(name)) {
1858     SynthesizeGLError(GL_INVALID_OPERATION, "bindAttribLocation",
1859                       "reserved prefix");
1860     return;
1861   }
1862   ContextGL()->BindAttribLocation(ObjectOrZero(program), index,
1863                                   name.Utf8().c_str());
1864 }
1865 
ValidateAndUpdateBufferBindTarget(const char * function_name,GLenum target,WebGLBuffer * buffer)1866 bool WebGLRenderingContextBase::ValidateAndUpdateBufferBindTarget(
1867     const char* function_name,
1868     GLenum target,
1869     WebGLBuffer* buffer) {
1870   if (!ValidateBufferTarget(function_name, target))
1871     return false;
1872 
1873   if (buffer && buffer->GetInitialTarget() &&
1874       buffer->GetInitialTarget() != target) {
1875     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
1876                       "buffers can not be used with multiple targets");
1877     return false;
1878   }
1879 
1880   switch (target) {
1881     case GL_ARRAY_BUFFER:
1882       bound_array_buffer_ = buffer;
1883       break;
1884     case GL_ELEMENT_ARRAY_BUFFER:
1885       bound_vertex_array_object_->SetElementArrayBuffer(buffer);
1886       break;
1887     default:
1888       NOTREACHED();
1889       return false;
1890   }
1891 
1892   if (buffer && !buffer->GetInitialTarget())
1893     buffer->SetInitialTarget(target);
1894   return true;
1895 }
1896 
bindBuffer(GLenum target,WebGLBuffer * buffer)1897 void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) {
1898   if (!ValidateNullableWebGLObject("bindBuffer", buffer))
1899     return;
1900   if (!ValidateAndUpdateBufferBindTarget("bindBuffer", target, buffer))
1901     return;
1902   ContextGL()->BindBuffer(target, ObjectOrZero(buffer));
1903 }
1904 
bindFramebuffer(GLenum target,WebGLFramebuffer * buffer)1905 void WebGLRenderingContextBase::bindFramebuffer(GLenum target,
1906                                                 WebGLFramebuffer* buffer) {
1907   if (!ValidateNullableWebGLObject("bindFramebuffer", buffer))
1908     return;
1909 
1910   if (target != GL_FRAMEBUFFER) {
1911     SynthesizeGLError(GL_INVALID_ENUM, "bindFramebuffer", "invalid target");
1912     return;
1913   }
1914 
1915   SetFramebuffer(target, buffer);
1916 }
1917 
bindRenderbuffer(GLenum target,WebGLRenderbuffer * render_buffer)1918 void WebGLRenderingContextBase::bindRenderbuffer(
1919     GLenum target,
1920     WebGLRenderbuffer* render_buffer) {
1921   if (!ValidateNullableWebGLObject("bindRenderbuffer", render_buffer))
1922     return;
1923   if (target != GL_RENDERBUFFER) {
1924     SynthesizeGLError(GL_INVALID_ENUM, "bindRenderbuffer", "invalid target");
1925     return;
1926   }
1927   renderbuffer_binding_ = render_buffer;
1928   ContextGL()->BindRenderbuffer(target, ObjectOrZero(render_buffer));
1929   if (render_buffer)
1930     render_buffer->SetHasEverBeenBound();
1931 }
1932 
bindTexture(GLenum target,WebGLTexture * texture)1933 void WebGLRenderingContextBase::bindTexture(GLenum target,
1934                                             WebGLTexture* texture) {
1935   if (!ValidateNullableWebGLObject("bindTexture", texture))
1936     return;
1937   if (texture && texture->GetTarget() && texture->GetTarget() != target) {
1938     SynthesizeGLError(GL_INVALID_OPERATION, "bindTexture",
1939                       "textures can not be used with multiple targets");
1940     return;
1941   }
1942 
1943   if (target == GL_TEXTURE_2D) {
1944     texture_units_[active_texture_unit_].texture2d_binding_ = texture;
1945   } else if (target == GL_TEXTURE_CUBE_MAP) {
1946     texture_units_[active_texture_unit_].texture_cube_map_binding_ = texture;
1947   } else if (IsWebGL2() && target == GL_TEXTURE_2D_ARRAY) {
1948     texture_units_[active_texture_unit_].texture2d_array_binding_ = texture;
1949   } else if (IsWebGL2() && target == GL_TEXTURE_3D) {
1950     texture_units_[active_texture_unit_].texture3d_binding_ = texture;
1951   } else if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
1952     if (!ExtensionEnabled(kWebGLVideoTextureName)) {
1953       SynthesizeGLError(
1954           GL_INVALID_VALUE, "bindTexture",
1955           "unhandled type, WEBGL_video_texture extension not enabled");
1956       return;
1957     }
1958     texture_units_[active_texture_unit_].texture_video_image_binding_ = texture;
1959   } else {
1960     SynthesizeGLError(GL_INVALID_ENUM, "bindTexture", "invalid target");
1961     return;
1962   }
1963 
1964   // We use TEXTURE_EXTERNAL_OES to implement video texture on Android platform
1965   if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
1966 #if defined(OS_ANDROID)
1967     // TODO(crbug.com/776222): Support extension on Android
1968     NOTIMPLEMENTED();
1969     return;
1970 #else
1971     // TODO(crbug.com/776222): Using GL_TEXTURE_VIDEO_IMAGE_WEBGL in blink
1972     ContextGL()->BindTexture(GL_TEXTURE_2D, ObjectOrZero(texture));
1973     if (texture && !texture->GetTarget()) {
1974       ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
1975                                  GL_LINEAR);
1976       ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1977                                  GL_LINEAR);
1978       ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
1979                                  GL_CLAMP_TO_EDGE);
1980       ContextGL()->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
1981                                  GL_CLAMP_TO_EDGE);
1982     }
1983 #endif  // defined OS_ANDROID
1984   } else {
1985     ContextGL()->BindTexture(target, ObjectOrZero(texture));
1986   }
1987   if (texture) {
1988     texture->SetTarget(target);
1989     one_plus_max_non_default_texture_unit_ =
1990         max(active_texture_unit_ + 1, one_plus_max_non_default_texture_unit_);
1991   } else {
1992     // If the disabled index is the current maximum, trace backwards to find the
1993     // new max enabled texture index
1994     if (one_plus_max_non_default_texture_unit_ == active_texture_unit_ + 1) {
1995       FindNewMaxNonDefaultTextureUnit();
1996     }
1997   }
1998 
1999   // Note: previously we used to automatically set the TEXTURE_WRAP_R
2000   // repeat mode to CLAMP_TO_EDGE for cube map textures, because OpenGL
2001   // ES 2.0 doesn't expose this flag (a bug in the specification) and
2002   // otherwise the application has no control over the seams in this
2003   // dimension. However, it appears that supporting this properly on all
2004   // platforms is fairly involved (will require a HashMap from texture ID
2005   // in all ports), and we have not had any complaints, so the logic has
2006   // been removed.
2007 }
2008 
blendColor(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha)2009 void WebGLRenderingContextBase::blendColor(GLfloat red,
2010                                            GLfloat green,
2011                                            GLfloat blue,
2012                                            GLfloat alpha) {
2013   if (isContextLost())
2014     return;
2015   ContextGL()->BlendColor(red, green, blue, alpha);
2016 }
2017 
blendEquation(GLenum mode)2018 void WebGLRenderingContextBase::blendEquation(GLenum mode) {
2019   if (isContextLost() || !ValidateBlendEquation("blendEquation", mode))
2020     return;
2021   ContextGL()->BlendEquation(mode);
2022 }
2023 
blendEquationSeparate(GLenum mode_rgb,GLenum mode_alpha)2024 void WebGLRenderingContextBase::blendEquationSeparate(GLenum mode_rgb,
2025                                                       GLenum mode_alpha) {
2026   if (isContextLost() ||
2027       !ValidateBlendEquation("blendEquationSeparate", mode_rgb) ||
2028       !ValidateBlendEquation("blendEquationSeparate", mode_alpha))
2029     return;
2030   ContextGL()->BlendEquationSeparate(mode_rgb, mode_alpha);
2031 }
2032 
blendFunc(GLenum sfactor,GLenum dfactor)2033 void WebGLRenderingContextBase::blendFunc(GLenum sfactor, GLenum dfactor) {
2034   if (isContextLost() ||
2035       !ValidateBlendFuncFactors("blendFunc", sfactor, dfactor))
2036     return;
2037   ContextGL()->BlendFunc(sfactor, dfactor);
2038 }
2039 
blendFuncSeparate(GLenum src_rgb,GLenum dst_rgb,GLenum src_alpha,GLenum dst_alpha)2040 void WebGLRenderingContextBase::blendFuncSeparate(GLenum src_rgb,
2041                                                   GLenum dst_rgb,
2042                                                   GLenum src_alpha,
2043                                                   GLenum dst_alpha) {
2044   // Note: Alpha does not have the same restrictions as RGB.
2045   if (isContextLost() ||
2046       !ValidateBlendFuncFactors("blendFuncSeparate", src_rgb, dst_rgb))
2047     return;
2048   ContextGL()->BlendFuncSeparate(src_rgb, dst_rgb, src_alpha, dst_alpha);
2049 }
2050 
BufferDataImpl(GLenum target,int64_t size,const void * data,GLenum usage)2051 void WebGLRenderingContextBase::BufferDataImpl(GLenum target,
2052                                                int64_t size,
2053                                                const void* data,
2054                                                GLenum usage) {
2055   WebGLBuffer* buffer = ValidateBufferDataTarget("bufferData", target);
2056   if (!buffer)
2057     return;
2058 
2059   if (!ValidateBufferDataUsage("bufferData", usage))
2060     return;
2061 
2062   if (!ValidateValueFitNonNegInt32("bufferData", "size", size))
2063     return;
2064 
2065   buffer->SetSize(size);
2066 
2067   ContextGL()->BufferData(target, static_cast<GLsizeiptr>(size), data, usage);
2068 }
2069 
bufferData(GLenum target,int64_t size,GLenum usage)2070 void WebGLRenderingContextBase::bufferData(GLenum target,
2071                                            int64_t size,
2072                                            GLenum usage) {
2073   if (isContextLost())
2074     return;
2075   BufferDataImpl(target, size, nullptr, usage);
2076 }
2077 
bufferData(GLenum target,DOMArrayBuffer * data,GLenum usage)2078 void WebGLRenderingContextBase::bufferData(GLenum target,
2079                                            DOMArrayBuffer* data,
2080                                            GLenum usage) {
2081   if (isContextLost())
2082     return;
2083   if (!data) {
2084     SynthesizeGLError(GL_INVALID_VALUE, "bufferData", "no data");
2085     return;
2086   }
2087   BufferDataImpl(target, data->ByteLength(), data->Data(), usage);
2088 }
2089 
bufferData(GLenum target,MaybeShared<DOMArrayBufferView> data,GLenum usage)2090 void WebGLRenderingContextBase::bufferData(GLenum target,
2091                                            MaybeShared<DOMArrayBufferView> data,
2092                                            GLenum usage) {
2093   if (isContextLost())
2094     return;
2095   DCHECK(data);
2096   BufferDataImpl(target, data.View()->byteLength(),
2097                  data.View()->BaseAddressMaybeShared(), usage);
2098 }
2099 
BufferSubDataImpl(GLenum target,int64_t offset,GLsizeiptr size,const void * data)2100 void WebGLRenderingContextBase::BufferSubDataImpl(GLenum target,
2101                                                   int64_t offset,
2102                                                   GLsizeiptr size,
2103                                                   const void* data) {
2104   WebGLBuffer* buffer = ValidateBufferDataTarget("bufferSubData", target);
2105   if (!buffer)
2106     return;
2107   if (!ValidateValueFitNonNegInt32("bufferSubData", "offset", offset))
2108     return;
2109   if (!data)
2110     return;
2111   if (offset + static_cast<int64_t>(size) > buffer->GetSize()) {
2112     SynthesizeGLError(GL_INVALID_VALUE, "bufferSubData", "buffer overflow");
2113     return;
2114   }
2115 
2116   ContextGL()->BufferSubData(target, static_cast<GLintptr>(offset), size, data);
2117 }
2118 
bufferSubData(GLenum target,int64_t offset,DOMArrayBuffer * data)2119 void WebGLRenderingContextBase::bufferSubData(GLenum target,
2120                                               int64_t offset,
2121                                               DOMArrayBuffer* data) {
2122   if (isContextLost())
2123     return;
2124   DCHECK(data);
2125   BufferSubDataImpl(target, offset, data->ByteLength(), data->Data());
2126 }
2127 
bufferSubData(GLenum target,int64_t offset,const FlexibleArrayBufferView & data)2128 void WebGLRenderingContextBase::bufferSubData(
2129     GLenum target,
2130     int64_t offset,
2131     const FlexibleArrayBufferView& data) {
2132   if (isContextLost())
2133     return;
2134   DCHECK(!data.IsNull());
2135   BufferSubDataImpl(target, offset, data.ByteLength(),
2136                     data.BaseAddressMaybeOnStack());
2137 }
2138 
ValidateFramebufferTarget(GLenum target)2139 bool WebGLRenderingContextBase::ValidateFramebufferTarget(GLenum target) {
2140   if (target == GL_FRAMEBUFFER)
2141     return true;
2142   return false;
2143 }
2144 
GetFramebufferBinding(GLenum target)2145 WebGLFramebuffer* WebGLRenderingContextBase::GetFramebufferBinding(
2146     GLenum target) {
2147   if (target == GL_FRAMEBUFFER)
2148     return framebuffer_binding_.Get();
2149   return nullptr;
2150 }
2151 
GetReadFramebufferBinding()2152 WebGLFramebuffer* WebGLRenderingContextBase::GetReadFramebufferBinding() {
2153   return framebuffer_binding_.Get();
2154 }
2155 
checkFramebufferStatus(GLenum target)2156 GLenum WebGLRenderingContextBase::checkFramebufferStatus(GLenum target) {
2157   if (isContextLost())
2158     return GL_FRAMEBUFFER_UNSUPPORTED;
2159   if (!ValidateFramebufferTarget(target)) {
2160     SynthesizeGLError(GL_INVALID_ENUM, "checkFramebufferStatus",
2161                       "invalid target");
2162     return 0;
2163   }
2164   WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
2165   if (framebuffer_binding) {
2166     const char* reason = "framebuffer incomplete";
2167     GLenum status = framebuffer_binding->CheckDepthStencilStatus(&reason);
2168     if (status != GL_FRAMEBUFFER_COMPLETE) {
2169       EmitGLWarning("checkFramebufferStatus", reason);
2170       return status;
2171     }
2172   }
2173   return ContextGL()->CheckFramebufferStatus(target);
2174 }
2175 
clear(GLbitfield mask)2176 void WebGLRenderingContextBase::clear(GLbitfield mask) {
2177   if (isContextLost())
2178     return;
2179   if (mask &
2180       ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) {
2181     SynthesizeGLError(GL_INVALID_VALUE, "clear", "invalid mask");
2182     return;
2183   }
2184   const char* reason = "framebuffer incomplete";
2185   if (framebuffer_binding_ && framebuffer_binding_->CheckDepthStencilStatus(
2186                                   &reason) != GL_FRAMEBUFFER_COMPLETE) {
2187     SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "clear", reason);
2188     return;
2189   }
2190 
2191   if (!mask) {
2192     // Use OnErrorMessage because it's both rate-limited and obeys the
2193     // webGLErrorsToConsole setting.
2194     OnErrorMessage(
2195         "Performance warning: clear() called with no buffers in bitmask", 0);
2196     // Don't skip the call to ClearIfComposited below; it has side
2197     // effects even without the user requesting to clear any buffers.
2198   }
2199 
2200   ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2201                                                    drawing_buffer_.get());
2202 
2203   if (ClearIfComposited(mask) != kCombinedClear) {
2204     // If clearing the default back buffer's depth buffer, also clear the
2205     // stencil buffer, if one was allocated implicitly. This avoids performance
2206     // problems on some GPUs.
2207     if (!framebuffer_binding_ &&
2208         GetDrawingBuffer()->HasImplicitStencilBuffer() &&
2209         (mask & GL_DEPTH_BUFFER_BIT)) {
2210       // It shouldn't matter what value it's cleared to, since in other queries
2211       // in the API, we claim that the stencil buffer doesn't exist.
2212       mask |= GL_STENCIL_BUFFER_BIT;
2213     }
2214     ContextGL()->Clear(mask);
2215   }
2216   MarkContextChanged(kCanvasChanged);
2217 }
2218 
clearColor(GLfloat r,GLfloat g,GLfloat b,GLfloat a)2219 void WebGLRenderingContextBase::clearColor(GLfloat r,
2220                                            GLfloat g,
2221                                            GLfloat b,
2222                                            GLfloat a) {
2223   if (isContextLost())
2224     return;
2225   if (std::isnan(r))
2226     r = 0;
2227   if (std::isnan(g))
2228     g = 0;
2229   if (std::isnan(b))
2230     b = 0;
2231   if (std::isnan(a))
2232     a = 1;
2233   clear_color_[0] = r;
2234   clear_color_[1] = g;
2235   clear_color_[2] = b;
2236   clear_color_[3] = a;
2237   ContextGL()->ClearColor(r, g, b, a);
2238 }
2239 
clearDepth(GLfloat depth)2240 void WebGLRenderingContextBase::clearDepth(GLfloat depth) {
2241   if (isContextLost())
2242     return;
2243   clear_depth_ = depth;
2244   ContextGL()->ClearDepthf(depth);
2245 }
2246 
clearStencil(GLint s)2247 void WebGLRenderingContextBase::clearStencil(GLint s) {
2248   if (isContextLost())
2249     return;
2250   clear_stencil_ = s;
2251   ContextGL()->ClearStencil(s);
2252 }
2253 
colorMask(GLboolean red,GLboolean green,GLboolean blue,GLboolean alpha)2254 void WebGLRenderingContextBase::colorMask(GLboolean red,
2255                                           GLboolean green,
2256                                           GLboolean blue,
2257                                           GLboolean alpha) {
2258   if (isContextLost())
2259     return;
2260   color_mask_[0] = red;
2261   color_mask_[1] = green;
2262   color_mask_[2] = blue;
2263   color_mask_[3] = alpha;
2264   ContextGL()->ColorMask(red, green, blue, alpha);
2265 }
2266 
compileShader(WebGLShader * shader)2267 void WebGLRenderingContextBase::compileShader(WebGLShader* shader) {
2268   if (!ValidateWebGLProgramOrShader("compileShader", shader))
2269     return;
2270   ContextGL()->CompileShader(ObjectOrZero(shader));
2271 }
2272 
compressedTexImage2D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLint border,MaybeShared<DOMArrayBufferView> data)2273 void WebGLRenderingContextBase::compressedTexImage2D(
2274     GLenum target,
2275     GLint level,
2276     GLenum internalformat,
2277     GLsizei width,
2278     GLsizei height,
2279     GLint border,
2280     MaybeShared<DOMArrayBufferView> data) {
2281   if (isContextLost())
2282     return;
2283   if (!ValidateTexture2DBinding("compressedTexImage2D", target))
2284     return;
2285   if (!ValidateCompressedTexFormat("compressedTexImage2D", internalformat))
2286     return;
2287   GLsizei data_length;
2288   if (!ExtractDataLengthIfValid("compressedTexImage2D", data, &data_length))
2289     return;
2290   ContextGL()->CompressedTexImage2D(target, level, internalformat, width,
2291                                     height, border, data_length,
2292                                     data.View()->BaseAddressMaybeShared());
2293 }
2294 
compressedTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,MaybeShared<DOMArrayBufferView> data)2295 void WebGLRenderingContextBase::compressedTexSubImage2D(
2296     GLenum target,
2297     GLint level,
2298     GLint xoffset,
2299     GLint yoffset,
2300     GLsizei width,
2301     GLsizei height,
2302     GLenum format,
2303     MaybeShared<DOMArrayBufferView> data) {
2304   if (isContextLost())
2305     return;
2306   if (!ValidateTexture2DBinding("compressedTexSubImage2D", target))
2307     return;
2308   if (!ValidateCompressedTexFormat("compressedTexSubImage2D", format))
2309     return;
2310   GLsizei data_length;
2311   if (!ExtractDataLengthIfValid("compressedTexSubImage2D", data, &data_length))
2312     return;
2313   ContextGL()->CompressedTexSubImage2D(target, level, xoffset, yoffset, width,
2314                                        height, format, data_length,
2315                                        data.View()->BaseAddressMaybeShared());
2316 }
2317 
ValidateSettableTexFormat(const char * function_name,GLenum format)2318 bool WebGLRenderingContextBase::ValidateSettableTexFormat(
2319     const char* function_name,
2320     GLenum format) {
2321   if (IsWebGL2())
2322     return true;
2323 
2324   if (WebGLImageConversion::GetChannelBitsByFormat(format) &
2325       WebGLImageConversion::kChannelDepthStencil) {
2326     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2327                       "format can not be set, only rendered to");
2328     return false;
2329   }
2330   return true;
2331 }
2332 
ValidateCopyTexFormat(const char * function_name,GLenum internalformat)2333 bool WebGLRenderingContextBase::ValidateCopyTexFormat(const char* function_name,
2334                                                       GLenum internalformat) {
2335   if (!is_web_gl2_internal_formats_copy_tex_image_added_ && IsWebGL2()) {
2336     ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
2337                       kSupportedInternalFormatsES3);
2338     is_web_gl2_internal_formats_copy_tex_image_added_ = true;
2339   }
2340   if (!is_ext_color_buffer_float_formats_added_ &&
2341       ExtensionEnabled(kEXTColorBufferFloatName)) {
2342     ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
2343                       kSupportedInternalFormatsCopyTexImageFloatES3);
2344     is_ext_color_buffer_float_formats_added_ = true;
2345   }
2346   if (!is_ext_color_buffer_half_float_formats_added_ &&
2347       ExtensionEnabled(kEXTColorBufferHalfFloatName)) {
2348     ADD_VALUES_TO_SET(supported_internal_formats_copy_tex_image_,
2349                       kSupportedInternalFormatsCopyTexImageHalfFloatES3);
2350     is_ext_color_buffer_half_float_formats_added_ = true;
2351   }
2352 
2353   if (supported_internal_formats_copy_tex_image_.find(internalformat) ==
2354       supported_internal_formats_copy_tex_image_.end()) {
2355     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid internalformat");
2356     return false;
2357   }
2358 
2359   return true;
2360 }
2361 
copyTexImage2D(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,GLint border)2362 void WebGLRenderingContextBase::copyTexImage2D(GLenum target,
2363                                                GLint level,
2364                                                GLenum internalformat,
2365                                                GLint x,
2366                                                GLint y,
2367                                                GLsizei width,
2368                                                GLsizei height,
2369                                                GLint border) {
2370   if (isContextLost())
2371     return;
2372   if (!ValidateTexture2DBinding("copyTexImage2D", target))
2373     return;
2374   if (!ValidateCopyTexFormat("copyTexImage2D", internalformat))
2375     return;
2376   if (!ValidateSettableTexFormat("copyTexImage2D", internalformat))
2377     return;
2378   WebGLFramebuffer* read_framebuffer_binding = nullptr;
2379   if (!ValidateReadBufferAndGetInfo("copyTexImage2D", read_framebuffer_binding))
2380     return;
2381   ClearIfComposited();
2382   ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
2383                                    read_framebuffer_binding);
2384   ContextGL()->CopyTexImage2D(target, level, internalformat, x, y, width,
2385                               height, border);
2386 }
2387 
copyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height)2388 void WebGLRenderingContextBase::copyTexSubImage2D(GLenum target,
2389                                                   GLint level,
2390                                                   GLint xoffset,
2391                                                   GLint yoffset,
2392                                                   GLint x,
2393                                                   GLint y,
2394                                                   GLsizei width,
2395                                                   GLsizei height) {
2396   if (isContextLost())
2397     return;
2398   if (!ValidateTexture2DBinding("copyTexSubImage2D", target))
2399     return;
2400   WebGLFramebuffer* read_framebuffer_binding = nullptr;
2401   if (!ValidateReadBufferAndGetInfo("copyTexSubImage2D",
2402                                     read_framebuffer_binding))
2403     return;
2404   ClearIfComposited();
2405   ScopedDrawingBufferBinder binder(GetDrawingBuffer(),
2406                                    read_framebuffer_binding);
2407   ContextGL()->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width,
2408                                  height);
2409 }
2410 
createBuffer()2411 WebGLBuffer* WebGLRenderingContextBase::createBuffer() {
2412   if (isContextLost())
2413     return nullptr;
2414   return MakeGarbageCollected<WebGLBuffer>(this);
2415 }
2416 
createFramebuffer()2417 WebGLFramebuffer* WebGLRenderingContextBase::createFramebuffer() {
2418   if (isContextLost())
2419     return nullptr;
2420   return MakeGarbageCollected<WebGLFramebuffer>(this);
2421 }
2422 
createTexture()2423 WebGLTexture* WebGLRenderingContextBase::createTexture() {
2424   if (isContextLost())
2425     return nullptr;
2426   return MakeGarbageCollected<WebGLTexture>(this);
2427 }
2428 
createProgram()2429 WebGLProgram* WebGLRenderingContextBase::createProgram() {
2430   if (isContextLost())
2431     return nullptr;
2432   return MakeGarbageCollected<WebGLProgram>(this);
2433 }
2434 
createRenderbuffer()2435 WebGLRenderbuffer* WebGLRenderingContextBase::createRenderbuffer() {
2436   if (isContextLost())
2437     return nullptr;
2438   return MakeGarbageCollected<WebGLRenderbuffer>(this);
2439 }
2440 
SetBoundVertexArrayObject(WebGLVertexArrayObjectBase * array_object)2441 void WebGLRenderingContextBase::SetBoundVertexArrayObject(
2442     WebGLVertexArrayObjectBase* array_object) {
2443   if (array_object)
2444     bound_vertex_array_object_ = array_object;
2445   else
2446     bound_vertex_array_object_ = default_vertex_array_object_;
2447 }
2448 
createShader(GLenum type)2449 WebGLShader* WebGLRenderingContextBase::createShader(GLenum type) {
2450   if (isContextLost())
2451     return nullptr;
2452   if (!ValidateShaderType("createShader", type)) {
2453     return nullptr;
2454   }
2455 
2456   return MakeGarbageCollected<WebGLShader>(this, type);
2457 }
2458 
cullFace(GLenum mode)2459 void WebGLRenderingContextBase::cullFace(GLenum mode) {
2460   if (isContextLost())
2461     return;
2462   ContextGL()->CullFace(mode);
2463 }
2464 
DeleteObject(WebGLObject * object)2465 bool WebGLRenderingContextBase::DeleteObject(WebGLObject* object) {
2466   if (isContextLost() || !object)
2467     return false;
2468   if (!object->Validate(ContextGroup(), this)) {
2469     SynthesizeGLError(GL_INVALID_OPERATION, "delete",
2470                       "object does not belong to this context");
2471     return false;
2472   }
2473   if (object->MarkedForDeletion()) {
2474     // This is specified to be a no-op, including skipping all unbinding from
2475     // the context's attachment points that would otherwise happen.
2476     return false;
2477   }
2478   if (object->HasObject()) {
2479     // We need to pass in context here because we want
2480     // things in this context unbound.
2481     object->DeleteObject(ContextGL());
2482   }
2483   return true;
2484 }
2485 
deleteBuffer(WebGLBuffer * buffer)2486 void WebGLRenderingContextBase::deleteBuffer(WebGLBuffer* buffer) {
2487   if (!DeleteObject(buffer))
2488     return;
2489   RemoveBoundBuffer(buffer);
2490 }
2491 
deleteFramebuffer(WebGLFramebuffer * framebuffer)2492 void WebGLRenderingContextBase::deleteFramebuffer(
2493     WebGLFramebuffer* framebuffer) {
2494   // Don't allow the application to delete an opaque framebuffer.
2495   if (framebuffer && framebuffer->Opaque()) {
2496     SynthesizeGLError(GL_INVALID_OPERATION, "deleteFramebuffer",
2497                       "cannot delete an opaque framebuffer");
2498     return;
2499   }
2500   if (!DeleteObject(framebuffer))
2501     return;
2502   if (framebuffer == framebuffer_binding_) {
2503     framebuffer_binding_ = nullptr;
2504     // Have to call drawingBuffer()->bind() here to bind back to internal fbo.
2505     GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
2506   }
2507 }
2508 
deleteProgram(WebGLProgram * program)2509 void WebGLRenderingContextBase::deleteProgram(WebGLProgram* program) {
2510   DeleteObject(program);
2511   // We don't reset m_currentProgram to 0 here because the deletion of the
2512   // current program is delayed.
2513 }
2514 
deleteRenderbuffer(WebGLRenderbuffer * renderbuffer)2515 void WebGLRenderingContextBase::deleteRenderbuffer(
2516     WebGLRenderbuffer* renderbuffer) {
2517   if (!DeleteObject(renderbuffer))
2518     return;
2519   if (renderbuffer == renderbuffer_binding_) {
2520     renderbuffer_binding_ = nullptr;
2521   }
2522   if (framebuffer_binding_)
2523     framebuffer_binding_->RemoveAttachmentFromBoundFramebuffer(GL_FRAMEBUFFER,
2524                                                                renderbuffer);
2525   if (GetFramebufferBinding(GL_READ_FRAMEBUFFER))
2526     GetFramebufferBinding(GL_READ_FRAMEBUFFER)
2527         ->RemoveAttachmentFromBoundFramebuffer(GL_READ_FRAMEBUFFER,
2528                                                renderbuffer);
2529 }
2530 
deleteShader(WebGLShader * shader)2531 void WebGLRenderingContextBase::deleteShader(WebGLShader* shader) {
2532   DeleteObject(shader);
2533 }
2534 
deleteTexture(WebGLTexture * texture)2535 void WebGLRenderingContextBase::deleteTexture(WebGLTexture* texture) {
2536   if (!DeleteObject(texture))
2537     return;
2538 
2539   int max_bound_texture_index = -1;
2540   for (wtf_size_t i = 0; i < one_plus_max_non_default_texture_unit_; ++i) {
2541     if (texture == texture_units_[i].texture2d_binding_) {
2542       texture_units_[i].texture2d_binding_ = nullptr;
2543       max_bound_texture_index = i;
2544     }
2545     if (texture == texture_units_[i].texture_cube_map_binding_) {
2546       texture_units_[i].texture_cube_map_binding_ = nullptr;
2547       max_bound_texture_index = i;
2548     }
2549     if (IsWebGL2()) {
2550       if (texture == texture_units_[i].texture3d_binding_) {
2551         texture_units_[i].texture3d_binding_ = nullptr;
2552         max_bound_texture_index = i;
2553       }
2554       if (texture == texture_units_[i].texture2d_array_binding_) {
2555         texture_units_[i].texture2d_array_binding_ = nullptr;
2556         max_bound_texture_index = i;
2557       }
2558     }
2559   }
2560   if (framebuffer_binding_)
2561     framebuffer_binding_->RemoveAttachmentFromBoundFramebuffer(GL_FRAMEBUFFER,
2562                                                                texture);
2563   if (GetFramebufferBinding(GL_READ_FRAMEBUFFER))
2564     GetFramebufferBinding(GL_READ_FRAMEBUFFER)
2565         ->RemoveAttachmentFromBoundFramebuffer(GL_READ_FRAMEBUFFER, texture);
2566 
2567   // If the deleted was bound to the the current maximum index, trace backwards
2568   // to find the new max texture index.
2569   if (one_plus_max_non_default_texture_unit_ ==
2570       static_cast<wtf_size_t>(max_bound_texture_index + 1)) {
2571     FindNewMaxNonDefaultTextureUnit();
2572   }
2573 }
2574 
depthFunc(GLenum func)2575 void WebGLRenderingContextBase::depthFunc(GLenum func) {
2576   if (isContextLost())
2577     return;
2578   ContextGL()->DepthFunc(func);
2579 }
2580 
depthMask(GLboolean flag)2581 void WebGLRenderingContextBase::depthMask(GLboolean flag) {
2582   if (isContextLost())
2583     return;
2584   depth_mask_ = flag;
2585   ContextGL()->DepthMask(flag);
2586 }
2587 
depthRange(GLfloat z_near,GLfloat z_far)2588 void WebGLRenderingContextBase::depthRange(GLfloat z_near, GLfloat z_far) {
2589   if (isContextLost())
2590     return;
2591   // Check required by WebGL spec section 6.12
2592   if (z_near > z_far) {
2593     SynthesizeGLError(GL_INVALID_OPERATION, "depthRange", "zNear > zFar");
2594     return;
2595   }
2596   ContextGL()->DepthRangef(z_near, z_far);
2597 }
2598 
detachShader(WebGLProgram * program,WebGLShader * shader)2599 void WebGLRenderingContextBase::detachShader(WebGLProgram* program,
2600                                              WebGLShader* shader) {
2601   if (!ValidateWebGLProgramOrShader("detachShader", program) ||
2602       !ValidateWebGLProgramOrShader("detachShader", shader))
2603     return;
2604   if (!program->DetachShader(shader)) {
2605     SynthesizeGLError(GL_INVALID_OPERATION, "detachShader",
2606                       "shader not attached");
2607     return;
2608   }
2609   ContextGL()->DetachShader(ObjectOrZero(program), ObjectOrZero(shader));
2610   shader->OnDetached(ContextGL());
2611 }
2612 
disable(GLenum cap)2613 void WebGLRenderingContextBase::disable(GLenum cap) {
2614   if (isContextLost() || !ValidateCapability("disable", cap))
2615     return;
2616   if (cap == GL_STENCIL_TEST) {
2617     stencil_enabled_ = false;
2618     ApplyStencilTest();
2619     return;
2620   }
2621   if (cap == GL_SCISSOR_TEST)
2622     scissor_enabled_ = false;
2623   ContextGL()->Disable(cap);
2624 }
2625 
disableVertexAttribArray(GLuint index)2626 void WebGLRenderingContextBase::disableVertexAttribArray(GLuint index) {
2627   if (isContextLost())
2628     return;
2629   if (index >= max_vertex_attribs_) {
2630     SynthesizeGLError(GL_INVALID_VALUE, "disableVertexAttribArray",
2631                       "index out of range");
2632     return;
2633   }
2634 
2635   bound_vertex_array_object_->SetAttribEnabled(index, false);
2636   ContextGL()->DisableVertexAttribArray(index);
2637 }
2638 
ValidateRenderingState(const char * function_name)2639 bool WebGLRenderingContextBase::ValidateRenderingState(
2640     const char* function_name) {
2641   // Command buffer will not error if no program is bound.
2642   if (!current_program_) {
2643     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2644                       "no valid shader program in use");
2645     return false;
2646   }
2647 
2648   return true;
2649 }
2650 
ValidateNullableWebGLObject(const char * function_name,WebGLObject * object)2651 bool WebGLRenderingContextBase::ValidateNullableWebGLObject(
2652     const char* function_name,
2653     WebGLObject* object) {
2654   if (isContextLost())
2655     return false;
2656   if (!object) {
2657     // This differs in behavior to ValidateWebGLObject; null objects are allowed
2658     // in these entry points.
2659     return true;
2660   }
2661   return ValidateWebGLObject(function_name, object);
2662 }
2663 
ValidateWebGLObject(const char * function_name,WebGLObject * object)2664 bool WebGLRenderingContextBase::ValidateWebGLObject(const char* function_name,
2665                                                     WebGLObject* object) {
2666   if (isContextLost())
2667     return false;
2668   DCHECK(object);
2669   if (object->MarkedForDeletion()) {
2670     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2671                       "attempt to use a deleted object");
2672     return false;
2673   }
2674   if (!object->Validate(ContextGroup(), this)) {
2675     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2676                       "object does not belong to this context");
2677     return false;
2678   }
2679   return true;
2680 }
2681 
ValidateWebGLProgramOrShader(const char * function_name,WebGLObject * object)2682 bool WebGLRenderingContextBase::ValidateWebGLProgramOrShader(
2683     const char* function_name,
2684     WebGLObject* object) {
2685   if (isContextLost())
2686     return false;
2687   DCHECK(object);
2688   // OpenGL ES 3.0.5 p. 45:
2689   // "Commands that accept shader or program object names will generate the
2690   // error INVALID_VALUE if the provided name is not the name of either a shader
2691   // or program object and INVALID_OPERATION if the provided name identifies an
2692   // object that is not the expected type."
2693   //
2694   // Programs and shaders also have slightly different lifetime rules than other
2695   // objects in the API; they continue to be usable after being marked for
2696   // deletion.
2697   if (!object->HasObject()) {
2698     SynthesizeGLError(GL_INVALID_VALUE, function_name,
2699                       "attempt to use a deleted object");
2700     return false;
2701   }
2702   if (!object->Validate(ContextGroup(), this)) {
2703     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
2704                       "object does not belong to this context");
2705     return false;
2706   }
2707   return true;
2708 }
2709 
drawArraysImpl(GLenum mode,GLint first,GLsizei count)2710 void WebGLRenderingContextBase::drawArraysImpl(GLenum mode,
2711                                                GLint first,
2712                                                GLsizei count) {
2713   if (!ValidateDrawArrays("drawArrays"))
2714     return;
2715 
2716   if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2717     SynthesizeGLError(GL_INVALID_OPERATION, "drawArrays",
2718                       "no buffer is bound to enabled attribute");
2719     return;
2720   }
2721 
2722   ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2723                                                    drawing_buffer_.get());
2724   OnBeforeDrawCall();
2725   ContextGL()->DrawArrays(mode, first, count);
2726 }
2727 
drawElementsImpl(GLenum mode,GLsizei count,GLenum type,int64_t offset)2728 void WebGLRenderingContextBase::drawElementsImpl(GLenum mode,
2729                                                  GLsizei count,
2730                                                  GLenum type,
2731                                                  int64_t offset) {
2732   if (!ValidateDrawElements("drawElements", type, offset))
2733     return;
2734 
2735   if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2736     SynthesizeGLError(GL_INVALID_OPERATION, "drawElements",
2737                       "no buffer is bound to enabled attribute");
2738     return;
2739   }
2740 
2741   ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2742                                                    drawing_buffer_.get());
2743   OnBeforeDrawCall();
2744   ContextGL()->DrawElements(
2745       mode, count, type,
2746       reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
2747 }
2748 
DrawArraysInstancedANGLE(GLenum mode,GLint first,GLsizei count,GLsizei primcount)2749 void WebGLRenderingContextBase::DrawArraysInstancedANGLE(GLenum mode,
2750                                                          GLint first,
2751                                                          GLsizei count,
2752                                                          GLsizei primcount) {
2753   if (!ValidateDrawArrays("drawArraysInstancedANGLE"))
2754     return;
2755 
2756   if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2757     SynthesizeGLError(GL_INVALID_OPERATION, "drawArraysInstancedANGLE",
2758                       "no buffer is bound to enabled attribute");
2759     return;
2760   }
2761 
2762   ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2763                                                    drawing_buffer_.get());
2764   OnBeforeDrawCall();
2765   ContextGL()->DrawArraysInstancedANGLE(mode, first, count, primcount);
2766 }
2767 
DrawElementsInstancedANGLE(GLenum mode,GLsizei count,GLenum type,int64_t offset,GLsizei primcount)2768 void WebGLRenderingContextBase::DrawElementsInstancedANGLE(GLenum mode,
2769                                                            GLsizei count,
2770                                                            GLenum type,
2771                                                            int64_t offset,
2772                                                            GLsizei primcount) {
2773   if (!ValidateDrawElements("drawElementsInstancedANGLE", type, offset))
2774     return;
2775 
2776   if (!bound_vertex_array_object_->IsAllEnabledAttribBufferBound()) {
2777     SynthesizeGLError(GL_INVALID_OPERATION, "drawElementsInstancedANGLE",
2778                       "no buffer is bound to enabled attribute");
2779     return;
2780   }
2781 
2782   ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
2783                                                    drawing_buffer_.get());
2784   OnBeforeDrawCall();
2785   ContextGL()->DrawElementsInstancedANGLE(
2786       mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset)),
2787       primcount);
2788 }
2789 
enable(GLenum cap)2790 void WebGLRenderingContextBase::enable(GLenum cap) {
2791   if (isContextLost() || !ValidateCapability("enable", cap))
2792     return;
2793   if (cap == GL_STENCIL_TEST) {
2794     stencil_enabled_ = true;
2795     ApplyStencilTest();
2796     return;
2797   }
2798   if (cap == GL_SCISSOR_TEST)
2799     scissor_enabled_ = true;
2800   ContextGL()->Enable(cap);
2801 }
2802 
enableVertexAttribArray(GLuint index)2803 void WebGLRenderingContextBase::enableVertexAttribArray(GLuint index) {
2804   if (isContextLost())
2805     return;
2806   if (index >= max_vertex_attribs_) {
2807     SynthesizeGLError(GL_INVALID_VALUE, "enableVertexAttribArray",
2808                       "index out of range");
2809     return;
2810   }
2811 
2812   bound_vertex_array_object_->SetAttribEnabled(index, true);
2813   ContextGL()->EnableVertexAttribArray(index);
2814 }
2815 
finish()2816 void WebGLRenderingContextBase::finish() {
2817   if (isContextLost())
2818     return;
2819   ContextGL()->Flush();  // Intentionally a flush, not a finish.
2820 }
2821 
flush()2822 void WebGLRenderingContextBase::flush() {
2823   if (isContextLost())
2824     return;
2825   ContextGL()->Flush();
2826 }
2827 
framebufferRenderbuffer(GLenum target,GLenum attachment,GLenum renderbuffertarget,WebGLRenderbuffer * buffer)2828 void WebGLRenderingContextBase::framebufferRenderbuffer(
2829     GLenum target,
2830     GLenum attachment,
2831     GLenum renderbuffertarget,
2832     WebGLRenderbuffer* buffer) {
2833   if (isContextLost() || !ValidateFramebufferFuncParameters(
2834                              "framebufferRenderbuffer", target, attachment))
2835     return;
2836   if (renderbuffertarget != GL_RENDERBUFFER) {
2837     SynthesizeGLError(GL_INVALID_ENUM, "framebufferRenderbuffer",
2838                       "invalid target");
2839     return;
2840   }
2841   if (!ValidateNullableWebGLObject("framebufferRenderbuffer", buffer))
2842     return;
2843   if (buffer && (!buffer->HasEverBeenBound())) {
2844     SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer",
2845                       "renderbuffer has never been bound");
2846     return;
2847   }
2848   // Don't allow the default framebuffer to be mutated; all current
2849   // implementations use an FBO internally in place of the default
2850   // FBO.
2851   WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
2852   if (!framebuffer_binding || !framebuffer_binding->Object()) {
2853     SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer",
2854                       "no framebuffer bound");
2855     return;
2856   }
2857   // Don't allow modifications to opaque framebuffer attachements.
2858   if (framebuffer_binding && framebuffer_binding->Opaque()) {
2859     SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer",
2860                       "opaque framebuffer bound");
2861     return;
2862   }
2863   framebuffer_binding->SetAttachmentForBoundFramebuffer(target, attachment,
2864                                                         buffer);
2865   ApplyStencilTest();
2866 }
2867 
framebufferTexture2D(GLenum target,GLenum attachment,GLenum textarget,WebGLTexture * texture,GLint level)2868 void WebGLRenderingContextBase::framebufferTexture2D(GLenum target,
2869                                                      GLenum attachment,
2870                                                      GLenum textarget,
2871                                                      WebGLTexture* texture,
2872                                                      GLint level) {
2873   if (isContextLost() || !ValidateFramebufferFuncParameters(
2874                              "framebufferTexture2D", target, attachment))
2875     return;
2876   if (!ValidateNullableWebGLObject("framebufferTexture2D", texture))
2877     return;
2878   // TODO(crbug.com/919711): validate texture's target against textarget.
2879 
2880   // Don't allow the default framebuffer to be mutated; all current
2881   // implementations use an FBO internally in place of the default
2882   // FBO.
2883   WebGLFramebuffer* framebuffer_binding = GetFramebufferBinding(target);
2884   if (!framebuffer_binding || !framebuffer_binding->Object()) {
2885     SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D",
2886                       "no framebuffer bound");
2887     return;
2888   }
2889   // Don't allow modifications to opaque framebuffer attachements.
2890   if (framebuffer_binding && framebuffer_binding->Opaque()) {
2891     SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D",
2892                       "opaque framebuffer bound");
2893     return;
2894   }
2895   framebuffer_binding->SetAttachmentForBoundFramebuffer(
2896       target, attachment, textarget, texture, level, 0, 0);
2897   ApplyStencilTest();
2898 }
2899 
frontFace(GLenum mode)2900 void WebGLRenderingContextBase::frontFace(GLenum mode) {
2901   if (isContextLost())
2902     return;
2903   ContextGL()->FrontFace(mode);
2904 }
2905 
generateMipmap(GLenum target)2906 void WebGLRenderingContextBase::generateMipmap(GLenum target) {
2907   if (isContextLost())
2908     return;
2909   if (!ValidateTextureBinding("generateMipmap", target))
2910     return;
2911   ContextGL()->GenerateMipmap(target);
2912 }
2913 
getActiveAttrib(WebGLProgram * program,GLuint index)2914 WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib(
2915     WebGLProgram* program,
2916     GLuint index) {
2917   if (!ValidateWebGLProgramOrShader("getActiveAttrib", program))
2918     return nullptr;
2919   GLuint program_id = ObjectNonZero(program);
2920   GLint max_name_length = -1;
2921   ContextGL()->GetProgramiv(program_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
2922                             &max_name_length);
2923   if (max_name_length < 0)
2924     return nullptr;
2925   if (max_name_length == 0) {
2926     SynthesizeGLError(GL_INVALID_VALUE, "getActiveAttrib",
2927                       "no active attributes exist");
2928     return nullptr;
2929   }
2930   LChar* name_ptr;
2931   scoped_refptr<StringImpl> name_impl =
2932       StringImpl::CreateUninitialized(max_name_length, name_ptr);
2933   GLsizei length = 0;
2934   GLint size = -1;
2935   GLenum type = 0;
2936   ContextGL()->GetActiveAttrib(program_id, index, max_name_length, &length,
2937                                &size, &type,
2938                                reinterpret_cast<GLchar*>(name_ptr));
2939   if (size < 0)
2940     return nullptr;
2941   return MakeGarbageCollected<WebGLActiveInfo>(name_impl->Substring(0, length),
2942                                                type, size);
2943 }
2944 
getActiveUniform(WebGLProgram * program,GLuint index)2945 WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform(
2946     WebGLProgram* program,
2947     GLuint index) {
2948   if (!ValidateWebGLProgramOrShader("getActiveUniform", program))
2949     return nullptr;
2950   GLuint program_id = ObjectNonZero(program);
2951   GLint max_name_length = -1;
2952   ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH,
2953                             &max_name_length);
2954   if (max_name_length < 0)
2955     return nullptr;
2956   if (max_name_length == 0) {
2957     SynthesizeGLError(GL_INVALID_VALUE, "getActiveUniform",
2958                       "no active uniforms exist");
2959     return nullptr;
2960   }
2961   LChar* name_ptr;
2962   scoped_refptr<StringImpl> name_impl =
2963       StringImpl::CreateUninitialized(max_name_length, name_ptr);
2964   GLsizei length = 0;
2965   GLint size = -1;
2966   GLenum type = 0;
2967   ContextGL()->GetActiveUniform(program_id, index, max_name_length, &length,
2968                                 &size, &type,
2969                                 reinterpret_cast<GLchar*>(name_ptr));
2970   if (size < 0)
2971     return nullptr;
2972   return MakeGarbageCollected<WebGLActiveInfo>(name_impl->Substring(0, length),
2973                                                type, size);
2974 }
2975 
2976 base::Optional<HeapVector<Member<WebGLShader>>>
getAttachedShaders(WebGLProgram * program)2977 WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program) {
2978   if (!ValidateWebGLProgramOrShader("getAttachedShaders", program))
2979     return base::nullopt;
2980 
2981   HeapVector<Member<WebGLShader>> shader_objects;
2982   for (GLenum shaderType : {GL_VERTEX_SHADER, GL_FRAGMENT_SHADER}) {
2983     WebGLShader* shader = program->GetAttachedShader(shaderType);
2984     if (shader)
2985       shader_objects.push_back(shader);
2986   }
2987   return shader_objects;
2988 }
2989 
getAttribLocation(WebGLProgram * program,const String & name)2990 GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program,
2991                                                    const String& name) {
2992   if (!ValidateWebGLProgramOrShader("getAttribLocation", program))
2993     return -1;
2994   if (!ValidateLocationLength("getAttribLocation", name))
2995     return -1;
2996   if (!ValidateString("getAttribLocation", name))
2997     return -1;
2998   if (IsPrefixReserved(name))
2999     return -1;
3000   if (!program->LinkStatus(this)) {
3001     SynthesizeGLError(GL_INVALID_OPERATION, "getAttribLocation",
3002                       "program not linked");
3003     return 0;
3004   }
3005   return ContextGL()->GetAttribLocation(ObjectOrZero(program),
3006                                         name.Utf8().c_str());
3007 }
3008 
ValidateBufferTarget(const char * function_name,GLenum target)3009 bool WebGLRenderingContextBase::ValidateBufferTarget(const char* function_name,
3010                                                      GLenum target) {
3011   switch (target) {
3012     case GL_ARRAY_BUFFER:
3013     case GL_ELEMENT_ARRAY_BUFFER:
3014       return true;
3015     default:
3016       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
3017       return false;
3018   }
3019 }
3020 
getBufferParameter(ScriptState * script_state,GLenum target,GLenum pname)3021 ScriptValue WebGLRenderingContextBase::getBufferParameter(
3022     ScriptState* script_state,
3023     GLenum target,
3024     GLenum pname) {
3025   if (isContextLost() || !ValidateBufferTarget("getBufferParameter", target))
3026     return ScriptValue::CreateNull(script_state->GetIsolate());
3027 
3028   switch (pname) {
3029     case GL_BUFFER_USAGE: {
3030       GLint value = 0;
3031       ContextGL()->GetBufferParameteriv(target, pname, &value);
3032       return WebGLAny(script_state, static_cast<unsigned>(value));
3033     }
3034     case GL_BUFFER_SIZE: {
3035       GLint value = 0;
3036       ContextGL()->GetBufferParameteriv(target, pname, &value);
3037       if (!IsWebGL2())
3038         return WebGLAny(script_state, value);
3039       return WebGLAny(script_state, static_cast<GLint64>(value));
3040     }
3041     default:
3042       SynthesizeGLError(GL_INVALID_ENUM, "getBufferParameter",
3043                         "invalid parameter name");
3044       return ScriptValue::CreateNull(script_state->GetIsolate());
3045   }
3046 }
3047 
getContextAttributes() const3048 WebGLContextAttributes* WebGLRenderingContextBase::getContextAttributes()
3049     const {
3050   if (isContextLost())
3051     return nullptr;
3052 
3053   WebGLContextAttributes* result =
3054       ToWebGLContextAttributes(CreationAttributes());
3055 
3056   // Some requested attributes may not be honored, so we need to query the
3057   // underlying context/drawing buffer and adjust accordingly.
3058   if (CreationAttributes().depth && !GetDrawingBuffer()->HasDepthBuffer())
3059     result->setDepth(false);
3060   if (CreationAttributes().stencil && !GetDrawingBuffer()->HasStencilBuffer())
3061     result->setStencil(false);
3062   result->setAntialias(GetDrawingBuffer()->Multisample());
3063   result->setXrCompatible(xr_compatible_);
3064   result->setDesynchronized(Host()->LowLatencyEnabled());
3065   return result;
3066 }
3067 
getError()3068 GLenum WebGLRenderingContextBase::getError() {
3069   if (!lost_context_errors_.IsEmpty()) {
3070     GLenum error = lost_context_errors_.front();
3071     lost_context_errors_.EraseAt(0);
3072     return error;
3073   }
3074 
3075   if (isContextLost())
3076     return GL_NO_ERROR;
3077 
3078   if (!synthetic_errors_.IsEmpty()) {
3079     GLenum error = synthetic_errors_.front();
3080     synthetic_errors_.EraseAt(0);
3081     return error;
3082   }
3083 
3084   return ContextGL()->GetError();
3085 }
3086 
Prefixes() const3087 const char* const* WebGLRenderingContextBase::ExtensionTracker::Prefixes()
3088     const {
3089   static const char* const kUnprefixed[] = {
3090       "",
3091       nullptr,
3092   };
3093   return prefixes_ ? prefixes_ : kUnprefixed;
3094 }
3095 
MatchesNameWithPrefixes(const String & name) const3096 bool WebGLRenderingContextBase::ExtensionTracker::MatchesNameWithPrefixes(
3097     const String& name) const {
3098   const char* const* prefix_set = Prefixes();
3099   for (; *prefix_set; ++prefix_set) {
3100     String prefixed_name = String(*prefix_set) + ExtensionName();
3101     if (DeprecatedEqualIgnoringCase(prefixed_name, name)) {
3102       return true;
3103     }
3104   }
3105   return false;
3106 }
3107 
ExtensionSupportedAndAllowed(const ExtensionTracker * tracker)3108 bool WebGLRenderingContextBase::ExtensionSupportedAndAllowed(
3109     const ExtensionTracker* tracker) {
3110   if (tracker->Draft() &&
3111       !RuntimeEnabledFeatures::WebGLDraftExtensionsEnabled())
3112     return false;
3113   if (!tracker->Supported(this))
3114     return false;
3115   if (disabled_extensions_.Contains(String(tracker->ExtensionName())))
3116     return false;
3117   return true;
3118 }
3119 
getExtension(ScriptState * script_state,const String & name)3120 ScriptValue WebGLRenderingContextBase::getExtension(ScriptState* script_state,
3121                                                     const String& name) {
3122   WebGLExtension* extension = nullptr;
3123 
3124   if (name == WebGLDebugRendererInfo::ExtensionName()) {
3125     ExecutionContext* context = ExecutionContext::From(script_state);
3126     UseCounter::Count(context, WebFeature::kWebGLDebugRendererInfo);
3127     Dactyloscoper::Record(context, WebFeature::kWebGLDebugRendererInfo);
3128   }
3129 
3130   if (!isContextLost()) {
3131     for (ExtensionTracker* tracker : extensions_) {
3132       if (tracker->MatchesNameWithPrefixes(name)) {
3133         if (ExtensionSupportedAndAllowed(tracker)) {
3134           extension = tracker->GetExtension(this);
3135           if (extension) {
3136             if (!extension_enabled_[extension->GetName()]) {
3137               extension_enabled_[extension->GetName()] = true;
3138             }
3139           }
3140         }
3141         break;
3142       }
3143     }
3144   }
3145 
3146   v8::Local<v8::Value> wrapped_extension =
3147       ToV8(extension, script_state->GetContext()->Global(),
3148            script_state->GetIsolate());
3149 
3150   return ScriptValue(script_state->GetIsolate(), wrapped_extension);
3151 }
3152 
getFramebufferAttachmentParameter(ScriptState * script_state,GLenum target,GLenum attachment,GLenum pname)3153 ScriptValue WebGLRenderingContextBase::getFramebufferAttachmentParameter(
3154     ScriptState* script_state,
3155     GLenum target,
3156     GLenum attachment,
3157     GLenum pname) {
3158   if (isContextLost() ||
3159       !ValidateFramebufferFuncParameters("getFramebufferAttachmentParameter",
3160                                          target, attachment))
3161     return ScriptValue::CreateNull(script_state->GetIsolate());
3162 
3163   if (!framebuffer_binding_ || !framebuffer_binding_->Object()) {
3164     SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
3165                       "no framebuffer bound");
3166     return ScriptValue::CreateNull(script_state->GetIsolate());
3167   }
3168 
3169   if (framebuffer_binding_ && framebuffer_binding_->Opaque()) {
3170     SynthesizeGLError(GL_INVALID_OPERATION, "getFramebufferAttachmentParameter",
3171                       "cannot query parameters of an opaque framebuffer");
3172     return ScriptValue::CreateNull(script_state->GetIsolate());
3173   }
3174 
3175   WebGLSharedObject* attachment_object =
3176       framebuffer_binding_->GetAttachmentObject(attachment);
3177   if (!attachment_object) {
3178     if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
3179       return WebGLAny(script_state, GL_NONE);
3180     // OpenGL ES 2.0 specifies INVALID_ENUM in this case, while desktop GL
3181     // specifies INVALID_OPERATION.
3182     SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3183                       "invalid parameter name");
3184     return ScriptValue::CreateNull(script_state->GetIsolate());
3185   }
3186 
3187   DCHECK(attachment_object->IsTexture() || attachment_object->IsRenderbuffer());
3188   if (attachment_object->IsTexture()) {
3189     switch (pname) {
3190       case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3191         return WebGLAny(script_state, GL_TEXTURE);
3192       case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3193         return WebGLAny(script_state, attachment_object);
3194       case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
3195       case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
3196         GLint value = 0;
3197         ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
3198                                                          pname, &value);
3199         return WebGLAny(script_state, value);
3200       }
3201       case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
3202         if (ExtensionEnabled(kEXTsRGBName)) {
3203           GLint value = 0;
3204           ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
3205                                                            pname, &value);
3206           return WebGLAny(script_state, static_cast<unsigned>(value));
3207         }
3208         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3209                           "invalid parameter name for renderbuffer attachment");
3210         return ScriptValue::CreateNull(script_state->GetIsolate());
3211       default:
3212         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3213                           "invalid parameter name for texture attachment");
3214         return ScriptValue::CreateNull(script_state->GetIsolate());
3215     }
3216   } else {
3217     switch (pname) {
3218       case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
3219         return WebGLAny(script_state, GL_RENDERBUFFER);
3220       case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
3221         return WebGLAny(script_state, attachment_object);
3222       case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
3223         if (ExtensionEnabled(kEXTsRGBName)) {
3224           GLint value = 0;
3225           ContextGL()->GetFramebufferAttachmentParameteriv(target, attachment,
3226                                                            pname, &value);
3227           return WebGLAny(script_state, value);
3228         }
3229         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3230                           "invalid parameter name for renderbuffer attachment");
3231         return ScriptValue::CreateNull(script_state->GetIsolate());
3232       default:
3233         SynthesizeGLError(GL_INVALID_ENUM, "getFramebufferAttachmentParameter",
3234                           "invalid parameter name for renderbuffer attachment");
3235         return ScriptValue::CreateNull(script_state->GetIsolate());
3236     }
3237   }
3238 }
3239 
3240 namespace {
3241 
3242 // WebGL parameters which can be used to identify users.
3243 // These parameters should each be uniquely defined,
3244 // see third_party/khronos/GLES2/gl2.h for their definitions.
3245 static const GLenum kIdentifiableGLParams[] = {
3246     // getParameter()
3247     GL_ALIASED_LINE_WIDTH_RANGE,          // GetWebGLFloatArrayParameter
3248     GL_ALIASED_POINT_SIZE_RANGE,          // GetWebGLFloatArrayParameter
3249     GL_ALPHA_BITS,                        // GetIntParameter
3250     GL_BLUE_BITS,                         // GetIntParameter
3251     GL_DEPTH_BITS,                        // GetIntParameter
3252     GL_GREEN_BITS,                        // GetIntParameter
3253     GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,  // GetIntParameter
3254     GL_MAX_CUBE_MAP_TEXTURE_SIZE,         // GetIntParameter
3255     GL_MAX_FRAGMENT_UNIFORM_VECTORS,      // GetIntParameter
3256     GL_MAX_RENDERBUFFER_SIZE,             // GetIntParameter
3257     GL_MAX_TEXTURE_IMAGE_UNITS,           // GetIntParameter
3258     GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT,    // GetFloatParameter
3259     GL_MAX_TEXTURE_SIZE,                  // GetIntParameter
3260     GL_MAX_VARYING_VECTORS,               // GetIntParameter
3261     GL_MAX_VERTEX_ATTRIBS,                // GetIntParameter
3262     GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,    // GetIntParameter
3263     GL_MAX_VERTEX_UNIFORM_VECTORS,        // GetIntParameter
3264     GL_MAX_VIEWPORT_DIMS,                 // GetWebGLIntArrayParameter
3265     GL_RED_BITS,                          // GetIntParameter
3266     GL_SHADING_LANGUAGE_VERSION,
3267     GL_STENCIL_BITS,  // GetIntParameter
3268     GL_VERSION,
3269     WebGLDebugRendererInfo::kUnmaskedRendererWebgl,
3270     WebGLDebugRendererInfo::kUnmaskedVendorWebgl,
3271 
3272     // getRenderBufferParameter()
3273     GL_RENDERBUFFER_GREEN_SIZE,
3274     GL_RENDERBUFFER_BLUE_SIZE,
3275     GL_RENDERBUFFER_RED_SIZE,
3276     GL_RENDERBUFFER_ALPHA_SIZE,
3277     GL_RENDERBUFFER_DEPTH_SIZE,
3278     GL_RENDERBUFFER_STENCIL_SIZE,
3279     GL_RENDERBUFFER_SAMPLES,
3280 };
3281 
ShouldMeasureGLParam(GLenum pname)3282 bool ShouldMeasureGLParam(GLenum pname) {
3283   return IdentifiabilityStudySettings::Get()->ShouldSample(
3284              blink::IdentifiableSurface::Type::kWebGLParameter) &&
3285          std::find(std::begin(kIdentifiableGLParams),
3286                    std::end(kIdentifiableGLParams),
3287                    pname) != std::end(kIdentifiableGLParams);
3288 }
3289 
3290 }  // namespace
3291 
RecordIdentifiableGLParameterDigest(GLenum pname,IdentifiableToken value)3292 void WebGLRenderingContextBase::RecordIdentifiableGLParameterDigest(
3293     GLenum pname,
3294     IdentifiableToken value) {
3295   DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
3296       blink::IdentifiableSurface::Type::kWebGLParameter));
3297   const auto ukm_params = GetUkmParameters();
3298   blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
3299       .Set(blink::IdentifiableSurface::FromTypeAndToken(
3300                blink::IdentifiableSurface::Type::kWebGLParameter, pname),
3301            value)
3302       .Record(ukm_params.ukm_recorder);
3303 }
3304 
RecordShaderPrecisionFormatForStudy(GLenum shader_type,GLenum precision_type,WebGLShaderPrecisionFormat * format)3305 void WebGLRenderingContextBase::RecordShaderPrecisionFormatForStudy(
3306     GLenum shader_type,
3307     GLenum precision_type,
3308     WebGLShaderPrecisionFormat* format) {
3309   DCHECK(IdentifiabilityStudySettings::Get()->IsTypeAllowed(
3310       blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat));
3311 
3312   const auto& ukm_params = GetUkmParameters();
3313   IdentifiableTokenBuilder builder;
3314   auto surface_token =
3315       builder.AddValue(shader_type).AddValue(precision_type).GetToken();
3316   auto sample_token = builder.AddValue(format->rangeMin())
3317                           .AddValue(format->rangeMax())
3318                           .AddValue(format->precision())
3319                           .GetToken();
3320 
3321   blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
3322       .Set(blink::IdentifiableSurface::FromTypeAndToken(
3323                blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat,
3324                surface_token),
3325            sample_token)
3326       .Record(ukm_params.ukm_recorder);
3327 }
3328 
getParameter(ScriptState * script_state,GLenum pname)3329 ScriptValue WebGLRenderingContextBase::getParameter(ScriptState* script_state,
3330                                                     GLenum pname) {
3331   if (isContextLost())
3332     return ScriptValue::CreateNull(script_state->GetIsolate());
3333   const int kIntZero = 0;
3334   switch (pname) {
3335     case GL_ACTIVE_TEXTURE:
3336       return GetUnsignedIntParameter(script_state, pname);
3337     case GL_ALIASED_LINE_WIDTH_RANGE:
3338       return GetWebGLFloatArrayParameter(script_state, pname);
3339     case GL_ALIASED_POINT_SIZE_RANGE:
3340       return GetWebGLFloatArrayParameter(script_state, pname);
3341     case GL_ALPHA_BITS:
3342       if (drawing_buffer_->RequiresAlphaChannelToBePreserved())
3343         return WebGLAny(script_state, 0);
3344       return GetIntParameter(script_state, pname);
3345     case GL_ARRAY_BUFFER_BINDING:
3346       return WebGLAny(script_state, bound_array_buffer_.Get());
3347     case GL_BLEND:
3348       return GetBooleanParameter(script_state, pname);
3349     case GL_BLEND_COLOR:
3350       return GetWebGLFloatArrayParameter(script_state, pname);
3351     case GL_BLEND_DST_ALPHA:
3352       return GetUnsignedIntParameter(script_state, pname);
3353     case GL_BLEND_DST_RGB:
3354       return GetUnsignedIntParameter(script_state, pname);
3355     case GL_BLEND_EQUATION_ALPHA:
3356       return GetUnsignedIntParameter(script_state, pname);
3357     case GL_BLEND_EQUATION_RGB:
3358       return GetUnsignedIntParameter(script_state, pname);
3359     case GL_BLEND_SRC_ALPHA:
3360       return GetUnsignedIntParameter(script_state, pname);
3361     case GL_BLEND_SRC_RGB:
3362       return GetUnsignedIntParameter(script_state, pname);
3363     case GL_BLUE_BITS:
3364       return GetIntParameter(script_state, pname);
3365     case GL_COLOR_CLEAR_VALUE:
3366       return GetWebGLFloatArrayParameter(script_state, pname);
3367     case GL_COLOR_WRITEMASK:
3368       return GetBooleanArrayParameter(script_state, pname);
3369     case GL_COMPRESSED_TEXTURE_FORMATS:
3370       return WebGLAny(script_state, DOMUint32Array::Create(
3371                                         compressed_texture_formats_.data(),
3372                                         compressed_texture_formats_.size()));
3373     case GL_CULL_FACE:
3374       return GetBooleanParameter(script_state, pname);
3375     case GL_CULL_FACE_MODE:
3376       return GetUnsignedIntParameter(script_state, pname);
3377     case GL_CURRENT_PROGRAM:
3378       return WebGLAny(script_state, current_program_.Get());
3379     case GL_DEPTH_BITS:
3380       if (!framebuffer_binding_ && !CreationAttributes().depth)
3381         return WebGLAny(script_state, kIntZero);
3382       return GetIntParameter(script_state, pname);
3383     case GL_DEPTH_CLEAR_VALUE:
3384       return GetFloatParameter(script_state, pname);
3385     case GL_DEPTH_FUNC:
3386       return GetUnsignedIntParameter(script_state, pname);
3387     case GL_DEPTH_RANGE:
3388       return GetWebGLFloatArrayParameter(script_state, pname);
3389     case GL_DEPTH_TEST:
3390       return GetBooleanParameter(script_state, pname);
3391     case GL_DEPTH_WRITEMASK:
3392       return GetBooleanParameter(script_state, pname);
3393     case GL_DITHER:
3394       return GetBooleanParameter(script_state, pname);
3395     case GL_ELEMENT_ARRAY_BUFFER_BINDING:
3396       return WebGLAny(script_state,
3397                       bound_vertex_array_object_->BoundElementArrayBuffer());
3398     case GL_FRAMEBUFFER_BINDING:
3399       return WebGLAny(script_state, framebuffer_binding_.Get());
3400     case GL_FRONT_FACE:
3401       return GetUnsignedIntParameter(script_state, pname);
3402     case GL_GENERATE_MIPMAP_HINT:
3403       return GetUnsignedIntParameter(script_state, pname);
3404     case GL_GREEN_BITS:
3405       return GetIntParameter(script_state, pname);
3406     case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
3407       return GetIntParameter(script_state, pname);
3408     case GL_IMPLEMENTATION_COLOR_READ_TYPE:
3409       return GetIntParameter(script_state, pname);
3410     case GL_LINE_WIDTH:
3411       return GetFloatParameter(script_state, pname);
3412     case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
3413       return GetIntParameter(script_state, pname);
3414     case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
3415       return GetIntParameter(script_state, pname);
3416     case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
3417       return GetIntParameter(script_state, pname);
3418     case GL_MAX_RENDERBUFFER_SIZE:
3419       return GetIntParameter(script_state, pname);
3420     case GL_MAX_TEXTURE_IMAGE_UNITS:
3421       return GetIntParameter(script_state, pname);
3422     case GL_MAX_TEXTURE_SIZE:
3423       return GetIntParameter(script_state, pname);
3424     case GL_MAX_VARYING_VECTORS:
3425       return GetIntParameter(script_state, pname);
3426     case GL_MAX_VERTEX_ATTRIBS:
3427       return GetIntParameter(script_state, pname);
3428     case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
3429       return GetIntParameter(script_state, pname);
3430     case GL_MAX_VERTEX_UNIFORM_VECTORS:
3431       return GetIntParameter(script_state, pname);
3432     case GL_MAX_VIEWPORT_DIMS:
3433       return GetWebGLIntArrayParameter(script_state, pname);
3434     case GL_NUM_SHADER_BINARY_FORMATS:
3435       // FIXME: should we always return 0 for this?
3436       return GetIntParameter(script_state, pname);
3437     case GL_PACK_ALIGNMENT:
3438       return GetIntParameter(script_state, pname);
3439     case GL_POLYGON_OFFSET_FACTOR:
3440       return GetFloatParameter(script_state, pname);
3441     case GL_POLYGON_OFFSET_FILL:
3442       return GetBooleanParameter(script_state, pname);
3443     case GL_POLYGON_OFFSET_UNITS:
3444       return GetFloatParameter(script_state, pname);
3445     case GL_RED_BITS:
3446       return GetIntParameter(script_state, pname);
3447     case GL_RENDERBUFFER_BINDING:
3448       return WebGLAny(script_state, renderbuffer_binding_.Get());
3449     case GL_RENDERER:
3450       return WebGLAny(script_state, String("WebKit WebGL"));
3451     case GL_SAMPLE_ALPHA_TO_COVERAGE:
3452       return GetBooleanParameter(script_state, pname);
3453     case GL_SAMPLE_BUFFERS:
3454       return GetIntParameter(script_state, pname);
3455     case GL_SAMPLE_COVERAGE:
3456       return GetBooleanParameter(script_state, pname);
3457     case GL_SAMPLE_COVERAGE_INVERT:
3458       return GetBooleanParameter(script_state, pname);
3459     case GL_SAMPLE_COVERAGE_VALUE:
3460       return GetFloatParameter(script_state, pname);
3461     case GL_SAMPLES:
3462       return GetIntParameter(script_state, pname);
3463     case GL_SCISSOR_BOX:
3464       return GetWebGLIntArrayParameter(script_state, pname);
3465     case GL_SCISSOR_TEST:
3466       return GetBooleanParameter(script_state, pname);
3467     case GL_SHADING_LANGUAGE_VERSION:
3468       if (IdentifiabilityStudySettings::Get()->ShouldSample(
3469               blink::IdentifiableSurface::Type::kWebGLParameter)) {
3470         RecordIdentifiableGLParameterDigest(
3471             pname, IdentifiabilityBenignStringToken(String(
3472                        ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION))));
3473       }
3474       return WebGLAny(
3475           script_state,
3476           "WebGL GLSL ES 1.0 (" +
3477               String(ContextGL()->GetString(GL_SHADING_LANGUAGE_VERSION)) +
3478               ")");
3479     case GL_STENCIL_BACK_FAIL:
3480       return GetUnsignedIntParameter(script_state, pname);
3481     case GL_STENCIL_BACK_FUNC:
3482       return GetUnsignedIntParameter(script_state, pname);
3483     case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
3484       return GetUnsignedIntParameter(script_state, pname);
3485     case GL_STENCIL_BACK_PASS_DEPTH_PASS:
3486       return GetUnsignedIntParameter(script_state, pname);
3487     case GL_STENCIL_BACK_REF:
3488       return GetIntParameter(script_state, pname);
3489     case GL_STENCIL_BACK_VALUE_MASK:
3490       return GetUnsignedIntParameter(script_state, pname);
3491     case GL_STENCIL_BACK_WRITEMASK:
3492       return GetUnsignedIntParameter(script_state, pname);
3493     case GL_STENCIL_BITS:
3494       if (!framebuffer_binding_ && !CreationAttributes().stencil)
3495         return WebGLAny(script_state, kIntZero);
3496       return GetIntParameter(script_state, pname);
3497     case GL_STENCIL_CLEAR_VALUE:
3498       return GetIntParameter(script_state, pname);
3499     case GL_STENCIL_FAIL:
3500       return GetUnsignedIntParameter(script_state, pname);
3501     case GL_STENCIL_FUNC:
3502       return GetUnsignedIntParameter(script_state, pname);
3503     case GL_STENCIL_PASS_DEPTH_FAIL:
3504       return GetUnsignedIntParameter(script_state, pname);
3505     case GL_STENCIL_PASS_DEPTH_PASS:
3506       return GetUnsignedIntParameter(script_state, pname);
3507     case GL_STENCIL_REF:
3508       return GetIntParameter(script_state, pname);
3509     case GL_STENCIL_TEST:
3510       return WebGLAny(script_state, stencil_enabled_);
3511     case GL_STENCIL_VALUE_MASK:
3512       return GetUnsignedIntParameter(script_state, pname);
3513     case GL_STENCIL_WRITEMASK:
3514       return GetUnsignedIntParameter(script_state, pname);
3515     case GL_SUBPIXEL_BITS:
3516       return GetIntParameter(script_state, pname);
3517     case GL_TEXTURE_BINDING_2D:
3518       return WebGLAny(
3519           script_state,
3520           texture_units_[active_texture_unit_].texture2d_binding_.Get());
3521     case GL_TEXTURE_BINDING_CUBE_MAP:
3522       return WebGLAny(
3523           script_state,
3524           texture_units_[active_texture_unit_].texture_cube_map_binding_.Get());
3525     case GL_UNPACK_ALIGNMENT:
3526       return GetIntParameter(script_state, pname);
3527     case GC3D_UNPACK_FLIP_Y_WEBGL:
3528       return WebGLAny(script_state, unpack_flip_y_);
3529     case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
3530       return WebGLAny(script_state, unpack_premultiply_alpha_);
3531     case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
3532       return WebGLAny(script_state, unpack_colorspace_conversion_);
3533     case GL_VENDOR:
3534       return WebGLAny(script_state, String("WebKit"));
3535     case GL_VERSION:
3536       if (IdentifiabilityStudySettings::Get()->ShouldSample(
3537               blink::IdentifiableSurface::Type::kWebGLParameter)) {
3538         RecordIdentifiableGLParameterDigest(
3539             pname, IdentifiabilityBenignStringToken(
3540                        String(ContextGL()->GetString(GL_VERSION))));
3541       }
3542       return WebGLAny(
3543           script_state,
3544           "WebGL 1.0 (" + String(ContextGL()->GetString(GL_VERSION)) + ")");
3545     case GL_VIEWPORT:
3546       return GetWebGLIntArrayParameter(script_state, pname);
3547     case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:  // OES_standard_derivatives
3548       if (ExtensionEnabled(kOESStandardDerivativesName) || IsWebGL2())
3549         return GetUnsignedIntParameter(script_state,
3550                                        GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
3551       SynthesizeGLError(
3552           GL_INVALID_ENUM, "getParameter",
3553           "invalid parameter name, OES_standard_derivatives not enabled");
3554       return ScriptValue::CreateNull(script_state->GetIsolate());
3555     case WebGLDebugRendererInfo::kUnmaskedRendererWebgl:
3556       if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
3557         if (IdentifiabilityStudySettings::Get()->ShouldSample(
3558                 blink::IdentifiableSurface::Type::kWebGLParameter)) {
3559           RecordIdentifiableGLParameterDigest(
3560               pname, IdentifiabilityBenignStringToken(
3561                          String(ContextGL()->GetString(GL_RENDERER))));
3562         }
3563         return WebGLAny(script_state,
3564                         String(ContextGL()->GetString(GL_RENDERER)));
3565       }
3566       SynthesizeGLError(
3567           GL_INVALID_ENUM, "getParameter",
3568           "invalid parameter name, WEBGL_debug_renderer_info not enabled");
3569       return ScriptValue::CreateNull(script_state->GetIsolate());
3570     case WebGLDebugRendererInfo::kUnmaskedVendorWebgl:
3571       if (ExtensionEnabled(kWebGLDebugRendererInfoName)) {
3572         if (IdentifiabilityStudySettings::Get()->ShouldSample(
3573                 blink::IdentifiableSurface::Type::kWebGLParameter)) {
3574           RecordIdentifiableGLParameterDigest(
3575               pname, IdentifiabilityBenignStringToken(
3576                          String(ContextGL()->GetString(GL_VENDOR))));
3577         }
3578         return WebGLAny(script_state,
3579                         String(ContextGL()->GetString(GL_VENDOR)));
3580       }
3581       SynthesizeGLError(
3582           GL_INVALID_ENUM, "getParameter",
3583           "invalid parameter name, WEBGL_debug_renderer_info not enabled");
3584       return ScriptValue::CreateNull(script_state->GetIsolate());
3585     case GL_VERTEX_ARRAY_BINDING_OES:  // OES_vertex_array_object
3586       if (ExtensionEnabled(kOESVertexArrayObjectName) || IsWebGL2()) {
3587         if (!bound_vertex_array_object_->IsDefaultObject())
3588           return WebGLAny(script_state, bound_vertex_array_object_.Get());
3589         return ScriptValue::CreateNull(script_state->GetIsolate());
3590       }
3591       SynthesizeGLError(
3592           GL_INVALID_ENUM, "getParameter",
3593           "invalid parameter name, OES_vertex_array_object not enabled");
3594       return ScriptValue::CreateNull(script_state->GetIsolate());
3595     case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:  // EXT_texture_filter_anisotropic
3596       if (ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
3597         return GetFloatParameter(script_state,
3598                                  GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
3599       }
3600       SynthesizeGLError(
3601           GL_INVALID_ENUM, "getParameter",
3602           "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
3603       return ScriptValue::CreateNull(script_state->GetIsolate());
3604     case GL_MAX_COLOR_ATTACHMENTS_EXT:  // EXT_draw_buffers BEGIN
3605       if (ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2())
3606         return WebGLAny(script_state, MaxColorAttachments());
3607       SynthesizeGLError(
3608           GL_INVALID_ENUM, "getParameter",
3609           "invalid parameter name, WEBGL_draw_buffers not enabled");
3610       return ScriptValue::CreateNull(script_state->GetIsolate());
3611     case GL_MAX_DRAW_BUFFERS_EXT:
3612       if (ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2())
3613         return WebGLAny(script_state, MaxDrawBuffers());
3614       SynthesizeGLError(
3615           GL_INVALID_ENUM, "getParameter",
3616           "invalid parameter name, WEBGL_draw_buffers not enabled");
3617       return ScriptValue::CreateNull(script_state->GetIsolate());
3618     case GL_TIMESTAMP_EXT:
3619       if (ExtensionEnabled(kEXTDisjointTimerQueryName))
3620         return WebGLAny(script_state, 0);
3621       SynthesizeGLError(
3622           GL_INVALID_ENUM, "getParameter",
3623           "invalid parameter name, EXT_disjoint_timer_query not enabled");
3624       return ScriptValue::CreateNull(script_state->GetIsolate());
3625     case GL_GPU_DISJOINT_EXT:
3626       if (ExtensionEnabled(kEXTDisjointTimerQueryName))
3627         return GetBooleanParameter(script_state, GL_GPU_DISJOINT_EXT);
3628       SynthesizeGLError(
3629           GL_INVALID_ENUM, "getParameter",
3630           "invalid parameter name, EXT_disjoint_timer_query not enabled");
3631       return ScriptValue::CreateNull(script_state->GetIsolate());
3632     case GL_MAX_VIEWS_OVR:
3633       if (ExtensionEnabled(kOVRMultiview2Name))
3634         return GetIntParameter(script_state, pname);
3635       SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
3636                         "invalid parameter name, OVR_multiview2 not enabled");
3637       return ScriptValue::CreateNull(script_state->GetIsolate());
3638     default:
3639       if ((ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()) &&
3640           pname >= GL_DRAW_BUFFER0_EXT &&
3641           pname < static_cast<GLenum>(GL_DRAW_BUFFER0_EXT + MaxDrawBuffers())) {
3642         GLint value = GL_NONE;
3643         if (framebuffer_binding_)
3644           value = framebuffer_binding_->GetDrawBuffer(pname);
3645         else  // emulated backbuffer
3646           value = back_draw_buffer_;
3647         return WebGLAny(script_state, value);
3648       }
3649       SynthesizeGLError(GL_INVALID_ENUM, "getParameter",
3650                         "invalid parameter name");
3651       return ScriptValue::CreateNull(script_state->GetIsolate());
3652   }
3653 }
3654 
getProgramParameter(ScriptState * script_state,WebGLProgram * program,GLenum pname)3655 ScriptValue WebGLRenderingContextBase::getProgramParameter(
3656     ScriptState* script_state,
3657     WebGLProgram* program,
3658     GLenum pname) {
3659   if (!ValidateWebGLProgramOrShader("getProgramParamter", program)) {
3660     return ScriptValue::CreateNull(script_state->GetIsolate());
3661   }
3662 
3663   GLint value = 0;
3664   switch (pname) {
3665     case GL_DELETE_STATUS:
3666       return WebGLAny(script_state, program->MarkedForDeletion());
3667     case GL_VALIDATE_STATUS:
3668       ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
3669       return WebGLAny(script_state, static_cast<bool>(value));
3670     case GL_LINK_STATUS:
3671       return WebGLAny(script_state, program->LinkStatus(this));
3672     case GL_COMPLETION_STATUS_KHR:
3673       if (!ExtensionEnabled(kKHRParallelShaderCompileName)) {
3674         SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3675                           "invalid parameter name");
3676         return ScriptValue::CreateNull(script_state->GetIsolate());
3677       }
3678       bool completed;
3679       if (checkProgramCompletionQueryAvailable(program, &completed)) {
3680         return WebGLAny(script_state, completed);
3681       }
3682       return WebGLAny(script_state, program->CompletionStatus(this));
3683     case GL_ACTIVE_UNIFORM_BLOCKS:
3684     case GL_TRANSFORM_FEEDBACK_VARYINGS:
3685       if (!IsWebGL2()) {
3686         SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3687                           "invalid parameter name");
3688         return ScriptValue::CreateNull(script_state->GetIsolate());
3689       }
3690       FALLTHROUGH;
3691     case GL_ATTACHED_SHADERS:
3692     case GL_ACTIVE_ATTRIBUTES:
3693     case GL_ACTIVE_UNIFORMS:
3694       ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
3695       return WebGLAny(script_state, value);
3696     case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
3697       if (!IsWebGL2()) {
3698         SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3699                           "invalid parameter name");
3700         return ScriptValue::CreateNull(script_state->GetIsolate());
3701       }
3702       ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value);
3703       return WebGLAny(script_state, static_cast<unsigned>(value));
3704     default:
3705       SynthesizeGLError(GL_INVALID_ENUM, "getProgramParameter",
3706                         "invalid parameter name");
3707       return ScriptValue::CreateNull(script_state->GetIsolate());
3708   }
3709 }
3710 
getProgramInfoLog(WebGLProgram * program)3711 String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program) {
3712   if (!ValidateWebGLProgramOrShader("getProgramInfoLog", program))
3713     return String();
3714   GLStringQuery query(ContextGL());
3715   return query.Run<GLStringQuery::ProgramInfoLog>(ObjectNonZero(program));
3716 }
3717 
getRenderbufferParameter(ScriptState * script_state,GLenum target,GLenum pname)3718 ScriptValue WebGLRenderingContextBase::getRenderbufferParameter(
3719     ScriptState* script_state,
3720     GLenum target,
3721     GLenum pname) {
3722   if (isContextLost())
3723     return ScriptValue::CreateNull(script_state->GetIsolate());
3724   if (target != GL_RENDERBUFFER) {
3725     SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
3726                       "invalid target");
3727     return ScriptValue::CreateNull(script_state->GetIsolate());
3728   }
3729   if (!renderbuffer_binding_ || !renderbuffer_binding_->Object()) {
3730     SynthesizeGLError(GL_INVALID_OPERATION, "getRenderbufferParameter",
3731                       "no renderbuffer bound");
3732     return ScriptValue::CreateNull(script_state->GetIsolate());
3733   }
3734 
3735   GLint value = 0;
3736   switch (pname) {
3737     case GL_RENDERBUFFER_SAMPLES:
3738       if (!IsWebGL2()) {
3739         SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
3740                           "invalid parameter name");
3741         return ScriptValue::CreateNull(script_state->GetIsolate());
3742       }
3743       FALLTHROUGH;
3744     case GL_RENDERBUFFER_WIDTH:
3745     case GL_RENDERBUFFER_HEIGHT:
3746     case GL_RENDERBUFFER_RED_SIZE:
3747     case GL_RENDERBUFFER_GREEN_SIZE:
3748     case GL_RENDERBUFFER_BLUE_SIZE:
3749     case GL_RENDERBUFFER_ALPHA_SIZE:
3750     case GL_RENDERBUFFER_DEPTH_SIZE:
3751     case GL_RENDERBUFFER_STENCIL_SIZE:
3752       ContextGL()->GetRenderbufferParameteriv(target, pname, &value);
3753       if (IdentifiabilityStudySettings::Get()->ShouldSample(
3754               blink::IdentifiableSurface::Type::kWebGLParameter)) {
3755         RecordIdentifiableGLParameterDigest(pname, value);
3756       }
3757       return WebGLAny(script_state, value);
3758     case GL_RENDERBUFFER_INTERNAL_FORMAT:
3759       return WebGLAny(script_state, renderbuffer_binding_->InternalFormat());
3760     default:
3761       SynthesizeGLError(GL_INVALID_ENUM, "getRenderbufferParameter",
3762                         "invalid parameter name");
3763       return ScriptValue::CreateNull(script_state->GetIsolate());
3764   }
3765 }
3766 
getShaderParameter(ScriptState * script_state,WebGLShader * shader,GLenum pname)3767 ScriptValue WebGLRenderingContextBase::getShaderParameter(
3768     ScriptState* script_state,
3769     WebGLShader* shader,
3770     GLenum pname) {
3771   if (!ValidateWebGLProgramOrShader("getShaderParameter", shader)) {
3772     return ScriptValue::CreateNull(script_state->GetIsolate());
3773   }
3774   GLint value = 0;
3775   switch (pname) {
3776     case GL_DELETE_STATUS:
3777       return WebGLAny(script_state, shader->MarkedForDeletion());
3778     case GL_COMPILE_STATUS:
3779       ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
3780       return WebGLAny(script_state, static_cast<bool>(value));
3781     case GL_COMPLETION_STATUS_KHR:
3782       if (!ExtensionEnabled(kKHRParallelShaderCompileName)) {
3783         SynthesizeGLError(GL_INVALID_ENUM, "getShaderParameter",
3784                           "invalid parameter name");
3785         return ScriptValue::CreateNull(script_state->GetIsolate());
3786       }
3787       ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
3788       return WebGLAny(script_state, static_cast<bool>(value));
3789     case GL_SHADER_TYPE:
3790       ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value);
3791       return WebGLAny(script_state, static_cast<unsigned>(value));
3792     default:
3793       SynthesizeGLError(GL_INVALID_ENUM, "getShaderParameter",
3794                         "invalid parameter name");
3795       return ScriptValue::CreateNull(script_state->GetIsolate());
3796   }
3797 }
3798 
getShaderInfoLog(WebGLShader * shader)3799 String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader) {
3800   if (!ValidateWebGLProgramOrShader("getShaderInfoLog", shader))
3801     return String();
3802   GLStringQuery query(ContextGL());
3803   return query.Run<GLStringQuery::ShaderInfoLog>(ObjectNonZero(shader));
3804 }
3805 
getShaderPrecisionFormat(GLenum shader_type,GLenum precision_type)3806 WebGLShaderPrecisionFormat* WebGLRenderingContextBase::getShaderPrecisionFormat(
3807     GLenum shader_type,
3808     GLenum precision_type) {
3809   if (isContextLost())
3810     return nullptr;
3811   if (!ValidateShaderType("getShaderPrecisionFormat", shader_type)) {
3812     return nullptr;
3813   }
3814   switch (precision_type) {
3815     case GL_LOW_FLOAT:
3816     case GL_MEDIUM_FLOAT:
3817     case GL_HIGH_FLOAT:
3818     case GL_LOW_INT:
3819     case GL_MEDIUM_INT:
3820     case GL_HIGH_INT:
3821       break;
3822     default:
3823       SynthesizeGLError(GL_INVALID_ENUM, "getShaderPrecisionFormat",
3824                         "invalid precision type");
3825       return nullptr;
3826   }
3827 
3828   GLint range[2] = {0, 0};
3829   GLint precision = 0;
3830   ContextGL()->GetShaderPrecisionFormat(shader_type, precision_type, range,
3831                                         &precision);
3832   auto* result = MakeGarbageCollected<WebGLShaderPrecisionFormat>(
3833       range[0], range[1], precision);
3834   if (IdentifiabilityStudySettings::Get()->ShouldSample(
3835           blink::IdentifiableSurface::Type::kWebGLShaderPrecisionFormat)) {
3836     RecordShaderPrecisionFormatForStudy(shader_type, precision_type, result);
3837   }
3838   return result;
3839 }
3840 
getShaderSource(WebGLShader * shader)3841 String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) {
3842   if (!ValidateWebGLProgramOrShader("getShaderSource", shader))
3843     return String();
3844   return EnsureNotNull(shader->Source());
3845 }
3846 
3847 base::Optional<Vector<String>>
getSupportedExtensions()3848 WebGLRenderingContextBase::getSupportedExtensions() {
3849   if (isContextLost())
3850     return base::nullopt;
3851 
3852   Vector<String> result;
3853 
3854   for (ExtensionTracker* tracker : extensions_) {
3855     if (ExtensionSupportedAndAllowed(tracker)) {
3856       const char* const* prefixes = tracker->Prefixes();
3857       for (; *prefixes; ++prefixes) {
3858         String prefixed_name = String(*prefixes) + tracker->ExtensionName();
3859         result.push_back(prefixed_name);
3860       }
3861     }
3862   }
3863 
3864   return result;
3865 }
3866 
getTexParameter(ScriptState * script_state,GLenum target,GLenum pname)3867 ScriptValue WebGLRenderingContextBase::getTexParameter(
3868     ScriptState* script_state,
3869     GLenum target,
3870     GLenum pname) {
3871   if (isContextLost())
3872     return ScriptValue::CreateNull(script_state->GetIsolate());
3873   if (!ValidateTextureBinding("getTexParameter", target))
3874     return ScriptValue::CreateNull(script_state->GetIsolate());
3875   switch (pname) {
3876     case GL_TEXTURE_MAG_FILTER:
3877     case GL_TEXTURE_MIN_FILTER:
3878     case GL_TEXTURE_WRAP_S:
3879     case GL_TEXTURE_WRAP_T: {
3880       GLint value = 0;
3881       ContextGL()->GetTexParameteriv(target, pname, &value);
3882       return WebGLAny(script_state, static_cast<unsigned>(value));
3883     }
3884     case GL_TEXTURE_MAX_ANISOTROPY_EXT:  // EXT_texture_filter_anisotropic
3885       if (ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
3886         GLfloat value = 0.f;
3887         ContextGL()->GetTexParameterfv(target, pname, &value);
3888         return WebGLAny(script_state, value);
3889       }
3890       SynthesizeGLError(
3891           GL_INVALID_ENUM, "getTexParameter",
3892           "invalid parameter name, EXT_texture_filter_anisotropic not enabled");
3893       return ScriptValue::CreateNull(script_state->GetIsolate());
3894     default:
3895       SynthesizeGLError(GL_INVALID_ENUM, "getTexParameter",
3896                         "invalid parameter name");
3897       return ScriptValue::CreateNull(script_state->GetIsolate());
3898   }
3899 }
3900 
getUniform(ScriptState * script_state,WebGLProgram * program,const WebGLUniformLocation * uniform_location)3901 ScriptValue WebGLRenderingContextBase::getUniform(
3902     ScriptState* script_state,
3903     WebGLProgram* program,
3904     const WebGLUniformLocation* uniform_location) {
3905   if (!ValidateWebGLProgramOrShader("getUniform", program))
3906     return ScriptValue::CreateNull(script_state->GetIsolate());
3907   DCHECK(uniform_location);
3908   if (uniform_location->Program() != program) {
3909     SynthesizeGLError(GL_INVALID_OPERATION, "getUniform",
3910                       "no uniformlocation or not valid for this program");
3911     return ScriptValue::CreateNull(script_state->GetIsolate());
3912   }
3913   GLint location = uniform_location->Location();
3914 
3915   GLuint program_id = ObjectNonZero(program);
3916   GLint max_name_length = -1;
3917   ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH,
3918                             &max_name_length);
3919   if (max_name_length < 0)
3920     return ScriptValue::CreateNull(script_state->GetIsolate());
3921   if (max_name_length == 0) {
3922     SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
3923                       "no active uniforms exist");
3924     return ScriptValue::CreateNull(script_state->GetIsolate());
3925   }
3926 
3927   // FIXME: make this more efficient using WebGLUniformLocation and caching
3928   // types in it.
3929   GLint active_uniforms = 0;
3930   ContextGL()->GetProgramiv(program_id, GL_ACTIVE_UNIFORMS, &active_uniforms);
3931   for (GLint i = 0; i < active_uniforms; i++) {
3932     LChar* name_ptr;
3933     scoped_refptr<StringImpl> name_impl =
3934         StringImpl::CreateUninitialized(max_name_length, name_ptr);
3935     GLsizei name_length = 0;
3936     GLint size = -1;
3937     GLenum type = 0;
3938     ContextGL()->GetActiveUniform(program_id, i, max_name_length, &name_length,
3939                                   &size, &type,
3940                                   reinterpret_cast<GLchar*>(name_ptr));
3941     if (size < 0)
3942       return ScriptValue::CreateNull(script_state->GetIsolate());
3943     String name(name_impl->Substring(0, name_length));
3944     StringBuilder name_builder;
3945     // Strip "[0]" from the name if it's an array.
3946     if (size > 1 && name.EndsWith("[0]"))
3947       name = name.Left(name.length() - 3);
3948     // If it's an array, we need to iterate through each element, appending
3949     // "[index]" to the name.
3950     for (GLint index = 0; index < size; ++index) {
3951       name_builder.Clear();
3952       name_builder.Append(name);
3953       if (size > 1 && index >= 1) {
3954         name_builder.Append('[');
3955         name_builder.AppendNumber(index);
3956         name_builder.Append(']');
3957       }
3958       // Now need to look this up by name again to find its location
3959       GLint loc = ContextGL()->GetUniformLocation(
3960           ObjectOrZero(program), name_builder.ToString().Utf8().c_str());
3961       if (loc == location) {
3962         // Found it. Use the type in the ActiveInfo to determine the return
3963         // type.
3964         GLenum base_type;
3965         unsigned length;
3966         switch (type) {
3967           case GL_BOOL:
3968             base_type = GL_BOOL;
3969             length = 1;
3970             break;
3971           case GL_BOOL_VEC2:
3972             base_type = GL_BOOL;
3973             length = 2;
3974             break;
3975           case GL_BOOL_VEC3:
3976             base_type = GL_BOOL;
3977             length = 3;
3978             break;
3979           case GL_BOOL_VEC4:
3980             base_type = GL_BOOL;
3981             length = 4;
3982             break;
3983           case GL_INT:
3984             base_type = GL_INT;
3985             length = 1;
3986             break;
3987           case GL_INT_VEC2:
3988             base_type = GL_INT;
3989             length = 2;
3990             break;
3991           case GL_INT_VEC3:
3992             base_type = GL_INT;
3993             length = 3;
3994             break;
3995           case GL_INT_VEC4:
3996             base_type = GL_INT;
3997             length = 4;
3998             break;
3999           case GL_FLOAT:
4000             base_type = GL_FLOAT;
4001             length = 1;
4002             break;
4003           case GL_FLOAT_VEC2:
4004             base_type = GL_FLOAT;
4005             length = 2;
4006             break;
4007           case GL_FLOAT_VEC3:
4008             base_type = GL_FLOAT;
4009             length = 3;
4010             break;
4011           case GL_FLOAT_VEC4:
4012             base_type = GL_FLOAT;
4013             length = 4;
4014             break;
4015           case GL_FLOAT_MAT2:
4016             base_type = GL_FLOAT;
4017             length = 4;
4018             break;
4019           case GL_FLOAT_MAT3:
4020             base_type = GL_FLOAT;
4021             length = 9;
4022             break;
4023           case GL_FLOAT_MAT4:
4024             base_type = GL_FLOAT;
4025             length = 16;
4026             break;
4027           case GL_SAMPLER_2D:
4028           case GL_SAMPLER_CUBE:
4029             base_type = GL_INT;
4030             length = 1;
4031             break;
4032           case GL_SAMPLER_VIDEO_IMAGE_WEBGL:
4033             if (!ExtensionEnabled(kWebGLVideoTextureName)) {
4034               SynthesizeGLError(
4035                   GL_INVALID_VALUE, "getUniform",
4036                   "unhandled type, WEBGL_video_texture extension not enabled");
4037               return ScriptValue::CreateNull(script_state->GetIsolate());
4038             }
4039             base_type = GL_INT;
4040             length = 1;
4041             break;
4042           default:
4043             if (!IsWebGL2()) {
4044               // Can't handle this type
4045               SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
4046                                 "unhandled type");
4047               return ScriptValue::CreateNull(script_state->GetIsolate());
4048             }
4049             // handle GLenums for WebGL 2.0 or higher
4050             switch (type) {
4051               case GL_UNSIGNED_INT:
4052                 base_type = GL_UNSIGNED_INT;
4053                 length = 1;
4054                 break;
4055               case GL_UNSIGNED_INT_VEC2:
4056                 base_type = GL_UNSIGNED_INT;
4057                 length = 2;
4058                 break;
4059               case GL_UNSIGNED_INT_VEC3:
4060                 base_type = GL_UNSIGNED_INT;
4061                 length = 3;
4062                 break;
4063               case GL_UNSIGNED_INT_VEC4:
4064                 base_type = GL_UNSIGNED_INT;
4065                 length = 4;
4066                 break;
4067               case GL_FLOAT_MAT2x3:
4068                 base_type = GL_FLOAT;
4069                 length = 6;
4070                 break;
4071               case GL_FLOAT_MAT2x4:
4072                 base_type = GL_FLOAT;
4073                 length = 8;
4074                 break;
4075               case GL_FLOAT_MAT3x2:
4076                 base_type = GL_FLOAT;
4077                 length = 6;
4078                 break;
4079               case GL_FLOAT_MAT3x4:
4080                 base_type = GL_FLOAT;
4081                 length = 12;
4082                 break;
4083               case GL_FLOAT_MAT4x2:
4084                 base_type = GL_FLOAT;
4085                 length = 8;
4086                 break;
4087               case GL_FLOAT_MAT4x3:
4088                 base_type = GL_FLOAT;
4089                 length = 12;
4090                 break;
4091               case GL_SAMPLER_3D:
4092               case GL_SAMPLER_2D_ARRAY:
4093               case GL_SAMPLER_2D_SHADOW:
4094               case GL_SAMPLER_CUBE_SHADOW:
4095               case GL_SAMPLER_2D_ARRAY_SHADOW:
4096               case GL_INT_SAMPLER_2D:
4097               case GL_INT_SAMPLER_CUBE:
4098               case GL_INT_SAMPLER_3D:
4099               case GL_INT_SAMPLER_2D_ARRAY:
4100               case GL_UNSIGNED_INT_SAMPLER_2D:
4101               case GL_UNSIGNED_INT_SAMPLER_CUBE:
4102               case GL_UNSIGNED_INT_SAMPLER_3D:
4103               case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
4104                 base_type = GL_INT;
4105                 length = 1;
4106                 break;
4107               default:
4108                 // Can't handle this type
4109                 SynthesizeGLError(GL_INVALID_VALUE, "getUniform",
4110                                   "unhandled type");
4111                 return ScriptValue::CreateNull(script_state->GetIsolate());
4112             }
4113         }
4114         switch (base_type) {
4115           case GL_FLOAT: {
4116             GLfloat value[16] = {0};
4117             ContextGL()->GetUniformfv(ObjectOrZero(program), location, value);
4118             if (length == 1)
4119               return WebGLAny(script_state, value[0]);
4120             return WebGLAny(script_state,
4121                             DOMFloat32Array::Create(value, length));
4122           }
4123           case GL_INT: {
4124             GLint value[4] = {0};
4125             ContextGL()->GetUniformiv(ObjectOrZero(program), location, value);
4126             if (length == 1)
4127               return WebGLAny(script_state, value[0]);
4128             return WebGLAny(script_state, DOMInt32Array::Create(value, length));
4129           }
4130           case GL_UNSIGNED_INT: {
4131             GLuint value[4] = {0};
4132             ContextGL()->GetUniformuiv(ObjectOrZero(program), location, value);
4133             if (length == 1)
4134               return WebGLAny(script_state, value[0]);
4135             return WebGLAny(script_state,
4136                             DOMUint32Array::Create(value, length));
4137           }
4138           case GL_BOOL: {
4139             GLint value[4] = {0};
4140             ContextGL()->GetUniformiv(ObjectOrZero(program), location, value);
4141             if (length > 1) {
4142               bool bool_value[4] = {0};
4143               for (unsigned j = 0; j < length; j++)
4144                 bool_value[j] = static_cast<bool>(value[j]);
4145               return WebGLAny(script_state, bool_value, length);
4146             }
4147             return WebGLAny(script_state, static_cast<bool>(value[0]));
4148           }
4149           default:
4150             NOTIMPLEMENTED();
4151         }
4152       }
4153     }
4154   }
4155   // If we get here, something went wrong in our unfortunately complex logic
4156   // above
4157   SynthesizeGLError(GL_INVALID_VALUE, "getUniform", "unknown error");
4158   return ScriptValue::CreateNull(script_state->GetIsolate());
4159 }
4160 
getUniformLocation(WebGLProgram * program,const String & name)4161 WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation(
4162     WebGLProgram* program,
4163     const String& name) {
4164   if (!ValidateWebGLProgramOrShader("getUniformLocation", program))
4165     return nullptr;
4166   if (!ValidateLocationLength("getUniformLocation", name))
4167     return nullptr;
4168   if (!ValidateString("getUniformLocation", name))
4169     return nullptr;
4170   if (IsPrefixReserved(name))
4171     return nullptr;
4172   if (!program->LinkStatus(this)) {
4173     SynthesizeGLError(GL_INVALID_OPERATION, "getUniformLocation",
4174                       "program not linked");
4175     return nullptr;
4176   }
4177   GLint uniform_location = ContextGL()->GetUniformLocation(
4178       ObjectOrZero(program), name.Utf8().c_str());
4179   if (uniform_location == -1)
4180     return nullptr;
4181   return MakeGarbageCollected<WebGLUniformLocation>(program, uniform_location);
4182 }
4183 
getVertexAttrib(ScriptState * script_state,GLuint index,GLenum pname)4184 ScriptValue WebGLRenderingContextBase::getVertexAttrib(
4185     ScriptState* script_state,
4186     GLuint index,
4187     GLenum pname) {
4188   if (isContextLost())
4189     return ScriptValue::CreateNull(script_state->GetIsolate());
4190   if (index >= max_vertex_attribs_) {
4191     SynthesizeGLError(GL_INVALID_VALUE, "getVertexAttrib",
4192                       "index out of range");
4193     return ScriptValue::CreateNull(script_state->GetIsolate());
4194   }
4195 
4196   if ((ExtensionEnabled(kANGLEInstancedArraysName) || IsWebGL2()) &&
4197       pname == GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE) {
4198     GLint value = 0;
4199     ContextGL()->GetVertexAttribiv(index, pname, &value);
4200     return WebGLAny(script_state, value);
4201   }
4202 
4203   switch (pname) {
4204     case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
4205       return WebGLAny(
4206           script_state,
4207           bound_vertex_array_object_->GetArrayBufferForAttrib(index));
4208     case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
4209     case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: {
4210       GLint value = 0;
4211       ContextGL()->GetVertexAttribiv(index, pname, &value);
4212       return WebGLAny(script_state, static_cast<bool>(value));
4213     }
4214     case GL_VERTEX_ATTRIB_ARRAY_SIZE:
4215     case GL_VERTEX_ATTRIB_ARRAY_STRIDE: {
4216       GLint value = 0;
4217       ContextGL()->GetVertexAttribiv(index, pname, &value);
4218       return WebGLAny(script_state, value);
4219     }
4220     case GL_VERTEX_ATTRIB_ARRAY_TYPE: {
4221       GLint value = 0;
4222       ContextGL()->GetVertexAttribiv(index, pname, &value);
4223       return WebGLAny(script_state, static_cast<GLenum>(value));
4224     }
4225     case GL_CURRENT_VERTEX_ATTRIB: {
4226       switch (vertex_attrib_type_[index]) {
4227         case kFloat32ArrayType: {
4228           GLfloat float_value[4];
4229           ContextGL()->GetVertexAttribfv(index, pname, float_value);
4230           return WebGLAny(script_state,
4231                           DOMFloat32Array::Create(float_value, 4));
4232         }
4233         case kInt32ArrayType: {
4234           GLint int_value[4];
4235           ContextGL()->GetVertexAttribIiv(index, pname, int_value);
4236           return WebGLAny(script_state, DOMInt32Array::Create(int_value, 4));
4237         }
4238         case kUint32ArrayType: {
4239           GLuint uint_value[4];
4240           ContextGL()->GetVertexAttribIuiv(index, pname, uint_value);
4241           return WebGLAny(script_state, DOMUint32Array::Create(uint_value, 4));
4242         }
4243         default:
4244           NOTREACHED();
4245           break;
4246       }
4247       return ScriptValue::CreateNull(script_state->GetIsolate());
4248     }
4249     case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
4250       if (IsWebGL2()) {
4251         GLint value = 0;
4252         ContextGL()->GetVertexAttribiv(index, pname, &value);
4253         return WebGLAny(script_state, static_cast<bool>(value));
4254       }
4255       FALLTHROUGH;
4256     default:
4257       SynthesizeGLError(GL_INVALID_ENUM, "getVertexAttrib",
4258                         "invalid parameter name");
4259       return ScriptValue::CreateNull(script_state->GetIsolate());
4260   }
4261 }
4262 
getVertexAttribOffset(GLuint index,GLenum pname)4263 int64_t WebGLRenderingContextBase::getVertexAttribOffset(GLuint index,
4264                                                          GLenum pname) {
4265   if (isContextLost())
4266     return 0;
4267   GLvoid* result = nullptr;
4268   // NOTE: If pname is ever a value that returns more than 1 element
4269   // this will corrupt memory.
4270   ContextGL()->GetVertexAttribPointerv(index, pname, &result);
4271   return static_cast<int64_t>(reinterpret_cast<intptr_t>(result));
4272 }
4273 
hint(GLenum target,GLenum mode)4274 void WebGLRenderingContextBase::hint(GLenum target, GLenum mode) {
4275   if (isContextLost())
4276     return;
4277   bool is_valid = false;
4278   switch (target) {
4279     case GL_GENERATE_MIPMAP_HINT:
4280       is_valid = true;
4281       break;
4282     case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:  // OES_standard_derivatives
4283       if (ExtensionEnabled(kOESStandardDerivativesName) || IsWebGL2())
4284         is_valid = true;
4285       break;
4286   }
4287   if (!is_valid) {
4288     SynthesizeGLError(GL_INVALID_ENUM, "hint", "invalid target");
4289     return;
4290   }
4291   ContextGL()->Hint(target, mode);
4292 }
4293 
isBuffer(WebGLBuffer * buffer)4294 GLboolean WebGLRenderingContextBase::isBuffer(WebGLBuffer* buffer) {
4295   if (!buffer || isContextLost() || !buffer->Validate(ContextGroup(), this))
4296     return 0;
4297 
4298   if (!buffer->HasEverBeenBound())
4299     return 0;
4300   if (buffer->MarkedForDeletion())
4301     return 0;
4302 
4303   return ContextGL()->IsBuffer(buffer->Object());
4304 }
4305 
isContextLost() const4306 bool WebGLRenderingContextBase::isContextLost() const {
4307   return context_lost_mode_ != kNotLostContext;
4308 }
4309 
isEnabled(GLenum cap)4310 GLboolean WebGLRenderingContextBase::isEnabled(GLenum cap) {
4311   if (isContextLost() || !ValidateCapability("isEnabled", cap))
4312     return 0;
4313   if (cap == GL_STENCIL_TEST)
4314     return stencil_enabled_;
4315   return ContextGL()->IsEnabled(cap);
4316 }
4317 
isFramebuffer(WebGLFramebuffer * framebuffer)4318 GLboolean WebGLRenderingContextBase::isFramebuffer(
4319     WebGLFramebuffer* framebuffer) {
4320   if (!framebuffer || isContextLost() ||
4321       !framebuffer->Validate(ContextGroup(), this))
4322     return 0;
4323 
4324   if (!framebuffer->HasEverBeenBound())
4325     return 0;
4326   if (framebuffer->MarkedForDeletion())
4327     return 0;
4328 
4329   return ContextGL()->IsFramebuffer(framebuffer->Object());
4330 }
4331 
isProgram(WebGLProgram * program)4332 GLboolean WebGLRenderingContextBase::isProgram(WebGLProgram* program) {
4333   if (!program || isContextLost() || !program->Validate(ContextGroup(), this))
4334     return 0;
4335 
4336   // OpenGL ES special-cases the behavior of program objects; if they're deleted
4337   // while attached to the current context state, glIsProgram is supposed to
4338   // still return true. For this reason, MarkedForDeletion is not checked here.
4339 
4340   return ContextGL()->IsProgram(program->Object());
4341 }
4342 
isRenderbuffer(WebGLRenderbuffer * renderbuffer)4343 GLboolean WebGLRenderingContextBase::isRenderbuffer(
4344     WebGLRenderbuffer* renderbuffer) {
4345   if (!renderbuffer || isContextLost() ||
4346       !renderbuffer->Validate(ContextGroup(), this))
4347     return 0;
4348 
4349   if (!renderbuffer->HasEverBeenBound())
4350     return 0;
4351   if (renderbuffer->MarkedForDeletion())
4352     return 0;
4353 
4354   return ContextGL()->IsRenderbuffer(renderbuffer->Object());
4355 }
4356 
isShader(WebGLShader * shader)4357 GLboolean WebGLRenderingContextBase::isShader(WebGLShader* shader) {
4358   if (!shader || isContextLost() || !shader->Validate(ContextGroup(), this))
4359     return 0;
4360 
4361   // OpenGL ES special-cases the behavior of shader objects; if they're deleted
4362   // while attached to a program, glIsShader is supposed to still return true.
4363   // For this reason, MarkedForDeletion is not checked here.
4364 
4365   return ContextGL()->IsShader(shader->Object());
4366 }
4367 
isTexture(WebGLTexture * texture)4368 GLboolean WebGLRenderingContextBase::isTexture(WebGLTexture* texture) {
4369   if (!texture || isContextLost() || !texture->Validate(ContextGroup(), this))
4370     return 0;
4371 
4372   if (!texture->HasEverBeenBound())
4373     return 0;
4374   if (texture->MarkedForDeletion())
4375     return 0;
4376 
4377   return ContextGL()->IsTexture(texture->Object());
4378 }
4379 
lineWidth(GLfloat width)4380 void WebGLRenderingContextBase::lineWidth(GLfloat width) {
4381   if (isContextLost())
4382     return;
4383   ContextGL()->LineWidth(width);
4384 }
4385 
linkProgram(WebGLProgram * program)4386 void WebGLRenderingContextBase::linkProgram(WebGLProgram* program) {
4387   if (!ValidateWebGLProgramOrShader("linkProgram", program))
4388     return;
4389 
4390   if (program->ActiveTransformFeedbackCount() > 0) {
4391     SynthesizeGLError(
4392         GL_INVALID_OPERATION, "linkProgram",
4393         "program being used by one or more active transform feedback objects");
4394     return;
4395   }
4396 
4397   GLuint query = 0u;
4398   if (ExtensionEnabled(kKHRParallelShaderCompileName)) {
4399     ContextGL()->GenQueriesEXT(1, &query);
4400     ContextGL()->BeginQueryEXT(GL_PROGRAM_COMPLETION_QUERY_CHROMIUM, query);
4401   }
4402   ContextGL()->LinkProgram(ObjectOrZero(program));
4403   if (ExtensionEnabled(kKHRParallelShaderCompileName)) {
4404     ContextGL()->EndQueryEXT(GL_PROGRAM_COMPLETION_QUERY_CHROMIUM);
4405     addProgramCompletionQuery(program, query);
4406   }
4407 
4408   program->IncreaseLinkCount();
4409 }
4410 
pixelStorei(GLenum pname,GLint param)4411 void WebGLRenderingContextBase::pixelStorei(GLenum pname, GLint param) {
4412   if (isContextLost())
4413     return;
4414   switch (pname) {
4415     case GC3D_UNPACK_FLIP_Y_WEBGL:
4416       unpack_flip_y_ = param;
4417       break;
4418     case GC3D_UNPACK_PREMULTIPLY_ALPHA_WEBGL:
4419       unpack_premultiply_alpha_ = param;
4420       break;
4421     case GC3D_UNPACK_COLORSPACE_CONVERSION_WEBGL:
4422       if (static_cast<GLenum>(param) == GC3D_BROWSER_DEFAULT_WEBGL ||
4423           param == GL_NONE) {
4424         unpack_colorspace_conversion_ = static_cast<GLenum>(param);
4425       } else {
4426         SynthesizeGLError(
4427             GL_INVALID_VALUE, "pixelStorei",
4428             "invalid parameter for UNPACK_COLORSPACE_CONVERSION_WEBGL");
4429         return;
4430       }
4431       break;
4432     case GL_PACK_ALIGNMENT:
4433     case GL_UNPACK_ALIGNMENT:
4434       if (param == 1 || param == 2 || param == 4 || param == 8) {
4435         if (pname == GL_PACK_ALIGNMENT) {
4436           pack_alignment_ = param;
4437         } else {  // GL_UNPACK_ALIGNMENT:
4438           unpack_alignment_ = param;
4439         }
4440         ContextGL()->PixelStorei(pname, param);
4441       } else {
4442         SynthesizeGLError(GL_INVALID_VALUE, "pixelStorei",
4443                           "invalid parameter for alignment");
4444         return;
4445       }
4446       break;
4447     default:
4448       SynthesizeGLError(GL_INVALID_ENUM, "pixelStorei",
4449                         "invalid parameter name");
4450       return;
4451   }
4452 }
4453 
polygonOffset(GLfloat factor,GLfloat units)4454 void WebGLRenderingContextBase::polygonOffset(GLfloat factor, GLfloat units) {
4455   if (isContextLost())
4456     return;
4457   ContextGL()->PolygonOffset(factor, units);
4458 }
4459 
ValidateReadBufferAndGetInfo(const char * function_name,WebGLFramebuffer * & read_framebuffer_binding)4460 bool WebGLRenderingContextBase::ValidateReadBufferAndGetInfo(
4461     const char* function_name,
4462     WebGLFramebuffer*& read_framebuffer_binding) {
4463   read_framebuffer_binding = GetReadFramebufferBinding();
4464   if (read_framebuffer_binding) {
4465     const char* reason = "framebuffer incomplete";
4466     if (read_framebuffer_binding->CheckDepthStencilStatus(&reason) !=
4467         GL_FRAMEBUFFER_COMPLETE) {
4468       SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, function_name,
4469                         reason);
4470       return false;
4471     }
4472   } else {
4473     if (read_buffer_of_default_framebuffer_ == GL_NONE) {
4474       DCHECK(IsWebGL2());
4475       SynthesizeGLError(GL_INVALID_OPERATION, function_name,
4476                         "no image to read from");
4477       return false;
4478     }
4479   }
4480   return true;
4481 }
4482 
ValidateReadPixelsFormatAndType(GLenum format,GLenum type,DOMArrayBufferView * buffer)4483 bool WebGLRenderingContextBase::ValidateReadPixelsFormatAndType(
4484     GLenum format,
4485     GLenum type,
4486     DOMArrayBufferView* buffer) {
4487   switch (format) {
4488     case GL_ALPHA:
4489     case GL_RGB:
4490     case GL_RGBA:
4491       break;
4492     default:
4493       SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid format");
4494       return false;
4495   }
4496 
4497   switch (type) {
4498     case GL_UNSIGNED_BYTE:
4499       if (buffer) {
4500         auto bufferType = buffer->GetType();
4501         if (bufferType != DOMArrayBufferView::kTypeUint8 &&
4502             bufferType != DOMArrayBufferView::kTypeUint8Clamped) {
4503           SynthesizeGLError(
4504               GL_INVALID_OPERATION, "readPixels",
4505               "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array or "
4506               "Uint8ClampedArray");
4507           return false;
4508         }
4509       }
4510       return true;
4511     case GL_UNSIGNED_SHORT_5_6_5:
4512     case GL_UNSIGNED_SHORT_4_4_4_4:
4513     case GL_UNSIGNED_SHORT_5_5_5_1:
4514       if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeUint16) {
4515         SynthesizeGLError(
4516             GL_INVALID_OPERATION, "readPixels",
4517             "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
4518         return false;
4519       }
4520       return true;
4521     case GL_FLOAT:
4522       if (ExtensionEnabled(kOESTextureFloatName) ||
4523           ExtensionEnabled(kOESTextureHalfFloatName)) {
4524         if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeFloat32) {
4525           SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
4526                             "type FLOAT but ArrayBufferView not Float32Array");
4527           return false;
4528         }
4529         return true;
4530       }
4531       SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
4532       return false;
4533     case GL_HALF_FLOAT_OES:
4534       if (ExtensionEnabled(kOESTextureHalfFloatName)) {
4535         if (buffer && buffer->GetType() != DOMArrayBufferView::kTypeUint16) {
4536           SynthesizeGLError(
4537               GL_INVALID_OPERATION, "readPixels",
4538               "type HALF_FLOAT_OES but ArrayBufferView not Uint16Array");
4539           return false;
4540         }
4541         return true;
4542       }
4543       SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
4544       return false;
4545     default:
4546       SynthesizeGLError(GL_INVALID_ENUM, "readPixels", "invalid type");
4547       return false;
4548   }
4549 }
4550 
4551 WebGLImageConversion::PixelStoreParams
GetPackPixelStoreParams()4552 WebGLRenderingContextBase::GetPackPixelStoreParams() {
4553   WebGLImageConversion::PixelStoreParams params;
4554   params.alignment = pack_alignment_;
4555   return params;
4556 }
4557 
4558 WebGLImageConversion::PixelStoreParams
GetUnpackPixelStoreParams(TexImageDimension)4559 WebGLRenderingContextBase::GetUnpackPixelStoreParams(TexImageDimension) {
4560   WebGLImageConversion::PixelStoreParams params;
4561   params.alignment = unpack_alignment_;
4562   return params;
4563 }
4564 
ValidateReadPixelsFuncParameters(GLsizei width,GLsizei height,GLenum format,GLenum type,DOMArrayBufferView * buffer,int64_t buffer_size)4565 bool WebGLRenderingContextBase::ValidateReadPixelsFuncParameters(
4566     GLsizei width,
4567     GLsizei height,
4568     GLenum format,
4569     GLenum type,
4570     DOMArrayBufferView* buffer,
4571     int64_t buffer_size) {
4572   if (!ValidateReadPixelsFormatAndType(format, type, buffer))
4573     return false;
4574 
4575   // Calculate array size, taking into consideration of pack parameters.
4576   unsigned total_bytes_required = 0, total_skip_bytes = 0;
4577   GLenum error = WebGLImageConversion::ComputeImageSizeInBytes(
4578       format, type, width, height, 1, GetPackPixelStoreParams(),
4579       &total_bytes_required, nullptr, &total_skip_bytes);
4580   if (error != GL_NO_ERROR) {
4581     SynthesizeGLError(error, "readPixels", "invalid dimensions");
4582     return false;
4583   }
4584   if (buffer_size <
4585       static_cast<int64_t>(total_bytes_required + total_skip_bytes)) {
4586     SynthesizeGLError(GL_INVALID_OPERATION, "readPixels",
4587                       "buffer is not large enough for dimensions");
4588     return false;
4589   }
4590   return true;
4591 }
4592 
readPixels(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,MaybeShared<DOMArrayBufferView> pixels)4593 void WebGLRenderingContextBase::readPixels(
4594     GLint x,
4595     GLint y,
4596     GLsizei width,
4597     GLsizei height,
4598     GLenum format,
4599     GLenum type,
4600     MaybeShared<DOMArrayBufferView> pixels) {
4601   if (IdentifiabilityStudySettings::Get()->ShouldSample(
4602           blink::IdentifiableSurface::Type::kCanvasReadback)) {
4603     const auto& ukm_params = GetUkmParameters();
4604     blink::IdentifiabilityMetricBuilder(ukm_params.source_id)
4605         .Set(blink::IdentifiableSurface::FromTypeAndToken(
4606                  blink::IdentifiableSurface::Type::kCanvasReadback,
4607                  GetContextType()),
4608              0)
4609         .Record(ukm_params.ukm_recorder);
4610   }
4611   ReadPixelsHelper(x, y, width, height, format, type, pixels.View(), 0);
4612 }
4613 
ReadPixelsHelper(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,DOMArrayBufferView * pixels,int64_t offset)4614 void WebGLRenderingContextBase::ReadPixelsHelper(GLint x,
4615                                                  GLint y,
4616                                                  GLsizei width,
4617                                                  GLsizei height,
4618                                                  GLenum format,
4619                                                  GLenum type,
4620                                                  DOMArrayBufferView* pixels,
4621                                                  int64_t offset) {
4622   if (isContextLost())
4623     return;
4624   // Due to WebGL's same-origin restrictions, it is not possible to
4625   // taint the origin using the WebGL API.
4626   DCHECK(Host()->OriginClean());
4627 
4628   // Validate input parameters.
4629   if (!pixels) {
4630     SynthesizeGLError(GL_INVALID_VALUE, "readPixels",
4631                       "no destination ArrayBufferView");
4632     return;
4633   }
4634   base::CheckedNumeric<GLuint> offset_in_bytes = offset;
4635   offset_in_bytes *= pixels->TypeSize();
4636   if (!offset_in_bytes.IsValid() ||
4637       static_cast<size_t>(offset_in_bytes.ValueOrDie()) >
4638           pixels->byteLength()) {
4639     SynthesizeGLError(GL_INVALID_VALUE, "readPixels",
4640                       "destination offset out of range");
4641     return;
4642   }
4643   const char* reason = "framebuffer incomplete";
4644   WebGLFramebuffer* framebuffer = GetReadFramebufferBinding();
4645   if (framebuffer && framebuffer->CheckDepthStencilStatus(&reason) !=
4646                          GL_FRAMEBUFFER_COMPLETE) {
4647     SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, "readPixels", reason);
4648     return;
4649   }
4650   base::CheckedNumeric<GLuint> buffer_size =
4651       pixels->byteLength() - offset_in_bytes;
4652   if (!buffer_size.IsValid()) {
4653     SynthesizeGLError(GL_INVALID_VALUE, "readPixels",
4654                       "destination offset out of range");
4655     return;
4656   }
4657   if (!ValidateReadPixelsFuncParameters(width, height, format, type, pixels,
4658                                         buffer_size.ValueOrDie())) {
4659     return;
4660   }
4661   ClearIfComposited();
4662 
4663   uint8_t* data = static_cast<uint8_t*>(pixels->BaseAddressMaybeShared()) +
4664                   offset_in_bytes.ValueOrDie();
4665 
4666   // We add special handling here if the 'ArrayBufferView' is size '0' and the
4667   // backing store is 'nullptr'. 'ReadPixels' creates an error if the provided
4668   // data is 'nullptr'. However, in the case that we want to read zero pixels,
4669   // we want to avoid this error. Therefore we provide temporary memory here if
4670   // 'ArrayBufferView' does not provide a backing store but we actually read
4671   // zero pixels.
4672   base::Optional<Vector<uint8_t>> buffer;
4673   if (!data && (width == 0 || height == 0)) {
4674     buffer.emplace(32);
4675     data = buffer->data();
4676   }
4677   {
4678     ScopedDrawingBufferBinder binder(GetDrawingBuffer(), framebuffer);
4679     ContextGL()->ReadPixels(x, y, width, height, format, type, data);
4680   }
4681 }
4682 
RenderbufferStorageImpl(GLenum target,GLsizei samples,GLenum internalformat,GLsizei width,GLsizei height,const char * function_name)4683 void WebGLRenderingContextBase::RenderbufferStorageImpl(
4684     GLenum target,
4685     GLsizei samples,
4686     GLenum internalformat,
4687     GLsizei width,
4688     GLsizei height,
4689     const char* function_name) {
4690   DCHECK(!samples);             // |samples| > 0 is only valid in WebGL2's
4691                                 // renderbufferStorageMultisample().
4692   DCHECK(!IsWebGL2());          // Make sure this is overridden in WebGL 2.
4693   switch (internalformat) {
4694     case GL_DEPTH_COMPONENT16:
4695     case GL_RGBA4:
4696     case GL_RGB5_A1:
4697     case GL_RGB565:
4698     case GL_STENCIL_INDEX8:
4699       ContextGL()->RenderbufferStorage(target, internalformat, width, height);
4700       renderbuffer_binding_->SetInternalFormat(internalformat);
4701       renderbuffer_binding_->SetSize(width, height);
4702       break;
4703     case GL_SRGB8_ALPHA8_EXT:
4704       if (!ExtensionEnabled(kEXTsRGBName)) {
4705         SynthesizeGLError(GL_INVALID_ENUM, function_name, "sRGB not enabled");
4706         break;
4707       }
4708       ContextGL()->RenderbufferStorage(target, internalformat, width, height);
4709       renderbuffer_binding_->SetInternalFormat(internalformat);
4710       renderbuffer_binding_->SetSize(width, height);
4711       break;
4712     case GL_DEPTH_STENCIL_OES:
4713       DCHECK(IsDepthStencilSupported());
4714       ContextGL()->RenderbufferStorage(target, GL_DEPTH24_STENCIL8_OES, width,
4715                                        height);
4716       renderbuffer_binding_->SetSize(width, height);
4717       renderbuffer_binding_->SetInternalFormat(internalformat);
4718       break;
4719     default:
4720       SynthesizeGLError(GL_INVALID_ENUM, function_name,
4721                         "invalid internalformat");
4722       break;
4723   }
4724   UpdateNumberOfUserAllocatedMultisampledRenderbuffers(
4725       renderbuffer_binding_->UpdateMultisampleState(false));
4726 }
4727 
renderbufferStorage(GLenum target,GLenum internalformat,GLsizei width,GLsizei height)4728 void WebGLRenderingContextBase::renderbufferStorage(GLenum target,
4729                                                     GLenum internalformat,
4730                                                     GLsizei width,
4731                                                     GLsizei height) {
4732   const char* function_name = "renderbufferStorage";
4733   if (isContextLost())
4734     return;
4735   if (target != GL_RENDERBUFFER) {
4736     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
4737     return;
4738   }
4739   if (!renderbuffer_binding_ || !renderbuffer_binding_->Object()) {
4740     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
4741                       "no bound renderbuffer");
4742     return;
4743   }
4744   if (!ValidateSize(function_name, width, height))
4745     return;
4746   RenderbufferStorageImpl(target, 0, internalformat, width, height,
4747                           function_name);
4748   ApplyStencilTest();
4749 }
4750 
sampleCoverage(GLfloat value,GLboolean invert)4751 void WebGLRenderingContextBase::sampleCoverage(GLfloat value,
4752                                                GLboolean invert) {
4753   if (isContextLost())
4754     return;
4755   ContextGL()->SampleCoverage(value, invert);
4756 }
4757 
scissor(GLint x,GLint y,GLsizei width,GLsizei height)4758 void WebGLRenderingContextBase::scissor(GLint x,
4759                                         GLint y,
4760                                         GLsizei width,
4761                                         GLsizei height) {
4762   if (isContextLost())
4763     return;
4764   scissor_box_[0] = x;
4765   scissor_box_[1] = y;
4766   scissor_box_[2] = width;
4767   scissor_box_[3] = height;
4768   ContextGL()->Scissor(x, y, width, height);
4769 }
4770 
shaderSource(WebGLShader * shader,const String & string)4771 void WebGLRenderingContextBase::shaderSource(WebGLShader* shader,
4772                                              const String& string) {
4773   if (!ValidateWebGLProgramOrShader("shaderSource", shader))
4774     return;
4775   String string_without_comments = StripComments(string).Result();
4776   shader->SetSource(string);
4777   if (!string_without_comments.Is8Bit() ||
4778       !string_without_comments.ContainsOnlyASCIIOrEmpty()) {
4779     SynthesizeGLError(
4780         GL_INVALID_VALUE, "shaderSource",
4781         "Non ASCII character detected after comments are stripped.");
4782     return;
4783   }
4784   const GLchar* shader_data =
4785       reinterpret_cast<const GLchar*>(string_without_comments.Characters8());
4786   const GLint shader_length = string_without_comments.length();
4787   ContextGL()->ShaderSource(ObjectOrZero(shader), 1, &shader_data,
4788                             &shader_length);
4789 }
4790 
stencilFunc(GLenum func,GLint ref,GLuint mask)4791 void WebGLRenderingContextBase::stencilFunc(GLenum func,
4792                                             GLint ref,
4793                                             GLuint mask) {
4794   if (isContextLost())
4795     return;
4796   if (!ValidateStencilOrDepthFunc("stencilFunc", func))
4797     return;
4798   stencil_func_ref_ = ref;
4799   stencil_func_ref_back_ = ref;
4800   stencil_func_mask_ = mask;
4801   stencil_func_mask_back_ = mask;
4802   ContextGL()->StencilFunc(func, ref, mask);
4803 }
4804 
stencilFuncSeparate(GLenum face,GLenum func,GLint ref,GLuint mask)4805 void WebGLRenderingContextBase::stencilFuncSeparate(GLenum face,
4806                                                     GLenum func,
4807                                                     GLint ref,
4808                                                     GLuint mask) {
4809   if (isContextLost())
4810     return;
4811   if (!ValidateStencilOrDepthFunc("stencilFuncSeparate", func))
4812     return;
4813   switch (face) {
4814     case GL_FRONT_AND_BACK:
4815       stencil_func_ref_ = ref;
4816       stencil_func_ref_back_ = ref;
4817       stencil_func_mask_ = mask;
4818       stencil_func_mask_back_ = mask;
4819       break;
4820     case GL_FRONT:
4821       stencil_func_ref_ = ref;
4822       stencil_func_mask_ = mask;
4823       break;
4824     case GL_BACK:
4825       stencil_func_ref_back_ = ref;
4826       stencil_func_mask_back_ = mask;
4827       break;
4828     default:
4829       SynthesizeGLError(GL_INVALID_ENUM, "stencilFuncSeparate", "invalid face");
4830       return;
4831   }
4832   ContextGL()->StencilFuncSeparate(face, func, ref, mask);
4833 }
4834 
stencilMask(GLuint mask)4835 void WebGLRenderingContextBase::stencilMask(GLuint mask) {
4836   if (isContextLost())
4837     return;
4838   stencil_mask_ = mask;
4839   stencil_mask_back_ = mask;
4840   ContextGL()->StencilMask(mask);
4841 }
4842 
stencilMaskSeparate(GLenum face,GLuint mask)4843 void WebGLRenderingContextBase::stencilMaskSeparate(GLenum face, GLuint mask) {
4844   if (isContextLost())
4845     return;
4846   switch (face) {
4847     case GL_FRONT_AND_BACK:
4848       stencil_mask_ = mask;
4849       stencil_mask_back_ = mask;
4850       break;
4851     case GL_FRONT:
4852       stencil_mask_ = mask;
4853       break;
4854     case GL_BACK:
4855       stencil_mask_back_ = mask;
4856       break;
4857     default:
4858       SynthesizeGLError(GL_INVALID_ENUM, "stencilMaskSeparate", "invalid face");
4859       return;
4860   }
4861   ContextGL()->StencilMaskSeparate(face, mask);
4862 }
4863 
stencilOp(GLenum fail,GLenum zfail,GLenum zpass)4864 void WebGLRenderingContextBase::stencilOp(GLenum fail,
4865                                           GLenum zfail,
4866                                           GLenum zpass) {
4867   if (isContextLost())
4868     return;
4869   ContextGL()->StencilOp(fail, zfail, zpass);
4870 }
4871 
stencilOpSeparate(GLenum face,GLenum fail,GLenum zfail,GLenum zpass)4872 void WebGLRenderingContextBase::stencilOpSeparate(GLenum face,
4873                                                   GLenum fail,
4874                                                   GLenum zfail,
4875                                                   GLenum zpass) {
4876   if (isContextLost())
4877     return;
4878   ContextGL()->StencilOpSeparate(face, fail, zfail, zpass);
4879 }
4880 
ConvertTexInternalFormat(GLenum internalformat,GLenum type)4881 GLenum WebGLRenderingContextBase::ConvertTexInternalFormat(
4882     GLenum internalformat,
4883     GLenum type) {
4884   // Convert to sized internal formats that are renderable with
4885   // GL_CHROMIUM_color_buffer_float_rgb(a).
4886   if (type == GL_FLOAT && internalformat == GL_RGBA &&
4887       ExtensionsUtil()->IsExtensionEnabled(
4888           "GL_CHROMIUM_color_buffer_float_rgba"))
4889     return GL_RGBA32F_EXT;
4890   if (type == GL_FLOAT && internalformat == GL_RGB &&
4891       ExtensionsUtil()->IsExtensionEnabled(
4892           "GL_CHROMIUM_color_buffer_float_rgb"))
4893     return GL_RGB32F_EXT;
4894   return internalformat;
4895 }
4896 
TexImage2DBase(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const void * pixels)4897 void WebGLRenderingContextBase::TexImage2DBase(GLenum target,
4898                                                GLint level,
4899                                                GLint internalformat,
4900                                                GLsizei width,
4901                                                GLsizei height,
4902                                                GLint border,
4903                                                GLenum format,
4904                                                GLenum type,
4905                                                const void* pixels) {
4906   // All calling functions check isContextLost, so a duplicate check is not
4907   // needed here.
4908   ContextGL()->TexImage2D(target, level,
4909                           ConvertTexInternalFormat(internalformat, type), width,
4910                           height, border, format, type, pixels);
4911 }
4912 
4913 // Software-based upload of Image* to WebGL texture.
TexImageImpl(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLint xoffset,GLint yoffset,GLint zoffset,GLenum format,GLenum type,Image * image,WebGLImageConversion::ImageHtmlDomSource dom_source,bool flip_y,bool premultiply_alpha,const IntRect & source_image_rect,GLsizei depth,GLint unpack_image_height)4914 void WebGLRenderingContextBase::TexImageImpl(
4915     TexImageFunctionID function_id,
4916     GLenum target,
4917     GLint level,
4918     GLint internalformat,
4919     GLint xoffset,
4920     GLint yoffset,
4921     GLint zoffset,
4922     GLenum format,
4923     GLenum type,
4924     Image* image,
4925     WebGLImageConversion::ImageHtmlDomSource dom_source,
4926     bool flip_y,
4927     bool premultiply_alpha,
4928     const IntRect& source_image_rect,
4929     GLsizei depth,
4930     GLint unpack_image_height) {
4931   const char* func_name = GetTexImageFunctionName(function_id);
4932   // All calling functions check isContextLost, so a duplicate check is not
4933   // needed here.
4934   if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
4935     // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
4936     type = GL_FLOAT;
4937   }
4938   Vector<uint8_t> data;
4939 
4940   IntRect sub_rect = source_image_rect;
4941   if (sub_rect.IsValid() && sub_rect == SentinelEmptyRect()) {
4942     // Recalculate based on the size of the Image.
4943     sub_rect = SafeGetImageSize(image);
4944   }
4945 
4946   bool selecting_sub_rectangle = false;
4947   if (!ValidateTexImageSubRectangle(func_name, function_id, image, sub_rect,
4948                                     depth, unpack_image_height,
4949                                     &selecting_sub_rectangle)) {
4950     return;
4951   }
4952 
4953   // Adjust the source image rectangle if doing a y-flip.
4954   IntRect adjusted_source_image_rect = sub_rect;
4955   if (flip_y) {
4956     adjusted_source_image_rect.SetY(image->height() -
4957                                     adjusted_source_image_rect.MaxY());
4958   }
4959 
4960   WebGLImageConversion::ImageExtractor image_extractor(
4961       image, dom_source, premultiply_alpha,
4962       unpack_colorspace_conversion_ == GL_NONE);
4963   if (!image_extractor.ImagePixelData()) {
4964     SynthesizeGLError(GL_INVALID_VALUE, func_name, "bad image data");
4965     return;
4966   }
4967 
4968   WebGLImageConversion::DataFormat source_data_format =
4969       image_extractor.ImageSourceFormat();
4970   WebGLImageConversion::AlphaOp alpha_op = image_extractor.ImageAlphaOp();
4971   const void* image_pixel_data = image_extractor.ImagePixelData();
4972 
4973   bool need_conversion = true;
4974   if (type == GL_UNSIGNED_BYTE &&
4975       source_data_format == WebGLImageConversion::kDataFormatRGBA8 &&
4976       format == GL_RGBA && alpha_op == WebGLImageConversion::kAlphaDoNothing &&
4977       !flip_y && !selecting_sub_rectangle && depth == 1) {
4978     need_conversion = false;
4979   } else {
4980     if (!WebGLImageConversion::PackImageData(
4981             image, image_pixel_data, format, type, flip_y, alpha_op,
4982             source_data_format, image_extractor.ImageWidth(),
4983             image_extractor.ImageHeight(), adjusted_source_image_rect, depth,
4984             image_extractor.ImageSourceUnpackAlignment(), unpack_image_height,
4985             data)) {
4986       SynthesizeGLError(GL_INVALID_VALUE, func_name, "packImage error");
4987       return;
4988     }
4989   }
4990 
4991   ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
4992   if (function_id == kTexImage2D) {
4993     TexImage2DBase(target, level, internalformat,
4994                    adjusted_source_image_rect.Width(),
4995                    adjusted_source_image_rect.Height(), 0, format, type,
4996                    need_conversion ? data.data() : image_pixel_data);
4997   } else if (function_id == kTexSubImage2D) {
4998     ContextGL()->TexSubImage2D(
4999         target, level, xoffset, yoffset, adjusted_source_image_rect.Width(),
5000         adjusted_source_image_rect.Height(), format, type,
5001         need_conversion ? data.data() : image_pixel_data);
5002   } else {
5003     // 3D functions.
5004     if (function_id == kTexImage3D) {
5005       ContextGL()->TexImage3D(
5006           target, level, internalformat, adjusted_source_image_rect.Width(),
5007           adjusted_source_image_rect.Height(), depth, 0, format, type,
5008           need_conversion ? data.data() : image_pixel_data);
5009     } else {
5010       DCHECK_EQ(function_id, kTexSubImage3D);
5011       ContextGL()->TexSubImage3D(
5012           target, level, xoffset, yoffset, zoffset,
5013           adjusted_source_image_rect.Width(),
5014           adjusted_source_image_rect.Height(), depth, format, type,
5015           need_conversion ? data.data() : image_pixel_data);
5016     }
5017   }
5018 }
5019 
ValidateTexFunc(const char * function_name,TexImageFunctionType function_type,TexFuncValidationSourceType source_type,GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset)5020 bool WebGLRenderingContextBase::ValidateTexFunc(
5021     const char* function_name,
5022     TexImageFunctionType function_type,
5023     TexFuncValidationSourceType source_type,
5024     GLenum target,
5025     GLint level,
5026     GLenum internalformat,
5027     GLsizei width,
5028     GLsizei height,
5029     GLsizei depth,
5030     GLint border,
5031     GLenum format,
5032     GLenum type,
5033     GLint xoffset,
5034     GLint yoffset,
5035     GLint zoffset) {
5036   if (!ValidateTexFuncLevel(function_name, target, level))
5037     return false;
5038 
5039   if (!ValidateTexFuncParameters(function_name, function_type, source_type,
5040                                  target, level, internalformat, width, height,
5041                                  depth, border, format, type))
5042     return false;
5043 
5044   if (function_type == kTexSubImage) {
5045     if (!ValidateSettableTexFormat(function_name, format))
5046       return false;
5047     if (!ValidateSize(function_name, xoffset, yoffset, zoffset))
5048       return false;
5049   } else {
5050     // For SourceArrayBufferView, function validateTexFuncData() would handle
5051     // whether to validate the SettableTexFormat
5052     // by checking if the ArrayBufferView is null or not.
5053     if (source_type != kSourceArrayBufferView) {
5054       if (!ValidateSettableTexFormat(function_name, format))
5055         return false;
5056     }
5057   }
5058 
5059   return true;
5060 }
5061 
ValidateValueFitNonNegInt32(const char * function_name,const char * param_name,int64_t value)5062 bool WebGLRenderingContextBase::ValidateValueFitNonNegInt32(
5063     const char* function_name,
5064     const char* param_name,
5065     int64_t value) {
5066   if (value < 0) {
5067     String error_msg = String(param_name) + " < 0";
5068     SynthesizeGLError(GL_INVALID_VALUE, function_name,
5069                       error_msg.Ascii().c_str());
5070     return false;
5071   }
5072   if (value > static_cast<int64_t>(std::numeric_limits<int>::max())) {
5073     String error_msg = String(param_name) + " more than 32-bit";
5074     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
5075                       error_msg.Ascii().c_str());
5076     return false;
5077   }
5078   return true;
5079 }
5080 
5081 // TODO(fmalita): figure why WebGLImageConversion::ImageExtractor can't handle
5082 // SVG-backed images, and get rid of this intermediate step.
DrawImageIntoBuffer(scoped_refptr<Image> pass_image,int width,int height,const char * function_name)5083 scoped_refptr<Image> WebGLRenderingContextBase::DrawImageIntoBuffer(
5084     scoped_refptr<Image> pass_image,
5085     int width,
5086     int height,
5087     const char* function_name) {
5088   scoped_refptr<Image> image(std::move(pass_image));
5089   DCHECK(image);
5090 
5091   IntSize size(width, height);
5092   CanvasResourceProvider* resource_provider =
5093       generated_image_cache_.GetCanvasResourceProvider(size);
5094   if (!resource_provider) {
5095     SynthesizeGLError(GL_OUT_OF_MEMORY, function_name, "out of memory");
5096     return nullptr;
5097   }
5098 
5099   if (!image->CurrentFrameKnownToBeOpaque())
5100     resource_provider->Canvas()->clear(SK_ColorTRANSPARENT);
5101 
5102   IntRect src_rect(IntPoint(), image->Size());
5103   IntRect dest_rect(0, 0, size.Width(), size.Height());
5104   PaintFlags flags;
5105   // TODO(ccameron): WebGL should produce sRGB images.
5106   // https://crbug.com/672299
5107   image->Draw(resource_provider->Canvas(), flags, FloatRect(dest_rect),
5108               FloatRect(src_rect), kRespectImageOrientation,
5109               Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
5110   return resource_provider->Snapshot();
5111 }
5112 
ValidateTexImageBinding(const char * func_name,TexImageFunctionID function_id,GLenum target)5113 WebGLTexture* WebGLRenderingContextBase::ValidateTexImageBinding(
5114     const char* func_name,
5115     TexImageFunctionID function_id,
5116     GLenum target) {
5117   return ValidateTexture2DBinding(func_name, target);
5118 }
5119 
GetTexImageFunctionName(TexImageFunctionID func_name)5120 const char* WebGLRenderingContextBase::GetTexImageFunctionName(
5121     TexImageFunctionID func_name) {
5122   switch (func_name) {
5123     case kTexImage2D:
5124       return "texImage2D";
5125     case kTexSubImage2D:
5126       return "texSubImage2D";
5127     case kTexSubImage3D:
5128       return "texSubImage3D";
5129     case kTexImage3D:
5130       return "texImage3D";
5131     default:  // Adding default to prevent compile error
5132       return "";
5133   }
5134 }
5135 
SentinelEmptyRect()5136 IntRect WebGLRenderingContextBase::SentinelEmptyRect() {
5137   // Return a rectangle with -1 width and height so we can recognize
5138   // it later and recalculate it based on the Image whose data we'll
5139   // upload. It's important that there be no possible differences in
5140   // the logic which computes the image's size.
5141   return IntRect(0, 0, -1, -1);
5142 }
5143 
SafeGetImageSize(Image * image)5144 IntRect WebGLRenderingContextBase::SafeGetImageSize(Image* image) {
5145   if (!image)
5146     return IntRect();
5147 
5148   return GetTextureSourceSize(image);
5149 }
5150 
GetImageDataSize(ImageData * pixels)5151 IntRect WebGLRenderingContextBase::GetImageDataSize(ImageData* pixels) {
5152   DCHECK(pixels);
5153   return GetTextureSourceSize(pixels);
5154 }
5155 
TexImageHelperDOMArrayBufferView(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,DOMArrayBufferView * pixels,NullDisposition null_disposition,GLuint src_offset)5156 void WebGLRenderingContextBase::TexImageHelperDOMArrayBufferView(
5157     TexImageFunctionID function_id,
5158     GLenum target,
5159     GLint level,
5160     GLint internalformat,
5161     GLsizei width,
5162     GLsizei height,
5163     GLsizei depth,
5164     GLint border,
5165     GLenum format,
5166     GLenum type,
5167     GLint xoffset,
5168     GLint yoffset,
5169     GLint zoffset,
5170     DOMArrayBufferView* pixels,
5171     NullDisposition null_disposition,
5172     GLuint src_offset) {
5173   const char* func_name = GetTexImageFunctionName(function_id);
5174   if (isContextLost())
5175     return;
5176   if (!ValidateTexImageBinding(func_name, function_id, target))
5177     return;
5178   TexImageFunctionType function_type;
5179   if (function_id == kTexImage2D || function_id == kTexImage3D)
5180     function_type = kTexImage;
5181   else
5182     function_type = kTexSubImage;
5183   if (!ValidateTexFunc(func_name, function_type, kSourceArrayBufferView, target,
5184                        level, internalformat, width, height, depth, border,
5185                        format, type, xoffset, yoffset, zoffset))
5186     return;
5187   TexImageDimension source_type;
5188   if (function_id == kTexImage2D || function_id == kTexSubImage2D)
5189     source_type = kTex2D;
5190   else
5191     source_type = kTex3D;
5192   if (!ValidateTexFuncData(func_name, source_type, level, width, height, depth,
5193                            format, type, pixels, null_disposition, src_offset))
5194     return;
5195   uint8_t* data = reinterpret_cast<uint8_t*>(
5196       pixels ? pixels->BaseAddressMaybeShared() : nullptr);
5197   if (src_offset) {
5198     DCHECK(pixels);
5199     // No need to check overflow because validateTexFuncData() already did.
5200     data += src_offset * pixels->TypeSize();
5201   }
5202   Vector<uint8_t> temp_data;
5203   bool change_unpack_params = false;
5204   if (data && width && height &&
5205       (unpack_flip_y_ || unpack_premultiply_alpha_)) {
5206     DCHECK_EQ(kTex2D, source_type);
5207     // Only enter here if width or height is non-zero. Otherwise, call to the
5208     // underlying driver to generate appropriate GL errors if needed.
5209     WebGLImageConversion::PixelStoreParams unpack_params =
5210         GetUnpackPixelStoreParams(kTex2D);
5211     GLint data_store_width =
5212         unpack_params.row_length ? unpack_params.row_length : width;
5213     if (unpack_params.skip_pixels + width > data_store_width) {
5214       SynthesizeGLError(GL_INVALID_OPERATION, func_name,
5215                         "Invalid unpack params combination.");
5216       return;
5217     }
5218     if (!WebGLImageConversion::ExtractTextureData(
5219             width, height, format, type, unpack_params, unpack_flip_y_,
5220             unpack_premultiply_alpha_, data, temp_data)) {
5221       SynthesizeGLError(GL_INVALID_OPERATION, func_name,
5222                         "Invalid format/type combination.");
5223       return;
5224     }
5225     data = temp_data.data();
5226     change_unpack_params = true;
5227   }
5228   if (function_id == kTexImage3D) {
5229     ContextGL()->TexImage3D(target, level,
5230                             ConvertTexInternalFormat(internalformat, type),
5231                             width, height, depth, border, format, type, data);
5232     return;
5233   }
5234   if (function_id == kTexSubImage3D) {
5235     ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
5236                                height, depth, format, type, data);
5237     return;
5238   }
5239 
5240   ScopedUnpackParametersResetRestore temporary_reset_unpack(
5241       this, change_unpack_params);
5242   if (function_id == kTexImage2D)
5243     TexImage2DBase(target, level, internalformat, width, height, border, format,
5244                    type, data);
5245   else if (function_id == kTexSubImage2D)
5246     ContextGL()->TexSubImage2D(target, level, xoffset, yoffset, width, height,
5247                                format, type, data);
5248 }
5249 
texImage2D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,MaybeShared<DOMArrayBufferView> pixels)5250 void WebGLRenderingContextBase::texImage2D(
5251     GLenum target,
5252     GLint level,
5253     GLint internalformat,
5254     GLsizei width,
5255     GLsizei height,
5256     GLint border,
5257     GLenum format,
5258     GLenum type,
5259     MaybeShared<DOMArrayBufferView> pixels) {
5260   TexImageHelperDOMArrayBufferView(kTexImage2D, target, level, internalformat,
5261                                    width, height, 1, border, format, type, 0, 0,
5262                                    0, pixels.View(), kNullAllowed, 0);
5263 }
5264 
TexImageHelperImageData(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLint border,GLenum format,GLenum type,GLsizei depth,GLint xoffset,GLint yoffset,GLint zoffset,ImageData * pixels,const IntRect & source_image_rect,GLint unpack_image_height)5265 void WebGLRenderingContextBase::TexImageHelperImageData(
5266     TexImageFunctionID function_id,
5267     GLenum target,
5268     GLint level,
5269     GLint internalformat,
5270     GLint border,
5271     GLenum format,
5272     GLenum type,
5273     GLsizei depth,
5274     GLint xoffset,
5275     GLint yoffset,
5276     GLint zoffset,
5277     ImageData* pixels,
5278     const IntRect& source_image_rect,
5279     GLint unpack_image_height) {
5280   const char* func_name = GetTexImageFunctionName(function_id);
5281   if (isContextLost())
5282     return;
5283   DCHECK(pixels);
5284   DCHECK(!pixels->data().IsNull());
5285   if (pixels->BufferBase()->IsDetached()) {
5286     SynthesizeGLError(GL_INVALID_VALUE, func_name,
5287                       "The source data has been detached.");
5288     return;
5289   }
5290 
5291   if (!ValidateTexImageBinding(func_name, function_id, target))
5292     return;
5293   TexImageFunctionType function_type;
5294   if (function_id == kTexImage2D || function_id == kTexImage3D)
5295     function_type = kTexImage;
5296   else
5297     function_type = kTexSubImage;
5298   if (!ValidateTexFunc(func_name, function_type, kSourceImageData, target,
5299                        level, internalformat, pixels->width(), pixels->height(),
5300                        depth, border, format, type, xoffset, yoffset, zoffset))
5301     return;
5302 
5303   bool selecting_sub_rectangle = false;
5304   if (!ValidateTexImageSubRectangle(
5305           func_name, function_id, pixels, source_image_rect, depth,
5306           unpack_image_height, &selecting_sub_rectangle)) {
5307     return;
5308   }
5309   // Adjust the source image rectangle if doing a y-flip.
5310   IntRect adjusted_source_image_rect = source_image_rect;
5311   if (unpack_flip_y_) {
5312     adjusted_source_image_rect.SetY(pixels->height() -
5313                                     adjusted_source_image_rect.MaxY());
5314   }
5315 
5316   // TODO(crbug.com/1115317): Should be compatible with uint_8, float16 and
5317   // float32.
5318   Vector<uint8_t> data;
5319   bool need_conversion = true;
5320   // The data from ImageData is always of format RGBA8.
5321   // No conversion is needed if destination format is RGBA and type is
5322   // UNSIGNED_BYTE and no Flip or Premultiply operation is required.
5323   if (!unpack_flip_y_ && !unpack_premultiply_alpha_ && format == GL_RGBA &&
5324       type == GL_UNSIGNED_BYTE && !selecting_sub_rectangle && depth == 1) {
5325     need_conversion = false;
5326   } else {
5327     if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
5328       // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
5329       type = GL_FLOAT;
5330     }
5331     if (!WebGLImageConversion::ExtractImageData(
5332             pixels->data().GetAsUint8ClampedArray()->Data(),
5333             WebGLImageConversion::DataFormat::kDataFormatRGBA8, pixels->Size(),
5334             adjusted_source_image_rect, depth, unpack_image_height, format,
5335             type, unpack_flip_y_, unpack_premultiply_alpha_, data)) {
5336       SynthesizeGLError(GL_INVALID_VALUE, func_name, "bad image data");
5337       return;
5338     }
5339   }
5340   ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
5341   const uint8_t* bytes = need_conversion
5342                              ? data.data()
5343                              : pixels->data().GetAsUint8ClampedArray()->Data();
5344   if (function_id == kTexImage2D) {
5345     DCHECK_EQ(unpack_image_height, 0);
5346     TexImage2DBase(
5347         target, level, internalformat, adjusted_source_image_rect.Width(),
5348         adjusted_source_image_rect.Height(), border, format, type, bytes);
5349   } else if (function_id == kTexSubImage2D) {
5350     DCHECK_EQ(unpack_image_height, 0);
5351     ContextGL()->TexSubImage2D(
5352         target, level, xoffset, yoffset, adjusted_source_image_rect.Width(),
5353         adjusted_source_image_rect.Height(), format, type, bytes);
5354   } else {
5355     GLint upload_height = adjusted_source_image_rect.Height();
5356     if (function_id == kTexImage3D) {
5357       ContextGL()->TexImage3D(target, level, internalformat,
5358                               adjusted_source_image_rect.Width(), upload_height,
5359                               depth, border, format, type, bytes);
5360     } else {
5361       DCHECK_EQ(function_id, kTexSubImage3D);
5362       ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset,
5363                                  adjusted_source_image_rect.Width(),
5364                                  upload_height, depth, format, type, bytes);
5365     }
5366   }
5367 }
5368 
texImage2D(GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,ImageData * pixels)5369 void WebGLRenderingContextBase::texImage2D(GLenum target,
5370                                            GLint level,
5371                                            GLint internalformat,
5372                                            GLenum format,
5373                                            GLenum type,
5374                                            ImageData* pixels) {
5375   TexImageHelperImageData(kTexImage2D, target, level, internalformat, 0, format,
5376                           type, 1, 0, 0, 0, pixels, GetImageDataSize(pixels),
5377                           0);
5378 }
5379 
TexImageHelperHTMLImageElement(const SecurityOrigin * security_origin,TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,HTMLImageElement * image,const IntRect & source_image_rect,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5380 void WebGLRenderingContextBase::TexImageHelperHTMLImageElement(
5381     const SecurityOrigin* security_origin,
5382     TexImageFunctionID function_id,
5383     GLenum target,
5384     GLint level,
5385     GLint internalformat,
5386     GLenum format,
5387     GLenum type,
5388     GLint xoffset,
5389     GLint yoffset,
5390     GLint zoffset,
5391     HTMLImageElement* image,
5392     const IntRect& source_image_rect,
5393     GLsizei depth,
5394     GLint unpack_image_height,
5395     ExceptionState& exception_state) {
5396   const char* func_name = GetTexImageFunctionName(function_id);
5397   if (isContextLost())
5398     return;
5399 
5400   if (!ValidateHTMLImageElement(security_origin, func_name, image,
5401                                 exception_state))
5402     return;
5403   if (!ValidateTexImageBinding(func_name, function_id, target))
5404     return;
5405 
5406   scoped_refptr<Image> image_for_render = image->CachedImage()->GetImage();
5407   bool have_svg_image = IsA<SVGImage>(image_for_render.get());
5408   if (have_svg_image || !image_for_render->HasDefaultOrientation()) {
5409     if (have_svg_image && canvas()) {
5410       UseCounter::Count(canvas()->GetDocument(), WebFeature::kSVGInWebGL);
5411     }
5412     // DrawImageIntoBuffer always respects orientation
5413     image_for_render =
5414         DrawImageIntoBuffer(std::move(image_for_render), image->width(),
5415                             image->height(), func_name);
5416   }
5417 
5418   TexImageFunctionType function_type;
5419   if (function_id == kTexImage2D || function_id == kTexImage3D)
5420     function_type = kTexImage;
5421   else
5422     function_type = kTexSubImage;
5423   if (!image_for_render ||
5424       !ValidateTexFunc(func_name, function_type, kSourceHTMLImageElement,
5425                        target, level, internalformat, image_for_render->width(),
5426                        image_for_render->height(), depth, 0, format, type,
5427                        xoffset, yoffset, zoffset))
5428     return;
5429 
5430   TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
5431                zoffset, format, type, image_for_render.get(),
5432                WebGLImageConversion::kHtmlDomImage, unpack_flip_y_,
5433                unpack_premultiply_alpha_, source_image_rect, depth,
5434                unpack_image_height);
5435 }
5436 
texImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,HTMLImageElement * image,ExceptionState & exception_state)5437 void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
5438                                            GLenum target,
5439                                            GLint level,
5440                                            GLint internalformat,
5441                                            GLenum format,
5442                                            GLenum type,
5443                                            HTMLImageElement* image,
5444                                            ExceptionState& exception_state) {
5445   TexImageHelperHTMLImageElement(execution_context->GetSecurityOrigin(),
5446                                  kTexImage2D, target, level, internalformat,
5447                                  format, type, 0, 0, 0, image,
5448                                  SentinelEmptyRect(), 1, 0, exception_state);
5449 }
5450 
CanUseTexImageViaGPU(GLenum format,GLenum type)5451 bool WebGLRenderingContextBase::CanUseTexImageViaGPU(GLenum format,
5452                                                      GLenum type) {
5453 #if defined(OS_MAC)
5454   // RGB5_A1 is not color-renderable on NVIDIA Mac, see crbug.com/676209.
5455   // Though, glCopyTextureCHROMIUM can handle RGB5_A1 internalformat by doing a
5456   // fallback path, but it doesn't know the type info. So, we still cannot do
5457   // the fallback path in glCopyTextureCHROMIUM for
5458   // RGBA/RGBA/UNSIGNED_SHORT_5_5_5_1 format and type combination.
5459   if (type == GL_UNSIGNED_SHORT_5_5_5_1)
5460     return false;
5461 #endif
5462 
5463   // TODO(kbr): continued bugs are seen on Linux with AMD's drivers handling
5464   // uploads to R8UI textures. crbug.com/710673
5465   if (format == GL_RED_INTEGER)
5466     return false;
5467 
5468 #if defined(OS_ANDROID)
5469   // TODO(kbr): bugs were seen on Android devices with NVIDIA GPUs
5470   // when copying hardware-accelerated video textures to
5471   // floating-point textures. Investigate the root cause of this and
5472   // fix it. crbug.com/710874
5473   if (type == GL_FLOAT)
5474     return false;
5475 #endif
5476 
5477   // OES_texture_half_float doesn't support HALF_FLOAT_OES type for
5478   // CopyTexImage/CopyTexSubImage. And OES_texture_half_float doesn't require
5479   // HALF_FLOAT_OES type texture to be renderable. So, HALF_FLOAT_OES type
5480   // texture cannot be copied to or drawn to by glCopyTextureCHROMIUM.
5481   if (type == GL_HALF_FLOAT_OES)
5482     return false;
5483 
5484   return true;
5485 }
5486 
TexImageViaGPU(TexImageFunctionID function_id,WebGLTexture * texture,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,AcceleratedStaticBitmapImage * source_image,WebGLRenderingContextBase * source_canvas_webgl_context,const IntRect & source_sub_rectangle,bool premultiply_alpha,bool flip_y)5487 void WebGLRenderingContextBase::TexImageViaGPU(
5488     TexImageFunctionID function_id,
5489     WebGLTexture* texture,
5490     GLenum target,
5491     GLint level,
5492     GLint xoffset,
5493     GLint yoffset,
5494     GLint zoffset,
5495     AcceleratedStaticBitmapImage* source_image,
5496     WebGLRenderingContextBase* source_canvas_webgl_context,
5497     const IntRect& source_sub_rectangle,
5498     bool premultiply_alpha,
5499     bool flip_y) {
5500   bool have_source_image = source_image;
5501   bool have_source_canvas_webgl_context = source_canvas_webgl_context;
5502   DCHECK(have_source_image ^ have_source_canvas_webgl_context);
5503 
5504   int width = source_sub_rectangle.Width();
5505   int height = source_sub_rectangle.Height();
5506 
5507   ScopedTexture2DRestorer restorer(this);
5508 
5509   GLuint target_texture = texture->Object();
5510   bool possible_direct_copy = false;
5511   if (function_id == kTexImage2D || function_id == kTexSubImage2D) {
5512     possible_direct_copy = Extensions3DUtil::CanUseCopyTextureCHROMIUM(target);
5513   }
5514 
5515   GLint copy_x_offset = xoffset;
5516   GLint copy_y_offset = yoffset;
5517   GLenum copy_target = target;
5518 
5519   // if direct copy is not possible, create a temporary texture and then copy
5520   // from canvas to temporary texture to target texture.
5521   if (!possible_direct_copy) {
5522     ContextGL()->GenTextures(1, &target_texture);
5523     ContextGL()->BindTexture(GL_TEXTURE_2D, target_texture);
5524     ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
5525                                GL_NEAREST);
5526     ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
5527                                GL_NEAREST);
5528     ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
5529                                GL_CLAMP_TO_EDGE);
5530     ContextGL()->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
5531                                GL_CLAMP_TO_EDGE);
5532     ContextGL()->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
5533                             GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
5534     copy_x_offset = 0;
5535     copy_y_offset = 0;
5536     copy_target = GL_TEXTURE_2D;
5537   }
5538 
5539   {
5540     // glCopyTextureCHROMIUM has a DRAW_AND_READBACK path which will call
5541     // texImage2D. So, reset unpack buffer parameters before that.
5542     ScopedUnpackParametersResetRestore temporaryResetUnpack(this);
5543     if (source_image) {
5544       source_image->CopyToTexture(
5545           ContextGL(), target, target_texture, level, premultiply_alpha, flip_y,
5546           IntPoint(xoffset, yoffset), source_sub_rectangle);
5547     } else {
5548       WebGLRenderingContextBase* gl = source_canvas_webgl_context;
5549       if (gl->is_origin_top_left_ && !canvas()->LowLatencyEnabled())
5550         flip_y = !flip_y;
5551       ScopedTexture2DRestorer inner_restorer(gl);
5552       if (!gl->GetDrawingBuffer()->CopyToPlatformTexture(
5553               ContextGL(), target, target_texture, level,
5554               unpack_premultiply_alpha_, !flip_y, IntPoint(xoffset, yoffset),
5555               source_sub_rectangle, kBackBuffer)) {
5556         NOTREACHED();
5557       }
5558     }
5559   }
5560 
5561   if (!possible_direct_copy) {
5562     GLuint tmp_fbo;
5563     ContextGL()->GenFramebuffers(1, &tmp_fbo);
5564     ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, tmp_fbo);
5565     ContextGL()->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
5566                                       GL_TEXTURE_2D, target_texture, 0);
5567     ContextGL()->BindTexture(texture->GetTarget(), texture->Object());
5568     if (function_id == kTexImage2D) {
5569       ContextGL()->CopyTexSubImage2D(target, level, 0, 0, 0, 0, width, height);
5570     } else if (function_id == kTexSubImage2D) {
5571       ContextGL()->CopyTexSubImage2D(target, level, xoffset, yoffset, 0, 0,
5572                                      width, height);
5573     } else if (function_id == kTexSubImage3D) {
5574       ContextGL()->CopyTexSubImage3D(target, level, xoffset, yoffset, zoffset,
5575                                      0, 0, width, height);
5576     }
5577     ContextGL()->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
5578                                       GL_TEXTURE_2D, 0, 0);
5579     RestoreCurrentFramebuffer();
5580     ContextGL()->DeleteFramebuffers(1, &tmp_fbo);
5581     ContextGL()->DeleteTextures(1, &target_texture);
5582   }
5583 }
5584 
TexImageHelperCanvasRenderingContextHost(const SecurityOrigin * security_origin,TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,CanvasRenderingContextHost * context_host,const IntRect & source_sub_rectangle,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5585 void WebGLRenderingContextBase::TexImageHelperCanvasRenderingContextHost(
5586     const SecurityOrigin* security_origin,
5587     TexImageFunctionID function_id,
5588     GLenum target,
5589     GLint level,
5590     GLint internalformat,
5591     GLenum format,
5592     GLenum type,
5593     GLint xoffset,
5594     GLint yoffset,
5595     GLint zoffset,
5596     CanvasRenderingContextHost* context_host,
5597     const IntRect& source_sub_rectangle,
5598     GLsizei depth,
5599     GLint unpack_image_height,
5600     ExceptionState& exception_state) {
5601   const char* func_name = GetTexImageFunctionName(function_id);
5602   if (isContextLost())
5603     return;
5604 
5605   if (!ValidateCanvasRenderingContextHost(security_origin, func_name,
5606                                           context_host, exception_state))
5607     return;
5608   WebGLTexture* texture =
5609       ValidateTexImageBinding(func_name, function_id, target);
5610   if (!texture)
5611     return;
5612   TexImageFunctionType function_type;
5613   if (function_id == kTexImage2D)
5614     function_type = kTexImage;
5615   else
5616     function_type = kTexSubImage;
5617   if (!ValidateTexFunc(func_name, function_type, kSourceHTMLCanvasElement,
5618                        target, level, internalformat,
5619                        source_sub_rectangle.Width(),
5620                        source_sub_rectangle.Height(), depth, 0, format, type,
5621                        xoffset, yoffset, zoffset))
5622     return;
5623 
5624   // Note that the sub-rectangle validation is needed for the GPU-GPU
5625   // copy case, but is redundant for the software upload case
5626   // (texImageImpl).
5627   bool selecting_sub_rectangle = false;
5628   if (!ValidateTexImageSubRectangle(
5629           func_name, function_id, context_host, source_sub_rectangle, depth,
5630           unpack_image_height, &selecting_sub_rectangle)) {
5631     return;
5632   }
5633 
5634   bool is_webgl_canvas = context_host->Is3d();
5635   WebGLRenderingContextBase* source_canvas_webgl_context = nullptr;
5636   SourceImageStatus source_image_status = kInvalidSourceImageStatus;
5637   scoped_refptr<Image> image;
5638 
5639   bool upload_via_gpu =
5640       (function_id == kTexImage2D || function_id == kTexSubImage2D) &&
5641       CanUseTexImageViaGPU(format, type);
5642 
5643   // The Image-based upload path may still be used for WebGL-rendered
5644   // canvases in the case of driver bug workarounds
5645   // (e.g. CanUseTexImageViaGPU returning false).
5646   if (is_webgl_canvas && upload_via_gpu) {
5647     source_canvas_webgl_context =
5648         To<WebGLRenderingContextBase>(context_host->RenderingContext());
5649   } else {
5650     image = context_host->GetSourceImageForCanvas(
5651         &source_image_status,
5652         FloatSize(source_sub_rectangle.Width(), source_sub_rectangle.Height()));
5653     if (source_image_status != kNormalSourceImageStatus)
5654       return;
5655   }
5656 
5657   // Still not clear whether we will take the accelerated upload path
5658   // at this point; it depends on what came back from
5659   // CanUseTexImageViaGPU, for example.
5660   auto* static_bitmap_image = DynamicTo<StaticBitmapImage>(image.get());
5661   upload_via_gpu &= source_canvas_webgl_context ||
5662                     (static_bitmap_image && image->IsTextureBacked());
5663 
5664   if (upload_via_gpu) {
5665     AcceleratedStaticBitmapImage* accel_image = nullptr;
5666     if (image) {
5667       accel_image =
5668           static_cast<AcceleratedStaticBitmapImage*>(static_bitmap_image);
5669     }
5670 
5671     // The GPU-GPU copy path uses the Y-up coordinate system.
5672     IntRect adjusted_source_sub_rectangle = source_sub_rectangle;
5673 
5674     bool should_adjust_source_sub_rectangle = !unpack_flip_y_;
5675     if (is_origin_top_left_ && source_canvas_webgl_context)
5676       should_adjust_source_sub_rectangle = !should_adjust_source_sub_rectangle;
5677 
5678     if (should_adjust_source_sub_rectangle) {
5679       adjusted_source_sub_rectangle.SetY(context_host->Size().Height() -
5680                                          adjusted_source_sub_rectangle.MaxY());
5681     }
5682 
5683     if (function_id == kTexImage2D) {
5684       TexImage2DBase(target, level, internalformat,
5685                      source_sub_rectangle.Width(),
5686                      source_sub_rectangle.Height(), 0, format, type, nullptr);
5687       TexImageViaGPU(function_id, texture, target, level, 0, 0, 0, accel_image,
5688                      source_canvas_webgl_context, adjusted_source_sub_rectangle,
5689                      unpack_premultiply_alpha_, unpack_flip_y_);
5690     } else {
5691       TexImageViaGPU(function_id, texture, target, level, xoffset, yoffset, 0,
5692                      accel_image, source_canvas_webgl_context,
5693                      adjusted_source_sub_rectangle, unpack_premultiply_alpha_,
5694                      unpack_flip_y_);
5695     }
5696   } else {
5697     // If these are the 2D functions, the caller must have passed in 1
5698     // for the depth and 0 for the unpack_image_height.
5699     DCHECK(!(function_id == kTexSubImage2D || function_id == kTexSubImage2D) ||
5700            (depth == 1 && unpack_image_height == 0));
5701     // We expect an Image at this point, not a WebGL-rendered canvas.
5702     DCHECK(image);
5703     // TODO(crbug.com/612542): Implement GPU-to-GPU copy path for more
5704     // cases, like copying to layers of 3D textures, and elements of
5705     // 2D texture arrays.
5706     bool flip_y = unpack_flip_y_;
5707     if (is_origin_top_left_ && is_webgl_canvas)
5708       flip_y = !flip_y;
5709 
5710     TexImageImpl(function_id, target, level, internalformat, xoffset, yoffset,
5711                  zoffset, format, type, image.get(),
5712                  WebGLImageConversion::kHtmlDomCanvas, flip_y,
5713                  unpack_premultiply_alpha_, source_sub_rectangle, depth,
5714                  unpack_image_height);
5715   }
5716 }
5717 
texImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,CanvasRenderingContextHost * context_host,ExceptionState & exception_state)5718 void WebGLRenderingContextBase::texImage2D(
5719     ExecutionContext* execution_context,
5720     GLenum target,
5721     GLint level,
5722     GLint internalformat,
5723     GLenum format,
5724     GLenum type,
5725     CanvasRenderingContextHost* context_host,
5726     ExceptionState& exception_state) {
5727   TexImageHelperCanvasRenderingContextHost(
5728       execution_context->GetSecurityOrigin(), kTexImage2D, target, level,
5729       internalformat, format, type, 0, 0, 0, context_host,
5730       GetTextureSourceSize(context_host), 1, 0, exception_state);
5731 }
5732 
VideoFrameToImage(HTMLVideoElement * video,int already_uploaded_id,WebMediaPlayer::VideoFrameUploadMetadata * out_metadata)5733 scoped_refptr<Image> WebGLRenderingContextBase::VideoFrameToImage(
5734     HTMLVideoElement* video,
5735     int already_uploaded_id,
5736     WebMediaPlayer::VideoFrameUploadMetadata* out_metadata) {
5737   const IntSize& visible_size = video->videoVisibleSize();
5738   if (visible_size.IsEmpty()) {
5739     SynthesizeGLError(GL_INVALID_VALUE, "tex(Sub)Image2D",
5740                       "video visible size is empty");
5741     return nullptr;
5742   }
5743   CanvasResourceProvider* resource_provider =
5744       generated_image_cache_.GetCanvasResourceProvider(visible_size);
5745   if (!resource_provider) {
5746     SynthesizeGLError(GL_OUT_OF_MEMORY, "texImage2D", "out of memory");
5747     return nullptr;
5748   }
5749   IntRect dest_rect(0, 0, visible_size.Width(), visible_size.Height());
5750   video->PaintCurrentFrame(resource_provider->Canvas(), dest_rect, nullptr,
5751                            already_uploaded_id, out_metadata);
5752   return resource_provider->Snapshot();
5753 }
5754 
TexImageHelperHTMLVideoElement(const SecurityOrigin * security_origin,TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,HTMLVideoElement * video,const IntRect & source_image_rect,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5755 void WebGLRenderingContextBase::TexImageHelperHTMLVideoElement(
5756     const SecurityOrigin* security_origin,
5757     TexImageFunctionID function_id,
5758     GLenum target,
5759     GLint level,
5760     GLint internalformat,
5761     GLenum format,
5762     GLenum type,
5763     GLint xoffset,
5764     GLint yoffset,
5765     GLint zoffset,
5766     HTMLVideoElement* video,
5767     const IntRect& source_image_rect,
5768     GLsizei depth,
5769     GLint unpack_image_height,
5770     ExceptionState& exception_state) {
5771   const char* func_name = GetTexImageFunctionName(function_id);
5772   if (isContextLost())
5773     return;
5774 
5775   if (!ValidateHTMLVideoElement(security_origin, func_name, video,
5776                                 exception_state))
5777     return;
5778   WebGLTexture* texture =
5779       ValidateTexImageBinding(func_name, function_id, target);
5780   if (!texture)
5781     return;
5782   TexImageFunctionType function_type;
5783   if (function_id == kTexImage2D || function_id == kTexImage3D)
5784     function_type = kTexImage;
5785   else
5786     function_type = kTexSubImage;
5787   if (!ValidateTexFunc(func_name, function_type, kSourceHTMLVideoElement,
5788                        target, level, internalformat, video->videoWidth(),
5789                        video->videoHeight(), 1, 0, format, type, xoffset,
5790                        yoffset, zoffset))
5791     return;
5792 
5793   GLint adjusted_internalformat =
5794       ConvertTexInternalFormat(internalformat, type);
5795 
5796   // For WebGL last-uploaded-frame-metadata API. https://crbug.com/639174
5797   WebMediaPlayer::VideoFrameUploadMetadata frame_metadata = {};
5798   int already_uploaded_id = -1;
5799   WebMediaPlayer::VideoFrameUploadMetadata* frame_metadata_ptr = nullptr;
5800   if (RuntimeEnabledFeatures::ExtraWebGLVideoTextureMetadataEnabled()) {
5801     already_uploaded_id = texture->GetLastUploadedVideoFrameId();
5802     frame_metadata_ptr = &frame_metadata;
5803   }
5804 
5805   if (!source_image_rect.IsValid()) {
5806     SynthesizeGLError(GL_INVALID_OPERATION, func_name,
5807                       "source sub-rectangle specified via pixel unpack "
5808                       "parameters is invalid");
5809     return;
5810   }
5811   bool source_image_rect_is_default =
5812       source_image_rect == SentinelEmptyRect() ||
5813       source_image_rect ==
5814           IntRect(0, 0, video->videoWidth(), video->videoHeight());
5815 
5816   const auto& caps = GetDrawingBuffer()->ContextProvider()->GetCapabilities();
5817   const bool may_need_image_external_essl3 =
5818       caps.egl_image_external &&
5819       Extensions3DUtil::CopyTextureCHROMIUMNeedsESSL3(internalformat);
5820   const bool have_image_external_essl3 = caps.egl_image_external_essl3;
5821   const bool use_copyTextureCHROMIUM =
5822       function_id == kTexImage2D && source_image_rect_is_default &&
5823       depth == 1 && GL_TEXTURE_2D == target &&
5824       (have_image_external_essl3 || !may_need_image_external_essl3) &&
5825       CanUseTexImageViaGPU(format, type);
5826 
5827   // Format of source video may be 16-bit format, e.g. Y16 format.
5828   // glCopyTextureCHROMIUM requires the source texture to be in 8-bit format.
5829   // Converting 16-bits formated source texture to 8-bits formated texture will
5830   // cause precision lost. So, uploading such video texture to half float or
5831   // float texture can not use GPU-GPU path.
5832   if (use_copyTextureCHROMIUM) {
5833     DCHECK(Extensions3DUtil::CanUseCopyTextureCHROMIUM(target));
5834     DCHECK_EQ(xoffset, 0);
5835     DCHECK_EQ(yoffset, 0);
5836     DCHECK_EQ(zoffset, 0);
5837     // Go through the fast path doing a GPU-GPU textures copy without a readback
5838     // to system memory if possible.  Otherwise, it will fall back to the normal
5839     // SW path.
5840 
5841     if (video->CopyVideoTextureToPlatformTexture(
5842             ContextGL(), target, texture->Object(), adjusted_internalformat,
5843             format, type, level, unpack_premultiply_alpha_, unpack_flip_y_,
5844             already_uploaded_id, frame_metadata_ptr)) {
5845       texture->UpdateLastUploadedFrame(frame_metadata);
5846       return;
5847     }
5848 
5849     // For certain video frame formats (e.g. I420/YUV), if they start on the CPU
5850     // (e.g. video camera frames): upload them to the GPU, do a GPU decode, and
5851     // then copy into the target texture.
5852     if (video->CopyVideoYUVDataToPlatformTexture(
5853             ContextGL(), target, texture->Object(), adjusted_internalformat,
5854             format, type, level, unpack_premultiply_alpha_, unpack_flip_y_,
5855             already_uploaded_id, frame_metadata_ptr)) {
5856       texture->UpdateLastUploadedFrame(frame_metadata);
5857       return;
5858     }
5859   }
5860 
5861   if (source_image_rect_is_default) {
5862     // Try using optimized CPU-GPU path for some formats: e.g. Y16 and Y8. It
5863     // leaves early for other formats or if frame is stored on GPU.
5864     ScopedUnpackParametersResetRestore unpack_params(
5865         this, unpack_flip_y_ || unpack_premultiply_alpha_);
5866     if (video->TexImageImpl(
5867             static_cast<WebMediaPlayer::TexImageFunctionID>(function_id),
5868             target, ContextGL(), texture->Object(), level,
5869             adjusted_internalformat, format, type, xoffset, yoffset, zoffset,
5870             unpack_flip_y_,
5871             unpack_premultiply_alpha_ &&
5872                 unpack_colorspace_conversion_ == GL_NONE)) {
5873       texture->ClearLastUploadedFrame();
5874       return;
5875     }
5876   }
5877 
5878   scoped_refptr<Image> image =
5879       VideoFrameToImage(video, already_uploaded_id, frame_metadata_ptr);
5880   if (!image)
5881     return;
5882   TexImageImpl(function_id, target, level, adjusted_internalformat, xoffset,
5883                yoffset, zoffset, format, type, image.get(),
5884                WebGLImageConversion::kHtmlDomVideo, unpack_flip_y_,
5885                unpack_premultiply_alpha_, source_image_rect, depth,
5886                unpack_image_height);
5887   texture->UpdateLastUploadedFrame(frame_metadata);
5888 }
5889 
texImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,HTMLVideoElement * video,ExceptionState & exception_state)5890 void WebGLRenderingContextBase::texImage2D(ExecutionContext* execution_context,
5891                                            GLenum target,
5892                                            GLint level,
5893                                            GLint internalformat,
5894                                            GLenum format,
5895                                            GLenum type,
5896                                            HTMLVideoElement* video,
5897                                            ExceptionState& exception_state) {
5898   TexImageHelperHTMLVideoElement(execution_context->GetSecurityOrigin(),
5899                                  kTexImage2D, target, level, internalformat,
5900                                  format, type, 0, 0, 0, video,
5901                                  SentinelEmptyRect(), 1, 0, exception_state);
5902 }
5903 
TexImageHelperImageBitmap(TexImageFunctionID function_id,GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,GLint xoffset,GLint yoffset,GLint zoffset,ImageBitmap * bitmap,const IntRect & source_sub_rect,GLsizei depth,GLint unpack_image_height,ExceptionState & exception_state)5904 void WebGLRenderingContextBase::TexImageHelperImageBitmap(
5905     TexImageFunctionID function_id,
5906     GLenum target,
5907     GLint level,
5908     GLint internalformat,
5909     GLenum format,
5910     GLenum type,
5911     GLint xoffset,
5912     GLint yoffset,
5913     GLint zoffset,
5914     ImageBitmap* bitmap,
5915     const IntRect& source_sub_rect,
5916     GLsizei depth,
5917     GLint unpack_image_height,
5918     ExceptionState& exception_state) {
5919   const char* func_name = GetTexImageFunctionName(function_id);
5920   if (isContextLost())
5921     return;
5922   if (!ValidateImageBitmap(func_name, bitmap, exception_state))
5923     return;
5924   WebGLTexture* texture =
5925       ValidateTexImageBinding(func_name, function_id, target);
5926   if (!texture)
5927     return;
5928 
5929   bool selecting_sub_rectangle = false;
5930   if (!ValidateTexImageSubRectangle(func_name, function_id, bitmap,
5931                                     source_sub_rect, depth, unpack_image_height,
5932                                     &selecting_sub_rectangle)) {
5933     return;
5934   }
5935 
5936   TexImageFunctionType function_type;
5937   if (function_id == kTexImage2D)
5938     function_type = kTexImage;
5939   else
5940     function_type = kTexSubImage;
5941 
5942   GLsizei width = source_sub_rect.Width();
5943   GLsizei height = source_sub_rect.Height();
5944   if (!ValidateTexFunc(func_name, function_type, kSourceImageBitmap, target,
5945                        level, internalformat, width, height, depth, 0, format,
5946                        type, xoffset, yoffset, zoffset))
5947     return;
5948 
5949   scoped_refptr<StaticBitmapImage> image = bitmap->BitmapImage();
5950   DCHECK(image);
5951 
5952   // TODO(kbr): make this work for sub-rectangles of ImageBitmaps.
5953   if (function_id != kTexSubImage3D && function_id != kTexImage3D &&
5954       image->IsTextureBacked() && CanUseTexImageViaGPU(format, type) &&
5955       !selecting_sub_rectangle) {
5956     AcceleratedStaticBitmapImage* accel_image =
5957         static_cast<AcceleratedStaticBitmapImage*>(image.get());
5958     // We hard-code premultiply_alpha and flip_y values because these should
5959     // have already been manipulated during construction of the ImageBitmap.
5960     bool premultiply_alpha = true;  // TODO(kbr): this looks wrong!
5961     bool flip_y = false;
5962     if (function_id == kTexImage2D) {
5963       TexImage2DBase(target, level, internalformat, width, height, 0, format,
5964                      type, nullptr);
5965       TexImageViaGPU(function_id, texture, target, level, 0, 0, 0, accel_image,
5966                      nullptr, source_sub_rect, premultiply_alpha, flip_y);
5967     } else if (function_id == kTexSubImage2D) {
5968       TexImageViaGPU(function_id, texture, target, level, xoffset, yoffset, 0,
5969                      accel_image, nullptr, source_sub_rect, premultiply_alpha,
5970                      flip_y);
5971     }
5972     return;
5973   }
5974 
5975   // Apply orientation if necessary
5976   PaintImage paint_image = bitmap->BitmapImage()->PaintImageForCurrentFrame();
5977   if (!image->HasDefaultOrientation()) {
5978     paint_image = Image::ResizeAndOrientImage(
5979         paint_image, image->CurrentFrameOrientation(), FloatSize(1, 1), 1,
5980         kInterpolationNone);
5981   }
5982 
5983   // TODO(kbr): refactor this away to use TexImageImpl on image.
5984   sk_sp<SkImage> sk_image = paint_image.GetSwSkImage();
5985   if (!sk_image) {
5986     SynthesizeGLError(GL_OUT_OF_MEMORY, func_name,
5987                       "ImageBitmap unexpectedly empty");
5988     return;
5989   }
5990 
5991   SkPixmap pixmap;
5992   uint8_t* pixel_data_ptr = nullptr;
5993   Vector<uint8_t> pixel_data;
5994   // PaintImage::GetSwSkImage() can return a lazily generated image which will
5995   // cause peekPixels() to fail. In that case we use CopyBitmapData to force
5996   // image generation.
5997   bool peek_succeed = sk_image->peekPixels(&pixmap);
5998   if (peek_succeed) {
5999     pixel_data_ptr = static_cast<uint8_t*>(pixmap.writable_addr());
6000   } else {
6001     pixel_data = bitmap->CopyBitmapData(
6002         bitmap->IsPremultiplied() ? kPremultiplyAlpha : kUnpremultiplyAlpha);
6003     pixel_data_ptr = pixel_data.data();
6004   }
6005   Vector<uint8_t> data;
6006   bool need_conversion = true;
6007   bool have_peekable_rgba =
6008       (peek_succeed &&
6009        pixmap.colorType() == SkColorType::kRGBA_8888_SkColorType);
6010   bool is_pixel_data_rgba = (have_peekable_rgba || !peek_succeed);
6011   if (is_pixel_data_rgba && format == GL_RGBA && type == GL_UNSIGNED_BYTE &&
6012       !selecting_sub_rectangle && depth == 1) {
6013     need_conversion = false;
6014   } else {
6015     if (type == GL_UNSIGNED_INT_10F_11F_11F_REV) {
6016       // The UNSIGNED_INT_10F_11F_11F_REV type pack/unpack isn't implemented.
6017       type = GL_FLOAT;
6018     }
6019     WebGLImageConversion::DataFormat data_format;
6020     if (is_pixel_data_rgba) {
6021       data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA8;
6022     } else {
6023       switch (pixmap.colorType()) {
6024         case SkColorType::kBGRA_8888_SkColorType:
6025           data_format = WebGLImageConversion::DataFormat::kDataFormatBGRA8;
6026           break;
6027         case SkColorType::kRGBA_F16_SkColorType:
6028           // Used in ImageBitmap's ApplyColorSpaceConversion.
6029           data_format = WebGLImageConversion::DataFormat::kDataFormatRGBA16F;
6030           break;
6031         default:
6032           // Can not handle this ImageBitmap's format.
6033           SynthesizeGLError(GL_INVALID_VALUE, func_name,
6034                             "unsupported color type / space in ImageBitmap");
6035           return;
6036       }
6037     }
6038     // In the case of ImageBitmap, we do not need to apply flipY or
6039     // premultiplyAlpha.
6040     if (!WebGLImageConversion::ExtractImageData(
6041             pixel_data_ptr, data_format, bitmap->Size(), source_sub_rect, depth,
6042             unpack_image_height, format, type, false, false, data)) {
6043       SynthesizeGLError(GL_INVALID_VALUE, func_name,
6044                         "error extracting data from ImageBitmap");
6045       return;
6046     }
6047   }
6048   ScopedUnpackParametersResetRestore temporary_reset_unpack(this);
6049   if (function_id == kTexImage2D) {
6050     TexImage2DBase(target, level, internalformat, width, height, 0, format,
6051                    type, need_conversion ? data.data() : pixel_data_ptr);
6052   } else if (function_id == kTexSubImage2D) {
6053     ContextGL()->TexSubImage2D(target, level, xoffset, yoffset, width, height,
6054                                format, type,
6055                                need_conversion ? data.data() : pixel_data_ptr);
6056   } else if (function_id == kTexImage3D) {
6057     ContextGL()->TexImage3D(target, level, internalformat, width, height, depth,
6058                             0, format, type,
6059                             need_conversion ? data.data() : pixel_data_ptr);
6060   } else {
6061     DCHECK_EQ(function_id, kTexSubImage3D);
6062     ContextGL()->TexSubImage3D(target, level, xoffset, yoffset, zoffset, width,
6063                                height, depth, format, type,
6064                                need_conversion ? data.data() : pixel_data_ptr);
6065   }
6066 }
6067 
texImage2D(GLenum target,GLint level,GLint internalformat,GLenum format,GLenum type,ImageBitmap * bitmap,ExceptionState & exception_state)6068 void WebGLRenderingContextBase::texImage2D(GLenum target,
6069                                            GLint level,
6070                                            GLint internalformat,
6071                                            GLenum format,
6072                                            GLenum type,
6073                                            ImageBitmap* bitmap,
6074                                            ExceptionState& exception_state) {
6075   TexImageHelperImageBitmap(kTexImage2D, target, level, internalformat, format,
6076                             type, 0, 0, 0, bitmap, GetTextureSourceSize(bitmap),
6077                             1, 0, exception_state);
6078 }
6079 
TexParameter(GLenum target,GLenum pname,GLfloat paramf,GLint parami,bool is_float)6080 void WebGLRenderingContextBase::TexParameter(GLenum target,
6081                                              GLenum pname,
6082                                              GLfloat paramf,
6083                                              GLint parami,
6084                                              bool is_float) {
6085   if (isContextLost())
6086     return;
6087   if (!ValidateTextureBinding("texParameter", target))
6088     return;
6089   switch (pname) {
6090     case GL_TEXTURE_MIN_FILTER:
6091       if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
6092         if ((is_float && paramf != GL_NEAREST && paramf != GL_LINEAR) ||
6093             (!is_float && parami != GL_NEAREST && parami != GL_LINEAR)) {
6094           SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6095                             "invalid parameter name");
6096           return;
6097         }
6098       }
6099       break;
6100     case GL_TEXTURE_MAG_FILTER:
6101       break;
6102     case GL_TEXTURE_WRAP_R:
6103       if (!IsWebGL2()) {
6104         SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6105                           "invalid parameter name");
6106         return;
6107       }
6108       FALLTHROUGH;
6109     case GL_TEXTURE_WRAP_S:
6110     case GL_TEXTURE_WRAP_T:
6111       if ((is_float && paramf != GL_CLAMP_TO_EDGE &&
6112            paramf != GL_MIRRORED_REPEAT && paramf != GL_REPEAT) ||
6113           (!is_float && parami != GL_CLAMP_TO_EDGE &&
6114            parami != GL_MIRRORED_REPEAT && parami != GL_REPEAT)) {
6115         SynthesizeGLError(GL_INVALID_ENUM, "texParameter", "invalid parameter");
6116         return;
6117       }
6118 
6119       if (target == GL_TEXTURE_VIDEO_IMAGE_WEBGL) {
6120         if ((is_float && paramf != GL_CLAMP_TO_EDGE) ||
6121             (!is_float && parami != GL_CLAMP_TO_EDGE)) {
6122           SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6123                             "invalid parameter");
6124           return;
6125         }
6126       }
6127       break;
6128     case GL_TEXTURE_MAX_ANISOTROPY_EXT:  // EXT_texture_filter_anisotropic
6129       if (!ExtensionEnabled(kEXTTextureFilterAnisotropicName)) {
6130         SynthesizeGLError(
6131             GL_INVALID_ENUM, "texParameter",
6132             "invalid parameter, EXT_texture_filter_anisotropic not enabled");
6133         return;
6134       }
6135       break;
6136     case GL_TEXTURE_COMPARE_FUNC:
6137     case GL_TEXTURE_COMPARE_MODE:
6138     case GL_TEXTURE_BASE_LEVEL:
6139     case GL_TEXTURE_MAX_LEVEL:
6140     case GL_TEXTURE_MAX_LOD:
6141     case GL_TEXTURE_MIN_LOD:
6142       if (!IsWebGL2()) {
6143         SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6144                           "invalid parameter name");
6145         return;
6146       }
6147       break;
6148     default:
6149       SynthesizeGLError(GL_INVALID_ENUM, "texParameter",
6150                         "invalid parameter name");
6151       return;
6152   }
6153   if (is_float) {
6154     ContextGL()->TexParameterf(target, pname, paramf);
6155   } else {
6156     ContextGL()->TexParameteri(target, pname, parami);
6157   }
6158 }
6159 
texParameterf(GLenum target,GLenum pname,GLfloat param)6160 void WebGLRenderingContextBase::texParameterf(GLenum target,
6161                                               GLenum pname,
6162                                               GLfloat param) {
6163   TexParameter(target, pname, param, 0, true);
6164 }
6165 
texParameteri(GLenum target,GLenum pname,GLint param)6166 void WebGLRenderingContextBase::texParameteri(GLenum target,
6167                                               GLenum pname,
6168                                               GLint param) {
6169   TexParameter(target, pname, 0, param, false);
6170 }
6171 
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLsizei width,GLsizei height,GLenum format,GLenum type,MaybeShared<DOMArrayBufferView> pixels)6172 void WebGLRenderingContextBase::texSubImage2D(
6173     GLenum target,
6174     GLint level,
6175     GLint xoffset,
6176     GLint yoffset,
6177     GLsizei width,
6178     GLsizei height,
6179     GLenum format,
6180     GLenum type,
6181     MaybeShared<DOMArrayBufferView> pixels) {
6182   TexImageHelperDOMArrayBufferView(kTexSubImage2D, target, level, 0, width,
6183                                    height, 1, 0, format, type, xoffset, yoffset,
6184                                    0, pixels.View(), kNullNotAllowed, 0);
6185 }
6186 
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,ImageData * pixels)6187 void WebGLRenderingContextBase::texSubImage2D(GLenum target,
6188                                               GLint level,
6189                                               GLint xoffset,
6190                                               GLint yoffset,
6191                                               GLenum format,
6192                                               GLenum type,
6193                                               ImageData* pixels) {
6194   TexImageHelperImageData(kTexSubImage2D, target, level, 0, 0, format, type, 1,
6195                           xoffset, yoffset, 0, pixels, GetImageDataSize(pixels),
6196                           0);
6197 }
6198 
texSubImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,HTMLImageElement * image,ExceptionState & exception_state)6199 void WebGLRenderingContextBase::texSubImage2D(
6200     ExecutionContext* execution_context,
6201     GLenum target,
6202     GLint level,
6203     GLint xoffset,
6204     GLint yoffset,
6205     GLenum format,
6206     GLenum type,
6207     HTMLImageElement* image,
6208     ExceptionState& exception_state) {
6209   TexImageHelperHTMLImageElement(execution_context->GetSecurityOrigin(),
6210                                  kTexSubImage2D, target, level, 0, format, type,
6211                                  xoffset, yoffset, 0, image,
6212                                  SentinelEmptyRect(), 1, 0, exception_state);
6213 }
6214 
texSubImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,CanvasRenderingContextHost * context_host,ExceptionState & exception_state)6215 void WebGLRenderingContextBase::texSubImage2D(
6216     ExecutionContext* execution_context,
6217     GLenum target,
6218     GLint level,
6219     GLint xoffset,
6220     GLint yoffset,
6221     GLenum format,
6222     GLenum type,
6223     CanvasRenderingContextHost* context_host,
6224     ExceptionState& exception_state) {
6225   TexImageHelperCanvasRenderingContextHost(
6226       execution_context->GetSecurityOrigin(), kTexSubImage2D, target, level, 0,
6227       format, type, xoffset, yoffset, 0, context_host,
6228       GetTextureSourceSize(context_host), 1, 0, exception_state);
6229 }
6230 
texSubImage2D(ExecutionContext * execution_context,GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,HTMLVideoElement * video,ExceptionState & exception_state)6231 void WebGLRenderingContextBase::texSubImage2D(
6232     ExecutionContext* execution_context,
6233     GLenum target,
6234     GLint level,
6235     GLint xoffset,
6236     GLint yoffset,
6237     GLenum format,
6238     GLenum type,
6239     HTMLVideoElement* video,
6240     ExceptionState& exception_state) {
6241   TexImageHelperHTMLVideoElement(execution_context->GetSecurityOrigin(),
6242                                  kTexSubImage2D, target, level, 0, format, type,
6243                                  xoffset, yoffset, 0, video,
6244                                  SentinelEmptyRect(), 1, 0, exception_state);
6245 }
6246 
texSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLenum format,GLenum type,ImageBitmap * bitmap,ExceptionState & exception_state)6247 void WebGLRenderingContextBase::texSubImage2D(GLenum target,
6248                                               GLint level,
6249                                               GLint xoffset,
6250                                               GLint yoffset,
6251                                               GLenum format,
6252                                               GLenum type,
6253                                               ImageBitmap* bitmap,
6254                                               ExceptionState& exception_state) {
6255   TexImageHelperImageBitmap(
6256       kTexSubImage2D, target, level, 0, format, type, xoffset, yoffset, 0,
6257       bitmap, GetTextureSourceSize(bitmap), 1, 0, exception_state);
6258 }
6259 
uniform1f(const WebGLUniformLocation * location,GLfloat x)6260 void WebGLRenderingContextBase::uniform1f(const WebGLUniformLocation* location,
6261                                           GLfloat x) {
6262   if (isContextLost() || !location)
6263     return;
6264 
6265   if (location->Program() != current_program_) {
6266     SynthesizeGLError(GL_INVALID_OPERATION, "uniform1f",
6267                       "location not for current program");
6268     return;
6269   }
6270 
6271   ContextGL()->Uniform1f(location->Location(), x);
6272 }
6273 
uniform1fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6274 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location,
6275                                            const FlexibleFloat32Array& v) {
6276   if (isContextLost() ||
6277       !ValidateUniformParameters("uniform1fv", location, v, 1, 0, v.length()))
6278     return;
6279 
6280   ContextGL()->Uniform1fv(location->Location(),
6281                           base::checked_cast<GLuint>(v.length()),
6282                           v.DataMaybeOnStack());
6283 }
6284 
uniform1fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6285 void WebGLRenderingContextBase::uniform1fv(const WebGLUniformLocation* location,
6286                                            Vector<GLfloat>& v) {
6287   if (isContextLost() ||
6288       !ValidateUniformParameters("uniform1fv", location, v.data(), v.size(), 1,
6289                                  0, v.size()))
6290     return;
6291 
6292   ContextGL()->Uniform1fv(location->Location(), v.size(), v.data());
6293 }
6294 
uniform1i(const WebGLUniformLocation * location,GLint x)6295 void WebGLRenderingContextBase::uniform1i(const WebGLUniformLocation* location,
6296                                           GLint x) {
6297   if (isContextLost() || !location)
6298     return;
6299 
6300   if (location->Program() != current_program_) {
6301     SynthesizeGLError(GL_INVALID_OPERATION, "uniform1i",
6302                       "location not for current program");
6303     return;
6304   }
6305 
6306   ContextGL()->Uniform1i(location->Location(), x);
6307 }
6308 
uniform1iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6309 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location,
6310                                            const FlexibleInt32Array& v) {
6311   if (isContextLost() ||
6312       !ValidateUniformParameters("uniform1iv", location, v, 1, 0, v.length()))
6313     return;
6314 
6315   ContextGL()->Uniform1iv(location->Location(),
6316                           base::checked_cast<GLuint>(v.length()),
6317                           v.DataMaybeOnStack());
6318 }
6319 
uniform1iv(const WebGLUniformLocation * location,Vector<GLint> & v)6320 void WebGLRenderingContextBase::uniform1iv(const WebGLUniformLocation* location,
6321                                            Vector<GLint>& v) {
6322   if (isContextLost() ||
6323       !ValidateUniformParameters("uniform1iv", location, v.data(), v.size(), 1,
6324                                  0, v.size()))
6325     return;
6326 
6327   ContextGL()->Uniform1iv(location->Location(), v.size(), v.data());
6328 }
6329 
uniform2f(const WebGLUniformLocation * location,GLfloat x,GLfloat y)6330 void WebGLRenderingContextBase::uniform2f(const WebGLUniformLocation* location,
6331                                           GLfloat x,
6332                                           GLfloat y) {
6333   if (isContextLost() || !location)
6334     return;
6335 
6336   if (location->Program() != current_program_) {
6337     SynthesizeGLError(GL_INVALID_OPERATION, "uniform2f",
6338                       "location not for current program");
6339     return;
6340   }
6341 
6342   ContextGL()->Uniform2f(location->Location(), x, y);
6343 }
6344 
uniform2fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6345 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location,
6346                                            const FlexibleFloat32Array& v) {
6347   if (isContextLost() ||
6348       !ValidateUniformParameters("uniform2fv", location, v, 2, 0, v.length()))
6349     return;
6350 
6351   ContextGL()->Uniform2fv(location->Location(),
6352                           base::checked_cast<GLuint>(v.length()) >> 1,
6353                           v.DataMaybeOnStack());
6354 }
6355 
uniform2fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6356 void WebGLRenderingContextBase::uniform2fv(const WebGLUniformLocation* location,
6357                                            Vector<GLfloat>& v) {
6358   if (isContextLost() ||
6359       !ValidateUniformParameters("uniform2fv", location, v.data(), v.size(), 2,
6360                                  0, v.size()))
6361     return;
6362 
6363   ContextGL()->Uniform2fv(location->Location(), v.size() >> 1, v.data());
6364 }
6365 
uniform2i(const WebGLUniformLocation * location,GLint x,GLint y)6366 void WebGLRenderingContextBase::uniform2i(const WebGLUniformLocation* location,
6367                                           GLint x,
6368                                           GLint y) {
6369   if (isContextLost() || !location)
6370     return;
6371 
6372   if (location->Program() != current_program_) {
6373     SynthesizeGLError(GL_INVALID_OPERATION, "uniform2i",
6374                       "location not for current program");
6375     return;
6376   }
6377 
6378   ContextGL()->Uniform2i(location->Location(), x, y);
6379 }
6380 
uniform2iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6381 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location,
6382                                            const FlexibleInt32Array& v) {
6383   if (isContextLost() ||
6384       !ValidateUniformParameters("uniform2iv", location, v, 2, 0, v.length()))
6385     return;
6386 
6387   ContextGL()->Uniform2iv(location->Location(),
6388                           base::checked_cast<GLuint>(v.length()) >> 1,
6389                           v.DataMaybeOnStack());
6390 }
6391 
uniform2iv(const WebGLUniformLocation * location,Vector<GLint> & v)6392 void WebGLRenderingContextBase::uniform2iv(const WebGLUniformLocation* location,
6393                                            Vector<GLint>& v) {
6394   if (isContextLost() ||
6395       !ValidateUniformParameters("uniform2iv", location, v.data(), v.size(), 2,
6396                                  0, v.size()))
6397     return;
6398 
6399   ContextGL()->Uniform2iv(location->Location(), v.size() >> 1, v.data());
6400 }
6401 
uniform3f(const WebGLUniformLocation * location,GLfloat x,GLfloat y,GLfloat z)6402 void WebGLRenderingContextBase::uniform3f(const WebGLUniformLocation* location,
6403                                           GLfloat x,
6404                                           GLfloat y,
6405                                           GLfloat z) {
6406   if (isContextLost() || !location)
6407     return;
6408 
6409   if (location->Program() != current_program_) {
6410     SynthesizeGLError(GL_INVALID_OPERATION, "uniform3f",
6411                       "location not for current program");
6412     return;
6413   }
6414 
6415   ContextGL()->Uniform3f(location->Location(), x, y, z);
6416 }
6417 
uniform3fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6418 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location,
6419                                            const FlexibleFloat32Array& v) {
6420   if (isContextLost() ||
6421       !ValidateUniformParameters("uniform3fv", location, v, 3, 0, v.length()))
6422     return;
6423 
6424   ContextGL()->Uniform3fv(location->Location(),
6425                           base::checked_cast<GLuint>(v.length()) / 3,
6426                           v.DataMaybeOnStack());
6427 }
6428 
uniform3fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6429 void WebGLRenderingContextBase::uniform3fv(const WebGLUniformLocation* location,
6430                                            Vector<GLfloat>& v) {
6431   if (isContextLost() ||
6432       !ValidateUniformParameters("uniform3fv", location, v.data(), v.size(), 3,
6433                                  0, v.size()))
6434     return;
6435 
6436   ContextGL()->Uniform3fv(location->Location(), v.size() / 3, v.data());
6437 }
6438 
uniform3i(const WebGLUniformLocation * location,GLint x,GLint y,GLint z)6439 void WebGLRenderingContextBase::uniform3i(const WebGLUniformLocation* location,
6440                                           GLint x,
6441                                           GLint y,
6442                                           GLint z) {
6443   if (isContextLost() || !location)
6444     return;
6445 
6446   if (location->Program() != current_program_) {
6447     SynthesizeGLError(GL_INVALID_OPERATION, "uniform3i",
6448                       "location not for current program");
6449     return;
6450   }
6451 
6452   ContextGL()->Uniform3i(location->Location(), x, y, z);
6453 }
6454 
uniform3iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6455 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location,
6456                                            const FlexibleInt32Array& v) {
6457   if (isContextLost() ||
6458       !ValidateUniformParameters("uniform3iv", location, v, 3, 0, v.length()))
6459     return;
6460 
6461   ContextGL()->Uniform3iv(location->Location(),
6462                           base::checked_cast<GLuint>(v.length()) / 3,
6463                           v.DataMaybeOnStack());
6464 }
6465 
uniform3iv(const WebGLUniformLocation * location,Vector<GLint> & v)6466 void WebGLRenderingContextBase::uniform3iv(const WebGLUniformLocation* location,
6467                                            Vector<GLint>& v) {
6468   if (isContextLost() ||
6469       !ValidateUniformParameters("uniform3iv", location, v.data(), v.size(), 3,
6470                                  0, v.size()))
6471     return;
6472 
6473   ContextGL()->Uniform3iv(location->Location(), v.size() / 3, v.data());
6474 }
6475 
uniform4f(const WebGLUniformLocation * location,GLfloat x,GLfloat y,GLfloat z,GLfloat w)6476 void WebGLRenderingContextBase::uniform4f(const WebGLUniformLocation* location,
6477                                           GLfloat x,
6478                                           GLfloat y,
6479                                           GLfloat z,
6480                                           GLfloat w) {
6481   if (isContextLost() || !location)
6482     return;
6483 
6484   if (location->Program() != current_program_) {
6485     SynthesizeGLError(GL_INVALID_OPERATION, "uniform4f",
6486                       "location not for current program");
6487     return;
6488   }
6489 
6490   ContextGL()->Uniform4f(location->Location(), x, y, z, w);
6491 }
6492 
uniform4fv(const WebGLUniformLocation * location,const FlexibleFloat32Array & v)6493 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location,
6494                                            const FlexibleFloat32Array& v) {
6495   if (isContextLost() ||
6496       !ValidateUniformParameters("uniform4fv", location, v, 4, 0, v.length()))
6497     return;
6498 
6499   ContextGL()->Uniform4fv(location->Location(),
6500                           base::checked_cast<GLuint>(v.length()) >> 2,
6501                           v.DataMaybeOnStack());
6502 }
6503 
uniform4fv(const WebGLUniformLocation * location,Vector<GLfloat> & v)6504 void WebGLRenderingContextBase::uniform4fv(const WebGLUniformLocation* location,
6505                                            Vector<GLfloat>& v) {
6506   if (isContextLost() ||
6507       !ValidateUniformParameters("uniform4fv", location, v.data(), v.size(), 4,
6508                                  0, v.size()))
6509     return;
6510 
6511   ContextGL()->Uniform4fv(location->Location(), v.size() >> 2, v.data());
6512 }
6513 
uniform4i(const WebGLUniformLocation * location,GLint x,GLint y,GLint z,GLint w)6514 void WebGLRenderingContextBase::uniform4i(const WebGLUniformLocation* location,
6515                                           GLint x,
6516                                           GLint y,
6517                                           GLint z,
6518                                           GLint w) {
6519   if (isContextLost() || !location)
6520     return;
6521 
6522   if (location->Program() != current_program_) {
6523     SynthesizeGLError(GL_INVALID_OPERATION, "uniform4i",
6524                       "location not for current program");
6525     return;
6526   }
6527 
6528   ContextGL()->Uniform4i(location->Location(), x, y, z, w);
6529 }
6530 
uniform4iv(const WebGLUniformLocation * location,const FlexibleInt32Array & v)6531 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location,
6532                                            const FlexibleInt32Array& v) {
6533   if (isContextLost() ||
6534       !ValidateUniformParameters("uniform4iv", location, v, 4, 0, v.length()))
6535     return;
6536 
6537   ContextGL()->Uniform4iv(location->Location(),
6538                           base::checked_cast<GLuint>(v.length()) >> 2,
6539                           v.DataMaybeOnStack());
6540 }
6541 
uniform4iv(const WebGLUniformLocation * location,Vector<GLint> & v)6542 void WebGLRenderingContextBase::uniform4iv(const WebGLUniformLocation* location,
6543                                            Vector<GLint>& v) {
6544   if (isContextLost() ||
6545       !ValidateUniformParameters("uniform4iv", location, v.data(), v.size(), 4,
6546                                  0, v.size()))
6547     return;
6548 
6549   ContextGL()->Uniform4iv(location->Location(), v.size() >> 2, v.data());
6550 }
6551 
uniformMatrix2fv(const WebGLUniformLocation * location,GLboolean transpose,MaybeShared<DOMFloat32Array> v)6552 void WebGLRenderingContextBase::uniformMatrix2fv(
6553     const WebGLUniformLocation* location,
6554     GLboolean transpose,
6555     MaybeShared<DOMFloat32Array> v) {
6556   if (isContextLost() ||
6557       !ValidateUniformMatrixParameters("uniformMatrix2fv", location, transpose,
6558                                        v.View(), 4, 0, v.View()->length()))
6559     return;
6560   ContextGL()->UniformMatrix2fv(
6561       location->Location(), base::checked_cast<GLuint>(v.View()->length()) >> 2,
6562       transpose, v.View()->DataMaybeShared());
6563 }
6564 
uniformMatrix2fv(const WebGLUniformLocation * location,GLboolean transpose,Vector<GLfloat> & v)6565 void WebGLRenderingContextBase::uniformMatrix2fv(
6566     const WebGLUniformLocation* location,
6567     GLboolean transpose,
6568     Vector<GLfloat>& v) {
6569   if (isContextLost() ||
6570       !ValidateUniformMatrixParameters("uniformMatrix2fv", location, transpose,
6571                                        v.data(), v.size(), 4, 0, v.size()))
6572     return;
6573   ContextGL()->UniformMatrix2fv(location->Location(), v.size() >> 2, transpose,
6574                                 v.data());
6575 }
6576 
uniformMatrix3fv(const WebGLUniformLocation * location,GLboolean transpose,MaybeShared<DOMFloat32Array> v)6577 void WebGLRenderingContextBase::uniformMatrix3fv(
6578     const WebGLUniformLocation* location,
6579     GLboolean transpose,
6580     MaybeShared<DOMFloat32Array> v) {
6581   if (isContextLost() ||
6582       !ValidateUniformMatrixParameters("uniformMatrix3fv", location, transpose,
6583                                        v.View(), 9, 0, v.View()->length()))
6584     return;
6585   ContextGL()->UniformMatrix3fv(
6586       location->Location(), base::checked_cast<GLuint>(v.View()->length()) / 9,
6587       transpose, v.View()->DataMaybeShared());
6588 }
6589 
uniformMatrix3fv(const WebGLUniformLocation * location,GLboolean transpose,Vector<GLfloat> & v)6590 void WebGLRenderingContextBase::uniformMatrix3fv(
6591     const WebGLUniformLocation* location,
6592     GLboolean transpose,
6593     Vector<GLfloat>& v) {
6594   if (isContextLost() ||
6595       !ValidateUniformMatrixParameters("uniformMatrix3fv", location, transpose,
6596                                        v.data(), v.size(), 9, 0, v.size()))
6597     return;
6598   ContextGL()->UniformMatrix3fv(location->Location(), v.size() / 9, transpose,
6599                                 v.data());
6600 }
6601 
uniformMatrix4fv(const WebGLUniformLocation * location,GLboolean transpose,MaybeShared<DOMFloat32Array> v)6602 void WebGLRenderingContextBase::uniformMatrix4fv(
6603     const WebGLUniformLocation* location,
6604     GLboolean transpose,
6605     MaybeShared<DOMFloat32Array> v) {
6606   if (isContextLost() ||
6607       !ValidateUniformMatrixParameters("uniformMatrix4fv", location, transpose,
6608                                        v.View(), 16, 0, v.View()->length()))
6609     return;
6610   ContextGL()->UniformMatrix4fv(
6611       location->Location(), base::checked_cast<GLuint>(v.View()->length()) >> 4,
6612       transpose, v.View()->DataMaybeShared());
6613 }
6614 
uniformMatrix4fv(const WebGLUniformLocation * location,GLboolean transpose,Vector<GLfloat> & v)6615 void WebGLRenderingContextBase::uniformMatrix4fv(
6616     const WebGLUniformLocation* location,
6617     GLboolean transpose,
6618     Vector<GLfloat>& v) {
6619   if (isContextLost() ||
6620       !ValidateUniformMatrixParameters("uniformMatrix4fv", location, transpose,
6621                                        v.data(), v.size(), 16, 0, v.size()))
6622     return;
6623   ContextGL()->UniformMatrix4fv(location->Location(), v.size() >> 4, transpose,
6624                                 v.data());
6625 }
6626 
useProgram(WebGLProgram * program)6627 void WebGLRenderingContextBase::useProgram(WebGLProgram* program) {
6628   if (!ValidateNullableWebGLObject("useProgram", program))
6629     return;
6630   if (program && !program->LinkStatus(this)) {
6631     SynthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid");
6632     return;
6633   }
6634 
6635   if (current_program_ != program) {
6636     if (current_program_)
6637       current_program_->OnDetached(ContextGL());
6638     current_program_ = program;
6639     ContextGL()->UseProgram(ObjectOrZero(program));
6640     if (program)
6641       program->OnAttached();
6642   }
6643 }
6644 
validateProgram(WebGLProgram * program)6645 void WebGLRenderingContextBase::validateProgram(WebGLProgram* program) {
6646   if (!ValidateWebGLProgramOrShader("validateProgram", program))
6647     return;
6648   ContextGL()->ValidateProgram(ObjectOrZero(program));
6649 }
6650 
SetVertexAttribType(GLuint index,VertexAttribValueType type)6651 void WebGLRenderingContextBase::SetVertexAttribType(
6652     GLuint index,
6653     VertexAttribValueType type) {
6654   if (index < max_vertex_attribs_)
6655     vertex_attrib_type_[index] = type;
6656 }
6657 
vertexAttrib1f(GLuint index,GLfloat v0)6658 void WebGLRenderingContextBase::vertexAttrib1f(GLuint index, GLfloat v0) {
6659   if (isContextLost())
6660     return;
6661   ContextGL()->VertexAttrib1f(index, v0);
6662   SetVertexAttribType(index, kFloat32ArrayType);
6663 }
6664 
vertexAttrib1fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6665 void WebGLRenderingContextBase::vertexAttrib1fv(
6666     GLuint index,
6667     MaybeShared<const DOMFloat32Array> v) {
6668   if (isContextLost())
6669     return;
6670   if (!v.View() || v.View()->length() < 1) {
6671     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib1fv", "invalid array");
6672     return;
6673   }
6674   ContextGL()->VertexAttrib1fv(index, v.View()->DataMaybeShared());
6675   SetVertexAttribType(index, kFloat32ArrayType);
6676 }
6677 
vertexAttrib1fv(GLuint index,const Vector<GLfloat> & v)6678 void WebGLRenderingContextBase::vertexAttrib1fv(GLuint index,
6679                                                 const Vector<GLfloat>& v) {
6680   if (isContextLost())
6681     return;
6682   if (v.size() < 1) {
6683     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib1fv", "invalid array");
6684     return;
6685   }
6686   ContextGL()->VertexAttrib1fv(index, v.data());
6687   SetVertexAttribType(index, kFloat32ArrayType);
6688 }
6689 
vertexAttrib2f(GLuint index,GLfloat v0,GLfloat v1)6690 void WebGLRenderingContextBase::vertexAttrib2f(GLuint index,
6691                                                GLfloat v0,
6692                                                GLfloat v1) {
6693   if (isContextLost())
6694     return;
6695   ContextGL()->VertexAttrib2f(index, v0, v1);
6696   SetVertexAttribType(index, kFloat32ArrayType);
6697 }
6698 
vertexAttrib2fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6699 void WebGLRenderingContextBase::vertexAttrib2fv(
6700     GLuint index,
6701     MaybeShared<const DOMFloat32Array> v) {
6702   if (isContextLost())
6703     return;
6704   if (!v.View() || v.View()->length() < 2) {
6705     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib2fv", "invalid array");
6706     return;
6707   }
6708   ContextGL()->VertexAttrib2fv(index, v.View()->DataMaybeShared());
6709   SetVertexAttribType(index, kFloat32ArrayType);
6710 }
6711 
vertexAttrib2fv(GLuint index,const Vector<GLfloat> & v)6712 void WebGLRenderingContextBase::vertexAttrib2fv(GLuint index,
6713                                                 const Vector<GLfloat>& v) {
6714   if (isContextLost())
6715     return;
6716   if (v.size() < 2) {
6717     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib2fv", "invalid array");
6718     return;
6719   }
6720   ContextGL()->VertexAttrib2fv(index, v.data());
6721   SetVertexAttribType(index, kFloat32ArrayType);
6722 }
6723 
vertexAttrib3f(GLuint index,GLfloat v0,GLfloat v1,GLfloat v2)6724 void WebGLRenderingContextBase::vertexAttrib3f(GLuint index,
6725                                                GLfloat v0,
6726                                                GLfloat v1,
6727                                                GLfloat v2) {
6728   if (isContextLost())
6729     return;
6730   ContextGL()->VertexAttrib3f(index, v0, v1, v2);
6731   SetVertexAttribType(index, kFloat32ArrayType);
6732 }
6733 
vertexAttrib3fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6734 void WebGLRenderingContextBase::vertexAttrib3fv(
6735     GLuint index,
6736     MaybeShared<const DOMFloat32Array> v) {
6737   if (isContextLost())
6738     return;
6739   if (!v.View() || v.View()->length() < 3) {
6740     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib3fv", "invalid array");
6741     return;
6742   }
6743   ContextGL()->VertexAttrib3fv(index, v.View()->DataMaybeShared());
6744   SetVertexAttribType(index, kFloat32ArrayType);
6745 }
6746 
vertexAttrib3fv(GLuint index,const Vector<GLfloat> & v)6747 void WebGLRenderingContextBase::vertexAttrib3fv(GLuint index,
6748                                                 const Vector<GLfloat>& v) {
6749   if (isContextLost())
6750     return;
6751   if (v.size() < 3) {
6752     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib3fv", "invalid array");
6753     return;
6754   }
6755   ContextGL()->VertexAttrib3fv(index, v.data());
6756   SetVertexAttribType(index, kFloat32ArrayType);
6757 }
6758 
vertexAttrib4f(GLuint index,GLfloat v0,GLfloat v1,GLfloat v2,GLfloat v3)6759 void WebGLRenderingContextBase::vertexAttrib4f(GLuint index,
6760                                                GLfloat v0,
6761                                                GLfloat v1,
6762                                                GLfloat v2,
6763                                                GLfloat v3) {
6764   if (isContextLost())
6765     return;
6766   ContextGL()->VertexAttrib4f(index, v0, v1, v2, v3);
6767   SetVertexAttribType(index, kFloat32ArrayType);
6768 }
6769 
vertexAttrib4fv(GLuint index,MaybeShared<const DOMFloat32Array> v)6770 void WebGLRenderingContextBase::vertexAttrib4fv(
6771     GLuint index,
6772     MaybeShared<const DOMFloat32Array> v) {
6773   if (isContextLost())
6774     return;
6775   if (!v.View() || v.View()->length() < 4) {
6776     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib4fv", "invalid array");
6777     return;
6778   }
6779   ContextGL()->VertexAttrib4fv(index, v.View()->DataMaybeShared());
6780   SetVertexAttribType(index, kFloat32ArrayType);
6781 }
6782 
vertexAttrib4fv(GLuint index,const Vector<GLfloat> & v)6783 void WebGLRenderingContextBase::vertexAttrib4fv(GLuint index,
6784                                                 const Vector<GLfloat>& v) {
6785   if (isContextLost())
6786     return;
6787   if (v.size() < 4) {
6788     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttrib4fv", "invalid array");
6789     return;
6790   }
6791   ContextGL()->VertexAttrib4fv(index, v.data());
6792   SetVertexAttribType(index, kFloat32ArrayType);
6793 }
6794 
vertexAttribPointer(GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,int64_t offset)6795 void WebGLRenderingContextBase::vertexAttribPointer(GLuint index,
6796                                                     GLint size,
6797                                                     GLenum type,
6798                                                     GLboolean normalized,
6799                                                     GLsizei stride,
6800                                                     int64_t offset) {
6801   if (isContextLost())
6802     return;
6803   if (index >= max_vertex_attribs_) {
6804     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttribPointer",
6805                       "index out of range");
6806     return;
6807   }
6808   if (!ValidateValueFitNonNegInt32("vertexAttribPointer", "offset", offset))
6809     return;
6810   if (!bound_array_buffer_ && offset != 0) {
6811     SynthesizeGLError(GL_INVALID_OPERATION, "vertexAttribPointer",
6812                       "no ARRAY_BUFFER is bound and offset is non-zero");
6813     return;
6814   }
6815 
6816   bound_vertex_array_object_->SetArrayBufferForAttrib(
6817       index, bound_array_buffer_.Get());
6818   ContextGL()->VertexAttribPointer(
6819       index, size, type, normalized, stride,
6820       reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
6821 }
6822 
VertexAttribDivisorANGLE(GLuint index,GLuint divisor)6823 void WebGLRenderingContextBase::VertexAttribDivisorANGLE(GLuint index,
6824                                                          GLuint divisor) {
6825   if (isContextLost())
6826     return;
6827 
6828   if (index >= max_vertex_attribs_) {
6829     SynthesizeGLError(GL_INVALID_VALUE, "vertexAttribDivisorANGLE",
6830                       "index out of range");
6831     return;
6832   }
6833 
6834   ContextGL()->VertexAttribDivisorANGLE(index, divisor);
6835 }
6836 
viewport(GLint x,GLint y,GLsizei width,GLsizei height)6837 void WebGLRenderingContextBase::viewport(GLint x,
6838                                          GLint y,
6839                                          GLsizei width,
6840                                          GLsizei height) {
6841   if (isContextLost())
6842     return;
6843   ContextGL()->Viewport(x, y, width, height);
6844 }
6845 
6846 // Added to provide a unified interface with CanvasRenderingContext2D. Prefer
6847 // calling forceLostContext instead.
LoseContext(LostContextMode mode)6848 void WebGLRenderingContextBase::LoseContext(LostContextMode mode) {
6849   ForceLostContext(mode, kManual);
6850 }
6851 
ForceLostContext(LostContextMode mode,AutoRecoveryMethod auto_recovery_method)6852 void WebGLRenderingContextBase::ForceLostContext(
6853     LostContextMode mode,
6854     AutoRecoveryMethod auto_recovery_method) {
6855   if (isContextLost()) {
6856     SynthesizeGLError(GL_INVALID_OPERATION, "loseContext",
6857                       "context already lost");
6858     return;
6859   }
6860 
6861   context_group_->LoseContextGroup(mode, auto_recovery_method);
6862 }
6863 
LoseContextImpl(WebGLRenderingContextBase::LostContextMode mode,AutoRecoveryMethod auto_recovery_method)6864 void WebGLRenderingContextBase::LoseContextImpl(
6865     WebGLRenderingContextBase::LostContextMode mode,
6866     AutoRecoveryMethod auto_recovery_method) {
6867   if (isContextLost())
6868     return;
6869 
6870   context_lost_mode_ = mode;
6871   DCHECK_NE(context_lost_mode_, kNotLostContext);
6872   auto_recovery_method_ = auto_recovery_method;
6873 
6874   // Lose all the extensions.
6875   for (ExtensionTracker* tracker : extensions_) {
6876     tracker->LoseExtension(false);
6877   }
6878 
6879   for (wtf_size_t i = 0; i < kWebGLExtensionNameCount; ++i)
6880     extension_enabled_[i] = false;
6881 
6882   RemoveAllCompressedTextureFormats();
6883 
6884   // If the DrawingBuffer is destroyed during a real lost context event it
6885   // causes the CommandBufferProxy that the DrawingBuffer owns, which is what
6886   // issued the lost context event in the first place, to be destroyed before
6887   // the event is done being handled. This causes a crash when an outstanding
6888   // AutoLock goes out of scope. To avoid this, we create a no-op task to hold
6889   // a reference to the DrawingBuffer until this function is done executing.
6890   if (mode == kRealLostContext) {
6891     task_runner_->PostTask(
6892         FROM_HERE,
6893         WTF::Bind(&WebGLRenderingContextBase::HoldReferenceToDrawingBuffer,
6894                   WrapWeakPersistent(this), WTF::RetainedRef(drawing_buffer_)));
6895   }
6896 
6897   // Always destroy the context, regardless of context loss mode. This will
6898   // set drawing_buffer_ to null, but it won't actually be destroyed until the
6899   // above task is executed. drawing_buffer_ is recreated in the event that the
6900   // context is restored by MaybeRestoreContext. If this was a real lost context
6901   // the OpenGL calls done during DrawingBuffer destruction will be ignored.
6902   DestroyContext();
6903 
6904   ConsoleDisplayPreference display =
6905       (mode == kRealLostContext) ? kDisplayInConsole : kDontDisplayInConsole;
6906   SynthesizeGLError(GC3D_CONTEXT_LOST_WEBGL, "loseContext", "context lost",
6907                     display);
6908 
6909   // Don't allow restoration unless the context lost event has both been
6910   // dispatched and its default behavior prevented.
6911   restore_allowed_ = false;
6912   DeactivateContext(this);
6913   if (auto_recovery_method_ == kWhenAvailable)
6914     AddToEvictedList(this);
6915 
6916   // Always defer the dispatch of the context lost event, to implement
6917   // the spec behavior of queueing a task.
6918   dispatch_context_lost_event_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
6919 }
6920 
HoldReferenceToDrawingBuffer(DrawingBuffer *)6921 void WebGLRenderingContextBase::HoldReferenceToDrawingBuffer(DrawingBuffer*) {
6922   // This function intentionally left blank.
6923 }
6924 
ForceRestoreContext()6925 void WebGLRenderingContextBase::ForceRestoreContext() {
6926   if (!isContextLost()) {
6927     SynthesizeGLError(GL_INVALID_OPERATION, "restoreContext",
6928                       "context not lost");
6929     return;
6930   }
6931 
6932   if (!restore_allowed_) {
6933     if (context_lost_mode_ == kWebGLLoseContextLostContext)
6934       SynthesizeGLError(GL_INVALID_OPERATION, "restoreContext",
6935                         "context restoration not allowed");
6936     return;
6937   }
6938 
6939   if (!restore_timer_.IsActive())
6940     restore_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
6941 }
6942 
NumberOfContextLosses() const6943 uint32_t WebGLRenderingContextBase::NumberOfContextLosses() const {
6944   return context_group_->NumberOfContextLosses();
6945 }
6946 
CcLayer() const6947 cc::Layer* WebGLRenderingContextBase::CcLayer() const {
6948   return isContextLost() ? nullptr : GetDrawingBuffer()->CcLayer();
6949 }
6950 
SetFilterQuality(SkFilterQuality filter_quality)6951 void WebGLRenderingContextBase::SetFilterQuality(
6952     SkFilterQuality filter_quality) {
6953   if (!isContextLost() && GetDrawingBuffer()) {
6954     GetDrawingBuffer()->SetFilterQuality(filter_quality);
6955   }
6956 }
6957 
ExtensionsUtil()6958 Extensions3DUtil* WebGLRenderingContextBase::ExtensionsUtil() {
6959   if (!extensions_util_) {
6960     gpu::gles2::GLES2Interface* gl = ContextGL();
6961     extensions_util_ = Extensions3DUtil::Create(gl);
6962     // The only reason the ExtensionsUtil should be invalid is if the gl context
6963     // is lost.
6964     DCHECK(extensions_util_->IsValid() ||
6965            gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR);
6966   }
6967   return extensions_util_.get();
6968 }
6969 
Stop()6970 void WebGLRenderingContextBase::Stop() {
6971   if (!isContextLost()) {
6972     // Never attempt to restore the context because the page is being torn down.
6973     ForceLostContext(kSyntheticLostContext, kManual);
6974   }
6975 }
6976 
DrawingBufferClientIsBoundForDraw()6977 bool WebGLRenderingContextBase::DrawingBufferClientIsBoundForDraw() {
6978   return !framebuffer_binding_;
6979 }
6980 
DrawingBufferClientRestoreScissorTest()6981 void WebGLRenderingContextBase::DrawingBufferClientRestoreScissorTest() {
6982   if (destruction_in_progress_)
6983     return;
6984   if (!ContextGL())
6985     return;
6986   if (scissor_enabled_)
6987     ContextGL()->Enable(GL_SCISSOR_TEST);
6988   else
6989     ContextGL()->Disable(GL_SCISSOR_TEST);
6990 }
6991 
DrawingBufferClientRestoreMaskAndClearValues()6992 void WebGLRenderingContextBase::DrawingBufferClientRestoreMaskAndClearValues() {
6993   if (destruction_in_progress_)
6994     return;
6995   if (!ContextGL())
6996     return;
6997   bool color_mask_alpha =
6998       color_mask_[3] && active_scoped_rgb_emulation_color_masks_ == 0;
6999   ContextGL()->ColorMask(color_mask_[0], color_mask_[1], color_mask_[2],
7000                          color_mask_alpha);
7001   ContextGL()->DepthMask(depth_mask_);
7002   ContextGL()->StencilMaskSeparate(GL_FRONT, stencil_mask_);
7003 
7004   ContextGL()->ClearColor(clear_color_[0], clear_color_[1], clear_color_[2],
7005                           clear_color_[3]);
7006   ContextGL()->ClearDepthf(clear_depth_);
7007   ContextGL()->ClearStencil(clear_stencil_);
7008 }
7009 
7010 void WebGLRenderingContextBase::
DrawingBufferClientRestorePixelPackParameters()7011     DrawingBufferClientRestorePixelPackParameters() {
7012   if (destruction_in_progress_)
7013     return;
7014   if (!ContextGL())
7015     return;
7016   ContextGL()->PixelStorei(GL_PACK_ALIGNMENT, pack_alignment_);
7017 }
7018 
DrawingBufferClientRestoreTexture2DBinding()7019 void WebGLRenderingContextBase::DrawingBufferClientRestoreTexture2DBinding() {
7020   if (destruction_in_progress_)
7021     return;
7022   if (!ContextGL())
7023     return;
7024   RestoreCurrentTexture2D();
7025 }
7026 
7027 void WebGLRenderingContextBase::
DrawingBufferClientRestoreTextureCubeMapBinding()7028     DrawingBufferClientRestoreTextureCubeMapBinding() {
7029   if (destruction_in_progress_)
7030     return;
7031   if (!ContextGL())
7032     return;
7033   RestoreCurrentTextureCubeMap();
7034 }
7035 
7036 void WebGLRenderingContextBase::
DrawingBufferClientRestoreRenderbufferBinding()7037     DrawingBufferClientRestoreRenderbufferBinding() {
7038   if (destruction_in_progress_)
7039     return;
7040   if (!ContextGL())
7041     return;
7042   ContextGL()->BindRenderbuffer(GL_RENDERBUFFER,
7043                                 ObjectOrZero(renderbuffer_binding_.Get()));
7044 }
7045 
DrawingBufferClientRestoreFramebufferBinding()7046 void WebGLRenderingContextBase::DrawingBufferClientRestoreFramebufferBinding() {
7047   if (destruction_in_progress_)
7048     return;
7049   if (!ContextGL())
7050     return;
7051   RestoreCurrentFramebuffer();
7052 }
7053 
7054 void WebGLRenderingContextBase::
DrawingBufferClientRestorePixelUnpackBufferBinding()7055     DrawingBufferClientRestorePixelUnpackBufferBinding() {}
7056 void WebGLRenderingContextBase::
DrawingBufferClientRestorePixelPackBufferBinding()7057     DrawingBufferClientRestorePixelPackBufferBinding() {}
7058 
7059 bool WebGLRenderingContextBase::
DrawingBufferClientUserAllocatedMultisampledRenderbuffers()7060     DrawingBufferClientUserAllocatedMultisampledRenderbuffers() {
7061   return number_of_user_allocated_multisampled_renderbuffers_ > 0;
7062 }
7063 
7064 void WebGLRenderingContextBase::
DrawingBufferClientForceLostContextWithAutoRecovery()7065     DrawingBufferClientForceLostContextWithAutoRecovery() {
7066   ForceLostContext(WebGLRenderingContextBase::kSyntheticLostContext,
7067                    WebGLRenderingContextBase::kAuto);
7068 }
7069 
GetBooleanParameter(ScriptState * script_state,GLenum pname)7070 ScriptValue WebGLRenderingContextBase::GetBooleanParameter(
7071     ScriptState* script_state,
7072     GLenum pname) {
7073   GLboolean value = 0;
7074   if (!isContextLost())
7075     ContextGL()->GetBooleanv(pname, &value);
7076   return WebGLAny(script_state, static_cast<bool>(value));
7077 }
7078 
GetBooleanArrayParameter(ScriptState * script_state,GLenum pname)7079 ScriptValue WebGLRenderingContextBase::GetBooleanArrayParameter(
7080     ScriptState* script_state,
7081     GLenum pname) {
7082   if (pname != GL_COLOR_WRITEMASK) {
7083     NOTIMPLEMENTED();
7084     return WebGLAny(script_state, nullptr, 0);
7085   }
7086   GLboolean value[4] = {0};
7087   if (!isContextLost())
7088     ContextGL()->GetBooleanv(pname, value);
7089   bool bool_value[4];
7090   for (int ii = 0; ii < 4; ++ii)
7091     bool_value[ii] = static_cast<bool>(value[ii]);
7092   return WebGLAny(script_state, bool_value, 4);
7093 }
7094 
GetFloatParameter(ScriptState * script_state,GLenum pname)7095 ScriptValue WebGLRenderingContextBase::GetFloatParameter(
7096     ScriptState* script_state,
7097     GLenum pname) {
7098   GLfloat value = 0;
7099   if (!isContextLost())
7100     ContextGL()->GetFloatv(pname, &value);
7101   if (IdentifiabilityStudySettings::Get()->ShouldSample(
7102           blink::IdentifiableSurface::Type::kWebGLParameter)) {
7103     RecordIdentifiableGLParameterDigest(pname, value);
7104   }
7105   return WebGLAny(script_state, value);
7106 }
7107 
GetIntParameter(ScriptState * script_state,GLenum pname)7108 ScriptValue WebGLRenderingContextBase::GetIntParameter(
7109     ScriptState* script_state,
7110     GLenum pname) {
7111   GLint value = 0;
7112   if (!isContextLost()) {
7113     ContextGL()->GetIntegerv(pname, &value);
7114     switch (pname) {
7115       case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
7116       case GL_IMPLEMENTATION_COLOR_READ_TYPE:
7117         if (value == 0) {
7118           // This indicates read framebuffer is incomplete and an
7119           // INVALID_OPERATION has been generated.
7120           return ScriptValue::CreateNull(script_state->GetIsolate());
7121         }
7122         break;
7123       default:
7124         break;
7125     }
7126   }
7127   if (IdentifiabilityStudySettings::Get()->ShouldSample(
7128           blink::IdentifiableSurface::Type::kWebGLParameter)) {
7129     RecordIdentifiableGLParameterDigest(pname, value);
7130   }
7131   return WebGLAny(script_state, value);
7132 }
7133 
GetInt64Parameter(ScriptState * script_state,GLenum pname)7134 ScriptValue WebGLRenderingContextBase::GetInt64Parameter(
7135     ScriptState* script_state,
7136     GLenum pname) {
7137   GLint64 value = 0;
7138   if (!isContextLost())
7139     ContextGL()->GetInteger64v(pname, &value);
7140   return WebGLAny(script_state, value);
7141 }
7142 
GetUnsignedIntParameter(ScriptState * script_state,GLenum pname)7143 ScriptValue WebGLRenderingContextBase::GetUnsignedIntParameter(
7144     ScriptState* script_state,
7145     GLenum pname) {
7146   GLint value = 0;
7147   if (!isContextLost())
7148     ContextGL()->GetIntegerv(pname, &value);
7149   return WebGLAny(script_state, static_cast<unsigned>(value));
7150 }
7151 
GetWebGLFloatArrayParameter(ScriptState * script_state,GLenum pname)7152 ScriptValue WebGLRenderingContextBase::GetWebGLFloatArrayParameter(
7153     ScriptState* script_state,
7154     GLenum pname) {
7155   GLfloat value[4] = {0};
7156   if (!isContextLost())
7157     ContextGL()->GetFloatv(pname, value);
7158   unsigned length = 0;
7159   switch (pname) {
7160     case GL_ALIASED_POINT_SIZE_RANGE:
7161     case GL_ALIASED_LINE_WIDTH_RANGE:
7162     case GL_DEPTH_RANGE:
7163       length = 2;
7164       break;
7165     case GL_BLEND_COLOR:
7166     case GL_COLOR_CLEAR_VALUE:
7167       length = 4;
7168       break;
7169     default:
7170       NOTIMPLEMENTED();
7171   }
7172   if (ShouldMeasureGLParam(pname)) {
7173     blink::IdentifiableTokenBuilder builder;
7174     for (unsigned i = 0; i < length; i++) {
7175       builder.AddValue(value[i]);
7176     }
7177     RecordIdentifiableGLParameterDigest(pname, builder.GetToken());
7178   }
7179   return WebGLAny(script_state, DOMFloat32Array::Create(value, length));
7180 }
7181 
GetWebGLIntArrayParameter(ScriptState * script_state,GLenum pname)7182 ScriptValue WebGLRenderingContextBase::GetWebGLIntArrayParameter(
7183     ScriptState* script_state,
7184     GLenum pname) {
7185   GLint value[4] = {0};
7186   if (!isContextLost())
7187     ContextGL()->GetIntegerv(pname, value);
7188   unsigned length = 0;
7189   switch (pname) {
7190     case GL_MAX_VIEWPORT_DIMS:
7191       length = 2;
7192       break;
7193     case GL_SCISSOR_BOX:
7194     case GL_VIEWPORT:
7195       length = 4;
7196       break;
7197     default:
7198       NOTIMPLEMENTED();
7199   }
7200   if (ShouldMeasureGLParam(pname)) {
7201     blink::IdentifiableTokenBuilder builder;
7202     for (unsigned i = 0; i < length; i++) {
7203       builder.AddValue(value[i]);
7204     }
7205     RecordIdentifiableGLParameterDigest(pname, builder.GetToken());
7206   }
7207   return WebGLAny(script_state, DOMInt32Array::Create(value, length));
7208 }
7209 
ValidateTexture2DBinding(const char * function_name,GLenum target)7210 WebGLTexture* WebGLRenderingContextBase::ValidateTexture2DBinding(
7211     const char* function_name,
7212     GLenum target) {
7213   WebGLTexture* tex = nullptr;
7214   switch (target) {
7215     case GL_TEXTURE_2D:
7216       tex = texture_units_[active_texture_unit_].texture2d_binding_.Get();
7217       break;
7218     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
7219     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
7220     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
7221     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
7222     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
7223     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
7224       tex =
7225           texture_units_[active_texture_unit_].texture_cube_map_binding_.Get();
7226       break;
7227     default:
7228       SynthesizeGLError(GL_INVALID_ENUM, function_name,
7229                         "invalid texture target");
7230       return nullptr;
7231   }
7232   if (!tex)
7233     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7234                       "no texture bound to target");
7235   return tex;
7236 }
7237 
ValidateTextureBinding(const char * function_name,GLenum target)7238 WebGLTexture* WebGLRenderingContextBase::ValidateTextureBinding(
7239     const char* function_name,
7240     GLenum target) {
7241   WebGLTexture* tex = nullptr;
7242   switch (target) {
7243     case GL_TEXTURE_2D:
7244       tex = texture_units_[active_texture_unit_].texture2d_binding_.Get();
7245       break;
7246     case GL_TEXTURE_CUBE_MAP:
7247       tex =
7248           texture_units_[active_texture_unit_].texture_cube_map_binding_.Get();
7249       break;
7250     case GL_TEXTURE_3D:
7251       if (!IsWebGL2()) {
7252         SynthesizeGLError(GL_INVALID_ENUM, function_name,
7253                           "invalid texture target");
7254         return nullptr;
7255       }
7256       tex = texture_units_[active_texture_unit_].texture3d_binding_.Get();
7257       break;
7258     case GL_TEXTURE_2D_ARRAY:
7259       if (!IsWebGL2()) {
7260         SynthesizeGLError(GL_INVALID_ENUM, function_name,
7261                           "invalid texture target");
7262         return nullptr;
7263       }
7264       tex = texture_units_[active_texture_unit_].texture2d_array_binding_.Get();
7265       break;
7266     case GL_TEXTURE_VIDEO_IMAGE_WEBGL:
7267       if (!ExtensionEnabled(kWebGLVideoTextureName)) {
7268         SynthesizeGLError(GL_INVALID_ENUM, function_name,
7269                           "invalid texture target");
7270         return nullptr;
7271       }
7272       tex = texture_units_[active_texture_unit_]
7273                 .texture_video_image_binding_.Get();
7274       break;
7275     default:
7276       SynthesizeGLError(GL_INVALID_ENUM, function_name,
7277                         "invalid texture target");
7278       return nullptr;
7279   }
7280   if (!tex)
7281     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7282                       "no texture bound to target");
7283   return tex;
7284 }
7285 
ValidateLocationLength(const char * function_name,const String & string)7286 bool WebGLRenderingContextBase::ValidateLocationLength(
7287     const char* function_name,
7288     const String& string) {
7289   const unsigned max_web_gl_location_length = GetMaxWebGLLocationLength();
7290   if (string.length() > max_web_gl_location_length) {
7291     SynthesizeGLError(GL_INVALID_VALUE, function_name, "location length > 256");
7292     return false;
7293   }
7294   return true;
7295 }
7296 
ValidateSize(const char * function_name,GLint x,GLint y,GLint z)7297 bool WebGLRenderingContextBase::ValidateSize(const char* function_name,
7298                                              GLint x,
7299                                              GLint y,
7300                                              GLint z) {
7301   if (x < 0 || y < 0 || z < 0) {
7302     SynthesizeGLError(GL_INVALID_VALUE, function_name, "size < 0");
7303     return false;
7304   }
7305   return true;
7306 }
7307 
ValidateCharacter(unsigned char c)7308 bool WebGLRenderingContextBase::ValidateCharacter(unsigned char c) {
7309   // Printing characters are valid except " $ ` @ \ ' DEL.
7310   if (c >= 32 && c <= 126 && c != '"' && c != '$' && c != '`' && c != '@' &&
7311       c != '\\' && c != '\'')
7312     return true;
7313   // Horizontal tab, line feed, vertical tab, form feed, carriage return
7314   // are also valid.
7315   if (c >= 9 && c <= 13)
7316     return true;
7317   return false;
7318 }
7319 
ValidateString(const char * function_name,const String & string)7320 bool WebGLRenderingContextBase::ValidateString(const char* function_name,
7321                                                const String& string) {
7322   for (wtf_size_t i = 0; i < string.length(); ++i) {
7323     if (!ValidateCharacter(string[i])) {
7324       SynthesizeGLError(GL_INVALID_VALUE, function_name, "string not ASCII");
7325       return false;
7326     }
7327   }
7328   return true;
7329 }
7330 
IsPrefixReserved(const String & name)7331 bool WebGLRenderingContextBase::IsPrefixReserved(const String& name) {
7332   if (name.StartsWith("gl_") || name.StartsWith("webgl_") ||
7333       name.StartsWith("_webgl_"))
7334     return true;
7335   return false;
7336 }
7337 
ValidateShaderType(const char * function_name,GLenum shader_type)7338 bool WebGLRenderingContextBase::ValidateShaderType(const char* function_name,
7339                                                    GLenum shader_type) {
7340   switch (shader_type) {
7341     case GL_VERTEX_SHADER:
7342     case GL_FRAGMENT_SHADER:
7343       return true;
7344     default:
7345       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid shader type");
7346       return false;
7347   }
7348 }
7349 
AddExtensionSupportedFormatsTypes()7350 void WebGLRenderingContextBase::AddExtensionSupportedFormatsTypes() {
7351   if (!is_oes_texture_float_formats_types_added_ &&
7352       ExtensionEnabled(kOESTextureFloatName)) {
7353     ADD_VALUES_TO_SET(supported_types_, kSupportedTypesOESTexFloat);
7354     ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7355                       kSupportedTypesOESTexFloat);
7356     is_oes_texture_float_formats_types_added_ = true;
7357   }
7358 
7359   if (!is_oes_texture_half_float_formats_types_added_ &&
7360       ExtensionEnabled(kOESTextureHalfFloatName)) {
7361     ADD_VALUES_TO_SET(supported_types_, kSupportedTypesOESTexHalfFloat);
7362     ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7363                       kSupportedTypesOESTexHalfFloat);
7364     is_oes_texture_half_float_formats_types_added_ = true;
7365   }
7366 
7367   if (!is_web_gl_depth_texture_formats_types_added_ &&
7368       ExtensionEnabled(kWebGLDepthTextureName)) {
7369     ADD_VALUES_TO_SET(supported_internal_formats_,
7370                       kSupportedInternalFormatsOESDepthTex);
7371     ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7372                       kSupportedInternalFormatsOESDepthTex);
7373     ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsOESDepthTex);
7374     ADD_VALUES_TO_SET(supported_tex_image_source_formats_,
7375                       kSupportedFormatsOESDepthTex);
7376     ADD_VALUES_TO_SET(supported_types_, kSupportedTypesOESDepthTex);
7377     ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7378                       kSupportedTypesOESDepthTex);
7379     is_web_gl_depth_texture_formats_types_added_ = true;
7380   }
7381 
7382   if (!is_ext_srgb_formats_types_added_ && ExtensionEnabled(kEXTsRGBName)) {
7383     ADD_VALUES_TO_SET(supported_internal_formats_,
7384                       kSupportedInternalFormatsEXTsRGB);
7385     ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7386                       kSupportedInternalFormatsEXTsRGB);
7387     ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsEXTsRGB);
7388     ADD_VALUES_TO_SET(supported_tex_image_source_formats_,
7389                       kSupportedFormatsEXTsRGB);
7390     is_ext_srgb_formats_types_added_ = true;
7391   }
7392 }
7393 
AddExtensionSupportedFormatsTypesWebGL2()7394 void WebGLRenderingContextBase::AddExtensionSupportedFormatsTypesWebGL2() {
7395   if (!is_ext_texture_norm16_added_ &&
7396       ExtensionEnabled(kEXTTextureNorm16Name)) {
7397     ADD_VALUES_TO_SET(supported_internal_formats_,
7398                       kSupportedInternalFormatsEXTTextureNorm16ES3);
7399     ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7400                       kSupportedInternalFormatsEXTTextureNorm16ES3);
7401     ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsEXTTextureNorm16ES3);
7402     ADD_VALUES_TO_SET(supported_types_, kSupportedTypesEXTTextureNorm16ES3);
7403     is_ext_texture_norm16_added_ = true;
7404   }
7405 }
7406 
ValidateTexImageSourceFormatAndType(const char * function_name,TexImageFunctionType function_type,GLenum internalformat,GLenum format,GLenum type)7407 bool WebGLRenderingContextBase::ValidateTexImageSourceFormatAndType(
7408     const char* function_name,
7409     TexImageFunctionType function_type,
7410     GLenum internalformat,
7411     GLenum format,
7412     GLenum type) {
7413   if (!is_web_gl2_tex_image_source_formats_types_added_ && IsWebGL2()) {
7414     ADD_VALUES_TO_SET(supported_tex_image_source_internal_formats_,
7415                       kSupportedInternalFormatsTexImageSourceES3);
7416     ADD_VALUES_TO_SET(supported_tex_image_source_formats_,
7417                       kSupportedFormatsTexImageSourceES3);
7418     ADD_VALUES_TO_SET(supported_tex_image_source_types_,
7419                       kSupportedTypesTexImageSourceES3);
7420     is_web_gl2_tex_image_source_formats_types_added_ = true;
7421   }
7422 
7423   if (!IsWebGL2()) {
7424     AddExtensionSupportedFormatsTypes();
7425   } else {
7426     AddExtensionSupportedFormatsTypesWebGL2();
7427   }
7428 
7429   if (internalformat != 0 &&
7430       supported_tex_image_source_internal_formats_.find(internalformat) ==
7431           supported_tex_image_source_internal_formats_.end()) {
7432     if (function_type == kTexImage) {
7433       SynthesizeGLError(GL_INVALID_VALUE, function_name,
7434                         "invalid internalformat");
7435     } else {
7436       SynthesizeGLError(GL_INVALID_ENUM, function_name,
7437                         "invalid internalformat");
7438     }
7439     return false;
7440   }
7441   if (supported_tex_image_source_formats_.find(format) ==
7442       supported_tex_image_source_formats_.end()) {
7443     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid format");
7444     return false;
7445   }
7446   if (supported_tex_image_source_types_.find(type) ==
7447       supported_tex_image_source_types_.end()) {
7448     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid type");
7449     return false;
7450   }
7451 
7452   return true;
7453 }
7454 
ValidateTexFuncFormatAndType(const char * function_name,TexImageFunctionType function_type,GLenum internalformat,GLenum format,GLenum type,GLint level)7455 bool WebGLRenderingContextBase::ValidateTexFuncFormatAndType(
7456     const char* function_name,
7457     TexImageFunctionType function_type,
7458     GLenum internalformat,
7459     GLenum format,
7460     GLenum type,
7461     GLint level) {
7462   if (!is_web_gl2_formats_types_added_ && IsWebGL2()) {
7463     ADD_VALUES_TO_SET(supported_internal_formats_,
7464                       kSupportedInternalFormatsES3);
7465     ADD_VALUES_TO_SET(supported_internal_formats_,
7466                       kSupportedInternalFormatsTexImageES3);
7467     ADD_VALUES_TO_SET(supported_formats_, kSupportedFormatsES3);
7468     ADD_VALUES_TO_SET(supported_types_, kSupportedTypesES3);
7469     is_web_gl2_formats_types_added_ = true;
7470   }
7471 
7472   if (!IsWebGL2()) {
7473     AddExtensionSupportedFormatsTypes();
7474   } else {
7475     AddExtensionSupportedFormatsTypesWebGL2();
7476   }
7477 
7478   if (internalformat != 0 && supported_internal_formats_.find(internalformat) ==
7479                                  supported_internal_formats_.end()) {
7480     if (function_type == kTexImage) {
7481       if (compressed_texture_formats_.Contains(internalformat)) {
7482         SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7483                           "compressed texture formats are not accepted");
7484       } else {
7485         SynthesizeGLError(GL_INVALID_VALUE, function_name,
7486                           "invalid internalformat");
7487       }
7488     } else {
7489       SynthesizeGLError(GL_INVALID_ENUM, function_name,
7490                         "invalid internalformat");
7491     }
7492     return false;
7493   }
7494   if (supported_formats_.find(format) == supported_formats_.end()) {
7495     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid format");
7496     return false;
7497   }
7498   if (supported_types_.find(type) == supported_types_.end()) {
7499     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid type");
7500     return false;
7501   }
7502 
7503   if (format == GL_DEPTH_COMPONENT && level > 0 && !IsWebGL2()) {
7504     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7505                       "level must be 0 for DEPTH_COMPONENT format");
7506     return false;
7507   }
7508   if (format == GL_DEPTH_STENCIL_OES && level > 0 && !IsWebGL2()) {
7509     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7510                       "level must be 0 for DEPTH_STENCIL format");
7511     return false;
7512   }
7513 
7514   return true;
7515 }
7516 
GetMaxTextureLevelForTarget(GLenum target)7517 GLint WebGLRenderingContextBase::GetMaxTextureLevelForTarget(GLenum target) {
7518   switch (target) {
7519     case GL_TEXTURE_2D:
7520       return max_texture_level_;
7521     case GL_TEXTURE_CUBE_MAP:
7522     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
7523     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
7524     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
7525     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
7526     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
7527     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
7528       return max_cube_map_texture_level_;
7529     case GL_TEXTURE_VIDEO_IMAGE_WEBGL:
7530       return 1;
7531   }
7532   return 0;
7533 }
7534 
ValidateTexFuncLevel(const char * function_name,GLenum target,GLint level)7535 bool WebGLRenderingContextBase::ValidateTexFuncLevel(const char* function_name,
7536                                                      GLenum target,
7537                                                      GLint level) {
7538   if (level < 0) {
7539     SynthesizeGLError(GL_INVALID_VALUE, function_name, "level < 0");
7540     return false;
7541   }
7542   GLint max_level = GetMaxTextureLevelForTarget(target);
7543   if (max_level && level >= max_level) {
7544     SynthesizeGLError(GL_INVALID_VALUE, function_name, "level out of range");
7545     return false;
7546   }
7547   // This function only checks if level is legal, so we return true and don't
7548   // generate INVALID_ENUM if target is illegal.
7549   return true;
7550 }
7551 
ValidateTexFuncDimensions(const char * function_name,TexImageFunctionType function_type,GLenum target,GLint level,GLsizei width,GLsizei height,GLsizei depth)7552 bool WebGLRenderingContextBase::ValidateTexFuncDimensions(
7553     const char* function_name,
7554     TexImageFunctionType function_type,
7555     GLenum target,
7556     GLint level,
7557     GLsizei width,
7558     GLsizei height,
7559     GLsizei depth) {
7560   if (width < 0 || height < 0 || depth < 0) {
7561     SynthesizeGLError(GL_INVALID_VALUE, function_name,
7562                       "width, height or depth < 0");
7563     return false;
7564   }
7565 
7566   switch (target) {
7567     case GL_TEXTURE_2D:
7568     case GL_TEXTURE_VIDEO_IMAGE_WEBGL:
7569       if (width > (max_texture_size_ >> level) ||
7570           height > (max_texture_size_ >> level)) {
7571         SynthesizeGLError(GL_INVALID_VALUE, function_name,
7572                           "width or height out of range");
7573         return false;
7574       }
7575       break;
7576     case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
7577     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
7578     case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
7579     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
7580     case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
7581     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
7582       if (function_type != kTexSubImage && width != height) {
7583         SynthesizeGLError(GL_INVALID_VALUE, function_name,
7584                           "width != height for cube map");
7585         return false;
7586       }
7587       // No need to check height here. For texImage width == height.
7588       // For texSubImage that will be checked when checking yoffset + height is
7589       // in range.
7590       if (width > (max_cube_map_texture_size_ >> level)) {
7591         SynthesizeGLError(GL_INVALID_VALUE, function_name,
7592                           "width or height out of range for cube map");
7593         return false;
7594       }
7595       break;
7596     case GL_TEXTURE_3D:
7597       if (IsWebGL2()) {
7598         if (width > (max3d_texture_size_ >> level) ||
7599             height > (max3d_texture_size_ >> level) ||
7600             depth > (max3d_texture_size_ >> level)) {
7601           SynthesizeGLError(GL_INVALID_VALUE, function_name,
7602                             "width, height or depth out of range");
7603           return false;
7604         }
7605         break;
7606       }
7607       FALLTHROUGH;
7608     case GL_TEXTURE_2D_ARRAY:
7609       if (IsWebGL2()) {
7610         if (width > (max_texture_size_ >> level) ||
7611             height > (max_texture_size_ >> level) ||
7612             depth > max_array_texture_layers_) {
7613           SynthesizeGLError(GL_INVALID_VALUE, function_name,
7614                             "width, height or depth out of range");
7615           return false;
7616         }
7617         break;
7618       }
7619       FALLTHROUGH;
7620     default:
7621       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
7622       return false;
7623   }
7624   return true;
7625 }
7626 
ValidateTexFuncParameters(const char * function_name,TexImageFunctionType function_type,TexFuncValidationSourceType source_type,GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type)7627 bool WebGLRenderingContextBase::ValidateTexFuncParameters(
7628     const char* function_name,
7629     TexImageFunctionType function_type,
7630     TexFuncValidationSourceType source_type,
7631     GLenum target,
7632     GLint level,
7633     GLenum internalformat,
7634     GLsizei width,
7635     GLsizei height,
7636     GLsizei depth,
7637     GLint border,
7638     GLenum format,
7639     GLenum type) {
7640   // We absolutely have to validate the format and type combination.
7641   // The texImage2D entry points taking HTMLImage, etc. will produce
7642   // temporary data based on this combination, so it must be legal.
7643   if (source_type == kSourceHTMLImageElement ||
7644       source_type == kSourceHTMLCanvasElement ||
7645       source_type == kSourceHTMLVideoElement ||
7646       source_type == kSourceImageData || source_type == kSourceImageBitmap) {
7647     if (!ValidateTexImageSourceFormatAndType(function_name, function_type,
7648                                              internalformat, format, type)) {
7649       return false;
7650     }
7651   } else {
7652     if (!ValidateTexFuncFormatAndType(function_name, function_type,
7653                                       internalformat, format, type, level)) {
7654       return false;
7655     }
7656   }
7657 
7658   if (!ValidateTexFuncDimensions(function_name, function_type, target, level,
7659                                  width, height, depth))
7660     return false;
7661 
7662   if (border) {
7663     SynthesizeGLError(GL_INVALID_VALUE, function_name, "border != 0");
7664     return false;
7665   }
7666 
7667   return true;
7668 }
7669 
ValidateTexFuncData(const char * function_name,TexImageDimension tex_dimension,GLint level,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,DOMArrayBufferView * pixels,NullDisposition disposition,GLuint src_offset)7670 bool WebGLRenderingContextBase::ValidateTexFuncData(
7671     const char* function_name,
7672     TexImageDimension tex_dimension,
7673     GLint level,
7674     GLsizei width,
7675     GLsizei height,
7676     GLsizei depth,
7677     GLenum format,
7678     GLenum type,
7679     DOMArrayBufferView* pixels,
7680     NullDisposition disposition,
7681     GLuint src_offset) {
7682   // All calling functions check isContextLost, so a duplicate check is not
7683   // needed here.
7684   if (!pixels) {
7685     DCHECK_NE(disposition, kNullNotReachable);
7686     if (disposition == kNullAllowed)
7687       return true;
7688     SynthesizeGLError(GL_INVALID_VALUE, function_name, "no pixels");
7689     return false;
7690   }
7691 
7692   if (!ValidateSettableTexFormat(function_name, format))
7693     return false;
7694 
7695   auto pixelType = pixels->GetType();
7696 
7697   switch (type) {
7698     case GL_BYTE:
7699       if (pixelType != DOMArrayBufferView::kTypeInt8) {
7700         SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7701                           "type BYTE but ArrayBufferView not Int8Array");
7702         return false;
7703       }
7704       break;
7705     case GL_UNSIGNED_BYTE:
7706       if (pixelType != DOMArrayBufferView::kTypeUint8 &&
7707           pixelType != DOMArrayBufferView::kTypeUint8Clamped) {
7708         SynthesizeGLError(
7709             GL_INVALID_OPERATION, function_name,
7710             "type UNSIGNED_BYTE but ArrayBufferView not Uint8Array or "
7711             "Uint8ClampedArray");
7712         return false;
7713       }
7714       break;
7715     case GL_SHORT:
7716       if (pixelType != DOMArrayBufferView::kTypeInt16) {
7717         SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7718                           "type SHORT but ArrayBufferView not Int16Array");
7719         return false;
7720       }
7721       break;
7722     case GL_UNSIGNED_SHORT:
7723     case GL_UNSIGNED_SHORT_5_6_5:
7724     case GL_UNSIGNED_SHORT_4_4_4_4:
7725     case GL_UNSIGNED_SHORT_5_5_5_1:
7726       if (pixelType != DOMArrayBufferView::kTypeUint16) {
7727         SynthesizeGLError(
7728             GL_INVALID_OPERATION, function_name,
7729             "type UNSIGNED_SHORT but ArrayBufferView not Uint16Array");
7730         return false;
7731       }
7732       break;
7733     case GL_INT:
7734       if (pixelType != DOMArrayBufferView::kTypeInt32) {
7735         SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7736                           "type INT but ArrayBufferView not Int32Array");
7737         return false;
7738       }
7739       break;
7740     case GL_UNSIGNED_INT:
7741     case GL_UNSIGNED_INT_2_10_10_10_REV:
7742     case GL_UNSIGNED_INT_10F_11F_11F_REV:
7743     case GL_UNSIGNED_INT_5_9_9_9_REV:
7744     case GL_UNSIGNED_INT_24_8:
7745       if (pixelType != DOMArrayBufferView::kTypeUint32) {
7746         SynthesizeGLError(
7747             GL_INVALID_OPERATION, function_name,
7748             "type UNSIGNED_INT but ArrayBufferView not Uint32Array");
7749         return false;
7750       }
7751       break;
7752     case GL_FLOAT:  // OES_texture_float
7753       if (pixelType != DOMArrayBufferView::kTypeFloat32) {
7754         SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7755                           "type FLOAT but ArrayBufferView not Float32Array");
7756         return false;
7757       }
7758       break;
7759     case GL_HALF_FLOAT:
7760     case GL_HALF_FLOAT_OES:  // OES_texture_half_float
7761       // As per the specification, ArrayBufferView should be null or a
7762       // Uint16Array when OES_texture_half_float is enabled.
7763       if (pixelType != DOMArrayBufferView::kTypeUint16) {
7764         SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7765                           "type HALF_FLOAT_OES but ArrayBufferView is not NULL "
7766                           "and not Uint16Array");
7767         return false;
7768       }
7769       break;
7770     case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
7771       SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7772                         "type FLOAT_32_UNSIGNED_INT_24_8_REV but "
7773                         "ArrayBufferView is not NULL");
7774       return false;
7775     default:
7776       NOTREACHED();
7777   }
7778 
7779   unsigned total_bytes_required, skip_bytes;
7780   GLenum error = WebGLImageConversion::ComputeImageSizeInBytes(
7781       format, type, width, height, depth,
7782       GetUnpackPixelStoreParams(tex_dimension), &total_bytes_required, nullptr,
7783       &skip_bytes);
7784   if (error != GL_NO_ERROR) {
7785     SynthesizeGLError(error, function_name, "invalid texture dimensions");
7786     return false;
7787   }
7788   base::CheckedNumeric<uint32_t> total = src_offset;
7789   total *= pixels->TypeSize();
7790   total += total_bytes_required;
7791   total += skip_bytes;
7792   if (!total.IsValid() ||
7793       pixels->byteLength() < static_cast<size_t>(total.ValueOrDie())) {
7794     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7795                       "ArrayBufferView not big enough for request");
7796     return false;
7797   }
7798   return true;
7799 }
7800 
ValidateCompressedTexFormat(const char * function_name,GLenum format)7801 bool WebGLRenderingContextBase::ValidateCompressedTexFormat(
7802     const char* function_name,
7803     GLenum format) {
7804   if (!compressed_texture_formats_.Contains(format)) {
7805     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid format");
7806     return false;
7807   }
7808   return true;
7809 }
7810 
ValidateStencilOrDepthFunc(const char * function_name,GLenum func)7811 bool WebGLRenderingContextBase::ValidateStencilOrDepthFunc(
7812     const char* function_name,
7813     GLenum func) {
7814   switch (func) {
7815     case GL_NEVER:
7816     case GL_LESS:
7817     case GL_LEQUAL:
7818     case GL_GREATER:
7819     case GL_GEQUAL:
7820     case GL_EQUAL:
7821     case GL_NOTEQUAL:
7822     case GL_ALWAYS:
7823       return true;
7824     default:
7825       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid function");
7826       return false;
7827   }
7828 }
7829 
PrintGLErrorToConsole(const String & message)7830 void WebGLRenderingContextBase::PrintGLErrorToConsole(const String& message) {
7831   if (!num_gl_errors_to_console_allowed_)
7832     return;
7833 
7834   --num_gl_errors_to_console_allowed_;
7835   PrintWarningToConsole(message);
7836 
7837   if (!num_gl_errors_to_console_allowed_)
7838     PrintWarningToConsole(
7839         "WebGL: too many errors, no more errors will be reported to the "
7840         "console for this context.");
7841 
7842   return;
7843 }
7844 
PrintWarningToConsole(const String & message)7845 void WebGLRenderingContextBase::PrintWarningToConsole(const String& message) {
7846   if (fast_call_.InFastCall()) {
7847     fast_call_.AddDeferredConsoleWarning(message);
7848     return;
7849   }
7850 
7851   blink::ExecutionContext* context = Host()->GetTopExecutionContext();
7852   if (context && !context->IsContextDestroyed()) {
7853     context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
7854         mojom::ConsoleMessageSource::kRendering,
7855         mojom::ConsoleMessageLevel::kWarning, message));
7856   }
7857 }
7858 
NotifyWebGLErrorOrWarning(const String & message)7859 void WebGLRenderingContextBase::NotifyWebGLErrorOrWarning(
7860     const String& message) {
7861   if (fast_call_.InFastCall()) {
7862     fast_call_.AddDeferredErrorOrWarningNotification(message);
7863     return;
7864   }
7865   probe::DidFireWebGLErrorOrWarning(canvas(), message);
7866 }
7867 
NotifyWebGLError(const String & error_type)7868 void WebGLRenderingContextBase::NotifyWebGLError(const String& error_type) {
7869   if (fast_call_.InFastCall()) {
7870     fast_call_.AddDeferredErrorNotification(error_type);
7871     return;
7872   }
7873   probe::DidFireWebGLError(canvas(), error_type);
7874 }
7875 
NotifyWebGLWarning()7876 void WebGLRenderingContextBase::NotifyWebGLWarning() {
7877   if (fast_call_.InFastCall()) {
7878     fast_call_.AddDeferredWarningNotification();
7879     return;
7880   }
7881   probe::DidFireWebGLWarning(canvas());
7882 }
7883 
ValidateFramebufferFuncParameters(const char * function_name,GLenum target,GLenum attachment)7884 bool WebGLRenderingContextBase::ValidateFramebufferFuncParameters(
7885     const char* function_name,
7886     GLenum target,
7887     GLenum attachment) {
7888   if (!ValidateFramebufferTarget(target)) {
7889     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
7890     return false;
7891   }
7892   switch (attachment) {
7893     case GL_COLOR_ATTACHMENT0:
7894     case GL_DEPTH_ATTACHMENT:
7895     case GL_STENCIL_ATTACHMENT:
7896     case GL_DEPTH_STENCIL_ATTACHMENT:
7897       break;
7898     default:
7899       if ((ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()) &&
7900           attachment > GL_COLOR_ATTACHMENT0 &&
7901           attachment <
7902               static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + MaxColorAttachments()))
7903         break;
7904       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid attachment");
7905       return false;
7906   }
7907   return true;
7908 }
7909 
ValidateBlendEquation(const char * function_name,GLenum mode)7910 bool WebGLRenderingContextBase::ValidateBlendEquation(const char* function_name,
7911                                                       GLenum mode) {
7912   switch (mode) {
7913     case GL_FUNC_ADD:
7914     case GL_FUNC_SUBTRACT:
7915     case GL_FUNC_REVERSE_SUBTRACT:
7916       return true;
7917     case GL_MIN_EXT:
7918     case GL_MAX_EXT:
7919       if (ExtensionEnabled(kEXTBlendMinMaxName) || IsWebGL2())
7920         return true;
7921       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid mode");
7922       return false;
7923     default:
7924       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid mode");
7925       return false;
7926   }
7927 }
7928 
ValidateBlendFuncFactors(const char * function_name,GLenum src,GLenum dst)7929 bool WebGLRenderingContextBase::ValidateBlendFuncFactors(
7930     const char* function_name,
7931     GLenum src,
7932     GLenum dst) {
7933   if (((src == GL_CONSTANT_COLOR || src == GL_ONE_MINUS_CONSTANT_COLOR) &&
7934        (dst == GL_CONSTANT_ALPHA || dst == GL_ONE_MINUS_CONSTANT_ALPHA)) ||
7935       ((dst == GL_CONSTANT_COLOR || dst == GL_ONE_MINUS_CONSTANT_COLOR) &&
7936        (src == GL_CONSTANT_ALPHA || src == GL_ONE_MINUS_CONSTANT_ALPHA))) {
7937     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
7938                       "incompatible src and dst");
7939     return false;
7940   }
7941   return true;
7942 }
7943 
ValidateCapability(const char * function_name,GLenum cap)7944 bool WebGLRenderingContextBase::ValidateCapability(const char* function_name,
7945                                                    GLenum cap) {
7946   switch (cap) {
7947     case GL_BLEND:
7948     case GL_CULL_FACE:
7949     case GL_DEPTH_TEST:
7950     case GL_DITHER:
7951     case GL_POLYGON_OFFSET_FILL:
7952     case GL_SAMPLE_ALPHA_TO_COVERAGE:
7953     case GL_SAMPLE_COVERAGE:
7954     case GL_SCISSOR_TEST:
7955     case GL_STENCIL_TEST:
7956       return true;
7957     default:
7958       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid capability");
7959       return false;
7960   }
7961 }
7962 
ValidateUniformParameters(const char * function_name,const WebGLUniformLocation * location,void * v,GLsizei size,GLsizei required_min_size,GLuint src_offset,GLuint src_length)7963 bool WebGLRenderingContextBase::ValidateUniformParameters(
7964     const char* function_name,
7965     const WebGLUniformLocation* location,
7966     void* v,
7967     GLsizei size,
7968     GLsizei required_min_size,
7969     GLuint src_offset,
7970     GLuint src_length) {
7971   return ValidateUniformMatrixParameters(function_name, location, false, v,
7972                                          size, required_min_size, src_offset,
7973                                          src_length);
7974 }
7975 
ValidateUniformMatrixParameters(const char * function_name,const WebGLUniformLocation * location,GLboolean transpose,DOMFloat32Array * v,GLsizei required_min_size,GLuint src_offset,size_t src_length)7976 bool WebGLRenderingContextBase::ValidateUniformMatrixParameters(
7977     const char* function_name,
7978     const WebGLUniformLocation* location,
7979     GLboolean transpose,
7980     DOMFloat32Array* v,
7981     GLsizei required_min_size,
7982     GLuint src_offset,
7983     size_t src_length) {
7984   if (!v) {
7985     SynthesizeGLError(GL_INVALID_VALUE, function_name, "no array");
7986     return false;
7987   }
7988   if (!base::CheckedNumeric<GLuint>(src_length).IsValid()) {
7989     SynthesizeGLError(GL_INVALID_VALUE, function_name,
7990                       "src_length exceeds the maximum supported length");
7991     return false;
7992   }
7993   return ValidateUniformMatrixParameters(
7994       function_name, location, transpose, v->DataMaybeShared(), v->length(),
7995       required_min_size, src_offset, static_cast<GLuint>(src_length));
7996 }
7997 
ValidateUniformMatrixParameters(const char * function_name,const WebGLUniformLocation * location,GLboolean transpose,void * v,size_t size,GLsizei required_min_size,GLuint src_offset,GLuint src_length)7998 bool WebGLRenderingContextBase::ValidateUniformMatrixParameters(
7999     const char* function_name,
8000     const WebGLUniformLocation* location,
8001     GLboolean transpose,
8002     void* v,
8003     size_t size,
8004     GLsizei required_min_size,
8005     GLuint src_offset,
8006     GLuint src_length) {
8007   DCHECK(size >= 0 && required_min_size > 0);
8008   if (!location)
8009     return false;
8010   if (location->Program() != current_program_) {
8011     SynthesizeGLError(GL_INVALID_OPERATION, function_name,
8012                       "location is not from current program");
8013     return false;
8014   }
8015   if (!v) {
8016     SynthesizeGLError(GL_INVALID_VALUE, function_name, "no array");
8017     return false;
8018   }
8019   if (!base::CheckedNumeric<GLsizei>(size).IsValid()) {
8020     SynthesizeGLError(GL_INVALID_VALUE, function_name,
8021                       "array exceeds the maximum supported size");
8022     return false;
8023   }
8024   if (transpose && !IsWebGL2()) {
8025     SynthesizeGLError(GL_INVALID_VALUE, function_name, "transpose not FALSE");
8026     return false;
8027   }
8028   if (src_offset >= static_cast<GLuint>(size)) {
8029     SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid srcOffset");
8030     return false;
8031   }
8032   GLsizei actual_size = static_cast<GLsizei>(size) - src_offset;
8033   if (src_length > 0) {
8034     if (src_length > static_cast<GLuint>(actual_size)) {
8035       SynthesizeGLError(GL_INVALID_VALUE, function_name,
8036                         "invalid srcOffset + srcLength");
8037       return false;
8038     }
8039     actual_size = src_length;
8040   }
8041   if (actual_size < required_min_size || (actual_size % required_min_size)) {
8042     SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid size");
8043     return false;
8044   }
8045   return true;
8046 }
8047 
ValidateBufferDataTarget(const char * function_name,GLenum target)8048 WebGLBuffer* WebGLRenderingContextBase::ValidateBufferDataTarget(
8049     const char* function_name,
8050     GLenum target) {
8051   WebGLBuffer* buffer = nullptr;
8052   switch (target) {
8053     case GL_ELEMENT_ARRAY_BUFFER:
8054       buffer = bound_vertex_array_object_->BoundElementArrayBuffer();
8055       break;
8056     case GL_ARRAY_BUFFER:
8057       buffer = bound_array_buffer_.Get();
8058       break;
8059     default:
8060       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid target");
8061       return nullptr;
8062   }
8063   if (!buffer) {
8064     SynthesizeGLError(GL_INVALID_OPERATION, function_name, "no buffer");
8065     return nullptr;
8066   }
8067   return buffer;
8068 }
8069 
ValidateBufferDataUsage(const char * function_name,GLenum usage)8070 bool WebGLRenderingContextBase::ValidateBufferDataUsage(
8071     const char* function_name,
8072     GLenum usage) {
8073   switch (usage) {
8074     case GL_STREAM_DRAW:
8075     case GL_STATIC_DRAW:
8076     case GL_DYNAMIC_DRAW:
8077       return true;
8078     default:
8079       SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid usage");
8080       return false;
8081   }
8082 }
8083 
RemoveBoundBuffer(WebGLBuffer * buffer)8084 void WebGLRenderingContextBase::RemoveBoundBuffer(WebGLBuffer* buffer) {
8085   if (bound_array_buffer_ == buffer)
8086     bound_array_buffer_ = nullptr;
8087 
8088   bound_vertex_array_object_->UnbindBuffer(buffer);
8089 }
8090 
ValidateHTMLImageElement(const SecurityOrigin * security_origin,const char * function_name,HTMLImageElement * image,ExceptionState & exception_state)8091 bool WebGLRenderingContextBase::ValidateHTMLImageElement(
8092     const SecurityOrigin* security_origin,
8093     const char* function_name,
8094     HTMLImageElement* image,
8095     ExceptionState& exception_state) {
8096   if (!image || !image->CachedImage()) {
8097     SynthesizeGLError(GL_INVALID_VALUE, function_name, "no image");
8098     return false;
8099   }
8100   const KURL& url = image->CachedImage()->GetResponse().CurrentRequestUrl();
8101   if (url.IsNull() || url.IsEmpty() || !url.IsValid()) {
8102     SynthesizeGLError(GL_INVALID_VALUE, function_name, "invalid image");
8103     return false;
8104   }
8105 
8106   if (WouldTaintOrigin(image)) {
8107     exception_state.ThrowSecurityError(
8108         "The image element contains cross-origin data, and may not be loaded.");
8109     return false;
8110   }
8111   return true;
8112 }
8113 
ValidateCanvasRenderingContextHost(const SecurityOrigin * security_origin,const char * function_name,CanvasRenderingContextHost * context_host,ExceptionState & exception_state)8114 bool WebGLRenderingContextBase::ValidateCanvasRenderingContextHost(
8115     const SecurityOrigin* security_origin,
8116     const char* function_name,
8117     CanvasRenderingContextHost* context_host,
8118     ExceptionState& exception_state) {
8119   if (!context_host || !context_host->IsPaintable()) {
8120     SynthesizeGLError(GL_INVALID_VALUE, function_name, "no canvas");
8121     return false;
8122   }
8123 
8124   if (WouldTaintOrigin(context_host)) {
8125     exception_state.ThrowSecurityError("Tainted canvases may not be loaded.");
8126     return false;
8127   }
8128   return true;
8129 }
8130 
ValidateHTMLVideoElement(const SecurityOrigin * security_origin,const char * function_name,HTMLVideoElement * video,ExceptionState & exception_state)8131 bool WebGLRenderingContextBase::ValidateHTMLVideoElement(
8132     const SecurityOrigin* security_origin,
8133     const char* function_name,
8134     HTMLVideoElement* video,
8135     ExceptionState& exception_state) {
8136   if (!video || !video->videoWidth() || !video->videoHeight()) {
8137     SynthesizeGLError(GL_INVALID_VALUE, function_name, "no video");
8138     return false;
8139   }
8140 
8141   if (WouldTaintOrigin(video)) {
8142     exception_state.ThrowSecurityError(
8143         "The video element contains cross-origin data, and may not be loaded.");
8144     return false;
8145   }
8146   return true;
8147 }
8148 
ValidateImageBitmap(const char * function_name,ImageBitmap * bitmap,ExceptionState & exception_state)8149 bool WebGLRenderingContextBase::ValidateImageBitmap(
8150     const char* function_name,
8151     ImageBitmap* bitmap,
8152     ExceptionState& exception_state) {
8153   if (bitmap->IsNeutered()) {
8154     SynthesizeGLError(GL_INVALID_VALUE, function_name,
8155                       "The source data has been detached.");
8156     return false;
8157   }
8158   if (!bitmap->OriginClean()) {
8159     exception_state.ThrowSecurityError(
8160         "The ImageBitmap contains cross-origin data, and may not be loaded.");
8161     return false;
8162   }
8163   return true;
8164 }
8165 
ValidateDrawArrays(const char * function_name)8166 bool WebGLRenderingContextBase::ValidateDrawArrays(const char* function_name) {
8167   if (isContextLost())
8168     return false;
8169 
8170   if (!ValidateRenderingState(function_name)) {
8171     return false;
8172   }
8173 
8174   const char* reason = "framebuffer incomplete";
8175   if (framebuffer_binding_ && framebuffer_binding_->CheckDepthStencilStatus(
8176                                   &reason) != GL_FRAMEBUFFER_COMPLETE) {
8177     SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, function_name, reason);
8178     return false;
8179   }
8180 
8181   return true;
8182 }
8183 
ValidateDrawElements(const char * function_name,GLenum type,int64_t offset)8184 bool WebGLRenderingContextBase::ValidateDrawElements(const char* function_name,
8185                                                      GLenum type,
8186                                                      int64_t offset) {
8187   if (isContextLost())
8188     return false;
8189 
8190   if (type == GL_UNSIGNED_INT && !IsWebGL2() &&
8191       !ExtensionEnabled(kOESElementIndexUintName)) {
8192     SynthesizeGLError(GL_INVALID_ENUM, function_name, "invalid type");
8193     return false;
8194   }
8195 
8196   if (!ValidateValueFitNonNegInt32(function_name, "offset", offset))
8197     return false;
8198 
8199   if (!ValidateRenderingState(function_name)) {
8200     return false;
8201   }
8202 
8203   const char* reason = "framebuffer incomplete";
8204   if (framebuffer_binding_ && framebuffer_binding_->CheckDepthStencilStatus(
8205                                   &reason) != GL_FRAMEBUFFER_COMPLETE) {
8206     SynthesizeGLError(GL_INVALID_FRAMEBUFFER_OPERATION, function_name, reason);
8207     return false;
8208   }
8209 
8210   return true;
8211 }
8212 
OnBeforeDrawCall()8213 void WebGLRenderingContextBase::OnBeforeDrawCall() {
8214   ClearIfComposited();
8215   MarkContextChanged(kCanvasChanged);
8216 }
8217 
DispatchContextLostEvent(TimerBase *)8218 void WebGLRenderingContextBase::DispatchContextLostEvent(TimerBase*) {
8219   // WebXR spec: When the WebGL context is lost, set the xr compatible boolean
8220   // to false prior to firing the webglcontextlost event.
8221   xr_compatible_ = false;
8222 
8223   WebGLContextEvent* event =
8224       WebGLContextEvent::Create(event_type_names::kWebglcontextlost, "");
8225   Host()->HostDispatchEvent(event);
8226   restore_allowed_ = event->defaultPrevented();
8227   if (restore_allowed_ && !is_hidden_) {
8228     if (auto_recovery_method_ == kAuto)
8229       restore_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
8230   }
8231 
8232   if (!restore_allowed_) {
8233     // Per WebXR spec, reject the promise with an AbortError if the default
8234     // behavior wasn't prevented. CompleteXrCompatiblePromiseIfPending rejects
8235     // the promise if xr_compatible_ is false, which was set at the beginning of
8236     // this method.
8237     CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
8238   }
8239 }
8240 
MaybeRestoreContext(TimerBase *)8241 void WebGLRenderingContextBase::MaybeRestoreContext(TimerBase*) {
8242   DCHECK(isContextLost());
8243 
8244   // The rendering context is not restored unless the default behavior of the
8245   // webglcontextlost event was prevented earlier.
8246   //
8247   // Because of the way m_restoreTimer is set up for real vs. synthetic lost
8248   // context events, we don't have to worry about this test short-circuiting
8249   // the retry loop for real context lost events.
8250   if (!restore_allowed_)
8251     return;
8252 
8253   if (canvas()) {
8254     LocalFrame* frame = canvas()->GetDocument().GetFrame();
8255     if (!frame)
8256       return;
8257 
8258     bool blocked = false;
8259     mojo::Remote<mojom::blink::GpuDataManager> gpu_data_manager;
8260     Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
8261         gpu_data_manager.BindNewPipeAndPassReceiver());
8262     gpu_data_manager->Are3DAPIsBlockedForUrl(canvas()->GetDocument().Url(),
8263                                              &blocked);
8264     if (blocked)
8265       return;
8266 
8267     Settings* settings = frame->GetSettings();
8268     if (settings && ((context_type_ == Platform::kWebGL1ContextType &&
8269                       !settings->GetWebGL1Enabled()) ||
8270                      (context_type_ == Platform::kWebGL2ContextType &&
8271                       !settings->GetWebGL2Enabled()))) {
8272       return;
8273     }
8274   }
8275 
8276   // Drawing buffer should have aready been destroyed during context loss to
8277   // ensure its resources were freed.
8278   DCHECK(!GetDrawingBuffer());
8279 
8280   auto* execution_context = Host()->GetTopExecutionContext();
8281   Platform::ContextAttributes attributes = ToPlatformContextAttributes(
8282       CreationAttributes(), context_type_,
8283       SupportOwnOffscreenSurface(execution_context));
8284   Platform::GraphicsInfo gl_info;
8285   std::unique_ptr<WebGraphicsContext3DProvider> context_provider;
8286   bool using_gpu_compositing;
8287   const auto& url = Host()->GetExecutionContextUrl();
8288 
8289   if (IsMainThread()) {
8290     // Ask for gpu compositing mode when making the context. The context will be
8291     // lost if the mode changes.
8292     using_gpu_compositing = !Platform::Current()->IsGpuCompositingDisabled();
8293     context_provider =
8294         Platform::Current()->CreateOffscreenGraphicsContext3DProvider(
8295             attributes, url, &gl_info);
8296   } else {
8297     context_provider = CreateContextProviderOnWorkerThread(
8298         attributes, &gl_info, &using_gpu_compositing, url);
8299   }
8300   scoped_refptr<DrawingBuffer> buffer;
8301   if (context_provider && context_provider->BindToCurrentThread()) {
8302     // Construct a new drawing buffer with the new GL context.
8303     buffer =
8304         CreateDrawingBuffer(std::move(context_provider), using_gpu_compositing);
8305     // If DrawingBuffer::create() fails to allocate a fbo, |drawingBuffer| is
8306     // set to null.
8307   }
8308   if (!buffer) {
8309     if (context_lost_mode_ == kRealLostContext) {
8310       restore_timer_.StartOneShot(kDurationBetweenRestoreAttempts, FROM_HERE);
8311     } else {
8312       // This likely shouldn't happen but is the best way to report it to the
8313       // WebGL app.
8314       SynthesizeGLError(GL_INVALID_OPERATION, "", "error restoring context");
8315     }
8316     return;
8317   }
8318 
8319   drawing_buffer_ = std::move(buffer);
8320   GetDrawingBuffer()->Bind(GL_FRAMEBUFFER);
8321   lost_context_errors_.clear();
8322   context_lost_mode_ = kNotLostContext;
8323   auto_recovery_method_ = kManual;
8324   restore_allowed_ = false;
8325   RemoveFromEvictedList(this);
8326 
8327   SetupFlags();
8328   InitializeNewContext();
8329   MarkContextChanged(kCanvasContextChanged);
8330   WebGLContextEvent* event =
8331       WebGLContextEvent::Create(event_type_names::kWebglcontextrestored, "");
8332   Host()->HostDispatchEvent(event);
8333 
8334   if (xr_compatible_) {
8335     CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kNoError);
8336   } else {
8337     CompleteXrCompatiblePromiseIfPending(DOMExceptionCode::kAbortError);
8338   }
8339 }
8340 
EnsureNotNull(const String & text) const8341 String WebGLRenderingContextBase::EnsureNotNull(const String& text) const {
8342   if (text.IsNull())
8343     return WTF::g_empty_string;
8344   return text;
8345 }
8346 
8347 WebGLRenderingContextBase::LRUCanvasResourceProviderCache::
LRUCanvasResourceProviderCache(wtf_size_t capacity)8348     LRUCanvasResourceProviderCache(wtf_size_t capacity)
8349     : resource_providers_(capacity) {}
8350 
8351 CanvasResourceProvider* WebGLRenderingContextBase::
GetCanvasResourceProvider(const IntSize & size)8352     LRUCanvasResourceProviderCache::GetCanvasResourceProvider(
8353         const IntSize& size) {
8354   wtf_size_t i;
8355   for (i = 0; i < resource_providers_.size(); ++i) {
8356     CanvasResourceProvider* resource_provider = resource_providers_[i].get();
8357     if (!resource_provider)
8358       break;
8359     if (resource_provider->Size() != size)
8360       continue;
8361     BubbleToFront(i);
8362     return resource_provider;
8363   }
8364 
8365   // TODO(fserb): why is this a BITMAP?
8366   std::unique_ptr<CanvasResourceProvider> temp(
8367       CanvasResourceProvider::CreateBitmapProvider(
8368           size, kLow_SkFilterQuality, CanvasColorParams(),
8369           CanvasResourceProvider::ShouldInitialize::kNo));  // TODO: should this
8370                                                             // use the canvas's
8371 
8372   if (!temp)
8373     return nullptr;
8374   i = std::min(resource_providers_.size() - 1, i);
8375   resource_providers_[i] = std::move(temp);
8376 
8377   CanvasResourceProvider* resource_provider = resource_providers_[i].get();
8378   BubbleToFront(i);
8379   return resource_provider;
8380 }
8381 
BubbleToFront(wtf_size_t idx)8382 void WebGLRenderingContextBase::LRUCanvasResourceProviderCache::BubbleToFront(
8383     wtf_size_t idx) {
8384   for (wtf_size_t i = idx; i > 0; --i)
8385     resource_providers_[i].swap(resource_providers_[i - 1]);
8386 }
8387 
8388 namespace {
8389 
GetErrorString(GLenum error)8390 String GetErrorString(GLenum error) {
8391   switch (error) {
8392     case GL_INVALID_ENUM:
8393       return "INVALID_ENUM";
8394     case GL_INVALID_VALUE:
8395       return "INVALID_VALUE";
8396     case GL_INVALID_OPERATION:
8397       return "INVALID_OPERATION";
8398     case GL_OUT_OF_MEMORY:
8399       return "OUT_OF_MEMORY";
8400     case GL_INVALID_FRAMEBUFFER_OPERATION:
8401       return "INVALID_FRAMEBUFFER_OPERATION";
8402     case GC3D_CONTEXT_LOST_WEBGL:
8403       return "CONTEXT_LOST_WEBGL";
8404     default:
8405       return String::Format("WebGL ERROR(0x%04X)", error);
8406   }
8407 }
8408 
8409 }  // namespace
8410 
SynthesizeGLError(GLenum error,const char * function_name,const char * description,ConsoleDisplayPreference display)8411 void WebGLRenderingContextBase::SynthesizeGLError(
8412     GLenum error,
8413     const char* function_name,
8414     const char* description,
8415     ConsoleDisplayPreference display) {
8416   String error_type = GetErrorString(error);
8417   if (synthesized_errors_to_console_ && display == kDisplayInConsole) {
8418     String message = String("WebGL: ") + error_type + ": " +
8419                      String(function_name) + ": " + String(description);
8420     PrintGLErrorToConsole(message);
8421   }
8422   if (!isContextLost()) {
8423     if (!synthetic_errors_.Contains(error))
8424       synthetic_errors_.push_back(error);
8425   } else {
8426     if (!lost_context_errors_.Contains(error))
8427       lost_context_errors_.push_back(error);
8428   }
8429   NotifyWebGLError(error_type);
8430 }
8431 
EmitGLWarning(const char * function_name,const char * description)8432 void WebGLRenderingContextBase::EmitGLWarning(const char* function_name,
8433                                               const char* description) {
8434   if (synthesized_errors_to_console_) {
8435     String message =
8436         String("WebGL: ") + String(function_name) + ": " + String(description);
8437     PrintGLErrorToConsole(message);
8438   }
8439   NotifyWebGLWarning();
8440 }
8441 
ApplyStencilTest()8442 void WebGLRenderingContextBase::ApplyStencilTest() {
8443   bool have_stencil_buffer = false;
8444 
8445   if (framebuffer_binding_) {
8446     have_stencil_buffer = framebuffer_binding_->HasStencilBuffer();
8447   } else {
8448     have_stencil_buffer = !isContextLost() && CreationAttributes().stencil &&
8449                           GetDrawingBuffer()->HasStencilBuffer();
8450   }
8451   EnableOrDisable(GL_STENCIL_TEST, stencil_enabled_ && have_stencil_buffer);
8452 }
8453 
EnableOrDisable(GLenum capability,bool enable)8454 void WebGLRenderingContextBase::EnableOrDisable(GLenum capability,
8455                                                 bool enable) {
8456   if (isContextLost())
8457     return;
8458   if (enable)
8459     ContextGL()->Enable(capability);
8460   else
8461     ContextGL()->Disable(capability);
8462 }
8463 
ClampedCanvasSize() const8464 IntSize WebGLRenderingContextBase::ClampedCanvasSize() const {
8465   int width = Host()->Size().Width();
8466   int height = Host()->Size().Height();
8467   return IntSize(Clamp(width, 1, max_viewport_dims_[0]),
8468                  Clamp(height, 1, max_viewport_dims_[1]));
8469 }
8470 
MaxDrawBuffers()8471 GLint WebGLRenderingContextBase::MaxDrawBuffers() {
8472   if (isContextLost() ||
8473       !(ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()))
8474     return 0;
8475   if (!max_draw_buffers_)
8476     ContextGL()->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
8477   if (!max_color_attachments_)
8478     ContextGL()->GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT,
8479                              &max_color_attachments_);
8480   // WEBGL_draw_buffers requires MAX_COLOR_ATTACHMENTS >= MAX_DRAW_BUFFERS.
8481   return std::min(max_draw_buffers_, max_color_attachments_);
8482 }
8483 
MaxColorAttachments()8484 GLint WebGLRenderingContextBase::MaxColorAttachments() {
8485   if (isContextLost() ||
8486       !(ExtensionEnabled(kWebGLDrawBuffersName) || IsWebGL2()))
8487     return 0;
8488   if (!max_color_attachments_)
8489     ContextGL()->GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT,
8490                              &max_color_attachments_);
8491   return max_color_attachments_;
8492 }
8493 
SetBackDrawBuffer(GLenum buf)8494 void WebGLRenderingContextBase::SetBackDrawBuffer(GLenum buf) {
8495   back_draw_buffer_ = buf;
8496 }
8497 
SetFramebuffer(GLenum target,WebGLFramebuffer * buffer)8498 void WebGLRenderingContextBase::SetFramebuffer(GLenum target,
8499                                                WebGLFramebuffer* buffer) {
8500   if (buffer)
8501     buffer->SetHasEverBeenBound();
8502 
8503   if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) {
8504     framebuffer_binding_ = buffer;
8505     ApplyStencilTest();
8506   }
8507   if (!buffer) {
8508     // Instead of binding fb 0, bind the drawing buffer.
8509     GetDrawingBuffer()->Bind(target);
8510   } else {
8511     ContextGL()->BindFramebuffer(target, buffer->Object());
8512   }
8513 }
8514 
RestoreCurrentFramebuffer()8515 void WebGLRenderingContextBase::RestoreCurrentFramebuffer() {
8516   bindFramebuffer(GL_FRAMEBUFFER, framebuffer_binding_.Get());
8517 }
8518 
RestoreCurrentTexture2D()8519 void WebGLRenderingContextBase::RestoreCurrentTexture2D() {
8520   bindTexture(GL_TEXTURE_2D,
8521               texture_units_[active_texture_unit_].texture2d_binding_.Get());
8522 }
8523 
RestoreCurrentTextureCubeMap()8524 void WebGLRenderingContextBase::RestoreCurrentTextureCubeMap() {
8525   bindTexture(
8526       GL_TEXTURE_CUBE_MAP,
8527       texture_units_[active_texture_unit_].texture_cube_map_binding_.Get());
8528 }
8529 
FindNewMaxNonDefaultTextureUnit()8530 void WebGLRenderingContextBase::FindNewMaxNonDefaultTextureUnit() {
8531   // Trace backwards from the current max to find the new max non-default
8532   // texture unit
8533   int start_index = one_plus_max_non_default_texture_unit_ - 1;
8534   for (int i = start_index; i >= 0; --i) {
8535     if (texture_units_[i].texture2d_binding_ ||
8536         texture_units_[i].texture_cube_map_binding_) {
8537       one_plus_max_non_default_texture_unit_ = i + 1;
8538       return;
8539     }
8540   }
8541   one_plus_max_non_default_texture_unit_ = 0;
8542 }
8543 
Trace(blink::Visitor * visitor) const8544 void WebGLRenderingContextBase::TextureUnitState::Trace(
8545     blink::Visitor* visitor) const {
8546   visitor->Trace(texture2d_binding_);
8547   visitor->Trace(texture_cube_map_binding_);
8548   visitor->Trace(texture3d_binding_);
8549   visitor->Trace(texture2d_array_binding_);
8550   visitor->Trace(texture_video_image_binding_);
8551 }
8552 
Trace(Visitor * visitor) const8553 void WebGLRenderingContextBase::Trace(Visitor* visitor) const {
8554   visitor->Trace(context_group_);
8555   visitor->Trace(bound_array_buffer_);
8556   visitor->Trace(default_vertex_array_object_);
8557   visitor->Trace(bound_vertex_array_object_);
8558   visitor->Trace(current_program_);
8559   visitor->Trace(framebuffer_binding_);
8560   visitor->Trace(renderbuffer_binding_);
8561   visitor->Trace(texture_units_);
8562   visitor->Trace(extensions_);
8563   visitor->Trace(make_xr_compatible_resolver_);
8564   CanvasRenderingContext::Trace(visitor);
8565 }
8566 
ExternallyAllocatedBufferCountPerPixel()8567 int WebGLRenderingContextBase::ExternallyAllocatedBufferCountPerPixel() {
8568   if (isContextLost())
8569     return 0;
8570 
8571   int buffer_count = 1;
8572   buffer_count *= 2;  // WebGL's front and back color buffers.
8573   int samples = GetDrawingBuffer() ? GetDrawingBuffer()->SampleCount() : 0;
8574   WebGLContextAttributes* attribs = getContextAttributes();
8575   if (attribs) {
8576     // Handle memory from WebGL multisample and depth/stencil buffers.
8577     // It is enabled only in case of explicit resolve assuming that there
8578     // is no memory overhead for MSAA on tile-based GPU arch.
8579     if (attribs->antialias() && samples > 0 &&
8580         GetDrawingBuffer()->ExplicitResolveOfMultisampleData()) {
8581       if (attribs->depth() || attribs->stencil())
8582         buffer_count += samples;  // depth/stencil multisample buffer
8583       buffer_count += samples;    // color multisample buffer
8584     } else if (attribs->depth() || attribs->stencil()) {
8585       buffer_count += 1;  // regular depth/stencil buffer
8586     }
8587   }
8588 
8589   return buffer_count;
8590 }
8591 
GetDrawingBuffer() const8592 DrawingBuffer* WebGLRenderingContextBase::GetDrawingBuffer() const {
8593   return drawing_buffer_.get();
8594 }
8595 
ResetUnpackParameters()8596 void WebGLRenderingContextBase::ResetUnpackParameters() {
8597   if (unpack_alignment_ != 1)
8598     ContextGL()->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
8599 }
8600 
RestoreUnpackParameters()8601 void WebGLRenderingContextBase::RestoreUnpackParameters() {
8602   if (unpack_alignment_ != 1)
8603     ContextGL()->PixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment_);
8604 }
8605 
getHTMLOrOffscreenCanvas(HTMLCanvasElementOrOffscreenCanvas & result) const8606 void WebGLRenderingContextBase::getHTMLOrOffscreenCanvas(
8607     HTMLCanvasElementOrOffscreenCanvas& result) const {
8608   if (canvas()) {
8609     result.SetHTMLCanvasElement(static_cast<HTMLCanvasElement*>(Host()));
8610   } else {
8611     result.SetOffscreenCanvas(static_cast<OffscreenCanvas*>(Host()));
8612   }
8613 }
8614 
addProgramCompletionQuery(WebGLProgram * program,GLuint query)8615 void WebGLRenderingContextBase::addProgramCompletionQuery(WebGLProgram* program,
8616                                                           GLuint query) {
8617   auto old_query = program_completion_queries_.Get(program);
8618   if (old_query != program_completion_queries_.end()) {
8619     ContextGL()->DeleteQueriesEXT(1, &old_query->second);
8620   }
8621   program_completion_queries_.Put(program, query);
8622   if (program_completion_queries_.size() > kMaxProgramCompletionQueries) {
8623     auto oldest = program_completion_queries_.rbegin();
8624     ContextGL()->DeleteQueriesEXT(1, &oldest->second);
8625     program_completion_queries_.Erase(oldest);
8626   }
8627 }
8628 
clearProgramCompletionQueries()8629 void WebGLRenderingContextBase::clearProgramCompletionQueries() {
8630   for (auto query : program_completion_queries_) {
8631     ContextGL()->DeleteQueriesEXT(1, &query.second);
8632   }
8633   program_completion_queries_.Clear();
8634 }
8635 
checkProgramCompletionQueryAvailable(WebGLProgram * program,bool * completed)8636 bool WebGLRenderingContextBase::checkProgramCompletionQueryAvailable(
8637     WebGLProgram* program,
8638     bool* completed) {
8639   GLuint id = 0;
8640   auto found = program_completion_queries_.Get(program);
8641   if (found != program_completion_queries_.end()) {
8642     id = found->second;
8643     GLuint available;
8644     ContextGL()->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_AVAILABLE,
8645                                       &available);
8646     if (available) {
8647       GLuint result = 0u;
8648       ContextGL()->GetQueryObjectuivEXT(id, GL_QUERY_RESULT, &result);
8649       program->setLinkStatus(result);
8650     }
8651     *completed = (available == GL_TRUE);
8652     return true;
8653   }
8654   return false;
8655 }
8656 }  // namespace blink
8657