mirror of
https://gitee.com/openharmony/arkui_ace_engine
synced 2024-11-27 17:21:11 +00:00
feat: image support pixelmap list and image animator support pixelmap
Signed-off-by: yangziyong <nsyangziyong@huawei.com> Change-Id: I383c1f5724bc56091de718442207d88bc7fc2583
This commit is contained in:
parent
2c70fcd8ec
commit
f4835c8ab4
@ -94,6 +94,21 @@ RefPtr<PixelMap> PixelMap::GetFromDrawable(void* ptr)
|
||||
return AceType::MakeRefPtr<PixelMapOhos>(drawable->GetPixelMap());
|
||||
}
|
||||
|
||||
bool PixelMap::GetPxielMapListFromAnimatedDrawable(void* ptr, std::vector<RefPtr<PixelMap>>& pixelMaps,
|
||||
int32_t& duration, int32_t& iterations)
|
||||
{
|
||||
CHECK_NULL_RETURN(ptr, false);
|
||||
auto* animatedDrawable = reinterpret_cast<Napi::AnimatedDrawableDescriptor*>(ptr);
|
||||
CHECK_NULL_RETURN(animatedDrawable, false);
|
||||
std::vector<std::shared_ptr<Media::PixelMap>> pixelMapList = animatedDrawable->GetPixelMapList();
|
||||
for (uint32_t i = 0; i < pixelMapList.size(); i++) {
|
||||
pixelMaps.push_back(AceType::MakeRefPtr<PixelMapOhos>(std::move(pixelMapList[i])));
|
||||
}
|
||||
duration = animatedDrawable->GetDuration();
|
||||
iterations = animatedDrawable->GetIterations();
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<PixelMap> PixelMap::CreatePixelMapFromDataAbility(void* ptr)
|
||||
{
|
||||
auto* pixmap = reinterpret_cast<Media::PixelMap*>(ptr);
|
||||
|
@ -30,6 +30,12 @@ RefPtr<PixelMap> PixelMap::GetFromDrawable(void* ptr)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool PixelMap::GetPxielMapListFromAnimatedDrawable(void* ptr, std::vector<RefPtr<PixelMap>>& pixelMaps,
|
||||
int32_t& duration, int32_t& iterations)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<PixelMap> PixelMap::CreatePixelMapFromDataAbility(void* uniquePtr)
|
||||
{
|
||||
return nullptr;
|
||||
|
@ -141,6 +141,8 @@ public:
|
||||
* @param ptr: drawable pointer of type Napi::DrawableDescriptor&
|
||||
*/
|
||||
static RefPtr<PixelMap> GetFromDrawable(void* ptr);
|
||||
static bool GetPxielMapListFromAnimatedDrawable(void* ptr, std::vector<RefPtr<PixelMap>>& pixelMaps,
|
||||
int32_t& duration, int32_t& iterations);
|
||||
static RefPtr<PixelMap> CreatePixelMapFromDataAbility(void* uniquePtr);
|
||||
static RefPtr<PixelMap> ConvertSkImageToPixmap(
|
||||
const uint32_t* colors, uint32_t colorLength, int32_t width, int32_t height);
|
||||
|
@ -104,6 +104,9 @@ JSRef<JSVal> LoadImageFailEventToJSValue(const LoadImageFailEvent& eventInfo)
|
||||
|
||||
void JSImage::SetAlt(const JSCallbackInfo& args)
|
||||
{
|
||||
if (ImageModel::GetInstance()->GetIsAnimation()) {
|
||||
return;
|
||||
}
|
||||
if (args.Length() < 1) {
|
||||
return;
|
||||
}
|
||||
@ -150,11 +153,17 @@ void JSImage::SetObjectFit(const JSCallbackInfo& args)
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -248,14 +257,20 @@ void JSImage::Create(const JSCallbackInfo& info)
|
||||
RefPtr<PixelMap> pixmap = nullptr;
|
||||
|
||||
// input is PixelMap / Drawable
|
||||
if (!srcValid) {
|
||||
if (!srcValid && !isCard) {
|
||||
#if defined(PIXEL_MAP_SUPPORTED)
|
||||
if (!isCard) {
|
||||
if (IsDrawable(info[0])) {
|
||||
pixmap = GetDrawablePixmap(info[0]);
|
||||
std::vector<RefPtr<PixelMap>> pixelMaps;
|
||||
int32_t duration = -1;
|
||||
int32_t iterations = 1;
|
||||
if (IsDrawable(info[0])) {
|
||||
if (GetPixelMapListFromAnimatedDrawable(info[0], pixelMaps, duration, iterations)) {
|
||||
CreateImageAnimation(pixelMaps, duration, iterations);
|
||||
return;
|
||||
} else {
|
||||
pixmap = CreatePixelMapFromNapiValue(info[0]);
|
||||
pixmap = GetDrawablePixmap(info[0]);
|
||||
}
|
||||
} else {
|
||||
pixmap = CreatePixelMapFromNapiValue(info[0]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -286,6 +301,9 @@ void JSImage::JsBorder(const JSCallbackInfo& info)
|
||||
|
||||
void JSImage::JsImageResizable(const JSCallbackInfo& info)
|
||||
{
|
||||
if (ImageModel::GetInstance()->GetIsAnimation()) {
|
||||
return;
|
||||
}
|
||||
auto infoObj = info[0];
|
||||
ImageResizableSlice sliceResult;
|
||||
if (!infoObj->IsObject()) {
|
||||
@ -341,11 +359,17 @@ void JSImage::JsBorderRadius(const JSCallbackInfo& info)
|
||||
|
||||
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;
|
||||
}
|
||||
@ -366,6 +390,9 @@ void JSImage::SetImageFill(const JSCallbackInfo& info)
|
||||
|
||||
void JSImage::SetImageRenderMode(const JSCallbackInfo& info)
|
||||
{
|
||||
if (ImageModel::GetInstance()->GetIsAnimation()) {
|
||||
return;
|
||||
}
|
||||
if (info.Length() < 1) {
|
||||
ImageModel::GetInstance()->SetImageRenderMode(ImageRenderMode::ORIGINAL);
|
||||
return;
|
||||
@ -384,6 +411,9 @@ void JSImage::SetImageRenderMode(const JSCallbackInfo& info)
|
||||
|
||||
void JSImage::SetImageInterpolation(int32_t imageInterpolation)
|
||||
{
|
||||
if (ImageModel::GetInstance()->GetIsAnimation()) {
|
||||
return;
|
||||
}
|
||||
auto interpolation = static_cast<ImageInterpolation>(imageInterpolation);
|
||||
if (interpolation < ImageInterpolation::NONE || interpolation > ImageInterpolation::HIGH) {
|
||||
interpolation = ImageInterpolation::NONE;
|
||||
@ -436,11 +466,17 @@ void JSImage::JsBlur(const JSCallbackInfo& info)
|
||||
|
||||
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;
|
||||
}
|
||||
@ -550,6 +586,17 @@ void JSImage::SetSmoothEdge(const JSCallbackInfo& info)
|
||||
ImageModel::GetInstance()->SetSmoothEdge(static_cast<float>(parseRes));
|
||||
}
|
||||
|
||||
void JSImage::CreateImageAnimation(std::vector<RefPtr<PixelMap>>& pixelMaps, int32_t duration, int32_t iterations)
|
||||
{
|
||||
std::vector<ImageProperties> imageList;
|
||||
for (int i = 0; i < 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<JSImage>::Declare("Image");
|
||||
@ -641,6 +688,9 @@ void JSImage::JsOnDragStart(const JSCallbackInfo& info)
|
||||
|
||||
void JSImage::SetCopyOption(const JSCallbackInfo& info)
|
||||
{
|
||||
if (ImageModel::GetInstance()->GetIsAnimation()) {
|
||||
return;
|
||||
}
|
||||
auto copyOptions = CopyOptions::None;
|
||||
if (info[0]->IsNumber()) {
|
||||
auto enumNumber = info[0]->ToNumber<int>();
|
||||
@ -654,6 +704,9 @@ void JSImage::SetCopyOption(const JSCallbackInfo& info)
|
||||
|
||||
void JSImage::EnableAnalyzer(bool isEnableAnalyzer)
|
||||
{
|
||||
if (ImageModel::GetInstance()->GetIsAnimation()) {
|
||||
return;
|
||||
}
|
||||
ImageModel::GetInstance()->EnableAnalyzer(isEnableAnalyzer);
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,8 @@ JSRef<JSVal> LoadImageFailEventToJSValue(const LoadImageFailEvent& eventInfo);
|
||||
class JSImage : public JSViewAbstract, public JSInteractableView {
|
||||
public:
|
||||
static void Create(const JSCallbackInfo& info);
|
||||
static void CreateImageAnimation(std::vector<RefPtr<PixelMap>>& pixelMaps,
|
||||
int32_t duration, int32_t iterations);
|
||||
static void HandleLoadImageSuccess(const BaseEventInfo& param);
|
||||
static void HandleLoadImageFail(const BaseEventInfo& param);
|
||||
static void SetAlt(const JSCallbackInfo& args);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "base/log/ace_scoring_log.h"
|
||||
#include "bridge/declarative_frontend/jsview/models/image_animator_model_impl.h"
|
||||
#include "core/components_ng/pattern/image_animator/image_animator_model_ng.h"
|
||||
#include "frameworks/bridge/declarative_frontend/jsview/js_utils.h"
|
||||
|
||||
namespace OHOS::Ace {
|
||||
std::unique_ptr<ImageAnimatorModel> ImageAnimatorModel::instance_ = nullptr;
|
||||
@ -257,8 +258,13 @@ void JSImageAnimator::ParseImages(const JSRef<JSVal>& image, ImageProperties& im
|
||||
return;
|
||||
}
|
||||
JSRef<JSObject> jsObjImage = JSRef<JSObject>::Cast(image);
|
||||
ParseJsMedia(jsObjImage->GetProperty("src"), imageProperties.src);
|
||||
bool srcValid = ParseJsMedia(jsObjImage->GetProperty("src"), imageProperties.src);
|
||||
GetJsMediaBundleInfo(jsObjImage->GetProperty("src"), imageProperties.bundleName, imageProperties.moduleName);
|
||||
if (!srcValid) {
|
||||
#if defined(PIXEL_MAP_SUPPORTED)
|
||||
imageProperties.pixelMap = CreatePixelMapFromNapiValue(jsObjImage->GetProperty("src"));
|
||||
#endif
|
||||
}
|
||||
ParseJsDimensionVp(jsObjImage->GetProperty("width"), imageProperties.width);
|
||||
ParseJsDimensionVp(jsObjImage->GetProperty("height"), imageProperties.height);
|
||||
ParseJsDimensionVp(jsObjImage->GetProperty("top"), imageProperties.top);
|
||||
|
@ -113,6 +113,12 @@ void* UnwrapNapiValue(const JSRef<JSVal>& obj)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool GetPixelMapListFromAnimatedDrawable(JSRef<JSVal> obj, std::vector<RefPtr<PixelMap>>& pixelMaps,
|
||||
int32_t& duration, int32_t& iterations)
|
||||
{
|
||||
return PixelMap::GetPxielMapListFromAnimatedDrawable(UnwrapNapiValue(obj), pixelMaps, duration, iterations);
|
||||
}
|
||||
|
||||
RefPtr<PixelMap> GetDrawablePixmap(JSRef<JSVal> obj)
|
||||
{
|
||||
return PixelMap::GetFromDrawable(UnwrapNapiValue(obj));
|
||||
|
@ -55,6 +55,8 @@ RefPtr<OHOS::Ace::WantWrap> CreateWantWrapFromNapiValue(JSRef<JSVal> obj);
|
||||
#ifdef PIXEL_MAP_SUPPORTED
|
||||
JSRef<JSVal> ConvertPixmap(const RefPtr<PixelMap>& pixelMap);
|
||||
napi_value ConvertPixmapNapi(const RefPtr<PixelMap>& pixelMap);
|
||||
bool GetPixelMapListFromAnimatedDrawable(JSRef<JSVal> obj, std::vector<RefPtr<PixelMap>>& pixelMaps,
|
||||
int32_t& duration, int32_t& iterations);
|
||||
#endif
|
||||
|
||||
bool IsDisableEventVersion();
|
||||
|
@ -256,4 +256,9 @@ bool ImageModelImpl::UpdateDragItemInfo(DragItemInfo& itemInfo)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImageModelImpl::GetIsAnimation()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace OHOS::Ace::Framework
|
||||
|
@ -60,6 +60,8 @@ public:
|
||||
void SetImageAnalyzerConfig(const ImageAnalyzerConfig& config) override {}
|
||||
void SetImageAnalyzerConfig(void* config) override {}
|
||||
void SetSmoothEdge(float value) override {}
|
||||
void CreateAnimation(const std::vector<ImageProperties>& imageList, int32_t duration, int32_t iteration) override {}
|
||||
bool GetIsAnimation() override;
|
||||
};
|
||||
|
||||
} // namespace OHOS::Ace::Framework
|
||||
|
@ -26,6 +26,7 @@ namespace OHOS::Ace {
|
||||
|
||||
struct ImageProperties {
|
||||
std::string src;
|
||||
RefPtr<PixelMap> pixelMap;
|
||||
std::string bundleName;
|
||||
std::string moduleName;
|
||||
CalcDimension width;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "core/components/common/layout/constants.h"
|
||||
#include "core/components/common/properties/border.h"
|
||||
#include "core/components/common/properties/color.h"
|
||||
#include "core/components/declaration/image/image_animator_declaration.h"
|
||||
#include "core/components/image/image_event.h"
|
||||
#include "core/components_ng/event/gesture_event_hub.h"
|
||||
#include "interfaces/inner_api/ace/ai/image_analyzer.h"
|
||||
@ -47,6 +48,8 @@ public:
|
||||
virtual void SetSvgAnimatorFinishEvent(std::function<void()> &&callback) = 0;
|
||||
virtual void Create(const std::string &src, RefPtr<PixelMap> &pixmap, const std::string &bundleName,
|
||||
const std::string &moduleName, bool isUriPureNumber = false) = 0;
|
||||
virtual void CreateAnimation(const std::vector<ImageProperties>& imageList,
|
||||
int32_t duration, int32_t iteration) = 0;
|
||||
virtual void SetImageSourceSize(const std::pair<Dimension, Dimension> &size) = 0;
|
||||
virtual void SetImageFill(const Color &color) = 0;
|
||||
virtual void SetImageInterpolation(ImageInterpolation interpolation) = 0;
|
||||
@ -69,7 +72,7 @@ public:
|
||||
virtual void SetImageAnalyzerConfig(const ImageAnalyzerConfig& config) = 0;
|
||||
virtual void SetImageAnalyzerConfig(void* config) = 0;
|
||||
virtual void SetSmoothEdge(float value) = 0;
|
||||
|
||||
virtual bool GetIsAnimation() = 0;
|
||||
private:
|
||||
static std::unique_ptr<ImageModel> instance_;
|
||||
static std::mutex mutex_;
|
||||
|
@ -64,11 +64,51 @@ void ImageModelNG::Create(const std::string &src, RefPtr<PixelMap> &pixMap, cons
|
||||
gestureHub->InitDragDropEvent();
|
||||
}
|
||||
frameNode->SetDraggable(draggable);
|
||||
GetImagePattern()->SetIsAnimation(false);
|
||||
auto srcInfo = CreateSourceInfo(src, pixMap, bundleName, moduleName);
|
||||
srcInfo.SetIsUriPureNumber(isUriPureNumber);
|
||||
ACE_UPDATE_LAYOUT_PROPERTY(ImageLayoutProperty, ImageSourceInfo, srcInfo);
|
||||
}
|
||||
|
||||
void ImageModelNG::CreateAnimation(const std::vector<ImageProperties>& imageList, int32_t duration, int32_t iteration)
|
||||
{
|
||||
auto* stack = ViewStackProcessor::GetInstance();
|
||||
auto nodeId = stack->ClaimNodeId();
|
||||
ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::IMAGE_ETS_TAG, nodeId);
|
||||
auto frameNode = FrameNode::GetOrCreateFrameNode(
|
||||
V2::IMAGE_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<ImagePattern>(); });
|
||||
CHECK_NULL_VOID(frameNode);
|
||||
if (frameNode->GetChildren().empty()) {
|
||||
auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
|
||||
CHECK_NULL_VOID(imageNode);
|
||||
auto imageLayoutProperty = AceType::DynamicCast<ImageLayoutProperty>(imageNode->GetLayoutProperty());
|
||||
CHECK_NULL_VOID(imageLayoutProperty);
|
||||
imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
|
||||
frameNode->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
|
||||
frameNode->AddChild(imageNode);
|
||||
}
|
||||
stack->Push(frameNode);
|
||||
|
||||
// set draggable for framenode
|
||||
auto pipeline = PipelineContext::GetCurrentContext();
|
||||
CHECK_NULL_VOID(pipeline);
|
||||
auto draggable = pipeline->GetDraggable<ImageTheme>();
|
||||
if (draggable && !frameNode->IsDraggable()) {
|
||||
auto gestureHub = frameNode->GetOrCreateGestureEventHub();
|
||||
CHECK_NULL_VOID(gestureHub);
|
||||
gestureHub->InitDragDropEvent();
|
||||
}
|
||||
frameNode->SetDraggable(draggable);
|
||||
auto pattern = GetImagePattern();
|
||||
pattern->StopAnimation();
|
||||
pattern->SetIsAnimation(true);
|
||||
std::vector<ImageProperties> images = imageList;
|
||||
pattern->SetImages(std::move(images));
|
||||
pattern->SetDuration(duration);
|
||||
pattern->SetIteration(iteration);
|
||||
pattern->StartAnimation();
|
||||
}
|
||||
|
||||
RefPtr<FrameNode> ImageModelNG::CreateFrameNode(int32_t nodeId, const std::string& src, RefPtr<PixelMap>& pixMap,
|
||||
const std::string& bundleName, const std::string& moduleName, bool isUriPureNumber)
|
||||
{
|
||||
@ -496,5 +536,17 @@ ImageRenderMode ImageModelNG::GetImageRenderMode(FrameNode* frameNode)
|
||||
CHECK_NULL_RETURN(paintProperty->GetImagePaintStyle(), ImageRenderMode::ORIGINAL);
|
||||
return paintProperty->GetImagePaintStyle()->GetImageRenderMode().value_or(ImageRenderMode::ORIGINAL);
|
||||
}
|
||||
|
||||
bool ImageModelNG::GetIsAnimation()
|
||||
{
|
||||
return GetImagePattern()->GetIsAnimation();
|
||||
}
|
||||
|
||||
RefPtr<ImagePattern> ImageModelNG::GetImagePattern()
|
||||
{
|
||||
auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
|
||||
CHECK_NULL_RETURN(frameNode, nullptr);
|
||||
return AceType::DynamicCast<ImagePattern>(frameNode->GetPattern());
|
||||
}
|
||||
} // namespace OHOS::Ace::NG
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_IMAGE_IMAGE_MODEL_NG_CPP
|
||||
|
@ -16,9 +16,10 @@
|
||||
#ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_IMAGE_IMAGE_MODEL_NG_H
|
||||
#define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_IMAGE_IMAGE_MODEL_NG_H
|
||||
|
||||
#include "core/components_ng/pattern/image/image_model.h"
|
||||
|
||||
#include "core/components/declaration/image/image_animator_declaration.h"
|
||||
#include "core/components_ng/base/frame_node.h"
|
||||
#include "core/components_ng/pattern/image/image_model.h"
|
||||
#include "core/components_ng/pattern/image/image_pattern.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
// ImageModel is essentially the same class as ImageView
|
||||
@ -28,6 +29,8 @@ class ACE_EXPORT ImageModelNG : public OHOS::Ace::ImageModel {
|
||||
public:
|
||||
void Create(const std::string &src, RefPtr<PixelMap> &pixMap, const std::string &bundleName,
|
||||
const std::string &moduleName, bool isUriPureNumber = false) override;
|
||||
void CreateAnimation(const std::vector<ImageProperties>& imageList, int32_t duration, int32_t iteration) override;
|
||||
bool GetIsAnimation() override;
|
||||
void SetAlt(const ImageSourceInfo &src) override;
|
||||
void SetBorder(const Border &border) override;
|
||||
void SetBackBorder() override;
|
||||
@ -92,6 +95,8 @@ public:
|
||||
static bool GetDraggable(FrameNode* frameNode);
|
||||
static ImageRenderMode GetImageRenderMode(FrameNode* frameNode);
|
||||
static void SetResizableSlice(FrameNode *frameNode, const ImageResizableSlice& slice);
|
||||
private:
|
||||
RefPtr<ImagePattern> GetImagePattern();
|
||||
};
|
||||
} // namespace OHOS::Ace::NG
|
||||
#endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERN_IMAGE_IMAGE_MODEL_NG_H
|
||||
|
@ -45,12 +45,19 @@
|
||||
#include "core/pipeline_ng/pipeline_context.h"
|
||||
|
||||
namespace OHOS::Ace::NG {
|
||||
namespace {
|
||||
constexpr int32_t DEFAULT_DURATION = 1000; // ms
|
||||
constexpr uint32_t CRITICAL_TIME = 50; // ms. If show time of image is less than this, use more cacheImages.
|
||||
constexpr int64_t MICROSEC_TO_MILLISEC = 1000;
|
||||
constexpr int32_t DEFAULT_ITERATIONS = 1;
|
||||
} // namespace
|
||||
|
||||
constexpr float BOX_EPSILON = 0.5f;
|
||||
|
||||
ImagePattern::ImagePattern()
|
||||
{
|
||||
InitDefaultValue();
|
||||
ImageAnimatorPattern();
|
||||
}
|
||||
|
||||
ImagePattern::~ImagePattern()
|
||||
@ -442,6 +449,18 @@ RefPtr<NodePaintMethod> ImagePattern::CreateNodePaintMethod()
|
||||
|
||||
bool ImagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
|
||||
{
|
||||
if (!isLayouted_ && isAnimation_) {
|
||||
isLayouted_ = true;
|
||||
if (images_.size()) {
|
||||
int32_t nextIndex = GetNextIndex(nowImageIndex_);
|
||||
for (auto& cacheImage : cacheImages_) {
|
||||
UpdateCacheImageInfo(cacheImage, nextIndex);
|
||||
nextIndex = GetNextIndex(nextIndex);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (config.skipMeasure || dirty->SkipMeasureContent()) {
|
||||
return false;
|
||||
}
|
||||
@ -577,6 +596,67 @@ void ImagePattern::UpdateGestureAndDragWhenModify()
|
||||
}
|
||||
|
||||
void ImagePattern::OnModifyDone()
|
||||
{
|
||||
if (isAnimation_) {
|
||||
OnAnimatedModifyDone();
|
||||
} else {
|
||||
OnImageModifyDone();
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePattern::OnAnimatedModifyDone()
|
||||
{
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
Pattern::OnModifyDone();
|
||||
auto size = static_cast<int32_t>(images_.size());
|
||||
if (size <= 0) {
|
||||
LOGE("image size is less than 0.");
|
||||
return;
|
||||
}
|
||||
GenerateCachedImages();
|
||||
auto index = nowImageIndex_;
|
||||
if ((status_ == Animator::Status::IDLE || status_ == Animator::Status::STOPPED) && !firstUpdateEvent_) {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
if (imagesChangedFlag_) {
|
||||
animator_->ClearInterpolators();
|
||||
animator_->AddInterpolator(CreatePictureAnimation(size));
|
||||
AdaptSelfSize();
|
||||
imagesChangedFlag_ = false;
|
||||
}
|
||||
if (firstUpdateEvent_) {
|
||||
firstUpdateEvent_ = false;
|
||||
auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
|
||||
AddImageLoadSuccessEvent(imageFrameNode);
|
||||
}
|
||||
UpdateFormDurationByRemainder();
|
||||
switch (status_) {
|
||||
case Animator::Status::IDLE:
|
||||
animator_->Cancel();
|
||||
ResetFormAnimationFlag();
|
||||
SetShowingIndex(index);
|
||||
break;
|
||||
case Animator::Status::PAUSED:
|
||||
animator_->Pause();
|
||||
ResetFormAnimationFlag();
|
||||
break;
|
||||
case Animator::Status::STOPPED:
|
||||
animator_->Finish();
|
||||
ResetFormAnimationFlag();
|
||||
break;
|
||||
default:
|
||||
ResetFormAnimationStartTime();
|
||||
if (isFormAnimationEnd_) {
|
||||
ResetFormAnimationFlag();
|
||||
return;
|
||||
}
|
||||
animator_->Forward();
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePattern::OnImageModifyDone()
|
||||
{
|
||||
Pattern::OnModifyDone();
|
||||
LoadImageDataIfNeed();
|
||||
@ -801,15 +881,20 @@ void ImagePattern::OnAttachToFrameNode()
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
auto renderCtx = host->GetRenderContext();
|
||||
renderCtx->SetClipToBounds(false);
|
||||
renderCtx->SetUsingContentRectForRenderFrame(true);
|
||||
if (isAnimation_) {
|
||||
CHECK_NULL_VOID(renderCtx);
|
||||
renderCtx->SetClipToFrame(true);
|
||||
} else {
|
||||
renderCtx->SetClipToBounds(false);
|
||||
renderCtx->SetUsingContentRectForRenderFrame(true);
|
||||
|
||||
// register image frame node to pipeline context to receive memory level notification and window state change
|
||||
// notification
|
||||
auto pipeline = PipelineContext::GetCurrentContext();
|
||||
CHECK_NULL_VOID(pipeline);
|
||||
pipeline->AddNodesToNotifyMemoryLevel(host->GetId());
|
||||
pipeline->AddWindowStateChangedCallback(host->GetId());
|
||||
// register image frame node to pipeline context to receive memory level notification and window state change
|
||||
// notification
|
||||
auto pipeline = PipelineContext::GetCurrentContext();
|
||||
CHECK_NULL_VOID(pipeline);
|
||||
pipeline->AddNodesToNotifyMemoryLevel(host->GetId());
|
||||
pipeline->AddWindowStateChangedCallback(host->GetId());
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePattern::OnDetachFromFrameNode(FrameNode* frameNode)
|
||||
@ -1359,4 +1444,386 @@ bool ImagePattern::hasSceneChanged()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImagePattern::ImageAnimatorPattern()
|
||||
{
|
||||
animator_ = CREATE_ANIMATOR(PipelineContext::GetCurrentContext());
|
||||
animator_->SetFillMode(FillMode::BACKWARDS);
|
||||
animator_->SetDuration(DEFAULT_DURATION);
|
||||
ResetFormAnimationFlag();
|
||||
}
|
||||
|
||||
RefPtr<PictureAnimation<int32_t>> ImagePattern::CreatePictureAnimation(int32_t size)
|
||||
{
|
||||
auto pictureAnimation = MakeRefPtr<PictureAnimation<int32_t>>();
|
||||
if (durationTotal_ > 0) {
|
||||
for (int32_t index = 0; index < size; ++index) {
|
||||
pictureAnimation->AddPicture(images_[index].duration / static_cast<float>(durationTotal_), index);
|
||||
}
|
||||
animator_->SetDuration(durationTotal_);
|
||||
} else {
|
||||
for (int32_t index = 0; index < size; ++index) {
|
||||
pictureAnimation->AddPicture(NORMALIZED_DURATION_MAX / static_cast<float>(size), index);
|
||||
}
|
||||
}
|
||||
|
||||
pictureAnimation->AddListener([weak = WeakClaim(this)](int32_t index) {
|
||||
auto imageAnimator = weak.Upgrade();
|
||||
CHECK_NULL_VOID(imageAnimator);
|
||||
imageAnimator->SetShowingIndex(index);
|
||||
});
|
||||
return pictureAnimation;
|
||||
}
|
||||
|
||||
void ImagePattern::SetShowingIndex(int32_t index)
|
||||
{
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
auto imageFrameNode = AceType::DynamicCast<FrameNode>(host->GetChildren().front());
|
||||
CHECK_NULL_VOID(imageFrameNode);
|
||||
auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
CHECK_NULL_VOID(imageLayoutProperty);
|
||||
if (index >= static_cast<int32_t>(images_.size())) {
|
||||
LOGW("ImageAnimator update index error, index: %{public}d, size: %{public}zu", index, images_.size());
|
||||
return;
|
||||
}
|
||||
CHECK_NULL_VOID(images_[index].pixelMap);
|
||||
nowImageIndex_ = index;
|
||||
auto cacheImageIter = FindCacheImageNode(images_[index].pixelMap);
|
||||
if (IsShowingSrc(imageFrameNode, images_[index].pixelMap)) {
|
||||
ACE_SCOPED_TRACE("ImageAnimator same src %s, index %d", "PixelMap", index);
|
||||
UpdateShowingImageInfo(imageFrameNode, index);
|
||||
} else if (cacheImageIter == cacheImages_.end()) {
|
||||
ACE_SCOPED_TRACE("ImageAnimator no cache found, src %s, index %d", "PixelMap", index);
|
||||
UpdateShowingImageInfo(imageFrameNode, index);
|
||||
} else if (cacheImageIter->isLoaded) {
|
||||
ACE_SCOPED_TRACE("ImageAnimator useCache src %s, index %d", "PixelMap", index);
|
||||
auto cacheImageNode = cacheImageIter->imageNode;
|
||||
host->RemoveChild(imageFrameNode);
|
||||
host->AddChild(cacheImageNode, DEFAULT_NODE_SLOT, true);
|
||||
host->RebuildRenderContextTree();
|
||||
cacheImages_.erase(cacheImageIter);
|
||||
CacheImageStruct newCacheImageStruct(imageFrameNode);
|
||||
newCacheImageStruct.isLoaded = true;
|
||||
cacheImages_.emplace_back(newCacheImageStruct);
|
||||
UpdateShowingImageInfo(cacheImageNode, index);
|
||||
} else {
|
||||
UpdateShowingImageInfo(imageFrameNode, index);
|
||||
// wait for cache image loading
|
||||
ACE_SCOPED_TRACE("ImageAnimator waitForCache src %s, index %d", "PixelMap", index);
|
||||
}
|
||||
// update cache images
|
||||
CHECK_NULL_VOID(cacheImages_.size());
|
||||
int32_t nextIndex = GetNextIndex(index);
|
||||
for (auto& cacheImage : cacheImages_) {
|
||||
UpdateCacheImageInfo(cacheImage, nextIndex);
|
||||
nextIndex = GetNextIndex(nextIndex);
|
||||
}
|
||||
host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
|
||||
}
|
||||
|
||||
void ImagePattern::UpdateShowingImageInfo(const RefPtr<FrameNode>& imageFrameNode, int32_t index)
|
||||
{
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
|
||||
CHECK_NULL_VOID(layoutProperty);
|
||||
auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
|
||||
CHECK_NULL_VOID(renderProperty);
|
||||
auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
CHECK_NULL_VOID(imageLayoutProperty);
|
||||
auto imageRenderProperty = imageFrameNode->GetPaintProperty<ImageRenderProperty>();
|
||||
CHECK_NULL_VOID(imageRenderProperty);
|
||||
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
|
||||
if (renderProperty->HasColorFilter()) {
|
||||
imageRenderProperty->UpdateColorFilter(renderProperty->GetColorFilter().value());
|
||||
}
|
||||
if (renderProperty->HasImageFit()) {
|
||||
imageRenderProperty->UpdateImageFit(renderProperty->GetImageFit().value());
|
||||
}
|
||||
if (layoutProperty->HasImageFit()) {
|
||||
imageLayoutProperty->UpdateImageFit(layoutProperty->GetImageFit().value());
|
||||
}
|
||||
//use the size of first pixelmap when no size is set
|
||||
auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
|
||||
if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
|
||||
CalcSize realSize = {
|
||||
CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
|
||||
imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
|
||||
imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_CONTENT);
|
||||
imageFrameNode->MarkModifyDone();
|
||||
imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
|
||||
return;
|
||||
}
|
||||
MarginProperty margin;
|
||||
margin.SetEdges(CalcLength(0.0));
|
||||
imageLayoutProperty->UpdateMargin(margin);
|
||||
imageLayoutProperty->ClearUserDefinedIdealSize(true, true);
|
||||
imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
|
||||
imageFrameNode->MarkModifyDone();
|
||||
imageFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
|
||||
}
|
||||
|
||||
void ImagePattern::UpdateCacheImageInfo(CacheImageStruct& cacheImage, int32_t index)
|
||||
{
|
||||
if (index >= static_cast<int32_t>(images_.size())) {
|
||||
LOGW("PrepareImageInfo index error, index: %{public}d, size: %{public}zu", index, images_.size());
|
||||
return;
|
||||
}
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
auto layoutProperty = host->GetLayoutProperty<ImageLayoutProperty>();
|
||||
CHECK_NULL_VOID(layoutProperty);
|
||||
auto renderProperty = host->GetPaintProperty<ImageRenderProperty>();
|
||||
CHECK_NULL_VOID(renderProperty);
|
||||
auto imageLayoutProperty = cacheImage.imageNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
CHECK_NULL_VOID(imageLayoutProperty);
|
||||
auto imageRenderProperty = cacheImage.imageNode->GetPaintProperty<ImageRenderProperty>();
|
||||
CHECK_NULL_VOID(imageRenderProperty);
|
||||
CHECK_NULL_VOID(images_[index].pixelMap);
|
||||
// pixelmap
|
||||
if (imageLayoutProperty->HasImageSourceInfo()) {
|
||||
auto preSrc = imageLayoutProperty->GetImageSourceInfoValue().GetPixmap();
|
||||
if (preSrc != images_[index].pixelMap) {
|
||||
// need to cache newImage
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
|
||||
cacheImage.index = index;
|
||||
cacheImage.isLoaded = false;
|
||||
}
|
||||
}
|
||||
if (renderProperty->HasColorFilter()) {
|
||||
imageRenderProperty->UpdateColorFilter(renderProperty->GetColorFilter().value());
|
||||
}
|
||||
if (renderProperty->HasImageFit()) {
|
||||
imageRenderProperty->UpdateImageFit(renderProperty->GetImageFit().value());
|
||||
}
|
||||
if (layoutProperty->HasImageFit()) {
|
||||
imageLayoutProperty->UpdateImageFit(layoutProperty->GetImageFit().value());
|
||||
}
|
||||
//use the size of first pixelmap when no size is set
|
||||
auto &&layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
|
||||
if (!layoutConstraint || !layoutConstraint->selfIdealSize.has_value()) {
|
||||
CalcSize realSize = {
|
||||
CalcLength(images_[0].pixelMap->GetWidth()), CalcLength(images_[0].pixelMap->GetHeight()) };
|
||||
imageLayoutProperty->UpdateUserDefinedIdealSize(realSize);
|
||||
cacheImage.imageNode->MarkModifyDone();
|
||||
return;
|
||||
}
|
||||
auto hostSize = host->GetGeometryNode()->GetPaddingSize();
|
||||
if (!hostSize.IsPositive()) {
|
||||
// if imageNode size is nonPositive, no pixelMap will be generated. Wait for size.
|
||||
return;
|
||||
}
|
||||
imageLayoutProperty->UpdateUserDefinedIdealSize(
|
||||
CalcSize(CalcLength(hostSize.Width()), CalcLength(hostSize.Height())));
|
||||
cacheImage.imageNode->MarkModifyDone();
|
||||
}
|
||||
|
||||
std::list<ImagePattern::CacheImageStruct>::iterator ImagePattern::FindCacheImageNode(const RefPtr<PixelMap>& src)
|
||||
{
|
||||
for (auto iter = cacheImages_.begin(); iter != cacheImages_.end(); ++iter) {
|
||||
if (IsShowingSrc(iter->imageNode, src)) {
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
return cacheImages_.end();
|
||||
}
|
||||
|
||||
void ImagePattern::GenerateCachedImages()
|
||||
{
|
||||
CHECK_NULL_VOID(images_.size());
|
||||
auto averageShowTime = animator_->GetDuration() / images_.size();
|
||||
size_t cacheImageNum = averageShowTime >= CRITICAL_TIME ? 1 : 2;
|
||||
cacheImageNum = std::min(images_.size() - 1, cacheImageNum);
|
||||
if (cacheImages_.size() > cacheImageNum) {
|
||||
cacheImages_.resize(cacheImageNum);
|
||||
return;
|
||||
}
|
||||
while (cacheImages_.size() < cacheImageNum) {
|
||||
auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, -1, AceType::MakeRefPtr<ImagePattern>());
|
||||
auto imageLayoutProperty = imageNode->GetLayoutProperty();
|
||||
imageLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
|
||||
imageLayoutProperty->UpdateAlignment(Alignment::TOP_LEFT);
|
||||
AddImageLoadSuccessEvent(imageNode);
|
||||
cacheImages_.emplace_back(CacheImageStruct(imageNode));
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePattern::AdaptSelfSize()
|
||||
{
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
const auto& layoutProperty = host->GetLayoutProperty();
|
||||
CHECK_NULL_VOID(layoutProperty);
|
||||
if (layoutProperty->GetCalcLayoutConstraint() && layoutProperty->GetCalcLayoutConstraint()->selfIdealSize &&
|
||||
layoutProperty->GetCalcLayoutConstraint()->selfIdealSize->IsValid()) {
|
||||
return;
|
||||
}
|
||||
Dimension maxWidth;
|
||||
Dimension maxHeight;
|
||||
double maxWidthPx = 0.0;
|
||||
double maxHeightPx = 0.0;
|
||||
for (const auto& image : images_) {
|
||||
if (image.width.Unit() != DimensionUnit::PERCENT) {
|
||||
auto widthPx = image.width.ConvertToPx();
|
||||
if (widthPx > maxWidthPx) {
|
||||
maxWidthPx = widthPx;
|
||||
maxWidth = image.width;
|
||||
}
|
||||
}
|
||||
if (image.height.Unit() != DimensionUnit::PERCENT) {
|
||||
auto heightPx = image.height.ConvertToPx();
|
||||
if (heightPx > maxHeightPx) {
|
||||
maxHeightPx = heightPx;
|
||||
maxHeight = image.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!maxWidth.IsValid() || !maxHeight.IsValid()) {
|
||||
return;
|
||||
}
|
||||
const auto& layoutConstraint = layoutProperty->GetCalcLayoutConstraint();
|
||||
if (!layoutConstraint || !layoutConstraint->selfIdealSize) {
|
||||
layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(maxWidth), CalcLength(maxHeight)));
|
||||
return;
|
||||
}
|
||||
if (!layoutConstraint->selfIdealSize->Width()) {
|
||||
layoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(maxWidth), std::nullopt));
|
||||
return;
|
||||
}
|
||||
layoutProperty->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(maxHeight)));
|
||||
}
|
||||
|
||||
int32_t ImagePattern::GetNextIndex(int32_t preIndex)
|
||||
{
|
||||
return (preIndex + 1) % static_cast<int32_t>(images_.size());
|
||||
}
|
||||
|
||||
void ImagePattern::AddImageLoadSuccessEvent(const RefPtr<FrameNode>& imageFrameNode)
|
||||
{
|
||||
CHECK_NULL_VOID(imageFrameNode);
|
||||
auto eventHub = imageFrameNode->GetEventHub<ImageEventHub>();
|
||||
eventHub->SetOnComplete(
|
||||
[weakImage = WeakPtr<FrameNode>(imageFrameNode), weak = WeakClaim(this)](const LoadImageSuccessEvent& info) {
|
||||
if (info.GetLoadingStatus() != 1) {
|
||||
// status 1 means load success. Only need loadSuccess event.
|
||||
return;
|
||||
}
|
||||
auto pattern = weak.Upgrade();
|
||||
CHECK_NULL_VOID(pattern);
|
||||
auto cacheImageNode = weakImage.Upgrade();
|
||||
CHECK_NULL_VOID(cacheImageNode);
|
||||
auto imageAnimator = pattern->GetHost();
|
||||
CHECK_NULL_VOID(imageAnimator);
|
||||
auto cacheLayoutProperty = cacheImageNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
auto cacheSrc = cacheLayoutProperty->GetImageSourceInfoValue(ImageSourceInfo()).GetSrc();
|
||||
ACE_SCOPED_TRACE("ImageAnimator cache succeed. src %s", cacheSrc.c_str());
|
||||
auto iter = std::find_if(pattern->cacheImages_.begin(), pattern->cacheImages_.end(),
|
||||
[&cacheImageNode](const CacheImageStruct& other) { return other.imageNode == cacheImageNode; });
|
||||
if (iter == pattern->cacheImages_.end()) {
|
||||
return;
|
||||
}
|
||||
iter->isLoaded = true;
|
||||
if (pattern->nowImageIndex_ >= static_cast<int32_t>(pattern->images_.size())) {
|
||||
LOGW("ImageAnimator showImage index is invalid");
|
||||
return;
|
||||
}
|
||||
if (pattern->nowImageIndex_ == iter->index &&
|
||||
IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].pixelMap)) {
|
||||
pattern->SetShowingIndex(pattern->nowImageIndex_);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ImagePattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src)
|
||||
{
|
||||
auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
return imageLayoutProperty->HasImageSourceInfo()
|
||||
&& imageLayoutProperty->GetImageSourceInfoValue().GetPixmap() == src;
|
||||
}
|
||||
|
||||
bool ImagePattern::IsFormRender()
|
||||
{
|
||||
auto pipeline = PipelineBase::GetCurrentContext();
|
||||
CHECK_NULL_RETURN(pipeline, false);
|
||||
return pipeline->IsFormRender();
|
||||
}
|
||||
|
||||
void ImagePattern::UpdateFormDurationByRemainder()
|
||||
{
|
||||
if (IsFormRender()) {
|
||||
if (!isFormAnimationStart_) {
|
||||
formAnimationRemainder_ =
|
||||
DEFAULT_DURATION - (GetMicroTickCount() - formAnimationStartTime_) / MICROSEC_TO_MILLISEC;
|
||||
}
|
||||
if ((formAnimationRemainder_ > 0) && (animator_->GetDuration() > formAnimationRemainder_)) {
|
||||
animator_->SetDuration(formAnimationRemainder_);
|
||||
}
|
||||
if (formAnimationRemainder_ <= 0) {
|
||||
isFormAnimationEnd_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePattern::ResetFormAnimationStartTime()
|
||||
{
|
||||
if (isFormAnimationStart_) {
|
||||
isFormAnimationStart_ = false;
|
||||
formAnimationStartTime_ = GetMicroTickCount();
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePattern::ResetFormAnimationFlag()
|
||||
{
|
||||
if (IsFormRender()) {
|
||||
formAnimationRemainder_ = DEFAULT_DURATION;
|
||||
isFormAnimationStart_ = true;
|
||||
isFormAnimationEnd_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ImagePattern::SetIteration(int32_t iteration)
|
||||
{
|
||||
if (iteration < -1) {
|
||||
iteration = DEFAULT_ITERATIONS;
|
||||
}
|
||||
if (IsFormRender()) {
|
||||
iteration = DEFAULT_ITERATIONS;
|
||||
}
|
||||
animator_->SetIteration(iteration);
|
||||
}
|
||||
|
||||
void ImagePattern::SetDuration(int32_t duration)
|
||||
{
|
||||
if (duration <= 0) {
|
||||
return;
|
||||
}
|
||||
if (durationTotal_ == 0) {
|
||||
for (int i = 0; i < images_.size(); i++) {
|
||||
images_[i].duration = duration / images_.size();
|
||||
durationTotal_ += images_[i].duration;
|
||||
}
|
||||
}
|
||||
int32_t finalDuration = durationTotal_ > 0 ? durationTotal_ : duration;
|
||||
if (IsFormRender()) {
|
||||
finalDuration = finalDuration < DEFAULT_DURATION ? finalDuration : DEFAULT_DURATION;
|
||||
}
|
||||
if (animator_->GetDuration() == finalDuration) {
|
||||
animator_->RemoveRepeatListener(repeatCallbackId_);
|
||||
return;
|
||||
}
|
||||
if (animator_->GetStatus() == Animator::Status::IDLE || animator_->GetStatus() == Animator::Status::STOPPED) {
|
||||
animator_->SetDuration(finalDuration);
|
||||
animator_->RemoveRepeatListener(repeatCallbackId_);
|
||||
return;
|
||||
}
|
||||
// if animator is running or paused, duration will work next time
|
||||
animator_->RemoveRepeatListener(repeatCallbackId_);
|
||||
repeatCallbackId_ = animator_->AddRepeatListener([weak = WeakClaim(this), finalDuration]() {
|
||||
auto imageAnimator = weak.Upgrade();
|
||||
CHECK_NULL_VOID(imageAnimator);
|
||||
imageAnimator->animator_->SetDuration(finalDuration);
|
||||
});
|
||||
}
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
@ -20,7 +20,10 @@
|
||||
|
||||
#include "base/geometry/offset.h"
|
||||
#include "base/memory/referenced.h"
|
||||
#include "core/animation/animator.h"
|
||||
#include "core/animation/picture_animation.h"
|
||||
#include "core/components/common/layout/constants.h"
|
||||
#include "core/components/declaration/image/image_animator_declaration.h"
|
||||
#include "core/components_ng/event/click_event.h"
|
||||
#include "core/components_ng/manager/select_overlay/selection_host.h"
|
||||
#include "core/components_ng/pattern/image/image_event_hub.h"
|
||||
@ -169,6 +172,71 @@ public:
|
||||
void EnableAnalyzer(bool value);
|
||||
bool hasSceneChanged();
|
||||
|
||||
//animation
|
||||
struct CacheImageStruct {
|
||||
CacheImageStruct() = default;
|
||||
CacheImageStruct(const RefPtr<FrameNode>& imageNode) : imageNode(imageNode) {}
|
||||
virtual ~CacheImageStruct() = default;
|
||||
RefPtr<FrameNode> imageNode;
|
||||
int32_t index = 0;
|
||||
bool isLoaded = false;
|
||||
};
|
||||
|
||||
void ImageAnimatorPattern();
|
||||
void SetImages(std::vector<ImageProperties>&& images)
|
||||
{
|
||||
images_ = std::move(images);
|
||||
durationTotal_ = 0;
|
||||
for (const auto& childImage : images_) {
|
||||
if ((!childImage.src.empty() || childImage.pixelMap != nullptr) && childImage.duration > 0) {
|
||||
durationTotal_ += childImage.duration;
|
||||
}
|
||||
}
|
||||
imagesChangedFlag_ = true;
|
||||
isAnimation_ = true;
|
||||
}
|
||||
|
||||
void StartAnimation() {
|
||||
status_ = Animator::Status::RUNNING;
|
||||
}
|
||||
|
||||
void StopAnimation() {
|
||||
status_ = Animator::Status::STOPPED;
|
||||
OnAnimatedModifyDone();
|
||||
}
|
||||
|
||||
void SetIsAnimation(bool isAnimation)
|
||||
{
|
||||
isAnimation_ = isAnimation;
|
||||
}
|
||||
|
||||
bool GetIsAnimation() const
|
||||
{
|
||||
return isAnimation_;
|
||||
}
|
||||
|
||||
bool IsAtomicNode() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnInActive() override
|
||||
{
|
||||
if (status_ == Animator::Status::RUNNING) {
|
||||
animator_->Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void OnActive() override
|
||||
{
|
||||
if (status_ == Animator::Status::RUNNING && animator_->GetStatus() != Animator::Status::RUNNING) {
|
||||
animator_->Forward();
|
||||
}
|
||||
}
|
||||
|
||||
void SetDuration(int32_t duration);
|
||||
void SetIteration(int32_t iteration);
|
||||
|
||||
protected:
|
||||
void RegisterWindowStateChangedCallback();
|
||||
void UnregisterWindowStateChangedCallback();
|
||||
@ -258,6 +326,24 @@ private:
|
||||
bool IsSupportImageAnalyzerFeature();
|
||||
void InitDefaultValue();
|
||||
|
||||
//animation
|
||||
RefPtr<PictureAnimation<int32_t>> CreatePictureAnimation(int32_t size);
|
||||
void AdaptSelfSize();
|
||||
void SetShowingIndex(int32_t index);
|
||||
void UpdateShowingImageInfo(const RefPtr<FrameNode>& imageFrameNode, int32_t index);
|
||||
void UpdateCacheImageInfo(CacheImageStruct& cacheImage, int32_t index);
|
||||
std::list<CacheImageStruct>::iterator FindCacheImageNode(const RefPtr<PixelMap>& src);
|
||||
int32_t GetNextIndex(int32_t preIndex);
|
||||
void GenerateCachedImages();
|
||||
void AddImageLoadSuccessEvent(const RefPtr<FrameNode>& imageFrameNode);
|
||||
static bool IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src);
|
||||
bool IsFormRender();
|
||||
void UpdateFormDurationByRemainder();
|
||||
void ResetFormAnimationStartTime();
|
||||
void ResetFormAnimationFlag();
|
||||
void OnAnimatedModifyDone();
|
||||
void OnImageModifyDone();
|
||||
|
||||
CopyOptions copyOption_ = CopyOptions::None;
|
||||
ImageInterpolation interpolation_ = ImageInterpolation::NONE;
|
||||
|
||||
@ -288,6 +374,23 @@ private:
|
||||
OffsetF parentGlobalOffset_;
|
||||
|
||||
ACE_DISALLOW_COPY_AND_MOVE(ImagePattern);
|
||||
|
||||
//animation
|
||||
bool isAnimation_ = false;
|
||||
RefPtr<Animator> animator_;
|
||||
std::vector<ImageProperties> images_;
|
||||
std::list<CacheImageStruct> cacheImages_;
|
||||
Animator::Status status_ = Animator::Status::IDLE;
|
||||
int32_t durationTotal_ = 0;
|
||||
int32_t nowImageIndex_ = 0;
|
||||
uint64_t repeatCallbackId_ = 0;
|
||||
bool imagesChangedFlag_ = false;
|
||||
bool firstUpdateEvent_ = true;
|
||||
bool isLayouted_ = false;
|
||||
int64_t formAnimationStartTime_ = 0;
|
||||
int32_t formAnimationRemainder_ = 0;
|
||||
bool isFormAnimationStart_ = true;
|
||||
bool isFormAnimationEnd_ = false;
|
||||
};
|
||||
|
||||
} // namespace OHOS::Ace::NG
|
||||
|
@ -81,15 +81,22 @@ void ImageAnimatorPattern::SetShowingIndex(int32_t index)
|
||||
return;
|
||||
}
|
||||
nowImageIndex_ = index;
|
||||
bool isShowingSrc = IsShowingSrc(imageFrameNode, images_[index].src);
|
||||
auto cacheImageIter = FindCacheImageNode(images_[index].src);
|
||||
if (IsShowingSrc(imageFrameNode, images_[index].src)) {
|
||||
ACE_SCOPED_TRACE("ImageAnimator same src %s, index %d", images_[index].src.c_str(), index);
|
||||
std::string traceTag = images_[index].src;
|
||||
if (images_[index].pixelMap != nullptr) {
|
||||
isShowingSrc = IsShowingSrc(imageFrameNode, images_[index].pixelMap);
|
||||
cacheImageIter = FindCacheImageNode(images_[index].pixelMap);
|
||||
traceTag = "PixelMap";
|
||||
}
|
||||
if (isShowingSrc) {
|
||||
ACE_SCOPED_TRACE("ImageAnimator same src %s, index %d", traceTag.c_str(), index);
|
||||
UpdateShowingImageInfo(imageFrameNode, index);
|
||||
} else if (cacheImageIter == cacheImages_.end()) {
|
||||
ACE_SCOPED_TRACE("ImageAnimator no cache found, src %s, index %d", images_[index].src.c_str(), index);
|
||||
ACE_SCOPED_TRACE("ImageAnimator no cache found, src %s, index %d", traceTag.c_str(), index);
|
||||
UpdateShowingImageInfo(imageFrameNode, index);
|
||||
} else if (cacheImageIter->isLoaded) {
|
||||
ACE_SCOPED_TRACE("ImageAnimator useCache src %s, index %d", images_[index].src.c_str(), index);
|
||||
ACE_SCOPED_TRACE("ImageAnimator useCache src %s, index %d", traceTag.c_str(), index);
|
||||
auto cacheImageNode = cacheImageIter->imageNode;
|
||||
host->RemoveChild(imageFrameNode);
|
||||
host->AddChild(cacheImageNode, DEFAULT_NODE_SLOT, true);
|
||||
@ -100,8 +107,9 @@ void ImageAnimatorPattern::SetShowingIndex(int32_t index)
|
||||
cacheImages_.emplace_back(newCacheImageStruct);
|
||||
UpdateShowingImageInfo(cacheImageNode, index);
|
||||
} else {
|
||||
UpdateShowingImageInfo(imageFrameNode, index);
|
||||
// wait for cache image loading
|
||||
ACE_SCOPED_TRACE("ImageAnimator waitForCache src %s, index %d", images_[index].src.c_str(), index);
|
||||
ACE_SCOPED_TRACE("ImageAnimator waitForCache src %s, index %d", traceTag.c_str(), index);
|
||||
return;
|
||||
}
|
||||
// update cache images
|
||||
@ -118,8 +126,12 @@ void ImageAnimatorPattern::UpdateShowingImageInfo(const RefPtr<FrameNode>& image
|
||||
{
|
||||
auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
CHECK_NULL_VOID(imageLayoutProperty);
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(
|
||||
images_[index].src, images_[index].bundleName, images_[index].moduleName));
|
||||
if (images_[index].pixelMap == nullptr) {
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(
|
||||
images_[index].src, images_[index].bundleName, images_[index].moduleName));
|
||||
} else {
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(images_[index].pixelMap));
|
||||
}
|
||||
MarginProperty margin;
|
||||
if (!fixedSize_) {
|
||||
margin.left = CalcLength(images_[index].left);
|
||||
@ -148,13 +160,30 @@ void ImageAnimatorPattern::UpdateCacheImageInfo(CacheImageStruct& cacheImage, in
|
||||
}
|
||||
auto imageLayoutProperty = cacheImage.imageNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
const auto& image = images_[index];
|
||||
auto preSrc =
|
||||
imageLayoutProperty->HasImageSourceInfo() ? imageLayoutProperty->GetImageSourceInfoValue().GetSrc() : "";
|
||||
if (preSrc != image.src) {
|
||||
// need to cache newImage
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(image.src, image.bundleName, image.moduleName));
|
||||
cacheImage.index = index;
|
||||
cacheImage.isLoaded = false;
|
||||
if (image.pixelMap == nullptr) {
|
||||
auto preSrc =
|
||||
imageLayoutProperty->HasImageSourceInfo() ? imageLayoutProperty->GetImageSourceInfoValue().GetSrc() : "";
|
||||
if (preSrc != image.src) {
|
||||
// need to cache newImage
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(image.src, image.bundleName, image.moduleName));
|
||||
cacheImage.index = index;
|
||||
cacheImage.isLoaded = false;
|
||||
}
|
||||
} else {
|
||||
// pixelmap
|
||||
if (imageLayoutProperty->HasImageSourceInfo()) {
|
||||
auto preSrc = imageLayoutProperty->GetImageSourceInfoValue().GetPixmap();
|
||||
if (preSrc != image.pixelMap) {
|
||||
// need to cache newImage
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(image.pixelMap));
|
||||
cacheImage.index = index;
|
||||
cacheImage.isLoaded = false;
|
||||
}
|
||||
} else {
|
||||
imageLayoutProperty->UpdateImageSourceInfo(ImageSourceInfo(image.pixelMap));
|
||||
cacheImage.index = index;
|
||||
cacheImage.isLoaded = false;
|
||||
}
|
||||
}
|
||||
auto host = GetHost();
|
||||
CHECK_NULL_VOID(host);
|
||||
@ -177,6 +206,17 @@ void ImageAnimatorPattern::UpdateCacheImageInfo(CacheImageStruct& cacheImage, in
|
||||
cacheImage.imageNode->MarkModifyDone();
|
||||
}
|
||||
|
||||
std::list<ImageAnimatorPattern::CacheImageStruct>::iterator ImageAnimatorPattern::FindCacheImageNode(
|
||||
const RefPtr<PixelMap>& src)
|
||||
{
|
||||
for (auto iter = cacheImages_.begin(); iter != cacheImages_.end(); ++iter) {
|
||||
if (IsShowingSrc(iter->imageNode, src)) {
|
||||
return iter;
|
||||
}
|
||||
}
|
||||
return cacheImages_.end();
|
||||
}
|
||||
|
||||
std::list<ImageAnimatorPattern::CacheImageStruct>::iterator ImageAnimatorPattern::FindCacheImageNode(
|
||||
const std::string& src)
|
||||
{
|
||||
@ -430,9 +470,16 @@ void ImageAnimatorPattern::AddImageLoadSuccessEvent(const RefPtr<FrameNode>& ima
|
||||
LOGW("ImageAnimator showImage index is invalid");
|
||||
return;
|
||||
}
|
||||
if (pattern->nowImageIndex_ == iter->index &&
|
||||
IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].src)) {
|
||||
pattern->SetShowingIndex(pattern->nowImageIndex_);
|
||||
if (pattern->images_[pattern->nowImageIndex_].pixelMap == nullptr) {
|
||||
if (pattern->nowImageIndex_ == iter->index &&
|
||||
IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].src)) {
|
||||
pattern->SetShowingIndex(pattern->nowImageIndex_);
|
||||
}
|
||||
} else {
|
||||
if (pattern->nowImageIndex_ == iter->index &&
|
||||
IsShowingSrc(cacheImageNode, pattern->images_[pattern->nowImageIndex_].pixelMap)) {
|
||||
pattern->SetShowingIndex(pattern->nowImageIndex_);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -443,6 +490,13 @@ bool ImageAnimatorPattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode,
|
||||
return imageLayoutProperty->HasImageSourceInfo() && imageLayoutProperty->GetImageSourceInfoValue().GetSrc() == src;
|
||||
}
|
||||
|
||||
bool ImageAnimatorPattern::IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src)
|
||||
{
|
||||
auto imageLayoutProperty = imageFrameNode->GetLayoutProperty<ImageLayoutProperty>();
|
||||
return imageLayoutProperty->HasImageSourceInfo()
|
||||
&& imageLayoutProperty->GetImageSourceInfoValue().GetPixmap() == src;
|
||||
}
|
||||
|
||||
bool ImageAnimatorPattern::IsFormRender()
|
||||
{
|
||||
auto pipeline = PipelineBase::GetCurrentContext();
|
||||
@ -493,6 +547,12 @@ void ImageAnimatorPattern::SetIteration(int32_t iteration)
|
||||
|
||||
void ImageAnimatorPattern::SetDuration(int32_t duration)
|
||||
{
|
||||
if (durationTotal_ == 0) {
|
||||
for (int i = 0; i < images_.size(); i++) {
|
||||
images_[i].duration = duration / images_.size();
|
||||
durationTotal_ += images_[i].duration;
|
||||
}
|
||||
}
|
||||
int32_t finalDuration = durationTotal_ > 0 ? durationTotal_ : duration;
|
||||
if (IsFormRender()) {
|
||||
finalDuration = finalDuration < DEFAULT_DURATION ? finalDuration : DEFAULT_DURATION;
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
images_ = std::move(images);
|
||||
durationTotal_ = 0;
|
||||
for (const auto& childImage : images_) {
|
||||
if (!childImage.src.empty() && childImage.duration > 0) {
|
||||
if ((!childImage.src.empty() || childImage.pixelMap != nullptr) && childImage.duration > 0) {
|
||||
durationTotal_ += childImage.duration;
|
||||
}
|
||||
}
|
||||
@ -120,10 +120,12 @@ private:
|
||||
void UpdateShowingImageInfo(const RefPtr<FrameNode>& imageFrameNode, int32_t index);
|
||||
void UpdateCacheImageInfo(CacheImageStruct& cacheImage, int32_t index);
|
||||
std::list<CacheImageStruct>::iterator FindCacheImageNode(const std::string& src);
|
||||
std::list<CacheImageStruct>::iterator FindCacheImageNode(const RefPtr<PixelMap>& src);
|
||||
int32_t GetNextIndex(int32_t preIndex);
|
||||
void GenerateCachedImages();
|
||||
void AddImageLoadSuccessEvent(const RefPtr<FrameNode>& imageFrameNode);
|
||||
static bool IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const std::string& src);
|
||||
static bool IsShowingSrc(const RefPtr<FrameNode>& imageFrameNode, const RefPtr<PixelMap>& src);
|
||||
bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& wrapper, const DirtySwapConfig& config) override;
|
||||
bool IsFormRender();
|
||||
void UpdateFormDurationByRemainder();
|
||||
|
@ -145,7 +145,7 @@ void SetImages(ArkUINodeHandle node, struct ArkUIImagePropertiesStruct* images,
|
||||
CHECK_NULL_VOID(image);
|
||||
CalcDimension dimension[IMAGES_LENGTH];
|
||||
ParseImage(dimension, IMAGES_LENGTH, image);
|
||||
ImageProperties property { std::string(image->src), "", "", dimension[0], dimension[1], dimension[2],
|
||||
ImageProperties property { std::string(image->src), nullptr, "", "", dimension[0], dimension[1], dimension[2],
|
||||
dimension[3], image->duration };
|
||||
imageList.emplace_back(property);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ const char DRAWABLEDESCRIPTOR_JSON_KEY_BACKGROUND[] = "background";
|
||||
const char DRAWABLEDESCRIPTOR_JSON_KEY_FOREGROUND[] = "foreground";
|
||||
#endif
|
||||
constexpr float SIDE = 192.0f;
|
||||
const int DEFAULT_DURATION = 1000;
|
||||
|
||||
// define for get resource path in preview scenes
|
||||
const static char PREVIEW_LOAD_RESOURCE_ID[] = "ohos_drawable_descriptor_path";
|
||||
@ -560,4 +561,33 @@ std::string LayeredDrawableDescriptor::GetStaticMaskClipPath()
|
||||
resMgr->GetStringByName(PREVIEW_LOAD_RESOURCE_ID, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
std::shared_ptr<Media::PixelMap> AnimatedDrawableDescriptor::GetPixelMap()
|
||||
{
|
||||
if (pixelMapList_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return pixelMapList_[0];
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Media::PixelMap>> AnimatedDrawableDescriptor::GetPixelMapList()
|
||||
{
|
||||
return pixelMapList_;
|
||||
}
|
||||
|
||||
int32_t AnimatedDrawableDescriptor::GetDuration()
|
||||
{
|
||||
if (duration_ <= 0) {
|
||||
duration_ = DEFAULT_DURATION * pixelMapList_.size();
|
||||
}
|
||||
return duration_;
|
||||
}
|
||||
|
||||
int32_t AnimatedDrawableDescriptor::GetIterations()
|
||||
{
|
||||
if (iterations_ < -1) {
|
||||
iterations_ = 1;
|
||||
}
|
||||
return iterations_;
|
||||
}
|
||||
} // namespace OHOS::Ace::Napi
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
enum class DrawableType {
|
||||
BASE,
|
||||
LAYERED,
|
||||
ANIMATED,
|
||||
};
|
||||
DrawableDescriptor() = default;
|
||||
explicit DrawableDescriptor(std::shared_ptr<Media::PixelMap> pixelMap) : pixelMap_(std::move(pixelMap)) {};
|
||||
@ -143,6 +144,21 @@ private:
|
||||
OptionalPixelMap layeredPixelMap_;
|
||||
};
|
||||
|
||||
class ACE_EXPORT AnimatedDrawableDescriptor : public DrawableDescriptor {
|
||||
public:
|
||||
AnimatedDrawableDescriptor(std::vector<std::shared_ptr<Media::PixelMap>> pixelMaps, int32_t duration,
|
||||
int32_t iterations): pixelMapList_(std::move(pixelMaps)), duration_(duration), iterations_(iterations) {};
|
||||
~AnimatedDrawableDescriptor() override = default;
|
||||
std::shared_ptr<Media::PixelMap> GetPixelMap() override;
|
||||
std::vector<std::shared_ptr<Media::PixelMap>> GetPixelMapList();
|
||||
int32_t GetDuration();
|
||||
int32_t GetIterations();
|
||||
private:
|
||||
std::vector<std::shared_ptr<Media::PixelMap>> pixelMapList_;
|
||||
int32_t duration_ = -1;
|
||||
int32_t iterations_ = 1;
|
||||
};
|
||||
|
||||
class DrawableDescriptorFactory {
|
||||
public:
|
||||
using DrawableType = DrawableDescriptor::DrawableType;
|
||||
|
@ -137,6 +137,11 @@ public:
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<PixelMap>* GetPixelMap()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
} // namespace Media
|
||||
} // namespace OHOS
|
||||
|
@ -29,11 +29,82 @@
|
||||
namespace {
|
||||
constexpr char DRAWABLE_BASE[] = "DrawableDescriptor";
|
||||
constexpr char DRAWABLE_LAYERED[] = "LayeredDrawableDescriptor";
|
||||
constexpr char DRAWABLE_ANIMATED[] = "AnimatedDrawableDescriptor";
|
||||
} // namespace
|
||||
|
||||
namespace OHOS::Ace::Napi {
|
||||
thread_local napi_ref JsDrawableDescriptor::baseConstructor_;
|
||||
thread_local napi_ref JsDrawableDescriptor::layeredConstructor_;
|
||||
thread_local napi_ref JsDrawableDescriptor::animatedConstructor_;
|
||||
|
||||
static bool GetPixelMapArray(
|
||||
napi_env env, napi_value arg, std::vector<std::shared_ptr<Media::PixelMap>>& pixelMaps)
|
||||
{
|
||||
bool isArray = false;
|
||||
uint32_t length = 0;
|
||||
napi_is_array(env, arg, &isArray);
|
||||
if (!isArray) {
|
||||
return false;
|
||||
}
|
||||
napi_get_array_length(env, arg, &length);
|
||||
if (length < 1) {
|
||||
return false;
|
||||
}
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
napi_value pixelMapValue = nullptr;
|
||||
napi_get_element(env, arg, i, &pixelMapValue);
|
||||
if (pixelMapValue == nullptr) {
|
||||
continue;
|
||||
}
|
||||
Media::PixelMapNapi* pixmapNapi = nullptr;
|
||||
napi_unwrap(env, pixelMapValue, reinterpret_cast<void**>(&pixmapNapi));
|
||||
if (pixmapNapi == nullptr) {
|
||||
continue;
|
||||
}
|
||||
pixelMaps.push_back(*(pixmapNapi->GetPixelMap()));
|
||||
}
|
||||
if (pixelMaps.size() <= 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
napi_value JsDrawableDescriptor::AnimatedConstructor(napi_env env, napi_callback_info info)
|
||||
{
|
||||
napi_escapable_handle_scope scope = nullptr;
|
||||
napi_open_escapable_handle_scope(env, &scope);
|
||||
|
||||
size_t argc = 2;
|
||||
napi_value argv[2] = {nullptr};
|
||||
napi_value thisVar = nullptr;
|
||||
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
|
||||
if (argc < 1) {
|
||||
return nullptr;
|
||||
}
|
||||
std::vector<std::shared_ptr<Media::PixelMap>> pixelMaps;
|
||||
if (!GetPixelMapArray(env, argv[0], pixelMaps)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//napi_get_named_property
|
||||
napi_value napiDuration;
|
||||
napi_value napiIterations;
|
||||
int32_t duration = -1;
|
||||
int32_t iterations = 1;
|
||||
if (argc > 1 && argv[1]) {
|
||||
napi_get_named_property(env, argv[1], "duration", &napiDuration);
|
||||
napi_get_named_property(env, argv[1], "iterations", &napiIterations);
|
||||
napi_get_value_int32(env, napiDuration, &duration);
|
||||
napi_get_value_int32(env, napiIterations, &iterations);
|
||||
}
|
||||
// create JsDrawable
|
||||
auto* animatedDrawable = new AnimatedDrawableDescriptor(pixelMaps, duration, iterations);
|
||||
// wrap to napi_value
|
||||
napi_wrap(env, thisVar, animatedDrawable, Destructor, nullptr, nullptr);
|
||||
napi_escape_handle(env, scope, thisVar, &thisVar);
|
||||
napi_close_escapable_handle_scope(env, scope);
|
||||
return thisVar;
|
||||
}
|
||||
|
||||
napi_value JsDrawableDescriptor::Constructor(napi_env env, napi_callback_info info)
|
||||
{
|
||||
@ -84,13 +155,25 @@ napi_value JsDrawableDescriptor::InitLayeredDrawable(napi_env env)
|
||||
return cons;
|
||||
}
|
||||
|
||||
napi_value JsDrawableDescriptor::InitAnimatedDrawable(napi_env env)
|
||||
{
|
||||
napi_value cons = nullptr;
|
||||
napi_property_descriptor animatedDes[] = {
|
||||
DECLARE_NAPI_FUNCTION("getPixelMap", GetPixelMap),
|
||||
};
|
||||
NAPI_CALL(env, napi_define_class(env, DRAWABLE_ANIMATED, NAPI_AUTO_LENGTH, AnimatedConstructor, nullptr,
|
||||
sizeof(animatedDes) / sizeof(napi_property_descriptor), animatedDes, &cons));
|
||||
NAPI_CALL(env, napi_create_reference(env, cons, 1, &animatedConstructor_));
|
||||
return cons;
|
||||
}
|
||||
|
||||
napi_value JsDrawableDescriptor::ToNapi(
|
||||
napi_env env, DrawableDescriptor* drawable, DrawableDescriptor::DrawableType type)
|
||||
{
|
||||
if (!drawable) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!baseConstructor_ || !layeredConstructor_) {
|
||||
if (!baseConstructor_ || !layeredConstructor_ || !animatedConstructor_) {
|
||||
// init js class constructor by importing module manually
|
||||
napi_value globalValue;
|
||||
napi_get_global(env, &globalValue);
|
||||
@ -107,6 +190,9 @@ napi_value JsDrawableDescriptor::ToNapi(
|
||||
napi_value result = nullptr;
|
||||
napi_status status;
|
||||
switch (type) {
|
||||
case DrawableDescriptor::DrawableType::ANIMATED:
|
||||
status = napi_get_reference_value(env, animatedConstructor_, &constructor);
|
||||
break;
|
||||
case DrawableDescriptor::DrawableType::LAYERED:
|
||||
status = napi_get_reference_value(env, layeredConstructor_, &constructor);
|
||||
break;
|
||||
@ -223,6 +309,11 @@ napi_value JsDrawableDescriptor::Export(napi_env env, napi_value exports)
|
||||
// export child class
|
||||
cons = InitLayeredDrawable(env);
|
||||
NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_LAYERED, cons));
|
||||
|
||||
//export child class
|
||||
cons = InitAnimatedDrawable(env);
|
||||
NAPI_CALL(env, napi_set_named_property(env, exports, DRAWABLE_ANIMATED, cons));
|
||||
|
||||
return exports;
|
||||
}
|
||||
} // namespace OHOS::Ace::Napi
|
||||
|
@ -33,9 +33,11 @@ public:
|
||||
private:
|
||||
static napi_value InitDrawable(napi_env env);
|
||||
static napi_value InitLayeredDrawable(napi_env env);
|
||||
static napi_value InitAnimatedDrawable(napi_env env);
|
||||
|
||||
static napi_value Constructor(napi_env env, napi_callback_info info);
|
||||
static void Destructor(napi_env env, void* nativeObject, void* finalize);
|
||||
static napi_value AnimatedConstructor(napi_env env, napi_callback_info info);
|
||||
|
||||
// methods
|
||||
static napi_value GetPixelMap(napi_env env, napi_callback_info info);
|
||||
@ -47,6 +49,7 @@ private:
|
||||
|
||||
static thread_local napi_ref baseConstructor_;
|
||||
static thread_local napi_ref layeredConstructor_;
|
||||
static thread_local napi_ref animatedConstructor_;
|
||||
};
|
||||
} // namespace OHOS::Ace::Napi
|
||||
#endif // INTERFACES_INNER_API_DRAWABLE_DESCRIPTOR_JS_DRAWABLE_DESCRIPTOR_H_
|
||||
|
Loading…
Reference in New Issue
Block a user