|
7 | 7 |
|
8 | 8 | #pragma once |
9 | 9 |
|
| 10 | +#include "configurePlatformColorCacheInvalidationHook.h" |
| 11 | + |
10 | 12 | #include <fbjni/fbjni.h> |
11 | | -#include <react/debug/react_native_expect.h> |
| 13 | +#include <folly/container/EvictingCacheMap.h> |
12 | 14 | #include <react/renderer/core/RawValue.h> |
13 | 15 | #include <react/renderer/graphics/Color.h> |
14 | 16 | #include <react/renderer/graphics/fromRawValueShared.h> |
15 | 17 | #include <react/utils/ContextContainer.h> |
| 18 | +#include <functional> |
| 19 | +#include <mutex> |
| 20 | +#include <string> |
16 | 21 | #include <unordered_map> |
| 22 | +#include <vector> |
17 | 23 |
|
18 | 24 | namespace facebook::react { |
19 | 25 |
|
| 26 | +inline size_t hashGetColourArguments( |
| 27 | + int32_t surfaceId, |
| 28 | + const std::vector<std::string>& resourcePaths) { |
| 29 | + size_t seed = std::hash<int32_t>{}(surfaceId); |
| 30 | + for (const auto& path : resourcePaths) { |
| 31 | + seed ^= |
| 32 | + std::hash<std::string>{}(path) + 0x9e3779b9 + (seed << 6) + (seed >> 2); |
| 33 | + } |
| 34 | + return seed; |
| 35 | +} |
| 36 | + |
20 | 37 | inline SharedColor parsePlatformColor( |
21 | 38 | const ContextContainer& contextContainer, |
22 | 39 | int32_t surfaceId, |
23 | 40 | const RawValue& value) { |
24 | | - ColorComponents colorComponents = {0, 0, 0, 0}; |
25 | | - |
| 41 | + Color color = 0; |
26 | 42 | if (value.hasType< |
27 | 43 | std::unordered_map<std::string, std::vector<std::string>>>()) { |
28 | | - const auto& fabricUIManager = |
29 | | - contextContainer.at<jni::global_ref<jobject>>("FabricUIManager"); |
30 | | - static auto getColorFromJava = |
31 | | - fabricUIManager->getClass() |
32 | | - ->getMethod<jint(jint, jni::JArrayClass<jni::JString>)>("getColor"); |
33 | | - |
34 | 44 | auto map = (std::unordered_map<std::string, std::vector<std::string>>)value; |
35 | 45 | auto& resourcePaths = map["resource_paths"]; |
36 | 46 |
|
37 | | - auto javaResourcePaths = |
38 | | - jni::JArrayClass<jni::JString>::newArray(resourcePaths.size()); |
39 | | - for (int i = 0; i < resourcePaths.size(); i++) { |
40 | | - javaResourcePaths->setElement(i, *jni::make_jstring(resourcePaths[i])); |
41 | | - } |
42 | | - auto color = |
43 | | - getColorFromJava(fabricUIManager, surfaceId, *javaResourcePaths); |
| 47 | + // JNI calls are time consuming. Let's cache results here to avoid |
| 48 | + // unnecessary calls. |
| 49 | + static std::mutex getColorCacheMutex; |
| 50 | + static folly::EvictingCacheMap<size_t, Color> getColorCache(64); |
| 51 | + |
| 52 | + // Listen for appearance changes, which should invalidate the cache |
| 53 | + static std::once_flag setupCacheInvalidation; |
| 54 | + std::call_once( |
| 55 | + setupCacheInvalidation, |
| 56 | + configurePlatformColorCacheInvalidationHook, |
| 57 | + [&] { |
| 58 | + std::scoped_lock lock(getColorCacheMutex); |
| 59 | + getColorCache.clear(); |
| 60 | + }); |
44 | 61 |
|
45 | | - auto argb = (int64_t)color; |
46 | | - auto ratio = 255.f; |
47 | | - colorComponents.alpha = ((argb >> 24) & 0xFF) / ratio; |
48 | | - colorComponents.red = ((argb >> 16) & 0xFF) / ratio; |
49 | | - colorComponents.green = ((argb >> 8) & 0xFF) / ratio; |
50 | | - colorComponents.blue = (argb & 0xFF) / ratio; |
| 62 | + auto hash = hashGetColourArguments(surfaceId, resourcePaths); |
| 63 | + { |
| 64 | + std::scoped_lock lock(getColorCacheMutex); |
| 65 | + auto iterator = getColorCache.find(hash); |
| 66 | + if (iterator != getColorCache.end()) { |
| 67 | + color = iterator->second; |
| 68 | + } else { |
| 69 | + const auto& fabricUIManager = |
| 70 | + contextContainer.at<jni::global_ref<jobject>>("FabricUIManager"); |
| 71 | + static auto getColorFromJava = |
| 72 | + fabricUIManager->getClass() |
| 73 | + ->getMethod<jint(jint, jni::JArrayClass<jni::JString>)>( |
| 74 | + "getColor"); |
| 75 | + auto javaResourcePaths = |
| 76 | + jni::JArrayClass<jni::JString>::newArray(resourcePaths.size()); |
| 77 | + |
| 78 | + for (int i = 0; i < resourcePaths.size(); i++) { |
| 79 | + javaResourcePaths->setElement( |
| 80 | + i, *jni::make_jstring(resourcePaths[i])); |
| 81 | + } |
| 82 | + color = |
| 83 | + getColorFromJava(fabricUIManager, surfaceId, *javaResourcePaths); |
| 84 | + getColorCache.set(hash, color); |
| 85 | + } |
| 86 | + } |
51 | 87 | } |
52 | 88 |
|
53 | | - return {colorFromComponents(colorComponents)}; |
| 89 | + return color; |
54 | 90 | } |
55 | 91 |
|
56 | 92 | inline void fromRawValue( |
|
0 commit comments