| 28 | } |
| 29 | |
| 30 | std::shared_ptr<TextBlob> shape(const std::string& text, std::shared_ptr<Typeface> typeface, |
| 31 | float fontSize) override { |
| 32 | std::vector<GlyphRun> glyphRuns = {}; |
| 33 | std::vector<GlyphID> glyphIDs = {}; |
| 34 | std::vector<Point> positions = {}; |
| 35 | |
| 36 | Font previousFont = Font(); |
| 37 | auto emptyAdvance = fontSize / 2.0f; |
| 38 | float XOffset = 0.0f; |
| 39 | |
| 40 | const char* textStart = text.data(); |
| 41 | const char* textStop = textStart + text.size(); |
| 42 | while (textStart < textStop) { |
| 43 | const auto oldPosition = textStart; |
| 44 | UTF::NextUTF8(&textStart, textStop); |
| 45 | auto length = textStart - oldPosition; |
| 46 | auto str = std::string(oldPosition, static_cast<size_t>(length)); |
| 47 | |
| 48 | GlyphID currentGlyphID = 0; |
| 49 | std::shared_ptr<Typeface> currentTypeface = nullptr; |
| 50 | |
| 51 | // Match the string with SVG-parsed typeface, and try fallback typefaces if no match |
| 52 | // is found |
| 53 | GlyphID glyphID = typeface ? typeface->getGlyphID(str) : 0; |
| 54 | if (glyphID != 0) { |
| 55 | currentGlyphID = glyphID; |
| 56 | currentTypeface = typeface; |
| 57 | } else { |
| 58 | for (const auto& typefaceItem : fallbackTypefaces) { |
| 59 | if (typefaceItem == nullptr) { |
| 60 | continue; |
| 61 | } |
| 62 | glyphID = typefaceItem->getGlyphID(str); |
| 63 | if (glyphID != 0) { |
| 64 | currentGlyphID = glyphID; |
| 65 | currentTypeface = typefaceItem; |
| 66 | break; |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | // Skip with empty advance if no matching typeface is found |
| 72 | if (!currentTypeface) { |
| 73 | XOffset += emptyAdvance; |
| 74 | continue; |
| 75 | } |
| 76 | |
| 77 | if (!previousFont.getTypeface()) { |
| 78 | previousFont = Font(currentTypeface, fontSize); |
| 79 | } else if (currentTypeface->uniqueID() != previousFont.getTypeface()->uniqueID()) { |
| 80 | // If the current typeface differs from the previous one, create a glyph run from current |
| 81 | // glyphs and start a new font |
| 82 | glyphRuns.emplace_back(previousFont, glyphIDs, positions); |
| 83 | glyphIDs.clear(); |
| 84 | positions.clear(); |
| 85 | previousFont = Font(currentTypeface, fontSize); |
| 86 | } |
| 87 |
no test coverage detected