|
1 | 1 | #pragma once |
2 | 2 |
|
| 3 | +#include <algorithm> |
| 4 | +#include <cmath> |
| 5 | +#include <limits> |
3 | 6 | #include <memory> |
4 | 7 | #include <string> |
5 | 8 | #include <utility> |
@@ -63,7 +66,72 @@ class JsiSkAnimatedImage |
63 | 66 | : JsiSkWrappingSkPtrHostObject<SkAnimatedImage>(std::move(context), |
64 | 67 | std::move(image)) {} |
65 | 68 |
|
66 | | - size_t getMemoryPressure() const override { return 8192; } |
| 69 | + size_t getMemoryPressure() const override { |
| 70 | + auto animation = getObject(); |
| 71 | + if (!animation) { |
| 72 | + return 0; |
| 73 | + } |
| 74 | + |
| 75 | + const auto safeMul = [](size_t a, size_t b) { |
| 76 | + if (a == 0 || b == 0) { |
| 77 | + return static_cast<size_t>(0); |
| 78 | + } |
| 79 | + if (std::numeric_limits<size_t>::max() / a < b) { |
| 80 | + return std::numeric_limits<size_t>::max(); |
| 81 | + } |
| 82 | + return a * b; |
| 83 | + }; |
| 84 | + |
| 85 | + const auto safeAdd = [](size_t a, size_t b) { |
| 86 | + if (std::numeric_limits<size_t>::max() - a < b) { |
| 87 | + return std::numeric_limits<size_t>::max(); |
| 88 | + } |
| 89 | + return a + b; |
| 90 | + }; |
| 91 | + |
| 92 | + SkRect bounds = animation->getBounds(); |
| 93 | + auto width = std::max<SkScalar>(0, bounds.width()); |
| 94 | + auto height = std::max<SkScalar>(0, bounds.height()); |
| 95 | + size_t frameWidth = |
| 96 | + static_cast<size_t>(std::ceil(static_cast<double>(width))); |
| 97 | + size_t frameHeight = |
| 98 | + static_cast<size_t>(std::ceil(static_cast<double>(height))); |
| 99 | + |
| 100 | + size_t frameBytes = safeMul(safeMul(frameWidth, frameHeight), |
| 101 | + static_cast<size_t>(4)); // RGBA bytes |
| 102 | + if (frameBytes == 0) { |
| 103 | + if (auto frame = animation->getCurrentFrame()) { |
| 104 | + auto frameInfo = frame->imageInfo(); |
| 105 | + size_t bytesPerPixel = static_cast<size_t>(frameInfo.bytesPerPixel()); |
| 106 | + if (bytesPerPixel == 0) { |
| 107 | + bytesPerPixel = 4; |
| 108 | + } |
| 109 | + frameBytes = |
| 110 | + safeMul(safeMul(static_cast<size_t>(frame->width()), |
| 111 | + static_cast<size_t>(frame->height())), |
| 112 | + bytesPerPixel); |
| 113 | + } |
| 114 | + } |
| 115 | + |
| 116 | + if (frameBytes == 0) { |
| 117 | + return 0; |
| 118 | + } |
| 119 | + |
| 120 | + int frameCount = animation->getFrameCount(); |
| 121 | + if (frameCount <= 0) { |
| 122 | + frameCount = 1; |
| 123 | + } |
| 124 | + |
| 125 | + // Animated images keep display, decoding, and restore frames resident. |
| 126 | + size_t cachedFrames = |
| 127 | + static_cast<size_t>(std::min(frameCount, 3)); // triple buffering |
| 128 | + size_t estimated = safeMul(frameBytes, cachedFrames); |
| 129 | + |
| 130 | + // Include codec/metadata overhead. |
| 131 | + estimated = safeAdd(estimated, 256 * 1024); |
| 132 | + |
| 133 | + return estimated; |
| 134 | + } |
67 | 135 |
|
68 | 136 | std::string getObjectType() const override { return "JsiSkAnimatedImage"; } |
69 | 137 | }; |
|
0 commit comments