Skip to content

Commit 86a44e8

Browse files
authored
Merge pull request #62 from r-ralph/fix-misc
Fix internal API usage and update comment
2 parents 16df0c4 + 209b320 commit 86a44e8

File tree

4 files changed

+39
-32
lines changed

4 files changed

+39
-32
lines changed

apng-drawable/src/main/cpp/apng-drawbale/ApngDecoderJni.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static jfieldID gResult_repeatCountFieldID;
4141
static jfieldID gResult_frameDurationsFieldID;
4242
static jfieldID gResult_allFrameByteCountFieldID;
4343

44-
bool copyFrameDurations(JNIEnv *env,
44+
void copyFrameDurations(JNIEnv *env,
4545
const std::shared_ptr<ApngImage> &image,
4646
jintArray &frame_durations_ptr);
4747

@@ -281,22 +281,19 @@ Java_com_linecorp_apng_decoder_ApngDecoderJni_copy(
281281
#pragma clang diagnostic pop
282282
}
283283

284-
bool copyFrameDurations(JNIEnv *env,
284+
void copyFrameDurations(JNIEnv *env,
285285
const std::shared_ptr<ApngImage> &image,
286286
jintArray &frame_durations_ptr) {
287287
uint32_t frame_count = image->getFrameCount();
288288
jint *frame_durations_array = env->GetIntArrayElements(frame_durations_ptr, nullptr);
289-
bool isSuccess = true;
290289
for (uint32_t i = 0; i < frame_count; ++i) {
291290
std::shared_ptr<ApngFrame> frame = image->getFrame(i);
292291
if (!frame) {
293-
isSuccess = false;
294292
break;
295293
}
296294
frame_durations_array[i] = frame->getDuration();
297295
}
298296
env->ReleaseIntArrayElements(frame_durations_ptr, frame_durations_array, 0);
299-
return isSuccess;
300297
}
301298

302299
}

apng-drawable/src/main/cpp/apng-drawbale/ApngImage.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,5 @@ void ApngImage::setFrame(const uint32_t index, std::unique_ptr<ApngFrame> frame)
4343
}
4444
mFrames[index] = std::move(frame);
4545
}
46-
47-
uint32_t ApngImage::getTotalDuration() const {
48-
uint32_t totalDuration = 0;
49-
for (uint32_t i = 0; i < mFrameCount; i++) {
50-
totalDuration += mFrames[i]->getDuration();
51-
}
52-
return totalDuration;
53-
}
5446
}
5547

apng-drawable/src/main/cpp/apng-drawbale/ApngImage.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ class ApngImage {
2929
ApngImage() = delete;
3030
uint32_t getWidth() const { return mWidth; }
3131
uint32_t getHeight() const { return mHeight; }
32-
uint32_t getTotalDuration() const;
3332
uint32_t getRepeatCount() const { return mLoopCount; }
3433
uint32_t getFrameCount() const { return mFrameCount; }
3534
uint32_t getFrameByteCount() const { return sizeof(uint32_t) * mWidth * mHeight; }

apng-drawable/src/main/kotlin/com/linecorp/apng/ApngDrawable.kt

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,8 @@ class ApngDrawable @VisibleForTesting internal constructor(
9393
@IntRange(from = LOOP_INTRINSIC.toLong(), to = Int.MAX_VALUE.toLong())
9494
var loopCount: Int = apngState.apng.loopCount
9595
set(value) {
96-
if (value < LOOP_INTRINSIC) {
97-
throw IllegalArgumentException(
98-
"`loopCount` must be a signed value or special values. (value = $value)"
99-
)
96+
require(value >= LOOP_INTRINSIC) {
97+
"`loopCount` must be a signed value or special values. (value = $value)"
10098
}
10199
field = if (value == LOOP_INTRINSIC) apngState.apng.loopCount else value
102100
}
@@ -115,22 +113,14 @@ class ApngDrawable @VisibleForTesting internal constructor(
115113
if (currentRepeatCountInternal > loopCount) loopCount else currentRepeatCountInternal
116114

117115
/**
118-
* [currentFrameIndex] is the index to indicate which frame should show at that time.
119-
* [currentFrameIndex] is calculated with APNG meta data and elapsed time after animation
120-
* started.
121-
* [durationMillis] is the duration to animate one loop of APNG animation. [frameCount]
122-
* is number of APNG frames. For example, if one loop duration is 1000ms, image count is 10 and
123-
* elapsed time is 2100ms, the frame index should be 1 of 3rd loop.
124-
* If this image isn't infinite looping image and [animationElapsedTimeMillis] is larger than
125-
* total duration of this image's animation, returns always last frame index.
116+
* The corresponding frame index with the elapsed time of the animation. This value indicates
117+
* the last frame after the animation finished.
126118
*/
127119
val currentFrameIndex: Int
128-
get() = if (loopCount != LOOP_FOREVER && exceedsRepeatCountLimitation()) {
129-
frameCount - 1
130-
} else {
131-
val durationInSingleLoop = animationElapsedTimeMillis % durationMillis
132-
val index = frameStartTimes.indexOfFirst { durationInSingleLoop < it } - 1
133-
if (index < 0) frameCount - 1 else index
120+
get() {
121+
var progressMillisInCurrentLoop = animationElapsedTimeMillis % durationMillis
122+
progressMillisInCurrentLoop += if (exceedsRepeatCountLimitation()) durationMillis else 0
123+
return calculateCurrentFrameIndex(0, frameCount - 1, progressMillisInCurrentLoop)
134124
}
135125

136126
private val currentRepeatCountInternal: Int
@@ -345,6 +335,35 @@ class ApngDrawable @VisibleForTesting internal constructor(
345335
bounds.set(0, 0, scaledWidth, scaledHeight)
346336
}
347337

338+
private tailrec fun calculateCurrentFrameIndex(
339+
lowerBoundIndex: Int,
340+
upperBoundIndex: Int,
341+
progressMillisInCurrentLoop: Long
342+
): Int {
343+
val middleIndex = (lowerBoundIndex + upperBoundIndex) / 2
344+
return when {
345+
// Continue searching in the upper half
346+
frameStartTimes.size > middleIndex + 1 &&
347+
progressMillisInCurrentLoop >= frameStartTimes[middleIndex + 1] ->
348+
calculateCurrentFrameIndex(
349+
middleIndex + 1,
350+
upperBoundIndex,
351+
progressMillisInCurrentLoop
352+
)
353+
354+
// Continue searching in the lower half
355+
lowerBoundIndex != upperBoundIndex &&
356+
progressMillisInCurrentLoop < frameStartTimes[middleIndex] ->
357+
calculateCurrentFrameIndex(
358+
lowerBoundIndex,
359+
middleIndex,
360+
progressMillisInCurrentLoop
361+
)
362+
363+
else -> middleIndex
364+
}
365+
}
366+
348367
internal class ApngState(
349368
val apng: Apng,
350369
/**

0 commit comments

Comments
 (0)