| 1689 | } |
| 1690 | |
| 1691 | void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y, const char* text, const bool black, |
| 1692 | const EpdFontFamily::Style style) const { |
| 1693 | // Cannot draw a NULL / empty string |
| 1694 | if (text == nullptr || *text == '\0') { |
| 1695 | return; |
| 1696 | } |
| 1697 | |
| 1698 | const auto fontIt = fontMap.find(fontId); |
| 1699 | if (fontIt == fontMap.end()) { |
| 1700 | LOG_ERR("GFX", "Font %d not found", fontId); |
| 1701 | return; |
| 1702 | } |
| 1703 | |
| 1704 | const auto& font = fontIt->second; |
| 1705 | |
| 1706 | int lastBaseY = y; |
| 1707 | int lastBaseLeft = 0; |
| 1708 | int lastBaseWidth = 0; |
| 1709 | int lastBaseTop = 0; |
| 1710 | int32_t prevAdvanceFP = 0; // 12.4 fixed-point: prev glyph's advance + next kern for snap |
| 1711 | |
| 1712 | uint32_t cp; |
| 1713 | uint32_t prevCp = 0; |
| 1714 | while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) { |
| 1715 | // Skip Hebrew Niqqud (vowel marks) |
| 1716 | // Temporary: avoid adding Niqqud to built-in fonts. Remove when custom fonts are supported. |
| 1717 | if (cp >= 0x0591 && cp <= 0x05C7) { |
| 1718 | continue; |
| 1719 | } |
| 1720 | |
| 1721 | if (utf8IsCombiningMark(cp)) { |
| 1722 | const EpdGlyph* combiningGlyph = font.getGlyph(cp, style); |
| 1723 | if (!combiningGlyph) continue; |
| 1724 | const int raiseBy = combiningMark::raiseAboveBase(combiningGlyph->top, combiningGlyph->height, lastBaseTop); |
| 1725 | const int combiningX = x - raiseBy; |
| 1726 | const int combiningY = combiningMark::centerOverRotated90CW(lastBaseY, lastBaseLeft, lastBaseWidth, |
| 1727 | combiningGlyph->left, combiningGlyph->width); |
| 1728 | renderCharImpl<TextRotation::Rotated90CW>(*this, renderMode, font, cp, combiningX, combiningY, black, style); |
| 1729 | continue; |
| 1730 | } |
| 1731 | |
| 1732 | cp = font.applyLigatures(cp, text, style); |
| 1733 | |
| 1734 | // Differential rounding: snap (previous advance + current kern) as one unit, |
| 1735 | // subtracting for the rotated coordinate direction. |
| 1736 | if (prevCp != 0) { |
| 1737 | const auto kernFP = font.getKerning(prevCp, cp, style); // 4.4 fixed-point kern |
| 1738 | lastBaseY -= fp4::toPixel(prevAdvanceFP + kernFP); // snap 12.4 fixed-point to nearest pixel |
| 1739 | } |
| 1740 | |
| 1741 | const EpdGlyph* glyph = font.getGlyph(cp, style); |
| 1742 | |
| 1743 | lastBaseLeft = glyph ? glyph->left : 0; |
| 1744 | lastBaseWidth = glyph ? glyph->width : 0; |
| 1745 | lastBaseTop = glyph ? glyph->top : 0; |
| 1746 | prevAdvanceFP = glyph ? glyph->advanceX : 0; // 12.4 fixed-point |
| 1747 | |
| 1748 | renderCharImpl<TextRotation::Rotated90CW>(*this, renderMode, font, cp, x, lastBaseY, black, style); |
no test coverage detected