From 81e373c79d390a1eea46e7e929b7b3d5cac0556f Mon Sep 17 00:00:00 2001 From: domrjchen Date: Sat, 21 Dec 2024 21:17:58 +0800 Subject: [PATCH 1/2] Fix the rendering issue with ZWJ emojis on apple platforms. --- ios/PAGViewer/Classes/ViewController.mm | 2 +- src/platform/Platform.cpp | 6 +-- src/platform/Platform.h | 6 +-- src/platform/cocoa/private/CocoaPlatform.h | 4 +- src/platform/cocoa/private/CocoaPlatform.mm | 18 ++------- src/platform/cocoa/private/NativeTextShaper.h | 6 +-- .../cocoa/private/NativeTextShaper.mm | 35 ++++++++++------- src/platform/web/NativePlatform.cpp | 10 +---- src/platform/web/NativePlatform.h | 4 +- src/platform/web/NativeTextShaper.cpp | 15 ++++--- src/platform/web/NativeTextShaper.h | 6 +-- src/rendering/caches/TextAtlas.cpp | 6 ++- src/rendering/graphics/Glyph.cpp | 39 +++++++++++-------- src/rendering/graphics/Glyph.h | 8 ++-- src/rendering/graphics/Text.cpp | 6 ++- .../{PositionedGlyphs.h => ShapedGlyph.h} | 37 ++++++------------ src/rendering/utils/shaper/TextShaper.cpp | 11 ++++-- src/rendering/utils/shaper/TextShaper.h | 14 ++++++- .../utils/shaper/TextShaperHarfbuzz.cpp | 20 +++++----- .../utils/shaper/TextShaperHarfbuzz.h | 5 ++- .../utils/shaper/TextShaperPrimitive.cpp | 8 ++-- .../utils/shaper/TextShaperPrimitive.h | 5 ++- 22 files changed, 134 insertions(+), 137 deletions(-) rename src/rendering/utils/shaper/{PositionedGlyphs.h => ShapedGlyph.h} (56%) diff --git a/ios/PAGViewer/Classes/ViewController.mm b/ios/PAGViewer/Classes/ViewController.mm index c89e9ce04f..9ba5cb1d89 100644 --- a/ios/PAGViewer/Classes/ViewController.mm +++ b/ios/PAGViewer/Classes/ViewController.mm @@ -100,7 +100,7 @@ - (void)addPAGViewAndPlay { PAGFile* pagFile = [PAGFile Load:path]; if ([pagFile numTexts] > 0) { PAGText* textData = [pagFile getTextData:0]; - textData.text = @"hah哈 哈哈哈哈👌하"; + textData.text = @"hah哈 哈哈👩🏼‍❤️‍👨🏽哈哈👌하"; [pagFile replaceText:0 data:textData]; } diff --git a/src/platform/Platform.cpp b/src/platform/Platform.cpp index c4bd114ce3..8421edb8a3 100644 --- a/src/platform/Platform.cpp +++ b/src/platform/Platform.cpp @@ -36,9 +36,9 @@ NALUType Platform::naluType() const { void Platform::traceImage(const tgfx::ImageInfo&, const void*, const std::string&) const { } -std::optional Platform::shapeText(const std::string&, - const std::shared_ptr&) const { - return std::nullopt; +std::vector Platform::shapeText(const std::string&, + std::shared_ptr) const { + return {}; } std::string Platform::getCacheDir() const { diff --git a/src/platform/Platform.h b/src/platform/Platform.h index b9507efc8d..92805749fe 100644 --- a/src/platform/Platform.h +++ b/src/platform/Platform.h @@ -25,7 +25,7 @@ #include #include "codec/NALUType.h" #include "rendering/utils/DisplayLink.h" -#include "rendering/utils/shaper/PositionedGlyphs.h" +#include "rendering/utils/shaper/ShapedGlyph.h" #include "rendering/video/VideoDecoderFactory.h" #include "tgfx/core/Data.h" #include "tgfx/core/ImageInfo.h" @@ -76,8 +76,8 @@ class Platform { /** * Returns the shaped glyphs of the given text and typeface. */ - virtual std::optional shapeText( - const std::string& text, const std::shared_ptr& typeface) const; + virtual std::vector shapeText(const std::string& text, + std::shared_ptr typeface) const; /** * Returns the corresponding sandbox path from the absolute file path, which usually starts with diff --git a/src/platform/cocoa/private/CocoaPlatform.h b/src/platform/cocoa/private/CocoaPlatform.h index ba88c29cef..0b260012e8 100644 --- a/src/platform/cocoa/private/CocoaPlatform.h +++ b/src/platform/cocoa/private/CocoaPlatform.h @@ -32,8 +32,8 @@ class CocoaPlatform : public Platform { void traceImage(const tgfx::ImageInfo& info, const void* pixels, const std::string& tag) const override; - std::optional shapeText( - const std::string& text, const std::shared_ptr& typeface) const override; + std::vector shapeText(const std::string& text, + std::shared_ptr typeface) const override; std::string getCacheDir() const override; }; diff --git a/src/platform/cocoa/private/CocoaPlatform.mm b/src/platform/cocoa/private/CocoaPlatform.mm index 644eff2567..c7e6ef46a4 100644 --- a/src/platform/cocoa/private/CocoaPlatform.mm +++ b/src/platform/cocoa/private/CocoaPlatform.mm @@ -18,13 +18,9 @@ #include "CocoaPlatform.h" #import +#include "NativeTextShaper.h" #include "TraceImage.h" #include "pag/pag.h" -#ifdef PAG_USE_HARFBUZZ -#include "base/utils/USE.h" -#else -#include "NativeTextShaper.h" -#endif namespace pag { bool CocoaPlatform::registerFallbackFonts() const { @@ -69,15 +65,9 @@ return [cachePath UTF8String]; } -std::optional CocoaPlatform::shapeText( - const std::string& text, const std::shared_ptr& typeface) const { -#ifdef PAG_USE_HARFBUZZ - USE(text); - USE(typeface); - return std::nullopt; -#else - return NativeTextShaper::Shape(text, typeface); -#endif +std::vector CocoaPlatform::shapeText(const std::string& text, + std::shared_ptr typeface) const { + return NativeTextShaper::Shape(text, std::move(typeface)); } } // namespace pag diff --git a/src/platform/cocoa/private/NativeTextShaper.h b/src/platform/cocoa/private/NativeTextShaper.h index 8a4294ae7c..abc7020e2d 100644 --- a/src/platform/cocoa/private/NativeTextShaper.h +++ b/src/platform/cocoa/private/NativeTextShaper.h @@ -19,13 +19,13 @@ #pragma once #include -#include "rendering/utils/shaper/PositionedGlyphs.h" +#include "rendering/utils/shaper/ShapedGlyph.h" #include "tgfx/core/Typeface.h" namespace pag { class NativeTextShaper { public: - static std::optional Shape(const std::string& text, - const std::shared_ptr& typeface); + static std::vector Shape(const std::string& text, + std::shared_ptr typeface); }; } // namespace pag diff --git a/src/platform/cocoa/private/NativeTextShaper.mm b/src/platform/cocoa/private/NativeTextShaper.mm index 8cfcff9ef4..2a1cbda1e1 100644 --- a/src/platform/cocoa/private/NativeTextShaper.mm +++ b/src/platform/cocoa/private/NativeTextShaper.mm @@ -22,13 +22,10 @@ #include "tgfx/platform/apple/CTTypeface.h" namespace pag { -std::optional NativeTextShaper::Shape( - const std::string& text, const std::shared_ptr& typeface) { - auto ctFont = tgfx::CTTypeface::GetCTFont(typeface.get()); - if (ctFont == nullptr) { - return std::nullopt; - } - std::vector clusters; +std::vector NativeTextShaper::Shape(const std::string& text, + std::shared_ptr typeface) { + auto mainFont = tgfx::CTTypeface::GetCTFont(typeface.get()); + std::vector clusters = {}; const char* textStart = text.data(); const char* textStop = textStart + text.size(); while (textStart < textStop) { @@ -43,17 +40,19 @@ auto str = CFStringCreateWithCString(kCFAllocatorDefault, text.c_str(), kCFStringEncodingUTF8); auto attr = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(attr, kCTFontAttributeName, ctFont); + if (mainFont != nullptr) { + CFDictionaryAddValue(attr, kCTFontAttributeName, mainFont); + } auto attrString = CFAttributedStringCreate(kCFAllocatorDefault, str, attr); auto line = CTLineCreateWithAttributedString(attrString); auto runs = CTLineGetGlyphRuns(line); - std::vector, tgfx::GlyphID, uint32_t>> glyphIDs; + std::vector glyphs = {}; for (CFIndex i = 0; i < CFArrayGetCount(runs); i++) { auto run = static_cast(CFArrayGetValueAtIndex(runs, i)); auto attrs = CTRunGetAttributes(run); auto font = (CTFontRef)CFDictionaryGetValue(attrs, kCTFontAttributeName); std::shared_ptr face; - if (font == ctFont) { + if (font == mainFont) { face = typeface; } else { face = tgfx::CTTypeface::MakeFromCTFont(font); @@ -62,18 +61,24 @@ } } auto count = CTRunGetGlyphCount(run); - std::vector glyphs(count); - CTRunGetGlyphs(run, CFRangeMake(0, count), glyphs.data()); + std::vector glyphIDs(count); + CTRunGetGlyphs(run, CFRangeMake(0, count), glyphIDs.data()); std::vector indices(count); CTRunGetStringIndices(run, CFRangeMake(0, count), indices.data()); - for (size_t j = 0; j < glyphs.size(); j++) { - glyphIDs.emplace_back(face, static_cast(glyphs[j]), clusters[indices[j]]); + std::vector positions(count); + CTRunGetPositions(run, CFRangeMake(0, count), positions.data()); + for (size_t j = 0; j < glyphIDs.size(); j++) { + if (j > 0 && positions[j].x == positions[j - 1].x) { + glyphs.back().glyphIDs.emplace_back(static_cast(glyphIDs[j])); + continue; + } + glyphs.emplace_back(face, static_cast(glyphIDs[j]), clusters[indices[j]]); } } CFRelease(line); CFRelease(attrString); CFRelease(attr); CFRelease(str); - return PositionedGlyphs(glyphIDs); + return glyphs; } } // namespace pag diff --git a/src/platform/web/NativePlatform.cpp b/src/platform/web/NativePlatform.cpp index 7905daf55f..dcb7e520eb 100644 --- a/src/platform/web/NativePlatform.cpp +++ b/src/platform/web/NativePlatform.cpp @@ -65,15 +65,9 @@ void NativePlatform::traceImage(const tgfx::ImageInfo& info, const void* pixels, traceImage(info, bytes, tag); } -std::optional NativePlatform::shapeText( - const std::string& text, const std::shared_ptr& typeface) const { -#ifdef PAG_USE_HARBUZZ - USE(text); - USE(typeface); - return std::nullopt; -#else +std::vector NativePlatform::shapeText(const std::string& text, + std::shared_ptr typeface) const { return NativeTextShaper::Shape(text, typeface); -#endif } std::vector NativePlatform::getVideoDecoderFactories() const { diff --git a/src/platform/web/NativePlatform.h b/src/platform/web/NativePlatform.h index 3d21d5411d..f0078f76c6 100644 --- a/src/platform/web/NativePlatform.h +++ b/src/platform/web/NativePlatform.h @@ -26,8 +26,8 @@ class NativePlatform : public Platform { void traceImage(const tgfx::ImageInfo& info, const void* pixels, const std::string& tag) const override; - std::optional shapeText( - const std::string& text, const std::shared_ptr& typeface) const override; + std::vector shapeText(const std::string& text, + std::shared_ptr typeface) const override; std::vector getVideoDecoderFactories() const override; }; diff --git a/src/platform/web/NativeTextShaper.cpp b/src/platform/web/NativeTextShaper.cpp index c748a7dbd0..d72795b20e 100644 --- a/src/platform/web/NativeTextShaper.cpp +++ b/src/platform/web/NativeTextShaper.cpp @@ -94,21 +94,20 @@ static void MergeClusters(std::vector& infos) { } } -PositionedGlyphs NativeTextShaper::Shape(const std::string& text, - const std::shared_ptr& typeface) { - std::vector infos; - const char* textStart = text.data(); - const char* textStop = textStart + text.size(); +std::vector NativeTextShaper::Shape(const std::string& text, + std::shared_ptr typeface) { + std::vector infos = {}; + auto textStart = text.data(); + auto textStop = textStart + text.size(); while (textStart < textStop) { auto cluster = static_cast(textStart - text.data()); infos.emplace_back(Info{tgfx::UTF::NextUTF8(&textStart, textStop), cluster}); } CheckContinuations(infos); - MergeClusters(infos); - std::vector, tgfx::GlyphID, uint32_t>> glyphs; + std::vector glyphs = {}; auto fallbackTypefaces = FontManager::GetFallbackTypefaces(); for (size_t i = 0; i < infos.size(); ++i) { auto length = (i + 1 == infos.size() ? text.length() : infos[i + 1].cluster) - infos[i].cluster; @@ -130,6 +129,6 @@ PositionedGlyphs NativeTextShaper::Shape(const std::string& text, glyphs.emplace_back(typeface, typeface->getGlyphID(str), infos[i].cluster); } } - return PositionedGlyphs(glyphs); + return glyphs; } } // namespace pag diff --git a/src/platform/web/NativeTextShaper.h b/src/platform/web/NativeTextShaper.h index 2e6209b4ca..fa7135d270 100644 --- a/src/platform/web/NativeTextShaper.h +++ b/src/platform/web/NativeTextShaper.h @@ -18,13 +18,13 @@ #pragma once -#include "rendering/utils/shaper/PositionedGlyphs.h" +#include "rendering/utils/shaper/ShapedGlyph.h" #include "tgfx/core/Typeface.h" namespace pag { class NativeTextShaper { public: - static PositionedGlyphs Shape(const std::string& text, - const std::shared_ptr& typeface); + static std::vector Shape(const std::string& text, + std::shared_ptr typeface); }; } // namespace pag diff --git a/src/rendering/caches/TextAtlas.cpp b/src/rendering/caches/TextAtlas.cpp index a95b0c234a..24504f5f60 100644 --- a/src/rendering/caches/TextAtlas.cpp +++ b/src/rendering/caches/TextAtlas.cpp @@ -202,8 +202,10 @@ static std::vector CreatePages(const std::vector& glyphs, int pack.reset(); point = pack.addRect(width, height); } - textRun->glyphIDs.push_back(glyph->getGlyphID()); - textRun->positions.push_back({-bounds.x() + point.x, -bounds.y() + point.y}); + for (auto& glyphID : glyph->getGlyphIDs()) { + textRun->glyphIDs.push_back(glyphID); + textRun->positions.push_back({-bounds.x() + point.x, -bounds.y() + point.y}); + } AtlasLocator locator; locator.imageIndex = pages.size(); locator.location = tgfx::Rect::MakeXYWH(point.x, point.y, static_cast(width), diff --git a/src/rendering/graphics/Glyph.cpp b/src/rendering/graphics/Glyph.cpp index 8351a019d8..5fefa77473 100644 --- a/src/rendering/graphics/Glyph.cpp +++ b/src/rendering/graphics/Glyph.cpp @@ -27,31 +27,34 @@ std::vector Glyph::BuildFromText(const std::string& text, const tgf auto textFont = font; std::unordered_map glyphMap; std::vector glyphList; - auto positionedGlyphs = TextShaper::Shape(text, font.getTypeface()); - auto count = positionedGlyphs.glyphCount(); + auto shapedGlyphs = TextShaper::Shape(text, font.getTypeface()); + auto count = shapedGlyphs.size(); for (size_t i = 0; i < count; ++i) { - auto index = positionedGlyphs.getStringIndex(i); - auto length = (i + 1 == count ? text.length() : positionedGlyphs.getStringIndex(i + 1)) - index; - auto name = text.substr(index, length); + auto& shapedGlyph = shapedGlyphs[i]; + auto length = (i + 1 == count ? text.length() : shapedGlyphs[i + 1].stringIndex) - + shapedGlyph.stringIndex; + auto name = text.substr(shapedGlyph.stringIndex, length); if (glyphMap.find(name) != glyphMap.end()) { glyphList.emplace_back(std::make_shared(*glyphMap[name])); continue; } - textFont.setTypeface(positionedGlyphs.getTypeface(i)); - auto glyph = std::shared_ptr( - new Glyph(positionedGlyphs.getGlyphID(i), name, textFont, isVertical, paint)); + textFont.setTypeface(shapedGlyph.typeface); + auto glyph = + std::shared_ptr(new Glyph(shapedGlyph.glyphIDs, name, textFont, isVertical, paint)); glyphMap[name] = glyph; glyphList.emplace_back(glyph); } return glyphList; } -Glyph::Glyph(tgfx::GlyphID glyphId, std::string name, tgfx::Font font, bool isVertical, - const TextPaint& textPaint) - : _glyphId(glyphId), _name(std::move(name)), _font(std::move(font)), _isVertical(isVertical) { - horizontalInfo->advance = _font.getAdvance(_glyphId); +Glyph::Glyph(std::vector glyphIDs, std::string name, tgfx::Font font, + bool isVertical, const TextPaint& textPaint) + : _glyphIDs(std::move(glyphIDs)), _name(std::move(name)), _font(std::move(font)), + _isVertical(isVertical) { + auto glyphID = _glyphIDs.front(); + horizontalInfo->advance = _font.getAdvance(glyphID); horizontalInfo->originPosition.set(horizontalInfo->advance / 2, 0); - horizontalInfo->bounds = _font.getBounds(_glyphId); + horizontalInfo->bounds = _font.getBounds(glyphID); auto metrics = _font.getMetrics(); if (horizontalInfo->bounds.isEmpty() && horizontalInfo->advance > 0) { horizontalInfo->bounds.setLTRB(0, metrics.ascent, horizontalInfo->advance, metrics.descent); @@ -78,10 +81,10 @@ Glyph::Glyph(tgfx::GlyphID glyphId, std::string name, tgfx::Font font, bool isVe verticalInfo->ascent += offsetX; verticalInfo->descent += offsetX; } else { - auto offset = _font.getVerticalOffset(_glyphId); + auto offset = _font.getVerticalOffset(glyphID); verticalInfo->extraMatrix.postTranslate(offset.x, offset.y); auto width = verticalInfo->advance; - verticalInfo->advance = _font.getAdvance(_glyphId, true); + verticalInfo->advance = _font.getAdvance(glyphID, true); if (verticalInfo->advance == 0) { verticalInfo->advance = width; } @@ -131,7 +134,9 @@ tgfx::Matrix Glyph::getTotalMatrix() const { void Glyph::computeAtlasKey(tgfx::BytesKey* bytesKey, TextStyle style) const { bytesKey->write(static_cast(getFont().hasColor())); - bytesKey->write(static_cast(getGlyphID())); + for (auto& glyphID : getGlyphIDs()) { + bytesKey->write(glyphID); + } bytesKey->write(static_cast(style)); } @@ -154,6 +159,6 @@ std::shared_ptr Glyph::makeScaledGlyph(float s) const { textPaint.fillColor = fillColor; textPaint.strokeColor = strokeColor; textPaint.strokeWidth = strokeWidth * s; - return std::shared_ptr(new Glyph(_glyphId, _name, scaledFont, _isVertical, textPaint)); + return std::shared_ptr(new Glyph(_glyphIDs, _name, scaledFont, _isVertical, textPaint)); } } // namespace pag diff --git a/src/rendering/graphics/Glyph.h b/src/rendering/graphics/Glyph.h index acfe51394c..fc084f99f4 100644 --- a/src/rendering/graphics/Glyph.h +++ b/src/rendering/graphics/Glyph.h @@ -67,8 +67,8 @@ class Glyph { /** * Returns the id of this glyph in associated typeface. */ - tgfx::GlyphID getGlyphID() const { - return _glyphId; + const std::vector& getGlyphIDs() const { + return _glyphIDs; } /** @@ -250,7 +250,7 @@ class Glyph { }; // read only attributes: - tgfx::GlyphID _glyphId = 0; + std::vector _glyphIDs = {}; std::string _name; tgfx::Font _font; bool _isVertical = false; @@ -268,7 +268,7 @@ class Glyph { std::shared_ptr verticalInfo; const Info* info = horizontalInfo.get(); - Glyph(tgfx::GlyphID glyphId, std::string name, tgfx::Font font, bool isVertical, + Glyph(std::vector glyphIDs, std::string name, tgfx::Font font, bool isVertical, const TextPaint& textPaint); }; } // namespace pag diff --git a/src/rendering/graphics/Text.cpp b/src/rendering/graphics/Text.cpp index cf85528d4e..db92453602 100644 --- a/src/rendering/graphics/Text.cpp +++ b/src/rendering/graphics/Text.cpp @@ -71,10 +71,12 @@ static std::unique_ptr MakeTextRun(const std::vector& glyphs) { std::vector glyphIDs = {}; std::vector positions = {}; for (auto& glyph : glyphs) { - glyphIDs.push_back(glyph->getGlyphID()); auto m = glyph->getTotalMatrix(); m.postConcat(noTranslateMatrix); - positions.push_back({m.getTranslateX(), m.getTranslateY()}); + for (auto& glyphID : glyph->getGlyphIDs()) { + glyphIDs.push_back(glyphID); + positions.push_back({m.getTranslateX(), m.getTranslateY()}); + } } textRun->textFont = firstGlyph->getFont(); textRun->glyphIDs = glyphIDs; diff --git a/src/rendering/utils/shaper/PositionedGlyphs.h b/src/rendering/utils/shaper/ShapedGlyph.h similarity index 56% rename from src/rendering/utils/shaper/PositionedGlyphs.h rename to src/rendering/utils/shaper/ShapedGlyph.h index afa4639333..2eda931a89 100644 --- a/src/rendering/utils/shaper/PositionedGlyphs.h +++ b/src/rendering/utils/shaper/ShapedGlyph.h @@ -2,7 +2,7 @@ // // Tencent is pleased to support the open source community by making libpag available. // -// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. +// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file // except in compliance with the License. You may obtain a copy of the License at @@ -22,32 +22,17 @@ #include "tgfx/core/Typeface.h" namespace pag { -class PositionedGlyphs { - public: - PositionedGlyphs() = default; - - explicit PositionedGlyphs( - std::vector, tgfx::GlyphID, uint32_t>> glyphs) - : glyphs(std::move(glyphs)) { - } - - std::shared_ptr getTypeface(size_t atIndex) const { - return std::get<0>(glyphs[atIndex]); - } - - tgfx::GlyphID getGlyphID(size_t atIndex) const { - return std::get<1>(glyphs[atIndex]); - } - - uint32_t getStringIndex(size_t atIndex) const { - return std::get<2>(glyphs[atIndex]); - } - - size_t glyphCount() const { - return glyphs.size(); +/** + * ShapedGlyph represents a shaped glyph. + */ +struct ShapedGlyph { + ShapedGlyph(std::shared_ptr typeface, tgfx::GlyphID glyphID, uint32_t stringIndex) + : typeface(std::move(typeface)), glyphIDs({glyphID}), stringIndex(stringIndex) { } - private: - std::vector, tgfx::GlyphID, uint32_t>> glyphs; + std::shared_ptr typeface = nullptr; + // There may be multiple glyph IDs for a single character in the case of ligatures. + std::vector glyphIDs = {}; + uint32_t stringIndex = 0; }; } // namespace pag diff --git a/src/rendering/utils/shaper/TextShaper.cpp b/src/rendering/utils/shaper/TextShaper.cpp index 16a0852fe5..1aa80a4993 100644 --- a/src/rendering/utils/shaper/TextShaper.cpp +++ b/src/rendering/utils/shaper/TextShaper.cpp @@ -25,17 +25,20 @@ #endif namespace pag { -PositionedGlyphs TextShaper::Shape(const std::string& text, - std::shared_ptr typeface) { +std::vector TextShaper::Shape(const std::string& text, + std::shared_ptr typeface) { if (text.empty()) { return {}; } #ifdef PAG_USE_HARFBUZZ return TextShaperHarfbuzz::Shape(text, std::move(typeface)); #else - if (auto ret = Platform::Current()->shapeText(text, typeface)) { - return *ret; +#ifndef TGFX_USE_FREETYPE + auto glyphs = Platform::Current()->shapeText(text, typeface); + if (!glyphs.empty()) { + return glyphs; } +#endif return TextShaperPrimitive::Shape(text, std::move(typeface)); #endif } diff --git a/src/rendering/utils/shaper/TextShaper.h b/src/rendering/utils/shaper/TextShaper.h index bd15172271..6d11739880 100644 --- a/src/rendering/utils/shaper/TextShaper.h +++ b/src/rendering/utils/shaper/TextShaper.h @@ -18,14 +18,24 @@ #pragma once -#include "PositionedGlyphs.h" +#include "ShapedGlyph.h" #include "tgfx/core/Typeface.h" namespace pag { +/** + * TextShaper is a utility class for shaping text. + */ class TextShaper { public: - static PositionedGlyphs Shape(const std::string& text, std::shared_ptr typeface); + /** + * Shapes the given text using the specified typeface. + */ + static std::vector Shape(const std::string& text, + std::shared_ptr typeface); + /** + * Purges the caches used by the text shaper. + */ static void PurgeCaches(); }; } // namespace pag diff --git a/src/rendering/utils/shaper/TextShaperHarfbuzz.cpp b/src/rendering/utils/shaper/TextShaperHarfbuzz.cpp index d9f23b283b..9aae0d2350 100644 --- a/src/rendering/utils/shaper/TextShaperHarfbuzz.cpp +++ b/src/rendering/utils/shaper/TextShaperHarfbuzz.cpp @@ -232,28 +232,28 @@ static bool Shape(std::list& glyphs, std::shared_ptr ty return allShaped; } -PositionedGlyphs TextShaperHarfbuzz::Shape(const std::string& text, - std::shared_ptr face) { - std::list glyphs; - glyphs.emplace_back(HBGlyph{text, {}, 0, nullptr}); +std::vector TextShaperHarfbuzz::Shape(const std::string& text, + std::shared_ptr face) { + std::list hbGlyphs = {}; + hbGlyphs.emplace_back(HBGlyph{text, {}, 0, nullptr}); bool allShaped = false; if (face && !face->fontFamily().empty()) { - allShaped = ::pag::Shape(glyphs, std::move(face)); + allShaped = ::pag::Shape(hbGlyphs, std::move(face)); } if (!allShaped) { auto typefaces = FontManager::GetFallbackTypefaces(); for (const auto& faceHolder : typefaces) { auto typeface = faceHolder->getTypeface(); - if (typeface && ::pag::Shape(glyphs, std::move(typeface))) { + if (typeface && ::pag::Shape(hbGlyphs, std::move(typeface))) { break; } } } - std::vector, tgfx::GlyphID, uint32_t>> glyphIDs; - for (const auto& glyph : glyphs) { - glyphIDs.emplace_back(glyph.typeface, glyph.glyphID, glyph.stringIndex); + std::vector glyphs = {}; + for (const auto& hbGlyph : hbGlyphs) { + glyphs.emplace_back(hbGlyph.typeface, hbGlyph.glyphID, hbGlyph.stringIndex); } - return PositionedGlyphs(std::move(glyphIDs)); + return glyphs; } void TextShaperHarfbuzz::PurgeCaches() { diff --git a/src/rendering/utils/shaper/TextShaperHarfbuzz.h b/src/rendering/utils/shaper/TextShaperHarfbuzz.h index 1d947697f8..f9cb4a6f8e 100644 --- a/src/rendering/utils/shaper/TextShaperHarfbuzz.h +++ b/src/rendering/utils/shaper/TextShaperHarfbuzz.h @@ -20,13 +20,14 @@ #ifdef PAG_USE_HARFBUZZ -#include "PositionedGlyphs.h" +#include "ShapedGlyph.h" #include "tgfx/core/Typeface.h" namespace pag { class TextShaperHarfbuzz { public: - static PositionedGlyphs Shape(const std::string& text, std::shared_ptr typeface); + static std::vector Shape(const std::string& text, + std::shared_ptr typeface); static void PurgeCaches(); }; diff --git a/src/rendering/utils/shaper/TextShaperPrimitive.cpp b/src/rendering/utils/shaper/TextShaperPrimitive.cpp index ab17f4ed6e..1429505567 100644 --- a/src/rendering/utils/shaper/TextShaperPrimitive.cpp +++ b/src/rendering/utils/shaper/TextShaperPrimitive.cpp @@ -21,11 +21,11 @@ #include "tgfx/core/UTF.h" namespace pag { -PositionedGlyphs TextShaperPrimitive::Shape(const std::string& text, - std::shared_ptr typeface) { +std::vector TextShaperPrimitive::Shape(const std::string& text, + std::shared_ptr typeface) { const char* textStart = text.data(); const char* textStop = textStart + text.size(); - std::vector, tgfx::GlyphID, uint32_t>> glyphs; + std::vector glyphs = {}; auto fallbackTypefaces = FontManager::GetFallbackTypefaces(); while (textStart < textStop) { auto oldPosition = textStart; @@ -49,6 +49,6 @@ PositionedGlyphs TextShaperPrimitive::Shape(const std::string& text, glyphs.emplace_back(typeface, glyphID, oldPosition - text.data()); } } - return PositionedGlyphs(glyphs); + return glyphs; } } // namespace pag diff --git a/src/rendering/utils/shaper/TextShaperPrimitive.h b/src/rendering/utils/shaper/TextShaperPrimitive.h index 895b021e1b..eed64a1b3d 100644 --- a/src/rendering/utils/shaper/TextShaperPrimitive.h +++ b/src/rendering/utils/shaper/TextShaperPrimitive.h @@ -18,12 +18,13 @@ #pragma once -#include "PositionedGlyphs.h" +#include "ShapedGlyph.h" #include "tgfx/core/Typeface.h" namespace pag { class TextShaperPrimitive { public: - static PositionedGlyphs Shape(const std::string& text, std::shared_ptr typeface); + static std::vector Shape(const std::string& text, + std::shared_ptr typeface); }; } // namespace pag From 8f03dbaa6cfd6b8e7ba926814a2684015c56ff8a Mon Sep 17 00:00:00 2001 From: domrjchen Date: Sun, 22 Dec 2024 11:04:46 +0800 Subject: [PATCH 2/2] Fix the web build. --- web/script/cmake.demo.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/script/cmake.demo.js b/web/script/cmake.demo.js index 4799389b30..74fad6d345 100644 --- a/web/script/cmake.demo.js +++ b/web/script/cmake.demo.js @@ -8,6 +8,8 @@ process.argv.push("-o"); process.argv.push("../src"); process.argv.push("-p"); process.argv.push("web"); +process.argv.push("-a"); +process.argv.push("wasm"); process.argv.push("pag"); require("../../build_pag");