diff --git a/src/alfons/font.cpp b/src/alfons/font.cpp index b618203..c24bcab 100644 --- a/src/alfons/font.cpp +++ b/src/alfons/font.cpp @@ -18,16 +18,15 @@ Font::Font(const Properties& properties) auto Font::addFace(std::shared_ptr _face, hb_language_t _lang) -> bool { + if (!_face) { return false; } + if (_lang == HB_LANGUAGE_INVALID) { m_faces.push_back(_face); return true; } for (auto& face : m_fontFaceMap[_lang]) { - if (face == _face) { - log("Won't add font twice. %s", _lang); - return false; - } + if (face == _face) { return false; } } m_fontFaceMap[_lang].push_back(_face); diff --git a/src/alfons/fontFace.h b/src/alfons/fontFace.h index cf78b0b..c75b272 100644 --- a/src/alfons/fontFace.h +++ b/src/alfons/fontFace.h @@ -106,6 +106,10 @@ class FontFace { return m_languages; } + Descriptor& descriptor() { + return m_descriptor; + } + protected: FreetypeHelper& m_ft; diff --git a/src/alfons/fontManager.cpp b/src/alfons/fontManager.cpp index a1d4e2d..9aaa834 100644 --- a/src/alfons/fontManager.cpp +++ b/src/alfons/fontManager.cpp @@ -160,7 +160,6 @@ void FontManager::unload(Font& font) { } void FontManager::unload() { - // layoutCache.clear(); for (auto& face : m_faces) { face->unload(); @@ -170,14 +169,11 @@ void FontManager::unload() { std::shared_ptr FontManager::addFontFace(const FontFace::Descriptor& descriptor, float baseSize) { - // FontFace::Key key(descriptor, baseSize); - // for (const auto& face : faces) { - // if (face.) - // } - // auto it = faces.find(key); - // if (it != faces.end()) { - // return it->second.faceId; - // } + if (m_maxFontId == std::numeric_limits::max()) { + LOGE("addFontFace failed: Reached maximum FontFace ID"); + return nullptr; + } + auto face = std::make_shared(m_ftHelper, m_maxFontId++, descriptor, baseSize); m_faces.push_back(face); diff --git a/src/alfons/inputSource.h b/src/alfons/inputSource.h index 9700586..58de9d8 100644 --- a/src/alfons/inputSource.h +++ b/src/alfons/inputSource.h @@ -49,6 +49,10 @@ class InputSource { bool hasSourceCallback() { return m_data && bool(m_data->loadSource); } + void clearData() { + m_data->buffer.clear(); + } + bool resolveSource() { if (!m_data || !bool(m_data->loadSource)) { return false; diff --git a/src/alfons/langHelper.cpp b/src/alfons/langHelper.cpp index b3acd45..4661c0f 100644 --- a/src/alfons/langHelper.cpp +++ b/src/alfons/langHelper.cpp @@ -21,7 +21,7 @@ namespace alfons { const std::string DEFAULT_LANGUAGES = "en:zh-cn"; // GIVING PRIORITY (BY DEFAULT) TO CHINESE OVER JAPANESE struct HBScriptForLang { - const char lang[7]; + const char *lang; hb_script_t scripts[3]; }; diff --git a/src/alfons/lineLayout.h b/src/alfons/lineLayout.h index bd7b44c..9c41129 100644 --- a/src/alfons/lineLayout.h +++ b/src/alfons/lineLayout.h @@ -34,7 +34,7 @@ enum class Alignment { struct Shape { // Reference to face within a Font. - uint8_t face; + uint16_t face; union { uint8_t flags; struct { @@ -59,7 +59,7 @@ struct Shape { Shape() : face(0), flags(0), advance(0), codepoint(0) {} - Shape(uint8_t faceID, uint32_t codepoint, glm::vec2 offset, + Shape(uint16_t faceID, uint32_t codepoint, glm::vec2 offset, float advance, uint8_t flags) : face(faceID), flags(flags), diff --git a/src/alfons/textShaper.cpp b/src/alfons/textShaper.cpp index e4ef1e4..53abcde 100644 --- a/src/alfons/textShaper.cpp +++ b/src/alfons/textShaper.cpp @@ -62,6 +62,7 @@ struct TextLine { // Input UnicodeString* text; + size_t offset; hb_language_t langHint; hb_direction_t overallDirection; @@ -72,7 +73,7 @@ struct TextLine { // Result std::vector runs; - void set(UnicodeString& _input, + void set(UnicodeString& _input, size_t _offset, hb_language_t _langHint = HB_LANGUAGE_INVALID, hb_direction_t _overallDirection = HB_DIRECTION_INVALID) { runs.clear(); @@ -80,6 +81,7 @@ struct TextLine { scriptLangItems.clear(); text = &_input; + offset = _offset; langHint = _langHint; overallDirection = _overallDirection; } @@ -293,7 +295,7 @@ TextShaper::~TextShaper() { } bool TextShaper::processRun(const FontFace& _face, const TextRun& _run, - FontFace::Metrics& _lineMetrics) { + size_t lineBreakOffset, FontFace::Metrics& _lineMetrics) { hb_shape(_face.hbFont(), m_hbBuffer, NULL, 0); @@ -317,7 +319,7 @@ bool TextShaper::processRun(const FontFace& _face, const TextRun& _run, } if (codepoint == 0) { - if (m_linebreaks[clusterId] != LINEBREAK_MUSTBREAK) { + if (!m_glyphAdded[id] && m_linebreaks[lineBreakOffset + clusterId] != LINEBREAK_MUSTBREAK) { missingGlyphs = true; } continue; @@ -345,12 +347,12 @@ bool TextShaper::processRun(const FontFace& _face, const TextRun& _run, addedGlyphs = true; m_glyphAdded[id] = 1; - uint8_t breakmode = m_linebreaks[clusterId]; + uint8_t breakmode = m_linebreaks[lineBreakOffset + clusterId]; - uint8_t flags = 1 | // cluster start - //((breakmode == LINEBREAK_MUSTBREAK) ? 2 : 0) | // must break - ((breakmode == 1) ? 4 : 0) | // can break - ((breakmode == 2) ? 8 : 0) | // no break + uint8_t flags = 1 | // cluster start + ((breakmode == LINEBREAK_MUSTBREAK) ? 2 : 0) | + ((breakmode == LINEBREAK_ALLOWBREAK) ? 4 : 0) | + ((breakmode == LINEBREAK_NOBREAK) ? 8 : 0) | (_face.isSpace(codepoint) ? 16 : 0); m_shapes[id] = Shape(_face.id(), codepoint, offset, advance, flags); @@ -411,7 +413,7 @@ bool TextShaper::shape(std::shared_ptr& _font, const TextLine& _line, hb_buffer_set_language(m_hbBuffer, run.language); } - if (processRun(*face, run, _layout.metrics())) { + if (processRun(*face, run, _line.offset, _layout.metrics())) { missingGlyphs = false; break; } @@ -436,6 +438,9 @@ bool TextShaper::shape(std::shared_ptr& _font, const TextLine& _line, if (shapes.empty()) { return false; } + // Last char on line: Must break at end of line + shapes.back().mustBreak = true; + _layout.addShapes(shapes); return true; @@ -468,16 +473,23 @@ LineLayout TextShaper::shapeICU(std::shared_ptr& _font, const UnicodeStrin int start = 0; for (int pos = 0; pos < numChars; pos++) { - if (m_linebreaks[pos] != 0) { continue; } + // Last char is always MUSTBREAK + if (m_linebreaks[pos] != LINEBREAK_MUSTBREAK) { + continue; + } + + // Remove linebreak after final char, this interferes with RTL text. + if (pos == numChars - 1) { + m_linebreaks[pos] = LINEBREAK_NOBREAK; + } auto cur = _text.tempSubStringBetween(start, pos+1); - line.set(cur, _langHint, _direction); + line.set(cur, start, _langHint, _direction); m_itemizer->processLine(line); shape(_font, line, line.runs, layout); start = pos + 1; - } return layout; diff --git a/src/alfons/textShaper.h b/src/alfons/textShaper.h index 57b77c4..e235761 100644 --- a/src/alfons/textShaper.h +++ b/src/alfons/textShaper.h @@ -54,7 +54,7 @@ class TextShaper { bool shape(std::shared_ptr& font, TextLine& line, LineLayout& layout); - bool processRun(const FontFace& face, const TextRun& run, FontFace::Metrics& _lineMetrics); + bool processRun(const FontFace& face, const TextRun& run, size_t lineBreakOffset, FontFace::Metrics& _lineMetrics); LangHelper m_langHelper; std::unique_ptr m_itemizer;