/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "bridge/declarative_frontend/jsview/js_image.h" #include #include #include #if !defined(PREVIEW) #include #endif #include "interfaces/inner_api/ace/ai/image_analyzer.h" #if !defined(PREVIEW) && defined(OHOS_PLATFORM) #include "interfaces/inner_api/ui_session/ui_session_manager.h" #endif #include "base/geometry/ng/vector.h" #include "base/image/drawing_color_filter.h" #include "base/image/drawing_lattice.h" #include "base/image/pixel_map.h" #include "base/log/ace_scoring_log.h" #include "base/log/ace_trace.h" #include "base/utils/utils.h" #include "bridge/common/utils/engine_helper.h" #include "bridge/declarative_frontend/engine/functions/js_drag_function.h" #include "bridge/declarative_frontend/engine/js_ref_ptr.h" #include "bridge/declarative_frontend/engine/js_types.h" #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h" #include "bridge/declarative_frontend/jsview/models/image_model_impl.h" #include "core/common/container.h" #include "core/components/common/layout/constants.h" #include "core/components/image/image_event.h" #include "core/components/image/image_theme.h" #include "core/components_ng/base/view_abstract_model.h" #include "core/components_ng/base/view_stack_processor.h" #include "core/components_ng/event/gesture_event_hub.h" #include "core/components_ng/pattern/image/image_model.h" #include "core/components_ng/pattern/image/image_model_ng.h" #include "core/image/image_source_info.h" namespace { const std::vector DEFAULT_COLORFILTER_MATRIX = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0 }; constexpr float CEIL_SMOOTHEDGE_VALUE = 1.333f; constexpr float FLOOR_SMOOTHEDGE_VALUE = 0.334f; constexpr float DEFAULT_SMOOTHEDGE_VALUE = 0.0f; } // namespace namespace OHOS::Ace { namespace { ImageSourceInfo CreateSourceInfo(const std::shared_ptr& srcRef, RefPtr& pixmap, const std::string& bundleName, const std::string& moduleName) { #if defined(PIXEL_MAP_SUPPORTED) if (pixmap) { return ImageSourceInfo(pixmap); } #endif return { srcRef, bundleName, moduleName }; } } // namespace std::unique_ptr ImageModel::instance_ = nullptr; std::mutex ImageModel::mutex_; ImageModel* __attribute__((optnone)) ImageModel::GetInstance() { if (!instance_) { std::lock_guard lock(mutex_); if (!instance_) { #ifdef NG_BUILD instance_.reset(new NG::ImageModelNG()); #else if (Container::IsCurrentUseNewPipeline()) { instance_.reset(new NG::ImageModelNG()); } else { instance_.reset(new Framework::ImageModelImpl()); } #endif } } return instance_.get(); } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { JSRef LoadImageSuccEventToJSValue(const LoadImageSuccessEvent& eventInfo) { JSRef obj = JSRef::New(); obj->SetProperty("width", eventInfo.GetWidth()); obj->SetProperty("height", eventInfo.GetHeight()); obj->SetProperty("componentWidth", eventInfo.GetComponentWidth()); obj->SetProperty("componentHeight", eventInfo.GetComponentHeight()); obj->SetProperty("loadingStatus", eventInfo.GetLoadingStatus()); obj->SetProperty("contentWidth", eventInfo.GetContentWidth()); obj->SetProperty("contentHeight", eventInfo.GetContentHeight()); obj->SetProperty("contentOffsetX", eventInfo.GetContentOffsetX()); obj->SetProperty("contentOffsetY", eventInfo.GetContentOffsetY()); return JSRef::Cast(obj); } JSRef LoadImageFailEventToJSValue(const LoadImageFailEvent& eventInfo) { JSRef obj = JSRef::New(); obj->SetProperty("componentWidth", eventInfo.GetComponentWidth()); obj->SetProperty("componentHeight", eventInfo.GetComponentHeight()); obj->SetProperty("message", eventInfo.GetErrorMessage()); return JSRef::Cast(obj); } void JSImage::SetAlt(const JSCallbackInfo& args) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } if (args.Length() < 1) { return; } auto context = PipelineBase::GetCurrentContext(); CHECK_NULL_VOID(context); bool isCard = context->IsFormRender(); std::string src; bool srcValid = false; if (args[0]->IsString()) { src = args[0]->ToString(); } else { srcValid = ParseJsMedia(args[0], src); } if (ImageSourceInfo::ResolveURIType(src) == SrcType::NETWORK) { return; } int32_t resId = 0; if (args[0]->IsObject()) { JSRef jsObj = JSRef::Cast(args[0]); JSRef tmp = jsObj->GetProperty("id"); if (!tmp->IsNull() && tmp->IsNumber()) { resId = tmp->ToNumber(); } } std::string bundleName; std::string moduleName; GetJsMediaBundleInfo(args[0], bundleName, moduleName); RefPtr pixmap = nullptr; // input is Drawable if (!srcValid && !isCard) { #if defined(PIXEL_MAP_SUPPORTED) pixmap = CreatePixelMapFromNapiValue(args[0]); #endif } auto srcRef = std::make_shared(src); auto srcInfo = CreateSourceInfo(srcRef, pixmap, bundleName, moduleName); srcInfo.SetIsUriPureNumber((resId == -1)); ImageModel::GetInstance()->SetAlt(srcInfo); } void JSImage::SetObjectFit(const JSCallbackInfo& args) { if (args.Length() < 1) { ImageModel::GetInstance()->SetImageFit(ImageFit::COVER); return; } int32_t parseRes = static_cast(ImageFit::COVER); ParseJsInteger(args[0], parseRes); if (parseRes < static_cast(ImageFit::FILL) || parseRes > static_cast(ImageFit::BOTTOM_END)) { parseRes = static_cast(ImageFit::COVER); } auto fit = static_cast(parseRes); ImageModel::GetInstance()->SetImageFit(fit); } void JSImage::SetMatchTextDirection(bool value) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } ImageModel::GetInstance()->SetMatchTextDirection(value); } void JSImage::SetFitOriginalSize(bool value) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } ImageModel::GetInstance()->SetFitOriginSize(value); } void JSImage::SetBorder(const Border& border) { ImageModel::GetInstance()->SetBorder(border); } void JSImage::OnComplete(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto jsLoadSuccFunc = AceType::MakeRefPtr>( JSRef::Cast(args[0]), LoadImageSuccEventToJSValue); auto onComplete = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadSuccFunc)]( const LoadImageSuccessEvent& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("Image.onComplete"); func->Execute(info); #if !defined(PREVIEW) && defined(OHOS_PLATFORM) UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Image.onComplete"); #endif }; ImageModel::GetInstance()->SetOnComplete(std::move(onComplete)); } } void JSImage::OnError(const JSCallbackInfo& args) { if (args[0]->IsFunction()) { auto jsLoadFailFunc = AceType::MakeRefPtr>( JSRef::Cast(args[0]), LoadImageFailEventToJSValue); auto onError = [execCtx = args.GetExecutionContext(), func = std::move(jsLoadFailFunc)]( const LoadImageFailEvent& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("Image.onError"); func->Execute(info); #if !defined(PREVIEW) && defined(OHOS_PLATFORM) UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "Image.onError"); #endif }; ImageModel::GetInstance()->SetOnError(onError); } } void JSImage::OnFinish(const JSCallbackInfo& info) { auto tmpInfo = info[0]; if (!tmpInfo->IsFunction()) { return; } RefPtr jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(tmpInfo)); WeakPtr targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto onFinish = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("Image.onFinish"); PipelineContext::SetCallBackNode(node); func->Execute(); }; ImageModel::GetInstance()->SetSvgAnimatorFinishEvent(onFinish); } void JSImage::Create(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } CreateImage(info); } bool JSImage::CheckIsCard() { auto container = Container::Current(); if (!container) { TAG_LOGE(AceLogTag::ACE_IMAGE, "Container is null in CreateImage."); return false; } return container->IsFormRender() && !container->IsDynamicRender(); } bool JSImage::CheckResetImage(const JSCallbackInfo& info) { int32_t parseRes = -1; if (info.Length() < 1 || !ParseJsInteger(info[0], parseRes)) { return false; } ImageModel::GetInstance()->ResetImage(); return true; } void JSImage::CreateImage(const JSCallbackInfo& info, bool isImageSpan) { if (CheckResetImage(info)) { return; } bool isCard = CheckIsCard(); // Interim programme std::string bundleName; std::string moduleName; std::string src; auto imageInfo = info[0]; int32_t resId = 0; bool srcValid = ParseJsMediaWithBundleName(imageInfo, src, bundleName, moduleName, resId); if (isCard && imageInfo->IsString()) { SrcType srcType = ImageSourceInfo::ResolveURIType(src); bool notSupport = (srcType == SrcType::NETWORK || srcType == SrcType::FILE || srcType == SrcType::DATA_ABILITY); if (notSupport) { src.clear(); } } RefPtr pixmap = nullptr; // input is PixelMap / Drawable if (!srcValid && !isCard) { #if defined(PIXEL_MAP_SUPPORTED) std::vector> pixelMaps; int32_t duration = -1; int32_t iterations = 1; if (IsDrawable(imageInfo)) { if (GetPixelMapListFromAnimatedDrawable(imageInfo, pixelMaps, duration, iterations)) { CreateImageAnimation(pixelMaps, duration, iterations); return; } pixmap = GetDrawablePixmap(imageInfo); } else { pixmap = CreatePixelMapFromNapiValue(imageInfo); } #endif } ImageInfoConfig imageInfoConfig( std::make_shared(src), bundleName, moduleName, (resId == -1), isImageSpan); ImageModel::GetInstance()->Create(imageInfoConfig, pixmap); if (info.Length() > 1) { ParseImageAIOptions(info[1]); } } void JSImage::ParseImageAIOptions(const JSRef& jsValue) { if (!jsValue->IsObject()) { return; } auto engine = EngineHelper::GetCurrentEngine(); CHECK_NULL_VOID(engine); NativeEngine* nativeEngine = engine->GetNativeEngine(); panda::Local value = jsValue.Get().GetLocalHandle(); JSValueWrapper valueWrapper = value; ScopeRAII scope(reinterpret_cast(nativeEngine)); napi_value optionsValue = nativeEngine->ValueToNapiValue(valueWrapper); ImageModel::GetInstance()->SetImageAIOptions(optionsValue); } bool JSImage::IsDrawable(const JSRef& jsValue) { if (!jsValue->IsObject()) { return false; } JSRef jsObj = JSRef::Cast(jsValue); if (jsObj->IsUndefined()) { return false; } // if jsObject has function getPixelMap, it's a DrawableDescriptor object JSRef func = jsObj->GetProperty("getPixelMap"); return (!func->IsNull() && func->IsFunction()); } void JSImage::JsBorder(const JSCallbackInfo& info) { if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) { JSViewAbstract::JsBorder(info); ImageModel::GetInstance()->SetBackBorder(); return; } // handles generic property logic. JSViewAbstract::JsBorder(info); // handles the image component separately, aiming to extract and set the borderRadius property if (!info[0]->IsObject()) { CalcDimension borderRadius; ImageModel::GetInstance()->SetBorderRadius(borderRadius); return; } JSRef object = JSRef::Cast(info[0]); auto valueRadius = object->GetProperty(static_cast(ArkUIIndex::RADIUS)); if (!valueRadius->IsUndefined()) { ParseBorderRadius(valueRadius); } } void JSImage::ParseBorderRadius(const JSRef& args) { CalcDimension borderRadius; if (ParseJsDimensionVp(args, borderRadius)) { ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius); ImageModel::GetInstance()->SetBorderRadius(borderRadius); } else if (args->IsObject()) { JSRef object = JSRef::Cast(args); CalcDimension topLeft; CalcDimension topRight; CalcDimension bottomLeft; CalcDimension bottomRight; if (ParseAllBorderRadiuses(object, topLeft, topRight, bottomLeft, bottomRight)) { ImageModel::GetInstance()->SetBorderRadius( GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight)); ViewAbstractModel::GetInstance()->SetBorderRadius( GetLocalizedBorderRadius(topLeft, topRight, bottomLeft, bottomRight)); return; } ImageModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight); ViewAbstractModel::GetInstance()->SetBorderRadius(topLeft, topRight, bottomLeft, bottomRight); } } void JSImage::ParseResizableSlice(const JSRef& resizableObject) { ImageResizableSlice sliceResult; if (resizableObject->IsEmpty()) { ImageModel::GetInstance()->SetResizableSlice(sliceResult); return; } auto sliceValue = resizableObject->GetProperty("slice"); if (!sliceValue->IsObject()) { ImageModel::GetInstance()->SetResizableSlice(sliceResult); return; } JSRef sliceObj = JSRef::Cast(sliceValue); if (sliceObj->IsEmpty()) { ImageModel::GetInstance()->SetResizableSlice(sliceResult); return; } UpdateSliceResult(sliceObj, sliceResult); ImageModel::GetInstance()->SetResizableSlice(sliceResult); } void JSImage::ParseResizableLattice(const JSRef& resizableObject) { auto latticeValue = resizableObject->GetProperty("lattice"); if (latticeValue->IsUndefined() || latticeValue->IsNull()) { ImageModel::GetInstance()->ResetResizableLattice(); } CHECK_NULL_VOID(latticeValue->IsObject()); auto drawingLattice = CreateDrawingLattice(latticeValue); if (drawingLattice) { ImageModel::GetInstance()->SetResizableLattice(drawingLattice); } else { ImageModel::GetInstance()->ResetResizableLattice(); } } void JSImage::JsImageResizable(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } auto infoObj = info[0]; if (!infoObj->IsObject()) { ImageModel::GetInstance()->SetResizableSlice(ImageResizableSlice()); return; } JSRef resizableObject = JSRef::Cast(infoObj); ParseResizableSlice(resizableObject); ParseResizableLattice(resizableObject); } void JSImage::UpdateSliceResult(const JSRef& sliceObj, ImageResizableSlice& sliceResult) { // creatge a array has 4 elements for paresing sliceSize static std::array keys = { static_cast(ArkUIIndex::LEFT), static_cast(ArkUIIndex::RIGHT), static_cast(ArkUIIndex::TOP), static_cast(ArkUIIndex::BOTTOM) }; for (uint32_t i = 0; i < keys.size(); i++) { auto sliceSize = sliceObj->GetProperty(keys.at(i)); CalcDimension sliceDimension; if (!ParseJsDimensionVp(sliceSize, sliceDimension)) { continue; } if (!sliceDimension.IsValid()) { continue; } switch (static_cast(i)) { case BorderImageDirection::LEFT: sliceResult.left = sliceDimension; break; case BorderImageDirection::RIGHT: sliceResult.right = sliceDimension; break; case BorderImageDirection::TOP: sliceResult.top = sliceDimension; break; case BorderImageDirection::BOTTOM: sliceResult.bottom = sliceDimension; break; default: break; } } ImageModel::GetInstance()->SetResizableSlice(sliceResult); } void JSImage::JsBorderRadius(const JSCallbackInfo& info) { if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_FOURTEEN)) { JSViewAbstract::JsBorderRadius(info); ImageModel::GetInstance()->SetBackBorder(); return; } static std::vector checkList { JSCallbackInfoType::STRING, JSCallbackInfoType::NUMBER, JSCallbackInfoType::OBJECT }; auto jsVal = info[0]; if (!CheckJSCallbackInfo("JsBorderRadius", jsVal, checkList)) { ViewAbstractModel::GetInstance()->SetBorderRadius(Dimension {}); ImageModel::GetInstance()->SetBorderRadius(Dimension {}); return; } ParseBorderRadius(jsVal); } void JSImage::SetSourceSize(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } ImageModel::GetInstance()->SetImageSourceSize(JSViewAbstract::ParseSize(info)); } void JSImage::SetImageFill(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } if (info.Length() < 1) { return; } Color color; if (!ParseJsColor(info[0], color)) { if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) { return; } auto pipelineContext = PipelineBase::GetCurrentContext(); CHECK_NULL_VOID(pipelineContext); auto theme = pipelineContext->GetTheme(); CHECK_NULL_VOID(theme); color = theme->GetFillColor(); } ImageModel::GetInstance()->SetImageFill(color); } void JSImage::SetImageRenderMode(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } if (info.Length() < 1) { ImageModel::GetInstance()->SetImageRenderMode(ImageRenderMode::ORIGINAL); return; } auto jsImageRenderMode = info[0]; if (jsImageRenderMode->IsNumber()) { auto renderMode = static_cast(jsImageRenderMode->ToNumber()); if (renderMode < ImageRenderMode::ORIGINAL || renderMode > ImageRenderMode::TEMPLATE) { renderMode = ImageRenderMode::ORIGINAL; } ImageModel::GetInstance()->SetImageRenderMode(renderMode); } else { ImageModel::GetInstance()->SetImageRenderMode(ImageRenderMode::ORIGINAL); } } void JSImage::SetImageInterpolation(int32_t imageInterpolation) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } auto interpolation = static_cast(imageInterpolation); if (interpolation < ImageInterpolation::NONE || interpolation > ImageInterpolation::HIGH) { interpolation = ImageInterpolation::NONE; } ImageModel::GetInstance()->SetImageInterpolation(interpolation); } void JSImage::SetImageRepeat(int32_t imageRepeat) { auto repeat = static_cast(imageRepeat); if (repeat < ImageRepeat::NO_REPEAT || repeat > ImageRepeat::REPEAT) { repeat = ImageRepeat::NO_REPEAT; } ImageModel::GetInstance()->SetImageRepeat(repeat); } void JSImage::JsTransition(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->IsSrcSvgImage()) { JSViewAbstract::JsTransition(info); } else { JSViewAbstract::JsTransitionPassThrough(info); } } void JSImage::JsOpacity(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->IsSrcSvgImage()) { JSViewAbstract::JsOpacity(info); } else { JSViewAbstract::JsOpacityPassThrough(info); } } void JSImage::JsBlur(const JSCallbackInfo& info) { // only flutter runs special image blur #ifdef ENABLE_ROSEN_BACKEND JSViewAbstract::JsBlur(info); #else if (info.Length() < 1) { return; } double blur = 0.0; if (ParseJsDouble(info[0], blur)) { ImageModel::GetInstance()->SetBlur(blur); } #endif } void JSImage::SetAutoResize(bool autoResize) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } ImageModel::GetInstance()->SetAutoResize(autoResize); } void JSImage::SetSyncLoad(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } if (info.Length() < 1) { return; } auto tmpInfo = info[0]; if (!tmpInfo->IsBoolean()) { return; } ImageModel::GetInstance()->SetSyncMode(tmpInfo->ToBoolean()); } void JSColorFilter::ConstructorCallback(const JSCallbackInfo& args) { if (args.Length() < 1) { return; } auto tmpInfo = args[0]; if (!tmpInfo->IsArray()) { return; } JSRef array = JSRef::Cast(tmpInfo); if (array->Length() != COLOR_FILTER_MATRIX_SIZE) { return; } auto jscolorfilter = Referenced::MakeRefPtr(); if (jscolorfilter == nullptr) { return; } std::vector colorfilter; for (size_t i = 0; i < array->Length(); i++) { JSRef value = array->GetValueAt(i); if (value->IsNumber()) { colorfilter.emplace_back(value->ToNumber()); } } if (colorfilter.size() != COLOR_FILTER_MATRIX_SIZE) { return; } jscolorfilter->SetColorFilterMatrix(std::move(colorfilter)); jscolorfilter->IncRefCount(); args.SetReturnValue(Referenced::RawPtr(jscolorfilter)); } void JSColorFilter::DestructorCallback(JSColorFilter* obj) { if (obj != nullptr) { obj->DecRefCount(); } } void JSImage::SetColorFilter(const JSCallbackInfo& info) { if (info.Length() != 1) { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } auto tmpInfo = info[0]; if (!tmpInfo->IsArray() && !tmpInfo->IsObject()) { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } if (tmpInfo->IsObject() && !tmpInfo->IsArray()) { auto drawingColorFilter = CreateDrawingColorFilter(tmpInfo); if (drawingColorFilter) { ImageModel::GetInstance()->SetDrawingColorFilter(drawingColorFilter); return; } JSColorFilter* colorFilter; if (!tmpInfo->IsUndefined() && !tmpInfo->IsNull()) { colorFilter = JSRef::Cast(tmpInfo)->Unwrap(); } else { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } if (colorFilter && colorFilter->GetColorFilterMatrix().size() == COLOR_FILTER_MATRIX_SIZE) { ImageModel::GetInstance()->SetColorFilterMatrix(colorFilter->GetColorFilterMatrix()); return; } ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } JSRef array = JSRef::Cast(tmpInfo); if (array->Length() != COLOR_FILTER_MATRIX_SIZE) { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } std::vector colorfilter; for (size_t i = 0; i < array->Length(); i++) { JSRef value = array->GetValueAt(i); if (value->IsNumber()) { colorfilter.emplace_back(value->ToNumber()); } else { ImageModel::GetInstance()->SetColorFilterMatrix(DEFAULT_COLORFILTER_MATRIX); return; } } ImageModel::GetInstance()->SetColorFilterMatrix(colorfilter); } void JSImage::SetSmoothEdge(const JSCallbackInfo& info) { if (info.Length() != 1) { ImageModel::GetInstance()->SetSmoothEdge(DEFAULT_SMOOTHEDGE_VALUE); return; } double parseRes = DEFAULT_SMOOTHEDGE_VALUE; ParseJsDouble(info[0], parseRes); // Effective range : (FLOOR_SMOOTHEDGE_VALUE, CEIL_SMOOTHEDGE_VALUE] // otherwise: DEFAULT_SMOOTHEDGE_VALUE if (GreatNotEqual(parseRes, CEIL_SMOOTHEDGE_VALUE) || LessNotEqual(parseRes, FLOOR_SMOOTHEDGE_VALUE)) { parseRes = DEFAULT_SMOOTHEDGE_VALUE; } ImageModel::GetInstance()->SetSmoothEdge(static_cast(parseRes)); } void JSImage::SetDynamicRangeMode(const JSCallbackInfo& info) { if (info.Length() < 1) { ImageModel::GetInstance()->SetDynamicRangeMode(DynamicRangeMode::STANDARD); return; } int32_t parseRes = static_cast(DynamicRangeMode::STANDARD); ParseJsInteger(info[0], parseRes); if (parseRes < static_cast(DynamicRangeMode::HIGH) || parseRes > static_cast(DynamicRangeMode::STANDARD)) { parseRes = static_cast(DynamicRangeMode::STANDARD); } DynamicRangeMode dynamicRangeMode = static_cast(parseRes); ImageModel::GetInstance()->SetDynamicRangeMode(dynamicRangeMode); } void JSImage::SetEnhancedImageQuality(const JSCallbackInfo& info) { if (info.Length() < 1) { ImageModel::GetInstance()->SetEnhancedImageQuality(AIImageQuality::LOW); return; } int32_t parseRes = static_cast(AIImageQuality::LOW); ParseJsInteger(info[0], parseRes); if (parseRes < static_cast(AIImageQuality::LOW) || parseRes > static_cast(AIImageQuality::HIGH)) { parseRes = static_cast(AIImageQuality::LOW); } AIImageQuality resolutionQuality = static_cast(parseRes); ImageModel::GetInstance()->SetEnhancedImageQuality(resolutionQuality); } void JSImage::SetOrientation(const JSCallbackInfo& info) { if (info.Length() < 1) { ImageModel::GetInstance()->SetOrientation(ImageRotateOrientation::UP); return; } int32_t parseRes = 0; ParseJsInteger(info[0], parseRes); if (parseRes < static_cast(ImageRotateOrientation::AUTO) || parseRes > static_cast(ImageRotateOrientation::LEFT)) { parseRes = static_cast(ImageRotateOrientation::UP); } auto res = static_cast(parseRes); ImageModel::GetInstance()->SetOrientation(res); } void JSImage::CreateImageAnimation(std::vector>& pixelMaps, int32_t duration, int32_t iterations) { std::vector imageList; for (int i = 0; i < static_cast(pixelMaps.size()); i++) { ImageProperties image; image.pixelMap = pixelMaps[i]; imageList.push_back(image); } ImageModel::GetInstance()->CreateAnimation(imageList, duration, iterations); } void JSImage::JSBind(BindingTarget globalObj) { JSClass::Declare("Image"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSImage::Create, opt); JSClass::StaticMethod("alt", &JSImage::SetAlt, opt); JSClass::StaticMethod("objectFit", &JSImage::SetObjectFit, opt); JSClass::StaticMethod("matchTextDirection", &JSImage::SetMatchTextDirection, opt); JSClass::StaticMethod("fitOriginalSize", &JSImage::SetFitOriginalSize, opt); JSClass::StaticMethod("sourceSize", &JSImage::SetSourceSize, opt); JSClass::StaticMethod("fillColor", &JSImage::SetImageFill, opt); JSClass::StaticMethod("renderMode", &JSImage::SetImageRenderMode, opt); JSClass::StaticMethod("objectRepeat", &JSImage::SetImageRepeat, opt); JSClass::StaticMethod("interpolation", &JSImage::SetImageInterpolation, opt); JSClass::StaticMethod("colorFilter", &JSImage::SetColorFilter, opt); JSClass::StaticMethod("edgeAntialiasing", &JSImage::SetSmoothEdge, opt); JSClass::StaticMethod("dynamicRangeMode", &JSImage::SetDynamicRangeMode, opt); JSClass::StaticMethod("enhancedImageQuality", &JSImage::SetEnhancedImageQuality, opt); JSClass::StaticMethod("orientation", &JSImage::SetOrientation, opt); JSClass::StaticMethod("border", &JSImage::JsBorder); JSClass::StaticMethod("borderRadius", &JSImage::JsBorderRadius); JSClass::StaticMethod("onAttach", &JSInteractableView::JsOnAttach); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDetach", &JSInteractableView::JsOnDetach); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::StaticMethod("autoResize", &JSImage::SetAutoResize); JSClass::StaticMethod("resizable", &JSImage::JsImageResizable); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onHover", &JSInteractableView::JsOnHover); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("onClick", &JSInteractableView::JsOnClick); JSClass::StaticMethod("onComplete", &JSImage::OnComplete); JSClass::StaticMethod("onError", &JSImage::OnError); JSClass::StaticMethod("onFinish", &JSImage::OnFinish); JSClass::StaticMethod("syncLoad", &JSImage::SetSyncLoad); JSClass::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage); JSClass::StaticMethod("draggable", &JSImage::JsSetDraggable); JSClass::StaticMethod("onDragStart", &JSImage::JsOnDragStart); JSClass::StaticMethod("copyOption", &JSImage::SetCopyOption); JSClass::StaticMethod("enableAnalyzer", &JSImage::EnableAnalyzer); JSClass::StaticMethod("analyzerConfig", &JSImage::AnalyzerConfig); // override method JSClass::StaticMethod("opacity", &JSImage::JsOpacity); JSClass::StaticMethod("blur", &JSImage::JsBlur); JSClass::StaticMethod("transition", &JSImage::JsTransition); JSClass::StaticMethod("pointLight", &JSViewAbstract::JsPointLight, opt); JSClass::InheritAndBind(globalObj); JSClass::Declare("ColorFilter"); JSClass::Bind(globalObj, JSColorFilter::ConstructorCallback, JSColorFilter::DestructorCallback); } void JSImage::JsSetDraggable(bool draggable) { ImageModel::GetInstance()->SetDraggable(draggable); } void JSImage::JsOnDragStart(const JSCallbackInfo& info) { if (info.Length() != 1 || !info[0]->IsFunction()) { return; } RefPtr jsOnDragStartFunc = AceType::MakeRefPtr(JSRef::Cast(info[0])); WeakPtr frameNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto onDragStartId = [execCtx = info.GetExecutionContext(), func = std::move(jsOnDragStartFunc), node = frameNode]( const RefPtr& info, const std::string& extraParams) -> NG::DragDropBaseInfo { NG::DragDropBaseInfo itemInfo; JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, itemInfo); PipelineContext::SetCallBackNode(node); auto ret = func->Execute(info, extraParams); if (!ret->IsObject()) { return itemInfo; } if (ParseAndUpdateDragItemInfo(ret, itemInfo)) { return itemInfo; } auto builderObj = JSRef::Cast(ret); #if defined(PIXEL_MAP_SUPPORTED) auto pixmap = builderObj->GetProperty("pixelMap"); itemInfo.pixelMap = CreatePixelMapFromNapiValue(pixmap); #endif auto extraInfo = builderObj->GetProperty("extraInfo"); ParseJsString(extraInfo, itemInfo.extraInfo); ParseAndUpdateDragItemInfo(builderObj->GetProperty("builder"), itemInfo); return itemInfo; }; ImageModel::GetInstance()->SetOnDragStart(std::move(onDragStartId)); } void JSImage::SetCopyOption(const JSCallbackInfo& info) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } auto copyOptions = CopyOptions::None; if (info[0]->IsNumber()) { auto enumNumber = info[0]->ToNumber(); copyOptions = static_cast(enumNumber); if (copyOptions < CopyOptions::None || copyOptions > CopyOptions::Distributed) { copyOptions = CopyOptions::None; } } ImageModel::GetInstance()->SetCopyOption(copyOptions); } void JSImage::EnableAnalyzer(bool isEnableAnalyzer) { if (ImageModel::GetInstance()->GetIsAnimation()) { return; } ImageModel::GetInstance()->EnableAnalyzer(isEnableAnalyzer); } void JSImage::AnalyzerConfig(const JSCallbackInfo& info) { auto configParams = info[0]; if (configParams->IsNull() || !configParams->IsObject()) { return; } auto engine = EngineHelper::GetCurrentEngine(); CHECK_NULL_VOID(engine); NativeEngine* nativeEngine = engine->GetNativeEngine(); CHECK_NULL_VOID(nativeEngine); panda::Local value = configParams.Get().GetLocalHandle(); JSValueWrapper valueWrapper = value; ScopeRAII scope(reinterpret_cast(nativeEngine)); napi_value nativeValue = nativeEngine->ValueToNapiValue(valueWrapper); ImageModel::GetInstance()->SetImageAnalyzerConfig(nativeValue); // As an example, the function is not in effect. auto paramObject = JSRef::Cast(configParams); JSRef typeVal = paramObject->GetProperty("types"); ImageAnalyzerConfig analyzerConfig; if (typeVal->IsArray()) { auto array = JSRef::Cast(typeVal); std::set types; for (size_t i = 0; i < array->Length(); ++i) { if (!array->GetValueAt(i)->IsNumber()) { continue; } int value = array->GetValueAt(i)->ToNumber(); ImageAnalyzerType type = static_cast(value); if (type != ImageAnalyzerType::SUBJECT && type != ImageAnalyzerType::TEXT) { continue; } types.insert(type); } analyzerConfig.types = std::move(types); } ImageModel::GetInstance()->SetImageAnalyzerConfig(analyzerConfig); } } // namespace OHOS::Ace::Framework