Skip to content

Commit

Permalink
WIP: platform dependency refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
espresso3389 committed Feb 19, 2025
1 parent bf1daa6 commit 61af684
Show file tree
Hide file tree
Showing 9 changed files with 40 additions and 110 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ A [demo site](https://espresso3389.github.io/pdfrx/) using Flutter Web
- Windows
- macOS
- Linux (even on Raspberry PI)
- Web (\*using [PDF.js](https://mozilla.github.io/pdf.js/))
- Web (\*using [PDF.js](https://mozilla.github.io/pdf.js/)) or Pdfium WASM (\*experimental)

## Example Code

Expand Down Expand Up @@ -73,7 +73,7 @@ dependencies:
pdfrx_wasm: ^1.1.6
```
And then, enable Pdfium WASM by adding the following line to somewhere that runs before calling any pdfrx functions:
And then, enable Pdfium WASM by adding the following line to somewhere that runs before calling any pdfrx functions (typically `main` function):

```dart
Pdfrx.webRuntimeType = PdfrxWebRuntimeType.pdfiumWasm;
Expand Down
1 change: 0 additions & 1 deletion lib/pdfrx.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export 'src/pdf_api.dart';
export 'src/pdf_document_ref.dart';
export 'src/pdf_file_cache.dart';
export 'src/web/pdfjs_configuration.dart';
export 'src/widgets/pdf_page_text_overlay.dart';
export 'src/widgets/pdf_text_searcher.dart';
Expand Down
File renamed without changes.
120 changes: 23 additions & 97 deletions lib/src/pdf_file_cache.dart → lib/src/pdfium/pdf_file_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,91 +8,18 @@ import 'package:http/http.dart' as http;
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';

import '../pdfrx.dart';
import '../../pdfrx.dart';
import 'http_cache_control.dart';

/// PDF file cache for downloading (Non-web).
/// PDF file cache backed by a file.
///
/// See [PdfFileCacheNative] for actual implementation.
abstract class PdfFileCache {
PdfFileCache();

/// Size of cache block in bytes.
int get blockSize;

/// File size of the PDF file.
int get fileSize;

/// Number of cache blocks.
int get totalBlocks;

/// Number of bytes cached.
int get cachedBytes {
if (!isInitialized) return 0;
var countCached = 0;
for (int i = 0; i < totalBlocks; i++) {
if (isCached(i)) {
countCached++;
}
}
return min(countCached * blockSize, fileSize);
}

/// The file path.
String get filePath;

HttpCacheControlState get cacheControlState;

/// Determine if the cache is initialized or not.
bool get isInitialized;

/// Close the cache file.
///
/// It does not delete the cache file but just close the file handle.
Future<void> close();

/// Write [bytes] (of the [position]) to the cache.
Future<void> write(int position, List<int> bytes);

/// Read [size] bytes from the cache to [buffer] (from the [position]).
Future<void> read(List<int> buffer, int bufferPosition, int position, int size);

/// Set flag to indicate that the cache block is available.
Future<void> setCached(int startBlock, {int? lastBlock});

/// Check if the cache block is available.
bool isCached(int block);
/// Because the code internally uses `dart:io`'s [File], it is not available on the web.
class PdfFileCache {
PdfFileCache(this.file);

/// Default cache block size is 32KB.
static const defaultBlockSize = 1024 * 1024;

/// Set the cache block size.
///
/// The block size must be set before [initializeWithFileSize] and it can be called only once.
bool setBlockSize(int cacheBlockSize);

/// Initialize the cache file.
Future<void> initializeWithFileSize(int fileSize, {required bool truncateExistingContent});

Future<void> setCacheControlState(HttpCacheControlState cacheControlState);

Future<void> invalidateCache();

/// Clear all the cached data.
Future<void> resetAll();

/// Create [PdfFileCache] object from URI.
///
/// You can override the default implementation by setting [fromUri].
static Future<PdfFileCache> Function(Uri uri) fromUri = PdfFileCacheNative.fromUri;
}

/// PDF file cache backed by a file.
///
/// Because the code internally uses `dart:io`'s [File], it is not available on the web.
class PdfFileCacheNative extends PdfFileCache {
PdfFileCacheNative(this.file);

/// Cache file.
final File file;

Expand All @@ -106,22 +33,30 @@ class PdfFileCacheNative extends PdfFileCache {
bool _initialized = false;
RandomAccessFile? _raf;

@override
int get blockSize => _cacheBlockSize!;
@override

int get totalBlocks => _cacheBlockCount!;
@override

int get fileSize => _fileSize!;
@override

String get filePath => file.path;

@override
HttpCacheControlState get cacheControlState => _cacheControlState;

@override
/// Number of bytes cached.
int get cachedBytes {
if (!isInitialized) return 0;
var countCached = 0;
for (int i = 0; i < totalBlocks; i++) {
if (isCached(i)) {
countCached++;
}
}
return min(countCached * blockSize, fileSize);
}

bool get isInitialized => _initialized;

@override
Future<void> close() async {
await _raf?.close();
_raf = null;
Expand All @@ -148,17 +83,13 @@ class PdfFileCacheNative extends PdfFileCache {
return await _raf!.length();
}

@override
Future<void> read(List<int> buffer, int bufferPosition, int position, int size) =>
_read(buffer, bufferPosition, _headerSize! + position, size);

@override
Future<void> write(int position, List<int> bytes) => _write(_headerSize! + position, bytes);

@override
bool isCached(int block) => _cacheState[block >> 3] & (1 << (block & 7)) != 0;

@override
Future<void> setCached(int startBlock, {int? lastBlock}) async {
lastBlock ??= startBlock;
for (int i = startBlock; i <= lastBlock; i++) {
Expand All @@ -173,8 +104,8 @@ class PdfFileCacheNative extends PdfFileCache {

Future<void> _saveCacheState() => _write(_cacheStatePosition!, _cacheState);

static Future<PdfFileCacheNative> fromFile(File file) async {
final cache = PdfFileCacheNative(file);
static Future<PdfFileCache> fromFile(File file) async {
final cache = PdfFileCache(file);
await cache._reloadFile();
return cache;
}
Expand Down Expand Up @@ -221,7 +152,6 @@ class PdfFileCacheNative extends PdfFileCache {
}
}

@override
Future<void> invalidateCache() async {
await _ensureFileOpen();
await _raf!.truncate(0);
Expand All @@ -234,20 +164,17 @@ class PdfFileCacheNative extends PdfFileCache {
_initialized = false;
}

@override
Future<void> resetAll() async {
await invalidateCache();
await _reloadFile();
}

@override
bool setBlockSize(int cacheBlockSize) {
if (_cacheBlockSize != null) return false;
_cacheBlockSize = cacheBlockSize;
return true;
}

@override
Future<void> initializeWithFileSize(int fileSize, {required bool truncateExistingContent}) async {
if (truncateExistingContent) {
await invalidateCache();
Expand Down Expand Up @@ -282,7 +209,6 @@ class PdfFileCacheNative extends PdfFileCache {
await _write(header1Size, dataStrEncoded);
}

@override
Future<void> setCacheControlState(HttpCacheControlState cacheControlState) async {
_cacheControlState = cacheControlState;
await _saveCacheControlState();
Expand All @@ -300,7 +226,7 @@ class PdfFileCacheNative extends PdfFileCache {
return File(path.join(dir.path, '$body.pdf'));
}

static Future<PdfFileCacheNative> fromUri(Uri uri) async {
static Future<PdfFileCache> fromUri(Uri uri) async {
return await fromFile(await getCacheFilePathForUri(uri));
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/pdfium/pdfrx_pdfium.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import '../pdf_api.dart';
import '../pdf_file_cache.dart';
import 'pdf_file_cache.dart';
import 'pdfium_bindings.dart' as pdfium_bindings;
import 'pdfium_interop.dart';
import 'worker.dart';
Expand Down
3 changes: 3 additions & 0 deletions lib/src/utils/native/native.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import 'dart:io';

final isApple = Platform.isMacOS || Platform.isIOS;
7 changes: 7 additions & 0 deletions lib/src/utils/platform.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import 'package:flutter/services.dart';

import 'web/web.dart' if (dart.library.io) 'native/native.dart';

/// Key pressing state of ⌘ or Control depending on the platform.
bool get isCommandKeyPressed =>
isApple ? HardwareKeyboard.instance.isMetaPressed : HardwareKeyboard.instance.isControlPressed;
1 change: 1 addition & 0 deletions lib/src/utils/web/web.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
final isApple = false;
12 changes: 3 additions & 9 deletions lib/src/widgets/pdf_viewer.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// ignore_for_file: public_member_api_docs
import 'dart:async';
import 'dart:collection';
import 'dart:io';
import 'dart:math';
import 'dart:ui' as ui;

Expand All @@ -15,6 +14,7 @@ import 'package:synchronized/extension.dart';
import 'package:vector_math/vector_math_64.dart' as vec;

import '../../pdfrx.dart';
import '../utils/platform.dart';
import 'interactive_viewer.dart' as iv;
import 'pdf_error_widget.dart';
import 'pdf_page_links_overlay.dart';
Expand Down Expand Up @@ -496,12 +496,6 @@ class _PdfViewerState extends State<PdfViewer> with SingleTickerProviderStateMix
/// Last page number that is explicitly requested to go to.
int? _gotoTargetPageNumber;

/// Key pressing state of ⌘ or Control depending on the platform.
static bool get _isCommandKeyPressed =>
Platform.isMacOS || Platform.isIOS
? HardwareKeyboard.instance.isMetaPressed
: HardwareKeyboard.instance.isControlPressed;

KeyEventResult _onKeyEvent(FocusNode node, KeyEvent event) {
final isDown = event is KeyDownEvent;
switch (event.logicalKey) {
Expand All @@ -526,12 +520,12 @@ class _PdfViewerState extends State<PdfViewer> with SingleTickerProviderStateMix
}
return KeyEventResult.handled;
case LogicalKeyboardKey.equal:
if (isDown && _isCommandKeyPressed) {
if (isDown && isCommandKeyPressed) {
_zoomUp();
}
return KeyEventResult.handled;
case LogicalKeyboardKey.minus:
if (isDown && _isCommandKeyPressed) {
if (isDown && isCommandKeyPressed) {
_zoomDown();
}
return KeyEventResult.handled;
Expand Down

0 comments on commit 61af684

Please sign in to comment.