react-native-pdf-jsi 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/DoubleTapView.js +125 -0
  2. package/INTEGRATION_GUIDE.md +419 -0
  3. package/LICENSE +21 -0
  4. package/PdfManager.js +26 -0
  5. package/PdfPageView.js +53 -0
  6. package/PdfView.js +421 -0
  7. package/PdfViewFlatList.js +30 -0
  8. package/PinchZoomView.js +125 -0
  9. package/README.md +693 -0
  10. package/README_JSI.md +348 -0
  11. package/android/.gradle/5.6.1/fileChanges/last-build.bin +0 -0
  12. package/android/.gradle/5.6.1/fileHashes/fileHashes.lock +0 -0
  13. package/android/.gradle/5.6.1/gc.properties +0 -0
  14. package/android/.gradle/8.5/checksums/checksums.lock +0 -0
  15. package/android/.gradle/8.5/checksums/md5-checksums.bin +0 -0
  16. package/android/.gradle/8.5/checksums/sha1-checksums.bin +0 -0
  17. package/android/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock +0 -0
  18. package/android/.gradle/8.5/dependencies-accessors/gc.properties +0 -0
  19. package/android/.gradle/8.5/executionHistory/executionHistory.lock +0 -0
  20. package/android/.gradle/8.5/fileChanges/last-build.bin +0 -0
  21. package/android/.gradle/8.5/fileHashes/fileHashes.lock +0 -0
  22. package/android/.gradle/8.5/gc.properties +0 -0
  23. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  24. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  25. package/android/.gradle/vcs-1/gc.properties +0 -0
  26. package/android/build.gradle +198 -0
  27. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  28. package/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  29. package/android/gradle.properties +2 -0
  30. package/android/gradlew +249 -0
  31. package/android/gradlew.bat +92 -0
  32. package/android/project.properties +12 -0
  33. package/android/src/main/AndroidManifest.xml +4 -0
  34. package/android/src/main/cpp/Android.mk +50 -0
  35. package/android/src/main/cpp/CMakeLists.txt +76 -0
  36. package/android/src/main/cpp/PDFJSI.cpp +190 -0
  37. package/android/src/main/cpp/PDFJSI.h +95 -0
  38. package/android/src/main/cpp/PDFJSIBridge.cpp +32 -0
  39. package/android/src/main/cpp/PDFJSIModule.cpp +31 -0
  40. package/android/src/main/java/org/wonday/pdf/EnhancedPdfJSIBridge.java +281 -0
  41. package/android/src/main/java/org/wonday/pdf/PDFJSIManager.java +317 -0
  42. package/android/src/main/java/org/wonday/pdf/PDFJSIModule.java +189 -0
  43. package/android/src/main/java/org/wonday/pdf/PdfManager.java +180 -0
  44. package/android/src/main/java/org/wonday/pdf/PdfView.java +505 -0
  45. package/android/src/main/java/org/wonday/pdf/RNPDFPackage.java +43 -0
  46. package/android/src/main/java/org/wonday/pdf/events/TopChangeEvent.java +26 -0
  47. package/android/src/main/jniLibs/arm64-v8a/libpdfjsi.so +0 -0
  48. package/android/src/main/jniLibs/armeabi-v7a/libpdfjsi.so +0 -0
  49. package/android/src/main/jniLibs/x86/libpdfjsi.so +0 -0
  50. package/android/src/main/jniLibs/x86_64/libpdfjsi.so +0 -0
  51. package/android/src/paper/java/com/facebook/react/viewmanagers/RNPDFPdfViewManagerDelegate.java +92 -0
  52. package/android/src/paper/java/com/facebook/react/viewmanagers/RNPDFPdfViewManagerInterface.java +35 -0
  53. package/fabric/RNPDFPdfNativeComponent.js +48 -0
  54. package/index.d.ts +72 -0
  55. package/index.js +603 -0
  56. package/index.js.flow +67 -0
  57. package/ios/RNPDFPdf/PdfManager.h +23 -0
  58. package/ios/RNPDFPdf/PdfManager.mm +152 -0
  59. package/ios/RNPDFPdf/RNPDFPdfPageView.h +21 -0
  60. package/ios/RNPDFPdf/RNPDFPdfPageView.mm +185 -0
  61. package/ios/RNPDFPdf/RNPDFPdfPageViewManager.h +18 -0
  62. package/ios/RNPDFPdf/RNPDFPdfPageViewManager.mm +30 -0
  63. package/ios/RNPDFPdf/RNPDFPdfView.h +63 -0
  64. package/ios/RNPDFPdf/RNPDFPdfView.mm +1092 -0
  65. package/ios/RNPDFPdf/RNPDFPdfViewManager.h +18 -0
  66. package/ios/RNPDFPdf/RNPDFPdfViewManager.mm +68 -0
  67. package/ios/RNPDFPdf.xcodeproj/project.pbxproj +321 -0
  68. package/package.json +78 -0
  69. package/react-native-pdf.podspec +31 -0
  70. package/src/EnhancedPdfView.js +362 -0
  71. package/src/PDFJSI.js +519 -0
  72. package/src/examples/PDFJSIExample.js +296 -0
  73. package/src/hooks/usePDFJSI.js +346 -0
  74. package/src/index.js +32 -0
  75. package/windows/RCTPdf/PropertySheet.props +16 -0
  76. package/windows/RCTPdf/RCTPdf.def +3 -0
  77. package/windows/RCTPdf/RCTPdf.vcxproj +180 -0
  78. package/windows/RCTPdf/RCTPdf.vcxproj.filters +38 -0
  79. package/windows/RCTPdf/RCTPdfControl.cpp +667 -0
  80. package/windows/RCTPdf/RCTPdfControl.h +119 -0
  81. package/windows/RCTPdf/RCTPdfControl.idl +10 -0
  82. package/windows/RCTPdf/RCTPdfControl.xaml +33 -0
  83. package/windows/RCTPdf/RCTPdfViewManager.cpp +69 -0
  84. package/windows/RCTPdf/RCTPdfViewManager.h +51 -0
  85. package/windows/RCTPdf/ReactPackageProvider.cpp +15 -0
  86. package/windows/RCTPdf/ReactPackageProvider.h +16 -0
  87. package/windows/RCTPdf/ReactPackageProvider.idl +9 -0
  88. package/windows/RCTPdf/packages.config +4 -0
  89. package/windows/RCTPdf/pch.cpp +1 -0
  90. package/windows/RCTPdf/pch.h +31 -0
  91. package/windows/README.md +21 -0
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Copyright (c) 2025-present, Punith M (punithm300@gmail.com)
3
+ * Enhanced PDF JSI Manager with high-performance operations
4
+ * All rights reserved.
5
+ *
6
+ * JSI Manager for high-performance PDF operations
7
+ * Provides React Native bridge integration for JSI PDF functions
8
+ */
9
+
10
+ package org.wonday.pdf;
11
+
12
+ import android.util.Log;
13
+
14
+ import com.facebook.react.bridge.ReactApplicationContext;
15
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
16
+ import com.facebook.react.bridge.ReactMethod;
17
+ import com.facebook.react.bridge.Promise;
18
+ import com.facebook.react.bridge.ReadableMap;
19
+ import com.facebook.react.bridge.ReadableArray;
20
+ import com.facebook.react.bridge.WritableMap;
21
+ import com.facebook.react.bridge.Arguments;
22
+
23
+ // import com.facebook.react.turbomodule.core.CallInvokerHolder; // Not available in this RN version
24
+ import com.facebook.soloader.SoLoader;
25
+
26
+ import java.util.concurrent.ExecutorService;
27
+ import java.util.concurrent.Executors;
28
+
29
+ public class PDFJSIManager extends ReactContextBaseJavaModule {
30
+ private static final String MODULE_NAME = "PDFJSIManager";
31
+ private static final String TAG = "PDFJSI";
32
+
33
+ private ExecutorService backgroundExecutor;
34
+ private boolean isJSIInitialized = false;
35
+
36
+ // Load native library
37
+ static {
38
+ try {
39
+ SoLoader.loadLibrary("pdfjsi");
40
+ Log.d(TAG, "PDF JSI native library loaded successfully");
41
+ } catch (UnsatisfiedLinkError e) {
42
+ Log.e(TAG, "Failed to load PDF JSI native library", e);
43
+ }
44
+ }
45
+
46
+ public PDFJSIManager(ReactApplicationContext reactContext) {
47
+ super(reactContext);
48
+ this.backgroundExecutor = Executors.newFixedThreadPool(2);
49
+
50
+ Log.d(TAG, "PDFJSIManager: Initializing high-performance PDF JSI manager");
51
+ initializeJSI(reactContext);
52
+ }
53
+
54
+ @Override
55
+ public String getName() {
56
+ return MODULE_NAME;
57
+ }
58
+
59
+ /**
60
+ * Initialize JSI integration
61
+ */
62
+ private void initializeJSI(ReactApplicationContext reactContext) {
63
+ try {
64
+ // Initialize JSI on background thread
65
+ backgroundExecutor.execute(() -> {
66
+ try {
67
+ // Initialize JSI module without CallInvokerHolder (fallback mode)
68
+ nativeInitializeJSI(null);
69
+ isJSIInitialized = true;
70
+ Log.d(TAG, "PDF JSI initialized successfully (fallback mode)");
71
+ } catch (Exception e) {
72
+ Log.e(TAG, "Failed to initialize PDF JSI", e);
73
+ }
74
+ });
75
+ } catch (Exception e) {
76
+ Log.e(TAG, "Error initializing PDF JSI", e);
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Check if JSI is available and initialized
82
+ */
83
+ @ReactMethod
84
+ public void isJSIAvailable(Promise promise) {
85
+ try {
86
+ boolean available = isJSIInitialized && nativeIsJSIAvailable();
87
+ Log.d(TAG, "JSI Availability check: " + available);
88
+ promise.resolve(available);
89
+ } catch (Exception e) {
90
+ Log.e(TAG, "Error checking JSI availability", e);
91
+ promise.reject("JSI_CHECK_ERROR", e.getMessage());
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Render page directly via JSI (high-performance)
97
+ */
98
+ @ReactMethod
99
+ public void renderPageDirect(String pdfId, int pageNumber, double scale, String base64Data, Promise promise) {
100
+ if (!isJSIInitialized) {
101
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
102
+ return;
103
+ }
104
+
105
+ backgroundExecutor.execute(() -> {
106
+ try {
107
+ Log.d(TAG, "Rendering page " + pageNumber + " via JSI for PDF " + pdfId);
108
+ WritableMap result = nativeRenderPageDirect(pdfId, pageNumber, (float) scale, base64Data);
109
+ promise.resolve(result);
110
+ } catch (Exception e) {
111
+ Log.e(TAG, "Error rendering page via JSI", e);
112
+ promise.reject("RENDER_ERROR", e.getMessage());
113
+ }
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Get page metrics via JSI
119
+ */
120
+ @ReactMethod
121
+ public void getPageMetrics(String pdfId, int pageNumber, Promise promise) {
122
+ if (!isJSIInitialized) {
123
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
124
+ return;
125
+ }
126
+
127
+ try {
128
+ Log.d(TAG, "Getting page metrics via JSI for page " + pageNumber);
129
+ WritableMap metrics = nativeGetPageMetrics(pdfId, pageNumber);
130
+ promise.resolve(metrics);
131
+ } catch (Exception e) {
132
+ Log.e(TAG, "Error getting page metrics via JSI", e);
133
+ promise.reject("METRICS_ERROR", e.getMessage());
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Preload pages directly via JSI
139
+ */
140
+ @ReactMethod
141
+ public void preloadPagesDirect(String pdfId, int startPage, int endPage, Promise promise) {
142
+ if (!isJSIInitialized) {
143
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
144
+ return;
145
+ }
146
+
147
+ backgroundExecutor.execute(() -> {
148
+ try {
149
+ Log.d(TAG, "Preloading pages " + startPage + "-" + endPage + " via JSI");
150
+ boolean success = nativePreloadPagesDirect(pdfId, startPage, endPage);
151
+ promise.resolve(success);
152
+ } catch (Exception e) {
153
+ Log.e(TAG, "Error preloading pages via JSI", e);
154
+ promise.reject("PRELOAD_ERROR", e.getMessage());
155
+ }
156
+ });
157
+ }
158
+
159
+ /**
160
+ * Get cache metrics via JSI
161
+ */
162
+ @ReactMethod
163
+ public void getCacheMetrics(String pdfId, Promise promise) {
164
+ if (!isJSIInitialized) {
165
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
166
+ return;
167
+ }
168
+
169
+ try {
170
+ Log.d(TAG, "Getting cache metrics via JSI for PDF " + pdfId);
171
+ WritableMap metrics = nativeGetCacheMetrics(pdfId);
172
+ promise.resolve(metrics);
173
+ } catch (Exception e) {
174
+ Log.e(TAG, "Error getting cache metrics via JSI", e);
175
+ promise.reject("CACHE_METRICS_ERROR", e.getMessage());
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Clear cache directly via JSI
181
+ */
182
+ @ReactMethod
183
+ public void clearCacheDirect(String pdfId, String cacheType, Promise promise) {
184
+ if (!isJSIInitialized) {
185
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
186
+ return;
187
+ }
188
+
189
+ backgroundExecutor.execute(() -> {
190
+ try {
191
+ Log.d(TAG, "Clearing cache via JSI for PDF " + pdfId + ", type: " + cacheType);
192
+ boolean success = nativeClearCacheDirect(pdfId, cacheType);
193
+ promise.resolve(success);
194
+ } catch (Exception e) {
195
+ Log.e(TAG, "Error clearing cache via JSI", e);
196
+ promise.reject("CLEAR_CACHE_ERROR", e.getMessage());
197
+ }
198
+ });
199
+ }
200
+
201
+ /**
202
+ * Optimize memory via JSI
203
+ */
204
+ @ReactMethod
205
+ public void optimizeMemory(String pdfId, Promise promise) {
206
+ if (!isJSIInitialized) {
207
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
208
+ return;
209
+ }
210
+
211
+ backgroundExecutor.execute(() -> {
212
+ try {
213
+ Log.d(TAG, "Optimizing memory via JSI for PDF " + pdfId);
214
+ boolean success = nativeOptimizeMemory(pdfId);
215
+ promise.resolve(success);
216
+ } catch (Exception e) {
217
+ Log.e(TAG, "Error optimizing memory via JSI", e);
218
+ promise.reject("OPTIMIZE_MEMORY_ERROR", e.getMessage());
219
+ }
220
+ });
221
+ }
222
+
223
+ /**
224
+ * Search text directly via JSI
225
+ */
226
+ @ReactMethod
227
+ public void searchTextDirect(String pdfId, String searchTerm, int startPage, int endPage, Promise promise) {
228
+ if (!isJSIInitialized) {
229
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
230
+ return;
231
+ }
232
+
233
+ backgroundExecutor.execute(() -> {
234
+ try {
235
+ Log.d(TAG, "Searching text via JSI: '" + searchTerm + "' in pages " + startPage + "-" + endPage);
236
+ ReadableArray results = nativeSearchTextDirect(pdfId, searchTerm, startPage, endPage);
237
+ promise.resolve(results);
238
+ } catch (Exception e) {
239
+ Log.e(TAG, "Error searching text via JSI", e);
240
+ promise.reject("SEARCH_ERROR", e.getMessage());
241
+ }
242
+ });
243
+ }
244
+
245
+ /**
246
+ * Get performance metrics via JSI
247
+ */
248
+ @ReactMethod
249
+ public void getPerformanceMetrics(String pdfId, Promise promise) {
250
+ if (!isJSIInitialized) {
251
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
252
+ return;
253
+ }
254
+
255
+ try {
256
+ Log.d(TAG, "Getting performance metrics via JSI for PDF " + pdfId);
257
+ WritableMap metrics = nativeGetPerformanceMetrics(pdfId);
258
+ promise.resolve(metrics);
259
+ } catch (Exception e) {
260
+ Log.e(TAG, "Error getting performance metrics via JSI", e);
261
+ promise.reject("PERFORMANCE_METRICS_ERROR", e.getMessage());
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Set render quality via JSI
267
+ */
268
+ @ReactMethod
269
+ public void setRenderQuality(String pdfId, int quality, Promise promise) {
270
+ if (!isJSIInitialized) {
271
+ promise.reject("JSI_NOT_INITIALIZED", "JSI is not initialized");
272
+ return;
273
+ }
274
+
275
+ try {
276
+ Log.d(TAG, "Setting render quality via JSI to " + quality + " for PDF " + pdfId);
277
+ boolean success = nativeSetRenderQuality(pdfId, quality);
278
+ promise.resolve(success);
279
+ } catch (Exception e) {
280
+ Log.e(TAG, "Error setting render quality via JSI", e);
281
+ promise.reject("SET_RENDER_QUALITY_ERROR", e.getMessage());
282
+ }
283
+ }
284
+
285
+ /**
286
+ * Cleanup resources
287
+ */
288
+ // Note: onCatalystInstanceDestroy is deprecated, using onCatalystInstanceDestroy for compatibility
289
+ @Override
290
+ public void onCatalystInstanceDestroy() {
291
+ super.onCatalystInstanceDestroy();
292
+
293
+ if (backgroundExecutor != null && !backgroundExecutor.isShutdown()) {
294
+ backgroundExecutor.shutdown();
295
+ }
296
+
297
+ if (isJSIInitialized) {
298
+ nativeCleanupJSI();
299
+ }
300
+
301
+ Log.d(TAG, "PDFJSIManager: Cleaned up resources");
302
+ }
303
+
304
+ // Native method declarations
305
+ private native void nativeInitializeJSI(Object callInvokerHolder);
306
+ private native boolean nativeIsJSIAvailable();
307
+ private native WritableMap nativeRenderPageDirect(String pdfId, int pageNumber, float scale, String base64Data);
308
+ private native WritableMap nativeGetPageMetrics(String pdfId, int pageNumber);
309
+ private native boolean nativePreloadPagesDirect(String pdfId, int startPage, int endPage);
310
+ private native WritableMap nativeGetCacheMetrics(String pdfId);
311
+ private native boolean nativeClearCacheDirect(String pdfId, String cacheType);
312
+ private native boolean nativeOptimizeMemory(String pdfId);
313
+ private native ReadableArray nativeSearchTextDirect(String pdfId, String searchTerm, int startPage, int endPage);
314
+ private native WritableMap nativeGetPerformanceMetrics(String pdfId);
315
+ private native boolean nativeSetRenderQuality(String pdfId, int quality);
316
+ private native void nativeCleanupJSI();
317
+ }
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Copyright (c) 2025-present, Punith M (punithm300@gmail.com)
3
+ * Enhanced PDF JSI Module with high-performance operations
4
+ * All rights reserved.
5
+ *
6
+ * React Native module for JSI PDF operations
7
+ * Provides high-performance PDF operations via JSI
8
+ */
9
+
10
+ package org.wonday.pdf;
11
+
12
+ import android.util.Log;
13
+
14
+ import com.facebook.react.bridge.ReactApplicationContext;
15
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
16
+ import com.facebook.react.bridge.ReactMethod;
17
+ import com.facebook.react.bridge.Promise;
18
+ import com.facebook.react.bridge.ReadableMap;
19
+ import com.facebook.react.bridge.WritableMap;
20
+ import com.facebook.react.bridge.Arguments;
21
+
22
+ // import com.facebook.react.turbomodule.core.CallInvokerHolder; // Not available in this RN version
23
+ import com.facebook.soloader.SoLoader;
24
+
25
+ import java.util.concurrent.ExecutorService;
26
+ import java.util.concurrent.Executors;
27
+
28
+ public class PDFJSIModule extends ReactContextBaseJavaModule {
29
+ private static final String MODULE_NAME = "PDFJSIModule";
30
+ private static final String TAG = "PDFJSIModule";
31
+
32
+ private ExecutorService backgroundExecutor;
33
+ private boolean isJSIInitialized = false;
34
+
35
+ // Load native library
36
+ static {
37
+ try {
38
+ SoLoader.loadLibrary("pdfjsi");
39
+ Log.d(TAG, "PDF JSI native library loaded successfully");
40
+ } catch (UnsatisfiedLinkError e) {
41
+ Log.e(TAG, "Failed to load PDF JSI native library", e);
42
+ }
43
+ }
44
+
45
+ public PDFJSIModule(ReactApplicationContext reactContext) {
46
+ super(reactContext);
47
+ this.backgroundExecutor = Executors.newFixedThreadPool(2);
48
+
49
+ Log.d(TAG, "PDFJSIModule: Initializing high-performance PDF JSI module");
50
+ initializeJSI(reactContext);
51
+ }
52
+
53
+ @Override
54
+ public String getName() {
55
+ return MODULE_NAME;
56
+ }
57
+
58
+ /**
59
+ * Initialize JSI integration
60
+ */
61
+ private void initializeJSI(ReactApplicationContext reactContext) {
62
+ try {
63
+ // Initialize JSI on background thread
64
+ backgroundExecutor.execute(() -> {
65
+ try {
66
+ // Initialize JSI module without CallInvokerHolder (fallback mode)
67
+ nativeInitializeJSI(null);
68
+ isJSIInitialized = true;
69
+ Log.d(TAG, "PDF JSI initialized successfully (fallback mode)");
70
+ } catch (Exception e) {
71
+ Log.e(TAG, "Failed to initialize PDF JSI", e);
72
+ }
73
+ });
74
+ } catch (Exception e) {
75
+ Log.e(TAG, "Error initializing PDF JSI", e);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Check if JSI is available and initialized
81
+ */
82
+ @ReactMethod
83
+ public void isJSIAvailable(Promise promise) {
84
+ try {
85
+ boolean available = isJSIInitialized && nativeIsJSIAvailable();
86
+ Log.d(TAG, "JSI Availability check: " + available);
87
+ promise.resolve(available);
88
+ } catch (Exception e) {
89
+ Log.e(TAG, "Error checking JSI availability", e);
90
+ promise.reject("JSI_CHECK_ERROR", e.getMessage());
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Get JSI performance statistics
96
+ */
97
+ @ReactMethod
98
+ public void getJSIStats(Promise promise) {
99
+ try {
100
+ Log.d(TAG, "Getting JSI stats");
101
+
102
+ WritableMap stats = Arguments.createMap();
103
+ stats.putString("version", "1.0.0");
104
+ stats.putString("buildDate", "2025-01-01");
105
+ stats.putBoolean("jsiEnabled", true);
106
+ stats.putBoolean("bridgeOptimized", true);
107
+ stats.putBoolean("directMemoryAccess", true);
108
+ stats.putInt("availableMethods", 9);
109
+ stats.putString("performanceLevel", "HIGH");
110
+ stats.putBoolean("isInitialized", isJSIInitialized);
111
+
112
+ promise.resolve(stats);
113
+
114
+ } catch (Exception e) {
115
+ Log.e(TAG, "Error getting JSI stats", e);
116
+ promise.reject("GET_JSI_STATS_ERROR", e.getMessage());
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Initialize JSI with custom configuration
122
+ */
123
+ @ReactMethod
124
+ public void initializeJSIConfig(ReadableMap config, Promise promise) {
125
+ try {
126
+ Log.d(TAG, "Initializing JSI with custom configuration");
127
+
128
+ boolean enablePerformanceTracking = config.getBoolean("enablePerformanceTracking");
129
+ boolean enableCaching = config.getBoolean("enableCaching");
130
+ int maxCacheSize = config.getInt("maxCacheSize");
131
+
132
+ boolean success = nativeInitializeJSIConfig(enablePerformanceTracking, enableCaching, maxCacheSize);
133
+
134
+ WritableMap result = Arguments.createMap();
135
+ result.putBoolean("success", success);
136
+ result.putBoolean("jsiEnabled", success);
137
+ result.putString("message", success ? "JSI configured successfully" : "Failed to configure JSI");
138
+
139
+ promise.resolve(result);
140
+
141
+ } catch (Exception e) {
142
+ Log.e(TAG, "Error initializing JSI config", e);
143
+ promise.reject("JSI_CONFIG_ERROR", e.getMessage());
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Get memory usage statistics
149
+ */
150
+ @ReactMethod
151
+ public void getMemoryStats(Promise promise) {
152
+ try {
153
+ Log.d(TAG, "Getting memory statistics");
154
+
155
+ WritableMap stats = nativeGetMemoryStats();
156
+ promise.resolve(stats);
157
+
158
+ } catch (Exception e) {
159
+ Log.e(TAG, "Error getting memory stats", e);
160
+ promise.reject("MEMORY_STATS_ERROR", e.getMessage());
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Cleanup resources
166
+ */
167
+ // Note: onCatalystInstanceDestroy is deprecated, using onCatalystInstanceDestroy for compatibility
168
+ @Override
169
+ public void onCatalystInstanceDestroy() {
170
+ super.onCatalystInstanceDestroy();
171
+
172
+ if (backgroundExecutor != null && !backgroundExecutor.isShutdown()) {
173
+ backgroundExecutor.shutdown();
174
+ }
175
+
176
+ if (isJSIInitialized) {
177
+ nativeCleanupJSI();
178
+ }
179
+
180
+ Log.d(TAG, "PDFJSIModule: Cleaned up resources");
181
+ }
182
+
183
+ // Native method declarations
184
+ private native void nativeInitializeJSI(Object callInvokerHolder);
185
+ private native boolean nativeIsJSIAvailable();
186
+ private native boolean nativeInitializeJSIConfig(boolean enablePerformanceTracking, boolean enableCaching, int maxCacheSize);
187
+ private native WritableMap nativeGetMemoryStats();
188
+ private native void nativeCleanupJSI();
189
+ }
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Copyright (c) 2017-present, Wonday (@wonday.org)
3
+ * All rights reserved.
4
+ *
5
+ * This source code is licensed under the MIT-style license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ package org.wonday.pdf;
10
+
11
+ import android.content.Context;
12
+
13
+ import androidx.annotation.NonNull;
14
+ import androidx.annotation.Nullable;
15
+
16
+ import com.facebook.infer.annotation.Assertions;
17
+ import com.facebook.react.bridge.ReactApplicationContext;
18
+ import com.facebook.react.bridge.ReadableArray;
19
+ import com.facebook.react.module.annotations.ReactModule;
20
+ import com.facebook.react.uimanager.SimpleViewManager;
21
+ import com.facebook.react.uimanager.ThemedReactContext;
22
+ import com.facebook.react.uimanager.annotations.ReactProp;
23
+
24
+ import com.facebook.react.uimanager.ViewManagerDelegate;
25
+ import com.facebook.react.viewmanagers.RNPDFPdfViewManagerDelegate;
26
+ import com.facebook.react.viewmanagers.RNPDFPdfViewManagerInterface;
27
+
28
+ @ReactModule(name = PdfManager.REACT_CLASS)
29
+ public class PdfManager extends SimpleViewManager<PdfView> implements RNPDFPdfViewManagerInterface<PdfView> {
30
+ public static final String REACT_CLASS = "RNPDFPdfView";
31
+ private Context context;
32
+ private PdfView pdfView;
33
+ private final ViewManagerDelegate<PdfView> mDelegate;
34
+
35
+ @Nullable
36
+ @Override
37
+ protected ViewManagerDelegate<PdfView> getDelegate() {
38
+ return mDelegate;
39
+ }
40
+
41
+ public PdfManager() {
42
+ mDelegate = new RNPDFPdfViewManagerDelegate<>(this);
43
+ }
44
+
45
+ public PdfManager(ReactApplicationContext reactContext){
46
+ this.context = reactContext;
47
+ mDelegate = new RNPDFPdfViewManagerDelegate<>(this);
48
+ }
49
+
50
+ @Override
51
+ public String getName() {
52
+ return REACT_CLASS;
53
+ }
54
+
55
+ @Override
56
+ public PdfView createViewInstance(ThemedReactContext context) {
57
+ this.pdfView = new PdfView(context,null);
58
+ return pdfView;
59
+ }
60
+
61
+ @Override
62
+ public void onDropViewInstance(PdfView pdfView) {
63
+ pdfView = null;
64
+ }
65
+
66
+ @ReactProp(name = "path")
67
+ public void setPath(PdfView pdfView, String path) {
68
+ pdfView.setPath(path);
69
+ }
70
+
71
+ // page start from 1
72
+ @ReactProp(name = "page")
73
+ public void setPage(PdfView pdfView, int page) {
74
+ pdfView.setPage(page);
75
+ }
76
+
77
+ @ReactProp(name = "scale")
78
+ public void setScale(PdfView pdfView, float scale) {
79
+ pdfView.setScale(scale);
80
+ }
81
+
82
+ @ReactProp(name = "minScale")
83
+ public void setMinScale(PdfView pdfView, float minScale) {
84
+ pdfView.setMinScale(minScale);
85
+ }
86
+
87
+ @ReactProp(name = "maxScale")
88
+ public void setMaxScale(PdfView pdfView, float maxScale) {
89
+ pdfView.setMaxScale(maxScale);
90
+ }
91
+
92
+ @ReactProp(name = "horizontal")
93
+ public void setHorizontal(PdfView pdfView, boolean horizontal) {
94
+ pdfView.setHorizontal(horizontal);
95
+ }
96
+
97
+ @Override
98
+ public void setShowsHorizontalScrollIndicator(PdfView view, boolean value) {
99
+ // NOOP on Android
100
+ }
101
+
102
+ @Override
103
+ public void setShowsVerticalScrollIndicator(PdfView view, boolean value) {
104
+ // NOOP on Android
105
+ }
106
+
107
+ @ReactProp(name = "scrollEnabled")
108
+ public void setScrollEnabled(PdfView view, boolean scrollEnabled) {
109
+ pdfView.setScrollEnabled(scrollEnabled);
110
+ }
111
+
112
+ @ReactProp(name = "spacing")
113
+ public void setSpacing(PdfView pdfView, int spacing) {
114
+ pdfView.setSpacing(spacing);
115
+ }
116
+
117
+ @ReactProp(name = "password")
118
+ public void setPassword(PdfView pdfView, String password) {
119
+ pdfView.setPassword(password);
120
+ }
121
+
122
+ @ReactProp(name = "enableAntialiasing")
123
+ public void setEnableAntialiasing(PdfView pdfView, boolean enableAntialiasing) {
124
+ pdfView.setEnableAntialiasing(enableAntialiasing);
125
+ }
126
+
127
+ @ReactProp(name = "enableAnnotationRendering")
128
+ public void setEnableAnnotationRendering(PdfView pdfView, boolean enableAnnotationRendering) {
129
+ pdfView.setEnableAnnotationRendering(enableAnnotationRendering);
130
+ }
131
+
132
+ @ReactProp(name = "enableDoubleTapZoom")
133
+ public void setEnableDoubleTapZoom(PdfView pdfView, boolean enableDoubleTap) {
134
+ pdfView.setEnableDoubleTapZoom(enableDoubleTap);
135
+ }
136
+
137
+ @ReactProp(name = "enablePaging")
138
+ public void setEnablePaging(PdfView pdfView, boolean enablePaging) {
139
+ pdfView.setEnablePaging(enablePaging);
140
+ }
141
+
142
+ @Override
143
+ public void setEnableRTL(PdfView view, boolean value) {
144
+ // NOOP on Android
145
+ }
146
+
147
+ @ReactProp(name = "fitPolicy")
148
+ public void setFitPolicy(PdfView pdfView, int fitPolicy) {
149
+ pdfView.setFitPolicy(fitPolicy);
150
+ }
151
+
152
+ @ReactProp(name = "singlePage")
153
+ public void setSinglePage(PdfView pdfView, boolean singlePage) {
154
+ pdfView.setSinglePage(singlePage);
155
+ }
156
+
157
+ // It seems funny, but this method is called through delegate on Paper, but on Fabric we need to
158
+ // use `receiveCommand` method and call this one there
159
+ @Override
160
+ public void setNativePage(PdfView view, int page) {
161
+ pdfView.setPage(page);
162
+ }
163
+
164
+ @Override
165
+ public void receiveCommand(@NonNull PdfView root, String commandId, @androidx.annotation.Nullable ReadableArray args) {
166
+ Assertions.assertNotNull(root);
167
+ if ("setNativePage".equals(commandId)) {
168
+ Assertions.assertNotNull(args);
169
+ assert args != null;
170
+ setNativePage(root, args.getInt(0));
171
+ }
172
+ }
173
+
174
+ @Override
175
+ public void onAfterUpdateTransaction(PdfView pdfView) {
176
+ super.onAfterUpdateTransaction(pdfView);
177
+ pdfView.drawPdf();
178
+ }
179
+
180
+ }