1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "webgl/webgl_arg.h"
17 
18 #include "context/webgl2_rendering_context_base.h"
19 #include "context/webgl_rendering_context_base.h"
20 #include "image_source.h"
21 #include "util/util.h"
22 #include <functional>
23 
24 namespace OHOS {
25 namespace Rosen {
26 using namespace std;
27 using namespace OHOS::Media;
Dump()28 void WebGLImageOption::Dump()
29 {
30     LOGD("ImageOption format 0x%{public}x type 0x%{public}x size [%{public}d, %{public}d]",
31         format, type, width, height);
32 }
33 
GetWebGLArg(napi_value data,WebGLArgValue & arg,const WebGLArgInfo & func)34 bool WebGLArg::GetWebGLArg(napi_value data, WebGLArgValue& arg, const WebGLArgInfo& func)
35 {
36     bool succ = true;
37     switch (func.argType) {
38         case ARG_BOOL: {
39             tie(succ, arg.glBool) = NVal(env_, data).ToBool();
40             break;
41         }
42         case ARG_UINT: {
43             tie(succ, arg.glUint) = NVal(env_, data).ToUint32();
44             break;
45         }
46         case ARG_INT: {
47             tie(succ, arg.glInt) = NVal(env_, data).ToInt32();
48             break;
49         }
50         case ARG_FLOAT: {
51             double v;
52             tie(succ, v) = NVal(env_, data).ToDouble();
53             arg.glFloat = v;
54             break;
55         }
56         case ARG_ENUM: {
57             tie(succ, arg.glEnum) = NVal(env_, data).ToGLenum();
58             break;
59         }
60         case ARG_INTPTR: {
61             int64_t v = 0;
62             tie(succ, v) = NVal(env_, data).ToInt64();
63             arg.glIntptr = static_cast<GLintptr>(v);
64             break;
65         }
66         case ARG_SIZE: {
67             int64_t v = 0;
68             tie(succ, v) = NVal(env_, data).ToInt64();
69             arg.glSizei = static_cast<GLsizei>(v);
70             break;
71         }
72         case ARG_SIZEPTR: {
73             int64_t v = 0;
74             tie(succ, v) = NVal(env_, data).ToInt64();
75             arg.glSizeptr = static_cast<GLsizei>(v);
76             break;
77         }
78         default:
79             break;
80     }
81     return succ;
82 }
83 
ToGLintptr(napi_env env,napi_value dataObj)84 std::tuple<GLenum, GLintptr> WebGLArg::ToGLintptr(napi_env env, napi_value dataObj)
85 {
86     int64_t data = 0;
87     bool succ = false;
88     tie(succ, data) = NVal(env, dataObj).ToInt64();
89     if (!succ) {
90         return make_tuple(WebGLRenderingContextBase::INVALID_VALUE, 0);
91     }
92     if (data < 0) {
93         return make_tuple(WebGLRenderingContextBase::INVALID_VALUE, 0);
94     }
95     if (data > static_cast<int64_t>(std::numeric_limits<int>::max())) {
96         return make_tuple(WebGLRenderingContextBase::INVALID_OPERATION, 0);
97     }
98     return make_tuple(WebGLRenderingContextBase::NO_ERROR, static_cast<GLintptr>(data));
99 }
100 
101 template<class T>
DumpDataBuffer(const char * format) const102 void WebGLCommBuffer::DumpDataBuffer(const char* format) const
103 {
104     LOGD("WebGL WebGLCommBuffer dataLen_ %{public}u ", static_cast<unsigned int>(dataLen_));
105     size_t count = dataLen_ / sizeof(T);
106     size_t i = 0;
107     if (count <= MAX_DUMP) {
108         return;
109     }
110     if (count > MAX_DUMP) {
111         i = count - MAX_DUMP;
112     }
113 }
114 
DumpBuffer(BufferDataType destDataType) const115 void WebGLCommBuffer::DumpBuffer(BufferDataType destDataType) const
116 {
117     switch (destDataType) {
118         case BUFFER_DATA_BOOLEAN:
119             DumpDataBuffer<bool>("WebGL WebGLCommBuffer bool elm %{public}u %{public}d");
120             break;
121         case BUFFER_DATA_INT_8:
122         case BUFFER_DATA_UINT_8:
123         case BUFFER_DATA_UINT_8_CLAMPED:
124             DumpDataBuffer<uint8_t>("WebGL WebGLCommBuffer int8 elm %{public}u %{public}d");
125             break;
126         case BUFFER_DATA_INT_16:
127         case BUFFER_DATA_UINT_16:
128             DumpDataBuffer<uint16_t>("WebGL WebGLCommBuffer int16 elm %{public}u %{public}u");
129             break;
130         case BUFFER_DATA_INT_32:
131         case BUFFER_DATA_UINT_32:
132             DumpDataBuffer<uint32_t>("WebGL WebGLCommBuffer int32 elm %{public}u %{public}u");
133             break;
134         case BUFFER_DATA_FLOAT_32:
135             DumpDataBuffer<float>("WebGL WebGLCommBuffer float elm %{public}u %{public}f");
136             break;
137         case BUFFER_DATA_FLOAT_64:
138             DumpDataBuffer<double>("WebGL WebGLCommBuffer float64 elm %{public}u %{public}lf");
139             break;
140         case BUFFER_DATA_BIGINT_64:
141         case BUFFER_DATA_BIGUINT_64:
142             DumpDataBuffer<uint64_t>("WebGL WebGLCommBuffer int64 elm %{public}u %{public}u");
143             break;
144         case BUFFER_DATA_GLENUM:
145             DumpDataBuffer<GLenum>("WebGL WebGLCommBuffer glenum elm %{public}u %{public}x");
146             break;
147         default:
148             break;
149     }
150 }
151 
GetBufferDataSize() const152 size_t WebGLCommBuffer::GetBufferDataSize() const
153 {
154     switch (type_) {
155         case BUFFER_DATA_BOOLEAN:
156             return sizeof(bool);
157         case BUFFER_DATA_INT_8:
158         case BUFFER_DATA_UINT_8:
159         case BUFFER_DATA_UINT_8_CLAMPED:
160             return sizeof(uint8_t);
161         case BUFFER_DATA_INT_16:
162         case BUFFER_DATA_UINT_16:
163             return sizeof(uint16_t);
164         case BUFFER_DATA_INT_32:
165         case BUFFER_DATA_FLOAT_32:
166         case BUFFER_DATA_UINT_32:
167             return sizeof(uint32_t);
168         case BUFFER_DATA_FLOAT_64:
169             return sizeof(double);
170         case BUFFER_DATA_BIGINT_64:
171         case BUFFER_DATA_BIGUINT_64:
172             return sizeof(uint64_t);
173         case BUFFER_DATA_GLENUM:
174             return sizeof(GLenum);
175         default:
176             break;
177     }
178     return sizeof(uint32_t);
179 }
180 
181 template<class srcT, class dstT>
GetArrayElement(napi_value data,dstT defaultValue,napi_status (* getElementValue)(napi_env env_,napi_value element,srcT * value))182 napi_status WebGLReadBufferArg::GetArrayElement(
183     napi_value data, dstT defaultValue, napi_status (*getElementValue)(napi_env env_, napi_value element, srcT* value))
184 {
185     uint32_t length = 0;
186     napi_status status = napi_get_array_length(env_, data, &length);
187     if (status != napi_ok) {
188         return status;
189     }
190     LOGD("WebGL GetArrayData array len %{public}u ", length);
191     if (length == 0) {
192         return napi_ok;
193     }
194     buffer_.resize(length * sizeof(dstT));
195     data_ = buffer_.data();
196     uint8_t* buffer = buffer_.data();
197     for (uint32_t i = 0; i < length; i++) {
198         napi_value element;
199         status = napi_get_element(env_, data, i, &element);
200         if (status != napi_ok) {
201             return status;
202         }
203         srcT elm = 0;
204         if (NVal(env_, element).IsUndefined()) {
205             *reinterpret_cast<dstT*>(buffer) = defaultValue;
206             buffer += sizeof(dstT);
207             continue;
208         }
209 
210         if (NVal(env_, element).IsNull()) {
211             *reinterpret_cast<dstT*>(buffer) = elm;
212             buffer += sizeof(dstT);
213             continue;
214         }
215         if ((status = getElementValue(env_, element, &elm)) != napi_ok) {
216             return status;
217         }
218         *reinterpret_cast<dstT*>(buffer) = elm;
219         buffer += sizeof(dstT);
220     }
221     dataLen_ = length * sizeof(dstT);
222     return napi_ok;
223 }
224 
GetArrayData(napi_value data,BufferDataType destDataType)225 napi_status WebGLReadBufferArg::GetArrayData(napi_value data, BufferDataType destDataType)
226 {
227     napi_status status = napi_invalid_arg;
228     switch (destDataType) {
229         case BufferDataType::BUFFER_DATA_BOOLEAN:
230             status = GetArrayElement<bool, bool>(data, false, napi_get_value_bool);
231             break;
232         case BufferDataType::BUFFER_DATA_INT_8:
233         case BufferDataType::BUFFER_DATA_UINT_8:
234         case BufferDataType::BUFFER_DATA_UINT_8_CLAMPED:
235             status = GetArrayElement<uint32_t, uint8_t>(data, 0, napi_get_value_uint32);
236             break;
237         case BufferDataType::BUFFER_DATA_INT_16:
238         case BufferDataType::BUFFER_DATA_UINT_16:
239             status = GetArrayElement<uint32_t, uint16_t>(data, 0, napi_get_value_uint32);
240             break;
241         case BufferDataType::BUFFER_DATA_INT_32:
242         case BufferDataType::BUFFER_DATA_UINT_32:
243             status = GetArrayElement<uint32_t, uint32_t>(data, 0, napi_get_value_uint32);
244             break;
245         case BufferDataType::BUFFER_DATA_FLOAT_32: {
246             float def = 0;
247             (void)memset_s(&def, sizeof(def), 0xff, sizeof(def));
248             status = GetArrayElement<double, float>(data, def, napi_get_value_double);
249             break;
250         }
251         case BufferDataType::BUFFER_DATA_FLOAT_64:
252             status = GetArrayElement<double, double>(data, 0, napi_get_value_double);
253             break;
254         case BufferDataType::BUFFER_DATA_BIGINT_64:
255         case BufferDataType::BUFFER_DATA_BIGUINT_64:
256             status = GetArrayElement<int64_t, uint64_t>(data, 0, napi_get_value_int64);
257             break;
258         case BufferDataType::BUFFER_DATA_GLENUM:
259             status = GetArrayElement<int64_t, GLenum>(data, 0, napi_get_value_int64);
260             break;
261         default:
262             break;
263     }
264     if (status != napi_ok) {
265         return status;
266     }
267     type_ = destDataType;
268     data_ = buffer_.data();
269     return napi_ok;
270 }
271 
272 // destDataType only for BUFFER_ARRAY
GenBufferData(napi_value data,BufferDataType destDataType)273 napi_status WebGLReadBufferArg::GenBufferData(napi_value data, BufferDataType destDataType)
274 {
275     if (data == nullptr) {
276         return napi_invalid_arg;
277     }
278     bool dataView = false;
279     bool isArrayBuffer = false;
280     bool typedArray = false;
281     bool array = false;
282     napi_status status = napi_invalid_arg;
283     napi_is_dataview(env_, data, &dataView);
284     napi_is_arraybuffer(env_, data, &isArrayBuffer);
285     napi_is_typedarray(env_, data, &typedArray);
286     napi_is_array(env_, data, &array);
287     napi_value arrayBuffer = nullptr;
288     size_t byteOffset = 0;
289     if (dataView) {
290         LOGD("WebGL WebGLReadBufferArg DataView");
291         bufferType_ = BUFFER_DATA_VIEW;
292         type_ = BUFFER_DATA_UINT_8;
293         status = napi_get_dataview_info(
294             env_, data, &dataLen_, reinterpret_cast<void**>(&data_), &arrayBuffer, &byteOffset);
295     } else if (isArrayBuffer) {
296         LOGD("WebGL WebGLReadBufferArg ArrayBuffer");
297         bufferType_ = BUFFER_ARRAY_BUFFER;
298         type_ = BUFFER_DATA_UINT_8;
299         status = napi_get_arraybuffer_info(env_, data, reinterpret_cast<void**>(&data_), &dataLen_);
300     } else if (typedArray) {
301         LOGD("WebGL WebGLReadBufferArg TypedArray");
302         bufferType_ = BUFFER_TYPED_ARRAY;
303         napi_typedarray_type arrayType;
304         status = napi_get_typedarray_info(
305             env_, data, &arrayType, &dataLen_, reinterpret_cast<void**>(&data_), &arrayBuffer, &byteOffset);
306         type_ = (BufferDataType)arrayType;
307     } else if (array) {
308         LOGD("WebGL WebGLReadBufferArg array ");
309         bufferType_ = BUFFER_ARRAY;
310         status = GetArrayData(data, destDataType);
311     }
312     LOGD("WebGL GenBufferData type %{public}u length %{public}zu bufferType %{public}u", type_, dataLen_, bufferType_);
313     return status;
314 }
315 
hash_pointer(void * ptr)316 size_t hash_pointer(void* ptr)
317 {
318     return std::hash<void*> {}(ptr);
319 }
320 
321 template<class dstT>
GenExternalArray()322 napi_value WebGLWriteBufferArg::GenExternalArray()
323 {
324     LOGD("GenExternalArray dataLen_[%{public}u  %{public}u]", static_cast<unsigned int>(dataLen_), type_);
325     napi_value outputBuffer = nullptr;
326     size_t count = dataLen_ / sizeof(dstT);
327     napi_value outputArray = nullptr;
328     napi_status status = napi_ok;
329     if (data_ == nullptr) {
330         status = napi_create_arraybuffer(env_, dataLen_, reinterpret_cast<void **>(&data_), &outputBuffer);
331     } else {
332         status = napi_create_external_arraybuffer(
333             env_, data_, dataLen_,
334             [](napi_env env_, void* finalizeData, void* finalizeHint) {
335                 free(finalizeData);
336             },
337             nullptr, &outputBuffer);
338     }
339     if (status == napi_ok) {
340         status = napi_create_typedarray(env_, (napi_typedarray_type)type_, count, outputBuffer, 0, &outputArray);
341     }
342     data_ = nullptr;
343     if (status != napi_ok) {
344         LOGE("GenExternalArray error %{public}d", status);
345         return nullptr;
346     }
347     return outputArray;
348 }
349 
ToExternalArray(BufferDataType dstDataType)350 napi_value WebGLWriteBufferArg::ToExternalArray(BufferDataType dstDataType)
351 {
352     type_ = dstDataType;
353     switch (dstDataType) {
354         case BUFFER_DATA_BOOLEAN:
355             return GenExternalArray<bool>();
356         case BUFFER_DATA_INT_8:
357         case BUFFER_DATA_UINT_8:
358         case BUFFER_DATA_UINT_8_CLAMPED:
359             return GenExternalArray<uint8_t>();
360         case BUFFER_DATA_INT_16:
361         case BUFFER_DATA_UINT_16:
362             return GenExternalArray<uint16_t>();
363         case BUFFER_DATA_INT_32:
364         case BUFFER_DATA_UINT_32:
365             return GenExternalArray<uint32_t>();
366         case BUFFER_DATA_FLOAT_32:
367             return GenExternalArray<float>();
368         case BUFFER_DATA_FLOAT_64:
369             return GenExternalArray<double>();
370         case BUFFER_DATA_BIGINT_64:
371         case BUFFER_DATA_BIGUINT_64:
372             return GenExternalArray<uint64_t>();
373         default:
374             break;
375     }
376     return NVal::CreateNull(env_).val_;
377 }
378 
379 template<class srcT, class dstT>
GenNormalArray(napi_status (* getNApiValue)(napi_env env_,dstT value,napi_value * element))380 napi_value WebGLWriteBufferArg::GenNormalArray(
381     napi_status (*getNApiValue)(napi_env env_, dstT value, napi_value* element))
382 {
383     napi_value res = nullptr;
384     size_t count = dataLen_ / sizeof(srcT);
385     napi_create_array_with_length(env_, count, &res);
386     for (size_t i = 0; i < count; i++) {
387         srcT data = *reinterpret_cast<srcT*>(data_ + i * sizeof(srcT));
388         napi_value element;
389         getNApiValue(env_, static_cast<dstT>(data), &element);
390         napi_set_element(env_, res, i, element);
391     }
392     return res;
393 }
394 
ToNormalArray(BufferDataType srcDataType,BufferDataType dstDataType)395 napi_value WebGLWriteBufferArg::ToNormalArray(BufferDataType srcDataType, BufferDataType dstDataType)
396 {
397     type_ = dstDataType;
398     if (dstDataType == BUFFER_DATA_BOOLEAN) {
399         if (srcDataType == BUFFER_DATA_BOOLEAN) {
400             return GenNormalArray<bool, bool>(napi_get_boolean);
401         } else if (srcDataType == BUFFER_DATA_INT_32 || srcDataType == BUFFER_DATA_UINT_32) {
402             return GenNormalArray<uint32_t, bool>(napi_get_boolean);
403         }
404         return NVal::CreateNull(env_).val_;
405     }
406 
407     if (dstDataType == BUFFER_DATA_INT_32 || dstDataType == BUFFER_DATA_UINT_32) {
408         if (srcDataType == BUFFER_DATA_INT_32 || srcDataType == BUFFER_DATA_UINT_32) {
409             return GenNormalArray<uint32_t, uint32_t>(napi_create_uint32);
410         }
411         return NVal::CreateNull(env_).val_;
412     }
413 
414     if (dstDataType == BUFFER_DATA_BIGINT_64 || dstDataType == BUFFER_DATA_BIGUINT_64) {
415         if (srcDataType == BUFFER_DATA_INT_32 || srcDataType == BUFFER_DATA_UINT_32) {
416             return GenNormalArray<uint32_t, int64_t>(napi_create_int64);
417         }
418         return NVal::CreateNull(env_).val_;
419     }
420 
421     if (srcDataType == BUFFER_DATA_FLOAT_32) {
422         return GenNormalArray<float, double>(napi_create_double);
423     }
424     return NVal::CreateNull(env_).val_;
425 }
426 
427 template<class T>
GetObjectIntField(napi_value resultObject,const std::string & name)428 tuple<bool, T> WebGLImageSource::GetObjectIntField(napi_value resultObject, const std::string& name)
429 {
430     napi_value result = nullptr;
431     napi_status status = napi_get_named_property(env_, resultObject, name.c_str(), &result);
432     if (status != napi_ok) {
433         return make_tuple(false, 0);
434     }
435     int64_t res = 0;
436     status = napi_get_value_int64(env_, result, &res);
437     return make_tuple(status == napi_ok, static_cast<T>(res));
438 }
439 
GetWebGLFormatMap(GLenum type,GLenum format)440 const WebGLFormatMap *WebGLImageSource::GetWebGLFormatMap(GLenum type, GLenum format)
441 {
442     static const WebGLFormatMap formatTypeMaps[] = {
443         {GL_RGBA, GL_UNSIGNED_BYTE, 4, 4, BUFFER_DATA_UINT_8, DECODE_RGBA_UBYTE},
444         {GL_RGB, GL_UNSIGNED_BYTE, 3, 3, BUFFER_DATA_UINT_8, DECODE_RGB_UBYTE},
445         {GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 4, 2, BUFFER_DATA_UINT_16, DECODE_RGBA_USHORT_4444},
446         {GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 4, 2, BUFFER_DATA_UINT_16, DECODE_RGBA_USHORT_5551},
447         {GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 3, 2, BUFFER_DATA_UINT_16, DECODE_RGB_USHORT_565},
448         {GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 2, 2, BUFFER_DATA_UINT_8, DECODE_LUMINANCE_ALPHA_UBYTE},
449         {GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1, BUFFER_DATA_UINT_8, DECODE_LUMINANCE_UBYTE},
450         {GL_ALPHA, GL_UNSIGNED_BYTE, 1, 1, BUFFER_DATA_UINT_8, DECODE_ALPHA_UBYTE},
451     };
452     for (size_t i = 0; i < sizeof(formatTypeMaps) / sizeof(formatTypeMaps[0]); ++i) {
453         if (type == formatTypeMaps[i].type && format == formatTypeMaps[i].format) {
454             return &formatTypeMaps[i];
455         }
456     }
457     return nullptr;
458 }
459 
~WebGLImageSource()460 WebGLImageSource::~WebGLImageSource()
461 {
462     imageData_.clear();
463 }
464 
HandleImageSourceData(napi_value resultData,napi_valuetype valueType)465 bool WebGLImageSource::HandleImageSourceData(napi_value resultData, napi_valuetype valueType)
466 {
467     uint32_t errorCode = 0;
468     SourceOptions opts;
469     std::unique_ptr<OHOS::Media::ImageSource> imageSource = nullptr;
470     if (valueType == napi_string) { // File Path
471         size_t ignore = 0;
472         std::unique_ptr<char[]> source = nullptr;
473         bool succ = false;
474         tie(succ, source, ignore) = NVal(env_, resultData).ToUTF8String();
475         if (!succ) {
476             return false;
477         }
478         LOGD("WebGl ImageSource src: %{public}s", source.get());
479         imageSource = ImageSource::CreateImageSource(source.get(), opts, errorCode);
480     } else if (valueType == napi_number) { // Fd
481         int32_t fd = 0;
482         napi_get_value_int32(env_, resultData, &fd);
483         LOGD("WebGl ImageSource fdIndex is [%{public}d]", fd);
484         imageSource = ImageSource::CreateImageSource(fd, opts, errorCode);
485     } else {
486         LOGE("WebGl ImageSource not support type %{public}u", valueType);
487         return false;
488     }
489     if (imageSource == nullptr) {
490         LOGE("WebGl ImageSource fail to get errorCode %{public}u", errorCode);
491         return false;
492     }
493 
494     ImageInfo imageInfo;
495     errorCode = imageSource->GetImageInfo(0, imageInfo);
496     if (errorCode == 0) {
497         errorCode = imageSource->GetImageInfo(imageInfo);
498         LOGD("WebGl ImageSource  [%{public}u %{public}u] pixelFormat %{public}u colorSpace %{public}u"
499             " alphaType  %{public}u", imageInfo.size.width, imageInfo.size.height, imageInfo.pixelFormat,
500             imageInfo.colorSpace, imageInfo.alphaType);
501         imageOption_.width = imageInfo.size.width;
502         imageOption_.height = imageInfo.size.height;
503     } else {
504         return false;
505     }
506     DecodeOptions decodeOpts;
507     pixelMap_ = imageSource->CreatePixelMap(decodeOpts, errorCode);
508     if (pixelMap_ == nullptr) {
509         LOGE("WebGl ImageSource fail to create pixel map");
510         return false;
511     }
512     return true;
513 }
514 
DecodeData(const WebGLFormatMap * formatMap,uint8_t * array)515 void WebGLImageSource::DecodeData(const WebGLFormatMap* formatMap, uint8_t* array)
516 {
517     imageData_.clear();
518     for (int32_t i = 0; i < imageOption_.height; ++i) {
519         for (int32_t j = 0; j < imageOption_.width; ++j) {
520             uint8_t *data = array + formatMap->bytesPrePixel * (j + imageOption_.width * i);
521             // 0,1,2,3 -- red,green,blue,alpha
522             imageData_.emplace_back(FromARGB(static_cast<uint8_t>(data[3]),
523                 static_cast<uint8_t>(data[0]), static_cast<uint8_t>(data[1]), static_cast<uint8_t>(data[2])).value);
524         }
525     }
526 }
527 
DecodeDataForRGB_UBYTE(const WebGLFormatMap * formatMap,uint8_t * array)528 void WebGLImageSource::DecodeDataForRGB_UBYTE(const WebGLFormatMap* formatMap, uint8_t* array)
529 {
530     imageData_.clear();
531     for (int32_t i = 0; i < imageOption_.height; ++i) {
532         for (int32_t j = 0; j < imageOption_.width; ++j) {
533             uint8_t *data = array + formatMap->bytesPrePixel * (j + imageOption_.width * i);
534             // 0,1,2 -- red,green,blue
535             imageData_.emplace_back(FromRGB(
536                 static_cast<uint8_t>(data[0]), static_cast<uint8_t>(data[1]), static_cast<uint8_t>(data[2])).value);
537         }
538     }
539 }
540 
DecodeDataForRGBA_USHORT_4444(const WebGLFormatMap * formatMap,uint8_t * array)541 void WebGLImageSource::DecodeDataForRGBA_USHORT_4444(const WebGLFormatMap* formatMap, uint8_t* array)
542 {
543     imageData_.clear();
544     for (int32_t i = 0; i < imageOption_.height; ++i) {
545         for (int32_t j = 0; j < imageOption_.width; ++j) {
546             uint8_t *data = array + formatMap->bytesPrePixel * (j + imageOption_.width * i);
547             ColorParam_4_4_4_4 param;
548             param.value = *reinterpret_cast<uint16_t *>(data);
549             imageData_.emplace_back(FromARGB(
550                 param.rgba.alpha, param.rgba.red, param.rgba.green, param.rgba.blue).value);
551         }
552     }
553 }
554 
DecodeDataForRGBA_USHORT_5551(const WebGLFormatMap * formatMap,uint8_t * array)555 void WebGLImageSource::DecodeDataForRGBA_USHORT_5551(const WebGLFormatMap* formatMap, uint8_t* array)
556 {
557     imageData_.clear();
558     for (int32_t i = 0; i < imageOption_.height; ++i) {
559         for (int32_t j = 0; j < imageOption_.width; ++j) {
560             uint8_t *data = array + formatMap->bytesPrePixel * (j + imageOption_.width * i);
561             ColorParam_5_5_5_1 param;
562             param.value = *reinterpret_cast<uint16_t *>(data);
563             imageData_.emplace_back(FromARGB(
564                 param.rgba.alpha, param.rgba.red, param.rgba.green, param.rgba.blue).value);
565         }
566     }
567 }
568 
DecodeDataForRGB_USHORT_565(const WebGLFormatMap * formatMap,uint8_t * array)569 void WebGLImageSource::DecodeDataForRGB_USHORT_565(const WebGLFormatMap* formatMap, uint8_t* array)
570 {
571     imageData_.clear();
572     for (int32_t i = 0; i < imageOption_.height; ++i) {
573         for (int32_t j = 0; j < imageOption_.width; ++j) {
574             uint8_t *data = array + formatMap->bytesPrePixel * (j + imageOption_.width * i);
575             ColorParam_5_6_5 param;
576             param.value = *reinterpret_cast<uint16_t *>(data);
577             imageData_.emplace_back(FromRGB(param.rgb.red, param.rgb.green, param.rgb.blue).value);
578         }
579     }
580 }
581 
DecodeImageData(const WebGLFormatMap * formatMap,const WebGLReadBufferArg * bufferDataArg,GLuint srcOffset)582 bool WebGLImageSource::DecodeImageData(
583     const WebGLFormatMap* formatMap, const WebGLReadBufferArg* bufferDataArg, GLuint srcOffset)
584 {
585     size_t maxSize = bufferDataArg->GetBufferLength() - srcOffset * formatMap->bytesPrePixel;
586     LOGD("GenImageSource element count %{public}zu %{public}u", maxSize, formatMap->bytesPrePixel);
587     if (maxSize < static_cast<size_t>(imageOption_.height * imageOption_.width * formatMap->bytesPrePixel)) {
588         LOGE("Invalid data element");
589         return false;
590     }
591 
592     uint8_t *start = bufferDataArg->GetBuffer() + srcOffset;
593     switch (formatMap->decodeFunc) {
594         case DECODE_RGBA_UBYTE:
595             DecodeData(formatMap, start);
596             break;
597         case DECODE_RGB_UBYTE:
598             DecodeDataForRGB_UBYTE(formatMap, start);
599             break;
600         case DECODE_RGBA_USHORT_4444:
601             DecodeDataForRGBA_USHORT_4444(formatMap, start);
602             break;
603         case DECODE_RGBA_USHORT_5551:
604             DecodeDataForRGBA_USHORT_5551(formatMap, start);
605             break;
606         case DECODE_RGB_USHORT_565:
607             DecodeDataForRGB_USHORT_565(formatMap, start);
608             break;
609         default:
610             LOGE("Not support type %{public}u format %{public}u", imageOption_.type, imageOption_.format);
611             return false;
612     }
613 
614     LOGD("GenImageSource imageData_ %{public}zu ", imageData_.size());
615     if (imageData_.size() != static_cast<size_t>(imageOption_.height * imageOption_.width)) {
616         return false;
617     }
618     return true;
619 }
620 
GenImageSource(const WebGLImageOption & opt,napi_value pixels,GLuint srcOffset)621 GLenum WebGLImageSource::GenImageSource(const WebGLImageOption& opt, napi_value pixels, GLuint srcOffset)
622 {
623     imageOption_.Assign(opt);
624     imageOption_.Dump();
625     if (readBuffer_ != nullptr) {
626         readBuffer_.reset();
627     }
628     readBuffer_ = std::make_unique<WebGLReadBufferArg>(env_);
629     if (readBuffer_ == nullptr) {
630         return GL_INVALID_OPERATION;
631     }
632     const WebGLFormatMap *formatMap = GetWebGLFormatMap(imageOption_.type, imageOption_.format);
633     if (formatMap == nullptr) {
634         return false;
635     }
636     napi_status status = readBuffer_->GenBufferData(pixels, formatMap->dataType);
637     if (status != napi_ok) {
638         return GL_INVALID_VALUE;
639     }
640     if (readBuffer_->GetBufferDataType() != formatMap->dataType) {
641         return GL_INVALID_OPERATION;
642     }
643     if (!(unpackFlipY_ || unpackPremultiplyAlpha_)) {
644         srcOffset_ = srcOffset;
645         return GL_NO_ERROR;
646     }
647     bool succ = false;
648     if (readBuffer_->GetBufferDataType() == BUFFER_DATA_UINT_8 ||
649         readBuffer_->GetBufferDataType() == BUFFER_DATA_UINT_16) {
650             succ = DecodeImageData(formatMap, readBuffer_.get(), srcOffset);
651     } else {
652         return GL_INVALID_OPERATION;
653     }
654     if (!succ) {
655         return GL_INVALID_OPERATION;
656     }
657 
658     Media::InitializationOptions opts;
659     opts.pixelFormat = Media::PixelFormat::RGBA_8888;
660     opts.size.width = imageOption_.width;
661     opts.size.height = imageOption_.height;
662     opts.editable = true;
663     pixelMap_ = Media::PixelMap::Create(imageData_.data(), imageData_.size(), opts);
664     return pixelMap_ == nullptr ? GL_INVALID_OPERATION : GL_NO_ERROR;
665 }
666 
GenImageSource(const WebGLImageOption & opt,napi_value sourceImage)667 GLenum WebGLImageSource::GenImageSource(const WebGLImageOption& opt, napi_value sourceImage)
668 {
669     imageOption_.Assign(opt);
670     bool succ = false;
671     napi_value resultObject = nullptr;
672     napi_status status = napi_coerce_to_object(env_, sourceImage, &resultObject);
673     if (status != napi_ok) {
674         return GL_INVALID_VALUE;
675     }
676 
677     // image maybe no width
678     tie(succ, imageOption_.width) = GetObjectIntField<GLsizei>(resultObject, "width");
679     if (!succ) {
680         return GL_INVALID_VALUE;
681     }
682     tie(succ, imageOption_.height) = GetObjectIntField<GLsizei>(resultObject, "height");
683     if (!succ) {
684         return GL_INVALID_VALUE;
685     }
686     LOGD("WebGl GenImageSource size [%{public}d %{public}d]", imageOption_.width, imageOption_.height);
687 
688     napi_value resultData = nullptr;
689     status = napi_get_named_property(env_, resultObject, "data", &resultData);
690     if (status != napi_ok || NVal(env_, resultData).IsNull()) {
691         status = napi_get_named_property(env_, resultObject, "src", &resultData);
692     }
693     if (status != napi_ok || NVal(env_, resultData).IsNull()) {
694         LOGE("WebGl GenImageSource status %{public}u", status);
695         return GL_INVALID_VALUE;
696     }
697     napi_valuetype valueType;
698     napi_typeof(env_, resultData, &valueType);
699     if (valueType == napi_object) {
700         return GenImageSource(imageOption_, resultData, 0);
701     }
702     return HandleImageSourceData(resultData, valueType) ? GL_NO_ERROR : GL_INVALID_VALUE;
703 }
704 
GetWebGLReadBuffer() const705 WebGLReadBufferArg *WebGLImageSource::GetWebGLReadBuffer() const
706 {
707     return readBuffer_ == nullptr ? nullptr : readBuffer_.get();
708 }
709 
GetImageSourceData() const710 GLvoid* WebGLImageSource::GetImageSourceData() const
711 {
712     if (pixelMap_ == nullptr) {
713         return readBuffer_ == nullptr ? nullptr : reinterpret_cast<GLvoid*>(readBuffer_->GetBuffer() + srcOffset_);
714     }
715 
716     LOGD("WebGl ImageSource [%{public}u %{public}u] byteCount %{public}u pixelBytes %{public}u rowBytes %{public}u "
717         " flipY %{public}u premultiplyAlpha %{public}u", pixelMap_->GetWidth(), pixelMap_->GetHeight(),
718         pixelMap_->GetByteCount(), pixelMap_->GetPixelBytes(), pixelMap_->GetRowBytes(),
719         unpackFlipY_, unpackPremultiplyAlpha_);
720     if (unpackFlipY_ || unpackPremultiplyAlpha_) {
721         pixelMap_->flip(false, unpackFlipY_);
722     }
723     return reinterpret_cast<GLvoid*>(const_cast<uint8_t*>(pixelMap_->GetPixels()));
724 }
725 
GetWebGLDataSize(GLenum type)726 uint32_t WebGLArg::GetWebGLDataSize(GLenum type)
727 {
728     switch (type) {
729         case GL_BYTE:
730             return sizeof(GLbyte);
731         case GL_UNSIGNED_BYTE:
732             return sizeof(GLubyte);
733         case GL_SHORT:
734             return sizeof(GLshort);
735         case GL_UNSIGNED_SHORT:
736             return sizeof(GLushort);
737         case GL_INT:
738             return sizeof(GLint);
739         case GL_UNSIGNED_INT:
740             return sizeof(GLuint);
741         case GL_FLOAT:
742             return sizeof(GLfloat);
743         default:
744             break;
745     }
746     return sizeof(GLuint);
747 }
748 
GetStringList(napi_env env,napi_value array,std::vector<char * > & list)749 bool WebGLArg::GetStringList(napi_env env, napi_value array, std::vector<char*>& list)
750 {
751     bool succ = false;
752     uint32_t count = 0;
753     napi_status status = napi_get_array_length(env, array, &count);
754     if (status != napi_ok) {
755         return false;
756     }
757     uint32_t i;
758     for (i = 0; i < count; i++) {
759         napi_value element;
760         status = napi_get_element(env, array, i, &element);
761         if (status != napi_ok) {
762             return false;
763         }
764         napi_value result;
765         status = napi_coerce_to_string(env, element, &result);
766         if (status != napi_ok) {
767             return false;
768         }
769         unique_ptr<char[]> name;
770         tie(succ, name, ignore) = NVal(env, result).ToUTF8String();
771         if (!succ) {
772             return false;
773         }
774         LOGD("WebGL2 GetStringList = %{public}s", name.get());
775         list.emplace_back(name.get());
776         name.release();
777     }
778     return true;
779 }
780 
FreeStringList(std::vector<char * > & list)781 void WebGLArg::FreeStringList(std::vector<char*>& list)
782 {
783     for (size_t i = 0; i < list.size(); i++) {
784         if (list[i] != nullptr) {
785             delete[] list[i];
786         }
787     }
788     list.clear();
789 }
790 
GetUint32Parameter(napi_env env,GLenum pname)791 napi_value WebGLArg::GetUint32Parameter(napi_env env, GLenum pname)
792 {
793     GLint value = 0;
794     glGetIntegerv(pname, &value);
795     napi_value res = nullptr;
796     napi_create_uint32(env, value, &res);
797     return res;
798 }
799 
GetBoolParameter(napi_env env,GLenum pname)800 napi_value WebGLArg::GetBoolParameter(napi_env env, GLenum pname)
801 {
802     GLboolean value = 0;
803     glGetBooleanv(pname, &value);
804     napi_value res = nullptr;
805     napi_get_boolean(env, value, &res);
806     return res;
807 }
808 
GetInt32Parameter(napi_env env,GLenum pname)809 napi_value WebGLArg::GetInt32Parameter(napi_env env, GLenum pname)
810 {
811     GLint value = 0;
812     glGetIntegerv(pname, &value);
813     napi_value res = nullptr;
814     napi_create_int32(env, value, &res);
815     return res;
816 }
817 
GetInt64Parameter(napi_env env,GLenum pname)818 napi_value WebGLArg::GetInt64Parameter(napi_env env, GLenum pname)
819 {
820     GLint64 value = 0;
821     glGetInteger64v(pname, &value);
822     napi_value res = nullptr;
823     napi_create_int64(env, value, &res);
824     return res;
825 }
826 
GetFloatParameter(napi_env env,GLenum pname)827 napi_value WebGLArg::GetFloatParameter(napi_env env, GLenum pname)
828 {
829     float value = 0;
830     glGetFloatv(pname, &value);
831     napi_value res = nullptr;
832     napi_create_double(env, static_cast<double>(value), &res);
833     return res;
834 }
835 
Dump(const std::string & info) const836 void TexImageArg::Dump(const std::string& info) const
837 {
838     LOGD("%{public}s target %{public}u %{public}d internalFormat %{public}u format %{public}u %{public}u",
839         info.c_str(), target, level, internalFormat, format, type);
840     LOGD("width %{public}d height %{public}d border %{public}d depth %{public}d", width, height, border, depth);
841 }
842 
Dump(const std::string & info) const843 void TexStorageArg::Dump(const std::string& info) const
844 {
845     LOGD("%{public}s target %{public}u %{public}d internalFormat %{public}u ",
846         info.c_str(), target, levels, internalFormat);
847     LOGD("width %{public}d height %{public}d depth %{public}d", width, height, depth);
848 }
849 
Dump(const std::string & info) const850 void TexSubImage2DArg::Dump(const std::string& info) const
851 {
852     TexImageArg::Dump(info);
853     LOGD("xOffset %{public}u yOffset %{public}u", xOffset, yOffset);
854 }
855 
Dump(const std::string & info) const856 void TexSubImage3DArg::Dump(const std::string& info) const
857 {
858     TexImageArg::Dump(info);
859     LOGD("xOffset %{public}u yOffset %{public}u zOffset %{public}u", xOffset, yOffset, zOffset);
860 }
861 
Dump(const std::string & info) const862 void PixelsArg::Dump(const std::string& info) const
863 {
864     LOGD("%{public}s position [%{public}d %{public}d %{public}d %{public}d] format [%{public}u %{public}u]",
865         info.c_str(), x, y, width, height, format, type);
866 }
867 
Dump(const std::string & info) const868 void VertexAttribArg::Dump(const std::string &info) const
869 {
870     LOGD("%{public}s vertexAttrib index %{public}u %{public}d type %{public}u %{public}d "
871         "stride [%{public}u %{public}u]",
872         info.c_str(), index, size, type, normalized, stride, static_cast<unsigned int>(offset));
873 }
874 
GetUniformExtInfo(napi_env env,const NFuncArg & funcArg,int32_t start)875 bool UniformExtInfo::GetUniformExtInfo(napi_env env, const NFuncArg& funcArg, int32_t start)
876 {
877     bool succ = false;
878     if (start + 1 > static_cast<int32_t>(funcArg.GetMaxArgc())) {
879         LOGE("funcArg.GetMaxArgc : %{public}zu", funcArg.GetMaxArgc());
880         return false;
881     }
882     if (funcArg[start] != nullptr) {
883         tie(succ, srcOffset) = NVal(env, funcArg[start]).ToUint32();
884         if (!succ) {
885             return false;
886         }
887         LOGD("WebGL UniformMatrixInfo srcOffset = %{public}u", srcOffset);
888     }
889     if (funcArg[start + 1] != nullptr) {
890         tie(succ, srcLength) = NVal(env, funcArg[start + 1]).ToUint32();
891         if (!succ) {
892             return false;
893         }
894         LOGD("WebGL UniformMatrixInfo srcLength = %{public}u", srcLength);
895     }
896     return true;
897 }
898 
GetBufferExt(napi_env env,napi_value offsetArg,napi_value lenArg)899 bool BufferExt::GetBufferExt(napi_env env, napi_value offsetArg, napi_value lenArg)
900 {
901     int64_t srcByteOffset = 0;
902     bool succ = false;
903     if (!NVal(env, offsetArg).IsNull()) {
904         tie(succ, srcByteOffset) = NVal(env, offsetArg).ToInt64();
905         if (!succ || srcByteOffset < 0) {
906             return false;
907         }
908         offset = static_cast<GLuint>(srcByteOffset);
909     }
910 
911     if (!NVal(env, lenArg).IsNull()) {
912         tie(succ, srcByteOffset) = NVal(env, lenArg).ToInt64();
913         if (!succ || srcByteOffset < 0) {
914             return false;
915         }
916         length = static_cast<GLuint>(srcByteOffset);
917     }
918     return true;
919 }
920 
CheckString(const std::string & str)921 bool WebGLArg::CheckString(const std::string& str)
922 {
923     for (size_t i = 0; i < str.length(); ++i) {
924         unsigned char c = str[i];
925         // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid
926         if (c >= 9 && c <= 13) { // Match character: 9 TAB, 10 LF, 11 VT, 12 FF, 13 CR
927             continue;
928         }
929         // Printing characters are valid except " $ ` @ \ ' DEL.
930         if (isprint(c) && c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'') {
931             continue;
932         }
933         return false;
934     }
935     return true;
936 }
937 
CheckReservedPrefix(const std::string & name)938 bool WebGLArg::CheckReservedPrefix(const std::string& name)
939 {
940     // 6: 'webgl_' length, 7: '_webgl_' length
941     if (strncmp("webgl_", name.c_str(), 6) == 0 || strncmp("_webgl_", name.c_str(), 7) == 0) {
942         return true;
943     }
944     return false;
945 }
946 } // namespace Rosen
947 } // namespace OHOS
948