mirror of
https://github.com/crosspoint-reader/crosspoint-reader.git
synced 2026-08-13 14:21:57 -07:00
Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd00c185f2 | ||
|
|
f180069643 | ||
|
|
a0ec5812b1 | ||
|
|
e84840b473 | ||
|
|
94ae750e89 | ||
|
|
8c5cd67f38 | ||
|
|
c5787d1cc1 | ||
|
|
2a19eb9e0d | ||
|
|
fae3423dec | ||
|
|
932a472835 | ||
|
|
552b2683e6 | ||
|
|
bfa1d706b1 | ||
|
|
73ab9ab20d | ||
|
|
3a97f3e63e | ||
|
|
39ea4b045f | ||
|
|
444d87de82 | ||
|
|
859f6cb0d5 | ||
|
|
d8139e9605 | ||
|
|
b596f21e61 | ||
|
|
5fbc657aeb | ||
|
|
bb06219c9c | ||
|
|
5202bbf911 | ||
|
|
e0253a8664 | ||
|
|
e142e88ce7 | ||
|
|
6add0b91bc | ||
|
|
287457f7dd | ||
|
|
3e627112f6 | ||
|
|
1f5669a08a | ||
|
|
0dc92c142c | ||
|
|
4b34a576eb | ||
|
|
4fb843ef92 | ||
|
|
a43061305a | ||
|
|
7ec07b4d9d | ||
|
|
c2c1badc7e | ||
|
|
5776911af0 | ||
|
|
3c5c5e8aa7 | ||
|
|
6f5c5a0900 | ||
|
|
f2b00f6b93 | ||
|
|
44ff313740 | ||
|
|
ca1b833126 |
No files matched your search
@@ -2,6 +2,8 @@
|
||||
.idea
|
||||
.DS_Store
|
||||
.vscode
|
||||
open-x4-sdk
|
||||
fs_
|
||||
lib/EpdFont/fontsrc
|
||||
lib/I18n/I18nKeys.h
|
||||
lib/I18n/I18nStrings.h
|
||||
|
||||
@@ -8,6 +8,8 @@ CrossPoint is open-source e-reader firmware - community-built, fully hackable, f
|
||||
|
||||

|
||||
|
||||
> If you're planning to buy an Xteink device, consider purchasing an **X3/X4 Developer Edition** through https://crosspointreader.com. CrossPoint receives a small share of each sale, helping fund development costs.
|
||||
|
||||
## What can CrossPoint do?
|
||||
|
||||
- **Reader engine**: EPUB 2/3 rendering with embedded-style option, image handling, hyphenation, kerning, chapter navigation, footnotes, bookmarks, go-to-percent, auto page turn, orientation control, focus reading, KOReader progress sync and more.
|
||||
|
||||
@@ -47,6 +47,7 @@ git ls-files --exclude-standard ${GIT_LS_FILES_FLAGS} \
|
||||
| grep -v -E '^lib/EpdFont/builtinFonts/' \
|
||||
| grep -v -E '^lib/Epub/Epub/hyphenation/generated/' \
|
||||
| grep -v -E '^lib/uzlib/' \
|
||||
| grep -v -E '^lib/miniz/third_party/' \
|
||||
| xargs -r "${CLANG_FORMAT_BIN}" -style=file -i
|
||||
# Restore strict pipeline failure handling for the rest of the script.
|
||||
set -o pipefail
|
||||
+26
-10
@@ -90,13 +90,19 @@ if (parsedSize != fileSize) {
|
||||
|
||||
## `section.bin`
|
||||
|
||||
### Version 28
|
||||
### Version 30
|
||||
|
||||
Each file in `sections/*.bin` stores one laid-out spine section. The header is
|
||||
also the cache-busting key: if any layout-affecting setting differs from the
|
||||
current reader settings, the section is discarded and rebuilt.
|
||||
|
||||
Version 28 includes:
|
||||
Version 30 is binary-identical to version 29. The version was bumped because
|
||||
Arabic contextual shaping changed text measurement (`getTextAdvanceX` now
|
||||
measures the shaped visual text), so word positions cached by v29 no longer
|
||||
match what `drawText` renders.
|
||||
|
||||
Version 28 introduced serialized word style bits for underline, strikethrough,
|
||||
superscript, and subscript. The format also includes:
|
||||
|
||||
- cache-busting fields for paragraph alignment, hyphenation, embedded CSS,
|
||||
image rendering mode, and Focus Reading
|
||||
@@ -107,6 +113,10 @@ Version 28 includes:
|
||||
- per-page footnote entries
|
||||
- serialized word style bits for underline, strikethrough, superscript, and
|
||||
subscript
|
||||
- flat TextBlock word storage (v29): per-word arrays plus one shared
|
||||
NUL-terminated text blob, replacing v28's length-prefixed word strings. The
|
||||
on-disk order mirrors the in-RAM arena so the firmware reads a whole block
|
||||
payload with a single allocation and a single SD read
|
||||
|
||||
ImHex pattern:
|
||||
|
||||
@@ -115,7 +125,7 @@ import std.mem;
|
||||
import std.string;
|
||||
import std.core;
|
||||
|
||||
#define EXPECTED_VERSION 28
|
||||
#define EXPECTED_VERSION 30
|
||||
#define MAX_STRING_LENGTH 65535
|
||||
#define FOOTNOTE_NUMBER_LEN 32
|
||||
#define FOOTNOTE_HREF_LEN 96
|
||||
@@ -176,14 +186,20 @@ struct BlockStyle {
|
||||
|
||||
struct TextBlock {
|
||||
u16 wordCount;
|
||||
String words[wordCount];
|
||||
s16 wordXPos[wordCount];
|
||||
WordStyle wordStyle[wordCount];
|
||||
|
||||
u8 hasFocus;
|
||||
if (hasFocus != 0) {
|
||||
u8 wordFocusBoundary[wordCount] [[comment("UTF-8 byte boundary between bold prefix and suffix")]];
|
||||
u16 wordFocusSuffixX[wordCount] [[comment("Suffix x offset from word start")]];
|
||||
u16 textBytes [[comment("Total size of text[], including one NUL per word")]];
|
||||
|
||||
if (wordCount > 0) {
|
||||
u16 textOff[wordCount] [[comment("Byte offset of word i's text within text[]")]];
|
||||
s16 wordXPos[wordCount];
|
||||
if (hasFocus != 0) {
|
||||
u16 wordFocusSuffixX[wordCount] [[comment("Suffix x offset from word start")]];
|
||||
}
|
||||
WordStyle wordStyle[wordCount];
|
||||
if (hasFocus != 0) {
|
||||
u8 wordFocusBoundary[wordCount] [[comment("UTF-8 byte boundary between bold prefix and suffix")]];
|
||||
}
|
||||
char text[textBytes] [[comment("All words back to back, each NUL-terminated")]];
|
||||
}
|
||||
|
||||
BlockStyle blockStyle;
|
||||
|
||||
+8
-3
@@ -32,9 +32,14 @@ networks or in hotspot mode when you control who is connected.
|
||||
## Join Network Mode
|
||||
|
||||
1. Select **Join Network**.
|
||||
2. Pick a 2.4 GHz Wi-Fi network from the scan results.
|
||||
3. Enter the password if prompted.
|
||||
4. Save credentials if you want the reader to reconnect automatically next time.
|
||||
2. If you have saved Wi-Fi credentials, CrossPoint first tries the last
|
||||
connected network, then other visible saved networks in signal-strength
|
||||
order. Press **Back** to cancel or **Confirm** to stop auto-connect and show
|
||||
the network list.
|
||||
3. If the network list is shown, pick a 2.4 GHz Wi-Fi network from the scan
|
||||
results.
|
||||
4. Enter the password if prompted.
|
||||
5. Save credentials if you want the reader to reconnect automatically next time.
|
||||
|
||||
After connection, the reader shows:
|
||||
|
||||
|
||||
+1
-1
Submodule freeink-sdk updated: f611d71d8e...e7d336191b.
@@ -44,16 +44,17 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
||||
continue;
|
||||
}
|
||||
|
||||
const int raiseBy = isCombining ? combiningMark::raiseAboveBase(glyph->top, glyph->height, lastBaseTop) : 0;
|
||||
const combiningMark::Anchor anchor = combiningMark::anchorFor(cp);
|
||||
const int raiseBy = isCombining ? combiningMark::raiseAboveBase(anchor, glyph->top, glyph->height, lastBaseTop) : 0;
|
||||
|
||||
if (!isCombining && prevCp != 0) {
|
||||
const auto kernFP = getKerning(prevCp, cp); // 4.4 fixed-point kern
|
||||
lastBaseX += fp4::toPixel(prevAdvanceFP + kernFP);
|
||||
}
|
||||
|
||||
const int glyphBaseX =
|
||||
isCombining ? combiningMark::centerOver(lastBaseX, lastBaseLeft, lastBaseWidth, glyph->left, glyph->width)
|
||||
: lastBaseX;
|
||||
const int glyphBaseX = isCombining ? combiningMark::anchorOver(anchor, lastBaseX, lastBaseLeft, lastBaseWidth,
|
||||
glyph->left, glyph->width)
|
||||
: lastBaseX;
|
||||
const int glyphBaseY = startY - raiseBy;
|
||||
|
||||
*minX = std::min(*minX, glyphBaseX + glyph->left);
|
||||
|
||||
+76
-11
@@ -36,24 +36,71 @@ namespace combiningMark {
|
||||
|
||||
constexpr int MIN_GAP_PX = 1;
|
||||
|
||||
/// Compute the cursor-X at which to render a combining mark so its bitmap
|
||||
/// is visually centered over the base glyph's bitmap.
|
||||
constexpr int centerOver(int baseCursorPos, int baseLeft, int baseWidth, int markLeft, int markWidth) {
|
||||
return baseCursorPos + baseLeft + baseWidth / 2 - markWidth / 2 - markLeft;
|
||||
/// Placement of a mark relative to its base glyph. The default heuristic —
|
||||
/// centered over the base, raised clear of its top — suits Latin diacritics
|
||||
/// and Arabic harakat, but misplaces the Hebrew niqqud whose identity depends
|
||||
/// on position: dagesh sits inside the letter body, the shin/sin dots
|
||||
/// distinguish the letter by sitting over its right/left arm, and holam hangs
|
||||
/// over the left corner. "Native" anchors keep the glyph's font-designed
|
||||
/// height (which may overlap the base) instead of raising it.
|
||||
enum class Anchor : uint8_t {
|
||||
CenterRaised, ///< centered over the base, lifted above its top (default)
|
||||
CenterNative, ///< centered over the base at font-native height
|
||||
RightNative, ///< right edges aligned, font-native height
|
||||
LeftNative, ///< left edges aligned, font-native height
|
||||
};
|
||||
|
||||
constexpr Anchor anchorFor(const uint32_t cp) {
|
||||
switch (cp) {
|
||||
case 0x05BC: // dagesh / mapiq / shuruk dot: inside the letter body
|
||||
case 0x05BA: // holam haser for vav: straight above the vav stem
|
||||
return Anchor::CenterNative;
|
||||
case 0x05C1: // shin dot: over the letter's right arm
|
||||
return Anchor::RightNative;
|
||||
case 0x05B9: // holam: above the letter's left corner
|
||||
case 0x05C2: // sin dot: over the letter's left arm
|
||||
return Anchor::LeftNative;
|
||||
default:
|
||||
return Anchor::CenterRaised;
|
||||
}
|
||||
}
|
||||
|
||||
/// Rotated-90CW variant of centerOver. In the rotated coordinate system
|
||||
/// Horizontal offset from the base bitmap's left edge to the mark bitmap's
|
||||
/// left edge for a given anchor.
|
||||
constexpr int anchorShift(const Anchor anchor, const int baseWidth, const int markWidth) {
|
||||
switch (anchor) {
|
||||
case Anchor::LeftNative:
|
||||
return 0;
|
||||
case Anchor::RightNative:
|
||||
return baseWidth - markWidth;
|
||||
default:
|
||||
return baseWidth / 2 - markWidth / 2;
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the cursor-X at which to render a combining mark so its bitmap
|
||||
/// lands at its anchor position over the base glyph's bitmap.
|
||||
constexpr int anchorOver(const Anchor anchor, const int baseCursorPos, const int baseLeft, const int baseWidth,
|
||||
const int markLeft, const int markWidth) {
|
||||
return baseCursorPos + baseLeft + anchorShift(anchor, baseWidth, markWidth) - markLeft;
|
||||
}
|
||||
|
||||
/// Rotated-90CW variant of anchorOver. In the rotated coordinate system
|
||||
/// renderCharImpl uses (cursorY - left) instead of (cursorX + left), so
|
||||
/// every left/width term inverts sign.
|
||||
constexpr int centerOverRotated90CW(int baseCursorPos, int baseLeft, int baseWidth, int markLeft, int markWidth) {
|
||||
return baseCursorPos - baseLeft - baseWidth / 2 + markWidth / 2 + markLeft;
|
||||
constexpr int anchorOverRotated90CW(const Anchor anchor, const int baseCursorPos, const int baseLeft,
|
||||
const int baseWidth, const int markLeft, const int markWidth) {
|
||||
return baseCursorPos - baseLeft - anchorShift(anchor, baseWidth, markWidth) + markLeft;
|
||||
}
|
||||
|
||||
/// For combining marks that sit entirely above the baseline, compute how many
|
||||
/// pixels to raise the mark so there is at least MIN_GAP_PX between its bottom
|
||||
/// edge and the top of the base glyph. Returns 0 for marks that extend to or
|
||||
/// below the baseline (e.g. cedilla, dot-below, ogonek).
|
||||
constexpr int raiseAboveBase(int markTop, int markHeight, int baseTop) {
|
||||
/// below the baseline (e.g. cedilla, dot-below, ogonek) and for anchors that
|
||||
/// keep the font-native height (dagesh must stay inside the letter, the
|
||||
/// shin/sin dots touch its arms).
|
||||
constexpr int raiseAboveBase(const Anchor anchor, const int markTop, const int markHeight, const int baseTop) {
|
||||
if (anchor != Anchor::CenterRaised) return 0;
|
||||
if (markTop - markHeight <= 0) return 0;
|
||||
const int gap = markTop - markHeight - baseTop;
|
||||
return (gap < MIN_GAP_PX) ? (MIN_GAP_PX - gap) : 0;
|
||||
@@ -61,6 +108,20 @@ constexpr int raiseAboveBase(int markTop, int markHeight, int baseTop) {
|
||||
|
||||
} // namespace combiningMark
|
||||
|
||||
/// GCC/Clang (the ESP32 firmware toolchain) pack structs with __attribute__((packed)).
|
||||
/// MSVC (host unit tests) has no equivalent attribute and instead needs a #pragma pack
|
||||
/// region achieving the same 1-byte alignment. These macros keep the on-disk font layout
|
||||
/// identical across both toolchains.
|
||||
#if defined(_MSC_VER)
|
||||
#define EPD_PACKED_BEGIN __pragma(pack(push, 1))
|
||||
#define EPD_PACKED_END __pragma(pack(pop))
|
||||
#define EPD_PACKED_ATTR
|
||||
#else
|
||||
#define EPD_PACKED_BEGIN
|
||||
#define EPD_PACKED_END
|
||||
#define EPD_PACKED_ATTR __attribute__((packed))
|
||||
#endif
|
||||
|
||||
/// Fixed-point conventions used by EpdGlyph and EpdFontData:
|
||||
/// advanceX: 12.4 unsigned fixed-point in uint16_t (use fp4::toPixel)
|
||||
/// kernMatrix: 4.4 signed fixed-point in int8_t (use fp4::toPixel)
|
||||
@@ -95,17 +156,21 @@ typedef struct {
|
||||
|
||||
/// Maps a codepoint to a kerning class ID, sorted by codepoint for binary search.
|
||||
/// Class IDs are 1-based; codepoints not in the table have implicit class 0 (no kerning).
|
||||
EPD_PACKED_BEGIN
|
||||
typedef struct {
|
||||
uint16_t codepoint; ///< Unicode codepoint
|
||||
uint8_t classId; ///< 1-based kerning class ID
|
||||
} __attribute__((packed)) EpdKernClassEntry;
|
||||
} EPD_PACKED_ATTR EpdKernClassEntry;
|
||||
EPD_PACKED_END
|
||||
|
||||
/// Ligature substitution for a specific glyph pair, sorted by `pair` for binary search.
|
||||
/// `pair` encodes (leftCodepoint << 16 | rightCodepoint) for single-key lookup.
|
||||
EPD_PACKED_BEGIN
|
||||
typedef struct {
|
||||
uint32_t pair; ///< Packed codepoint pair (left << 16 | right)
|
||||
uint32_t ligatureCp; ///< Codepoint of the replacement ligature glyph
|
||||
} __attribute__((packed)) EpdLigaturePair;
|
||||
} EPD_PACKED_ATTR EpdLigaturePair;
|
||||
EPD_PACKED_END
|
||||
|
||||
/// Data stored for FONT AS A WHOLE
|
||||
typedef struct {
|
||||
|
||||
@@ -33,12 +33,24 @@ void FontDecompressor::freePageBuffer() {
|
||||
}
|
||||
|
||||
void FontDecompressor::freeHotGroup() {
|
||||
hotGroup.clear();
|
||||
hotGroup.shrink_to_fit();
|
||||
free(hotGroup);
|
||||
hotGroup = nullptr;
|
||||
hotGroupCapacity = 0;
|
||||
hotGroupFont = nullptr;
|
||||
hotGroupIndex = UINT16_MAX;
|
||||
hotGlyphBuf.clear();
|
||||
hotGlyphBuf.shrink_to_fit();
|
||||
free(hotGlyphBuf);
|
||||
hotGlyphBuf = nullptr;
|
||||
hotGlyphBufCapacity = 0;
|
||||
}
|
||||
|
||||
bool FontDecompressor::ensureCapacity(uint8_t*& buf, uint32_t& capacity, uint32_t needed) {
|
||||
if (capacity >= needed) return true;
|
||||
// Grow-only, free-then-malloc: every caller fully rewrites the buffer after a grow, so the
|
||||
// old contents are dead -- freeing first gives the allocator its best shot on a tight heap.
|
||||
free(buf);
|
||||
buf = static_cast<uint8_t*>(malloc(needed)); // owned by FontDecompressor, freed in freeHotGroup()
|
||||
capacity = buf ? needed : 0;
|
||||
return buf != nullptr;
|
||||
}
|
||||
|
||||
uint16_t FontDecompressor::getGroupIndex(const EpdFontData* fontData, uint32_t glyphIndex) {
|
||||
@@ -170,24 +182,20 @@ const uint8_t* FontDecompressor::getBitmap(const EpdFontData* fontData, const Ep
|
||||
}
|
||||
|
||||
// Check if hot group already has this group decompressed — if not, decompress it
|
||||
if (!(!hotGroup.empty() && hotGroupFont == fontData && hotGroupIndex == groupIndex)) {
|
||||
if (!(hotGroup != nullptr && hotGroupFont == fontData && hotGroupIndex == groupIndex)) {
|
||||
stats.cacheMisses++;
|
||||
const EpdFontGroup& group = fontData->groups[groupIndex];
|
||||
|
||||
hotGroup.resize(group.uncompressedSize);
|
||||
if (hotGroup.empty()) {
|
||||
// ensureCapacity may free the buffer, so the cached-group identity dies with it either way.
|
||||
hotGroupFont = nullptr;
|
||||
hotGroupIndex = UINT16_MAX;
|
||||
if (!ensureCapacity(hotGroup, hotGroupCapacity, group.uncompressedSize)) {
|
||||
LOG_ERR("FDC", "Failed to allocate %u bytes for hot group %u", group.uncompressedSize, groupIndex);
|
||||
hotGroupFont = nullptr;
|
||||
hotGroupIndex = UINT16_MAX;
|
||||
stats.getBitmapTimeUs += micros() - tStart;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!decompressGroup(fontData, groupIndex, hotGroup.data(), group.uncompressedSize)) {
|
||||
hotGroup.clear();
|
||||
hotGroup.shrink_to_fit();
|
||||
hotGroupFont = nullptr;
|
||||
hotGroupIndex = UINT16_MAX;
|
||||
if (!decompressGroup(fontData, groupIndex, hotGroup, group.uncompressedSize)) {
|
||||
stats.getBitmapTimeUs += micros() - tStart;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -200,18 +208,16 @@ const uint8_t* FontDecompressor::getBitmap(const EpdFontData* fontData, const Ep
|
||||
}
|
||||
|
||||
// Compact just the requested glyph from byte-aligned data into scratch buffer
|
||||
if (glyph->dataLength > hotGlyphBuf.size()) {
|
||||
hotGlyphBuf.resize(glyph->dataLength);
|
||||
}
|
||||
if (hotGlyphBuf.empty()) {
|
||||
if (!ensureCapacity(hotGlyphBuf, hotGlyphBufCapacity, glyph->dataLength)) {
|
||||
LOG_ERR("FDC", "Failed to allocate %u bytes for glyph scratch", (unsigned)glyph->dataLength);
|
||||
stats.getBitmapTimeUs += micros() - tStart;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t alignedOff = getAlignedOffset(fontData, groupIndex, glyphIndex);
|
||||
compactSingleGlyph(&hotGroup[alignedOff], hotGlyphBuf.data(), glyph->width, glyph->height);
|
||||
compactSingleGlyph(&hotGroup[alignedOff], hotGlyphBuf, glyph->width, glyph->height);
|
||||
stats.getBitmapTimeUs += micros() - tStart;
|
||||
return hotGlyphBuf.data();
|
||||
return hotGlyphBuf;
|
||||
}
|
||||
|
||||
// --- Prewarm: pre-decompress glyph bitmaps for a page of text ---
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <InflateReader.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "EpdFontData.h"
|
||||
|
||||
class FontDecompressor {
|
||||
@@ -67,13 +65,22 @@ class FontDecompressor {
|
||||
|
||||
// Hot group: last decompressed group (byte-aligned) for non-prewarmed fallback path.
|
||||
// Kept in byte-aligned format; individual glyphs are compacted on demand into hotGlyphBuf.
|
||||
// Nothrow high-water malloc buffers, NOT std::vector: getBitmap() runs on the render path,
|
||||
// and under -fno-exceptions a vector resize that hits OOM abort()s the firmware instead of
|
||||
// failing (field crash: hotGroup.resize() -> std::bad_alloc -> abort with ~11 KB free).
|
||||
// ensureCapacity() returns false on OOM so the caller can skip the glyph gracefully.
|
||||
const EpdFontData* hotGroupFont = nullptr;
|
||||
uint16_t hotGroupIndex = UINT16_MAX;
|
||||
std::vector<uint8_t> hotGroup;
|
||||
uint8_t* hotGroup = nullptr; // owned; freed in freeHotGroup()/dtor
|
||||
uint32_t hotGroupCapacity = 0;
|
||||
|
||||
// Scratch buffer for compacting a single glyph from the hot group.
|
||||
// Valid until the next getBitmap() call.
|
||||
std::vector<uint8_t> hotGlyphBuf;
|
||||
// Valid until the next getBitmap() call. Same ownership/OOM contract as hotGroup.
|
||||
uint8_t* hotGlyphBuf = nullptr;
|
||||
uint32_t hotGlyphBufCapacity = 0;
|
||||
|
||||
// Grow (never shrink) an owned buffer to at least `needed` bytes; false on OOM, buffer freed.
|
||||
static bool ensureCapacity(uint8_t*& buf, uint32_t& capacity, uint32_t needed);
|
||||
|
||||
void freePageBuffer();
|
||||
void freeHotGroup();
|
||||
|
||||
@@ -1195,7 +1195,8 @@ int SdCardFont::fetchAdvancesForCodepoints(uint32_t* codepoints, uint32_t cpCoun
|
||||
}
|
||||
|
||||
template <typename Iter>
|
||||
int SdCardFont::buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace, bool includeHyphen, uint8_t styleMask) {
|
||||
int SdCardFont::buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace, bool includeHyphen, uint8_t styleMask,
|
||||
const char* extraText) {
|
||||
if (!loaded_) return -1;
|
||||
styleMask = resolveStyleMask(styleMask);
|
||||
if (styleMask == 0) return 0;
|
||||
@@ -1215,6 +1216,9 @@ int SdCardFont::buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace,
|
||||
for (auto it = begin; it != end && !hitCap; ++it) {
|
||||
hitCap = collectUniqueCodepoints(asCStr(*it), codepoints, cpCount, MAX_UNIQUE_CODEPOINTS);
|
||||
}
|
||||
if (extraText && !hitCap) {
|
||||
hitCap = collectUniqueCodepoints(extraText, codepoints, cpCount, MAX_UNIQUE_CODEPOINTS);
|
||||
}
|
||||
|
||||
if (includeSpace && std::none_of(codepoints, codepoints + cpCount, [](uint32_t c) { return c == ' '; }))
|
||||
codepoints[cpCount++] = ' ';
|
||||
@@ -1232,12 +1236,13 @@ int SdCardFont::buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace,
|
||||
return totalMissed;
|
||||
}
|
||||
|
||||
int SdCardFont::buildAdvanceTable(const char* utf8Text, uint8_t styleMask) {
|
||||
return buildAdvanceTableRange(&utf8Text, &utf8Text + 1, false, false, styleMask);
|
||||
int SdCardFont::buildAdvanceTable(const char* utf8Text, uint8_t styleMask, const char* extraText) {
|
||||
return buildAdvanceTableRange(&utf8Text, &utf8Text + 1, false, false, styleMask, extraText);
|
||||
}
|
||||
|
||||
int SdCardFont::buildAdvanceTable(const std::vector<std::string>& words, bool includeHyphen, uint8_t styleMask) {
|
||||
return buildAdvanceTableRange(words.begin(), words.end(), words.size() > 1, includeHyphen, styleMask);
|
||||
int SdCardFont::buildAdvanceTable(const std::vector<std::string>& words, bool includeHyphen, uint8_t styleMask,
|
||||
const char* extraText) {
|
||||
return buildAdvanceTableRange(words.begin(), words.end(), words.size() > 1, includeHyphen, styleMask, extraText);
|
||||
}
|
||||
|
||||
// --- Stats ---
|
||||
|
||||
@@ -47,9 +47,12 @@ class SdCardFont {
|
||||
// Build a compact advance-only table for layout measurement.
|
||||
// Extracts ALL unique codepoints from words (no MAX_PAGE_GLYPHS cap),
|
||||
// batch-reads advanceX from SD, stores in a sorted per-style table.
|
||||
// extraText: optional additional codepoints to warm in the same SD pass
|
||||
// (e.g. shaped Arabic presentation forms the measurement path will look up).
|
||||
// Returns number of codepoints not found in font coverage.
|
||||
int buildAdvanceTable(const char* utf8Text, uint8_t styleMask = 0x0F);
|
||||
int buildAdvanceTable(const std::vector<std::string>& words, bool includeHyphen, uint8_t styleMask = 0x0F);
|
||||
int buildAdvanceTable(const char* utf8Text, uint8_t styleMask = 0x0F, const char* extraText = nullptr);
|
||||
int buildAdvanceTable(const std::vector<std::string>& words, bool includeHyphen, uint8_t styleMask = 0x0F,
|
||||
const char* extraText = nullptr);
|
||||
|
||||
// Look up advanceX for a codepoint from the advance table.
|
||||
// Returns the 12.4 fixed-point advance, or 0 if not found.
|
||||
@@ -140,11 +143,13 @@ class SdCardFont {
|
||||
|
||||
// Full intervals loaded from file (kept in RAM for codepoint lookup)
|
||||
EpdUnicodeInterval* fullIntervals = nullptr;
|
||||
EPD_PACKED_BEGIN
|
||||
struct BmpInterval16 {
|
||||
uint16_t first;
|
||||
uint16_t last;
|
||||
uint16_t offset;
|
||||
} __attribute__((packed));
|
||||
} EPD_PACKED_ATTR;
|
||||
EPD_PACKED_END
|
||||
static_assert(sizeof(BmpInterval16) == 6, "BmpInterval16 must remain compact");
|
||||
BmpInterval16* bmpIntervals = nullptr;
|
||||
bool intervalsAreBmp16 = false;
|
||||
@@ -249,7 +254,8 @@ class SdCardFont {
|
||||
int32_t findGlobalGlyphIndex(const PerStyle& s, uint32_t codepoint) const;
|
||||
int fetchAdvancesForCodepoints(uint32_t* codepoints, uint32_t cpCount, uint8_t styleMask);
|
||||
template <typename Iter>
|
||||
int buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace, bool includeHyphen, uint8_t styleMask);
|
||||
int buildAdvanceTableRange(Iter begin, Iter end, bool includeSpace, bool includeHyphen, uint8_t styleMask,
|
||||
const char* extraText = nullptr);
|
||||
int prewarmStyle(uint8_t styleIdx, const uint32_t* codepoints, uint32_t cpCount, bool metadataOnly);
|
||||
|
||||
// Global helpers
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -6,6 +6,8 @@
|
||||
!NotoSerif/**
|
||||
!NotoSans/
|
||||
!NotoSans/**
|
||||
!NotoSansArabic/
|
||||
!NotoSansArabic/**
|
||||
!NotoSansHebrew/
|
||||
!NotoSansHebrew/**
|
||||
!OpenDyslexic/
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/arabic)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://openfontlicense.org
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
+1872
-1256
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+2244
-1483
File diff suppressed because it is too large.
Load diff
Loaded 20 of 151 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user