From 12940cc5466ed9c59c808e567f084dbe8a031a50 Mon Sep 17 00:00:00 2001 From: Eunchurn Park Date: Mon, 19 Jan 2026 20:41:48 +0900 Subject: [PATCH 1/5] fix: XTC 1-bit thumb BMP polarity inversion (#373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary * **What is the goal of this PR?** (e.g., Implements the new feature for file uploading.) * **What changes are included?** - Fix inverted colors in Continue Reading cover image for 1-bit XTC files ## Additional Context * Add any other information that might be helpful for the reviewer (e.g., performance implications, potential risks, specific areas to focus on). - Fix `grayValue = pixelBit ? 0 : 255` → `grayValue = pixelBit ? 255 : 0` in `lib/Xtc/Xtc.cpp` - The thumb BMP generation had inverted polarity compared to cover BMP generation - bit=0 should be black, bit=1 should be white (matching the BMP palette order) - Update misleading comment about XTC polarity --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**PARTIALLY**_ --- lib/Xtc/Xtc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Xtc/Xtc.cpp b/lib/Xtc/Xtc.cpp index 7205ffb9..c79421d7 100644 --- a/lib/Xtc/Xtc.cpp +++ b/lib/Xtc/Xtc.cpp @@ -203,7 +203,7 @@ bool Xtc::generateCoverBmp() const { coverBmp.write(reinterpret_cast(&colorsImportant), 4); // Color palette (2 colors for 1-bit) - // XTC uses inverted polarity: 0 = black, 1 = white + // XTC 1-bit polarity: 0 = black, 1 = white (standard BMP palette order) // Color 0: Black (text/foreground in XTC) uint8_t black[4] = {0x00, 0x00, 0x00, 0x00}; coverBmp.write(black, 4); @@ -506,8 +506,8 @@ bool Xtc::generateThumbBmp() const { // Bounds check for buffer access if (byteIdx < bitmapSize) { const uint8_t pixelBit = (pageBuffer[byteIdx] >> bitIdx) & 1; - // XTC polarity: 1=black, 0=white - grayValue = pixelBit ? 0 : 255; + // XTC 1-bit polarity: 0=black, 1=white (same as BMP palette) + grayValue = pixelBit ? 255 : 0; } } From 7185e5d2876f488acbaeb6b9530201db12aec2c2 Mon Sep 17 00:00:00 2001 From: Nathan James <64075030+Nathanjms@users.noreply.github.com> Date: Mon, 19 Jan 2026 11:50:34 +0000 Subject: [PATCH 2/5] feat: Change keyboard "caps" to "shift" & Wrap Keyboard (#377) ## Summary * This PR solves issue https://github.com/crosspoint-reader/crosspoint-reader/issues/357 in the first commit * I then added an additional commit which means when you reach the end of the keyboard, if you go 'beyond', you wrap back to the other side. * This replaces existing behaviour, so if you would rather this be removed, let me know and I'll just do the `caps` -> `shift` change ## Additional Context ### Screenshots for the new shift display I thought it might not fit and need column size changes, but ended up fitting fine, see screenshots showing this below: image image ### Gif showing the wrap-around of the text ![IMG_7648](https://github.com/user-attachments/assets/7eec9066-e1cc-49a1-8b6b-a61556038d31) --- ### AI Usage Did you use AI tools to help write this code? **PARTIALLY** - used to double check the text wrapping had no edge-cases. (It did also suggest rewriting the function, but I decided that was too big of a change for a working part of the codebase, for now!) --- src/activities/util/KeyboardEntryActivity.cpp | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/activities/util/KeyboardEntryActivity.cpp b/src/activities/util/KeyboardEntryActivity.cpp index aa4ffc20..8c36ac33 100644 --- a/src/activities/util/KeyboardEntryActivity.cpp +++ b/src/activities/util/KeyboardEntryActivity.cpp @@ -73,7 +73,7 @@ int KeyboardEntryActivity::getRowLength(const int row) const { case 3: return 10; // zxcvbnm,./ case 4: - return 10; // caps (2 wide), space (5 wide), backspace (2 wide), OK + return 10; // shift (2 wide), space (5 wide), backspace (2 wide), OK default: return 0; } @@ -145,6 +145,11 @@ void KeyboardEntryActivity::loop() { // Clamp column to valid range for new row const int maxCol = getRowLength(selectedRow) - 1; if (selectedCol > maxCol) selectedCol = maxCol; + } else { + // Wrap to bottom row + selectedRow = NUM_ROWS - 1; + const int maxCol = getRowLength(selectedRow) - 1; + if (selectedCol > maxCol) selectedCol = maxCol; } updateRequired = true; } @@ -154,16 +159,24 @@ void KeyboardEntryActivity::loop() { selectedRow++; const int maxCol = getRowLength(selectedRow) - 1; if (selectedCol > maxCol) selectedCol = maxCol; + } else { + // Wrap to top row + selectedRow = 0; + const int maxCol = getRowLength(selectedRow) - 1; + if (selectedCol > maxCol) selectedCol = maxCol; } updateRequired = true; } if (mappedInput.wasPressed(MappedInputManager::Button::Left)) { + const int maxCol = getRowLength(selectedRow) - 1; + // Special bottom row case if (selectedRow == SPECIAL_ROW) { // Bottom row has special key widths if (selectedCol >= SHIFT_COL && selectedCol < SPACE_COL) { - // In shift key, do nothing + // In shift key, wrap to end of row + selectedCol = maxCol; } else if (selectedCol >= SPACE_COL && selectedCol < BACKSPACE_COL) { // In space bar, move to shift selectedCol = SHIFT_COL; @@ -180,10 +193,9 @@ void KeyboardEntryActivity::loop() { if (selectedCol > 0) { selectedCol--; - } else if (selectedRow > 0) { - // Wrap to previous row - selectedRow--; - selectedCol = getRowLength(selectedRow) - 1; + } else { + // Wrap to end of current row + selectedCol = maxCol; } updateRequired = true; } @@ -204,7 +216,8 @@ void KeyboardEntryActivity::loop() { // In backspace, move to done selectedCol = DONE_COL; } else if (selectedCol >= DONE_COL) { - // At done button, do nothing + // At done button, wrap to beginning of row + selectedCol = SHIFT_COL; } updateRequired = true; return; @@ -212,9 +225,8 @@ void KeyboardEntryActivity::loop() { if (selectedCol < maxCol) { selectedCol++; - } else if (selectedRow < NUM_ROWS - 1) { - // Wrap to next row - selectedRow++; + } else { + // Wrap to beginning of current row selectedCol = 0; } updateRequired = true; @@ -288,14 +300,14 @@ void KeyboardEntryActivity::render() const { // Handle bottom row (row 4) specially with proper multi-column keys if (row == 4) { - // Bottom row layout: CAPS (2 cols) | SPACE (5 cols) | <- (2 cols) | OK (2 cols) + // Bottom row layout: SHIFT (2 cols) | SPACE (5 cols) | <- (2 cols) | OK (2 cols) // Total: 11 visual columns, but we use logical positions for selection int currentX = startX; - // CAPS key (logical col 0, spans 2 key widths) - const bool capsSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL); - renderItemWithSelector(currentX + 2, rowY, shiftActive ? "CAPS" : "caps", capsSelected); + // SHIFT key (logical col 0, spans 2 key widths) + const bool shiftSelected = (selectedRow == 4 && selectedCol >= SHIFT_COL && selectedCol < SPACE_COL); + renderItemWithSelector(currentX + 2, rowY, shiftActive ? "SHIFT" : "shift", shiftSelected); currentX += 2 * (keyWidth + keySpacing); // Space bar (logical cols 2-6, spans 5 key widths) From f69cddf2cc26a1ba9fcee4f45a18c822fed03d2a Mon Sep 17 00:00:00 2001 From: Justin Mitchell Date: Mon, 19 Jan 2026 06:55:35 -0500 Subject: [PATCH 3/5] Adds KOReader Sync support (#232) ## Summary - Adds KOReader progress sync integration, allowing CrossPoint to sync reading positions with other KOReader-compatible devices - Stores credentials securely with XOR obfuscation - Uses KOReader's partial MD5 document hashing for cross-device book matching - Syncs position via percentage with estimated XPath for compatibility # Features - Settings: KOReader Username, Password, and Authenticate options - Sync from chapters menu: "Sync Progress" option appears when credentials are configured - Bidirectional sync: Can apply remote progress or upload local progress --------- Co-authored-by: Dave Allie --- lib/Epub/Epub.cpp | 11 +- lib/Epub/Epub.h | 2 +- lib/KOReaderSync/KOReaderCredentialStore.cpp | 168 +++++++ lib/KOReaderSync/KOReaderCredentialStore.h | 69 +++ lib/KOReaderSync/KOReaderDocumentId.cpp | 96 ++++ lib/KOReaderSync/KOReaderDocumentId.h | 45 ++ lib/KOReaderSync/KOReaderSyncClient.cpp | 198 ++++++++ lib/KOReaderSync/KOReaderSyncClient.h | 59 +++ lib/KOReaderSync/ProgressMapper.cpp | 112 +++++ lib/KOReaderSync/ProgressMapper.h | 72 +++ src/activities/reader/EpubReaderActivity.cpp | 22 +- .../EpubReaderChapterSelectionActivity.cpp | 95 +++- .../EpubReaderChapterSelectionActivity.h | 37 +- .../reader/KOReaderSyncActivity.cpp | 439 ++++++++++++++++++ src/activities/reader/KOReaderSyncActivity.h | 98 ++++ .../settings/KOReaderAuthActivity.cpp | 167 +++++++ .../settings/KOReaderAuthActivity.h | 44 ++ .../settings/KOReaderSettingsActivity.cpp | 213 +++++++++ .../settings/KOReaderSettingsActivity.h | 36 ++ src/activities/settings/SettingsActivity.cpp | 28 +- src/main.cpp | 2 + 21 files changed, 1974 insertions(+), 39 deletions(-) create mode 100644 lib/KOReaderSync/KOReaderCredentialStore.cpp create mode 100644 lib/KOReaderSync/KOReaderCredentialStore.h create mode 100644 lib/KOReaderSync/KOReaderDocumentId.cpp create mode 100644 lib/KOReaderSync/KOReaderDocumentId.h create mode 100644 lib/KOReaderSync/KOReaderSyncClient.cpp create mode 100644 lib/KOReaderSync/KOReaderSyncClient.h create mode 100644 lib/KOReaderSync/ProgressMapper.cpp create mode 100644 lib/KOReaderSync/ProgressMapper.h create mode 100644 src/activities/reader/KOReaderSyncActivity.cpp create mode 100644 src/activities/reader/KOReaderSyncActivity.h create mode 100644 src/activities/settings/KOReaderAuthActivity.cpp create mode 100644 src/activities/settings/KOReaderAuthActivity.h create mode 100644 src/activities/settings/KOReaderSettingsActivity.cpp create mode 100644 src/activities/settings/KOReaderSettingsActivity.h diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 1b337721..e3b66b42 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -609,14 +609,15 @@ int Epub::getSpineIndexForTextReference() const { return 0; } -// Calculate progress in book -uint8_t Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const { +// Calculate progress in book (returns 0.0-1.0) +float Epub::calculateProgress(const int currentSpineIndex, const float currentSpineRead) const { const size_t bookSize = getBookSize(); if (bookSize == 0) { - return 0; + return 0.0f; } const size_t prevChapterSize = (currentSpineIndex >= 1) ? getCumulativeSpineItemSize(currentSpineIndex - 1) : 0; const size_t curChapterSize = getCumulativeSpineItemSize(currentSpineIndex) - prevChapterSize; - const size_t sectionProgSize = currentSpineRead * curChapterSize; - return round(static_cast(prevChapterSize + sectionProgSize) / bookSize * 100.0); + const float sectionProgSize = currentSpineRead * static_cast(curChapterSize); + const float totalProgress = static_cast(prevChapterSize) + sectionProgSize; + return totalProgress / static_cast(bookSize); } diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index 91062aa4..20d08166 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -62,5 +62,5 @@ class Epub { int getSpineIndexForTextReference() const; size_t getBookSize() const; - uint8_t calculateProgress(int currentSpineIndex, float currentSpineRead) const; + float calculateProgress(int currentSpineIndex, float currentSpineRead) const; }; diff --git a/lib/KOReaderSync/KOReaderCredentialStore.cpp b/lib/KOReaderSync/KOReaderCredentialStore.cpp new file mode 100644 index 00000000..c5737809 --- /dev/null +++ b/lib/KOReaderSync/KOReaderCredentialStore.cpp @@ -0,0 +1,168 @@ +#include "KOReaderCredentialStore.h" + +#include +#include +#include +#include + +// Initialize the static instance +KOReaderCredentialStore KOReaderCredentialStore::instance; + +namespace { +// File format version +constexpr uint8_t KOREADER_FILE_VERSION = 1; + +// KOReader credentials file path +constexpr char KOREADER_FILE[] = "/.crosspoint/koreader.bin"; + +// Default sync server URL +constexpr char DEFAULT_SERVER_URL[] = "https://sync.koreader.rocks:443"; + +// Obfuscation key - "KOReader" in ASCII +// This is NOT cryptographic security, just prevents casual file reading +constexpr uint8_t OBFUSCATION_KEY[] = {0x4B, 0x4F, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72}; +constexpr size_t KEY_LENGTH = sizeof(OBFUSCATION_KEY); +} // namespace + +void KOReaderCredentialStore::obfuscate(std::string& data) const { + for (size_t i = 0; i < data.size(); i++) { + data[i] ^= OBFUSCATION_KEY[i % KEY_LENGTH]; + } +} + +bool KOReaderCredentialStore::saveToFile() const { + // Make sure the directory exists + SdMan.mkdir("/.crosspoint"); + + FsFile file; + if (!SdMan.openFileForWrite("KRS", KOREADER_FILE, file)) { + return false; + } + + // Write header + serialization::writePod(file, KOREADER_FILE_VERSION); + + // Write username (plaintext - not particularly sensitive) + serialization::writeString(file, username); + Serial.printf("[%lu] [KRS] Saving username: %s\n", millis(), username.c_str()); + + // Write password (obfuscated) + std::string obfuscatedPwd = password; + obfuscate(obfuscatedPwd); + serialization::writeString(file, obfuscatedPwd); + + // Write server URL + serialization::writeString(file, serverUrl); + + // Write match method + serialization::writePod(file, static_cast(matchMethod)); + + file.close(); + Serial.printf("[%lu] [KRS] Saved KOReader credentials to file\n", millis()); + return true; +} + +bool KOReaderCredentialStore::loadFromFile() { + FsFile file; + if (!SdMan.openFileForRead("KRS", KOREADER_FILE, file)) { + Serial.printf("[%lu] [KRS] No credentials file found\n", millis()); + return false; + } + + // Read and verify version + uint8_t version; + serialization::readPod(file, version); + if (version != KOREADER_FILE_VERSION) { + Serial.printf("[%lu] [KRS] Unknown file version: %u\n", millis(), version); + file.close(); + return false; + } + + // Read username + if (file.available()) { + serialization::readString(file, username); + } else { + username.clear(); + } + + // Read and deobfuscate password + if (file.available()) { + serialization::readString(file, password); + obfuscate(password); // XOR is symmetric, so same function deobfuscates + } else { + password.clear(); + } + + // Read server URL + if (file.available()) { + serialization::readString(file, serverUrl); + } else { + serverUrl.clear(); + } + + // Read match method + if (file.available()) { + uint8_t method; + serialization::readPod(file, method); + matchMethod = static_cast(method); + } else { + matchMethod = DocumentMatchMethod::FILENAME; + } + + file.close(); + Serial.printf("[%lu] [KRS] Loaded KOReader credentials for user: %s\n", millis(), username.c_str()); + return true; +} + +void KOReaderCredentialStore::setCredentials(const std::string& user, const std::string& pass) { + username = user; + password = pass; + Serial.printf("[%lu] [KRS] Set credentials for user: %s\n", millis(), user.c_str()); +} + +std::string KOReaderCredentialStore::getMd5Password() const { + if (password.empty()) { + return ""; + } + + // Calculate MD5 hash of password using ESP32's MD5Builder + MD5Builder md5; + md5.begin(); + md5.add(password.c_str()); + md5.calculate(); + + return md5.toString().c_str(); +} + +bool KOReaderCredentialStore::hasCredentials() const { return !username.empty() && !password.empty(); } + +void KOReaderCredentialStore::clearCredentials() { + username.clear(); + password.clear(); + saveToFile(); + Serial.printf("[%lu] [KRS] Cleared KOReader credentials\n", millis()); +} + +void KOReaderCredentialStore::setServerUrl(const std::string& url) { + serverUrl = url; + Serial.printf("[%lu] [KRS] Set server URL: %s\n", millis(), url.empty() ? "(default)" : url.c_str()); +} + +std::string KOReaderCredentialStore::getBaseUrl() const { + if (serverUrl.empty()) { + return DEFAULT_SERVER_URL; + } + + // Normalize URL: add http:// if no protocol specified (local servers typically don't have SSL) + if (serverUrl.find("://") == std::string::npos) { + return "http://" + serverUrl; + } + + return serverUrl; +} + +void KOReaderCredentialStore::setMatchMethod(DocumentMatchMethod method) { + matchMethod = method; + Serial.printf("[%lu] [KRS] Set match method: %s\n", millis(), + method == DocumentMatchMethod::FILENAME ? "Filename" : "Binary"); +} diff --git a/lib/KOReaderSync/KOReaderCredentialStore.h b/lib/KOReaderSync/KOReaderCredentialStore.h new file mode 100644 index 00000000..998101a2 --- /dev/null +++ b/lib/KOReaderSync/KOReaderCredentialStore.h @@ -0,0 +1,69 @@ +#pragma once +#include +#include + +// Document matching method for KOReader sync +enum class DocumentMatchMethod : uint8_t { + FILENAME = 0, // Match by filename (simpler, works across different file sources) + BINARY = 1, // Match by partial MD5 of file content (more accurate, but files must be identical) +}; + +/** + * Singleton class for storing KOReader sync credentials on the SD card. + * Credentials are stored in /sd/.crosspoint/koreader.bin with basic + * XOR obfuscation to prevent casual reading (not cryptographically secure). + */ +class KOReaderCredentialStore { + private: + static KOReaderCredentialStore instance; + std::string username; + std::string password; + std::string serverUrl; // Custom sync server URL (empty = default) + DocumentMatchMethod matchMethod = DocumentMatchMethod::FILENAME; // Default to filename for compatibility + + // Private constructor for singleton + KOReaderCredentialStore() = default; + + // XOR obfuscation (symmetric - same for encode/decode) + void obfuscate(std::string& data) const; + + public: + // Delete copy constructor and assignment + KOReaderCredentialStore(const KOReaderCredentialStore&) = delete; + KOReaderCredentialStore& operator=(const KOReaderCredentialStore&) = delete; + + // Get singleton instance + static KOReaderCredentialStore& getInstance() { return instance; } + + // Save/load from SD card + bool saveToFile() const; + bool loadFromFile(); + + // Credential management + void setCredentials(const std::string& user, const std::string& pass); + const std::string& getUsername() const { return username; } + const std::string& getPassword() const { return password; } + + // Get MD5 hash of password for API authentication + std::string getMd5Password() const; + + // Check if credentials are set + bool hasCredentials() const; + + // Clear credentials + void clearCredentials(); + + // Server URL management + void setServerUrl(const std::string& url); + const std::string& getServerUrl() const { return serverUrl; } + + // Get base URL for API calls (with http:// normalization if no protocol, falls back to default) + std::string getBaseUrl() const; + + // Document matching method + void setMatchMethod(DocumentMatchMethod method); + DocumentMatchMethod getMatchMethod() const { return matchMethod; } +}; + +// Helper macro to access credential store +#define KOREADER_STORE KOReaderCredentialStore::getInstance() diff --git a/lib/KOReaderSync/KOReaderDocumentId.cpp b/lib/KOReaderSync/KOReaderDocumentId.cpp new file mode 100644 index 00000000..2c52464c --- /dev/null +++ b/lib/KOReaderSync/KOReaderDocumentId.cpp @@ -0,0 +1,96 @@ +#include "KOReaderDocumentId.h" + +#include +#include +#include + +namespace { +// Extract filename from path (everything after last '/') +std::string getFilename(const std::string& path) { + const size_t pos = path.rfind('/'); + if (pos == std::string::npos) { + return path; + } + return path.substr(pos + 1); +} +} // namespace + +std::string KOReaderDocumentId::calculateFromFilename(const std::string& filePath) { + const std::string filename = getFilename(filePath); + if (filename.empty()) { + return ""; + } + + MD5Builder md5; + md5.begin(); + md5.add(filename.c_str()); + md5.calculate(); + + std::string result = md5.toString().c_str(); + Serial.printf("[%lu] [KODoc] Filename hash: %s (from '%s')\n", millis(), result.c_str(), filename.c_str()); + return result; +} + +size_t KOReaderDocumentId::getOffset(int i) { + // Offset = 1024 << (2*i) + // For i = -1: 1024 >> 2 = 256 + // For i >= 0: 1024 << (2*i) + if (i < 0) { + return CHUNK_SIZE >> (-2 * i); + } + return CHUNK_SIZE << (2 * i); +} + +std::string KOReaderDocumentId::calculate(const std::string& filePath) { + FsFile file; + if (!SdMan.openFileForRead("KODoc", filePath, file)) { + Serial.printf("[%lu] [KODoc] Failed to open file: %s\n", millis(), filePath.c_str()); + return ""; + } + + const size_t fileSize = file.fileSize(); + Serial.printf("[%lu] [KODoc] Calculating hash for file: %s (size: %zu)\n", millis(), filePath.c_str(), fileSize); + + // Initialize MD5 builder + MD5Builder md5; + md5.begin(); + + // Buffer for reading chunks + uint8_t buffer[CHUNK_SIZE]; + size_t totalBytesRead = 0; + + // Read from each offset (i = -1 to 10) + for (int i = -1; i < OFFSET_COUNT - 1; i++) { + const size_t offset = getOffset(i); + + // Skip if offset is beyond file size + if (offset >= fileSize) { + continue; + } + + // Seek to offset + if (!file.seekSet(offset)) { + Serial.printf("[%lu] [KODoc] Failed to seek to offset %zu\n", millis(), offset); + continue; + } + + // Read up to CHUNK_SIZE bytes + const size_t bytesToRead = std::min(CHUNK_SIZE, fileSize - offset); + const size_t bytesRead = file.read(buffer, bytesToRead); + + if (bytesRead > 0) { + md5.add(buffer, bytesRead); + totalBytesRead += bytesRead; + } + } + + file.close(); + + // Calculate final hash + md5.calculate(); + std::string result = md5.toString().c_str(); + + Serial.printf("[%lu] [KODoc] Hash calculated: %s (from %zu bytes)\n", millis(), result.c_str(), totalBytesRead); + + return result; +} diff --git a/lib/KOReaderSync/KOReaderDocumentId.h b/lib/KOReaderSync/KOReaderDocumentId.h new file mode 100644 index 00000000..2b6189e2 --- /dev/null +++ b/lib/KOReaderSync/KOReaderDocumentId.h @@ -0,0 +1,45 @@ +#pragma once +#include + +/** + * Calculate KOReader document ID (partial MD5 hash). + * + * KOReader identifies documents using a partial MD5 hash of the file content. + * The algorithm reads 1024 bytes at specific offsets and computes the MD5 hash + * of the concatenated data. + * + * Offsets are calculated as: 1024 << (2*i) for i = -1 to 10 + * Producing: 256, 1024, 4096, 16384, 65536, 262144, 1048576, 4194304, + * 16777216, 67108864, 268435456, 1073741824 bytes + * + * If an offset is beyond the file size, it is skipped. + */ +class KOReaderDocumentId { + public: + /** + * Calculate the KOReader document hash for a file (binary/content-based). + * + * @param filePath Path to the file (typically an EPUB) + * @return 32-character lowercase hex string, or empty string on failure + */ + static std::string calculate(const std::string& filePath); + + /** + * Calculate document hash from filename only (filename-based sync mode). + * This is simpler and works when files have the same name across devices. + * + * @param filePath Path to the file (only the filename portion is used) + * @return 32-character lowercase hex MD5 of the filename + */ + static std::string calculateFromFilename(const std::string& filePath); + + private: + // Size of each chunk to read at each offset + static constexpr size_t CHUNK_SIZE = 1024; + + // Number of offsets to try (i = -1 to 10, so 12 offsets) + static constexpr int OFFSET_COUNT = 12; + + // Calculate offset for index i: 1024 << (2*i) + static size_t getOffset(int i); +}; diff --git a/lib/KOReaderSync/KOReaderSyncClient.cpp b/lib/KOReaderSync/KOReaderSyncClient.cpp new file mode 100644 index 00000000..c5053c64 --- /dev/null +++ b/lib/KOReaderSync/KOReaderSyncClient.cpp @@ -0,0 +1,198 @@ +#include "KOReaderSyncClient.h" + +#include +#include +#include +#include +#include + +#include + +#include "KOReaderCredentialStore.h" + +namespace { +// Device identifier for CrossPoint reader +constexpr char DEVICE_NAME[] = "CrossPoint"; +constexpr char DEVICE_ID[] = "crosspoint-reader"; + +void addAuthHeaders(HTTPClient& http) { + http.addHeader("Accept", "application/vnd.koreader.v1+json"); + http.addHeader("x-auth-user", KOREADER_STORE.getUsername().c_str()); + http.addHeader("x-auth-key", KOREADER_STORE.getMd5Password().c_str()); +} + +bool isHttpsUrl(const std::string& url) { return url.rfind("https://", 0) == 0; } +} // namespace + +KOReaderSyncClient::Error KOReaderSyncClient::authenticate() { + if (!KOREADER_STORE.hasCredentials()) { + Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); + return NO_CREDENTIALS; + } + + std::string url = KOREADER_STORE.getBaseUrl() + "/users/auth"; + Serial.printf("[%lu] [KOSync] Authenticating: %s\n", millis(), url.c_str()); + + HTTPClient http; + std::unique_ptr secureClient; + WiFiClient plainClient; + + if (isHttpsUrl(url)) { + secureClient.reset(new WiFiClientSecure); + secureClient->setInsecure(); + http.begin(*secureClient, url.c_str()); + } else { + http.begin(plainClient, url.c_str()); + } + addAuthHeaders(http); + + const int httpCode = http.GET(); + http.end(); + + Serial.printf("[%lu] [KOSync] Auth response: %d\n", millis(), httpCode); + + if (httpCode == 200) { + return OK; + } else if (httpCode == 401) { + return AUTH_FAILED; + } else if (httpCode < 0) { + return NETWORK_ERROR; + } + return SERVER_ERROR; +} + +KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& documentHash, + KOReaderProgress& outProgress) { + if (!KOREADER_STORE.hasCredentials()) { + Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); + return NO_CREDENTIALS; + } + + std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress/" + documentHash; + Serial.printf("[%lu] [KOSync] Getting progress: %s\n", millis(), url.c_str()); + + HTTPClient http; + std::unique_ptr secureClient; + WiFiClient plainClient; + + if (isHttpsUrl(url)) { + secureClient.reset(new WiFiClientSecure); + secureClient->setInsecure(); + http.begin(*secureClient, url.c_str()); + } else { + http.begin(plainClient, url.c_str()); + } + addAuthHeaders(http); + + const int httpCode = http.GET(); + + if (httpCode == 200) { + // Parse JSON response from response string + String responseBody = http.getString(); + http.end(); + + JsonDocument doc; + const DeserializationError error = deserializeJson(doc, responseBody); + + if (error) { + Serial.printf("[%lu] [KOSync] JSON parse failed: %s\n", millis(), error.c_str()); + return JSON_ERROR; + } + + outProgress.document = documentHash; + outProgress.progress = doc["progress"].as(); + outProgress.percentage = doc["percentage"].as(); + outProgress.device = doc["device"].as(); + outProgress.deviceId = doc["device_id"].as(); + outProgress.timestamp = doc["timestamp"].as(); + + Serial.printf("[%lu] [KOSync] Got progress: %.2f%% at %s\n", millis(), outProgress.percentage * 100, + outProgress.progress.c_str()); + return OK; + } + + http.end(); + + Serial.printf("[%lu] [KOSync] Get progress response: %d\n", millis(), httpCode); + + if (httpCode == 401) { + return AUTH_FAILED; + } else if (httpCode == 404) { + return NOT_FOUND; + } else if (httpCode < 0) { + return NETWORK_ERROR; + } + return SERVER_ERROR; +} + +KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgress& progress) { + if (!KOREADER_STORE.hasCredentials()) { + Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); + return NO_CREDENTIALS; + } + + std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress"; + Serial.printf("[%lu] [KOSync] Updating progress: %s\n", millis(), url.c_str()); + + HTTPClient http; + std::unique_ptr secureClient; + WiFiClient plainClient; + + if (isHttpsUrl(url)) { + secureClient.reset(new WiFiClientSecure); + secureClient->setInsecure(); + http.begin(*secureClient, url.c_str()); + } else { + http.begin(plainClient, url.c_str()); + } + addAuthHeaders(http); + http.addHeader("Content-Type", "application/json"); + + // Build JSON body (timestamp not required per API spec) + JsonDocument doc; + doc["document"] = progress.document; + doc["progress"] = progress.progress; + doc["percentage"] = progress.percentage; + doc["device"] = DEVICE_NAME; + doc["device_id"] = DEVICE_ID; + + std::string body; + serializeJson(doc, body); + + Serial.printf("[%lu] [KOSync] Request body: %s\n", millis(), body.c_str()); + + const int httpCode = http.PUT(body.c_str()); + http.end(); + + Serial.printf("[%lu] [KOSync] Update progress response: %d\n", millis(), httpCode); + + if (httpCode == 200 || httpCode == 202) { + return OK; + } else if (httpCode == 401) { + return AUTH_FAILED; + } else if (httpCode < 0) { + return NETWORK_ERROR; + } + return SERVER_ERROR; +} + +const char* KOReaderSyncClient::errorString(Error error) { + switch (error) { + case OK: + return "Success"; + case NO_CREDENTIALS: + return "No credentials configured"; + case NETWORK_ERROR: + return "Network error"; + case AUTH_FAILED: + return "Authentication failed"; + case SERVER_ERROR: + return "Server error (try again later)"; + case JSON_ERROR: + return "JSON parse error"; + case NOT_FOUND: + return "No progress found"; + default: + return "Unknown error"; + } +} diff --git a/lib/KOReaderSync/KOReaderSyncClient.h b/lib/KOReaderSync/KOReaderSyncClient.h new file mode 100644 index 00000000..a9bc5c09 --- /dev/null +++ b/lib/KOReaderSync/KOReaderSyncClient.h @@ -0,0 +1,59 @@ +#pragma once +#include + +/** + * Progress data from KOReader sync server. + */ +struct KOReaderProgress { + std::string document; // Document hash + std::string progress; // XPath-like progress string + float percentage; // Progress percentage (0.0 to 1.0) + std::string device; // Device name + std::string deviceId; // Device ID + int64_t timestamp; // Unix timestamp of last update +}; + +/** + * HTTP client for KOReader sync API. + * + * Base URL: https://sync.koreader.rocks:443/ + * + * API Endpoints: + * GET /users/auth - Authenticate (validate credentials) + * GET /syncs/progress/:document - Get progress for a document + * PUT /syncs/progress - Update progress for a document + * + * Authentication: + * x-auth-user: username + * x-auth-key: MD5 hash of password + */ +class KOReaderSyncClient { + public: + enum Error { OK = 0, NO_CREDENTIALS, NETWORK_ERROR, AUTH_FAILED, SERVER_ERROR, JSON_ERROR, NOT_FOUND }; + + /** + * Authenticate with the sync server (validate credentials). + * @return OK on success, error code on failure + */ + static Error authenticate(); + + /** + * Get reading progress for a document. + * @param documentHash The document hash (from KOReaderDocumentId) + * @param outProgress Output: the progress data + * @return OK on success, NOT_FOUND if no progress exists, error code on failure + */ + static Error getProgress(const std::string& documentHash, KOReaderProgress& outProgress); + + /** + * Update reading progress for a document. + * @param progress The progress data to upload + * @return OK on success, error code on failure + */ + static Error updateProgress(const KOReaderProgress& progress); + + /** + * Get human-readable error message. + */ + static const char* errorString(Error error); +}; diff --git a/lib/KOReaderSync/ProgressMapper.cpp b/lib/KOReaderSync/ProgressMapper.cpp new file mode 100644 index 00000000..2c15ab71 --- /dev/null +++ b/lib/KOReaderSync/ProgressMapper.cpp @@ -0,0 +1,112 @@ +#include "ProgressMapper.h" + +#include + +#include + +KOReaderPosition ProgressMapper::toKOReader(const std::shared_ptr& epub, const CrossPointPosition& pos) { + KOReaderPosition result; + + // Calculate page progress within current spine item + float intraSpineProgress = 0.0f; + if (pos.totalPages > 0) { + intraSpineProgress = static_cast(pos.pageNumber) / static_cast(pos.totalPages); + } + + // Calculate overall book progress (0.0-1.0) + result.percentage = epub->calculateProgress(pos.spineIndex, intraSpineProgress); + + // Generate XPath with estimated paragraph position based on page + result.xpath = generateXPath(pos.spineIndex, pos.pageNumber, pos.totalPages); + + // Get chapter info for logging + const int tocIndex = epub->getTocIndexForSpineIndex(pos.spineIndex); + const std::string chapterName = (tocIndex >= 0) ? epub->getTocItem(tocIndex).title : "unknown"; + + Serial.printf("[%lu] [ProgressMapper] CrossPoint -> KOReader: chapter='%s', page=%d/%d -> %.2f%% at %s\n", millis(), + chapterName.c_str(), pos.pageNumber, pos.totalPages, result.percentage * 100, result.xpath.c_str()); + + return result; +} + +CrossPointPosition ProgressMapper::toCrossPoint(const std::shared_ptr& epub, const KOReaderPosition& koPos, + int totalPagesInSpine) { + CrossPointPosition result; + result.spineIndex = 0; + result.pageNumber = 0; + result.totalPages = totalPagesInSpine; + + const size_t bookSize = epub->getBookSize(); + if (bookSize == 0) { + return result; + } + + // First, try to get spine index from XPath (DocFragment) + int xpathSpineIndex = parseDocFragmentIndex(koPos.xpath); + if (xpathSpineIndex >= 0 && xpathSpineIndex < epub->getSpineItemsCount()) { + result.spineIndex = xpathSpineIndex; + // When we have XPath, go to page 0 of the spine - byte-based page calculation is unreliable + result.pageNumber = 0; + } else { + // Fall back to percentage-based lookup for both spine and page + const size_t targetBytes = static_cast(bookSize * koPos.percentage); + + // Find the spine item that contains this byte position + for (int i = 0; i < epub->getSpineItemsCount(); i++) { + const size_t cumulativeSize = epub->getCumulativeSpineItemSize(i); + if (cumulativeSize >= targetBytes) { + result.spineIndex = i; + break; + } + } + + // Estimate page number within the spine item using percentage (only when no XPath) + if (totalPagesInSpine > 0 && result.spineIndex < epub->getSpineItemsCount()) { + const size_t prevCumSize = (result.spineIndex > 0) ? epub->getCumulativeSpineItemSize(result.spineIndex - 1) : 0; + const size_t currentCumSize = epub->getCumulativeSpineItemSize(result.spineIndex); + const size_t spineSize = currentCumSize - prevCumSize; + + if (spineSize > 0) { + const size_t bytesIntoSpine = (targetBytes > prevCumSize) ? (targetBytes - prevCumSize) : 0; + const float intraSpineProgress = static_cast(bytesIntoSpine) / static_cast(spineSize); + const float clampedProgress = std::max(0.0f, std::min(1.0f, intraSpineProgress)); + result.pageNumber = static_cast(clampedProgress * totalPagesInSpine); + result.pageNumber = std::max(0, std::min(result.pageNumber, totalPagesInSpine - 1)); + } + } + } + + Serial.printf("[%lu] [ProgressMapper] KOReader -> CrossPoint: %.2f%% at %s -> spine=%d, page=%d\n", millis(), + koPos.percentage * 100, koPos.xpath.c_str(), result.spineIndex, result.pageNumber); + + return result; +} + +std::string ProgressMapper::generateXPath(int spineIndex, int pageNumber, int totalPages) { + // KOReader uses 1-based DocFragment indices + // Use a simple xpath pointing to the DocFragment - KOReader will use the percentage for fine positioning + // Avoid specifying paragraph numbers as they may not exist in the target document + return "/body/DocFragment[" + std::to_string(spineIndex + 1) + "]/body"; +} + +int ProgressMapper::parseDocFragmentIndex(const std::string& xpath) { + // Look for DocFragment[N] pattern + const size_t start = xpath.find("DocFragment["); + if (start == std::string::npos) { + return -1; + } + + const size_t numStart = start + 12; // Length of "DocFragment[" + const size_t numEnd = xpath.find(']', numStart); + if (numEnd == std::string::npos) { + return -1; + } + + try { + const int docFragmentIndex = std::stoi(xpath.substr(numStart, numEnd - numStart)); + // KOReader uses 1-based indices, we use 0-based + return docFragmentIndex - 1; + } catch (...) { + return -1; + } +} diff --git a/lib/KOReaderSync/ProgressMapper.h b/lib/KOReaderSync/ProgressMapper.h new file mode 100644 index 00000000..694549da --- /dev/null +++ b/lib/KOReaderSync/ProgressMapper.h @@ -0,0 +1,72 @@ +#pragma once +#include + +#include +#include + +/** + * CrossPoint position representation. + */ +struct CrossPointPosition { + int spineIndex; // Current spine item (chapter) index + int pageNumber; // Current page within the spine item + int totalPages; // Total pages in the current spine item +}; + +/** + * KOReader position representation. + */ +struct KOReaderPosition { + std::string xpath; // XPath-like progress string + float percentage; // Progress percentage (0.0 to 1.0) +}; + +/** + * Maps between CrossPoint and KOReader position formats. + * + * CrossPoint tracks position as (spineIndex, pageNumber). + * KOReader uses XPath-like strings + percentage. + * + * Since CrossPoint discards HTML structure during parsing, we generate + * synthetic XPath strings based on spine index, using percentage as the + * primary sync mechanism. + */ +class ProgressMapper { + public: + /** + * Convert CrossPoint position to KOReader format. + * + * @param epub The EPUB book + * @param pos CrossPoint position + * @return KOReader position + */ + static KOReaderPosition toKOReader(const std::shared_ptr& epub, const CrossPointPosition& pos); + + /** + * Convert KOReader position to CrossPoint format. + * + * Note: The returned pageNumber may be approximate since different + * rendering settings produce different page counts. + * + * @param epub The EPUB book + * @param koPos KOReader position + * @param totalPagesInSpine Total pages in the target spine item (for page estimation) + * @return CrossPoint position + */ + static CrossPointPosition toCrossPoint(const std::shared_ptr& epub, const KOReaderPosition& koPos, + int totalPagesInSpine = 0); + + private: + /** + * Generate XPath for KOReader compatibility. + * Format: /body/DocFragment[spineIndex+1]/body/p[estimatedParagraph] + * Paragraph is estimated based on page position within the chapter. + */ + static std::string generateXPath(int spineIndex, int pageNumber, int totalPages); + + /** + * Parse DocFragment index from XPath string. + * Returns -1 if not found. + */ + static int parseDocFragmentIndex(const std::string& xpath); +}; diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 2eeba80f..07b5b22a 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -118,9 +118,11 @@ void EpubReaderActivity::loop() { if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { // Don't start activity transition while rendering xSemaphoreTake(renderingMutex, portMAX_DELAY); + const int currentPage = section ? section->currentPage : 0; + const int totalPages = section ? section->pageCount : 0; exitActivity(); enterNewActivity(new EpubReaderChapterSelectionActivity( - this->renderer, this->mappedInput, epub, currentSpineIndex, + this->renderer, this->mappedInput, epub, epub->getPath(), currentSpineIndex, currentPage, totalPages, [this] { exitActivity(); updateRequired = true; @@ -133,6 +135,16 @@ void EpubReaderActivity::loop() { } exitActivity(); updateRequired = true; + }, + [this](const int newSpineIndex, const int newPage) { + // Handle sync position + if (currentSpineIndex != newSpineIndex || (section && section->currentPage != newPage)) { + currentSpineIndex = newSpineIndex; + nextPageNumber = newPage; + section.reset(); + } + exitActivity(); + updateRequired = true; })); xSemaphoreGive(renderingMutex); } @@ -430,11 +442,13 @@ void EpubReaderActivity::renderStatusBar(const int orientedMarginRight, const in if (showProgress) { // Calculate progress in book const float sectionChapterProg = static_cast(section->currentPage) / section->pageCount; - const uint8_t bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg); + const float bookProgress = epub->calculateProgress(currentSpineIndex, sectionChapterProg) * 100; // Right aligned text for progress counter - const std::string progress = std::to_string(section->currentPage + 1) + "/" + std::to_string(section->pageCount) + - " " + std::to_string(bookProgress) + "%"; + char progressStr[32]; + snprintf(progressStr, sizeof(progressStr), "%d/%d %.1f%%", section->currentPage + 1, section->pageCount, + bookProgress); + const std::string progress = progressStr; progressTextWidth = renderer.getTextWidth(SMALL_FONT_ID, progress.c_str()); renderer.drawText(SMALL_FONT_ID, renderer.getScreenWidth() - orientedMarginRight - progressTextWidth, textY, progress.c_str()); diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index 8f3ecb80..f9a1aa69 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -2,6 +2,8 @@ #include +#include "KOReaderCredentialStore.h" +#include "KOReaderSyncActivity.h" #include "MappedInputManager.h" #include "fontIds.h" @@ -10,6 +12,26 @@ namespace { constexpr int SKIP_PAGE_MS = 700; } // namespace +bool EpubReaderChapterSelectionActivity::hasSyncOption() const { return KOREADER_STORE.hasCredentials(); } + +int EpubReaderChapterSelectionActivity::getTotalItems() const { + // Add 2 for sync options (top and bottom) if credentials are configured + const int syncCount = hasSyncOption() ? 2 : 0; + return epub->getTocItemsCount() + syncCount; +} + +bool EpubReaderChapterSelectionActivity::isSyncItem(int index) const { + if (!hasSyncOption()) return false; + // First item and last item are sync options + return index == 0 || index == getTotalItems() - 1; +} + +int EpubReaderChapterSelectionActivity::tocIndexFromItemIndex(int itemIndex) const { + // Account for the sync option at the top + const int offset = hasSyncOption() ? 1 : 0; + return itemIndex - offset; +} + int EpubReaderChapterSelectionActivity::getPageItems() const { // Layout constants used in renderScreen constexpr int startY = 60; @@ -34,17 +56,21 @@ void EpubReaderChapterSelectionActivity::taskTrampoline(void* param) { } void EpubReaderChapterSelectionActivity::onEnter() { - Activity::onEnter(); + ActivityWithSubactivity::onEnter(); if (!epub) { return; } renderingMutex = xSemaphoreCreateMutex(); + + // Account for sync option offset when finding current TOC index + const int syncOffset = hasSyncOption() ? 1 : 0; selectorIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); if (selectorIndex == -1) { selectorIndex = 0; } + selectorIndex += syncOffset; // Offset for top sync option // Trigger first update updateRequired = true; @@ -57,7 +83,7 @@ void EpubReaderChapterSelectionActivity::onEnter() { } void EpubReaderChapterSelectionActivity::onExit() { - Activity::onExit(); + ActivityWithSubactivity::onExit(); // Wait until not rendering to delete task to avoid killing mid-instruction to EPD xSemaphoreTake(renderingMutex, portMAX_DELAY); @@ -69,7 +95,30 @@ void EpubReaderChapterSelectionActivity::onExit() { renderingMutex = nullptr; } +void EpubReaderChapterSelectionActivity::launchSyncActivity() { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + exitActivity(); + enterNewActivity(new KOReaderSyncActivity( + renderer, mappedInput, epub, epubPath, currentSpineIndex, currentPage, totalPagesInSpine, + [this]() { + // On cancel + exitActivity(); + updateRequired = true; + }, + [this](int newSpineIndex, int newPage) { + // On sync complete + exitActivity(); + onSyncPosition(newSpineIndex, newPage); + })); + xSemaphoreGive(renderingMutex); +} + void EpubReaderChapterSelectionActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + const bool prevReleased = mappedInput.wasReleased(MappedInputManager::Button::Up) || mappedInput.wasReleased(MappedInputManager::Button::Left); const bool nextReleased = mappedInput.wasReleased(MappedInputManager::Button::Down) || @@ -77,9 +126,18 @@ void EpubReaderChapterSelectionActivity::loop() { const bool skipPage = mappedInput.getHeldTime() > SKIP_PAGE_MS; const int pageItems = getPageItems(); + const int totalItems = getTotalItems(); if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { - const auto newSpineIndex = epub->getSpineIndexForTocIndex(selectorIndex); + // Check if sync option is selected (first or last item) + if (isSyncItem(selectorIndex)) { + launchSyncActivity(); + return; + } + + // Get TOC index (account for top sync offset) + const int tocIndex = tocIndexFromItemIndex(selectorIndex); + const auto newSpineIndex = epub->getSpineIndexForTocIndex(tocIndex); if (newSpineIndex == -1) { onGoBack(); } else { @@ -89,17 +147,16 @@ void EpubReaderChapterSelectionActivity::loop() { onGoBack(); } else if (prevReleased) { if (skipPage) { - selectorIndex = - ((selectorIndex / pageItems - 1) * pageItems + epub->getTocItemsCount()) % epub->getTocItemsCount(); + selectorIndex = ((selectorIndex / pageItems - 1) * pageItems + totalItems) % totalItems; } else { - selectorIndex = (selectorIndex + epub->getTocItemsCount() - 1) % epub->getTocItemsCount(); + selectorIndex = (selectorIndex + totalItems - 1) % totalItems; } updateRequired = true; } else if (nextReleased) { if (skipPage) { - selectorIndex = ((selectorIndex / pageItems + 1) * pageItems) % epub->getTocItemsCount(); + selectorIndex = ((selectorIndex / pageItems + 1) * pageItems) % totalItems; } else { - selectorIndex = (selectorIndex + 1) % epub->getTocItemsCount(); + selectorIndex = (selectorIndex + 1) % totalItems; } updateRequired = true; } @@ -107,7 +164,7 @@ void EpubReaderChapterSelectionActivity::loop() { void EpubReaderChapterSelectionActivity::displayTaskLoop() { while (true) { - if (updateRequired) { + if (updateRequired && !subActivity) { updateRequired = false; xSemaphoreTake(renderingMutex, portMAX_DELAY); renderScreen(); @@ -122,6 +179,7 @@ void EpubReaderChapterSelectionActivity::renderScreen() { const auto pageWidth = renderer.getScreenWidth(); const int pageItems = getPageItems(); + const int totalItems = getTotalItems(); const std::string title = renderer.truncatedText(UI_12_FONT_ID, epub->getTitle().c_str(), pageWidth - 40, EpdFontFamily::BOLD); @@ -129,11 +187,20 @@ void EpubReaderChapterSelectionActivity::renderScreen() { const auto pageStartIndex = selectorIndex / pageItems * pageItems; renderer.fillRect(0, 60 + (selectorIndex % pageItems) * 30 - 2, pageWidth - 1, 30); - for (int tocIndex = pageStartIndex; tocIndex < epub->getTocItemsCount() && tocIndex < pageStartIndex + pageItems; - tocIndex++) { - auto item = epub->getTocItem(tocIndex); - renderer.drawText(UI_10_FONT_ID, 20 + (item.level - 1) * 15, 60 + (tocIndex % pageItems) * 30, item.title.c_str(), - tocIndex != selectorIndex); + + for (int itemIndex = pageStartIndex; itemIndex < totalItems && itemIndex < pageStartIndex + pageItems; itemIndex++) { + const int displayY = 60 + (itemIndex % pageItems) * 30; + const bool isSelected = (itemIndex == selectorIndex); + + if (isSyncItem(itemIndex)) { + // Draw sync option (at top or bottom) + renderer.drawText(UI_10_FONT_ID, 20, displayY, ">> Sync Progress", !isSelected); + } else { + // Draw TOC item (account for top sync offset) + const int tocIndex = tocIndexFromItemIndex(itemIndex); + auto item = epub->getTocItem(tocIndex); + renderer.drawText(UI_10_FONT_ID, 20 + (item.level - 1) * 15, displayY, item.title.c_str(), !isSelected); + } } const auto labels = mappedInput.mapLabels("« Back", "Select", "Up", "Down"); diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.h b/src/activities/reader/EpubReaderChapterSelectionActivity.h index cf3f1905..255f0cea 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.h +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.h @@ -6,36 +6,59 @@ #include -#include "../Activity.h" +#include "../ActivityWithSubactivity.h" -class EpubReaderChapterSelectionActivity final : public Activity { +class EpubReaderChapterSelectionActivity final : public ActivityWithSubactivity { std::shared_ptr epub; + std::string epubPath; TaskHandle_t displayTaskHandle = nullptr; SemaphoreHandle_t renderingMutex = nullptr; int currentSpineIndex = 0; + int currentPage = 0; + int totalPagesInSpine = 0; int selectorIndex = 0; bool updateRequired = false; const std::function onGoBack; const std::function onSelectSpineIndex; + const std::function onSyncPosition; // Number of items that fit on a page, derived from logical screen height. // This adapts automatically when switching between portrait and landscape. int getPageItems() const; + // Total items including sync options (top and bottom) + int getTotalItems() const; + + // Check if sync option is available (credentials configured) + bool hasSyncOption() const; + + // Check if given item index is a sync option (first or last) + bool isSyncItem(int index) const; + + // Convert item index to TOC index (accounting for top sync option offset) + int tocIndexFromItemIndex(int itemIndex) const; + static void taskTrampoline(void* param); [[noreturn]] void displayTaskLoop(); void renderScreen(); + void launchSyncActivity(); public: explicit EpubReaderChapterSelectionActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, - const std::shared_ptr& epub, const int currentSpineIndex, - const std::function& onGoBack, - const std::function& onSelectSpineIndex) - : Activity("EpubReaderChapterSelection", renderer, mappedInput), + const std::shared_ptr& epub, const std::string& epubPath, + const int currentSpineIndex, const int currentPage, + const int totalPagesInSpine, const std::function& onGoBack, + const std::function& onSelectSpineIndex, + const std::function& onSyncPosition) + : ActivityWithSubactivity("EpubReaderChapterSelection", renderer, mappedInput), epub(epub), + epubPath(epubPath), currentSpineIndex(currentSpineIndex), + currentPage(currentPage), + totalPagesInSpine(totalPagesInSpine), onGoBack(onGoBack), - onSelectSpineIndex(onSelectSpineIndex) {} + onSelectSpineIndex(onSelectSpineIndex), + onSyncPosition(onSyncPosition) {} void onEnter() override; void onExit() override; void loop() override; diff --git a/src/activities/reader/KOReaderSyncActivity.cpp b/src/activities/reader/KOReaderSyncActivity.cpp new file mode 100644 index 00000000..4a85f23d --- /dev/null +++ b/src/activities/reader/KOReaderSyncActivity.cpp @@ -0,0 +1,439 @@ +#include "KOReaderSyncActivity.h" + +#include +#include +#include + +#include "KOReaderCredentialStore.h" +#include "KOReaderDocumentId.h" +#include "MappedInputManager.h" +#include "activities/network/WifiSelectionActivity.h" +#include "fontIds.h" + +namespace { +void syncTimeWithNTP() { + // Stop SNTP if already running (can't reconfigure while running) + if (esp_sntp_enabled()) { + esp_sntp_stop(); + } + + // Configure SNTP + esp_sntp_setoperatingmode(ESP_SNTP_OPMODE_POLL); + esp_sntp_setservername(0, "pool.ntp.org"); + esp_sntp_init(); + + // Wait for time to sync (with timeout) + int retry = 0; + const int maxRetries = 50; // 5 seconds max + while (sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED && retry < maxRetries) { + vTaskDelay(100 / portTICK_PERIOD_MS); + retry++; + } + + if (retry < maxRetries) { + Serial.printf("[%lu] [KOSync] NTP time synced\n", millis()); + } else { + Serial.printf("[%lu] [KOSync] NTP sync timeout, using fallback\n", millis()); + } +} +} // namespace + +void KOReaderSyncActivity::taskTrampoline(void* param) { + auto* self = static_cast(param); + self->displayTaskLoop(); +} + +void KOReaderSyncActivity::onWifiSelectionComplete(const bool success) { + exitActivity(); + + if (!success) { + Serial.printf("[%lu] [KOSync] WiFi connection failed, exiting\n", millis()); + onCancel(); + return; + } + + Serial.printf("[%lu] [KOSync] WiFi connected, starting sync\n", millis()); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNCING; + statusMessage = "Syncing time..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + + // Sync time with NTP before making API requests + syncTimeWithNTP(); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + statusMessage = "Calculating document hash..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + + performSync(); +} + +void KOReaderSyncActivity::performSync() { + // Calculate document hash based on user's preferred method + if (KOREADER_STORE.getMatchMethod() == DocumentMatchMethod::FILENAME) { + documentHash = KOReaderDocumentId::calculateFromFilename(epubPath); + } else { + documentHash = KOReaderDocumentId::calculate(epubPath); + } + if (documentHash.empty()) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNC_FAILED; + statusMessage = "Failed to calculate document hash"; + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + Serial.printf("[%lu] [KOSync] Document hash: %s\n", millis(), documentHash.c_str()); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + statusMessage = "Fetching remote progress..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + vTaskDelay(10 / portTICK_PERIOD_MS); + + // Fetch remote progress + const auto result = KOReaderSyncClient::getProgress(documentHash, remoteProgress); + + if (result == KOReaderSyncClient::NOT_FOUND) { + // No remote progress - offer to upload + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = NO_REMOTE_PROGRESS; + hasRemoteProgress = false; + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + if (result != KOReaderSyncClient::OK) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNC_FAILED; + statusMessage = KOReaderSyncClient::errorString(result); + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + // Convert remote progress to CrossPoint position + hasRemoteProgress = true; + KOReaderPosition koPos = {remoteProgress.progress, remoteProgress.percentage}; + remotePosition = ProgressMapper::toCrossPoint(epub, koPos, totalPagesInSpine); + + // Calculate local progress in KOReader format (for display) + CrossPointPosition localPos = {currentSpineIndex, currentPage, totalPagesInSpine}; + localProgress = ProgressMapper::toKOReader(epub, localPos); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SHOWING_RESULT; + selectedOption = 0; // Default to "Apply" + xSemaphoreGive(renderingMutex); + updateRequired = true; +} + +void KOReaderSyncActivity::performUpload() { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = UPLOADING; + statusMessage = "Uploading progress..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + vTaskDelay(10 / portTICK_PERIOD_MS); + + // Convert current position to KOReader format + CrossPointPosition localPos = {currentSpineIndex, currentPage, totalPagesInSpine}; + KOReaderPosition koPos = ProgressMapper::toKOReader(epub, localPos); + + KOReaderProgress progress; + progress.document = documentHash; + progress.progress = koPos.xpath; + progress.percentage = koPos.percentage; + + const auto result = KOReaderSyncClient::updateProgress(progress); + + if (result != KOReaderSyncClient::OK) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = SYNC_FAILED; + statusMessage = KOReaderSyncClient::errorString(result); + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = UPLOAD_COMPLETE; + xSemaphoreGive(renderingMutex); + updateRequired = true; +} + +void KOReaderSyncActivity::onEnter() { + ActivityWithSubactivity::onEnter(); + + renderingMutex = xSemaphoreCreateMutex(); + + xTaskCreate(&KOReaderSyncActivity::taskTrampoline, "KOSyncTask", + 4096, // Stack size (larger for network operations) + this, // Parameters + 1, // Priority + &displayTaskHandle // Task handle + ); + + // Check for credentials first + if (!KOREADER_STORE.hasCredentials()) { + state = NO_CREDENTIALS; + updateRequired = true; + return; + } + + // Turn on WiFi + Serial.printf("[%lu] [KOSync] Turning on WiFi...\n", millis()); + WiFi.mode(WIFI_STA); + + // Check if already connected + if (WiFi.status() == WL_CONNECTED) { + Serial.printf("[%lu] [KOSync] Already connected to WiFi\n", millis()); + state = SYNCING; + statusMessage = "Syncing time..."; + updateRequired = true; + + // Perform sync directly (will be handled in loop) + xTaskCreate( + [](void* param) { + auto* self = static_cast(param); + // Sync time first + syncTimeWithNTP(); + xSemaphoreTake(self->renderingMutex, portMAX_DELAY); + self->statusMessage = "Calculating document hash..."; + xSemaphoreGive(self->renderingMutex); + self->updateRequired = true; + self->performSync(); + vTaskDelete(nullptr); + }, + "SyncTask", 4096, this, 1, nullptr); + return; + } + + // Launch WiFi selection subactivity + Serial.printf("[%lu] [KOSync] Launching WifiSelectionActivity...\n", millis()); + enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, + [this](const bool connected) { onWifiSelectionComplete(connected); })); +} + +void KOReaderSyncActivity::onExit() { + ActivityWithSubactivity::onExit(); + + // Turn off wifi + WiFi.disconnect(false); + delay(100); + WiFi.mode(WIFI_OFF); + delay(100); + + // Wait until not rendering to delete task + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (displayTaskHandle) { + vTaskDelete(displayTaskHandle); + displayTaskHandle = nullptr; + } + vSemaphoreDelete(renderingMutex); + renderingMutex = nullptr; +} + +void KOReaderSyncActivity::displayTaskLoop() { + while (true) { + if (updateRequired) { + updateRequired = false; + xSemaphoreTake(renderingMutex, portMAX_DELAY); + render(); + xSemaphoreGive(renderingMutex); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void KOReaderSyncActivity::render() { + if (subActivity) { + return; + } + + const auto pageWidth = renderer.getScreenWidth(); + + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Sync", true, EpdFontFamily::BOLD); + + if (state == NO_CREDENTIALS) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "No credentials configured", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, "Set up KOReader account in Settings"); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == SYNCING || state == UPLOADING) { + renderer.drawCenteredText(UI_10_FONT_ID, 300, statusMessage.c_str(), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + + if (state == SHOWING_RESULT) { + // Show comparison + renderer.drawCenteredText(UI_10_FONT_ID, 120, "Progress found!", true, EpdFontFamily::BOLD); + + // Get chapter names from TOC + const int remoteTocIndex = epub->getTocIndexForSpineIndex(remotePosition.spineIndex); + const int localTocIndex = epub->getTocIndexForSpineIndex(currentSpineIndex); + const std::string remoteChapter = (remoteTocIndex >= 0) + ? epub->getTocItem(remoteTocIndex).title + : ("Section " + std::to_string(remotePosition.spineIndex + 1)); + const std::string localChapter = (localTocIndex >= 0) ? epub->getTocItem(localTocIndex).title + : ("Section " + std::to_string(currentSpineIndex + 1)); + + // Remote progress - chapter and page + renderer.drawText(UI_10_FONT_ID, 20, 160, "Remote:", true); + char remoteChapterStr[128]; + snprintf(remoteChapterStr, sizeof(remoteChapterStr), " %s", remoteChapter.c_str()); + renderer.drawText(UI_10_FONT_ID, 20, 185, remoteChapterStr); + char remotePageStr[64]; + snprintf(remotePageStr, sizeof(remotePageStr), " Page %d, %.2f%% overall", remotePosition.pageNumber + 1, + remoteProgress.percentage * 100); + renderer.drawText(UI_10_FONT_ID, 20, 210, remotePageStr); + + if (!remoteProgress.device.empty()) { + char deviceStr[64]; + snprintf(deviceStr, sizeof(deviceStr), " From: %s", remoteProgress.device.c_str()); + renderer.drawText(UI_10_FONT_ID, 20, 235, deviceStr); + } + + // Local progress - chapter and page + renderer.drawText(UI_10_FONT_ID, 20, 270, "Local:", true); + char localChapterStr[128]; + snprintf(localChapterStr, sizeof(localChapterStr), " %s", localChapter.c_str()); + renderer.drawText(UI_10_FONT_ID, 20, 295, localChapterStr); + char localPageStr[64]; + snprintf(localPageStr, sizeof(localPageStr), " Page %d/%d, %.2f%% overall", currentPage + 1, totalPagesInSpine, + localProgress.percentage * 100); + renderer.drawText(UI_10_FONT_ID, 20, 320, localPageStr); + + // Options + const int optionY = 350; + const int optionHeight = 30; + + // Apply option + if (selectedOption == 0) { + renderer.fillRect(0, optionY - 2, pageWidth - 1, optionHeight); + } + renderer.drawText(UI_10_FONT_ID, 20, optionY, "Apply remote progress", selectedOption != 0); + + // Upload option + if (selectedOption == 1) { + renderer.fillRect(0, optionY + optionHeight - 2, pageWidth - 1, optionHeight); + } + renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight, "Upload local progress", selectedOption != 1); + + // Cancel option + if (selectedOption == 2) { + renderer.fillRect(0, optionY + optionHeight * 2 - 2, pageWidth - 1, optionHeight); + } + renderer.drawText(UI_10_FONT_ID, 20, optionY + optionHeight * 2, "Cancel", selectedOption != 2); + + const auto labels = mappedInput.mapLabels("", "Select", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == NO_REMOTE_PROGRESS) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "No remote progress found", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, "Upload current position?"); + + const auto labels = mappedInput.mapLabels("Cancel", "Upload", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == UPLOAD_COMPLETE) { + renderer.drawCenteredText(UI_10_FONT_ID, 300, "Progress uploaded!", true, EpdFontFamily::BOLD); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == SYNC_FAILED) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "Sync failed", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, statusMessage.c_str()); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } +} + +void KOReaderSyncActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + + if (state == NO_CREDENTIALS || state == SYNC_FAILED || state == UPLOAD_COMPLETE) { + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onCancel(); + } + return; + } + + if (state == SHOWING_RESULT) { + // Navigate options + if (mappedInput.wasPressed(MappedInputManager::Button::Up) || + mappedInput.wasPressed(MappedInputManager::Button::Left)) { + selectedOption = (selectedOption + 2) % 3; // Wrap around + updateRequired = true; + } else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || + mappedInput.wasPressed(MappedInputManager::Button::Right)) { + selectedOption = (selectedOption + 1) % 3; + updateRequired = true; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + if (selectedOption == 0) { + // Apply remote progress + onSyncComplete(remotePosition.spineIndex, remotePosition.pageNumber); + } else if (selectedOption == 1) { + // Upload local progress + performUpload(); + } else { + // Cancel + onCancel(); + } + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onCancel(); + } + return; + } + + if (state == NO_REMOTE_PROGRESS) { + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + // Calculate hash if not done yet + if (documentHash.empty()) { + if (KOREADER_STORE.getMatchMethod() == DocumentMatchMethod::FILENAME) { + documentHash = KOReaderDocumentId::calculateFromFilename(epubPath); + } else { + documentHash = KOReaderDocumentId::calculate(epubPath); + } + } + performUpload(); + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onCancel(); + } + return; + } +} diff --git a/src/activities/reader/KOReaderSyncActivity.h b/src/activities/reader/KOReaderSyncActivity.h new file mode 100644 index 00000000..dd61ffa5 --- /dev/null +++ b/src/activities/reader/KOReaderSyncActivity.h @@ -0,0 +1,98 @@ +#pragma once +#include +#include +#include +#include + +#include +#include + +#include "KOReaderSyncClient.h" +#include "ProgressMapper.h" +#include "activities/ActivityWithSubactivity.h" + +/** + * Activity for syncing reading progress with KOReader sync server. + * + * Flow: + * 1. Connect to WiFi (if not connected) + * 2. Calculate document hash + * 3. Fetch remote progress + * 4. Show comparison and options (Apply/Upload/Cancel) + * 5. Apply or upload progress + */ +class KOReaderSyncActivity final : public ActivityWithSubactivity { + public: + using OnCancelCallback = std::function; + using OnSyncCompleteCallback = std::function; + + explicit KOReaderSyncActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::shared_ptr& epub, const std::string& epubPath, int currentSpineIndex, + int currentPage, int totalPagesInSpine, OnCancelCallback onCancel, + OnSyncCompleteCallback onSyncComplete) + : ActivityWithSubactivity("KOReaderSync", renderer, mappedInput), + epub(epub), + epubPath(epubPath), + currentSpineIndex(currentSpineIndex), + currentPage(currentPage), + totalPagesInSpine(totalPagesInSpine), + remoteProgress{}, + remotePosition{}, + localProgress{}, + onCancel(std::move(onCancel)), + onSyncComplete(std::move(onSyncComplete)) {} + + void onEnter() override; + void onExit() override; + void loop() override; + bool preventAutoSleep() override { return state == CONNECTING || state == SYNCING; } + + private: + enum State { + WIFI_SELECTION, + CONNECTING, + SYNCING, + SHOWING_RESULT, + UPLOADING, + UPLOAD_COMPLETE, + NO_REMOTE_PROGRESS, + SYNC_FAILED, + NO_CREDENTIALS + }; + + std::shared_ptr epub; + std::string epubPath; + int currentSpineIndex; + int currentPage; + int totalPagesInSpine; + + TaskHandle_t displayTaskHandle = nullptr; + SemaphoreHandle_t renderingMutex = nullptr; + bool updateRequired = false; + + State state = WIFI_SELECTION; + std::string statusMessage; + std::string documentHash; + + // Remote progress data + bool hasRemoteProgress = false; + KOReaderProgress remoteProgress; + CrossPointPosition remotePosition; + + // Local progress as KOReader format (for display) + KOReaderPosition localProgress; + + // Selection in result screen (0=Apply, 1=Upload, 2=Cancel) + int selectedOption = 0; + + OnCancelCallback onCancel; + OnSyncCompleteCallback onSyncComplete; + + void onWifiSelectionComplete(bool success); + void performSync(); + void performUpload(); + + static void taskTrampoline(void* param); + [[noreturn]] void displayTaskLoop(); + void render(); +}; diff --git a/src/activities/settings/KOReaderAuthActivity.cpp b/src/activities/settings/KOReaderAuthActivity.cpp new file mode 100644 index 00000000..8681812f --- /dev/null +++ b/src/activities/settings/KOReaderAuthActivity.cpp @@ -0,0 +1,167 @@ +#include "KOReaderAuthActivity.h" + +#include +#include + +#include "KOReaderCredentialStore.h" +#include "KOReaderSyncClient.h" +#include "MappedInputManager.h" +#include "activities/network/WifiSelectionActivity.h" +#include "fontIds.h" + +void KOReaderAuthActivity::taskTrampoline(void* param) { + auto* self = static_cast(param); + self->displayTaskLoop(); +} + +void KOReaderAuthActivity::onWifiSelectionComplete(const bool success) { + exitActivity(); + + if (!success) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = FAILED; + errorMessage = "WiFi connection failed"; + xSemaphoreGive(renderingMutex); + updateRequired = true; + return; + } + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + state = AUTHENTICATING; + statusMessage = "Authenticating..."; + xSemaphoreGive(renderingMutex); + updateRequired = true; + + performAuthentication(); +} + +void KOReaderAuthActivity::performAuthentication() { + const auto result = KOReaderSyncClient::authenticate(); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (result == KOReaderSyncClient::OK) { + state = SUCCESS; + statusMessage = "Successfully authenticated!"; + } else { + state = FAILED; + errorMessage = KOReaderSyncClient::errorString(result); + } + xSemaphoreGive(renderingMutex); + updateRequired = true; +} + +void KOReaderAuthActivity::onEnter() { + ActivityWithSubactivity::onEnter(); + + renderingMutex = xSemaphoreCreateMutex(); + + xTaskCreate(&KOReaderAuthActivity::taskTrampoline, "KOAuthTask", + 4096, // Stack size + this, // Parameters + 1, // Priority + &displayTaskHandle // Task handle + ); + + // Turn on WiFi + WiFi.mode(WIFI_STA); + + // Check if already connected + if (WiFi.status() == WL_CONNECTED) { + state = AUTHENTICATING; + statusMessage = "Authenticating..."; + updateRequired = true; + + // Perform authentication in a separate task + xTaskCreate( + [](void* param) { + auto* self = static_cast(param); + self->performAuthentication(); + vTaskDelete(nullptr); + }, + "AuthTask", 4096, this, 1, nullptr); + return; + } + + // Launch WiFi selection + enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, + [this](const bool connected) { onWifiSelectionComplete(connected); })); +} + +void KOReaderAuthActivity::onExit() { + ActivityWithSubactivity::onExit(); + + // Turn off wifi + WiFi.disconnect(false); + delay(100); + WiFi.mode(WIFI_OFF); + delay(100); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (displayTaskHandle) { + vTaskDelete(displayTaskHandle); + displayTaskHandle = nullptr; + } + vSemaphoreDelete(renderingMutex); + renderingMutex = nullptr; +} + +void KOReaderAuthActivity::displayTaskLoop() { + while (true) { + if (updateRequired && !subActivity) { + updateRequired = false; + xSemaphoreTake(renderingMutex, portMAX_DELAY); + render(); + xSemaphoreGive(renderingMutex); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void KOReaderAuthActivity::render() { + if (subActivity) { + return; + } + + renderer.clearScreen(); + renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Auth", true, EpdFontFamily::BOLD); + + if (state == AUTHENTICATING) { + renderer.drawCenteredText(UI_10_FONT_ID, 300, statusMessage.c_str(), true, EpdFontFamily::BOLD); + renderer.displayBuffer(); + return; + } + + if (state == SUCCESS) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "Success!", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, "KOReader sync is ready to use"); + + const auto labels = mappedInput.mapLabels("Done", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } + + if (state == FAILED) { + renderer.drawCenteredText(UI_10_FONT_ID, 280, "Authentication Failed", true, EpdFontFamily::BOLD); + renderer.drawCenteredText(UI_10_FONT_ID, 320, errorMessage.c_str()); + + const auto labels = mappedInput.mapLabels("Back", "", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + renderer.displayBuffer(); + return; + } +} + +void KOReaderAuthActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + + if (state == SUCCESS || state == FAILED) { + if (mappedInput.wasPressed(MappedInputManager::Button::Back) || + mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + onComplete(); + } + } +} diff --git a/src/activities/settings/KOReaderAuthActivity.h b/src/activities/settings/KOReaderAuthActivity.h new file mode 100644 index 00000000..a6ed0d3e --- /dev/null +++ b/src/activities/settings/KOReaderAuthActivity.h @@ -0,0 +1,44 @@ +#pragma once +#include +#include +#include + +#include + +#include "activities/ActivityWithSubactivity.h" + +/** + * Activity for testing KOReader credentials. + * Connects to WiFi and authenticates with the KOReader sync server. + */ +class KOReaderAuthActivity final : public ActivityWithSubactivity { + public: + explicit KOReaderAuthActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::function& onComplete) + : ActivityWithSubactivity("KOReaderAuth", renderer, mappedInput), onComplete(onComplete) {} + + void onEnter() override; + void onExit() override; + void loop() override; + bool preventAutoSleep() override { return state == CONNECTING || state == AUTHENTICATING; } + + private: + enum State { WIFI_SELECTION, CONNECTING, AUTHENTICATING, SUCCESS, FAILED }; + + TaskHandle_t displayTaskHandle = nullptr; + SemaphoreHandle_t renderingMutex = nullptr; + bool updateRequired = false; + + State state = WIFI_SELECTION; + std::string statusMessage; + std::string errorMessage; + + const std::function onComplete; + + void onWifiSelectionComplete(bool success); + void performAuthentication(); + + static void taskTrampoline(void* param); + [[noreturn]] void displayTaskLoop(); + void render(); +}; diff --git a/src/activities/settings/KOReaderSettingsActivity.cpp b/src/activities/settings/KOReaderSettingsActivity.cpp new file mode 100644 index 00000000..6eb22c8e --- /dev/null +++ b/src/activities/settings/KOReaderSettingsActivity.cpp @@ -0,0 +1,213 @@ +#include "KOReaderSettingsActivity.h" + +#include + +#include + +#include "KOReaderAuthActivity.h" +#include "KOReaderCredentialStore.h" +#include "MappedInputManager.h" +#include "activities/util/KeyboardEntryActivity.h" +#include "fontIds.h" + +namespace { +constexpr int MENU_ITEMS = 5; +const char* menuNames[MENU_ITEMS] = {"Username", "Password", "Sync Server URL", "Document Matching", "Authenticate"}; +} // namespace + +void KOReaderSettingsActivity::taskTrampoline(void* param) { + auto* self = static_cast(param); + self->displayTaskLoop(); +} + +void KOReaderSettingsActivity::onEnter() { + ActivityWithSubactivity::onEnter(); + + renderingMutex = xSemaphoreCreateMutex(); + selectedIndex = 0; + updateRequired = true; + + xTaskCreate(&KOReaderSettingsActivity::taskTrampoline, "KOReaderSettingsTask", + 4096, // Stack size + this, // Parameters + 1, // Priority + &displayTaskHandle // Task handle + ); +} + +void KOReaderSettingsActivity::onExit() { + ActivityWithSubactivity::onExit(); + + xSemaphoreTake(renderingMutex, portMAX_DELAY); + if (displayTaskHandle) { + vTaskDelete(displayTaskHandle); + displayTaskHandle = nullptr; + } + vSemaphoreDelete(renderingMutex); + renderingMutex = nullptr; +} + +void KOReaderSettingsActivity::loop() { + if (subActivity) { + subActivity->loop(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { + onBack(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { + handleSelection(); + return; + } + + if (mappedInput.wasPressed(MappedInputManager::Button::Up) || + mappedInput.wasPressed(MappedInputManager::Button::Left)) { + selectedIndex = (selectedIndex + MENU_ITEMS - 1) % MENU_ITEMS; + updateRequired = true; + } else if (mappedInput.wasPressed(MappedInputManager::Button::Down) || + mappedInput.wasPressed(MappedInputManager::Button::Right)) { + selectedIndex = (selectedIndex + 1) % MENU_ITEMS; + updateRequired = true; + } +} + +void KOReaderSettingsActivity::handleSelection() { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + + if (selectedIndex == 0) { + // Username + exitActivity(); + enterNewActivity(new KeyboardEntryActivity( + renderer, mappedInput, "KOReader Username", KOREADER_STORE.getUsername(), 10, + 64, // maxLength + false, // not password + [this](const std::string& username) { + KOREADER_STORE.setCredentials(username, KOREADER_STORE.getPassword()); + KOREADER_STORE.saveToFile(); + exitActivity(); + updateRequired = true; + }, + [this]() { + exitActivity(); + updateRequired = true; + })); + } else if (selectedIndex == 1) { + // Password + exitActivity(); + enterNewActivity(new KeyboardEntryActivity( + renderer, mappedInput, "KOReader Password", KOREADER_STORE.getPassword(), 10, + 64, // maxLength + false, // show characters + [this](const std::string& password) { + KOREADER_STORE.setCredentials(KOREADER_STORE.getUsername(), password); + KOREADER_STORE.saveToFile(); + exitActivity(); + updateRequired = true; + }, + [this]() { + exitActivity(); + updateRequired = true; + })); + } else if (selectedIndex == 2) { + // Sync Server URL - prefill with https:// if empty to save typing + const std::string currentUrl = KOREADER_STORE.getServerUrl(); + const std::string prefillUrl = currentUrl.empty() ? "https://" : currentUrl; + exitActivity(); + enterNewActivity(new KeyboardEntryActivity( + renderer, mappedInput, "Sync Server URL", prefillUrl, 10, + 128, // maxLength - URLs can be long + false, // not password + [this](const std::string& url) { + // Clear if user just left the prefilled https:// + const std::string urlToSave = (url == "https://" || url == "http://") ? "" : url; + KOREADER_STORE.setServerUrl(urlToSave); + KOREADER_STORE.saveToFile(); + exitActivity(); + updateRequired = true; + }, + [this]() { + exitActivity(); + updateRequired = true; + })); + } else if (selectedIndex == 3) { + // Document Matching - toggle between Filename and Binary + const auto current = KOREADER_STORE.getMatchMethod(); + const auto newMethod = + (current == DocumentMatchMethod::FILENAME) ? DocumentMatchMethod::BINARY : DocumentMatchMethod::FILENAME; + KOREADER_STORE.setMatchMethod(newMethod); + KOREADER_STORE.saveToFile(); + updateRequired = true; + } else if (selectedIndex == 4) { + // Authenticate + if (!KOREADER_STORE.hasCredentials()) { + // Can't authenticate without credentials - just show message briefly + xSemaphoreGive(renderingMutex); + return; + } + exitActivity(); + enterNewActivity(new KOReaderAuthActivity(renderer, mappedInput, [this] { + exitActivity(); + updateRequired = true; + })); + } + + xSemaphoreGive(renderingMutex); +} + +void KOReaderSettingsActivity::displayTaskLoop() { + while (true) { + if (updateRequired && !subActivity) { + updateRequired = false; + xSemaphoreTake(renderingMutex, portMAX_DELAY); + render(); + xSemaphoreGive(renderingMutex); + } + vTaskDelay(10 / portTICK_PERIOD_MS); + } +} + +void KOReaderSettingsActivity::render() { + renderer.clearScreen(); + + const auto pageWidth = renderer.getScreenWidth(); + + // Draw header + renderer.drawCenteredText(UI_12_FONT_ID, 15, "KOReader Sync", true, EpdFontFamily::BOLD); + + // Draw selection highlight + renderer.fillRect(0, 60 + selectedIndex * 30 - 2, pageWidth - 1, 30); + + // Draw menu items + for (int i = 0; i < MENU_ITEMS; i++) { + const int settingY = 60 + i * 30; + const bool isSelected = (i == selectedIndex); + + renderer.drawText(UI_10_FONT_ID, 20, settingY, menuNames[i], !isSelected); + + // Draw status for each item + const char* status = ""; + if (i == 0) { + status = KOREADER_STORE.getUsername().empty() ? "[Not Set]" : "[Set]"; + } else if (i == 1) { + status = KOREADER_STORE.getPassword().empty() ? "[Not Set]" : "[Set]"; + } else if (i == 2) { + status = KOREADER_STORE.getServerUrl().empty() ? "[Not Set]" : "[Set]"; + } else if (i == 3) { + status = KOREADER_STORE.getMatchMethod() == DocumentMatchMethod::FILENAME ? "[Filename]" : "[Binary]"; + } else if (i == 4) { + status = KOREADER_STORE.hasCredentials() ? "" : "[Set credentials first]"; + } + + const auto width = renderer.getTextWidth(UI_10_FONT_ID, status); + renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, status, !isSelected); + } + + // Draw button hints + const auto labels = mappedInput.mapLabels("« Back", "Select", "", ""); + renderer.drawButtonHints(UI_10_FONT_ID, labels.btn1, labels.btn2, labels.btn3, labels.btn4); + + renderer.displayBuffer(); +} diff --git a/src/activities/settings/KOReaderSettingsActivity.h b/src/activities/settings/KOReaderSettingsActivity.h new file mode 100644 index 00000000..2bedf034 --- /dev/null +++ b/src/activities/settings/KOReaderSettingsActivity.h @@ -0,0 +1,36 @@ +#pragma once +#include +#include +#include + +#include + +#include "activities/ActivityWithSubactivity.h" + +/** + * Submenu for KOReader Sync settings. + * Shows username, password, and authenticate options. + */ +class KOReaderSettingsActivity final : public ActivityWithSubactivity { + public: + explicit KOReaderSettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, + const std::function& onBack) + : ActivityWithSubactivity("KOReaderSettings", renderer, mappedInput), onBack(onBack) {} + + void onEnter() override; + void onExit() override; + void loop() override; + + private: + TaskHandle_t displayTaskHandle = nullptr; + SemaphoreHandle_t renderingMutex = nullptr; + bool updateRequired = false; + + int selectedIndex = 0; + const std::function onBack; + + static void taskTrampoline(void* param); + [[noreturn]] void displayTaskLoop(); + void render(); + void handleSelection(); +}; diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index efa0b9e1..08ff6ed5 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -7,13 +7,14 @@ #include "CalibreSettingsActivity.h" #include "CrossPointSettings.h" +#include "KOReaderSettingsActivity.h" #include "MappedInputManager.h" #include "OtaUpdateActivity.h" #include "fontIds.h" // Define the static settings list namespace { -constexpr int settingsCount = 20; +constexpr int settingsCount = 21; const SettingInfo settingsList[settingsCount] = { // Should match with SLEEP_SCREEN_MODE SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}), @@ -41,6 +42,7 @@ const SettingInfo settingsList[settingsCount] = { {"1 min", "5 min", "10 min", "15 min", "30 min"}), SettingInfo::Enum("Refresh Frequency", &CrossPointSettings::refreshFrequency, {"1 page", "5 pages", "10 pages", "15 pages", "30 pages"}), + SettingInfo::Action("KOReader Sync"), SettingInfo::Action("Calibre Settings"), SettingInfo::Action("Check for updates")}; } // namespace @@ -115,7 +117,6 @@ void SettingsActivity::loop() { } void SettingsActivity::toggleCurrentSetting() { - // Validate index if (selectedSettingIndex < 0 || selectedSettingIndex >= settingsCount) { return; } @@ -139,7 +140,15 @@ void SettingsActivity::toggleCurrentSetting() { SETTINGS.*(setting.valuePtr) = currentValue + setting.valueRange.step; } } else if (setting.type == SettingType::ACTION) { - if (strcmp(setting.name, "Calibre Settings") == 0) { + if (strcmp(setting.name, "KOReader Sync") == 0) { + xSemaphoreTake(renderingMutex, portMAX_DELAY); + exitActivity(); + enterNewActivity(new KOReaderSettingsActivity(renderer, mappedInput, [this] { + exitActivity(); + updateRequired = true; + })); + xSemaphoreGive(renderingMutex); + } else if (strcmp(setting.name, "Calibre Settings") == 0) { xSemaphoreTake(renderingMutex, portMAX_DELAY); exitActivity(); enterNewActivity(new CalibreSettingsActivity(renderer, mappedInput, [this] { @@ -186,18 +195,19 @@ void SettingsActivity::render() const { // Draw header renderer.drawCenteredText(UI_12_FONT_ID, 15, "Settings", true, EpdFontFamily::BOLD); - // Draw selection + // Draw selection highlight renderer.fillRect(0, 60 + selectedSettingIndex * 30 - 2, pageWidth - 1, 30); // Draw all settings for (int i = 0; i < settingsCount; i++) { const int settingY = 60 + i * 30; // 30 pixels between settings + const bool isSelected = (i == selectedSettingIndex); // Draw setting name - renderer.drawText(UI_10_FONT_ID, 20, settingY, settingsList[i].name, i != selectedSettingIndex); + renderer.drawText(UI_10_FONT_ID, 20, settingY, settingsList[i].name, !isSelected); // Draw value based on setting type - std::string valueText = ""; + std::string valueText; if (settingsList[i].type == SettingType::TOGGLE && settingsList[i].valuePtr != nullptr) { const bool value = SETTINGS.*(settingsList[i].valuePtr); valueText = value ? "ON" : "OFF"; @@ -207,8 +217,10 @@ void SettingsActivity::render() const { } else if (settingsList[i].type == SettingType::VALUE && settingsList[i].valuePtr != nullptr) { valueText = std::to_string(SETTINGS.*(settingsList[i].valuePtr)); } - const auto width = renderer.getTextWidth(UI_10_FONT_ID, valueText.c_str()); - renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, valueText.c_str(), i != selectedSettingIndex); + if (!valueText.empty()) { + const auto width = renderer.getTextWidth(UI_10_FONT_ID, valueText.c_str()); + renderer.drawText(UI_10_FONT_ID, pageWidth - 20 - width, settingY, valueText.c_str(), !isSelected); + } } // Draw version text above button hints diff --git a/src/main.cpp b/src/main.cpp index 8a7c3b91..e0ad316a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "Battery.h" #include "CrossPointSettings.h" #include "CrossPointState.h" +#include "KOReaderCredentialStore.h" #include "MappedInputManager.h" #include "activities/boot_sleep/BootActivity.h" #include "activities/boot_sleep/SleepActivity.h" @@ -289,6 +290,7 @@ void setup() { } SETTINGS.loadFromFile(); + KOREADER_STORE.loadFromFile(); // verify power button press duration after we've read settings. verifyWakeupLongPress(); From 7a792a5384d193a5757060fc1e856b3de71d1240 Mon Sep 17 00:00:00 2001 From: Luke Stein <44452336+lukestein@users.noreply.github.com> Date: Mon, 19 Jan 2026 06:57:39 -0500 Subject: [PATCH 4/5] fix: Invert colors on home screen cover overlay when recent book is selected (#390) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary * Fixes #388 ## Additional Context * Tested on my own device * See images at #388 for what home screen looked like before. * With this PR the home screen shows the following (selected and unselected recent book × cover image rendered or not) ![Picsew_20260115153419](https://github.com/user-attachments/assets/44193f9d-76b7-4c77-b890-72b0dbae01c4) --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? **YES** --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- src/activities/home/HomeActivity.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index 3a97e132..6f27e39c 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -325,6 +325,10 @@ void HomeActivity::render() { } if (hasContinueReading) { + // Invert text colors based on selection state: + // - With cover: selected = white text on black box, unselected = black text on white box + // - Without cover: selected = white text on black card, unselected = black text on white card + // Split into words (avoid stringstream to keep this light on the MCU) std::vector words; words.reserve(8); @@ -407,7 +411,7 @@ void HomeActivity::render() { // Vertically center the title block within the card int titleYStart = bookY + (bookHeight - totalTextHeight) / 2; - // If cover image was rendered, draw white box behind title and author + // If cover image was rendered, draw box behind title and author if (coverRendered) { constexpr int boxPadding = 8; // Calculate the max text width for the box @@ -438,14 +442,14 @@ void HomeActivity::render() { const int boxX = (pageWidth - boxWidth) / 2; const int boxY = titleYStart - boxPadding; - // Draw white filled box - renderer.fillRect(boxX, boxY, boxWidth, boxHeight, false); - // Draw black border around the box - renderer.drawRect(boxX, boxY, boxWidth, boxHeight, true); + // Draw box (inverted when selected: black box instead of white) + renderer.fillRect(boxX, boxY, boxWidth, boxHeight, bookSelected); + // Draw border around the box (inverted when selected: white border instead of black) + renderer.drawRect(boxX, boxY, boxWidth, boxHeight, !bookSelected); } for (const auto& line : lines) { - renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, line.c_str(), !bookSelected || coverRendered); + renderer.drawCenteredText(UI_12_FONT_ID, titleYStart, line.c_str(), !bookSelected); titleYStart += renderer.getLineHeight(UI_12_FONT_ID); } @@ -466,13 +470,13 @@ void HomeActivity::render() { } trimmedAuthor.append("..."); } - renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, trimmedAuthor.c_str(), !bookSelected || coverRendered); + renderer.drawCenteredText(UI_10_FONT_ID, titleYStart, trimmedAuthor.c_str(), !bookSelected); } // "Continue Reading" label at the bottom const int continueY = bookY + bookHeight - renderer.getLineHeight(UI_10_FONT_ID) * 3 / 2; if (coverRendered) { - // Draw white box behind "Continue Reading" text + // Draw box behind "Continue Reading" text (inverted when selected: black box instead of white) const char* continueText = "Continue Reading"; const int continueTextWidth = renderer.getTextWidth(UI_10_FONT_ID, continueText); constexpr int continuePadding = 6; @@ -480,9 +484,9 @@ void HomeActivity::render() { const int continueBoxHeight = renderer.getLineHeight(UI_10_FONT_ID) + continuePadding; const int continueBoxX = (pageWidth - continueBoxWidth) / 2; const int continueBoxY = continueY - continuePadding / 2; - renderer.fillRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, false); - renderer.drawRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, true); - renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, true); + renderer.fillRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, bookSelected); + renderer.drawRect(continueBoxX, continueBoxY, continueBoxWidth, continueBoxHeight, !bookSelected); + renderer.drawCenteredText(UI_10_FONT_ID, continueY, continueText, !bookSelected); } else { renderer.drawCenteredText(UI_10_FONT_ID, continueY, "Continue Reading", !bookSelected); } From 5fef99c641360d7f7933c07980f61be43f20c166 Mon Sep 17 00:00:00 2001 From: Maeve Andrews <37351465+maeveynot@users.noreply.github.com> Date: Mon, 19 Jan 2026 05:58:43 -0600 Subject: [PATCH 5/5] fix: render U+FFFD replacement character instead of ? (#366) The current behavior of rendering `?` for an unknown Unicode character can be hard to distinguish from a typo. Use the standard Unicode "replacement character" instead, that's what it's designed for: https://en.wikipedia.org/wiki/Specials_(Unicode_block) I'm making this PR as a draft because I'm not sure I did everything that was needed to change the character set covered by the fonts. Running that script is in its own commit. If this is proper, I'll rebase/squash into one commit and un-draft. Co-authored-by: Maeve Andrews --- lib/EpdFont/EpdFont.cpp | 3 +- lib/EpdFont/builtinFonts/bookerly_12_bold.h | 17 +++++++++-- .../builtinFonts/bookerly_12_bolditalic.h | 17 +++++++++-- lib/EpdFont/builtinFonts/bookerly_12_italic.h | 18 ++++++++++-- .../builtinFonts/bookerly_12_regular.h | 18 ++++++++++-- lib/EpdFont/builtinFonts/bookerly_14_bold.h | 20 +++++++++++-- .../builtinFonts/bookerly_14_bolditalic.h | 20 +++++++++++-- lib/EpdFont/builtinFonts/bookerly_14_italic.h | 20 +++++++++++-- .../builtinFonts/bookerly_14_regular.h | 19 +++++++++++-- lib/EpdFont/builtinFonts/bookerly_16_bold.h | 23 +++++++++++++-- .../builtinFonts/bookerly_16_bolditalic.h | 22 +++++++++++++-- lib/EpdFont/builtinFonts/bookerly_16_italic.h | 24 ++++++++++++++-- .../builtinFonts/bookerly_16_regular.h | 24 ++++++++++++++-- lib/EpdFont/builtinFonts/bookerly_18_bold.h | 28 +++++++++++++++++-- .../builtinFonts/bookerly_18_bolditalic.h | 28 +++++++++++++++++-- lib/EpdFont/builtinFonts/bookerly_18_italic.h | 28 +++++++++++++++++-- .../builtinFonts/bookerly_18_regular.h | 28 +++++++++++++++++-- lib/EpdFont/builtinFonts/notosans_12_bold.h | 16 +++++++++-- .../builtinFonts/notosans_12_bolditalic.h | 17 +++++++++-- lib/EpdFont/builtinFonts/notosans_12_italic.h | 17 +++++++++-- .../builtinFonts/notosans_12_regular.h | 15 ++++++++-- lib/EpdFont/builtinFonts/notosans_14_bold.h | 20 +++++++++++-- .../builtinFonts/notosans_14_bolditalic.h | 20 +++++++++++-- lib/EpdFont/builtinFonts/notosans_14_italic.h | 20 +++++++++++-- .../builtinFonts/notosans_14_regular.h | 19 +++++++++++-- lib/EpdFont/builtinFonts/notosans_16_bold.h | 22 +++++++++++++-- .../builtinFonts/notosans_16_bolditalic.h | 23 +++++++++++++-- lib/EpdFont/builtinFonts/notosans_16_italic.h | 24 ++++++++++++++-- .../builtinFonts/notosans_16_regular.h | 22 +++++++++++++-- lib/EpdFont/builtinFonts/notosans_18_bold.h | 27 ++++++++++++++++-- .../builtinFonts/notosans_18_bolditalic.h | 27 ++++++++++++++++-- lib/EpdFont/builtinFonts/notosans_18_italic.h | 27 ++++++++++++++++-- .../builtinFonts/notosans_18_regular.h | 27 ++++++++++++++++-- lib/EpdFont/builtinFonts/notosans_8_regular.h | 10 +++++-- lib/EpdFont/scripts/fontconvert.py | 3 ++ lib/GfxRenderer/GfxRenderer.cpp | 5 ++-- lib/Utf8/Utf8.h | 2 ++ 37 files changed, 620 insertions(+), 100 deletions(-) diff --git a/lib/EpdFont/EpdFont.cpp b/lib/EpdFont/EpdFont.cpp index 7dde633f..8550cba4 100644 --- a/lib/EpdFont/EpdFont.cpp +++ b/lib/EpdFont/EpdFont.cpp @@ -22,8 +22,7 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star const EpdGlyph* glyph = getGlyph(cp); if (!glyph) { - // TODO: Replace with fallback glyph property? - glyph = getGlyph('?'); + glyph = getGlyph(REPLACEMENT_GLYPH); } if (!glyph) { diff --git a/lib/EpdFont/builtinFonts/bookerly_12_bold.h b/lib/EpdFont/builtinFonts/bookerly_12_bold.h index 3d38b148..7ba50cc9 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_boldBitmaps[51217] = { +static const uint8_t bookerly_12_boldBitmaps[51367] = { 0x0A, 0x83, 0xFC, 0x3F, 0x87, 0xF4, 0x7F, 0x43, 0xF4, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x2F, 0x01, 0xF0, 0x00, 0x00, 0x10, 0x2F, 0xC3, 0xFC, 0x3F, 0xC0, 0x50, 0x7E, 0x1F, 0x7F, 0x8F, 0xDF, 0xD3, 0xF3, 0xF4, 0xFC, 0xFD, 0x3F, 0x2F, 0x0F, 0xCB, 0xC3, 0xF2, 0xE0, 0xF8, @@ -3209,7 +3209,16 @@ static const uint8_t bookerly_12_boldBitmaps[51217] = { 0x2F, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x2F, 0x47, 0xFC, 0x7F, 0xC3, 0xF4, 0x00, 0x00, 0x1F, 0x80, 0x0B, 0xC0, 0x0B, 0xD0, 0xFF, 0x40, 0xBF, 0x80, 0x7F, 0xC3, 0xFD, 0x02, 0xFE, 0x01, 0xFF, 0x0B, 0xE0, 0x07, 0xF0, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, + 0x00, 0x00, 0x74, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, + 0xE0, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFD, 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, + 0x7F, 0xFF, 0xFF, 0xE1, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, + 0x3F, 0xFE, 0x02, 0xFF, 0xFC, 0x00, 0xBF, 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, + 0xFF, 0xE2, 0xFF, 0xFE, 0x00, 0x00, 0x2F, 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, + 0x00, 0x00, 0x00, 0x2F, 0xD2, 0xFE, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, + 0x2D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_12_boldGlyphs[] = { @@ -3941,6 +3950,7 @@ static const EpdGlyph bookerly_12_boldGlyphs[] = { { 15, 18, 25, 5, 18, 68, 51112 }, // ⊥ { 6, 5, 16, 5, 9, 8, 51180 }, // ⋅ { 23, 5, 25, 1, 9, 29, 51188 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 51217 }, // � }; static const EpdUnicodeInterval bookerly_12_boldIntervals[] = { @@ -4004,13 +4014,14 @@ static const EpdUnicodeInterval bookerly_12_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_bold = { bookerly_12_boldBitmaps, bookerly_12_boldGlyphs, bookerly_12_boldIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h index 9fd2471d..e2077955 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_bolditalicBitmaps[52522] = { +static const uint8_t bookerly_12_bolditalicBitmaps[52672] = { 0x00, 0x68, 0x01, 0xFC, 0x03, 0xF8, 0x07, 0xF4, 0x07, 0xF0, 0x0B, 0xE0, 0x0F, 0xD0, 0x0F, 0xC0, 0x0F, 0xC0, 0x0F, 0x80, 0x1F, 0x40, 0x1F, 0x00, 0x2F, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x04, 0x00, 0x7F, 0x00, 0xBF, 0x00, 0xBD, 0x00, 0x10, 0x00, 0x0B, 0x87, 0xC2, 0xF4, 0xFC, 0x3F, 0x2F, 0x83, @@ -3290,7 +3290,16 @@ static const uint8_t bookerly_12_bolditalicBitmaps[52522] = { 0xC0, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x2F, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x2F, 0x47, 0xFC, 0x7F, 0xC3, 0xF4, 0x00, 0x00, 0x1F, 0x80, 0x0B, 0xC0, 0x0B, 0xD0, 0xFF, 0x40, 0xBF, 0x80, 0x7F, 0xC3, 0xFD, 0x02, 0xFE, 0x01, 0xFF, 0x0B, 0xE0, - 0x07, 0xF0, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0xF0, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x7F, + 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x74, 0x00, 0x78, 0x00, 0x00, + 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0xF8, 0x00, 0x00, 0x7F, 0xFF, 0xFD, + 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xE1, 0xFF, 0x80, 0x7F, + 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x3F, 0xFE, 0x02, 0xFF, 0xFC, 0x00, 0xBF, + 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xE2, 0xFF, 0xFE, 0x00, 0x00, 0x2F, + 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x2F, 0xD2, 0xFE, 0x00, + 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_12_bolditalicGlyphs[] = { @@ -4022,6 +4031,7 @@ static const EpdGlyph bookerly_12_bolditalicGlyphs[] = { { 15, 18, 25, 5, 18, 68, 52417 }, // ⊥ { 6, 5, 16, 5, 9, 8, 52485 }, // ⋅ { 23, 5, 25, 1, 9, 29, 52493 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 52522 }, // � }; static const EpdUnicodeInterval bookerly_12_bolditalicIntervals[] = { @@ -4085,13 +4095,14 @@ static const EpdUnicodeInterval bookerly_12_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_bolditalic = { bookerly_12_bolditalicBitmaps, bookerly_12_bolditalicGlyphs, bookerly_12_bolditalicIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_12_italic.h b/lib/EpdFont/builtinFonts/bookerly_12_italic.h index a323a97e..9c965a92 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_italicBitmaps[48812] = { +static const uint8_t bookerly_12_italicBitmaps[48962] = { 0x00, 0x14, 0x03, 0xD0, 0x1F, 0x00, 0xF8, 0x03, 0xD0, 0x0F, 0x00, 0x7C, 0x02, 0xD0, 0x0B, 0x00, 0x3C, 0x00, 0xE0, 0x03, 0x80, 0x1D, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1D, 0x01, 0xF8, 0x07, 0xC0, 0x04, 0x00, 0x0A, 0x07, 0x0B, 0x87, 0xC3, 0xD2, 0xE0, 0xF0, 0xB4, 0x38, 0x3C, 0x0D, 0x0E, @@ -3058,7 +3058,17 @@ static const uint8_t bookerly_12_italicBitmaps[48812] = { 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x56, 0xE5, 0x54, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x10, 0xBD, 0xFE, 0xBC, 0x04, 0x00, 0x04, 0x00, 0x05, 0x1F, 0xC0, 0x0F, 0xC0, - 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, + 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x74, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0xF8, 0x00, 0x00, 0x7F, + 0xFF, 0xFD, 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, 0x7F, 0xFF, 0xFF, 0xE1, 0xFF, + 0x80, 0x7F, 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x3F, 0xFE, 0x02, 0xFF, 0xFC, + 0x00, 0xBF, 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xE2, 0xFF, 0xFE, 0x00, + 0x00, 0x2F, 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x2F, 0xD2, + 0xFE, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x2E, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, }; static const EpdGlyph bookerly_12_italicGlyphs[] = { @@ -3790,6 +3800,7 @@ static const EpdGlyph bookerly_12_italicGlyphs[] = { { 15, 18, 25, 5, 18, 68, 48719 }, // ⊥ { 4, 4, 16, 6, 9, 4, 48787 }, // ⋅ { 21, 4, 25, 2, 9, 21, 48791 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 48812 }, // � }; static const EpdUnicodeInterval bookerly_12_italicIntervals[] = { @@ -3853,13 +3864,14 @@ static const EpdUnicodeInterval bookerly_12_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_italic = { bookerly_12_italicBitmaps, bookerly_12_italicGlyphs, bookerly_12_italicIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_12_regular.h b/lib/EpdFont/builtinFonts/bookerly_12_regular.h index baa107de..822369ee 100644 --- a/lib/EpdFont/builtinFonts/bookerly_12_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_12_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_12_regularBitmaps[47071] = { +static const uint8_t bookerly_12_regularBitmaps[47221] = { 0x28, 0xBC, 0xFC, 0xF8, 0xF8, 0xF8, 0xF4, 0xF4, 0xF4, 0xF4, 0xB4, 0xB4, 0x74, 0x74, 0x00, 0x00, 0x78, 0xFD, 0xFC, 0x10, 0x28, 0x2E, 0xE1, 0xFB, 0x47, 0xED, 0x1E, 0xB4, 0x7A, 0xD1, 0xEB, 0x03, 0x94, 0x04, 0x00, 0x0E, 0x02, 0xC0, 0x00, 0x0D, 0x03, 0x80, 0x00, 0x1D, 0x03, 0x40, 0x00, 0x2C, @@ -2949,7 +2949,17 @@ static const uint8_t bookerly_12_regularBitmaps[47071] = { 0x00, 0x0B, 0x80, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, 0x0B, 0x80, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x05, 0x56, 0xE5, 0x54, 0xBF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xE0, 0x10, 0xBD, 0xFE, 0xBC, 0x04, 0x00, 0x04, 0x00, 0x05, 0x1F, - 0xC0, 0x0F, 0xC0, 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, + 0xC0, 0x0F, 0xC0, 0x0B, 0xDB, 0xF0, 0x03, 0xF0, 0x03, 0xF8, 0xF4, 0x00, 0xF8, 0x00, 0x7C, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x74, 0x1F, 0x80, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x78, 0x00, 0x00, 0x00, 0x7D, 0x04, 0x0B, 0x80, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0xF8, + 0x00, 0x00, 0x7F, 0xFF, 0xFD, 0x2F, 0x80, 0x00, 0x7F, 0xFF, 0xFF, 0x87, 0xF8, 0x00, 0x7F, 0xFF, + 0xFF, 0xE1, 0xFF, 0x80, 0x7F, 0xFF, 0xFF, 0x80, 0xBF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x3F, 0xFE, + 0x02, 0xFF, 0xFC, 0x00, 0xBF, 0xFE, 0x00, 0x2F, 0xFF, 0x42, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xE2, + 0xFF, 0xFE, 0x00, 0x00, 0x2F, 0xFC, 0xBF, 0xFE, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFE, 0x00, 0x00, + 0x00, 0x2F, 0xD2, 0xFE, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x2D, 0x2E, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_12_regularGlyphs[] = { @@ -3681,6 +3691,7 @@ static const EpdGlyph bookerly_12_regularGlyphs[] = { { 15, 18, 25, 5, 18, 68, 46978 }, // ⊥ { 4, 4, 16, 6, 9, 4, 47046 }, // ⋅ { 21, 4, 25, 2, 9, 21, 47050 }, // ⋯ + { 25, 24, 25, 0, 21, 150, 47071 }, // � }; static const EpdUnicodeInterval bookerly_12_regularIntervals[] = { @@ -3744,13 +3755,14 @@ static const EpdUnicodeInterval bookerly_12_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_12_regular = { bookerly_12_regularBitmaps, bookerly_12_regularGlyphs, bookerly_12_regularIntervals, - 60, + 61, 33, 27, -7, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_bold.h b/lib/EpdFont/builtinFonts/bookerly_14_bold.h index e6b98785..39de4d1d 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_boldBitmaps[67020] = { +static const uint8_t bookerly_14_boldBitmaps[67209] = { 0x1A, 0x4B, 0xF8, 0xFF, 0x8F, 0xF4, 0xFF, 0x4F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xBF, 0x0B, 0xF0, 0x7F, 0x07, 0xF0, 0x3F, 0x03, 0xF0, 0x10, 0x00, 0x00, 0x2F, 0x4B, 0xFC, 0xBF, 0xC7, 0xFC, 0x15, 0x00, 0x2F, 0x42, 0xE7, 0xF4, 0xFF, 0xBF, 0x0F, 0xEB, 0xF0, 0xFE, 0xBF, 0x0F, 0xEB, @@ -4196,7 +4196,19 @@ static const uint8_t bookerly_14_boldBitmaps[67020] = { 0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0x03, 0xFC, 0xBF, 0xEB, 0xFE, 0x3F, 0xC0, 0x00, 0x05, 0x00, 0x00, 0x40, 0x00, 0x04, 0x0F, 0xF0, 0x02, 0xFE, 0x00, 0x3F, 0xDB, 0xFD, 0x00, 0xFF, 0xC0, 0x1F, 0xFA, 0xFF, 0x40, 0x3F, 0xF0, 0x07, 0xFE, 0x7F, - 0xC0, 0x0B, 0xF4, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x0B, 0xF4, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, + 0xC0, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, + 0xE0, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0x03, 0xE0, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, + 0x2F, 0xFF, 0xFF, 0xFC, 0x2F, 0xE0, 0x02, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, + 0xFF, 0x42, 0xFF, 0xE2, 0xFF, 0xFF, 0xFE, 0x40, 0x0F, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, + 0xFF, 0x03, 0xFF, 0xFF, 0x00, 0x2F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, + 0xFF, 0xF0, 0xBF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xD1, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, + 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, + 0x00, 0x00, 0x03, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_boldGlyphs[] = { @@ -4928,6 +4940,7 @@ static const EpdGlyph bookerly_14_boldGlyphs[] = { { 17, 21, 29, 6, 21, 90, 66883 }, // ⊥ { 6, 6, 18, 6, 11, 9, 66973 }, // ⋅ { 25, 6, 29, 2, 11, 38, 66982 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 67020 }, // � }; static const EpdUnicodeInterval bookerly_14_boldIntervals[] = { @@ -4991,13 +5004,14 @@ static const EpdUnicodeInterval bookerly_14_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_bold = { bookerly_14_boldBitmaps, bookerly_14_boldGlyphs, bookerly_14_boldIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h index 6081791a..807d85fc 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_bolditalicBitmaps[70024] = { +static const uint8_t bookerly_14_bolditalicBitmaps[70213] = { 0x00, 0x1A, 0x40, 0x2F, 0xD0, 0x0F, 0xF0, 0x0B, 0xF8, 0x03, 0xFD, 0x00, 0xFF, 0x00, 0x3F, 0x80, 0x1F, 0xD0, 0x07, 0xF0, 0x02, 0xFC, 0x00, 0xBE, 0x00, 0x3F, 0x40, 0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xF8, 0x00, 0x3D, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xF4, 0x01, 0xFF, 0x00, 0xBF, 0x80, 0x1F, @@ -4384,7 +4384,19 @@ static const uint8_t bookerly_14_bolditalicBitmaps[70024] = { 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x01, 0x03, 0xFC, 0xBF, 0xEB, 0xFE, 0x3F, 0xC0, 0x00, 0x05, 0x00, 0x00, 0x40, 0x00, 0x04, 0x0F, 0xF0, 0x02, 0xFE, 0x00, 0x3F, 0xDB, 0xFD, 0x00, 0xFF, 0xC0, 0x1F, 0xFA, 0xFF, 0x40, 0x3F, 0xF0, 0x07, 0xFE, 0x7F, 0xC0, 0x0B, 0xF4, 0x00, - 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x02, 0xE0, 0x00, + 0x00, 0x00, 0x2E, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, 0xE0, 0x00, 0x00, 0x2F, + 0xFF, 0xFF, 0x03, 0xE0, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, 0x2F, 0xFF, 0xFF, 0xFC, + 0x2F, 0xE0, 0x02, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0x42, 0xFF, 0xE2, + 0xFF, 0xFF, 0xFE, 0x40, 0x0F, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, + 0x00, 0x2F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0xBF, 0xFF, + 0xF0, 0x00, 0x03, 0xFF, 0xD1, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x03, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF0, + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_bolditalicGlyphs[] = { @@ -5116,6 +5128,7 @@ static const EpdGlyph bookerly_14_bolditalicGlyphs[] = { { 17, 21, 29, 6, 21, 90, 69887 }, // ⊥ { 6, 6, 18, 6, 11, 9, 69977 }, // ⋅ { 25, 6, 29, 2, 11, 38, 69986 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 70024 }, // � }; static const EpdUnicodeInterval bookerly_14_bolditalicIntervals[] = { @@ -5179,13 +5192,14 @@ static const EpdUnicodeInterval bookerly_14_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_bolditalic = { bookerly_14_bolditalicBitmaps, bookerly_14_bolditalicGlyphs, bookerly_14_bolditalicIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_italic.h b/lib/EpdFont/builtinFonts/bookerly_14_italic.h index 5edb8798..8710dab2 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_italicBitmaps[64856] = { +static const uint8_t bookerly_14_italicBitmaps[65045] = { 0x00, 0x05, 0x00, 0x0F, 0x80, 0x0B, 0xD0, 0x03, 0xF0, 0x00, 0xF8, 0x00, 0x7D, 0x00, 0x2F, 0x00, 0x0F, 0x80, 0x03, 0xD0, 0x00, 0xF0, 0x00, 0x7C, 0x00, 0x1E, 0x00, 0x0B, 0x40, 0x02, 0xC0, 0x00, 0xF0, 0x00, 0x3C, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x3F, 0x40, 0x0F, @@ -4061,7 +4061,19 @@ static const uint8_t bookerly_14_italicBitmaps[64856] = { 0xFC, 0x00, 0x06, 0xAA, 0xBF, 0xAA, 0xA6, 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x0A, 0x43, 0xFC, 0x3F, 0xC2, 0xF8, 0x00, 0x00, 0x0A, 0x00, 0x01, 0xA0, 0x00, 0x29, 0x0F, 0xF0, 0x01, 0xFD, 0x00, 0x2F, 0xC3, 0xFC, 0x00, 0xBF, 0x80, 0x0F, 0xF0, 0xFD, 0x00, 0x0F, 0xC0, 0x01, - 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x02, 0xE0, 0x00, + 0x00, 0x00, 0x2E, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, 0xE0, 0x00, 0x00, 0x2F, + 0xFF, 0xFF, 0x03, 0xE0, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, 0x2F, 0xFF, 0xFF, 0xFC, + 0x2F, 0xE0, 0x02, 0xFF, 0xFF, 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0x42, 0xFF, 0xE2, + 0xFF, 0xFF, 0xFE, 0x40, 0x0F, 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, + 0x00, 0x2F, 0xFF, 0xF0, 0x03, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0xBF, 0xFF, + 0xF0, 0x00, 0x03, 0xFF, 0xD1, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x03, 0xFF, 0xEF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF0, + 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_italicGlyphs[] = { @@ -4793,6 +4805,7 @@ static const EpdGlyph bookerly_14_italicGlyphs[] = { { 17, 21, 29, 6, 21, 90, 64726 }, // ⊥ { 6, 5, 18, 6, 10, 8, 64816 }, // ⋅ { 25, 5, 29, 2, 10, 32, 64824 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 64856 }, // � }; static const EpdUnicodeInterval bookerly_14_italicIntervals[] = { @@ -4856,13 +4869,14 @@ static const EpdUnicodeInterval bookerly_14_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_italic = { bookerly_14_italicBitmaps, bookerly_14_italicGlyphs, bookerly_14_italicIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_14_regular.h b/lib/EpdFont/builtinFonts/bookerly_14_regular.h index f178d44c..1fec866c 100644 --- a/lib/EpdFont/builtinFonts/bookerly_14_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_14_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_14_regularBitmaps[62675] = { +static const uint8_t bookerly_14_regularBitmaps[62864] = { 0x1A, 0x1F, 0xCB, 0xE2, 0xF4, 0xBD, 0x2F, 0x4B, 0xC2, 0xF0, 0xBC, 0x2F, 0x07, 0xC1, 0xF0, 0x7C, 0x0F, 0x03, 0xC0, 0xF0, 0x00, 0x00, 0x00, 0x40, 0xFC, 0xBF, 0x5F, 0xC1, 0x40, 0x18, 0x06, 0x1F, 0x07, 0xCB, 0xC2, 0xF1, 0xF0, 0xBC, 0x7C, 0x1F, 0x1F, 0x07, 0xC7, 0xC1, 0xF1, 0xF0, 0x7C, 0x34, @@ -3925,7 +3925,18 @@ static const uint8_t bookerly_14_regularBitmaps[62675] = { 0xAA, 0xA6, 0xFF, 0xFF, 0xFF, 0xFE, 0xBF, 0xFF, 0xFF, 0xFF, 0x80, 0x0A, 0x43, 0xFC, 0x3F, 0xC2, 0xF8, 0x00, 0x00, 0x0A, 0x00, 0x01, 0xA0, 0x00, 0x29, 0x0F, 0xF0, 0x01, 0xFD, 0x00, 0x2F, 0xC3, 0xFC, 0x00, 0xBF, 0x80, 0x0F, 0xF0, 0xFD, 0x00, 0x0F, 0xC0, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x2E, 0x5B, 0xE0, 0x00, 0x00, 0x00, 0x02, 0xC0, 0x02, 0xE0, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x01, + 0xE0, 0x00, 0x00, 0x02, 0xFC, 0x69, 0x02, 0xE0, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0x03, 0xE0, 0x00, + 0x02, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0x00, 0x2F, 0xFF, 0xFF, 0xFC, 0x2F, 0xE0, 0x02, 0xFF, 0xFF, + 0xFF, 0xF0, 0xBF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0x42, 0xFF, 0xE2, 0xFF, 0xFF, 0xFE, 0x40, 0x0F, + 0xFF, 0xE3, 0xFF, 0xFF, 0xC0, 0x00, 0xFF, 0xFF, 0x03, 0xFF, 0xFF, 0x00, 0x2F, 0xFF, 0xF0, 0x03, + 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xF0, 0xBF, 0xFF, 0xF0, 0x00, 0x03, 0xFF, 0xD1, + 0xFF, 0xFF, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x03, 0xFF, 0xEF, 0xFF, 0x00, + 0x00, 0x00, 0x03, 0xFC, 0x0F, 0xF0, 0x00, 0x00, 0x00, 0x03, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xD2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_14_regularGlyphs[] = { @@ -4657,6 +4668,7 @@ static const EpdGlyph bookerly_14_regularGlyphs[] = { { 17, 21, 29, 6, 21, 90, 62545 }, // ⊥ { 6, 5, 18, 6, 10, 8, 62635 }, // ⋅ { 25, 5, 29, 2, 10, 32, 62643 }, // ⋯ + { 27, 28, 29, 1, 24, 189, 62675 }, // � }; static const EpdUnicodeInterval bookerly_14_regularIntervals[] = { @@ -4720,13 +4732,14 @@ static const EpdUnicodeInterval bookerly_14_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_14_regular = { bookerly_14_regularBitmaps, bookerly_14_regularGlyphs, bookerly_14_regularIntervals, - 60, + 61, 38, 31, -8, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_bold.h b/lib/EpdFont/builtinFonts/bookerly_16_bold.h index 67bdff95..71694b75 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_boldBitmaps[85154] = { +static const uint8_t bookerly_16_boldBitmaps[85402] = { 0x0A, 0x90, 0xFF, 0x87, 0xFE, 0x2F, 0xF4, 0xBF, 0xC2, 0xFF, 0x0B, 0xFC, 0x2F, 0xF0, 0xBF, 0xC2, 0xFF, 0x0B, 0xFC, 0x1F, 0xF0, 0x7F, 0xC0, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0xC0, 0xBF, 0x01, 0x40, 0x00, 0x00, 0x05, 0x40, 0xFF, 0xC7, 0xFF, 0x1F, 0xFC, 0x3F, 0xF0, 0x19, 0x00, 0x0A, 0x80, @@ -5330,7 +5330,22 @@ static const uint8_t bookerly_16_boldBitmaps[85154] = { 0x2F, 0xFC, 0x7F, 0xE0, 0x15, 0x00, 0x0A, 0x90, 0x00, 0x2A, 0x40, 0x00, 0xA9, 0x0F, 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0xC7, 0xFF, 0x40, 0x1F, 0xFD, 0x00, 0x7F, 0xF5, 0xFF, 0xD0, 0x07, 0xFF, 0x40, 0x1F, 0xFD, 0x3F, 0xF0, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x01, 0x50, 0x00, 0x05, 0x40, 0x00, - 0x15, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFF, 0x81, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, + 0xFF, 0xFF, 0xFF, 0xD0, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, + 0xFF, 0xD0, 0x00, 0x2F, 0xFF, 0xF4, 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, + 0xF8, 0x00, 0x7F, 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, + 0xC2, 0xFF, 0xFF, 0xF4, 0x00, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, + 0x7F, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, + 0x7F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, + 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_boldGlyphs[] = { @@ -6062,6 +6077,7 @@ static const EpdGlyph bookerly_16_boldGlyphs[] = { { 19, 23, 33, 7, 23, 110, 84989 }, // ⊥ { 7, 6, 21, 7, 12, 11, 85099 }, // ⋅ { 29, 6, 33, 2, 12, 44, 85110 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 85154 }, // � }; static const EpdUnicodeInterval bookerly_16_boldIntervals[] = { @@ -6125,13 +6141,14 @@ static const EpdUnicodeInterval bookerly_16_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_bold = { bookerly_16_boldBitmaps, bookerly_16_boldGlyphs, bookerly_16_boldIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h index 4a7a9e25..75f34b6a 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_bolditalicBitmaps[88512] = { +static const uint8_t bookerly_16_bolditalicBitmaps[88760] = { 0x00, 0x06, 0xA0, 0x00, 0xBF, 0xC0, 0x07, 0xFD, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0x80, 0x07, 0xFD, 0x00, 0x1F, 0xF0, 0x00, 0xBF, 0x80, 0x03, 0xFD, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFE, 0x00, 0x07, 0xF4, 0x00, 0x1F, 0xC0, 0x00, 0xBF, 0x00, 0x02, 0xF8, 0x00, 0x0B, 0xD0, 0x00, 0x3F, @@ -5540,6 +5540,22 @@ static const uint8_t bookerly_16_bolditalicBitmaps[88512] = { 0x7F, 0xE0, 0x15, 0x00, 0x0A, 0x90, 0x00, 0x2A, 0x40, 0x00, 0xA9, 0x0F, 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0xC7, 0xFF, 0x40, 0x1F, 0xFD, 0x00, 0x7F, 0xF5, 0xFF, 0xD0, 0x07, 0xFF, 0x40, 0x1F, 0xFD, 0x3F, 0xF0, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x01, 0x50, 0x00, 0x05, 0x40, 0x00, 0x15, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF0, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFF, 0x81, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFE, 0x0F, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xD0, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xD0, + 0x00, 0x2F, 0xFF, 0xF4, 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xF8, 0x00, + 0x7F, 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xC2, 0xFF, + 0xFF, 0xF4, 0x00, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFF, + 0xF4, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x7F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_bolditalicGlyphs[] = { @@ -6271,6 +6287,7 @@ static const EpdGlyph bookerly_16_bolditalicGlyphs[] = { { 19, 23, 33, 7, 23, 110, 88347 }, // ⊥ { 7, 6, 21, 7, 12, 11, 88457 }, // ⋅ { 29, 6, 33, 2, 12, 44, 88468 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 88512 }, // � }; static const EpdUnicodeInterval bookerly_16_bolditalicIntervals[] = { @@ -6334,13 +6351,14 @@ static const EpdUnicodeInterval bookerly_16_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_bolditalic = { bookerly_16_bolditalicBitmaps, bookerly_16_bolditalicGlyphs, bookerly_16_bolditalicIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_italic.h b/lib/EpdFont/builtinFonts/bookerly_16_italic.h index 2a4b5ef6..fbbd0069 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_italicBitmaps[82412] = { +static const uint8_t bookerly_16_italicBitmaps[82660] = { 0x00, 0x01, 0x40, 0x00, 0xFC, 0x00, 0x3F, 0x80, 0x03, 0xF0, 0x00, 0x7F, 0x00, 0x0B, 0xE0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x40, 0x02, 0xF0, 0x00, 0x2F, 0x00, 0x03, 0xE0, 0x00, 0x3D, 0x00, 0x03, 0xC0, 0x00, 0x7C, 0x00, 0x07, 0x80, 0x00, 0x74, 0x00, 0x0A, 0x00, 0x00, @@ -5158,7 +5158,23 @@ static const uint8_t bookerly_16_italicBitmaps[82412] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFC, 0x3F, 0xE3, 0xFE, 0x2F, 0xC0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x03, 0xF0, 0x00, 0x0B, 0xDB, 0xFC, 0x00, 0x2F, 0xF0, 0x00, 0xBF, 0xFF, 0xF0, 0x00, 0xFF, 0xC0, 0x03, 0xFF, 0x7F, 0x40, - 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, + 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x01, 0xFC, + 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xBC, + 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x81, 0xFC, + 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFE, 0x0F, 0xFC, + 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xFF, 0xFC, + 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xD0, 0x00, 0x2F, 0xFF, 0xF4, + 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, 0xFF, 0xF4, 0x00, + 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xC2, 0xFF, 0xFF, 0xF4, 0x00, 0x00, + 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFF, 0xF4, 0x00, 0x00, 0x00, + 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x7F, 0xF4, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_italicGlyphs[] = { @@ -5890,6 +5906,7 @@ static const EpdGlyph bookerly_16_italicGlyphs[] = { { 19, 23, 33, 7, 23, 110, 82252 }, // ⊥ { 6, 6, 21, 7, 12, 9, 82362 }, // ⋅ { 27, 6, 33, 3, 12, 41, 82371 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 82412 }, // � }; static const EpdUnicodeInterval bookerly_16_italicIntervals[] = { @@ -5953,13 +5970,14 @@ static const EpdUnicodeInterval bookerly_16_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_italic = { bookerly_16_italicBitmaps, bookerly_16_italicGlyphs, bookerly_16_italicIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_16_regular.h b/lib/EpdFont/builtinFonts/bookerly_16_regular.h index 92ba41ad..e40411fe 100644 --- a/lib/EpdFont/builtinFonts/bookerly_16_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_16_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_16_regularBitmaps[79871] = { +static const uint8_t bookerly_16_regularBitmaps[80119] = { 0x0A, 0x83, 0xF8, 0x3F, 0x47, 0xF4, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x3F, 0x03, 0xF0, 0x2F, 0x02, 0xF0, 0x04, 0x00, 0x00, 0x00, 0x01, 0xA4, 0x3F, 0xC3, 0xFC, 0x3F, 0xC0, 0x50, 0x05, 0x01, 0x93, 0xE0, 0x7D, 0x7E, 0x0B, 0xD7, 0xE0, @@ -4999,7 +4999,23 @@ static const uint8_t bookerly_16_regularBitmaps[79871] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x00, 0x01, 0xFC, 0x3F, 0xE3, 0xFE, 0x2F, 0xC0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x03, 0xF0, 0x00, 0x0B, 0xDB, 0xFC, 0x00, 0x2F, 0xF0, 0x00, 0xBF, 0xFF, 0xF0, 0x00, 0xFF, 0xC0, 0x03, - 0xFF, 0x7F, 0x40, 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, + 0xFF, 0x7F, 0x40, 0x01, 0xFD, 0x00, 0x07, 0xF4, 0x10, 0x00, 0x00, 0x40, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xEF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF0, 0x01, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xFC, + 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x0F, 0xF9, 0xBE, 0x40, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0x81, 0xFC, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x43, 0xFC, 0x00, 0x00, 0xFF, 0xFF, 0xFF, + 0xFE, 0x0F, 0xFC, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFC, 0x2F, 0xFC, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xD0, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xFF, 0xE4, 0x03, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xD0, 0x00, + 0x2F, 0xFF, 0xF4, 0x7F, 0xFF, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xF8, 0x00, 0x7F, + 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xC2, 0xFF, 0xFF, + 0xF4, 0x00, 0x00, 0x7F, 0xFF, 0x07, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFF, 0xF4, + 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x7F, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x7F, 0x80, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x03, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7D, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_16_regularGlyphs[] = { @@ -5731,6 +5747,7 @@ static const EpdGlyph bookerly_16_regularGlyphs[] = { { 19, 23, 33, 7, 23, 110, 79711 }, // ⊥ { 6, 6, 21, 7, 12, 9, 79821 }, // ⋅ { 27, 6, 33, 3, 12, 41, 79830 }, // ⋯ + { 31, 32, 33, 1, 28, 248, 79871 }, // � }; static const EpdUnicodeInterval bookerly_16_regularIntervals[] = { @@ -5794,13 +5811,14 @@ static const EpdUnicodeInterval bookerly_16_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_16_regular = { bookerly_16_regularBitmaps, bookerly_16_regularGlyphs, bookerly_16_regularIntervals, - 60, + 61, 44, 36, -9, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_bold.h b/lib/EpdFont/builtinFonts/bookerly_18_bold.h index 74590181..db3d2d55 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_bold.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_boldBitmaps[112410] = { +static const uint8_t bookerly_18_boldBitmaps[112734] = { 0x01, 0x54, 0x1F, 0xFC, 0x3F, 0xF8, 0x3F, 0xF8, 0x7F, 0xF4, 0x7F, 0xF4, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x3F, 0xF0, 0x2F, 0xF0, 0x2F, 0xF0, 0x1F, 0xF0, 0x1F, 0xF0, 0x0F, 0xF0, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -7033,7 +7033,27 @@ static const uint8_t bookerly_18_boldBitmaps[112410] = { 0x00, 0x00, 0x54, 0x00, 0x00, 0x54, 0x01, 0xFF, 0xC0, 0x00, 0xBF, 0xF0, 0x00, 0x3F, 0xF4, 0x3F, 0xFE, 0x00, 0x0F, 0xFF, 0x40, 0x0B, 0xFF, 0xC3, 0xFF, 0xF0, 0x01, 0xFF, 0xF4, 0x00, 0xBF, 0xFC, 0x3F, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x0B, 0xFF, 0xC1, 0xFF, 0xC0, 0x00, 0xFF, 0xE0, 0x00, 0x3F, - 0xF4, 0x01, 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, + 0xF4, 0x01, 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0B, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, + 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, + 0x2F, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, + 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, + 0x1F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, + 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, + 0x00, 0x7F, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, + 0xF4, 0x00, 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, + 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xEB, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_boldGlyphs[] = { @@ -7765,6 +7785,7 @@ static const EpdGlyph bookerly_18_boldGlyphs[] = { { 22, 27, 38, 8, 27, 149, 112187 }, // ⊥ { 8, 7, 24, 8, 14, 14, 112336 }, // ⋅ { 34, 7, 38, 2, 14, 60, 112350 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 112410 }, // � }; static const EpdUnicodeInterval bookerly_18_boldIntervals[] = { @@ -7828,13 +7849,14 @@ static const EpdUnicodeInterval bookerly_18_boldIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_bold = { bookerly_18_boldBitmaps, bookerly_18_boldGlyphs, bookerly_18_boldIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h b/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h index f0484d6d..ca65d6a4 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_bolditalicBitmaps[115736] = { +static const uint8_t bookerly_18_bolditalicBitmaps[116060] = { 0x00, 0x00, 0x54, 0x00, 0x07, 0xFE, 0x00, 0x0F, 0xFC, 0x00, 0x2F, 0xFC, 0x00, 0x3F, 0xF4, 0x00, 0x7F, 0xF0, 0x00, 0xBF, 0xF0, 0x00, 0xFF, 0xD0, 0x00, 0xFF, 0xC0, 0x00, 0xFF, 0xC0, 0x01, 0xFF, 0x80, 0x01, 0xFF, 0x40, 0x02, 0xFF, 0x00, 0x02, 0xFE, 0x00, 0x03, 0xFD, 0x00, 0x03, 0xFC, 0x00, @@ -7241,7 +7241,27 @@ static const uint8_t bookerly_18_bolditalicBitmaps[115736] = { 0x54, 0x00, 0x00, 0x54, 0x01, 0xFF, 0xC0, 0x00, 0xBF, 0xF0, 0x00, 0x3F, 0xF4, 0x3F, 0xFE, 0x00, 0x0F, 0xFF, 0x40, 0x0B, 0xFF, 0xC3, 0xFF, 0xF0, 0x01, 0xFF, 0xF4, 0x00, 0xBF, 0xFC, 0x3F, 0xFE, 0x00, 0x1F, 0xFF, 0x00, 0x0B, 0xFF, 0xC1, 0xFF, 0xC0, 0x00, 0xFF, 0xE0, 0x00, 0x3F, 0xF4, 0x01, - 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, + 0x50, 0x00, 0x01, 0x50, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, 0x01, 0xF8, + 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, + 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, 0x2F, 0xFF, + 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, 0x00, 0x02, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x1F, 0xFF, + 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, + 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, 0xFF, 0xF8, + 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x7F, + 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xF4, 0x00, + 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, + 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xEB, + 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_bolditalicGlyphs[] = { @@ -7973,6 +7993,7 @@ static const EpdGlyph bookerly_18_bolditalicGlyphs[] = { { 22, 27, 38, 8, 27, 149, 115513 }, // ⊥ { 8, 7, 24, 8, 14, 14, 115662 }, // ⋅ { 34, 7, 38, 2, 14, 60, 115676 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 115736 }, // � }; static const EpdUnicodeInterval bookerly_18_bolditalicIntervals[] = { @@ -8036,13 +8057,14 @@ static const EpdUnicodeInterval bookerly_18_bolditalicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_bolditalic = { bookerly_18_bolditalicBitmaps, bookerly_18_bolditalicGlyphs, bookerly_18_bolditalicIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_italic.h b/lib/EpdFont/builtinFonts/bookerly_18_italic.h index e7735b16..a04a75fa 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_italic.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_italicBitmaps[108017] = { +static const uint8_t bookerly_18_italicBitmaps[108341] = { 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x2F, 0xD0, 0x03, 0xFC, 0x00, 0x7F, 0x80, 0x0B, 0xF0, 0x00, 0xFF, 0x00, 0x0F, 0xE0, 0x00, 0xFC, 0x00, 0x1F, 0xC0, 0x02, 0xF8, 0x00, 0x2F, 0x40, 0x03, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x7D, 0x00, 0x07, 0xC0, 0x00, 0xBC, 0x00, 0x0F, 0x80, 0x00, @@ -6759,7 +6759,27 @@ static const uint8_t bookerly_18_italicBitmaps[108017] = { 0x50, 0x0A, 0x80, 0x00, 0x02, 0x90, 0x00, 0x01, 0xA0, 0x3F, 0xF0, 0x00, 0x1F, 0xF4, 0x00, 0x0B, 0xFC, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x3F, 0xD0, 0x00, 0x0F, 0xF0, 0x00, 0x07, 0xF8, 0x05, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, - 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, + 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, + 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, + 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, + 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x1F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, + 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, + 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, + 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, 0x00, 0x7F, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, + 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, 0xF4, 0x00, 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, + 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, + 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xEB, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, + 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_italicGlyphs[] = { @@ -7491,6 +7511,7 @@ static const EpdGlyph bookerly_18_italicGlyphs[] = { { 22, 27, 38, 8, 27, 149, 107811 }, // ⊥ { 6, 6, 24, 9, 13, 9, 107960 }, // ⋅ { 32, 6, 38, 3, 13, 48, 107969 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 108017 }, // � }; static const EpdUnicodeInterval bookerly_18_italicIntervals[] = { @@ -7554,13 +7575,14 @@ static const EpdUnicodeInterval bookerly_18_italicIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_italic = { bookerly_18_italicBitmaps, bookerly_18_italicGlyphs, bookerly_18_italicIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/bookerly_18_regular.h b/lib/EpdFont/builtinFonts/bookerly_18_regular.h index 08d657db..0b860dbd 100644 --- a/lib/EpdFont/builtinFonts/bookerly_18_regular.h +++ b/lib/EpdFont/builtinFonts/bookerly_18_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t bookerly_18_regularBitmaps[105210] = { +static const uint8_t bookerly_18_regularBitmaps[105534] = { 0x05, 0x43, 0xF8, 0xBF, 0x4F, 0xF4, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFE, 0x0F, 0xE0, 0xBE, 0x0B, 0xE0, 0xBE, 0x0B, 0xE0, 0x7E, 0x07, 0xE0, 0x7E, 0x03, 0xE0, 0x3E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0xFC, 0xBF, 0xCF, 0xFC, 0xBF, 0xC1, 0x90, 0x00, 0x00, 0x00, @@ -6583,7 +6583,27 @@ static const uint8_t bookerly_18_regularBitmaps[105210] = { 0xF0, 0x1A, 0x47, 0xFC, 0xFF, 0xDF, 0xFD, 0x7F, 0xC0, 0x50, 0x0A, 0x80, 0x00, 0x02, 0x90, 0x00, 0x01, 0xA0, 0x3F, 0xF0, 0x00, 0x1F, 0xF4, 0x00, 0x0B, 0xFC, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x7F, 0xF0, 0x00, 0x2F, 0xF8, 0x00, 0x0F, 0xFD, 0x3F, 0xD0, 0x00, 0x0F, 0xF0, 0x00, - 0x07, 0xF8, 0x05, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, + 0x07, 0xF8, 0x05, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0B, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xBE, 0x56, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xE0, 0x00, 0x2F, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x0B, 0xC0, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0xC0, 0x00, + 0x01, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xD1, 0xA9, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x0B, 0xFF, 0xFF, 0xFF, 0xF0, 0x2F, 0xE0, 0x00, 0x00, + 0x2F, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFE, + 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x0F, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, + 0x1F, 0xFF, 0xE0, 0x2F, 0xFF, 0xFF, 0xFF, 0xFE, 0x40, 0x1F, 0xFF, 0xF8, 0x7F, 0xFF, 0xFF, 0xFF, + 0x80, 0x00, 0x3F, 0xFF, 0xFD, 0x1F, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xF4, 0x07, 0xFF, + 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xD0, 0x01, 0xFF, 0xFF, 0xF8, 0x00, 0xBF, 0xFF, 0xFF, 0x40, + 0x00, 0x7F, 0xFF, 0xFC, 0x0B, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x1F, 0xFF, 0xFC, 0x0F, 0xFF, 0xFF, + 0xF4, 0x00, 0x00, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x1F, + 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xFF, 0xEB, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFE, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0xFD, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x97, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xD0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph bookerly_18_regularGlyphs[] = { @@ -7315,6 +7335,7 @@ static const EpdGlyph bookerly_18_regularGlyphs[] = { { 22, 27, 38, 8, 27, 149, 105004 }, // ⊥ { 6, 6, 24, 9, 13, 9, 105153 }, // ⋅ { 32, 6, 38, 3, 13, 48, 105162 }, // ⋯ + { 36, 36, 38, 1, 32, 324, 105210 }, // � }; static const EpdUnicodeInterval bookerly_18_regularIntervals[] = { @@ -7378,13 +7399,14 @@ static const EpdUnicodeInterval bookerly_18_regularIntervals[] = { { 0x22A5, 0x22A5, 0x2D5 }, { 0x22C5, 0x22C5, 0x2D6 }, { 0x22EF, 0x22EF, 0x2D7 }, + { 0xFFFD, 0xFFFD, 0x2D8 }, }; static const EpdFontData bookerly_18_regular = { bookerly_18_regularBitmaps, bookerly_18_regularGlyphs, bookerly_18_regularIntervals, - 60, + 61, 49, 40, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_12_bold.h b/lib/EpdFont/builtinFonts/notosans_12_bold.h index 69540f55..5843a599 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_12_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_boldBitmaps[49639] = { +static const uint8_t notosans_12_boldBitmaps[49772] = { 0x7F, 0xAF, 0xE7, 0xF9, 0xFD, 0x7F, 0x5F, 0xD7, 0xF4, 0xFD, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x00, 0x00, 0x02, 0xE2, 0xFE, 0xBF, 0x9F, 0xD0, 0x40, 0x7F, 0x0F, 0xD7, 0xF0, 0xFD, 0x7F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xE0, 0xBC, 0x29, 0x06, 0x80, 0x00, 0x0F, 0x43, 0xD0, 0x00, 0x1F, @@ -3110,7 +3110,15 @@ static const uint8_t notosans_12_boldBitmaps[49639] = { 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xBF, 0x40, 0x00, 0x7F, 0xC0, 0x14, 0x3F, 0xFF, 0xF8, 0x0F, 0xFF, 0xF8, 0x02, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFC, 0x55, 0x55, 0x54, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, - 0xDF, 0xFF, 0xFF, 0xF5, 0xAA, 0xAA, 0xA8, + 0xDF, 0xFF, 0xFF, 0xF5, 0xAA, 0xAA, 0xA8, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x2F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, + 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, + 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, 0xFF, 0xFE, 0x03, 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, + 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, + 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, 0xF0, 0x00, 0x00, 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, + 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_12_boldGlyphs[] = { @@ -3948,6 +3956,7 @@ static const EpdGlyph notosans_12_boldGlyphs[] = { { 12, 24, 14, 2, 21, 72, 49497 }, // ₿ { 12, 19, 13, 1, 14, 57, 49569 }, // ⃀ { 13, 4, 15, 1, 11, 13, 49626 }, // − + { 23, 23, 25, 1, 19, 133, 49639 }, // � }; static const EpdUnicodeInterval notosans_12_boldIntervals[] = { @@ -3962,13 +3971,14 @@ static const EpdUnicodeInterval notosans_12_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_12_bold = { notosans_12_boldBitmaps, notosans_12_boldGlyphs, notosans_12_boldIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h index 1cb1536d..cd44fdb2 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_12_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_bolditalicBitmaps[52863] = { +static const uint8_t notosans_12_bolditalicBitmaps[52996] = { 0x01, 0xFE, 0x02, 0xFE, 0x02, 0xFD, 0x03, 0xFC, 0x03, 0xFC, 0x03, 0xF8, 0x07, 0xF4, 0x0B, 0xF0, 0x0B, 0xF0, 0x0F, 0xE0, 0x0F, 0xD0, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x7F, 0x80, 0xBF, 0x80, 0x7F, 0x00, 0x04, 0x00, 0x2F, 0x4B, 0xD3, 0xF4, 0xFD, 0x3F, 0x0F, 0xC3, 0xE0, 0xF8, @@ -3311,7 +3311,16 @@ static const uint8_t notosans_12_bolditalicBitmaps[52863] = { 0xFC, 0x0F, 0xE0, 0x3F, 0x82, 0xFD, 0x03, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0x80, 0x0B, 0xFF, 0xFD, 0x00, 0xFF, 0x1F, 0xF0, 0x0F, 0xE0, 0x7F, 0x80, 0xFD, 0x03, 0xF8, 0x1F, 0xC0, 0x7F, 0x42, 0xFC, 0x1F, 0xF0, 0x3F, 0xFF, 0xFE, 0x03, 0xFF, 0xFF, 0x80, 0x3F, 0xFF, 0x90, 0x00, 0x34, 0xF0, 0x00, - 0x07, 0x0E, 0x00, 0x00, 0x50, 0x40, 0x00, 0x05, 0x54, 0x3F, 0xFD, 0x7F, 0xFC, 0x7F, 0xFC, + 0x07, 0x0E, 0x00, 0x00, 0x50, 0x40, 0x00, 0x05, 0x54, 0x3F, 0xFD, 0x7F, 0xFC, 0x7F, 0xFC, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x2F, + 0x00, 0x00, 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, 0xFF, + 0xC1, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, 0xFF, + 0xFE, 0x03, 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, 0x00, + 0x3F, 0xFF, 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, 0xF0, + 0x00, 0x00, 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, 0xBF, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_12_bolditalicGlyphs[] = { @@ -4148,6 +4157,7 @@ static const EpdGlyph notosans_12_bolditalicGlyphs[] = { { 18, 21, 15, -1, 21, 95, 52676 }, // ₾ { 14, 24, 14, 0, 21, 84, 52771 }, // ₿ { 8, 4, 8, 0, 9, 8, 52855 }, // − + { 23, 23, 25, 1, 19, 133, 52863 }, // � }; static const EpdUnicodeInterval notosans_12_bolditalicIntervals[] = { @@ -4162,13 +4172,14 @@ static const EpdUnicodeInterval notosans_12_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_12_bolditalic = { notosans_12_bolditalicBitmaps, notosans_12_bolditalicGlyphs, notosans_12_bolditalicIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_12_italic.h b/lib/EpdFont/builtinFonts/notosans_12_italic.h index e4b05ad5..6dad453e 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_12_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_italicBitmaps[48397] = { +static const uint8_t notosans_12_italicBitmaps[48530] = { 0x00, 0xB8, 0x03, 0xE0, 0x0F, 0x40, 0x7C, 0x02, 0xF0, 0x0F, 0x80, 0x3D, 0x00, 0xF0, 0x07, 0xC0, 0x1E, 0x00, 0xB4, 0x03, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x40, 0x7E, 0x01, 0xF4, 0x01, 0x00, 0x00, 0x1E, 0x0F, 0x0B, 0x87, 0xC2, 0xD1, 0xE0, 0xF0, 0xB4, 0x38, 0x2C, 0x0D, 0x0E, 0x02, @@ -3032,7 +3032,16 @@ static const uint8_t notosans_12_italicBitmaps[48397] = { 0x0F, 0x00, 0x2E, 0x07, 0xC0, 0x0B, 0x82, 0xE0, 0x07, 0xC0, 0xF9, 0x5B, 0xD0, 0x3F, 0xFF, 0x80, 0x0F, 0xAB, 0xF4, 0x07, 0xC0, 0x1F, 0x02, 0xE0, 0x03, 0xD0, 0xF4, 0x00, 0xF8, 0x3C, 0x00, 0x3D, 0x0F, 0x00, 0x1F, 0x07, 0xC0, 0x1F, 0x82, 0xFF, 0xFF, 0x80, 0xFF, 0xFE, 0x40, 0x03, 0x8B, 0x00, - 0x00, 0xD3, 0x80, 0x00, 0x10, 0x40, 0x00, 0x2A, 0xA8, 0xFF, 0xE1, 0x55, 0x00, + 0x00, 0xD3, 0x80, 0x00, 0x10, 0x40, 0x00, 0x2A, 0xA8, 0xFF, 0xE1, 0x55, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x2F, 0x00, 0x00, + 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, 0xFF, 0xC1, 0xFF, + 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, 0xFF, 0xFE, 0x03, + 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, 0x00, 0x3F, 0xFF, + 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, 0xF0, 0x00, 0x00, + 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, 0xBF, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, }; static const EpdGlyph notosans_12_italicGlyphs[] = { @@ -3869,6 +3878,7 @@ static const EpdGlyph notosans_12_italicGlyphs[] = { { 17, 21, 15, -1, 21, 90, 48223 }, // ₾ { 13, 24, 14, 1, 21, 78, 48313 }, // ₿ { 7, 3, 8, 0, 8, 6, 48391 }, // − + { 23, 23, 25, 1, 19, 133, 48397 }, // � }; static const EpdUnicodeInterval notosans_12_italicIntervals[] = { @@ -3883,13 +3893,14 @@ static const EpdUnicodeInterval notosans_12_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_12_italic = { notosans_12_italicBitmaps, notosans_12_italicGlyphs, notosans_12_italicIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_12_regular.h b/lib/EpdFont/builtinFonts/notosans_12_regular.h index fd0d91f3..e580f83f 100644 --- a/lib/EpdFont/builtinFonts/notosans_12_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_12_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_12_regularBitmaps[45168] = { +static const uint8_t notosans_12_regularBitmaps[45301] = { 0x3E, 0x3E, 0x3E, 0x3E, 0x3D, 0x2D, 0x2D, 0x2D, 0x2D, 0x2C, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x3E, 0x3F, 0x3E, 0x04, 0x7C, 0x2D, 0x7C, 0x2D, 0x3C, 0x2D, 0x38, 0x2D, 0x38, 0x1C, 0x38, 0x1C, 0x24, 0x08, 0x00, 0x0B, 0x01, 0xC0, 0x00, 0x0E, 0x02, 0xC0, 0x00, 0x0E, 0x03, 0xC0, 0x00, 0x1D, 0x03, @@ -2831,6 +2831,15 @@ static const uint8_t notosans_12_regularBitmaps[45168] = { 0x95, 0x93, 0xE0, 0x00, 0x7C, 0x00, 0x0B, 0x80, 0x00, 0xF8, 0x00, 0x0F, 0x40, 0x00, 0xB8, 0x00, 0x0B, 0x80, 0x00, 0x7C, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xEA, 0xF0, 0x2F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xFF, 0xF6, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x00, + 0x2F, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x2F, 0x00, 0x00, 0x3F, 0xC6, 0xD0, 0x7F, 0x00, 0x03, 0xFF, + 0xFF, 0xC1, 0xFF, 0x00, 0x3F, 0xFF, 0xFE, 0x07, 0xFF, 0x03, 0xFF, 0xFF, 0xE0, 0x3F, 0xFF, 0x2F, + 0xFF, 0xFE, 0x03, 0xFF, 0xFE, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0xF0, 0x3F, 0xFF, 0x82, 0xFF, 0xFF, + 0x00, 0x3F, 0xFF, 0x5F, 0xFF, 0xF0, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF5, 0xFF, + 0xF0, 0x00, 0x00, 0x3F, 0x41, 0xFF, 0x00, 0x00, 0x00, 0x3D, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x3E, + 0xBF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_12_regularGlyphs[] = { @@ -3668,6 +3677,7 @@ static const EpdGlyph notosans_12_regularGlyphs[] = { { 12, 24, 14, 2, 21, 72, 45042 }, // ₿ { 10, 18, 12, 1, 14, 45, 45114 }, // ⃀ { 12, 3, 14, 1, 10, 9, 45159 }, // − + { 23, 23, 25, 1, 19, 133, 45168 }, // � }; static const EpdUnicodeInterval notosans_12_regularIntervals[] = { @@ -3682,13 +3692,14 @@ static const EpdUnicodeInterval notosans_12_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_12_regular = { notosans_12_regularBitmaps, notosans_12_regularGlyphs, notosans_12_regularIntervals, - 11, + 12, 34, 27, -8, diff --git a/lib/EpdFont/builtinFonts/notosans_14_bold.h b/lib/EpdFont/builtinFonts/notosans_14_bold.h index 968dbb73..1f6931e1 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_14_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_boldBitmaps[67224] = { +static const uint8_t notosans_14_boldBitmaps[67413] = { 0x7F, 0xD7, 0xFE, 0x3F, 0xD3, 0xFD, 0x3F, 0xD3, 0xFD, 0x3F, 0xD3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x2F, 0xC2, 0xFC, 0x00, 0x00, 0x00, 0x05, 0x03, 0xFD, 0x7F, 0xE7, 0xFE, 0x3F, 0xC0, 0x50, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0x82, 0xFC, 0x3F, 0x82, 0xFC, @@ -4209,7 +4209,19 @@ static const uint8_t notosans_14_boldBitmaps[67224] = { 0x00, 0x00, 0x7F, 0xE0, 0x00, 0x03, 0xFF, 0x95, 0xB8, 0x1F, 0xFF, 0xFF, 0x80, 0x7F, 0xFF, 0xF8, 0x00, 0xBF, 0xFE, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x06, 0xAA, 0xAA, 0xA8, 0xBF, 0xFF, 0xFF, 0xCB, 0xFF, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xFF, 0xFF, 0xF6, 0xFF, 0xFF, 0xFF, - 0xEB, 0xFF, 0xFF, 0xFF, 0x85, 0x55, 0x55, 0x54, + 0xEB, 0xFF, 0xFF, 0xFF, 0x85, 0x55, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xD0, 0x00, + 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x0F, + 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0xFF, 0x86, 0xE0, 0x2F, 0xD0, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, + 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xD0, 0x0F, 0xFF, 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, + 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, 0xD7, 0xFF, 0xFF, 0xF4, 0x0B, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, + 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x2F, 0xFF, + 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, + 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xF0, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xD0, + 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, 0xD7, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_boldGlyphs[] = { @@ -5047,6 +5059,7 @@ static const EpdGlyph notosans_14_boldGlyphs[] = { { 14, 27, 17, 2, 24, 95, 67033 }, // ₿ { 14, 23, 15, 1, 17, 81, 67128 }, // ⃀ { 15, 4, 17, 1, 12, 15, 67209 }, // − + { 27, 28, 29, 1, 23, 189, 67224 }, // � }; static const EpdUnicodeInterval notosans_14_boldIntervals[] = { @@ -5061,13 +5074,14 @@ static const EpdUnicodeInterval notosans_14_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_14_bold = { notosans_14_boldBitmaps, notosans_14_boldGlyphs, notosans_14_boldIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h index b7ab87aa..a867cf01 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_14_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_bolditalicBitmaps[71405] = { +static const uint8_t notosans_14_bolditalicBitmaps[71594] = { 0x00, 0xBF, 0xC0, 0x0F, 0xFC, 0x00, 0xFF, 0x80, 0x0F, 0xF4, 0x01, 0xFF, 0x00, 0x2F, 0xF0, 0x02, 0xFE, 0x00, 0x3F, 0xD0, 0x03, 0xFC, 0x00, 0x3F, 0xC0, 0x07, 0xF8, 0x00, 0xBF, 0x40, 0x0F, 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0xFC, 0x00, 0xBF, 0xD0, 0x0B, @@ -4470,7 +4470,19 @@ static const uint8_t notosans_14_bolditalicBitmaps[71405] = { 0x00, 0x1F, 0xE0, 0x7F, 0xD0, 0x0B, 0xF4, 0x0F, 0xF8, 0x03, 0xFC, 0x03, 0xFE, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0xC0, 0xBF, 0xD0, 0x1F, 0xFA, 0xFF, 0xF0, 0x0B, 0xFF, 0xFF, 0xF4, 0x03, 0xFF, 0xFF, 0xF4, 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x03, 0xC3, 0xC0, 0x00, 0x00, 0xF0, 0xF0, 0x00, 0x00, - 0x38, 0x38, 0x00, 0x00, 0x2A, 0xAA, 0x4F, 0xFF, 0xE3, 0xFF, 0xF5, 0xFF, 0xFC, + 0x38, 0x38, 0x00, 0x00, 0x2A, 0xAA, 0x4F, 0xFF, 0xE3, 0xFF, 0xF5, 0xFF, 0xFC, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xD0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, 0x00, 0x00, 0x00, 0xF4, 0x00, + 0x0F, 0xD0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0xFF, 0x86, 0xE0, 0x2F, 0xD0, + 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xD0, 0x0F, 0xFF, + 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, 0xD7, 0xFF, 0xFF, 0xF4, 0x0B, + 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x07, 0xFF, 0xFF, 0x80, + 0x07, 0xFF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x07, 0xFF, + 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xF0, 0x0F, 0xF8, + 0x00, 0x00, 0x00, 0x07, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, 0xD7, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_bolditalicGlyphs[] = { @@ -5307,6 +5319,7 @@ static const EpdGlyph notosans_14_bolditalicGlyphs[] = { { 20, 24, 18, -1, 24, 120, 71161 }, // ₾ { 17, 27, 16, 0, 24, 115, 71281 }, // ₿ { 9, 4, 9, 0, 10, 9, 71396 }, // − + { 27, 28, 29, 1, 23, 189, 71405 }, // � }; static const EpdUnicodeInterval notosans_14_bolditalicIntervals[] = { @@ -5321,13 +5334,14 @@ static const EpdUnicodeInterval notosans_14_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_14_bolditalic = { notosans_14_bolditalicBitmaps, notosans_14_bolditalicGlyphs, notosans_14_bolditalicIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_14_italic.h b/lib/EpdFont/builtinFonts/notosans_14_italic.h index d0091c08..b112b3ae 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_14_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_italicBitmaps[65135] = { +static const uint8_t notosans_14_italicBitmaps[65324] = { 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0B, 0xD0, 0x02, 0xF0, 0x00, 0xFC, 0x00, 0x3E, 0x00, 0x0F, 0x40, 0x07, 0xC0, 0x02, 0xF0, 0x00, 0xF8, 0x00, 0x3D, 0x00, 0x0F, 0x00, 0x07, 0xC0, 0x01, 0xE0, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x03, 0xF0, 0x01, 0xFC, 0x00, 0x7F, 0x00, 0x05, @@ -4078,7 +4078,19 @@ static const uint8_t notosans_14_italicBitmaps[65135] = { 0x0B, 0xFF, 0xFD, 0x00, 0x0F, 0xC0, 0x6F, 0x80, 0x0F, 0x80, 0x0B, 0xD0, 0x0F, 0x40, 0x03, 0xE0, 0x1F, 0x00, 0x03, 0xE0, 0x2F, 0x00, 0x03, 0xE0, 0x3E, 0x00, 0x07, 0xD0, 0x3E, 0x00, 0x0F, 0xC0, 0x7D, 0x01, 0xBF, 0x40, 0x7F, 0xFF, 0xFD, 0x00, 0xBF, 0xFF, 0xD0, 0x00, 0x07, 0x4B, 0x00, 0x00, - 0x0B, 0x0F, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x3F, 0xFF, 0x0F, 0xFF, 0xC1, 0x55, 0x50, + 0x0B, 0x0F, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x3F, 0xFF, 0x0F, 0xFF, 0xC1, 0x55, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xD0, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, 0x00, 0x00, 0x00, + 0xF4, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0xFF, 0x86, 0xE0, + 0x2F, 0xD0, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xD0, + 0x0F, 0xFF, 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, 0xD7, 0xFF, 0xFF, + 0xF4, 0x0B, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, 0xFE, 0x07, 0xFF, + 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, + 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x07, 0xF0, + 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, 0xD7, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_italicGlyphs[] = { @@ -4915,6 +4927,7 @@ static const EpdGlyph notosans_14_italicGlyphs[] = { { 20, 24, 17, -1, 24, 120, 64900 }, // ₾ { 16, 27, 16, 1, 24, 108, 65020 }, // ₿ { 9, 3, 9, 0, 9, 7, 65128 }, // − + { 27, 28, 29, 1, 23, 189, 65135 }, // � }; static const EpdUnicodeInterval notosans_14_italicIntervals[] = { @@ -4929,13 +4942,14 @@ static const EpdUnicodeInterval notosans_14_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_14_italic = { notosans_14_italicBitmaps, notosans_14_italicGlyphs, notosans_14_italicIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_14_regular.h b/lib/EpdFont/builtinFonts/notosans_14_regular.h index 429c50d0..edc03246 100644 --- a/lib/EpdFont/builtinFonts/notosans_14_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_14_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_14_regularBitmaps[61202] = { +static const uint8_t notosans_14_regularBitmaps[61391] = { 0xBD, 0xBD, 0xBD, 0x7D, 0x7D, 0x7C, 0x7C, 0x7C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00, 0x14, 0xBE, 0xFE, 0xBD, 0x14, 0x3E, 0x0B, 0xCF, 0x82, 0xF3, 0xD0, 0xBC, 0xF4, 0x2E, 0x3D, 0x07, 0x8B, 0x41, 0xE2, 0xC0, 0x78, 0x60, 0x09, 0x00, 0x02, 0xC0, 0x1D, 0x00, 0x00, 0x0F, 0x00, @@ -3833,7 +3833,18 @@ static const uint8_t notosans_14_regularBitmaps[61202] = { 0x00, 0x00, 0xBC, 0x00, 0x00, 0x7D, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x1F, 0xD0, 0x05, 0x07, 0xFF, 0xFE, 0x00, 0xBF, 0xFD, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xFE, 0x7F, 0xFF, 0xFE, 0x15, 0x55, 0x54, 0x15, 0x55, 0x55, 0x52, 0xFF, 0xFF, 0xFF, 0xC7, 0xFF, 0xFF, - 0xFF, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xD0, 0x00, 0x00, 0x00, 0x0F, 0xE9, 0x6F, 0xD0, + 0x00, 0x00, 0x00, 0xF4, 0x00, 0x0F, 0xD0, 0x00, 0x00, 0x0F, 0xC0, 0x00, 0x0F, 0xD0, 0x00, 0x00, + 0xFF, 0x86, 0xE0, 0x2F, 0xD0, 0x00, 0x0F, 0xFF, 0xFF, 0xC0, 0x7F, 0xD0, 0x00, 0xFF, 0xFF, 0xFF, + 0x02, 0xFF, 0xD0, 0x0F, 0xFF, 0xFF, 0xF4, 0x0F, 0xFF, 0xD0, 0xFF, 0xFF, 0xFF, 0x40, 0xBF, 0xFF, + 0xD7, 0xFF, 0xFF, 0xF4, 0x0B, 0xFF, 0xFF, 0x87, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xF8, 0x07, 0xFF, + 0xFE, 0x07, 0xFF, 0xFF, 0x80, 0x07, 0xFF, 0xF8, 0x2F, 0xFF, 0xF8, 0x00, 0x07, 0xFF, 0xFF, 0xFF, + 0xFF, 0x80, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x07, 0xFD, 0x07, 0xFF, 0x80, 0x00, + 0x00, 0x07, 0xF0, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x07, 0xD0, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x07, + 0xD7, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_14_regularGlyphs[] = { @@ -4671,6 +4682,7 @@ static const EpdGlyph notosans_14_regularGlyphs[] = { { 14, 27, 17, 2, 24, 95, 61032 }, // ₿ { 12, 21, 14, 1, 16, 63, 61127 }, // ⃀ { 15, 3, 17, 1, 12, 12, 61190 }, // − + { 27, 28, 29, 1, 23, 189, 61202 }, // � }; static const EpdUnicodeInterval notosans_14_regularIntervals[] = { @@ -4685,13 +4697,14 @@ static const EpdUnicodeInterval notosans_14_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_14_regular = { notosans_14_regularBitmaps, notosans_14_regularGlyphs, notosans_14_regularIntervals, - 11, + 12, 40, 32, -9, diff --git a/lib/EpdFont/builtinFonts/notosans_16_bold.h b/lib/EpdFont/builtinFonts/notosans_16_bold.h index 29b0bd21..b273a2f7 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_16_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_boldBitmaps[86944] = { +static const uint8_t notosans_16_boldBitmaps[87192] = { 0x3F, 0xF4, 0xFF, 0xD3, 0xFF, 0x4F, 0xFD, 0x3F, 0xF4, 0xFF, 0xD3, 0xFF, 0x0F, 0xFC, 0x2F, 0xF0, 0xBF, 0xC2, 0xFF, 0x0B, 0xFC, 0x1F, 0xF0, 0x7F, 0xC1, 0xFF, 0x07, 0xF8, 0x05, 0x40, 0x00, 0x00, 0x00, 0x07, 0xF8, 0x3F, 0xF4, 0xFF, 0xE3, 0xFF, 0x4B, 0xFC, 0x01, 0x40, 0xFF, 0x82, 0xFE, 0xFF, @@ -5442,6 +5442,22 @@ static const uint8_t notosans_16_boldBitmaps[86944] = { 0xFF, 0xE0, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x55, 0x55, 0x54, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x7F, 0xFF, 0xFF, 0xFC, 0x2A, 0xAA, 0xAA, 0xAA, 0x5F, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, + 0xC1, 0xA8, 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xE0, 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, + 0xF0, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, + 0x07, 0xFF, 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, + 0xFF, 0xFF, 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF4, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, + 0xF4, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_boldGlyphs[] = { @@ -6279,6 +6295,7 @@ static const EpdGlyph notosans_16_boldGlyphs[] = { { 15, 32, 19, 3, 28, 120, 86702 }, // ₿ { 16, 25, 17, 1, 19, 100, 86822 }, // ⃀ { 17, 5, 19, 1, 14, 22, 86922 }, // − + { 31, 32, 33, 1, 26, 248, 86944 }, // � }; static const EpdUnicodeInterval notosans_16_boldIntervals[] = { @@ -6293,13 +6310,14 @@ static const EpdUnicodeInterval notosans_16_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_16_bold = { notosans_16_boldBitmaps, notosans_16_boldGlyphs, notosans_16_boldIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h index 8b0d1e85..e92077e2 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_16_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_bolditalicBitmaps[92423] = { +static const uint8_t notosans_16_bolditalicBitmaps[92671] = { 0x00, 0x3F, 0xF4, 0x01, 0xFF, 0xD0, 0x07, 0xFF, 0x00, 0x2F, 0xF8, 0x00, 0xFF, 0xD0, 0x03, 0xFF, 0x00, 0x0F, 0xFC, 0x00, 0x7F, 0xE0, 0x01, 0xFF, 0x40, 0x0B, 0xFC, 0x00, 0x3F, 0xF0, 0x00, 0xFF, 0x80, 0x03, 0xFD, 0x00, 0x1F, 0xF0, 0x00, 0x7F, 0xC0, 0x02, 0xFE, 0x00, 0x01, 0x50, 0x00, 0x00, @@ -5784,7 +5784,22 @@ static const uint8_t notosans_16_bolditalicBitmaps[92423] = { 0xFE, 0x07, 0xFF, 0xC0, 0x1F, 0xFF, 0xFF, 0xFE, 0x00, 0xBF, 0xFF, 0xFF, 0xF0, 0x03, 0xFF, 0xFF, 0xFE, 0x00, 0x0F, 0xFF, 0xFF, 0x40, 0x00, 0x01, 0xF0, 0xF4, 0x00, 0x00, 0x07, 0x83, 0xC0, 0x00, 0x00, 0x2E, 0x1F, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x2F, 0xFF, 0xF3, 0xFF, 0xFE, 0x3F, - 0xFF, 0xD7, 0xFF, 0xFD, 0x00, 0x00, 0x00, + 0xFF, 0xD7, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, + 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, + 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, 0xC1, 0xA8, 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, + 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, + 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, + 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, + 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, 0xFF, 0xFF, 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, + 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, + 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, 0xF4, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, + 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_bolditalicGlyphs[] = { @@ -6621,6 +6636,7 @@ static const EpdGlyph notosans_16_bolditalicGlyphs[] = { { 23, 28, 20, -1, 28, 161, 92097 }, // ₾ { 19, 32, 18, 0, 28, 152, 92258 }, // ₿ { 10, 5, 11, 0, 11, 13, 92410 }, // − + { 31, 32, 33, 1, 26, 248, 92423 }, // � }; static const EpdUnicodeInterval notosans_16_bolditalicIntervals[] = { @@ -6635,13 +6651,14 @@ static const EpdUnicodeInterval notosans_16_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_16_bolditalic = { notosans_16_bolditalicBitmaps, notosans_16_bolditalicGlyphs, notosans_16_bolditalicIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_16_italic.h b/lib/EpdFont/builtinFonts/notosans_16_italic.h index fed176a0..86fedbfb 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_16_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_italicBitmaps[83982] = { +static const uint8_t notosans_16_italicBitmaps[84230] = { 0x00, 0x1F, 0xC0, 0x02, 0xFC, 0x00, 0x3F, 0x80, 0x03, 0xF4, 0x00, 0x3F, 0x00, 0x07, 0xF0, 0x00, 0xBE, 0x00, 0x0B, 0xD0, 0x00, 0xFC, 0x00, 0x0F, 0xC0, 0x00, 0xF8, 0x00, 0x1F, 0x40, 0x02, 0xF0, 0x00, 0x3F, 0x00, 0x03, 0xE0, 0x00, 0x3D, 0x00, 0x07, 0xC0, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, @@ -5256,7 +5256,23 @@ static const uint8_t notosans_16_italicBitmaps[83982] = { 0x00, 0x7F, 0x01, 0xF8, 0x00, 0x07, 0xE0, 0x1F, 0x40, 0x00, 0xBE, 0x02, 0xF4, 0x00, 0x0F, 0xC0, 0x3F, 0x00, 0x07, 0xF8, 0x03, 0xFA, 0xAB, 0xFF, 0x00, 0x7F, 0xFF, 0xFF, 0x80, 0x0B, 0xFF, 0xFF, 0x80, 0x00, 0x03, 0xC2, 0xD0, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x07, 0x83, 0xC0, 0x00, 0x00, - 0x10, 0x10, 0x00, 0x00, 0x05, 0x55, 0x42, 0xFF, 0xFC, 0x3F, 0xFF, 0xC1, 0x55, 0x54, + 0x10, 0x10, 0x00, 0x00, 0x05, 0x55, 0x42, 0xFF, 0xFC, 0x3F, 0xFF, 0xC1, 0x55, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, + 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, + 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, 0xC1, 0xA8, + 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xE0, + 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, + 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, + 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, 0xFF, 0xFF, + 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF4, + 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, 0xF4, 0x00, + 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_italicGlyphs[] = { @@ -6093,6 +6109,7 @@ static const EpdGlyph notosans_16_italicGlyphs[] = { { 22, 28, 20, -1, 28, 154, 83674 }, // ₾ { 18, 32, 18, 1, 28, 144, 83828 }, // ₿ { 10, 4, 10, 0, 11, 10, 83972 }, // − + { 31, 32, 33, 1, 26, 248, 83982 }, // � }; static const EpdUnicodeInterval notosans_16_italicIntervals[] = { @@ -6107,13 +6124,14 @@ static const EpdUnicodeInterval notosans_16_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_16_italic = { notosans_16_italicBitmaps, notosans_16_italicGlyphs, notosans_16_italicIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_16_regular.h b/lib/EpdFont/builtinFonts/notosans_16_regular.h index 1604c06d..a2ee89ff 100644 --- a/lib/EpdFont/builtinFonts/notosans_16_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_16_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_16_regularBitmaps[78480] = { +static const uint8_t notosans_16_regularBitmaps[78728] = { 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xFC, 0x3F, 0x0F, 0xC3, 0xF0, 0xF8, 0x2E, 0x0B, 0x82, 0xE0, 0xB8, 0x2D, 0x01, 0x00, 0x00, 0x00, 0x3F, 0x2F, 0xDB, 0xF9, 0xFC, 0x04, 0x00, 0xBC, 0x0B, 0xDB, 0xC0, 0xBD, 0xBC, 0x0B, 0xDB, 0xC0, 0x7C, 0xBC, 0x07, 0xC7, 0xC0, 0x7C, 0x7C, @@ -4913,6 +4913,22 @@ static const uint8_t notosans_16_regularBitmaps[78480] = { 0x2F, 0x80, 0x00, 0x01, 0xFD, 0x00, 0x00, 0x0B, 0xF9, 0x06, 0xD0, 0x2F, 0xFF, 0xFD, 0x00, 0x7F, 0xFF, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, 0x55, 0x55, 0x54, 0x3F, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFD, 0x7F, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xD1, 0x55, 0x55, 0x55, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0xFF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE4, 0x06, 0xFD, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0xFD, 0x00, 0x00, 0x00, 0xFF, + 0xC1, 0xA8, 0x03, 0xFD, 0x00, 0x00, 0x0F, 0xFF, 0xBF, 0xF4, 0x0B, 0xFD, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xE0, 0x2F, 0xFD, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFD, 0x00, 0xFF, 0xFF, 0xFF, + 0xF0, 0x07, 0xFF, 0xFD, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xF0, + 0x07, 0xFF, 0xFF, 0xF4, 0x3F, 0xFF, 0xFF, 0x80, 0xBF, 0xFF, 0xFF, 0x40, 0x3F, 0xFF, 0xFD, 0x03, + 0xFF, 0xFF, 0xF4, 0x00, 0x3F, 0xFF, 0xF4, 0x1F, 0xFF, 0xFF, 0x40, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF4, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x00, 0x00, 0x3F, 0xFF, 0x5B, 0xFF, + 0xF4, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x0F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0x2F, 0xF4, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x5B, 0xF4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_16_regularGlyphs[] = { @@ -5750,6 +5766,7 @@ static const EpdGlyph notosans_16_regularGlyphs[] = { { 15, 32, 19, 3, 28, 120, 78263 }, // ₿ { 14, 24, 16, 1, 19, 84, 78383 }, // ⃀ { 17, 3, 19, 1, 13, 13, 78467 }, // − + { 31, 32, 33, 1, 26, 248, 78480 }, // � }; static const EpdUnicodeInterval notosans_16_regularIntervals[] = { @@ -5764,13 +5781,14 @@ static const EpdUnicodeInterval notosans_16_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_16_regular = { notosans_16_regularBitmaps, notosans_16_regularGlyphs, notosans_16_regularIntervals, - 11, + 12, 45, 36, -10, diff --git a/lib/EpdFont/builtinFonts/notosans_18_bold.h b/lib/EpdFont/builtinFonts/notosans_18_bold.h index b3e925e8..982b1dcc 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_bold.h +++ b/lib/EpdFont/builtinFonts/notosans_18_bold.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_boldBitmaps[108125] = { +static const uint8_t notosans_18_boldBitmaps[108432] = { 0xBF, 0xF7, 0xFF, 0xDF, 0xFF, 0x6F, 0xFD, 0xBF, 0xF2, 0xFF, 0xCB, 0xFF, 0x2F, 0xFC, 0x7F, 0xF1, 0xFF, 0xC7, 0xFF, 0x1F, 0xFC, 0x7F, 0xF0, 0xFF, 0xC3, 0xFE, 0x0F, 0xF8, 0x3F, 0xE0, 0xFF, 0x81, 0x54, 0x00, 0x00, 0x00, 0x00, 0x6E, 0x0B, 0xFF, 0x3F, 0xFD, 0xFF, 0xF7, 0xFF, 0xD7, 0xFE, 0x01, @@ -6765,7 +6765,26 @@ static const uint8_t notosans_18_boldBitmaps[108125] = { 0xF8, 0x00, 0x1F, 0xFF, 0xFD, 0x00, 0x00, 0x01, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xC3, 0xFF, 0xFF, 0xFF, 0xFC, 0x3F, 0xFF, 0xFF, 0xFF, 0xC2, 0xAA, 0xAA, 0xAA, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3, 0xFF, - 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, + 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, + 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, + 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x1F, 0xFF, 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, + 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, + 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, + 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0x40, 0x7F, 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, + 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, + 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, + 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, + 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_boldGlyphs[] = { @@ -7603,6 +7622,7 @@ static const EpdGlyph notosans_18_boldGlyphs[] = { { 18, 35, 21, 3, 31, 158, 107817 }, // ₿ { 18, 28, 20, 1, 21, 126, 107975 }, // ⃀ { 19, 5, 22, 1, 16, 24, 108101 }, // − + { 35, 35, 38, 1, 29, 307, 108125 }, // � }; static const EpdUnicodeInterval notosans_18_boldIntervals[] = { @@ -7617,13 +7637,14 @@ static const EpdUnicodeInterval notosans_18_boldIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_18_bold = { notosans_18_boldBitmaps, notosans_18_boldGlyphs, notosans_18_boldIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h b/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h index 4a34f197..aff1b253 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h +++ b/lib/EpdFont/builtinFonts/notosans_18_bolditalic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_bolditalicBitmaps[115270] = { +static const uint8_t notosans_18_bolditalicBitmaps[115577] = { 0x00, 0x1F, 0xFE, 0x00, 0x2F, 0xFE, 0x00, 0x3F, 0xFD, 0x00, 0x3F, 0xFC, 0x00, 0x3F, 0xFC, 0x00, 0x7F, 0xF8, 0x00, 0x7F, 0xF4, 0x00, 0xBF, 0xF0, 0x00, 0xFF, 0xF0, 0x00, 0xFF, 0xE0, 0x00, 0xFF, 0xD0, 0x01, 0xFF, 0xC0, 0x02, 0xFF, 0x80, 0x02, 0xFF, 0x40, 0x03, 0xFF, 0x00, 0x03, 0xFF, 0x00, @@ -7212,7 +7212,26 @@ static const uint8_t notosans_18_bolditalicBitmaps[115270] = { 0xFF, 0xFF, 0xFF, 0x40, 0x0B, 0xFF, 0xFF, 0xFF, 0x00, 0x03, 0xFF, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xE0, 0xF8, 0x00, 0x00, 0x00, 0xF8, 0x3E, 0x00, 0x00, 0x00, 0x3D, 0x0F, 0x40, 0x00, 0x00, 0x1A, 0x06, 0x80, 0x00, 0x00, 0x05, 0x55, 0x54, 0x2F, 0xFF, 0xFC, 0x3F, 0xFF, 0xFC, 0x3F, 0xFF, 0xF8, - 0x3F, 0xFF, 0xF4, 0x15, 0x55, 0x50, + 0x3F, 0xFF, 0xF4, 0x15, 0x55, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, + 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x1F, + 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, 0x00, + 0x1F, 0xFF, 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, + 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, + 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, + 0x3F, 0xFF, 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, + 0x40, 0x7F, 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0xFF, + 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, 0x00, + 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x02, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_bolditalicGlyphs[] = { @@ -8049,6 +8068,7 @@ static const EpdGlyph notosans_18_bolditalicGlyphs[] = { { 26, 31, 23, -1, 31, 202, 114866 }, // ₾ { 21, 35, 21, 0, 31, 184, 115068 }, // ₿ { 12, 6, 12, 0, 13, 18, 115252 }, // − + { 35, 35, 38, 1, 29, 307, 115270 }, // � }; static const EpdUnicodeInterval notosans_18_bolditalicIntervals[] = { @@ -8063,13 +8083,14 @@ static const EpdUnicodeInterval notosans_18_bolditalicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_18_bolditalic = { notosans_18_bolditalicBitmaps, notosans_18_bolditalicGlyphs, notosans_18_bolditalicIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_18_italic.h b/lib/EpdFont/builtinFonts/notosans_18_italic.h index 6be5ad98..723fc7d4 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_italic.h +++ b/lib/EpdFont/builtinFonts/notosans_18_italic.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_italicBitmaps[105127] = { +static const uint8_t notosans_18_italicBitmaps[105434] = { 0x00, 0x0B, 0xF0, 0x00, 0x3F, 0xC0, 0x00, 0xFF, 0x00, 0x07, 0xF8, 0x00, 0x1F, 0xD0, 0x00, 0xBF, 0x00, 0x03, 0xFC, 0x00, 0x0F, 0xE0, 0x00, 0x3F, 0x40, 0x01, 0xFC, 0x00, 0x0B, 0xF0, 0x00, 0x2F, 0x80, 0x00, 0xFD, 0x00, 0x03, 0xF0, 0x00, 0x0F, 0xC0, 0x00, 0x7E, 0x00, 0x02, 0xF4, 0x00, 0x0F, @@ -6578,7 +6578,26 @@ static const uint8_t notosans_18_italicBitmaps[105127] = { 0xC0, 0x00, 0x3F, 0xC0, 0x2F, 0x80, 0x02, 0xFF, 0x40, 0x3F, 0xFF, 0xFF, 0xFD, 0x00, 0x3F, 0xFF, 0xFF, 0xF4, 0x00, 0x7F, 0xFF, 0xFE, 0x40, 0x00, 0x01, 0xF0, 0xB8, 0x00, 0x00, 0x02, 0xE0, 0xF4, 0x00, 0x00, 0x03, 0xD0, 0xF4, 0x00, 0x00, 0x02, 0x80, 0xA0, 0x00, 0x00, 0x0A, 0xAA, 0xA0, 0xBF, - 0xFF, 0xD3, 0xFF, 0xFF, 0x05, 0x55, 0x54, + 0xFF, 0xD3, 0xFF, 0xFF, 0x05, 0x55, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, + 0xE0, 0x00, 0x2F, 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, + 0x1F, 0xF0, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, + 0x00, 0x1F, 0xFF, 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, + 0xE0, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x7F, 0xFF, 0xE0, 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, + 0x00, 0x3F, 0xFF, 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, + 0xFF, 0x40, 0x7F, 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, + 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, + 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, + 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_italicGlyphs[] = { @@ -7415,6 +7434,7 @@ static const EpdGlyph notosans_18_italicGlyphs[] = { { 25, 31, 22, -1, 31, 194, 104747 }, // ₾ { 20, 35, 21, 1, 31, 175, 104941 }, // ₿ { 11, 4, 12, 0, 12, 11, 105116 }, // − + { 35, 35, 38, 1, 29, 307, 105127 }, // � }; static const EpdUnicodeInterval notosans_18_italicIntervals[] = { @@ -7429,13 +7449,14 @@ static const EpdUnicodeInterval notosans_18_italicIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20BF, 0x320 }, { 0x2212, 0x2212, 0x340 }, + { 0xFFFD, 0xFFFD, 0x341 }, }; static const EpdFontData notosans_18_italic = { notosans_18_italicBitmaps, notosans_18_italicGlyphs, notosans_18_italicIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_18_regular.h b/lib/EpdFont/builtinFonts/notosans_18_regular.h index a934c691..5a5eedbe 100644 --- a/lib/EpdFont/builtinFonts/notosans_18_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_18_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_18_regularBitmaps[98532] = { +static const uint8_t notosans_18_regularBitmaps[98839] = { 0x2F, 0xC3, 0xFC, 0x3F, 0xC3, 0xFC, 0x3F, 0xC2, 0xFC, 0x2F, 0x82, 0xF8, 0x2F, 0x82, 0xF8, 0x1F, 0x81, 0xF4, 0x1F, 0x41, 0xF4, 0x1F, 0x40, 0xF4, 0x0F, 0x40, 0xF0, 0x0F, 0x00, 0x50, 0x00, 0x00, 0x00, 0x05, 0x03, 0xFC, 0x7F, 0xD3, 0xFD, 0x3F, 0xC0, 0x50, 0x7F, 0x02, 0xF9, 0xFC, 0x0B, 0xF7, @@ -6166,7 +6166,26 @@ static const uint8_t notosans_18_regularBitmaps[98532] = { 0xBC, 0x00, 0xFF, 0xFF, 0xFC, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFD, 0x3F, 0xFF, 0xFF, 0xFD, 0x2A, 0xAA, 0xAA, 0xA8, 0x2A, 0xAA, 0xAA, 0xAA, 0xA4, 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, - 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xE0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xE0, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFA, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xE0, 0x00, 0x2F, + 0xE0, 0x00, 0x00, 0x00, 0x01, 0xFC, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x00, 0x1F, 0xF0, 0x00, + 0x00, 0x1F, 0xE0, 0x00, 0x00, 0x01, 0xFF, 0xD0, 0x6A, 0x00, 0x3F, 0xE0, 0x00, 0x00, 0x1F, 0xFF, + 0xDF, 0xFE, 0x00, 0xFF, 0xE0, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xE0, 0x00, 0x1F, + 0xFF, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xE0, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7F, 0xFF, 0xE0, + 0x1F, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x3F, 0xFF, + 0xFF, 0xE2, 0xFF, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xFF, 0x02, 0xFF, 0xFF, 0xFF, 0x40, 0x7F, + 0xFF, 0xFF, 0xF0, 0x02, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x02, 0xFF, 0xFF, 0xF0, + 0x0F, 0xFF, 0xFF, 0xF0, 0x00, 0x02, 0xFF, 0xFF, 0xEA, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x02, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x02, 0xFF, 0xF4, 0x0F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x80, 0x1F, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x02, 0xFE, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFC, 0x02, 0xFF, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xF9, 0x6F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, }; static const EpdGlyph notosans_18_regularGlyphs[] = { @@ -7004,6 +7023,7 @@ static const EpdGlyph notosans_18_regularGlyphs[] = { { 18, 35, 21, 3, 31, 158, 98247 }, // ₿ { 16, 27, 18, 1, 21, 108, 98405 }, // ⃀ { 19, 4, 21, 1, 15, 19, 98513 }, // − + { 35, 35, 38, 1, 29, 307, 98532 }, // � }; static const EpdUnicodeInterval notosans_18_regularIntervals[] = { @@ -7018,13 +7038,14 @@ static const EpdUnicodeInterval notosans_18_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_18_regular = { notosans_18_regularBitmaps, notosans_18_regularGlyphs, notosans_18_regularIntervals, - 11, + 12, 51, 41, -11, diff --git a/lib/EpdFont/builtinFonts/notosans_8_regular.h b/lib/EpdFont/builtinFonts/notosans_8_regular.h index 9296ac53..b6c07922 100644 --- a/lib/EpdFont/builtinFonts/notosans_8_regular.h +++ b/lib/EpdFont/builtinFonts/notosans_8_regular.h @@ -7,7 +7,7 @@ #pragma once #include "EpdFontData.h" -static const uint8_t notosans_8_regularBitmaps[10949] = { +static const uint8_t notosans_8_regularBitmaps[10981] = { 0xDB, 0x6D, 0xB6, 0xC3, 0xF4, 0xDE, 0xF7, 0xBD, 0x80, 0x0D, 0x83, 0x30, 0x66, 0x3F, 0xF7, 0xFE, 0x36, 0x04, 0xC7, 0xFE, 0xFF, 0xC6, 0x40, 0xD8, 0x1B, 0x00, 0x18, 0x18, 0xFE, 0xFE, 0xD8, 0xF8, 0xFC, 0x3E, 0x1F, 0x1B, 0xFF, 0xFE, 0x38, 0x18, 0x00, 0x01, 0xE1, 0x86, 0xCC, 0x13, 0x30, 0xCD, @@ -692,7 +692,9 @@ static const uint8_t notosans_8_regularBitmaps[10949] = { 0x07, 0x01, 0xC0, 0x1B, 0x03, 0xE1, 0xFF, 0x3D, 0xED, 0xBF, 0xB6, 0xF6, 0xDE, 0x53, 0xC0, 0x1C, 0x01, 0x80, 0x3F, 0xE7, 0xFC, 0x3C, 0x3C, 0xFE, 0xFF, 0xE3, 0xE3, 0xE7, 0xFE, 0xFF, 0xE3, 0xE3, 0xE3, 0xFF, 0xFE, 0x3C, 0x3C, 0x00, 0x3F, 0x7E, 0x60, 0x60, 0xE0, 0xE0, 0x60, 0x7E, 0x3F, 0x0C, - 0x7F, 0x7E, 0x7F, 0xFF, 0xC0, + 0x7F, 0x7E, 0x7F, 0xFF, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x03, 0xE0, 0x07, 0xF0, 0x0C, 0x38, 0x1F, + 0xDC, 0x3F, 0xDE, 0x7F, 0xBF, 0x7F, 0x7F, 0x3F, 0x7E, 0x1F, 0xFC, 0x0F, 0xF8, 0x06, 0x70, 0x03, + 0xE0, 0x01, 0xC0, 0x00, 0x80, }; static const EpdGlyph notosans_8_regularGlyphs[] = { @@ -1530,6 +1532,7 @@ static const EpdGlyph notosans_8_regularGlyphs[] = { { 8, 16, 10, 1, 14, 16, 10917 }, // ₿ { 8, 13, 8, 0, 10, 13, 10933 }, // ⃀ { 9, 2, 10, 0, 7, 3, 10946 }, // − + { 16, 16, 17, 0, 13, 32, 10949 }, // � }; static const EpdUnicodeInterval notosans_8_regularIntervals[] = { @@ -1544,13 +1547,14 @@ static const EpdUnicodeInterval notosans_8_regularIntervals[] = { { 0x2066, 0x206F, 0x316 }, { 0x20A0, 0x20C0, 0x320 }, { 0x2212, 0x2212, 0x341 }, + { 0xFFFD, 0xFFFD, 0x342 }, }; static const EpdFontData notosans_8_regular = { notosans_8_regularBitmaps, notosans_8_regularGlyphs, notosans_8_regularIntervals, - 11, + 12, 23, 18, -5, diff --git a/lib/EpdFont/scripts/fontconvert.py b/lib/EpdFont/scripts/fontconvert.py index ca923f90..7d4274ed 100755 --- a/lib/EpdFont/scripts/fontconvert.py +++ b/lib/EpdFont/scripts/fontconvert.py @@ -99,6 +99,9 @@ intervals = [ # (0xFE30, 0xFE4F), # # CJK Compatibility Ideographs # (0xF900, 0xFAFF), + ### Specials + # Replacement Character + (0xFFFD, 0xFFFD), ] add_ints = [] diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index 7072fed8..e5b25bee 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -582,7 +582,7 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y while ((cp = utf8NextCodepoint(reinterpret_cast(&text)))) { const EpdGlyph* glyph = font.getGlyph(cp, style); if (!glyph) { - glyph = font.getGlyph('?', style); + glyph = font.getGlyph(REPLACEMENT_GLYPH, style); } if (!glyph) { continue; @@ -760,8 +760,7 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp, const bool pixelState, const EpdFontFamily::Style style) const { const EpdGlyph* glyph = fontFamily.getGlyph(cp, style); if (!glyph) { - // TODO: Replace with fallback glyph property? - glyph = fontFamily.getGlyph('?', style); + glyph = fontFamily.getGlyph(REPLACEMENT_GLYPH, style); } // no glyph? diff --git a/lib/Utf8/Utf8.h b/lib/Utf8/Utf8.h index 0209bc25..095c1584 100644 --- a/lib/Utf8/Utf8.h +++ b/lib/Utf8/Utf8.h @@ -2,4 +2,6 @@ #include +#define REPLACEMENT_GLYPH 0xFFFD + uint32_t utf8NextCodepoint(const unsigned char** string);