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:
yangziyong 2024-04-07 08:11:53 +08:00
parent 2c70fcd8ec
commit f4835c8ab4
24 changed files with 974 additions and 37 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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();

View File

@ -256,4 +256,9 @@ bool ImageModelImpl::UpdateDragItemInfo(DragItemInfo& itemInfo)
return true;
}
bool ImageModelImpl::GetIsAnimation()
{
return false;
}
} // namespace OHOS::Ace::Framework

View File

@ -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

View File

@ -26,6 +26,7 @@ namespace OHOS::Ace {
struct ImageProperties {
std::string src;
RefPtr<PixelMap> pixelMap;
std::string bundleName;
std::string moduleName;
CalcDimension width;

View File

@ -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_;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -137,6 +137,11 @@ public:
{
return nullptr;
}
std::shared_ptr<PixelMap>* GetPixelMap()
{
return nullptr;
}
};
} // namespace Media
} // namespace OHOS

View File

@ -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

View File

@ -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_