1 /*
2  * Copyright (c) 2021 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 <securec.h>
17 
18 #include "bridge/declarative_frontend/jsview/canvas/js_canvas_image_data.h"
19 #include "bridge/declarative_frontend/jsview/canvas/js_rendering_context.h"
20 
21 namespace OHOS::Ace::Framework {
22 constexpr size_t FIRST_PARAM = 0;
23 constexpr size_t SECOND_PARAM = 1;
24 constexpr size_t THIRD_PARAM = 2;
25 constexpr size_t FOURTH_PARAM = 3;
26 constexpr double DIFF = 1e-10;
27 constexpr int32_t PIXEL_SIZE = 4;
Constructor(const JSCallbackInfo & args)28 void JSCanvasImageData::Constructor(const JSCallbackInfo& args)
29 {
30     auto jsCanvasImageData = Referenced::MakeRefPtr<JSCanvasImageData>();
31     jsCanvasImageData->IncRefCount();
32     args.SetReturnValue(Referenced::RawPtr(jsCanvasImageData));
33 
34     if (args.Length() < 2) { // Invalid argument, the arguments should be at least 2: width, height
35         return;
36     }
37     int32_t finalWidth = 0;
38     int32_t finalHeight = 0;
39     int32_t unit = 0;
40 
41     if (args.GetInt32Arg(FOURTH_PARAM, unit) && (static_cast<CanvasUnit>(unit) == CanvasUnit::PX)) {
42         jsCanvasImageData->SetUnit(CanvasUnit::PX);
43     }
44     if (!jsCanvasImageData->GetImageDataSize(args, finalWidth, finalHeight)) {
45         return;
46     }
47     int32_t result = finalWidth * finalHeight * PIXEL_SIZE;
48     jsCanvasImageData->width_ = finalWidth;
49     jsCanvasImageData->height_ = finalHeight;
50 
51     if (args.Length() == 2) { // 2 arguments: width, height
52         JSRef<JSArrayBuffer> arrayBuffer = JSRef<JSArrayBuffer>::New(result);
53         args.SetSize(static_cast<size_t>(arrayBuffer->ByteLength()));
54         // return the transparent black image
55         auto* buffer = static_cast<uint32_t*>(arrayBuffer->GetBuffer());
56         if ((arrayBuffer->ByteLength() != 0) &&
57             (memset_s(buffer, arrayBuffer->ByteLength(), 0, arrayBuffer->ByteLength()))) {
58             return;
59         }
60         jsCanvasImageData->colorArray_ =
61             JSRef<JSUint8ClampedArray>::New(arrayBuffer->GetLocalHandle(), 0, arrayBuffer->ByteLength());
62     } else if (args.Length() >= 3 && args[THIRD_PARAM]->IsUint8ClampedArray()) { // 3 arguments: width, height, data
63         JSRef<JSUint8ClampedArray> data = JSRef<JSUint8ClampedArray>::Cast(args[THIRD_PARAM]);
64         auto buffer = data->GetArrayBuffer();
65         args.SetSize(static_cast<size_t>(buffer->ByteLength()));
66         if ((static_cast<CanvasUnit>(unit) == CanvasUnit::PX) && (buffer->ByteLength() != result)) {
67             TAG_LOGE(AceLogTag::ACE_CANVAS,
68                 "Failed to construct 'ImageData': The input data length is not equal to (4 * widthPX * heightPX).");
69             return;
70         }
71         jsCanvasImageData->colorArray_ = data;
72     }
73 }
74 
GetImageDataSize(const JSCallbackInfo & args,int32_t & finalWidth,int32_t & finalHeight)75 bool JSCanvasImageData::GetImageDataSize(const JSCallbackInfo& args, int32_t& finalWidth, int32_t& finalHeight)
76 {
77     double width = 0.0;
78     double height = 0.0;
79     double density = GetDensity();
80     args.GetDoubleArg(FIRST_PARAM, width);
81     args.GetDoubleArg(SECOND_PARAM, height);
82     width *= density;
83     height *= density;
84     if (NonPositive(width) || NonPositive(height)) {
85         TAG_LOGE(AceLogTag::ACE_CANVAS,
86             "Failed to construct 'ImageData': The input 'width' or 'height' is non-positive number or not number.");
87         return false;
88     }
89     // Integer Overflow.
90     width += DIFF;
91     height += DIFF;
92     if ((width > INT32_MAX) || (height > INT32_MAX) || ((width > 0) && (height > (INT32_MAX / width / PIXEL_SIZE)))) {
93         return false;
94     }
95     finalWidth = static_cast<int32_t>(width);
96     finalHeight = static_cast<int32_t>(height);
97     return true;
98 }
99 
Destructor(JSCanvasImageData * controller)100 void JSCanvasImageData::Destructor(JSCanvasImageData* controller)
101 {
102     if (controller != nullptr) {
103         controller->DecRefCount();
104     }
105 }
106 
JSBind(BindingTarget globalObj)107 void JSCanvasImageData::JSBind(BindingTarget globalObj)
108 {
109     JSClass<JSCanvasImageData>::Declare("ImageData");
110     JSClass<JSCanvasImageData>::CustomProperty("width", &JSCanvasImageData::JsGetWidth, &JSCanvasImageData::JsSetWidth);
111     JSClass<JSCanvasImageData>::CustomProperty(
112         "height", &JSCanvasImageData::JsGetHeight, &JSCanvasImageData::JsSetHeight);
113     JSClass<JSCanvasImageData>::CustomProperty("data", &JSCanvasImageData::JsGetData, &JSCanvasImageData::JsSetData);
114     JSClass<JSCanvasImageData>::Bind(globalObj, JSCanvasImageData::Constructor, JSCanvasImageData::Destructor);
115 }
116 
JsGetWidth(const JSCallbackInfo & info)117 void JSCanvasImageData::JsGetWidth(const JSCallbackInfo& info)
118 {
119     auto returnValue = JSVal(ToJSValue(width_));
120     auto returnPtr = JSRef<JSVal>::Make(returnValue);
121     info.SetReturnValue(returnPtr);
122 }
123 
JsGetHeight(const JSCallbackInfo & info)124 void JSCanvasImageData::JsGetHeight(const JSCallbackInfo& info)
125 {
126     auto returnValue = JSVal(ToJSValue(height_));
127     auto returnPtr = JSRef<JSVal>::Make(returnValue);
128     info.SetReturnValue(returnPtr);
129 }
130 
JsGetData(const JSCallbackInfo & info)131 void JSCanvasImageData::JsGetData(const JSCallbackInfo& info)
132 {
133     info.SetReturnValue(colorArray_);
134 }
135 
JsSetWidth(const JSCallbackInfo & info)136 void JSCanvasImageData::JsSetWidth(const JSCallbackInfo& info)
137 {
138     return;
139 }
140 
JsSetHeight(const JSCallbackInfo & info)141 void JSCanvasImageData::JsSetHeight(const JSCallbackInfo& info)
142 {
143     return;
144 }
145 
JsSetData(const JSCallbackInfo & info)146 void JSCanvasImageData::JsSetData(const JSCallbackInfo& info)
147 {
148     return;
149 }
150 } // namespace OHOS::Ace::Framework
151