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 "frameworks/bridge/declarative_frontend/jsview/js_image_span.h"
17 #include "frameworks/bridge/declarative_frontend/jsview/js_container_span.h"
18 
19 #if !defined(PREVIEW)
20 #include <dlfcn.h>
21 #endif
22 
23 #include "base/log/ace_scoring_log.h"
24 #include "core/components/common/layout/constants.h"
25 #include "core/components_ng/pattern/image/image_model.h"
26 #include "core/components_ng/pattern/text/image_span_view.h"
27 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
28 #include "frameworks/bridge/declarative_frontend/jsview/js_image.h"
29 
30 namespace OHOS::Ace::Framework {
31     const std::vector<float> DEFAULT_COLORFILTER_MATRIX = {
32     1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
33     0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f
34     };
35 
Create(const JSCallbackInfo & info)36 void JSImageSpan::Create(const JSCallbackInfo& info)
37 {
38     if (!Container::IsCurrentUseNewPipeline()) {
39         return;
40     }
41     if (info.Length() != 1) {
42         return;
43     }
44     JSImage::CreateImage(info, true);
45     NG::ImageSpanView::Create();
46 }
47 
SetAlt(const JSCallbackInfo & info)48 void JSImageSpan::SetAlt(const JSCallbackInfo& info)
49 {
50     if (!Container::IsCurrentUseNewPipeline()) {
51         return;
52     }
53     if (info.Length() < 1) {
54         return;
55     }
56     JSImage::SetAlt(info);
57 }
58 
SetObjectFit(const JSCallbackInfo & info)59 void JSImageSpan::SetObjectFit(const JSCallbackInfo& info)
60 {
61     if (info.Length() != 1) {
62         return;
63     }
64 
65     JSRef<JSVal> args = info[0];
66     if (args->IsNumber()) {
67         auto fit = static_cast<ImageFit>(args->ToNumber<int32_t>());
68         if (fit < ImageFit::FILL || fit > ImageFit::BOTTOM_END) {
69             fit = ImageFit::COVER;
70         }
71         ImageModel::GetInstance()->SetImageFit(fit);
72     } else {
73         ImageModel::GetInstance()->SetImageFit(ImageFit::COVER);
74     }
75 }
76 
SetVerticalAlign(int32_t verticalAlign)77 void JSImageSpan::SetVerticalAlign(int32_t verticalAlign)
78 {
79     auto align = static_cast<VerticalAlign>(verticalAlign);
80     if (align < VerticalAlign::TOP || align > VerticalAlign::NONE) {
81         align = VerticalAlign::BOTTOM;
82     }
83     NG::ImageSpanView::SetVerticalAlign(align);
84 }
85 
SetTextBackgroundStyle(const JSCallbackInfo & info)86 void JSImageSpan::SetTextBackgroundStyle(const JSCallbackInfo& info)
87 {
88     auto textBackgroundStyle = JSContainerSpan::ParseTextBackgroundStyle(info);
89     NG::ImageSpanView::SetPlaceHolderStyle(textBackgroundStyle);
90 }
91 
OnComplete(const JSCallbackInfo & args)92 void JSImageSpan::OnComplete(const JSCallbackInfo& args)
93 {
94     JSRef<JSVal> arg = args[0];
95     if (arg->IsFunction()) {
96         auto jsLoadSuccFunc = AceType::MakeRefPtr<JsEventFunction<LoadImageSuccessEvent, 1>>(
97             JSRef<JSFunc>::Cast(arg), LoadImageSuccEventToJSValue);
98 
99         auto onComplete = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadSuccFunc)](
100                               const LoadImageSuccessEvent& info) {
101             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
102             ACE_SCORING_EVENT("ImageSpan.onComplete");
103             func->Execute(info);
104         };
105         ImageModel::GetInstance()->SetOnComplete(std::move(onComplete));
106     }
107 }
108 
OnError(const JSCallbackInfo & args)109 void JSImageSpan::OnError(const JSCallbackInfo& args)
110 {
111     JSRef<JSVal> arg = args[0];
112     if (arg->IsFunction()) {
113         auto jsLoadFailFunc = AceType::MakeRefPtr<JsEventFunction<LoadImageFailEvent, 1>>(
114             JSRef<JSFunc>::Cast(arg), LoadImageFailEventToJSValue);
115         auto onError = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadFailFunc)](
116                            const LoadImageFailEvent& info) {
117             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
118             ACE_SCORING_EVENT("ImageSpan.onError");
119             func->Execute(info);
120         };
121         ImageModel::GetInstance()->SetOnError(onError);
122     }
123 }
124 
SetBaselineOffset(const JSCallbackInfo & info)125 void JSImageSpan::SetBaselineOffset(const JSCallbackInfo& info)
126 {
127     if (info.Length() < 1) {
128         return;
129     }
130     NG::CalcLength value;
131     if (ConvertFromJSValueNG(info[0], value) &&
132         value.GetDimensionContainsNegative().Unit() != DimensionUnit::PERCENT) {
133         NG::ImageSpanView::SetBaselineOffset(value.GetDimensionContainsNegative());
134         return;
135     }
136     value.Reset();
137     NG::ImageSpanView::SetBaselineOffset(value.GetDimensionContainsNegative());
138 }
139 
SetColorFilter(const JSCallbackInfo & info)140 void JSImageSpan::SetColorFilter(const JSCallbackInfo& info)
141 {
142     if (info.Length() != 1) {
143         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
144         return;
145     }
146     auto tmpInfo = info[0];
147     if (!tmpInfo->IsArray() && !tmpInfo->IsObject()) {
148         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
149         return;
150     }
151     if (tmpInfo->IsObject() && !tmpInfo->IsArray()) {
152         auto drawingColorFilter = CreateDrawingColorFilter(tmpInfo);
153         if (drawingColorFilter) {
154             ImageModel::GetInstance()->SetDrawingColorFilter(drawingColorFilter);
155             return;
156         }
157         JSColorFilter* colorFilter;
158         if (!tmpInfo->IsUndefined() && !tmpInfo->IsNull()) {
159             colorFilter = JSRef<JSObject>::Cast(tmpInfo)->Unwrap<JSColorFilter>();
160         } else {
161             ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
162             return;
163         }
164         if (colorFilter && colorFilter->GetColorFilterMatrix().size() == COLOR_FILTER_MATRIX_SIZE) {
165             ImageModel::GetInstance()->SetColorFilterMatrix(colorFilter->GetColorFilterMatrix());
166             return;
167         }
168         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
169         return;
170     }
171     JSRef<JSArray> array = JSRef<JSArray>::Cast(tmpInfo);
172     if (array->Length() != COLOR_FILTER_MATRIX_SIZE) {
173         ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
174         return;
175     }
176     std::vector<float> colorfilter;
177     for (size_t i = 0; i < array->Length(); i++) {
178         JSRef<JSVal> value = array->GetValueAt(i);
179         if (value->IsNumber()) {
180             colorfilter.emplace_back(value->ToNumber<float>());
181         } else {
182             ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX);
183             return;
184         }
185     }
186     ImageModel::GetInstance()->SetColorFilterMatrix(colorfilter);
187 }
188 
JSBind(BindingTarget globalObj)189 void JSImageSpan::JSBind(BindingTarget globalObj)
190 {
191     JSClass<JSImageSpan>::Declare("ImageSpan");
192     MethodOptions opt = MethodOptions::NONE;
193     JSClass<JSImageSpan>::StaticMethod("create", &JSImageSpan::Create, opt);
194     JSClass<JSImageSpan>::StaticMethod("alt", &JSImageSpan::SetAlt, opt);
195     JSClass<JSImageSpan>::StaticMethod("objectFit", &JSImageSpan::SetObjectFit);
196     JSClass<JSImageSpan>::StaticMethod("verticalAlign", &JSImageSpan::SetVerticalAlign);
197     JSClass<JSImageSpan>::StaticMethod("textBackgroundStyle", &JSImageSpan::SetTextBackgroundStyle);
198     JSClass<JSImageSpan>::StaticMethod("onComplete", &JSImageSpan::OnComplete);
199     JSClass<JSImageSpan>::StaticMethod("onError", &JSImageSpan::OnError);
200     JSClass<JSImageSpan>::StaticMethod("border", &JSImage::JsBorder);
201     JSClass<JSImageSpan>::StaticMethod("borderRadius", &JSImage::JsBorderRadius);
202     JSClass<JSImageSpan>::StaticMethod("colorFilter", &JSImageSpan::SetColorFilter, opt);
203     JSClass<JSImageSpan>::StaticMethod("baselineOffset", &JSImageSpan::SetBaselineOffset);
204     JSClass<JSImageSpan>::InheritAndBind<JSViewAbstract>(globalObj);
205 }
206 } // namespace OHOS::Ace::Framework
207