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