| 724 | } |
| 725 | |
| 726 | CrossPointPosition ProgressMapper::toCrossPoint(const std::shared_ptr<Epub>& epub, const SavedProgressPosition& koPos, |
| 727 | GfxRenderer& renderer, int currentSpineIndex, |
| 728 | int totalPagesInCurrentSpine, int fallbackTotalPages) { |
| 729 | CrossPointPosition result{}; |
| 730 | const size_t bookSize = epub->getBookSize(); |
| 731 | if (bookSize == 0) return result; |
| 732 | |
| 733 | const int spineCount = epub->getSpineItemsCount(); |
| 734 | const float clampedPercentage = std::max(0.0f, std::min(1.0f, koPos.percentage)); |
| 735 | const size_t targetBytes = static_cast<size_t>(static_cast<float>(bookSize) * clampedPercentage); |
| 736 | |
| 737 | const int docFrag = parseIndex(koPos.xpath, "/body/DocFragment["); |
| 738 | const int xpathP = parseIndex(koPos.xpath, "/p[", true); |
| 739 | const int xpathChar = parseCharOffset(koPos.xpath); |
| 740 | const int xpathTextNode = parseTextNodeIndex(koPos.xpath); |
| 741 | const int xpathSpine = (docFrag >= 1) ? (docFrag - 1) : -1; |
| 742 | |
| 743 | XPathStep xpathSteps[MAX_XPATH_DEPTH]; |
| 744 | const int xpathStepCount = parseXPathSteps(koPos.xpath, xpathSteps); |
| 745 | // Use ancestry mode whenever the XPath has a structured path (always more accurate than global counting). |
| 746 | const bool useAncestry = xpathStepCount > 0; |
| 747 | |
| 748 | if (xpathSpine >= 0 && xpathSpine < spineCount) { |
| 749 | result.spineIndex = xpathSpine; |
| 750 | } else { |
| 751 | for (int i = 0; i < spineCount; i++) { |
| 752 | if (epub->getCumulativeSpineItemSize(i) >= targetBytes) { |
| 753 | result.spineIndex = i; |
| 754 | break; |
| 755 | } |
| 756 | } |
| 757 | } |
| 758 | |
| 759 | const size_t prevCum = (result.spineIndex > 0) ? epub->getCumulativeSpineItemSize(result.spineIndex - 1) : 0; |
| 760 | const size_t spineSize = epub->getCumulativeSpineItemSize(result.spineIndex) - prevCum; |
| 761 | |
| 762 | if (result.spineIndex == currentSpineIndex && totalPagesInCurrentSpine > 0) { |
| 763 | result.totalPages = totalPagesInCurrentSpine; |
| 764 | } else if (currentSpineIndex >= 0 && currentSpineIndex < spineCount && totalPagesInCurrentSpine > 0) { |
| 765 | const size_t pc = (currentSpineIndex > 0) ? epub->getCumulativeSpineItemSize(currentSpineIndex - 1) : 0; |
| 766 | const size_t cs = epub->getCumulativeSpineItemSize(currentSpineIndex) - pc; |
| 767 | if (cs > 0) |
| 768 | result.totalPages = std::max( |
| 769 | 1, static_cast<int>(totalPagesInCurrentSpine * static_cast<float>(spineSize) / static_cast<float>(cs))); |
| 770 | } |
| 771 | |
| 772 | if (result.totalPages <= 0) { |
| 773 | Section tempSection(epub, result.spineIndex, renderer); |
| 774 | if (auto cachedCount = tempSection.getCachedPageCount()) { |
| 775 | result.totalPages = *cachedCount; |
| 776 | } else if (fallbackTotalPages > 0) { |
| 777 | result.totalPages = fallbackTotalPages; |
| 778 | } else { |
| 779 | result.totalPages = 1; // Prevent division by zero and give a fallback |
| 780 | } |
| 781 | } |
| 782 | |
| 783 | float intra = 0.0f; |
nothing calls this directly
no test coverage detected