From 194d822d880db458db063ec1d484d8de192c8182 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Fri, 6 Dec 2024 19:46:08 +0800 Subject: [PATCH 01/17] Implement RenderFont --- drawers/src/layertree/CustomLayerTree.cpp | 3 +- include/tgfx/core/Canvas.h | 13 +++ include/tgfx/core/FontWrapper.h | 44 +++++++ include/tgfx/core/GlyphRun.h | 11 +- include/tgfx/core/RenderFont.h | 68 +++++++++++ resources/assets/image1.png | 3 + resources/assets/image2.png | 3 + resources/assets/image3.png | 3 + src/core/Canvas.cpp | 23 +++- src/core/FontWrapper.cpp | 50 ++++++++ src/core/GlyphRunList.cpp | 24 ++-- src/core/GlyphRunList.h | 12 +- src/core/TextBlob.cpp | 20 ++-- src/gpu/RenderContext.cpp | 9 +- src/layers/TextLayer.cpp | 3 +- src/layers/contents/TextContent.cpp | 15 ++- src/layers/contents/TextContent.h | 2 +- test/src/CanvasTest.cpp | 134 ++++++++++++++++++++++ 18 files changed, 403 insertions(+), 37 deletions(-) create mode 100644 include/tgfx/core/FontWrapper.h create mode 100644 include/tgfx/core/RenderFont.h create mode 100644 resources/assets/image1.png create mode 100644 resources/assets/image2.png create mode 100644 resources/assets/image3.png create mode 100644 src/core/FontWrapper.cpp diff --git a/drawers/src/layertree/CustomLayerTree.cpp b/drawers/src/layertree/CustomLayerTree.cpp index 6a3dc37e..d22261ab 100644 --- a/drawers/src/layertree/CustomLayerTree.cpp +++ b/drawers/src/layertree/CustomLayerTree.cpp @@ -19,6 +19,7 @@ #include "CustomLayer.h" #include "base/LayerTreeDrawers.h" #include "drawers/AppHost.h" +#include "tgfx/core/FontWrapper.h" #include "tgfx/core/UTF.h" namespace drawers { @@ -66,7 +67,7 @@ std::unique_ptr CustomLayer::onUpdateContent() { xOffset += emptyAdvance; } } - tgfx::GlyphRun glyphRun(_font, std::move(glyphs), std::move(positions)); + tgfx::GlyphRun glyphRun(std::make_shared(_font), std::move(glyphs), std::move(positions)); auto textBlob = tgfx::TextBlob::MakeFrom(std::move(glyphRun)); if (textBlob == nullptr) { return nullptr; diff --git a/include/tgfx/core/Canvas.h b/include/tgfx/core/Canvas.h index f8a4f7c9..afb1f37b 100644 --- a/include/tgfx/core/Canvas.h +++ b/include/tgfx/core/Canvas.h @@ -24,6 +24,7 @@ #include "tgfx/core/Paint.h" #include "tgfx/core/Path.h" #include "tgfx/core/Picture.h" +#include "tgfx/core/RenderFont.h" #include "tgfx/core/SamplingOptions.h" #include "tgfx/core/Shape.h" #include "tgfx/core/TextBlob.h" @@ -279,6 +280,18 @@ class Canvas { void drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, const Font& font, const Paint& paint); + /** + * Draws an array of glyphIDs using RenderFont, with paths and images provided by RenderFont and + * positions specified by positions. + * @param glyphIDs The array of GlyphID to draw. + * @param positions Where to draw each glyph. + * @param renderFont Custom RenderFont used for rendering glyphs. + * @param paint Blend, color, and so on, used to draw. + * @note The lengths of `glyphIDs` and `positions` must be the same. + */ + void drawGlyphs(const std::vector& glyphIDs, const std::vector& positions, + std::shared_ptr renderFont, const Paint& paint) const; + /** * Draws a TextBlob at (x, y) using clip, matrix, and paint. * @param textBlob the text blob to draw. diff --git a/include/tgfx/core/FontWrapper.h b/include/tgfx/core/FontWrapper.h new file mode 100644 index 00000000..afe3d700 --- /dev/null +++ b/include/tgfx/core/FontWrapper.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "tgfx/core/Font.h" +#include "tgfx/core/RenderFont.h" + +namespace tgfx { +class FontWrapper final : public RenderFont { + public: + explicit FontWrapper(const Font& font) : _font(font) { + } + + bool hasColor() const override; + + bool hasOutlines() const override; + + std::shared_ptr makeScaled(float scale) override; + + bool getPath(GlyphID glyphID, Path* path) const override; + + std::shared_ptr getImage(GlyphID glyphID, Matrix* matrix) const override; + + Rect getBounds(GlyphID glyphID) const override; + + private: + Font _font = {}; +}; +} // namespace tgfx diff --git a/include/tgfx/core/GlyphRun.h b/include/tgfx/core/GlyphRun.h index 99f011cb..0be6ac4f 100644 --- a/include/tgfx/core/GlyphRun.h +++ b/include/tgfx/core/GlyphRun.h @@ -19,6 +19,7 @@ #pragma once #include "tgfx/core/Font.h" +#include "tgfx/core/RenderFont.h" namespace tgfx { /** @@ -31,16 +32,16 @@ struct GlyphRun { GlyphRun() = default; /** - * Constructs a GlyphRun using a font, a list of glyph IDs, and their positions. + * Constructs a GlyphRun using a RenderFont, a list of glyph IDs, and their positions. */ - GlyphRun(Font font, std::vector glyphIDs, std::vector positions) - : font(font), glyphs(glyphIDs), positions(positions) { + GlyphRun(std::shared_ptr renderFont, std::vector glyphIDs, std::vector positions) + : renderFont(renderFont), glyphs(glyphIDs), positions(positions) { } /** - * Returns the font used to render the glyphs in this run. + * Returns the RenderFont used to render the glyphs in this run. */ - Font font = {}; + std::shared_ptr renderFont = nullptr; /** * Returns the sequence of glyph IDs in this run. diff --git a/include/tgfx/core/RenderFont.h b/include/tgfx/core/RenderFont.h new file mode 100644 index 00000000..36fe3ca5 --- /dev/null +++ b/include/tgfx/core/RenderFont.h @@ -0,0 +1,68 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include "tgfx/core/Image.h" +#include "tgfx/core/Path.h" +#include "tgfx/core/Typeface.h" + +namespace tgfx { +/** +* RenderFont is a content provider for glyphs. It provides the glyph path, image, and bounds, etc. +*/ +class RenderFont { + public: + RenderFont() = default; + virtual ~RenderFont() = default; + + /** + * Returns true if the font has color glyphs, for example, color emojis. + */ + virtual bool hasColor() const = 0; + + /** + * Returns true if the font has outline glyphs, meaning it can generate paths. + */ + virtual bool hasOutlines() const = 0; + + /** + * Returns a new RenderFont with the same attributes of this font, but with the specified scale. + */ + virtual std::shared_ptr makeScaled(float scale) = 0; + + /** + * Creates a path corresponding to glyph outline. If glyph has an outline, copies outline to path + * and returns true. If glyph is described by a bitmap, returns false and ignores path parameter. + */ + virtual bool getPath(GlyphID glyphID, Path* path) const = 0; + + /** + * Creates an Image capturing the content of the specified glyph. The returned matrix should apply + * to the glyph image when drawing. Please note that the fauxBold is not supported for this + * method. + */ + virtual std::shared_ptr getImage(GlyphID glyphID, Matrix* matrix) const = 0; + + /** + * Returns the bounding box of the specified glyph. + */ + virtual Rect getBounds(GlyphID glyphID) const = 0; +}; +} // namespace tgfx diff --git a/resources/assets/image1.png b/resources/assets/image1.png new file mode 100644 index 00000000..d6971a52 --- /dev/null +++ b/resources/assets/image1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:516466eee3a3cd8c2866a4bafa73a02b485d653493be26e64571d59a77d1a63b +size 7650 diff --git a/resources/assets/image2.png b/resources/assets/image2.png new file mode 100644 index 00000000..8e9674ba --- /dev/null +++ b/resources/assets/image2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0ce97e2a0219915ed4bb18610a6a46c8eff36e2c3375d6c3c2160a1b8be079d0 +size 8593 diff --git a/resources/assets/image3.png b/resources/assets/image3.png new file mode 100644 index 00000000..a7e2650c --- /dev/null +++ b/resources/assets/image3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7350d57ce253a763e80a97a44ad66bf08c7d7e85d228e681fb15cebdc4804c34 +size 8334 diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index 068c8cdd..dd6ec92f 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -19,10 +19,9 @@ #include "tgfx/core/Canvas.h" #include "core/DrawContext.h" #include "core/LayerUnrollContext.h" -#include "core/Records.h" #include "core/utils/Log.h" #include "core/utils/Profiling.h" -#include "tgfx/core/PathEffect.h" +#include "tgfx/core/FontWrapper.h" #include "tgfx/core/Surface.h" namespace tgfx { @@ -333,12 +332,30 @@ void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t if (glyphCount == 0 || paint.nothingToDraw()) { return; } - GlyphRun glyphRun(font, {glyphs, glyphs + glyphCount}, {positions, positions + glyphCount}); + GlyphRun glyphRun(std::make_shared(font), {glyphs, glyphs + glyphCount}, {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); auto style = CreateFillStyle(paint); drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); } +void Canvas::drawGlyphs(const std::vector& glyphIDs, const std::vector& positions, + std::shared_ptr renderFont, const Paint& paint) const { + TRACE_EVENT; + if (glyphIDs.empty() || positions.empty() || paint.nothingToDraw()) { + return; + } + + if (glyphIDs.size() != positions.size()) { + LOGE("Canvas::drawGlyphs() glyphs and positions size mismatch!"); + return; + } + + GlyphRun glyphRun(renderFont, glyphIDs, positions); + auto glyphRunList = std::make_shared(std::move(glyphRun)); + const auto style = CreateFillStyle(paint); + drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); +} + void Canvas::drawTextBlob(std::shared_ptr textBlob, float x, float y, const Paint& paint) { TRACE_EVENT; diff --git a/src/core/FontWrapper.cpp b/src/core/FontWrapper.cpp new file mode 100644 index 00000000..591124da --- /dev/null +++ b/src/core/FontWrapper.cpp @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "tgfx/core/FontWrapper.h" +#include "utils/MathExtra.h" + +namespace tgfx { +bool FontWrapper::hasColor() const { + return _font.hasColor(); +} + +bool FontWrapper::hasOutlines() const { + return _font.hasOutlines(); +} + +std::shared_ptr FontWrapper::makeScaled(float scale) { + if (FloatNearlyZero(scale)) { + return nullptr; + } + auto size = _font.getSize() * scale; + return std::make_shared(_font.makeWithSize(size)); +} + +bool FontWrapper::getPath(GlyphID glyphID, Path* path) const { + return _font.getPath(glyphID, path); +} + +std::shared_ptr FontWrapper::getImage(GlyphID glyphID, Matrix* matrix) const { + return _font.getImage(glyphID, matrix); +} + +Rect FontWrapper::getBounds(GlyphID glyphID) const { + return _font.getBounds(glyphID); +} +} // namespace tgfx \ No newline at end of file diff --git a/src/core/GlyphRunList.cpp b/src/core/GlyphRunList.cpp index 6f912795..d7dd2ff5 100644 --- a/src/core/GlyphRunList.cpp +++ b/src/core/GlyphRunList.cpp @@ -38,11 +38,13 @@ GlyphRunList::GlyphRunList(GlyphRun glyphRun) { GlyphRunList::GlyphRunList(std::vector glyphRuns) : _glyphRuns(std::move(glyphRuns)) { DEBUG_ASSERT(!_glyphRuns.empty()); + DEBUG_ASSERT(_glyphRuns[0].renderFont != nullptr); DEBUG_ASSERT(std::all_of(_glyphRuns.begin(), _glyphRuns.end(), - [hasColor = _glyphRuns[0].font.hasColor()](const GlyphRun& glyphRun) { + [hasColor = _glyphRuns[0].renderFont->hasColor()](const GlyphRun& glyphRun) { return !glyphRun.glyphs.empty() && glyphRun.glyphs.size() == glyphRun.positions.size() && - glyphRun.font.hasColor() == hasColor; + glyphRun.renderFont != nullptr && + glyphRun.renderFont->hasColor() == hasColor; })); } @@ -53,15 +55,18 @@ Rect GlyphRunList::getBounds(float resolutionScale) const { auto hasScale = !FloatNearlyEqual(resolutionScale, 1.0f); auto totalBounds = Rect::MakeEmpty(); for (auto& run : _glyphRuns) { - auto font = run.font; + auto renderFont = run.renderFont; + if (renderFont == nullptr) { + continue; + } if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. - font = font.makeWithSize(font.getSize() * resolutionScale); + renderFont = renderFont->makeScaled(resolutionScale); } size_t index = 0; auto& positions = run.positions; for (auto& glyphID : run.glyphs) { - auto bounds = font.getBounds(glyphID); + auto bounds = renderFont->getBounds(glyphID); auto& position = positions[index]; bounds.offset(position.x * resolutionScale, position.y * resolutionScale); totalBounds.join(bounds); @@ -81,16 +86,19 @@ bool GlyphRunList::getPath(Path* path, float resolutionScale) const { auto hasScale = !FloatNearlyEqual(resolutionScale, 1.0f); Path totalPath = {}; for (auto& run : _glyphRuns) { - auto font = run.font; + auto renderFont = run.renderFont; + if (renderFont == nullptr) { + continue; + } if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. - font = font.makeWithSize(font.getSize() * resolutionScale); + renderFont = renderFont->makeScaled(resolutionScale); } size_t index = 0; auto& positions = run.positions; for (auto& glyphID : run.glyphs) { Path glyphPath = {}; - if (font.getPath(glyphID, &glyphPath)) { + if (renderFont->getPath(glyphID, &glyphPath)) { auto& position = positions[index]; auto glyphMatrix = Matrix::MakeScale(1.0f / resolutionScale, 1.0f / resolutionScale); glyphMatrix.postTranslate(position.x, position.y); diff --git a/src/core/GlyphRunList.h b/src/core/GlyphRunList.h index 9c52f013..099916db 100644 --- a/src/core/GlyphRunList.h +++ b/src/core/GlyphRunList.h @@ -51,14 +51,22 @@ class GlyphRunList { * Returns true if the GlyphRunList has color. */ bool hasColor() const { - return _glyphRuns[0].font.hasColor(); + if (_glyphRuns.empty()) { + return false; + } + const auto& renderFont = _glyphRuns[0].renderFont; + return renderFont ? renderFont->hasColor() : false; } /** * Returns true if the GlyphRunList has outlines. */ bool hasOutlines() const { - return _glyphRuns[0].font.hasOutlines(); + if (_glyphRuns.empty()) { + return false; + } + const auto& renderFont = _glyphRuns[0].renderFont; + return renderFont ? renderFont->hasOutlines() : false; } /** diff --git a/src/core/TextBlob.cpp b/src/core/TextBlob.cpp index e606b37b..44302c32 100644 --- a/src/core/TextBlob.cpp +++ b/src/core/TextBlob.cpp @@ -18,6 +18,7 @@ #include "tgfx/core/TextBlob.h" #include "core/GlyphRunList.h" +#include "tgfx/core/FontWrapper.h" #include "tgfx/core/UTF.h" namespace tgfx { @@ -25,7 +26,7 @@ std::shared_ptr TextBlob::MakeFrom(const std::string& text, const Font const char* textStart = text.data(); const char* textStop = textStart + text.size(); GlyphRun glyphRun = {}; - glyphRun.font = font; + glyphRun.renderFont = std::make_shared(font); // Use half the font size as width for spaces auto emptyAdvance = font.getSize() / 2.0f; float xOffset = 0; @@ -53,7 +54,7 @@ std::shared_ptr TextBlob::MakeFrom(const GlyphID glyphIDs[], const Poi if (glyphCount == 0) { return nullptr; } - GlyphRun glyphRun(font, {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); + GlyphRun glyphRun(std::make_shared(font), {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); return std::shared_ptr(new TextBlob({glyphRunList})); } @@ -71,13 +72,18 @@ std::shared_ptr TextBlob::MakeFrom(GlyphRun glyphRun) { enum class FontType { Path, Color, Other }; -static FontType GetFontType(const Font& font) { - if (font.hasColor()) { +static FontType GetFontType(const std::shared_ptr& font) { + if (font == nullptr) { + return FontType::Other; + } + + if (font->hasColor()) { return FontType::Color; } - if (font.hasOutlines()) { + if (font->hasOutlines()) { return FontType::Path; } + return FontType::Other; } @@ -90,7 +96,7 @@ std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { } std::vector> runLists; std::vector currentRuns; - FontType fontType = GetFontType(glyphRuns[0].font); + FontType fontType = GetFontType(glyphRuns[0].renderFont); for (auto& run : glyphRuns) { if (run.glyphs.size() != run.positions.size()) { return nullptr; @@ -98,7 +104,7 @@ std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { if (run.glyphs.empty()) { continue; } - auto currentFontType = GetFontType(run.font); + auto currentFontType = GetFontType(run.renderFont); if (currentFontType != fontType) { if (!currentRuns.empty()) { runLists.push_back(std::make_shared(std::move(currentRuns))); diff --git a/src/gpu/RenderContext.cpp b/src/gpu/RenderContext.cpp index b4e828be..be568515 100644 --- a/src/gpu/RenderContext.cpp +++ b/src/gpu/RenderContext.cpp @@ -264,8 +264,11 @@ void RenderContext::drawColorGlyphs(std::shared_ptr glyphRunList, auto scale = viewMatrix.getMaxScale(); viewMatrix.preScale(1.0f / scale, 1.0f / scale); for (auto& glyphRun : glyphRunList->glyphRuns()) { - auto font = glyphRun.font; - font = font.makeWithSize(font.getSize() * scale); + auto renderFont = glyphRun.renderFont; + if (renderFont == nullptr) { + continue; + } + renderFont = renderFont->makeScaled(scale); auto& glyphIDs = glyphRun.glyphs; auto glyphCount = glyphIDs.size(); auto& positions = glyphRun.positions; @@ -273,7 +276,7 @@ void RenderContext::drawColorGlyphs(std::shared_ptr glyphRunList, for (size_t i = 0; i < glyphCount; ++i) { const auto& glyphID = glyphIDs[i]; const auto& position = positions[i]; - auto glyphImage = font.getImage(glyphID, &glyphState.matrix); + auto glyphImage = renderFont->getImage(glyphID, &glyphState.matrix); if (glyphImage == nullptr) { continue; } diff --git a/src/layers/TextLayer.cpp b/src/layers/TextLayer.cpp index 45c6a1ac..17cb4e4e 100644 --- a/src/layers/TextLayer.cpp +++ b/src/layers/TextLayer.cpp @@ -20,6 +20,7 @@ #include "core/utils/Log.h" #include "core/utils/Profiling.h" #include "layers/contents/TextContent.h" +#include "tgfx/core/FontWrapper.h" #include "tgfx/core/UTF.h" namespace tgfx { @@ -422,7 +423,7 @@ void TextLayer::buildGlyphRunList(const std::vector>& if (glyphRunMap.find(typefaceID) == glyphRunMap.end()) { auto font = _font; font.setTypeface(typeface); - glyphRunMap[typefaceID] = GlyphRun(font, {}, {}); + glyphRunMap[typefaceID] = GlyphRun(std::make_shared(font), {}, {}); } auto& fontGlyphRun = glyphRunMap[typefaceID]; fontGlyphRun.glyphs.emplace_back(glyphInfo->getGlyphID()); diff --git a/src/layers/contents/TextContent.cpp b/src/layers/contents/TextContent.cpp index 688bd55f..54621d19 100644 --- a/src/layers/contents/TextContent.cpp +++ b/src/layers/contents/TextContent.cpp @@ -44,7 +44,7 @@ bool TextContent::hitTestPoint(float localX, float localY, bool pixelHitTest) { } for (const auto& glyphRunList : *glyphRunLists) { - if (hitTestPointInternal(localX, localY, glyphRunList)) { + if (HitTestPointInternal(localX, localY, glyphRunList)) { return true; } } @@ -55,25 +55,28 @@ bool TextContent::hitTestPoint(float localX, float localY, bool pixelHitTest) { return bounds.contains(localX, localY); } -bool TextContent::hitTestPointInternal(float localX, float localY, +bool TextContent::HitTestPointInternal(float localX, float localY, const std::shared_ptr& glyphRunList) { const auto& glyphRuns = glyphRunList->glyphRuns(); for (const auto& glyphRun : glyphRuns) { - const auto& font = glyphRun.font; + const auto& renderFont = glyphRun.renderFont; + if (renderFont == nullptr) { + continue; + } const auto& positions = glyphRun.positions; size_t index = 0; for (const auto& glyphID : glyphRun.glyphs) { const auto& position = positions[index]; - if (font.hasColor()) { - auto bounds = font.getBounds(glyphID); + if (renderFont->hasColor()) { + auto bounds = renderFont->getBounds(glyphID); bounds.offset(position.x, position.y); if (bounds.contains(localX, localY)) { return true; } } else { Path glyphPath = {}; - if (font.getPath(glyphID, &glyphPath)) { + if (renderFont->getPath(glyphID, &glyphPath)) { if (glyphPath.contains(localX - position.x, localY - position.y)) { return true; } diff --git a/src/layers/contents/TextContent.h b/src/layers/contents/TextContent.h index dcab6311..938c4fe8 100644 --- a/src/layers/contents/TextContent.h +++ b/src/layers/contents/TextContent.h @@ -38,7 +38,7 @@ class TextContent : public LayerContent { std::shared_ptr textBlob = nullptr; Color textColor = Color::White(); - bool hitTestPointInternal(float localX, float localY, + static bool HitTestPointInternal(float localX, float localY, const std::shared_ptr& glyphRunList); }; } // namespace tgfx diff --git a/test/src/CanvasTest.cpp b/test/src/CanvasTest.cpp index 2741b7b6..2433f8cd 100644 --- a/test/src/CanvasTest.cpp +++ b/test/src/CanvasTest.cpp @@ -20,6 +20,7 @@ #include "core/images/ResourceImage.h" #include "core/images/SubsetImage.h" #include "core/images/TransformImage.h" +#include "core/utils/MathExtra.h" #include "gpu/DrawingManager.h" #include "gpu/Texture.h" #include "gpu/opengl/GLCaps.h" @@ -1171,4 +1172,137 @@ TGFX_TEST(CanvasTest, Path_addArc) { EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/Path_addArc_reversed" + std::to_string(i))); } } + +class CustomPathRenderFont : public RenderFont, std::enable_shared_from_this { + public: + bool hasColor() const override { + return false; + } + bool hasOutlines() const override { + return false; + } + std::shared_ptr makeScaled(float scale) override { + _scale = scale; + return shared_from_this(); + } + + bool getPath(GlyphID glyphID, Path* path) const override { + switch (glyphID) { + case 1: + path->moveTo(25.0f, 5.0f); + path->lineTo(45.0f, 45.0f); + path->lineTo(5.0f, 45.0f); + path->close(); + return true; + case 2: + path->moveTo(5.0f, 5.0f); + path->lineTo(45.0f, 5.0f); + path->lineTo(45.0f, 45.0f); + path->lineTo(5.0f, 45.0f); + path->close(); + return true; + case 3: + path->addOval(Rect::MakeXYWH(5.0f, 5.0f, 40.0f, 40.0f)); + path->close(); + return true; + default: + return false; + } + return false; + } + + std::shared_ptr getImage(GlyphID /*glyphID*/, Matrix* /*matrix*/) const override { + return nullptr; + } + + Rect getBounds(GlyphID glyphID) const override { + if (glyphID < 1 || glyphID > 3) { + return Rect::MakeEmpty(); + } + return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + } + + private: + float _scale = 1.0f; +}; + +class CustomImageRenderFont : public RenderFont, + std::enable_shared_from_this { + public: + bool hasColor() const override { + return true; + } + bool hasOutlines() const override { + return false; + } + std::shared_ptr makeScaled(float scale) override { + if (FloatNearlyZero(scale)) { + return nullptr; + } + _scale = scale; + return shared_from_this(); + } + + bool getPath(GlyphID /*glyphID*/, Path* /*path*/) const override { + return false; + } + + std::shared_ptr getImage(GlyphID glyphID, Matrix* matrix) const override { + std::string imagePath; + switch (glyphID) { + case 4: + imagePath = "resources/assets/image1.png"; + break; + case 5: + imagePath = "resources/assets/image2.png"; + break; + case 6: + imagePath = "resources/assets/image3.png"; + break; + default: + return nullptr; + } + + matrix->setScale(0.25f, 0.25f); + return Image::MakeFromFile(ProjectPath::Absolute(imagePath)); + ; + } + + Rect getBounds(GlyphID glyphID) const override { + if (glyphID < 3 || glyphID > 6) { + return Rect::MakeEmpty(); + } + return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + } + + private: + float _scale = 1.0f; +}; + +TGFX_TEST(CanvasTest, RenderFontTest) { + ContextScope scope; + auto context = scope.getContext(); + ASSERT_TRUE(context != nullptr); + auto surface = Surface::Make(context, 400, 200); + auto canvas = surface->getCanvas(); + + auto paint = Paint(); + paint.setColor(Color::Red()); + + std::vector glyphIDs1 = {1, 2, 3}; + std::vector positions1 = {}; + positions1.push_back(Point::Make(0.0f, 0.0f)); + positions1.push_back(Point::Make(50.0f, 0.0f)); + positions1.push_back(Point::Make(100.0f, 0.0f)); + canvas->drawGlyphs(glyphIDs1, positions1, std::make_shared(), paint); + + std::vector glyphIDs2 = {4, 5, 6}; + std::vector positions2 = {}; + positions2.push_back(Point::Make(150.0f, 0.0f)); + positions2.push_back(Point::Make(205.0f, 0.0f)); + positions2.push_back(Point::Make(260.0f, 0.0f)); + canvas->drawGlyphs(glyphIDs2, positions2, std::make_shared(), paint); + + EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/RenderFontTest")); +} } // namespace tgfx From a49135f271c097faac45cbea67cca245bd6bfd6d Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Fri, 6 Dec 2024 20:01:54 +0800 Subject: [PATCH 02/17] RenderFont renamed to GlyphFace. --- drawers/src/layertree/CustomLayerTree.cpp | 4 ++-- include/tgfx/core/Canvas.h | 8 +++---- .../core/{FontWrapper.h => FontGlyphFace.h} | 8 +++---- .../tgfx/core/{RenderFont.h => GlyphFace.h} | 12 +++++----- include/tgfx/core/GlyphRun.h | 12 +++++----- src/core/Canvas.cpp | 8 +++---- src/core/FontWrapper.cpp | 16 ++++++------- src/core/GlyphRunList.cpp | 24 +++++++++---------- src/core/GlyphRunList.h | 8 +++---- src/core/TextBlob.cpp | 12 +++++----- src/gpu/RenderContext.cpp | 8 +++---- src/layers/TextLayer.cpp | 4 ++-- src/layers/contents/TextContent.cpp | 10 ++++---- test/src/CanvasTest.cpp | 18 +++++++------- 14 files changed, 76 insertions(+), 76 deletions(-) rename include/tgfx/core/{FontWrapper.h => FontGlyphFace.h} (86%) rename include/tgfx/core/{RenderFont.h => GlyphFace.h} (85%) diff --git a/drawers/src/layertree/CustomLayerTree.cpp b/drawers/src/layertree/CustomLayerTree.cpp index d22261ab..ecdbc899 100644 --- a/drawers/src/layertree/CustomLayerTree.cpp +++ b/drawers/src/layertree/CustomLayerTree.cpp @@ -19,7 +19,7 @@ #include "CustomLayer.h" #include "base/LayerTreeDrawers.h" #include "drawers/AppHost.h" -#include "tgfx/core/FontWrapper.h" +#include "tgfx/core/FontGlyphFace.h" #include "tgfx/core/UTF.h" namespace drawers { @@ -67,7 +67,7 @@ std::unique_ptr CustomLayer::onUpdateContent() { xOffset += emptyAdvance; } } - tgfx::GlyphRun glyphRun(std::make_shared(_font), std::move(glyphs), std::move(positions)); + tgfx::GlyphRun glyphRun(std::make_shared(_font), std::move(glyphs), std::move(positions)); auto textBlob = tgfx::TextBlob::MakeFrom(std::move(glyphRun)); if (textBlob == nullptr) { return nullptr; diff --git a/include/tgfx/core/Canvas.h b/include/tgfx/core/Canvas.h index afb1f37b..517eef44 100644 --- a/include/tgfx/core/Canvas.h +++ b/include/tgfx/core/Canvas.h @@ -24,7 +24,7 @@ #include "tgfx/core/Paint.h" #include "tgfx/core/Path.h" #include "tgfx/core/Picture.h" -#include "tgfx/core/RenderFont.h" +#include "tgfx/core/GlyphFace.h" #include "tgfx/core/SamplingOptions.h" #include "tgfx/core/Shape.h" #include "tgfx/core/TextBlob.h" @@ -281,16 +281,16 @@ class Canvas { const Font& font, const Paint& paint); /** - * Draws an array of glyphIDs using RenderFont, with paths and images provided by RenderFont and + * Draws an array of glyphIDs using GlyphFace, with paths and images provided by GlyphFace and * positions specified by positions. * @param glyphIDs The array of GlyphID to draw. * @param positions Where to draw each glyph. - * @param renderFont Custom RenderFont used for rendering glyphs. + * @param glyphFace Custom GlyphFace used for rendering glyphs. * @param paint Blend, color, and so on, used to draw. * @note The lengths of `glyphIDs` and `positions` must be the same. */ void drawGlyphs(const std::vector& glyphIDs, const std::vector& positions, - std::shared_ptr renderFont, const Paint& paint) const; + std::shared_ptr glyphFace, const Paint& paint) const; /** * Draws a TextBlob at (x, y) using clip, matrix, and paint. diff --git a/include/tgfx/core/FontWrapper.h b/include/tgfx/core/FontGlyphFace.h similarity index 86% rename from include/tgfx/core/FontWrapper.h rename to include/tgfx/core/FontGlyphFace.h index afe3d700..267f92dc 100644 --- a/include/tgfx/core/FontWrapper.h +++ b/include/tgfx/core/FontGlyphFace.h @@ -18,19 +18,19 @@ #pragma once #include "tgfx/core/Font.h" -#include "tgfx/core/RenderFont.h" +#include "tgfx/core/GlyphFace.h" namespace tgfx { -class FontWrapper final : public RenderFont { +class FontGlyphFace final : public GlyphFace { public: - explicit FontWrapper(const Font& font) : _font(font) { + explicit FontGlyphFace(const Font& font) : _font(font) { } bool hasColor() const override; bool hasOutlines() const override; - std::shared_ptr makeScaled(float scale) override; + std::shared_ptr makeScaled(float scale) override; bool getPath(GlyphID glyphID, Path* path) const override; diff --git a/include/tgfx/core/RenderFont.h b/include/tgfx/core/GlyphFace.h similarity index 85% rename from include/tgfx/core/RenderFont.h rename to include/tgfx/core/GlyphFace.h index 36fe3ca5..372c7462 100644 --- a/include/tgfx/core/RenderFont.h +++ b/include/tgfx/core/GlyphFace.h @@ -25,12 +25,12 @@ namespace tgfx { /** -* RenderFont is a content provider for glyphs. It provides the glyph path, image, and bounds, etc. +* GlyphFace is a provider for glyphs. It provides the glyph path, image, and bounds, etc. */ -class RenderFont { +class GlyphFace { public: - RenderFont() = default; - virtual ~RenderFont() = default; + GlyphFace() = default; + virtual ~GlyphFace() = default; /** * Returns true if the font has color glyphs, for example, color emojis. @@ -43,9 +43,9 @@ class RenderFont { virtual bool hasOutlines() const = 0; /** - * Returns a new RenderFont with the same attributes of this font, but with the specified scale. + * Returns a new GlyphFace with the same attributes of this font, but with the specified scale. */ - virtual std::shared_ptr makeScaled(float scale) = 0; + virtual std::shared_ptr makeScaled(float scale) = 0; /** * Creates a path corresponding to glyph outline. If glyph has an outline, copies outline to path diff --git a/include/tgfx/core/GlyphRun.h b/include/tgfx/core/GlyphRun.h index 0be6ac4f..9524ffe3 100644 --- a/include/tgfx/core/GlyphRun.h +++ b/include/tgfx/core/GlyphRun.h @@ -19,7 +19,7 @@ #pragma once #include "tgfx/core/Font.h" -#include "tgfx/core/RenderFont.h" +#include "tgfx/core/GlyphFace.h" namespace tgfx { /** @@ -32,16 +32,16 @@ struct GlyphRun { GlyphRun() = default; /** - * Constructs a GlyphRun using a RenderFont, a list of glyph IDs, and their positions. + * Constructs a GlyphRun using a GlyphFace, a list of glyph IDs, and their positions. */ - GlyphRun(std::shared_ptr renderFont, std::vector glyphIDs, std::vector positions) - : renderFont(renderFont), glyphs(glyphIDs), positions(positions) { + GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, std::vector positions) + : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { } /** - * Returns the RenderFont used to render the glyphs in this run. + * Returns the GlyphFace used to render the glyphs in this run. */ - std::shared_ptr renderFont = nullptr; + std::shared_ptr glyphFace = nullptr; /** * Returns the sequence of glyph IDs in this run. diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index dd6ec92f..75266389 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -21,7 +21,7 @@ #include "core/LayerUnrollContext.h" #include "core/utils/Log.h" #include "core/utils/Profiling.h" -#include "tgfx/core/FontWrapper.h" +#include "tgfx/core/FontGlyphFace.h" #include "tgfx/core/Surface.h" namespace tgfx { @@ -332,14 +332,14 @@ void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t if (glyphCount == 0 || paint.nothingToDraw()) { return; } - GlyphRun glyphRun(std::make_shared(font), {glyphs, glyphs + glyphCount}, {positions, positions + glyphCount}); + GlyphRun glyphRun(std::make_shared(font), {glyphs, glyphs + glyphCount}, {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); auto style = CreateFillStyle(paint); drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); } void Canvas::drawGlyphs(const std::vector& glyphIDs, const std::vector& positions, - std::shared_ptr renderFont, const Paint& paint) const { + std::shared_ptr glyphFace, const Paint& paint) const { TRACE_EVENT; if (glyphIDs.empty() || positions.empty() || paint.nothingToDraw()) { return; @@ -350,7 +350,7 @@ void Canvas::drawGlyphs(const std::vector& glyphIDs, const std::vector< return; } - GlyphRun glyphRun(renderFont, glyphIDs, positions); + GlyphRun glyphRun(glyphFace, glyphIDs, positions); auto glyphRunList = std::make_shared(std::move(glyphRun)); const auto style = CreateFillStyle(paint); drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); diff --git a/src/core/FontWrapper.cpp b/src/core/FontWrapper.cpp index 591124da..c6781448 100644 --- a/src/core/FontWrapper.cpp +++ b/src/core/FontWrapper.cpp @@ -16,35 +16,35 @@ // ///////////////////////////////////////////////////////////////////////////////////////////////// -#include "tgfx/core/FontWrapper.h" +#include "tgfx/core/FontGlyphFace.h" #include "utils/MathExtra.h" namespace tgfx { -bool FontWrapper::hasColor() const { +bool FontGlyphFace::hasColor() const { return _font.hasColor(); } -bool FontWrapper::hasOutlines() const { +bool FontGlyphFace::hasOutlines() const { return _font.hasOutlines(); } -std::shared_ptr FontWrapper::makeScaled(float scale) { +std::shared_ptr FontGlyphFace::makeScaled(float scale) { if (FloatNearlyZero(scale)) { return nullptr; } auto size = _font.getSize() * scale; - return std::make_shared(_font.makeWithSize(size)); + return std::make_shared(_font.makeWithSize(size)); } -bool FontWrapper::getPath(GlyphID glyphID, Path* path) const { +bool FontGlyphFace::getPath(GlyphID glyphID, Path* path) const { return _font.getPath(glyphID, path); } -std::shared_ptr FontWrapper::getImage(GlyphID glyphID, Matrix* matrix) const { +std::shared_ptr FontGlyphFace::getImage(GlyphID glyphID, Matrix* matrix) const { return _font.getImage(glyphID, matrix); } -Rect FontWrapper::getBounds(GlyphID glyphID) const { +Rect FontGlyphFace::getBounds(GlyphID glyphID) const { return _font.getBounds(glyphID); } } // namespace tgfx \ No newline at end of file diff --git a/src/core/GlyphRunList.cpp b/src/core/GlyphRunList.cpp index d7dd2ff5..3e9242ca 100644 --- a/src/core/GlyphRunList.cpp +++ b/src/core/GlyphRunList.cpp @@ -38,13 +38,13 @@ GlyphRunList::GlyphRunList(GlyphRun glyphRun) { GlyphRunList::GlyphRunList(std::vector glyphRuns) : _glyphRuns(std::move(glyphRuns)) { DEBUG_ASSERT(!_glyphRuns.empty()); - DEBUG_ASSERT(_glyphRuns[0].renderFont != nullptr); + DEBUG_ASSERT(_glyphRuns[0].glyphFace != nullptr); DEBUG_ASSERT(std::all_of(_glyphRuns.begin(), _glyphRuns.end(), - [hasColor = _glyphRuns[0].renderFont->hasColor()](const GlyphRun& glyphRun) { + [hasColor = _glyphRuns[0].glyphFace->hasColor()](const GlyphRun& glyphRun) { return !glyphRun.glyphs.empty() && glyphRun.glyphs.size() == glyphRun.positions.size() && - glyphRun.renderFont != nullptr && - glyphRun.renderFont->hasColor() == hasColor; + glyphRun.glyphFace != nullptr && + glyphRun.glyphFace->hasColor() == hasColor; })); } @@ -55,18 +55,18 @@ Rect GlyphRunList::getBounds(float resolutionScale) const { auto hasScale = !FloatNearlyEqual(resolutionScale, 1.0f); auto totalBounds = Rect::MakeEmpty(); for (auto& run : _glyphRuns) { - auto renderFont = run.renderFont; - if (renderFont == nullptr) { + auto glyphFace = run.glyphFace; + if (glyphFace == nullptr) { continue; } if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. - renderFont = renderFont->makeScaled(resolutionScale); + glyphFace = glyphFace->makeScaled(resolutionScale); } size_t index = 0; auto& positions = run.positions; for (auto& glyphID : run.glyphs) { - auto bounds = renderFont->getBounds(glyphID); + auto bounds = glyphFace->getBounds(glyphID); auto& position = positions[index]; bounds.offset(position.x * resolutionScale, position.y * resolutionScale); totalBounds.join(bounds); @@ -86,19 +86,19 @@ bool GlyphRunList::getPath(Path* path, float resolutionScale) const { auto hasScale = !FloatNearlyEqual(resolutionScale, 1.0f); Path totalPath = {}; for (auto& run : _glyphRuns) { - auto renderFont = run.renderFont; - if (renderFont == nullptr) { + auto glyphFace = run.glyphFace; + if (glyphFace == nullptr) { continue; } if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. - renderFont = renderFont->makeScaled(resolutionScale); + glyphFace = glyphFace->makeScaled(resolutionScale); } size_t index = 0; auto& positions = run.positions; for (auto& glyphID : run.glyphs) { Path glyphPath = {}; - if (renderFont->getPath(glyphID, &glyphPath)) { + if (glyphFace->getPath(glyphID, &glyphPath)) { auto& position = positions[index]; auto glyphMatrix = Matrix::MakeScale(1.0f / resolutionScale, 1.0f / resolutionScale); glyphMatrix.postTranslate(position.x, position.y); diff --git a/src/core/GlyphRunList.h b/src/core/GlyphRunList.h index 099916db..cafad6e8 100644 --- a/src/core/GlyphRunList.h +++ b/src/core/GlyphRunList.h @@ -54,8 +54,8 @@ class GlyphRunList { if (_glyphRuns.empty()) { return false; } - const auto& renderFont = _glyphRuns[0].renderFont; - return renderFont ? renderFont->hasColor() : false; + const auto& glyphFace = _glyphRuns[0].glyphFace; + return glyphFace ? glyphFace->hasColor() : false; } /** @@ -65,8 +65,8 @@ class GlyphRunList { if (_glyphRuns.empty()) { return false; } - const auto& renderFont = _glyphRuns[0].renderFont; - return renderFont ? renderFont->hasOutlines() : false; + const auto& glyphFace = _glyphRuns[0].glyphFace; + return glyphFace ? glyphFace->hasOutlines() : false; } /** diff --git a/src/core/TextBlob.cpp b/src/core/TextBlob.cpp index 44302c32..8e6ca7c7 100644 --- a/src/core/TextBlob.cpp +++ b/src/core/TextBlob.cpp @@ -18,7 +18,7 @@ #include "tgfx/core/TextBlob.h" #include "core/GlyphRunList.h" -#include "tgfx/core/FontWrapper.h" +#include "tgfx/core/FontGlyphFace.h" #include "tgfx/core/UTF.h" namespace tgfx { @@ -26,7 +26,7 @@ std::shared_ptr TextBlob::MakeFrom(const std::string& text, const Font const char* textStart = text.data(); const char* textStop = textStart + text.size(); GlyphRun glyphRun = {}; - glyphRun.renderFont = std::make_shared(font); + glyphRun.glyphFace = std::make_shared(font); // Use half the font size as width for spaces auto emptyAdvance = font.getSize() / 2.0f; float xOffset = 0; @@ -54,7 +54,7 @@ std::shared_ptr TextBlob::MakeFrom(const GlyphID glyphIDs[], const Poi if (glyphCount == 0) { return nullptr; } - GlyphRun glyphRun(std::make_shared(font), {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); + GlyphRun glyphRun(std::make_shared(font), {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); return std::shared_ptr(new TextBlob({glyphRunList})); } @@ -72,7 +72,7 @@ std::shared_ptr TextBlob::MakeFrom(GlyphRun glyphRun) { enum class FontType { Path, Color, Other }; -static FontType GetFontType(const std::shared_ptr& font) { +static FontType GetFontType(const std::shared_ptr& font) { if (font == nullptr) { return FontType::Other; } @@ -96,7 +96,7 @@ std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { } std::vector> runLists; std::vector currentRuns; - FontType fontType = GetFontType(glyphRuns[0].renderFont); + FontType fontType = GetFontType(glyphRuns[0].glyphFace); for (auto& run : glyphRuns) { if (run.glyphs.size() != run.positions.size()) { return nullptr; @@ -104,7 +104,7 @@ std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { if (run.glyphs.empty()) { continue; } - auto currentFontType = GetFontType(run.renderFont); + auto currentFontType = GetFontType(run.glyphFace); if (currentFontType != fontType) { if (!currentRuns.empty()) { runLists.push_back(std::make_shared(std::move(currentRuns))); diff --git a/src/gpu/RenderContext.cpp b/src/gpu/RenderContext.cpp index be568515..061d9b53 100644 --- a/src/gpu/RenderContext.cpp +++ b/src/gpu/RenderContext.cpp @@ -264,11 +264,11 @@ void RenderContext::drawColorGlyphs(std::shared_ptr glyphRunList, auto scale = viewMatrix.getMaxScale(); viewMatrix.preScale(1.0f / scale, 1.0f / scale); for (auto& glyphRun : glyphRunList->glyphRuns()) { - auto renderFont = glyphRun.renderFont; - if (renderFont == nullptr) { + auto glyphFace = glyphRun.glyphFace; + if (glyphFace == nullptr) { continue; } - renderFont = renderFont->makeScaled(scale); + glyphFace = glyphFace->makeScaled(scale); auto& glyphIDs = glyphRun.glyphs; auto glyphCount = glyphIDs.size(); auto& positions = glyphRun.positions; @@ -276,7 +276,7 @@ void RenderContext::drawColorGlyphs(std::shared_ptr glyphRunList, for (size_t i = 0; i < glyphCount; ++i) { const auto& glyphID = glyphIDs[i]; const auto& position = positions[i]; - auto glyphImage = renderFont->getImage(glyphID, &glyphState.matrix); + auto glyphImage = glyphFace->getImage(glyphID, &glyphState.matrix); if (glyphImage == nullptr) { continue; } diff --git a/src/layers/TextLayer.cpp b/src/layers/TextLayer.cpp index 17cb4e4e..24ff4709 100644 --- a/src/layers/TextLayer.cpp +++ b/src/layers/TextLayer.cpp @@ -20,7 +20,7 @@ #include "core/utils/Log.h" #include "core/utils/Profiling.h" #include "layers/contents/TextContent.h" -#include "tgfx/core/FontWrapper.h" +#include "tgfx/core/FontGlyphFace.h" #include "tgfx/core/UTF.h" namespace tgfx { @@ -423,7 +423,7 @@ void TextLayer::buildGlyphRunList(const std::vector>& if (glyphRunMap.find(typefaceID) == glyphRunMap.end()) { auto font = _font; font.setTypeface(typeface); - glyphRunMap[typefaceID] = GlyphRun(std::make_shared(font), {}, {}); + glyphRunMap[typefaceID] = GlyphRun(std::make_shared(font), {}, {}); } auto& fontGlyphRun = glyphRunMap[typefaceID]; fontGlyphRun.glyphs.emplace_back(glyphInfo->getGlyphID()); diff --git a/src/layers/contents/TextContent.cpp b/src/layers/contents/TextContent.cpp index 54621d19..cccd4643 100644 --- a/src/layers/contents/TextContent.cpp +++ b/src/layers/contents/TextContent.cpp @@ -59,8 +59,8 @@ bool TextContent::HitTestPointInternal(float localX, float localY, const std::shared_ptr& glyphRunList) { const auto& glyphRuns = glyphRunList->glyphRuns(); for (const auto& glyphRun : glyphRuns) { - const auto& renderFont = glyphRun.renderFont; - if (renderFont == nullptr) { + const auto& glyphFace = glyphRun.glyphFace; + if (glyphFace == nullptr) { continue; } const auto& positions = glyphRun.positions; @@ -68,15 +68,15 @@ bool TextContent::HitTestPointInternal(float localX, float localY, for (const auto& glyphID : glyphRun.glyphs) { const auto& position = positions[index]; - if (renderFont->hasColor()) { - auto bounds = renderFont->getBounds(glyphID); + if (glyphFace->hasColor()) { + auto bounds = glyphFace->getBounds(glyphID); bounds.offset(position.x, position.y); if (bounds.contains(localX, localY)) { return true; } } else { Path glyphPath = {}; - if (renderFont->getPath(glyphID, &glyphPath)) { + if (glyphFace->getPath(glyphID, &glyphPath)) { if (glyphPath.contains(localX - position.x, localY - position.y)) { return true; } diff --git a/test/src/CanvasTest.cpp b/test/src/CanvasTest.cpp index 2433f8cd..36eb2f6f 100644 --- a/test/src/CanvasTest.cpp +++ b/test/src/CanvasTest.cpp @@ -1173,7 +1173,7 @@ TGFX_TEST(CanvasTest, Path_addArc) { } } -class CustomPathRenderFont : public RenderFont, std::enable_shared_from_this { +class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_this { public: bool hasColor() const override { return false; @@ -1181,7 +1181,7 @@ class CustomPathRenderFont : public RenderFont, std::enable_shared_from_this makeScaled(float scale) override { + std::shared_ptr makeScaled(float scale) override { _scale = scale; return shared_from_this(); } @@ -1226,8 +1226,8 @@ class CustomPathRenderFont : public RenderFont, std::enable_shared_from_this { +class CustomImageGlyphFace : public GlyphFace, + std::enable_shared_from_this { public: bool hasColor() const override { return true; @@ -1235,7 +1235,7 @@ class CustomImageRenderFont : public RenderFont, bool hasOutlines() const override { return false; } - std::shared_ptr makeScaled(float scale) override { + std::shared_ptr makeScaled(float scale) override { if (FloatNearlyZero(scale)) { return nullptr; } @@ -1279,7 +1279,7 @@ class CustomImageRenderFont : public RenderFont, float _scale = 1.0f; }; -TGFX_TEST(CanvasTest, RenderFontTest) { +TGFX_TEST(CanvasTest, GlyphFaceTest) { ContextScope scope; auto context = scope.getContext(); ASSERT_TRUE(context != nullptr); @@ -1294,15 +1294,15 @@ TGFX_TEST(CanvasTest, RenderFontTest) { positions1.push_back(Point::Make(0.0f, 0.0f)); positions1.push_back(Point::Make(50.0f, 0.0f)); positions1.push_back(Point::Make(100.0f, 0.0f)); - canvas->drawGlyphs(glyphIDs1, positions1, std::make_shared(), paint); + canvas->drawGlyphs(glyphIDs1, positions1, std::make_shared(), paint); std::vector glyphIDs2 = {4, 5, 6}; std::vector positions2 = {}; positions2.push_back(Point::Make(150.0f, 0.0f)); positions2.push_back(Point::Make(205.0f, 0.0f)); positions2.push_back(Point::Make(260.0f, 0.0f)); - canvas->drawGlyphs(glyphIDs2, positions2, std::make_shared(), paint); + canvas->drawGlyphs(glyphIDs2, positions2, std::make_shared(), paint); - EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/RenderFontTest")); + EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/GlyphFaceTest")); } } // namespace tgfx From ace00c1731ad635f4f9fb1934a55b57c88e37014 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Fri, 6 Dec 2024 20:03:33 +0800 Subject: [PATCH 03/17] format code. --- drawers/src/layertree/CustomLayerTree.cpp | 3 ++- include/tgfx/core/Canvas.h | 2 +- include/tgfx/core/GlyphRun.h | 3 ++- src/core/Canvas.cpp | 3 ++- src/core/GlyphRunList.cpp | 13 ++++++------- src/core/TextBlob.cpp | 3 ++- src/layers/contents/TextContent.h | 2 +- test/src/CanvasTest.cpp | 3 +-- 8 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drawers/src/layertree/CustomLayerTree.cpp b/drawers/src/layertree/CustomLayerTree.cpp index ecdbc899..fce846f6 100644 --- a/drawers/src/layertree/CustomLayerTree.cpp +++ b/drawers/src/layertree/CustomLayerTree.cpp @@ -67,7 +67,8 @@ std::unique_ptr CustomLayer::onUpdateContent() { xOffset += emptyAdvance; } } - tgfx::GlyphRun glyphRun(std::make_shared(_font), std::move(glyphs), std::move(positions)); + tgfx::GlyphRun glyphRun(std::make_shared(_font), std::move(glyphs), + std::move(positions)); auto textBlob = tgfx::TextBlob::MakeFrom(std::move(glyphRun)); if (textBlob == nullptr) { return nullptr; diff --git a/include/tgfx/core/Canvas.h b/include/tgfx/core/Canvas.h index 517eef44..e12f3109 100644 --- a/include/tgfx/core/Canvas.h +++ b/include/tgfx/core/Canvas.h @@ -20,11 +20,11 @@ #include #include "tgfx/core/Font.h" +#include "tgfx/core/GlyphFace.h" #include "tgfx/core/Image.h" #include "tgfx/core/Paint.h" #include "tgfx/core/Path.h" #include "tgfx/core/Picture.h" -#include "tgfx/core/GlyphFace.h" #include "tgfx/core/SamplingOptions.h" #include "tgfx/core/Shape.h" #include "tgfx/core/TextBlob.h" diff --git a/include/tgfx/core/GlyphRun.h b/include/tgfx/core/GlyphRun.h index 9524ffe3..e66e66d0 100644 --- a/include/tgfx/core/GlyphRun.h +++ b/include/tgfx/core/GlyphRun.h @@ -34,7 +34,8 @@ struct GlyphRun { /** * Constructs a GlyphRun using a GlyphFace, a list of glyph IDs, and their positions. */ - GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, std::vector positions) + GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, + std::vector positions) : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { } diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index 75266389..fa76ec29 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -332,7 +332,8 @@ void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t if (glyphCount == 0 || paint.nothingToDraw()) { return; } - GlyphRun glyphRun(std::make_shared(font), {glyphs, glyphs + glyphCount}, {positions, positions + glyphCount}); + GlyphRun glyphRun(std::make_shared(font), {glyphs, glyphs + glyphCount}, + {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); auto style = CreateFillStyle(paint); drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); diff --git a/src/core/GlyphRunList.cpp b/src/core/GlyphRunList.cpp index 3e9242ca..d5c54e6c 100644 --- a/src/core/GlyphRunList.cpp +++ b/src/core/GlyphRunList.cpp @@ -39,13 +39,12 @@ GlyphRunList::GlyphRunList(GlyphRun glyphRun) { GlyphRunList::GlyphRunList(std::vector glyphRuns) : _glyphRuns(std::move(glyphRuns)) { DEBUG_ASSERT(!_glyphRuns.empty()); DEBUG_ASSERT(_glyphRuns[0].glyphFace != nullptr); - DEBUG_ASSERT(std::all_of(_glyphRuns.begin(), _glyphRuns.end(), - [hasColor = _glyphRuns[0].glyphFace->hasColor()](const GlyphRun& glyphRun) { - return !glyphRun.glyphs.empty() && - glyphRun.glyphs.size() == glyphRun.positions.size() && - glyphRun.glyphFace != nullptr && - glyphRun.glyphFace->hasColor() == hasColor; - })); + DEBUG_ASSERT(std::all_of( + _glyphRuns.begin(), _glyphRuns.end(), + [hasColor = _glyphRuns[0].glyphFace->hasColor()](const GlyphRun& glyphRun) { + return !glyphRun.glyphs.empty() && glyphRun.glyphs.size() == glyphRun.positions.size() && + glyphRun.glyphFace != nullptr && glyphRun.glyphFace->hasColor() == hasColor; + })); } Rect GlyphRunList::getBounds(float resolutionScale) const { diff --git a/src/core/TextBlob.cpp b/src/core/TextBlob.cpp index 8e6ca7c7..ad270914 100644 --- a/src/core/TextBlob.cpp +++ b/src/core/TextBlob.cpp @@ -54,7 +54,8 @@ std::shared_ptr TextBlob::MakeFrom(const GlyphID glyphIDs[], const Poi if (glyphCount == 0) { return nullptr; } - GlyphRun glyphRun(std::make_shared(font), {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); + GlyphRun glyphRun(std::make_shared(font), {glyphIDs, glyphIDs + glyphCount}, + {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); return std::shared_ptr(new TextBlob({glyphRunList})); } diff --git a/src/layers/contents/TextContent.h b/src/layers/contents/TextContent.h index 938c4fe8..f7167598 100644 --- a/src/layers/contents/TextContent.h +++ b/src/layers/contents/TextContent.h @@ -39,6 +39,6 @@ class TextContent : public LayerContent { Color textColor = Color::White(); static bool HitTestPointInternal(float localX, float localY, - const std::shared_ptr& glyphRunList); + const std::shared_ptr& glyphRunList); }; } // namespace tgfx diff --git a/test/src/CanvasTest.cpp b/test/src/CanvasTest.cpp index 36eb2f6f..91a0ad98 100644 --- a/test/src/CanvasTest.cpp +++ b/test/src/CanvasTest.cpp @@ -1226,8 +1226,7 @@ class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_this { +class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this { public: bool hasColor() const override { return true; From 4032de23fa41eaf700feb65e058d0882d6d73d79 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 12:22:31 +0800 Subject: [PATCH 04/17] Add glyph face tese --- test/src/CanvasTest.cpp | 135 ----------------- test/src/GlyphFaceTest.cpp | 296 +++++++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+), 135 deletions(-) create mode 100644 test/src/GlyphFaceTest.cpp diff --git a/test/src/CanvasTest.cpp b/test/src/CanvasTest.cpp index 91a0ad98..0f26af53 100644 --- a/test/src/CanvasTest.cpp +++ b/test/src/CanvasTest.cpp @@ -20,7 +20,6 @@ #include "core/images/ResourceImage.h" #include "core/images/SubsetImage.h" #include "core/images/TransformImage.h" -#include "core/utils/MathExtra.h" #include "gpu/DrawingManager.h" #include "gpu/Texture.h" #include "gpu/opengl/GLCaps.h" @@ -32,9 +31,7 @@ #include "tgfx/core/ImageCodec.h" #include "tgfx/core/ImageReader.h" #include "tgfx/core/Mask.h" -#include "tgfx/core/PathEffect.h" #include "tgfx/core/Recorder.h" -#include "tgfx/core/Stream.h" #include "tgfx/core/Surface.h" #include "tgfx/gpu/opengl/GLFunctions.h" #include "utils/TestUtils.h" @@ -1172,136 +1169,4 @@ TGFX_TEST(CanvasTest, Path_addArc) { EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/Path_addArc_reversed" + std::to_string(i))); } } - -class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_this { - public: - bool hasColor() const override { - return false; - } - bool hasOutlines() const override { - return false; - } - std::shared_ptr makeScaled(float scale) override { - _scale = scale; - return shared_from_this(); - } - - bool getPath(GlyphID glyphID, Path* path) const override { - switch (glyphID) { - case 1: - path->moveTo(25.0f, 5.0f); - path->lineTo(45.0f, 45.0f); - path->lineTo(5.0f, 45.0f); - path->close(); - return true; - case 2: - path->moveTo(5.0f, 5.0f); - path->lineTo(45.0f, 5.0f); - path->lineTo(45.0f, 45.0f); - path->lineTo(5.0f, 45.0f); - path->close(); - return true; - case 3: - path->addOval(Rect::MakeXYWH(5.0f, 5.0f, 40.0f, 40.0f)); - path->close(); - return true; - default: - return false; - } - return false; - } - - std::shared_ptr getImage(GlyphID /*glyphID*/, Matrix* /*matrix*/) const override { - return nullptr; - } - - Rect getBounds(GlyphID glyphID) const override { - if (glyphID < 1 || glyphID > 3) { - return Rect::MakeEmpty(); - } - return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); - } - - private: - float _scale = 1.0f; -}; - -class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this { - public: - bool hasColor() const override { - return true; - } - bool hasOutlines() const override { - return false; - } - std::shared_ptr makeScaled(float scale) override { - if (FloatNearlyZero(scale)) { - return nullptr; - } - _scale = scale; - return shared_from_this(); - } - - bool getPath(GlyphID /*glyphID*/, Path* /*path*/) const override { - return false; - } - - std::shared_ptr getImage(GlyphID glyphID, Matrix* matrix) const override { - std::string imagePath; - switch (glyphID) { - case 4: - imagePath = "resources/assets/image1.png"; - break; - case 5: - imagePath = "resources/assets/image2.png"; - break; - case 6: - imagePath = "resources/assets/image3.png"; - break; - default: - return nullptr; - } - - matrix->setScale(0.25f, 0.25f); - return Image::MakeFromFile(ProjectPath::Absolute(imagePath)); - ; - } - - Rect getBounds(GlyphID glyphID) const override { - if (glyphID < 3 || glyphID > 6) { - return Rect::MakeEmpty(); - } - return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); - } - - private: - float _scale = 1.0f; -}; - -TGFX_TEST(CanvasTest, GlyphFaceTest) { - ContextScope scope; - auto context = scope.getContext(); - ASSERT_TRUE(context != nullptr); - auto surface = Surface::Make(context, 400, 200); - auto canvas = surface->getCanvas(); - - auto paint = Paint(); - paint.setColor(Color::Red()); - - std::vector glyphIDs1 = {1, 2, 3}; - std::vector positions1 = {}; - positions1.push_back(Point::Make(0.0f, 0.0f)); - positions1.push_back(Point::Make(50.0f, 0.0f)); - positions1.push_back(Point::Make(100.0f, 0.0f)); - canvas->drawGlyphs(glyphIDs1, positions1, std::make_shared(), paint); - - std::vector glyphIDs2 = {4, 5, 6}; - std::vector positions2 = {}; - positions2.push_back(Point::Make(150.0f, 0.0f)); - positions2.push_back(Point::Make(205.0f, 0.0f)); - positions2.push_back(Point::Make(260.0f, 0.0f)); - canvas->drawGlyphs(glyphIDs2, positions2, std::make_shared(), paint); - - EXPECT_TRUE(Baseline::Compare(surface, "CanvasTest/GlyphFaceTest")); -} } // namespace tgfx diff --git a/test/src/GlyphFaceTest.cpp b/test/src/GlyphFaceTest.cpp new file mode 100644 index 00000000..678ed905 --- /dev/null +++ b/test/src/GlyphFaceTest.cpp @@ -0,0 +1,296 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#include "core/utils/MathExtra.h" +#include "tgfx/core/Canvas.h" +#include "utils/TestUtils.h" + +namespace tgfx { +class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_this { + public: + bool hasColor() const override { + return false; + } + bool hasOutlines() const override { + return false; + } + std::shared_ptr makeScaled(float scale) override { + _scale = scale; + return shared_from_this(); + } + + bool getPath(GlyphID glyphID, Path* path) const override { + switch (glyphID) { + case 1: + Point points[] = {{25.0f, 5.0f}, {45.0f, 45.0f}, {5.0f, 45.0f}}; + path->moveTo(25.0f, 5.0f); + path->lineTo(45.0f, 45.0f); + path->lineTo(5.0f, 45.0f); + path->close(); + return true; + case 2: + path->moveTo(5.0f, 5.0f); + path->lineTo(45.0f, 5.0f); + path->lineTo(45.0f, 45.0f); + path->lineTo(5.0f, 45.0f); + path->close(); + return true; + case 3: + path->addOval(Rect::MakeXYWH(5.0f, 5.0f, 40.0f, 40.0f)); + path->close(); + return true; + default: + return false; + } + } + + std::shared_ptr getImage(GlyphID /*glyphID*/, Matrix* /*matrix*/) const override { + return nullptr; + } + + Rect getBounds(GlyphID glyphID) const override { + if (glyphID < 1 || glyphID > 3) { + return Rect::MakeEmpty(); + } + return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + } + + private: + float _scale = 1.0f; +}; + +class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this { + public: + bool hasColor() const override { + return true; + } + bool hasOutlines() const override { + return false; + } + std::shared_ptr makeScaled(float scale) override { + if (FloatNearlyZero(scale)) { + return nullptr; + } + _scale = scale; + return shared_from_this(); + } + + bool getPath(GlyphID /*glyphID*/, Path* /*path*/) const override { + return false; + } + + std::shared_ptr getImage(GlyphID glyphID, Matrix* matrix) const override { + std::string imagePath; + switch (glyphID) { + case 4: + imagePath = "resources/assets/image1.png"; + break; + case 5: + imagePath = "resources/assets/image2.png"; + break; + case 6: + imagePath = "resources/assets/image3.png"; + break; + default: + return nullptr; + } + + matrix->setScale(0.25f, 0.25f); + return Image::MakeFromFile(ProjectPath::Absolute(imagePath)); + } + + Rect getBounds(GlyphID glyphID) const override { + if (glyphID < 3 || glyphID > 6) { + return Rect::MakeEmpty(); + } + return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + } + + private: + float _scale = 1.0f; +}; + +TGFX_TEST(GlyphFaceTest, GlyphFaceSimple) { + ContextScope scope; + auto context = scope.getContext(); + ASSERT_TRUE(context != nullptr); + auto surface = Surface::Make(context, 400, 200); + auto canvas = surface->getCanvas(); + + auto paint = Paint(); + paint.setColor(Color::Red()); + + std::vector glyphIDs1 = {1, 2, 3}; + std::vector positions1 = {}; + positions1.push_back(Point::Make(0.0f, 0.0f)); + positions1.push_back(Point::Make(50.0f, 0.0f)); + positions1.push_back(Point::Make(100.0f, 0.0f)); + canvas->drawGlyphs(glyphIDs1, positions1, std::make_shared(), paint); + + std::vector glyphIDs2 = {4, 5, 6}; + std::vector positions2 = {}; + positions2.push_back(Point::Make(150.0f, 0.0f)); + positions2.push_back(Point::Make(205.0f, 0.0f)); + positions2.push_back(Point::Make(260.0f, 0.0f)); + canvas->drawGlyphs(glyphIDs2, positions2, std::make_shared(), paint); + + EXPECT_TRUE(Baseline::Compare(surface, "GlyphFaceTest/GlyphFaceSimple")); +} + +auto typeface1 = MakeTypeface("resources/font/NotoSansSC-Regular.otf"); +Font font20(typeface1, 20); +Font font40(typeface1, 40); +Font font60(typeface1, 60); + +auto typeface2 = Typeface::MakeFromPath(ProjectPath::Absolute("resources/font/NotoColorEmoji.ttf")); +Font fontEmoji(typeface2, 50); + +class CustomPathGlyphFace2 : public GlyphFace, std::enable_shared_from_this { + public: + bool hasColor() const override { + return false; + } + bool hasOutlines() const override { + return false; + } + std::shared_ptr makeScaled(float scale) override { + _scale = scale; + return shared_from_this(); + } + + bool getPath(GlyphID glyphID, Path* path) const override { + if (glyphID == 8699 || glyphID == 16266) { + return font40.getPath(glyphID, path); + } + if (glyphID == 16671 || glyphID == 24458) { + return font60.getPath(glyphID, path); + } + return font20.getPath(glyphID, path); + } + + std::shared_ptr getImage(GlyphID /*glyphID*/, Matrix* /*matrix*/) const override { + return nullptr; + } + + Rect getBounds(GlyphID glyphID) const override { + if (glyphID == 8699 || glyphID == 16266) { + return font40.getBounds(glyphID); + } + if (glyphID == 16671 || glyphID == 24458) { + return font60.getBounds(glyphID); + } + return font20.getBounds(glyphID); + } + + private: + float _scale = 1.0f; +}; + +class CustomImageGlyphFace2 : public GlyphFace, + std::enable_shared_from_this { + public: + bool hasColor() const override { + return true; + } + bool hasOutlines() const override { + return false; + } + std::shared_ptr makeScaled(float scale) override { + if (FloatNearlyZero(scale)) { + return nullptr; + } + _scale = scale; + return shared_from_this(); + } + + bool getPath(GlyphID /*glyphID*/, Path* /*path*/) const override { + return false; + } + + std::shared_ptr getImage(GlyphID glyphID, Matrix* matrix) const override { + return fontEmoji.getImage(glyphID, matrix); + } + + Rect getBounds(GlyphID glyphID) const override { + return fontEmoji.getBounds(glyphID); + } + + private: + float _scale = 1.0f; +}; + +TGFX_TEST(GlyphFaceTest, GlyphFaceWithStyle) { + ContextScope scope; + auto context = scope.getContext(); + ASSERT_TRUE(context != nullptr); + auto surface = Surface::Make(context, 800, 200); + auto canvas = surface->getCanvas(); + ASSERT_TRUE(canvas != nullptr); + + // GlyphID:25483 14857 8699 16266 16671 24458 14689 15107 29702 41 70 77 77 80 29702 53 40 39 57 95 + // Text:这是一段测试文本,Hello,TGFX~ + auto glyphFace1 = std::make_shared(); + + auto paint = Paint(); + paint.setColor(Color::Red()); + std::vector glyphIDs1 = {25483, 14857}; + std::vector positions1 = {}; + positions1.push_back(Point::Make(0.0f, 100.0f)); + positions1.push_back(Point::Make(20.0f, 100.0f)); + canvas->drawGlyphs(glyphIDs1, positions1, glyphFace1, paint); + + paint.setColor(Color::Green()); + std::vector glyphIDs2 = {8699, 16266}; + std::vector positions2 = {}; + positions2.push_back(Point::Make(40.0f, 100.0f)); + positions2.push_back(Point::Make(80.0f, 100.0f)); + canvas->drawGlyphs(glyphIDs2, positions2, glyphFace1, paint); + + paint.setColor(Color::Blue()); + std::vector glyphIDs3 = {16671, 24458}; + std::vector positions3 = {}; + positions3.push_back(Point::Make(120.0f, 100.0f)); + positions3.push_back(Point::Make(180.0f, 100.0f)); + canvas->drawGlyphs(glyphIDs3, positions3, glyphFace1, paint); + + paint.setColor(Color::FromRGBA(255, 0, 255, 255)); + std::vector glyphIDs4 = {14689, 15107, 29702, 41, 70, 77, 77, + 80, 29702, 53, 40, 39, 57, 95}; + std::vector positions4 = {}; + float advance = 240.0f; + positions4.push_back(Point::Make(advance, 100.0f)); + for (size_t i = 1; i < glyphIDs4.size(); ++i) { + advance += font20.getAdvance(glyphIDs4[i - 1]); + positions4.push_back(Point::Make(advance, 100.0f)); + } + canvas->drawGlyphs(glyphIDs4, positions4, glyphFace1, paint); + + // 1109 886 1110 888 + // 🤩😃🤪😅 + std::vector emojiGlyphIDs = {1109, 886, 1110, 888}; + std::vector emojiPositions = {}; + emojiPositions.push_back(Point::Make(450.0f, 100.0f)); + emojiPositions.push_back(Point::Make(510.0f, 100.0f)); + emojiPositions.push_back(Point::Make(570.0f, 100.0f)); + emojiPositions.push_back(Point::Make(630.0f, 100.0f)); + canvas->drawGlyphs(emojiGlyphIDs, emojiPositions, std::make_shared(), + paint); + + EXPECT_TRUE(Baseline::Compare(surface, "GlyphFaceTest/GlyphFaceWithStyle")); +} +} // namespace tgfx From c2252203dcae47e4b45b0e4dacc39d82a2fbf665 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 14:39:11 +0800 Subject: [PATCH 05/17] Modify unit test cases. --- include/tgfx/core/FontGlyphFace.h | 2 + include/tgfx/core/GlyphFace.h | 5 ++ .../{FontWrapper.cpp => FontGlyphFace.cpp} | 4 + test/src/GlyphFaceTest.cpp | 76 +++++++++++++++---- 4 files changed, 71 insertions(+), 16 deletions(-) rename src/core/{FontWrapper.cpp => FontGlyphFace.cpp} (96%) diff --git a/include/tgfx/core/FontGlyphFace.h b/include/tgfx/core/FontGlyphFace.h index 267f92dc..7574cc61 100644 --- a/include/tgfx/core/FontGlyphFace.h +++ b/include/tgfx/core/FontGlyphFace.h @@ -38,6 +38,8 @@ class FontGlyphFace final : public GlyphFace { Rect getBounds(GlyphID glyphID) const override; + Font asFont() const override; + private: Font _font = {}; }; diff --git a/include/tgfx/core/GlyphFace.h b/include/tgfx/core/GlyphFace.h index 372c7462..73624d7e 100644 --- a/include/tgfx/core/GlyphFace.h +++ b/include/tgfx/core/GlyphFace.h @@ -64,5 +64,10 @@ class GlyphFace { * Returns the bounding box of the specified glyph. */ virtual Rect getBounds(GlyphID glyphID) const = 0; + + /** + * + */ + virtual Font asFont() const = 0; }; } // namespace tgfx diff --git a/src/core/FontWrapper.cpp b/src/core/FontGlyphFace.cpp similarity index 96% rename from src/core/FontWrapper.cpp rename to src/core/FontGlyphFace.cpp index c6781448..99f256ce 100644 --- a/src/core/FontWrapper.cpp +++ b/src/core/FontGlyphFace.cpp @@ -47,4 +47,8 @@ std::shared_ptr FontGlyphFace::getImage(GlyphID glyphID, Matrix* matrix) Rect FontGlyphFace::getBounds(GlyphID glyphID) const { return _font.getBounds(glyphID); } + +Font FontGlyphFace::asFont() const { + return _font; +} } // namespace tgfx \ No newline at end of file diff --git a/test/src/GlyphFaceTest.cpp b/test/src/GlyphFaceTest.cpp index 678ed905..8bcfc964 100644 --- a/test/src/GlyphFaceTest.cpp +++ b/test/src/GlyphFaceTest.cpp @@ -37,23 +37,25 @@ class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_thismoveTo(25.0f, 5.0f); - path->lineTo(45.0f, 45.0f); - path->lineTo(5.0f, 45.0f); + path->moveTo(Point::Make(25.0f, 5.0f) * _scale); + path->lineTo(Point::Make(45.0f, 45.0f) * _scale); + path->lineTo(Point::Make(5.0f, 45.0f) * _scale); path->close(); return true; case 2: - path->moveTo(5.0f, 5.0f); - path->lineTo(45.0f, 5.0f); - path->lineTo(45.0f, 45.0f); - path->lineTo(5.0f, 45.0f); + path->moveTo(Point::Make(5.0f, 5.0f) * _scale); + path->lineTo(Point::Make(45.0f, 5.0f) * _scale); + path->lineTo(Point::Make(45.0f, 45.0f) * _scale); + path->lineTo(Point::Make(5.0f, 45.0f) * _scale); path->close(); return true; - case 3: - path->addOval(Rect::MakeXYWH(5.0f, 5.0f, 40.0f, 40.0f)); + case 3: { + Rect rect = Rect::MakeXYWH(5.0f, 5.0f, 40.0f, 40.0f); + rect.scale(_scale, _scale); + path->addOval(rect); path->close(); return true; + } default: return false; } @@ -67,7 +69,13 @@ class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_this 3) { return Rect::MakeEmpty(); } - return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + Rect bounds = Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + bounds.scale(_scale, _scale); + return bounds; + } + + Font asFont() const override { + return Font(); } private: @@ -83,6 +91,7 @@ class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this makeScaled(float scale) override { + printf("CustomImageGlyphFace::makeScaled -> scale: %f\n", scale); if (FloatNearlyZero(scale)) { return nullptr; } @@ -110,7 +119,7 @@ class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_thissetScale(0.25f, 0.25f); + matrix->setScale(0.25f * _scale, 0.25f * _scale); return Image::MakeFromFile(ProjectPath::Absolute(imagePath)); } @@ -118,7 +127,13 @@ class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this 6) { return Rect::MakeEmpty(); } - return Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + Rect bounds = Rect::MakeXYWH(50 * (glyphID - 1), 0, 50, 50); + bounds.scale(_scale, _scale); + return bounds; + } + + Font asFont() const override { + return Font(); } private: @@ -135,6 +150,9 @@ TGFX_TEST(GlyphFaceTest, GlyphFaceSimple) { auto paint = Paint(); paint.setColor(Color::Red()); + float scaleFactor = 1.0f; + canvas->scale(scaleFactor, scaleFactor); + std::vector glyphIDs1 = {1, 2, 3}; std::vector positions1 = {}; positions1.push_back(Point::Make(0.0f, 0.0f)); @@ -169,7 +187,17 @@ class CustomPathGlyphFace2 : public GlyphFace, std::enable_shared_from_this makeScaled(float scale) override { - _scale = scale; + if (FloatNearlyZero(scale)) { + return nullptr; + } + + if (!FloatNearlyEqual(scale, _scale)) { + _scale = scale; + font20 = font20.makeWithSize(font20.getSize() * scale); + font40 = font40.makeWithSize(font40.getSize() * scale); + font60 = font60.makeWithSize(font60.getSize() * scale); + } + return shared_from_this(); } @@ -197,6 +225,10 @@ class CustomPathGlyphFace2 : public GlyphFace, std::enable_shared_from_this(); + float scaleFactor = 1.0f; + canvas->scale(scaleFactor, scaleFactor); + auto paint = Paint(); paint.setColor(Color::Red()); std::vector glyphIDs1 = {25483, 14857}; @@ -275,7 +319,7 @@ TGFX_TEST(GlyphFaceTest, GlyphFaceWithStyle) { float advance = 240.0f; positions4.push_back(Point::Make(advance, 100.0f)); for (size_t i = 1; i < glyphIDs4.size(); ++i) { - advance += font20.getAdvance(glyphIDs4[i - 1]); + advance += font20.getAdvance(glyphIDs4[i - 1]) / scaleFactor; positions4.push_back(Point::Make(advance, 100.0f)); } canvas->drawGlyphs(glyphIDs4, positions4, glyphFace1, paint); From fa332733200921a5b93c6d6cf275badded317bed Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 15:07:46 +0800 Subject: [PATCH 06/17] Add asFont method for GlyphFace class. --- include/tgfx/core/FontGlyphFace.h | 2 +- include/tgfx/core/GlyphFace.h | 4 ++-- src/core/FontGlyphFace.cpp | 4 ++-- test/src/GlyphFaceTest.cpp | 16 ++++++++-------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/tgfx/core/FontGlyphFace.h b/include/tgfx/core/FontGlyphFace.h index 7574cc61..67f16e24 100644 --- a/include/tgfx/core/FontGlyphFace.h +++ b/include/tgfx/core/FontGlyphFace.h @@ -38,7 +38,7 @@ class FontGlyphFace final : public GlyphFace { Rect getBounds(GlyphID glyphID) const override; - Font asFont() const override; + std::optional asFont() const override; private: Font _font = {}; diff --git a/include/tgfx/core/GlyphFace.h b/include/tgfx/core/GlyphFace.h index 73624d7e..0c332262 100644 --- a/include/tgfx/core/GlyphFace.h +++ b/include/tgfx/core/GlyphFace.h @@ -66,8 +66,8 @@ class GlyphFace { virtual Rect getBounds(GlyphID glyphID) const = 0; /** - * + * Returns the Font if this GlyphFace is a FontGlyphFace, otherwise returns std::nullopt. */ - virtual Font asFont() const = 0; + virtual std::optional asFont() const = 0; }; } // namespace tgfx diff --git a/src/core/FontGlyphFace.cpp b/src/core/FontGlyphFace.cpp index 99f256ce..d1d1adbb 100644 --- a/src/core/FontGlyphFace.cpp +++ b/src/core/FontGlyphFace.cpp @@ -48,7 +48,7 @@ Rect FontGlyphFace::getBounds(GlyphID glyphID) const { return _font.getBounds(glyphID); } -Font FontGlyphFace::asFont() const { - return _font; +std::optional FontGlyphFace::asFont() const { + return std::optional(_font); } } // namespace tgfx \ No newline at end of file diff --git a/test/src/GlyphFaceTest.cpp b/test/src/GlyphFaceTest.cpp index 8bcfc964..2d63bdf7 100644 --- a/test/src/GlyphFaceTest.cpp +++ b/test/src/GlyphFaceTest.cpp @@ -74,8 +74,8 @@ class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_this asFont() const override { + return std::nullopt; } private: @@ -132,8 +132,8 @@ class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this asFont() const override { + return std::nullopt; } private: @@ -225,8 +225,8 @@ class CustomPathGlyphFace2 : public GlyphFace, std::enable_shared_from_this asFont() const override { + return std::nullopt; } private: @@ -267,8 +267,8 @@ class CustomImageGlyphFace2 : public GlyphFace, return fontEmoji.getBounds(glyphID); } - Font asFont() const override { - return Font(); + std::optional asFont() const override { + return std::nullopt; } private: From bd287e5a274a971b56865f4aaa4878fe9ffd7561 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 15:13:29 +0800 Subject: [PATCH 07/17] Update version.json --- test/baseline/version.json | 4 ++++ test/src/GlyphFaceTest.cpp | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/baseline/version.json b/test/baseline/version.json index 2bf23db9..1d32da88 100644 --- a/test/baseline/version.json +++ b/test/baseline/version.json @@ -73,6 +73,10 @@ "innerShadow": "01cce38", "shaderMaskFilter": "ded3c91" }, + "GlyphFaceTest": { + "GlyphFaceSimple": "4032de2", + "GlyphFaceWithStyle": "4032de2" + }, "ImageReaderTest": { "update_bitmap": "d010fb8", "update_mask": "d010fb8" diff --git a/test/src/GlyphFaceTest.cpp b/test/src/GlyphFaceTest.cpp index 2d63bdf7..0021b97c 100644 --- a/test/src/GlyphFaceTest.cpp +++ b/test/src/GlyphFaceTest.cpp @@ -91,7 +91,6 @@ class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this makeScaled(float scale) override { - printf("CustomImageGlyphFace::makeScaled -> scale: %f\n", scale); if (FloatNearlyZero(scale)) { return nullptr; } From 9ed1938ef15e7759cb121859d63e672b4724a543 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 16:23:36 +0800 Subject: [PATCH 08/17] Fix compilation errors. --- include/tgfx/core/GlyphFace.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/tgfx/core/GlyphFace.h b/include/tgfx/core/GlyphFace.h index 0c332262..acd1cd37 100644 --- a/include/tgfx/core/GlyphFace.h +++ b/include/tgfx/core/GlyphFace.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include "tgfx/core/Image.h" #include "tgfx/core/Path.h" #include "tgfx/core/Typeface.h" From b36088b292aa109063d0fe53a7fad2a3309c1724 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 17:20:33 +0800 Subject: [PATCH 09/17] Fix ios compilation error> --- src/core/vectors/coregraphics/CGMask.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/core/vectors/coregraphics/CGMask.cpp b/src/core/vectors/coregraphics/CGMask.cpp index 0fa16210..263efa24 100644 --- a/src/core/vectors/coregraphics/CGMask.cpp +++ b/src/core/vectors/coregraphics/CGMask.cpp @@ -187,7 +187,13 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, return false; } for (auto& glyphRun : glyphRunList->glyphRuns()) { - auto& font = glyphRun.font; + auto glyphFace = glyphRun.glyphFace; + if (glyphFace == nullptr || glyphFace->asFont() == std::nullopt) { + continue; + } + + const auto& fontOptional = glyphFace->asFont(); + auto& font = fontOptional.value(); if (font.isFauxBold() || font.getTypeface() == nullptr) { return false; } @@ -209,8 +215,14 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, CGContextSetShouldSubpixelPositionFonts(cgContext, true); for (auto& glyphRun : glyphRunList->glyphRuns()) { + auto glyphFace = glyphRun.glyphFace; + if (glyphFace == nullptr || glyphFace->asFont() == std::nullopt) { + continue; + } + CGContextSaveGState(cgContext); - auto& font = glyphRun.font; + const auto& fontOptional = glyphFace->asFont(); + auto& font = fontOptional.value(); auto typeface = std::static_pointer_cast(font.getTypeface()); CTFontRef ctFont = typeface->getCTFont(); ctFont = CTFontCreateCopyWithAttributes(ctFont, static_cast(font.getSize()), nullptr, From cc2ddb2cb1720b75859dcc06388cfbb5fe850709 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 18:42:07 +0800 Subject: [PATCH 10/17] fix ios compilation error. --- src/core/vectors/coregraphics/CGMask.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/vectors/coregraphics/CGMask.cpp b/src/core/vectors/coregraphics/CGMask.cpp index 263efa24..8d5ce87e 100644 --- a/src/core/vectors/coregraphics/CGMask.cpp +++ b/src/core/vectors/coregraphics/CGMask.cpp @@ -21,6 +21,7 @@ #include "core/GlyphRunList.h" #include "core/ScalerContext.h" #include "platform/apple/BitmapContextUtil.h" +#include "tgfx/core/GlyphFace.h" #include "tgfx/core/Mask.h" #include "tgfx/core/Pixmap.h" From fcecbfbbfa27fd4f1dc1cb09b4deb774665a5c04 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Mon, 9 Dec 2024 19:10:25 +0800 Subject: [PATCH 11/17] fix ios compilation error. --- src/core/vectors/coregraphics/CGMask.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/core/vectors/coregraphics/CGMask.cpp b/src/core/vectors/coregraphics/CGMask.cpp index 8d5ce87e..557d768a 100644 --- a/src/core/vectors/coregraphics/CGMask.cpp +++ b/src/core/vectors/coregraphics/CGMask.cpp @@ -193,9 +193,8 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, continue; } - const auto& fontOptional = glyphFace->asFont(); - auto& font = fontOptional.value(); - if (font.isFauxBold() || font.getTypeface() == nullptr) { + const auto& font = glyphFace->asFont(); + if (font->isFauxBold() || font->getTypeface() == nullptr) { return false; } } @@ -222,13 +221,12 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, } CGContextSaveGState(cgContext); - const auto& fontOptional = glyphFace->asFont(); - auto& font = fontOptional.value(); - auto typeface = std::static_pointer_cast(font.getTypeface()); + const auto& font = glyphFace->asFont(); + auto typeface = std::static_pointer_cast(font->getTypeface()); CTFontRef ctFont = typeface->getCTFont(); - ctFont = CTFontCreateCopyWithAttributes(ctFont, static_cast(font.getSize()), nullptr, + ctFont = CTFontCreateCopyWithAttributes(ctFont, static_cast(font->getSize()), nullptr, nullptr); - if (font.isFauxItalic()) { + if (font->isFauxItalic()) { CGContextSetTextMatrix(cgContext, CGAffineTransformMake(1, 0, -ITALIC_SKEW, 1, 0, 0)); } CGContextTranslateCTM(cgContext, 0.f, static_cast(height())); From ea7f358ed537540a7302c70651d0e2a94b5a37ef Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Tue, 10 Dec 2024 13:14:08 +0800 Subject: [PATCH 12/17] Modify comment. --- drawers/src/layertree/CustomLayerTree.cpp | 4 +-- include/tgfx/core/Canvas.h | 14 ++++---- include/tgfx/core/GlyphFace.h | 11 +++--- include/tgfx/core/GlyphRun.h | 12 ++++--- resources/assets/{image1.png => glyph1.png} | 0 resources/assets/{image2.png => glyph2.png} | 0 resources/assets/{image3.png => glyph3.png} | 0 src/core/Canvas.cpp | 27 +++++--------- src/core/FontGlyphFace.cpp | 19 +++++++--- {include/tgfx => src}/core/FontGlyphFace.h | 8 +++-- src/core/GlyphRun.cpp | 31 ++++++++++++++++ src/core/GlyphRunList.cpp | 5 ++- src/core/GlyphRunList.h | 12 ++----- src/core/TextBlob.cpp | 33 +++++++++-------- src/core/vectors/coregraphics/CGMask.cpp | 28 +++++++-------- src/gpu/RenderContext.cpp | 4 +-- src/layers/TextLayer.cpp | 4 +-- test/src/GlyphFaceTest.cpp | 40 +++++++++++---------- 18 files changed, 139 insertions(+), 113 deletions(-) rename resources/assets/{image1.png => glyph1.png} (100%) rename resources/assets/{image2.png => glyph2.png} (100%) rename resources/assets/{image3.png => glyph3.png} (100%) rename {include/tgfx => src}/core/FontGlyphFace.h (93%) create mode 100644 src/core/GlyphRun.cpp diff --git a/drawers/src/layertree/CustomLayerTree.cpp b/drawers/src/layertree/CustomLayerTree.cpp index fce846f6..36182ff7 100644 --- a/drawers/src/layertree/CustomLayerTree.cpp +++ b/drawers/src/layertree/CustomLayerTree.cpp @@ -19,8 +19,8 @@ #include "CustomLayer.h" #include "base/LayerTreeDrawers.h" #include "drawers/AppHost.h" -#include "tgfx/core/FontGlyphFace.h" #include "tgfx/core/UTF.h" +#include "tgfx/core/GlyphRun.h" namespace drawers { @@ -67,7 +67,7 @@ std::unique_ptr CustomLayer::onUpdateContent() { xOffset += emptyAdvance; } } - tgfx::GlyphRun glyphRun(std::make_shared(_font), std::move(glyphs), + tgfx::GlyphRun glyphRun(_font, std::move(glyphs), std::move(positions)); auto textBlob = tgfx::TextBlob::MakeFrom(std::move(glyphRun)); if (textBlob == nullptr) { diff --git a/include/tgfx/core/Canvas.h b/include/tgfx/core/Canvas.h index e12f3109..b4a7c9c4 100644 --- a/include/tgfx/core/Canvas.h +++ b/include/tgfx/core/Canvas.h @@ -281,15 +281,15 @@ class Canvas { const Font& font, const Paint& paint); /** - * Draws an array of glyphIDs using GlyphFace, with paths and images provided by GlyphFace and - * positions specified by positions. - * @param glyphIDs The array of GlyphID to draw. + * Draws an array of glyphs from glyphIDs at positions using clip, matrix, glyphFace, and paint. + * @param glyphs The array of GlyphID to draw. * @param positions Where to draw each glyph. - * @param glyphFace Custom GlyphFace used for rendering glyphs. - * @param paint Blend, color, and so on, used to draw. - * @note The lengths of `glyphIDs` and `positions` must be the same. + * @param glyphCount number of glyphs to draw. + * @param glyphFace custom `GlyphFace` used for rendering glyphs. + * @param paint blend, color, and so on, used to draw. + * @note The lengths of `glyphs` and `positions` must be the same. */ - void drawGlyphs(const std::vector& glyphIDs, const std::vector& positions, + void drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, std::shared_ptr glyphFace, const Paint& paint) const; /** diff --git a/include/tgfx/core/GlyphFace.h b/include/tgfx/core/GlyphFace.h index acd1cd37..c1d4f60a 100644 --- a/include/tgfx/core/GlyphFace.h +++ b/include/tgfx/core/GlyphFace.h @@ -19,15 +19,14 @@ #pragma once #include -#include #include "tgfx/core/Image.h" #include "tgfx/core/Path.h" #include "tgfx/core/Typeface.h" namespace tgfx { /** -* GlyphFace is a provider for glyphs. It provides the glyph path, image, and bounds, etc. -*/ + * GlyphFace is a render-only font that contains only the necessary information to render glyphs. It can be implemented externally to render glyphs from a custom font or used as a wrapper around a Font object. + */ class GlyphFace { public: GlyphFace() = default; @@ -67,8 +66,10 @@ class GlyphFace { virtual Rect getBounds(GlyphID glyphID) const = 0; /** - * Returns the Font if this GlyphFace is a FontGlyphFace, otherwise returns std::nullopt. + * Returns the font object represented by this GlyphFace. + * If the GlyphFace is not a font object, returns false and sets the font pointer to null. + * If the GlyphFace is a font object, returns true and sets the font pointer to the font object. */ - virtual std::optional asFont() const = 0; + virtual bool asFont(Font* font) const = 0; }; } // namespace tgfx diff --git a/include/tgfx/core/GlyphRun.h b/include/tgfx/core/GlyphRun.h index e66e66d0..c3e194d1 100644 --- a/include/tgfx/core/GlyphRun.h +++ b/include/tgfx/core/GlyphRun.h @@ -25,19 +25,23 @@ namespace tgfx { /** * GlyphRun represents a sequence of glyphs from a single font, along with their positions. */ -struct GlyphRun { +class GlyphRun { +public: /** * Constructs an empty GlyphRun. */ GlyphRun() = default; + /** + * Constructs a GlyphRun using a font, a list of glyph IDs, and their positions. + */ + GlyphRun(Font font, std::vector glyphIDs, std::vector positions); + /** * Constructs a GlyphRun using a GlyphFace, a list of glyph IDs, and their positions. */ GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, - std::vector positions) - : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { - } + std::vector positions); /** * Returns the GlyphFace used to render the glyphs in this run. diff --git a/resources/assets/image1.png b/resources/assets/glyph1.png similarity index 100% rename from resources/assets/image1.png rename to resources/assets/glyph1.png diff --git a/resources/assets/image2.png b/resources/assets/glyph2.png similarity index 100% rename from resources/assets/image2.png rename to resources/assets/glyph2.png diff --git a/resources/assets/image3.png b/resources/assets/glyph3.png similarity index 100% rename from resources/assets/image3.png rename to resources/assets/glyph3.png diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index fa76ec29..2a2a1a03 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -21,7 +21,7 @@ #include "core/LayerUnrollContext.h" #include "core/utils/Log.h" #include "core/utils/Profiling.h" -#include "tgfx/core/FontGlyphFace.h" +#include "core/FontGlyphFace.h" #include "tgfx/core/Surface.h" namespace tgfx { @@ -329,31 +329,20 @@ void Canvas::drawSimpleText(const std::string& text, float x, float y, const Fon void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, const Font& font, const Paint& paint) { TRACE_EVENT; - if (glyphCount == 0 || paint.nothingToDraw()) { - return; - } - GlyphRun glyphRun(std::make_shared(font), {glyphs, glyphs + glyphCount}, - {positions, positions + glyphCount}); - auto glyphRunList = std::make_shared(std::move(glyphRun)); - auto style = CreateFillStyle(paint); - drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); + drawGlyphs(glyphs, positions, glyphCount, FontGlyphFace::Make(font), paint); } -void Canvas::drawGlyphs(const std::vector& glyphIDs, const std::vector& positions, - std::shared_ptr glyphFace, const Paint& paint) const { +void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, + std::shared_ptr glyphFace, const Paint& paint) const { TRACE_EVENT; - if (glyphIDs.empty() || positions.empty() || paint.nothingToDraw()) { - return; - } - - if (glyphIDs.size() != positions.size()) { - LOGE("Canvas::drawGlyphs() glyphs and positions size mismatch!"); + if (glyphCount == 0 || glyphFace == nullptr || paint.nothingToDraw()) { return; } - GlyphRun glyphRun(glyphFace, glyphIDs, positions); + GlyphRun glyphRun(glyphFace, {glyphs, glyphs + glyphCount}, + {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); - const auto style = CreateFillStyle(paint); + auto style = CreateFillStyle(paint); drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); } diff --git a/src/core/FontGlyphFace.cpp b/src/core/FontGlyphFace.cpp index d1d1adbb..142bbb64 100644 --- a/src/core/FontGlyphFace.cpp +++ b/src/core/FontGlyphFace.cpp @@ -16,10 +16,17 @@ // ///////////////////////////////////////////////////////////////////////////////////////////////// -#include "tgfx/core/FontGlyphFace.h" +#include "core/FontGlyphFace.h" #include "utils/MathExtra.h" namespace tgfx { +std::shared_ptr FontGlyphFace::Make(const Font& font) { + if (font.getTypeface() == nullptr) { + return nullptr; + } + return std::shared_ptr(new FontGlyphFace(font)); +} + bool FontGlyphFace::hasColor() const { return _font.hasColor(); } @@ -33,7 +40,7 @@ std::shared_ptr FontGlyphFace::makeScaled(float scale) { return nullptr; } auto size = _font.getSize() * scale; - return std::make_shared(_font.makeWithSize(size)); + return FontGlyphFace::Make(_font.makeWithSize(size)); } bool FontGlyphFace::getPath(GlyphID glyphID, Path* path) const { @@ -48,7 +55,11 @@ Rect FontGlyphFace::getBounds(GlyphID glyphID) const { return _font.getBounds(glyphID); } -std::optional FontGlyphFace::asFont() const { - return std::optional(_font); +bool FontGlyphFace::asFont(Font* font) const { + if (font == nullptr) { + return false; + } + *font = _font; + return true; } } // namespace tgfx \ No newline at end of file diff --git a/include/tgfx/core/FontGlyphFace.h b/src/core/FontGlyphFace.h similarity index 93% rename from include/tgfx/core/FontGlyphFace.h rename to src/core/FontGlyphFace.h index 67f16e24..db751846 100644 --- a/include/tgfx/core/FontGlyphFace.h +++ b/src/core/FontGlyphFace.h @@ -23,8 +23,7 @@ namespace tgfx { class FontGlyphFace final : public GlyphFace { public: - explicit FontGlyphFace(const Font& font) : _font(font) { - } + static std::shared_ptr Make(const Font& font); bool hasColor() const override; @@ -38,9 +37,12 @@ class FontGlyphFace final : public GlyphFace { Rect getBounds(GlyphID glyphID) const override; - std::optional asFont() const override; + bool asFont(Font* font) const override; private: + explicit FontGlyphFace(const Font& font) : _font(font) { + } + Font _font = {}; }; } // namespace tgfx diff --git a/src/core/GlyphRun.cpp b/src/core/GlyphRun.cpp new file mode 100644 index 00000000..53c1522f --- /dev/null +++ b/src/core/GlyphRun.cpp @@ -0,0 +1,31 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making tgfx available. +// +// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// https://opensource.org/licenses/BSD-3-Clause +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// +#include "tgfx/core/GlyphRun.h" +#include "core/FontGlyphFace.h" + +namespace tgfx { +GlyphRun::GlyphRun(Font font, std::vector glyphIDs, std::vector positions) + : GlyphRun(FontGlyphFace::Make(font), glyphIDs, positions) { + } + +GlyphRun::GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, + std::vector positions) + : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { + } + +} // namespace tgfx \ No newline at end of file diff --git a/src/core/GlyphRunList.cpp b/src/core/GlyphRunList.cpp index d5c54e6c..b470f6b6 100644 --- a/src/core/GlyphRunList.cpp +++ b/src/core/GlyphRunList.cpp @@ -61,6 +61,7 @@ Rect GlyphRunList::getBounds(float resolutionScale) const { if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. glyphFace = glyphFace->makeScaled(resolutionScale); + DEBUG_ASSERT(glyphFace != nullptr); } size_t index = 0; auto& positions = run.positions; @@ -86,12 +87,10 @@ bool GlyphRunList::getPath(Path* path, float resolutionScale) const { Path totalPath = {}; for (auto& run : _glyphRuns) { auto glyphFace = run.glyphFace; - if (glyphFace == nullptr) { - continue; - } if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. glyphFace = glyphFace->makeScaled(resolutionScale); + DEBUG_ASSERT(glyphFace != nullptr); } size_t index = 0; auto& positions = run.positions; diff --git a/src/core/GlyphRunList.h b/src/core/GlyphRunList.h index cafad6e8..006ee5d6 100644 --- a/src/core/GlyphRunList.h +++ b/src/core/GlyphRunList.h @@ -51,22 +51,14 @@ class GlyphRunList { * Returns true if the GlyphRunList has color. */ bool hasColor() const { - if (_glyphRuns.empty()) { - return false; - } - const auto& glyphFace = _glyphRuns[0].glyphFace; - return glyphFace ? glyphFace->hasColor() : false; + return _glyphRuns[0].glyphFace->hasColor(); } /** * Returns true if the GlyphRunList has outlines. */ bool hasOutlines() const { - if (_glyphRuns.empty()) { - return false; - } - const auto& glyphFace = _glyphRuns[0].glyphFace; - return glyphFace ? glyphFace->hasOutlines() : false; + return _glyphRuns[0].glyphFace->hasOutlines(); } /** diff --git a/src/core/TextBlob.cpp b/src/core/TextBlob.cpp index ad270914..f02f15fb 100644 --- a/src/core/TextBlob.cpp +++ b/src/core/TextBlob.cpp @@ -18,15 +18,14 @@ #include "tgfx/core/TextBlob.h" #include "core/GlyphRunList.h" -#include "tgfx/core/FontGlyphFace.h" +#include "core/FontGlyphFace.h" #include "tgfx/core/UTF.h" namespace tgfx { std::shared_ptr TextBlob::MakeFrom(const std::string& text, const Font& font) { const char* textStart = text.data(); const char* textStop = textStart + text.size(); - GlyphRun glyphRun = {}; - glyphRun.glyphFace = std::make_shared(font); + GlyphRun glyphRun = GlyphRun(font, {}, {}); // Use half the font size as width for spaces auto emptyAdvance = font.getSize() / 2.0f; float xOffset = 0; @@ -54,7 +53,7 @@ std::shared_ptr TextBlob::MakeFrom(const GlyphID glyphIDs[], const Poi if (glyphCount == 0) { return nullptr; } - GlyphRun glyphRun(std::make_shared(font), {glyphIDs, glyphIDs + glyphCount}, + GlyphRun glyphRun(font, {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); return std::shared_ptr(new TextBlob({glyphRunList})); @@ -71,21 +70,21 @@ std::shared_ptr TextBlob::MakeFrom(GlyphRun glyphRun) { return std::shared_ptr(new TextBlob({glyphRunList})); } -enum class FontType { Path, Color, Other }; +enum class GlyphFaceType { Path, Color, Other }; -static FontType GetFontType(const std::shared_ptr& font) { - if (font == nullptr) { - return FontType::Other; +static GlyphFaceType GetGlyphFaceType(const std::shared_ptr& glyphFace) { + if (glyphFace == nullptr) { + return GlyphFaceType::Other; } - if (font->hasColor()) { - return FontType::Color; + if (glyphFace->hasColor()) { + return GlyphFaceType::Color; } - if (font->hasOutlines()) { - return FontType::Path; + if (glyphFace->hasOutlines()) { + return GlyphFaceType::Path; } - return FontType::Other; + return GlyphFaceType::Other; } std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { @@ -97,7 +96,7 @@ std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { } std::vector> runLists; std::vector currentRuns; - FontType fontType = GetFontType(glyphRuns[0].glyphFace); + GlyphFaceType glyphFaceType = GetGlyphFaceType(glyphRuns[0].glyphFace); for (auto& run : glyphRuns) { if (run.glyphs.size() != run.positions.size()) { return nullptr; @@ -105,13 +104,13 @@ std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { if (run.glyphs.empty()) { continue; } - auto currentFontType = GetFontType(run.glyphFace); - if (currentFontType != fontType) { + auto currentFontType = GetGlyphFaceType(run.glyphFace); + if (currentFontType != glyphFaceType) { if (!currentRuns.empty()) { runLists.push_back(std::make_shared(std::move(currentRuns))); currentRuns = {}; } - fontType = currentFontType; + glyphFaceType = currentFontType; } currentRuns.push_back(std::move(run)); } diff --git a/src/core/vectors/coregraphics/CGMask.cpp b/src/core/vectors/coregraphics/CGMask.cpp index 557d768a..06ea04ce 100644 --- a/src/core/vectors/coregraphics/CGMask.cpp +++ b/src/core/vectors/coregraphics/CGMask.cpp @@ -20,6 +20,7 @@ #include "CGTypeface.h" #include "core/GlyphRunList.h" #include "core/ScalerContext.h" +#include "core/utils/Log.h" #include "platform/apple/BitmapContextUtil.h" #include "tgfx/core/GlyphFace.h" #include "tgfx/core/Mask.h" @@ -188,13 +189,9 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, return false; } for (auto& glyphRun : glyphRunList->glyphRuns()) { - auto glyphFace = glyphRun.glyphFace; - if (glyphFace == nullptr || glyphFace->asFont() == std::nullopt) { - continue; - } - - const auto& font = glyphFace->asFont(); - if (font->isFauxBold() || font->getTypeface() == nullptr) { + Font font; + bool success = glyphRun.glyphFace->asFont(&font); + if (!success || font.isFauxBold() || font.getTypeface() == nullptr) { return false; } } @@ -215,18 +212,19 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, CGContextSetShouldSubpixelPositionFonts(cgContext, true); for (auto& glyphRun : glyphRunList->glyphRuns()) { - auto glyphFace = glyphRun.glyphFace; - if (glyphFace == nullptr || glyphFace->asFont() == std::nullopt) { + CGContextSaveGState(cgContext); + Font font; + bool success = glyphRun.glyphFace->asFont(&font); + if (!success) { + CGContextRestoreGState(cgContext); continue; } - - CGContextSaveGState(cgContext); - const auto& font = glyphFace->asFont(); - auto typeface = std::static_pointer_cast(font->getTypeface()); + DEBUG_ASSERT(font.getTypeface() != nullptr); + auto typeface = std::static_pointer_cast(font.getTypeface()); CTFontRef ctFont = typeface->getCTFont(); - ctFont = CTFontCreateCopyWithAttributes(ctFont, static_cast(font->getSize()), nullptr, + ctFont = CTFontCreateCopyWithAttributes(ctFont, static_cast(font.getSize()), nullptr, nullptr); - if (font->isFauxItalic()) { + if (font.isFauxItalic()) { CGContextSetTextMatrix(cgContext, CGAffineTransformMake(1, 0, -ITALIC_SKEW, 1, 0, 0)); } CGContextTranslateCTM(cgContext, 0.f, static_cast(height())); diff --git a/src/gpu/RenderContext.cpp b/src/gpu/RenderContext.cpp index 061d9b53..c8dd9f2f 100644 --- a/src/gpu/RenderContext.cpp +++ b/src/gpu/RenderContext.cpp @@ -265,10 +265,8 @@ void RenderContext::drawColorGlyphs(std::shared_ptr glyphRunList, viewMatrix.preScale(1.0f / scale, 1.0f / scale); for (auto& glyphRun : glyphRunList->glyphRuns()) { auto glyphFace = glyphRun.glyphFace; - if (glyphFace == nullptr) { - continue; - } glyphFace = glyphFace->makeScaled(scale); + DEBUG_ASSERT(glyphFace != nullptr); auto& glyphIDs = glyphRun.glyphs; auto glyphCount = glyphIDs.size(); auto& positions = glyphRun.positions; diff --git a/src/layers/TextLayer.cpp b/src/layers/TextLayer.cpp index 24ff4709..81825f4b 100644 --- a/src/layers/TextLayer.cpp +++ b/src/layers/TextLayer.cpp @@ -20,7 +20,7 @@ #include "core/utils/Log.h" #include "core/utils/Profiling.h" #include "layers/contents/TextContent.h" -#include "tgfx/core/FontGlyphFace.h" +#include "core/FontGlyphFace.h" #include "tgfx/core/UTF.h" namespace tgfx { @@ -423,7 +423,7 @@ void TextLayer::buildGlyphRunList(const std::vector>& if (glyphRunMap.find(typefaceID) == glyphRunMap.end()) { auto font = _font; font.setTypeface(typeface); - glyphRunMap[typefaceID] = GlyphRun(std::make_shared(font), {}, {}); + glyphRunMap[typefaceID] = GlyphRun(font, {}, {}); } auto& fontGlyphRun = glyphRunMap[typefaceID]; fontGlyphRun.glyphs.emplace_back(glyphInfo->getGlyphID()); diff --git a/test/src/GlyphFaceTest.cpp b/test/src/GlyphFaceTest.cpp index 0021b97c..98d49c67 100644 --- a/test/src/GlyphFaceTest.cpp +++ b/test/src/GlyphFaceTest.cpp @@ -74,8 +74,8 @@ class CustomPathGlyphFace : public GlyphFace, std::enable_shared_from_this asFont() const override { - return std::nullopt; + bool asFont(Font* /*font*/) const override { + return false; } private: @@ -106,13 +106,13 @@ class CustomImageGlyphFace : public GlyphFace, std::enable_shared_from_this asFont() const override { - return std::nullopt; + bool asFont(Font* /*font*/) const override { + return false; } private: @@ -157,14 +157,16 @@ TGFX_TEST(GlyphFaceTest, GlyphFaceSimple) { positions1.push_back(Point::Make(0.0f, 0.0f)); positions1.push_back(Point::Make(50.0f, 0.0f)); positions1.push_back(Point::Make(100.0f, 0.0f)); - canvas->drawGlyphs(glyphIDs1, positions1, std::make_shared(), paint); + canvas->drawGlyphs(glyphIDs1.data(), positions1.data(), glyphIDs1.size(), + std::make_shared(), paint); std::vector glyphIDs2 = {4, 5, 6}; std::vector positions2 = {}; positions2.push_back(Point::Make(150.0f, 0.0f)); positions2.push_back(Point::Make(205.0f, 0.0f)); positions2.push_back(Point::Make(260.0f, 0.0f)); - canvas->drawGlyphs(glyphIDs2, positions2, std::make_shared(), paint); + canvas->drawGlyphs(glyphIDs2.data(), positions2.data(), glyphIDs2.size(), + std::make_shared(), paint); EXPECT_TRUE(Baseline::Compare(surface, "GlyphFaceTest/GlyphFaceSimple")); } @@ -224,8 +226,8 @@ class CustomPathGlyphFace2 : public GlyphFace, std::enable_shared_from_this asFont() const override { - return std::nullopt; + bool asFont(Font* /*font*/) const override { + return false; } private: @@ -266,8 +268,8 @@ class CustomImageGlyphFace2 : public GlyphFace, return fontEmoji.getBounds(glyphID); } - std::optional asFont() const override { - return std::nullopt; + bool asFont(Font* /*font*/) const override { + return false; } private: @@ -295,21 +297,21 @@ TGFX_TEST(GlyphFaceTest, GlyphFaceWithStyle) { std::vector positions1 = {}; positions1.push_back(Point::Make(0.0f, 100.0f)); positions1.push_back(Point::Make(20.0f, 100.0f)); - canvas->drawGlyphs(glyphIDs1, positions1, glyphFace1, paint); + canvas->drawGlyphs(glyphIDs1.data(), positions1.data(), glyphIDs1.size(), glyphFace1, paint); paint.setColor(Color::Green()); std::vector glyphIDs2 = {8699, 16266}; std::vector positions2 = {}; positions2.push_back(Point::Make(40.0f, 100.0f)); positions2.push_back(Point::Make(80.0f, 100.0f)); - canvas->drawGlyphs(glyphIDs2, positions2, glyphFace1, paint); + canvas->drawGlyphs(glyphIDs2.data(), positions2.data(), glyphIDs2.size(), glyphFace1, paint); paint.setColor(Color::Blue()); std::vector glyphIDs3 = {16671, 24458}; std::vector positions3 = {}; positions3.push_back(Point::Make(120.0f, 100.0f)); positions3.push_back(Point::Make(180.0f, 100.0f)); - canvas->drawGlyphs(glyphIDs3, positions3, glyphFace1, paint); + canvas->drawGlyphs(glyphIDs3.data(), positions3.data(), glyphIDs3.size(), glyphFace1, paint); paint.setColor(Color::FromRGBA(255, 0, 255, 255)); std::vector glyphIDs4 = {14689, 15107, 29702, 41, 70, 77, 77, @@ -321,7 +323,7 @@ TGFX_TEST(GlyphFaceTest, GlyphFaceWithStyle) { advance += font20.getAdvance(glyphIDs4[i - 1]) / scaleFactor; positions4.push_back(Point::Make(advance, 100.0f)); } - canvas->drawGlyphs(glyphIDs4, positions4, glyphFace1, paint); + canvas->drawGlyphs(glyphIDs4.data(), positions4.data(), glyphIDs4.size(), glyphFace1, paint); // 1109 886 1110 888 // 🤩😃🤪😅 @@ -331,8 +333,8 @@ TGFX_TEST(GlyphFaceTest, GlyphFaceWithStyle) { emojiPositions.push_back(Point::Make(510.0f, 100.0f)); emojiPositions.push_back(Point::Make(570.0f, 100.0f)); emojiPositions.push_back(Point::Make(630.0f, 100.0f)); - canvas->drawGlyphs(emojiGlyphIDs, emojiPositions, std::make_shared(), - paint); + canvas->drawGlyphs(emojiGlyphIDs.data(), emojiPositions.data(), emojiGlyphIDs.size(), + std::make_shared(), paint); EXPECT_TRUE(Baseline::Compare(surface, "GlyphFaceTest/GlyphFaceWithStyle")); } From 797b3f34c2fa2ed5713178155ecf60da867c7a72 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Tue, 10 Dec 2024 13:15:04 +0800 Subject: [PATCH 13/17] format code. --- drawers/src/layertree/CustomLayerTree.cpp | 5 ++--- include/tgfx/core/GlyphRun.h | 2 +- src/core/Canvas.cpp | 7 +++---- src/core/GlyphRun.cpp | 6 +++--- src/core/TextBlob.cpp | 5 ++--- src/layers/TextLayer.cpp | 2 +- 6 files changed, 12 insertions(+), 15 deletions(-) diff --git a/drawers/src/layertree/CustomLayerTree.cpp b/drawers/src/layertree/CustomLayerTree.cpp index 36182ff7..1ffc8e91 100644 --- a/drawers/src/layertree/CustomLayerTree.cpp +++ b/drawers/src/layertree/CustomLayerTree.cpp @@ -19,8 +19,8 @@ #include "CustomLayer.h" #include "base/LayerTreeDrawers.h" #include "drawers/AppHost.h" -#include "tgfx/core/UTF.h" #include "tgfx/core/GlyphRun.h" +#include "tgfx/core/UTF.h" namespace drawers { @@ -67,8 +67,7 @@ std::unique_ptr CustomLayer::onUpdateContent() { xOffset += emptyAdvance; } } - tgfx::GlyphRun glyphRun(_font, std::move(glyphs), - std::move(positions)); + tgfx::GlyphRun glyphRun(_font, std::move(glyphs), std::move(positions)); auto textBlob = tgfx::TextBlob::MakeFrom(std::move(glyphRun)); if (textBlob == nullptr) { return nullptr; diff --git a/include/tgfx/core/GlyphRun.h b/include/tgfx/core/GlyphRun.h index c3e194d1..82ae47ae 100644 --- a/include/tgfx/core/GlyphRun.h +++ b/include/tgfx/core/GlyphRun.h @@ -26,7 +26,7 @@ namespace tgfx { * GlyphRun represents a sequence of glyphs from a single font, along with their positions. */ class GlyphRun { -public: + public: /** * Constructs an empty GlyphRun. */ diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index 2a2a1a03..68f5acec 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -18,10 +18,10 @@ #include "tgfx/core/Canvas.h" #include "core/DrawContext.h" +#include "core/FontGlyphFace.h" #include "core/LayerUnrollContext.h" #include "core/utils/Log.h" #include "core/utils/Profiling.h" -#include "core/FontGlyphFace.h" #include "tgfx/core/Surface.h" namespace tgfx { @@ -333,14 +333,13 @@ void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t } void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, - std::shared_ptr glyphFace, const Paint& paint) const { + std::shared_ptr glyphFace, const Paint& paint) const { TRACE_EVENT; if (glyphCount == 0 || glyphFace == nullptr || paint.nothingToDraw()) { return; } - GlyphRun glyphRun(glyphFace, {glyphs, glyphs + glyphCount}, - {positions, positions + glyphCount}); + GlyphRun glyphRun(glyphFace, {glyphs, glyphs + glyphCount}, {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); auto style = CreateFillStyle(paint); drawContext->drawGlyphRunList(std::move(glyphRunList), *mcState, style, paint.getStroke()); diff --git a/src/core/GlyphRun.cpp b/src/core/GlyphRun.cpp index 53c1522f..20d8b580 100644 --- a/src/core/GlyphRun.cpp +++ b/src/core/GlyphRun.cpp @@ -21,11 +21,11 @@ namespace tgfx { GlyphRun::GlyphRun(Font font, std::vector glyphIDs, std::vector positions) : GlyphRun(FontGlyphFace::Make(font), glyphIDs, positions) { - } +} GlyphRun::GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, - std::vector positions) + std::vector positions) : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { - } +} } // namespace tgfx \ No newline at end of file diff --git a/src/core/TextBlob.cpp b/src/core/TextBlob.cpp index f02f15fb..af825eaf 100644 --- a/src/core/TextBlob.cpp +++ b/src/core/TextBlob.cpp @@ -17,8 +17,8 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "tgfx/core/TextBlob.h" -#include "core/GlyphRunList.h" #include "core/FontGlyphFace.h" +#include "core/GlyphRunList.h" #include "tgfx/core/UTF.h" namespace tgfx { @@ -53,8 +53,7 @@ std::shared_ptr TextBlob::MakeFrom(const GlyphID glyphIDs[], const Poi if (glyphCount == 0) { return nullptr; } - GlyphRun glyphRun(font, {glyphIDs, glyphIDs + glyphCount}, - {positions, positions + glyphCount}); + GlyphRun glyphRun(font, {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); auto glyphRunList = std::make_shared(std::move(glyphRun)); return std::shared_ptr(new TextBlob({glyphRunList})); } diff --git a/src/layers/TextLayer.cpp b/src/layers/TextLayer.cpp index 81825f4b..c49540f8 100644 --- a/src/layers/TextLayer.cpp +++ b/src/layers/TextLayer.cpp @@ -17,10 +17,10 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "tgfx/layers/TextLayer.h" +#include "core/FontGlyphFace.h" #include "core/utils/Log.h" #include "core/utils/Profiling.h" #include "layers/contents/TextContent.h" -#include "core/FontGlyphFace.h" #include "tgfx/core/UTF.h" namespace tgfx { From 9333349f613c8ceb5379e0d1e0fcde47868a1595 Mon Sep 17 00:00:00 2001 From: shlzxjp Date: Tue, 10 Dec 2024 15:11:06 +0800 Subject: [PATCH 14/17] Modify comment. --- include/tgfx/core/GlyphFace.h | 19 +++++++++------ include/tgfx/core/GlyphRun.h | 11 ++++++--- src/core/Canvas.cpp | 2 +- src/core/FontGlyphFace.cpp | 4 +-- src/core/FontGlyphFace.h | 4 +-- src/core/GlyphRun.cpp | 31 ------------------------ src/core/GlyphRunList.cpp | 4 --- src/core/TextBlob.cpp | 12 ++++++++- src/core/vectors/coregraphics/CGMask.cpp | 9 ++----- 9 files changed, 37 insertions(+), 59 deletions(-) delete mode 100644 src/core/GlyphRun.cpp diff --git a/include/tgfx/core/GlyphFace.h b/include/tgfx/core/GlyphFace.h index c1d4f60a..7d07b830 100644 --- a/include/tgfx/core/GlyphFace.h +++ b/include/tgfx/core/GlyphFace.h @@ -25,25 +25,30 @@ namespace tgfx { /** - * GlyphFace is a render-only font that contains only the necessary information to render glyphs. It can be implemented externally to render glyphs from a custom font or used as a wrapper around a Font object. + * GlyphFace is a render-only font that contains only the necessary information to render glyphs. + * It can be implemented externally to render glyphs from a custom font or used as a wrapper + * around a Font object. */ class GlyphFace { public: + static std::shared_ptr Wrap(const Font& font); + GlyphFace() = default; virtual ~GlyphFace() = default; /** - * Returns true if the font has color glyphs, for example, color emojis. + * Returns true if the glyph face has color glyphs, for example, color emojis. */ virtual bool hasColor() const = 0; /** - * Returns true if the font has outline glyphs, meaning it can generate paths. + * Returns true if the glyph face has outline glyphs, meaning it can generate paths. */ virtual bool hasOutlines() const = 0; /** - * Returns a new GlyphFace with the same attributes of this font, but with the specified scale. + * Returns a new GlyphFace with the same attributes of this glyph face, but with the specified + * scale. */ virtual std::shared_ptr makeScaled(float scale) = 0; @@ -66,9 +71,9 @@ class GlyphFace { virtual Rect getBounds(GlyphID glyphID) const = 0; /** - * Returns the font object represented by this GlyphFace. - * If the GlyphFace is not a font object, returns false and sets the font pointer to null. - * If the GlyphFace is a font object, returns true and sets the font pointer to the font object. + * Checks if the GlyphFace is backed by a Font object. + * If so, sets the font pointer to the backing Font object and returns true. + * Otherwise, returns false and leaves the font pointer unchanged. */ virtual bool asFont(Font* font) const = 0; }; diff --git a/include/tgfx/core/GlyphRun.h b/include/tgfx/core/GlyphRun.h index 82ae47ae..1aaaa790 100644 --- a/include/tgfx/core/GlyphRun.h +++ b/include/tgfx/core/GlyphRun.h @@ -25,8 +25,7 @@ namespace tgfx { /** * GlyphRun represents a sequence of glyphs from a single font, along with their positions. */ -class GlyphRun { - public: +struct GlyphRun { /** * Constructs an empty GlyphRun. */ @@ -35,13 +34,17 @@ class GlyphRun { /** * Constructs a GlyphRun using a font, a list of glyph IDs, and their positions. */ - GlyphRun(Font font, std::vector glyphIDs, std::vector positions); + GlyphRun(Font font, std::vector glyphIDs, std::vector positions) + : GlyphRun(GlyphFace::Wrap(font), glyphIDs, positions) { + } /** * Constructs a GlyphRun using a GlyphFace, a list of glyph IDs, and their positions. */ GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, - std::vector positions); + std::vector positions) + : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { + } /** * Returns the GlyphFace used to render the glyphs in this run. diff --git a/src/core/Canvas.cpp b/src/core/Canvas.cpp index 68f5acec..7e39666b 100644 --- a/src/core/Canvas.cpp +++ b/src/core/Canvas.cpp @@ -329,7 +329,7 @@ void Canvas::drawSimpleText(const std::string& text, float x, float y, const Fon void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, const Font& font, const Paint& paint) { TRACE_EVENT; - drawGlyphs(glyphs, positions, glyphCount, FontGlyphFace::Make(font), paint); + drawGlyphs(glyphs, positions, glyphCount, GlyphFace::Wrap(font), paint); } void Canvas::drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, diff --git a/src/core/FontGlyphFace.cpp b/src/core/FontGlyphFace.cpp index 142bbb64..2ffae743 100644 --- a/src/core/FontGlyphFace.cpp +++ b/src/core/FontGlyphFace.cpp @@ -20,7 +20,7 @@ #include "utils/MathExtra.h" namespace tgfx { -std::shared_ptr FontGlyphFace::Make(const Font& font) { +std::shared_ptr GlyphFace::Wrap(const Font& font) { if (font.getTypeface() == nullptr) { return nullptr; } @@ -40,7 +40,7 @@ std::shared_ptr FontGlyphFace::makeScaled(float scale) { return nullptr; } auto size = _font.getSize() * scale; - return FontGlyphFace::Make(_font.makeWithSize(size)); + return GlyphFace::Wrap(_font.makeWithSize(size)); } bool FontGlyphFace::getPath(GlyphID glyphID, Path* path) const { diff --git a/src/core/FontGlyphFace.h b/src/core/FontGlyphFace.h index db751846..d16e7c74 100644 --- a/src/core/FontGlyphFace.h +++ b/src/core/FontGlyphFace.h @@ -23,8 +23,6 @@ namespace tgfx { class FontGlyphFace final : public GlyphFace { public: - static std::shared_ptr Make(const Font& font); - bool hasColor() const override; bool hasOutlines() const override; @@ -44,5 +42,7 @@ class FontGlyphFace final : public GlyphFace { } Font _font = {}; + + friend class GlyphFace; }; } // namespace tgfx diff --git a/src/core/GlyphRun.cpp b/src/core/GlyphRun.cpp deleted file mode 100644 index 20d8b580..00000000 --- a/src/core/GlyphRun.cpp +++ /dev/null @@ -1,31 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////////////////////// -// -// Tencent is pleased to support the open source community by making tgfx available. -// -// Copyright (C) 2024 THL A29 Limited, a Tencent company. All rights reserved. -// -// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except -// in compliance with the License. You may obtain a copy of the License at -// -// https://opensource.org/licenses/BSD-3-Clause -// -// unless required by applicable law or agreed to in writing, software distributed under the -// license is distributed on an "as is" basis, without warranties or conditions of any kind, -// either express or implied. see the license for the specific language governing permissions -// and limitations under the license. -// -///////////////////////////////////////////////////////////////////////////////////////////////// -#include "tgfx/core/GlyphRun.h" -#include "core/FontGlyphFace.h" - -namespace tgfx { -GlyphRun::GlyphRun(Font font, std::vector glyphIDs, std::vector positions) - : GlyphRun(FontGlyphFace::Make(font), glyphIDs, positions) { -} - -GlyphRun::GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, - std::vector positions) - : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { -} - -} // namespace tgfx \ No newline at end of file diff --git a/src/core/GlyphRunList.cpp b/src/core/GlyphRunList.cpp index b470f6b6..c9477d5b 100644 --- a/src/core/GlyphRunList.cpp +++ b/src/core/GlyphRunList.cpp @@ -38,7 +38,6 @@ GlyphRunList::GlyphRunList(GlyphRun glyphRun) { GlyphRunList::GlyphRunList(std::vector glyphRuns) : _glyphRuns(std::move(glyphRuns)) { DEBUG_ASSERT(!_glyphRuns.empty()); - DEBUG_ASSERT(_glyphRuns[0].glyphFace != nullptr); DEBUG_ASSERT(std::all_of( _glyphRuns.begin(), _glyphRuns.end(), [hasColor = _glyphRuns[0].glyphFace->hasColor()](const GlyphRun& glyphRun) { @@ -55,9 +54,6 @@ Rect GlyphRunList::getBounds(float resolutionScale) const { auto totalBounds = Rect::MakeEmpty(); for (auto& run : _glyphRuns) { auto glyphFace = run.glyphFace; - if (glyphFace == nullptr) { - continue; - } if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. glyphFace = glyphFace->makeScaled(resolutionScale); diff --git a/src/core/TextBlob.cpp b/src/core/TextBlob.cpp index af825eaf..c9615d65 100644 --- a/src/core/TextBlob.cpp +++ b/src/core/TextBlob.cpp @@ -23,6 +23,10 @@ namespace tgfx { std::shared_ptr TextBlob::MakeFrom(const std::string& text, const Font& font) { + if (font.getTypeface() == nullptr) { + return nullptr; + } + const char* textStart = text.data(); const char* textStop = textStart + text.size(); GlyphRun glyphRun = GlyphRun(font, {}, {}); @@ -50,7 +54,7 @@ std::shared_ptr TextBlob::MakeFrom(const std::string& text, const Font std::shared_ptr TextBlob::MakeFrom(const GlyphID glyphIDs[], const Point positions[], size_t glyphCount, const Font& font) { - if (glyphCount == 0) { + if (glyphCount == 0 || font.getTypeface() == nullptr) { return nullptr; } GlyphRun glyphRun(font, {glyphIDs, glyphIDs + glyphCount}, {positions, positions + glyphCount}); @@ -65,6 +69,9 @@ std::shared_ptr TextBlob::MakeFrom(GlyphRun glyphRun) { if (glyphRun.glyphs.empty()) { return nullptr; } + if (glyphRun.glyphFace == nullptr) { + return nullptr; + } auto glyphRunList = std::make_shared(std::move(glyphRun)); return std::shared_ptr(new TextBlob({glyphRunList})); } @@ -100,6 +107,9 @@ std::shared_ptr TextBlob::MakeFrom(std::vector glyphRuns) { if (run.glyphs.size() != run.positions.size()) { return nullptr; } + if (run.glyphFace == nullptr) { + return nullptr; + } if (run.glyphs.empty()) { continue; } diff --git a/src/core/vectors/coregraphics/CGMask.cpp b/src/core/vectors/coregraphics/CGMask.cpp index 06ea04ce..79827ad7 100644 --- a/src/core/vectors/coregraphics/CGMask.cpp +++ b/src/core/vectors/coregraphics/CGMask.cpp @@ -191,7 +191,7 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, for (auto& glyphRun : glyphRunList->glyphRuns()) { Font font; bool success = glyphRun.glyphFace->asFont(&font); - if (!success || font.isFauxBold() || font.getTypeface() == nullptr) { + if (!success || font.isFauxBold()) { return false; } } @@ -214,12 +214,7 @@ bool CGMask::onFillText(const GlyphRunList* glyphRunList, const Stroke* stroke, for (auto& glyphRun : glyphRunList->glyphRuns()) { CGContextSaveGState(cgContext); Font font; - bool success = glyphRun.glyphFace->asFont(&font); - if (!success) { - CGContextRestoreGState(cgContext); - continue; - } - DEBUG_ASSERT(font.getTypeface() != nullptr); + glyphRun.glyphFace->asFont(&font); auto typeface = std::static_pointer_cast(font.getTypeface()); CTFontRef ctFont = typeface->getCTFont(); ctFont = CTFontCreateCopyWithAttributes(ctFont, static_cast(font.getSize()), nullptr, From 413e3d8253e4749b41bee5a05f412ae8ee27e236 Mon Sep 17 00:00:00 2001 From: domrjchen Date: Tue, 10 Dec 2024 16:50:11 +0800 Subject: [PATCH 15/17] Update some comments. --- drawers/src/layertree/CustomLayerTree.cpp | 1 - include/tgfx/core/Canvas.h | 14 +++++++------- include/tgfx/core/GlyphFace.h | 6 +++--- include/tgfx/core/GlyphRun.h | 5 +++-- src/core/FontGlyphFace.cpp | 4 ++-- src/core/FontGlyphFace.h | 2 +- src/core/GlyphRunList.cpp | 9 +++++++-- src/gpu/RenderContext.cpp | 3 +++ 8 files changed, 26 insertions(+), 18 deletions(-) diff --git a/drawers/src/layertree/CustomLayerTree.cpp b/drawers/src/layertree/CustomLayerTree.cpp index 1ffc8e91..6a3dc37e 100644 --- a/drawers/src/layertree/CustomLayerTree.cpp +++ b/drawers/src/layertree/CustomLayerTree.cpp @@ -19,7 +19,6 @@ #include "CustomLayer.h" #include "base/LayerTreeDrawers.h" #include "drawers/AppHost.h" -#include "tgfx/core/GlyphRun.h" #include "tgfx/core/UTF.h" namespace drawers { diff --git a/include/tgfx/core/Canvas.h b/include/tgfx/core/Canvas.h index b4a7c9c4..4eb5212b 100644 --- a/include/tgfx/core/Canvas.h +++ b/include/tgfx/core/Canvas.h @@ -281,13 +281,13 @@ class Canvas { const Font& font, const Paint& paint); /** - * Draws an array of glyphs from glyphIDs at positions using clip, matrix, glyphFace, and paint. - * @param glyphs The array of GlyphID to draw. - * @param positions Where to draw each glyph. - * @param glyphCount number of glyphs to draw. - * @param glyphFace custom `GlyphFace` used for rendering glyphs. - * @param paint blend, color, and so on, used to draw. - * @note The lengths of `glyphs` and `positions` must be the same. + * Draws an array of glyphs at specified positions using the current clip, matrix, glyphFace, and + * paint. + * @param glyphs The array of GlyphIDs to draw. + * @param positions The positions to draw each glyph. + * @param glyphCount The number of glyphs to draw. + * @param glyphFace The custom GlyphFace used for rendering glyphs. + * @param paint The paint used for blending, coloring, etc. */ void drawGlyphs(const GlyphID glyphs[], const Point positions[], size_t glyphCount, std::shared_ptr glyphFace, const Paint& paint) const; diff --git a/include/tgfx/core/GlyphFace.h b/include/tgfx/core/GlyphFace.h index 7d07b830..14d5e729 100644 --- a/include/tgfx/core/GlyphFace.h +++ b/include/tgfx/core/GlyphFace.h @@ -31,7 +31,7 @@ namespace tgfx { */ class GlyphFace { public: - static std::shared_ptr Wrap(const Font& font); + static std::shared_ptr Wrap(Font font); GlyphFace() = default; virtual ~GlyphFace() = default; @@ -47,8 +47,8 @@ class GlyphFace { virtual bool hasOutlines() const = 0; /** - * Returns a new GlyphFace with the same attributes of this glyph face, but with the specified - * scale. + * Returns a new GlyphFace with the same attributes as this one, but with the glyph size scaled by + * the specified factor. If the scale is less than or equal to 0, returns nullptr. */ virtual std::shared_ptr makeScaled(float scale) = 0; diff --git a/include/tgfx/core/GlyphRun.h b/include/tgfx/core/GlyphRun.h index 1aaaa790..423ff18f 100644 --- a/include/tgfx/core/GlyphRun.h +++ b/include/tgfx/core/GlyphRun.h @@ -35,7 +35,7 @@ struct GlyphRun { * Constructs a GlyphRun using a font, a list of glyph IDs, and their positions. */ GlyphRun(Font font, std::vector glyphIDs, std::vector positions) - : GlyphRun(GlyphFace::Wrap(font), glyphIDs, positions) { + : GlyphRun(GlyphFace::Wrap(std::move(font)), std::move(glyphIDs), std::move(positions)) { } /** @@ -43,7 +43,8 @@ struct GlyphRun { */ GlyphRun(std::shared_ptr glyphFace, std::vector glyphIDs, std::vector positions) - : glyphFace(glyphFace), glyphs(glyphIDs), positions(positions) { + : glyphFace(std::move(glyphFace)), glyphs(std::move(glyphIDs)), + positions(std::move(positions)) { } /** diff --git a/src/core/FontGlyphFace.cpp b/src/core/FontGlyphFace.cpp index 2ffae743..e71991c7 100644 --- a/src/core/FontGlyphFace.cpp +++ b/src/core/FontGlyphFace.cpp @@ -20,11 +20,11 @@ #include "utils/MathExtra.h" namespace tgfx { -std::shared_ptr GlyphFace::Wrap(const Font& font) { +std::shared_ptr GlyphFace::Wrap(Font font) { if (font.getTypeface() == nullptr) { return nullptr; } - return std::shared_ptr(new FontGlyphFace(font)); + return std::shared_ptr(new FontGlyphFace(std::move(font))); } bool FontGlyphFace::hasColor() const { diff --git a/src/core/FontGlyphFace.h b/src/core/FontGlyphFace.h index d16e7c74..4eb90d8a 100644 --- a/src/core/FontGlyphFace.h +++ b/src/core/FontGlyphFace.h @@ -38,7 +38,7 @@ class FontGlyphFace final : public GlyphFace { bool asFont(Font* font) const override; private: - explicit FontGlyphFace(const Font& font) : _font(font) { + explicit FontGlyphFace(Font font) : _font(std::move(font)) { } Font _font = {}; diff --git a/src/core/GlyphRunList.cpp b/src/core/GlyphRunList.cpp index c9477d5b..847ed3a9 100644 --- a/src/core/GlyphRunList.cpp +++ b/src/core/GlyphRunList.cpp @@ -38,6 +38,7 @@ GlyphRunList::GlyphRunList(GlyphRun glyphRun) { GlyphRunList::GlyphRunList(std::vector glyphRuns) : _glyphRuns(std::move(glyphRuns)) { DEBUG_ASSERT(!_glyphRuns.empty()); + DEBUG_ASSERT(_glyphRuns[0].glyphFace != nullptr); DEBUG_ASSERT(std::all_of( _glyphRuns.begin(), _glyphRuns.end(), [hasColor = _glyphRuns[0].glyphFace->hasColor()](const GlyphRun& glyphRun) { @@ -57,7 +58,9 @@ Rect GlyphRunList::getBounds(float resolutionScale) const { if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. glyphFace = glyphFace->makeScaled(resolutionScale); - DEBUG_ASSERT(glyphFace != nullptr); + if (glyphFace == nullptr) { + return Rect::MakeEmpty(); + } } size_t index = 0; auto& positions = run.positions; @@ -86,7 +89,9 @@ bool GlyphRunList::getPath(Path* path, float resolutionScale) const { if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. glyphFace = glyphFace->makeScaled(resolutionScale); - DEBUG_ASSERT(glyphFace != nullptr); + if (glyphFace == nullptr) { + return false; + } } size_t index = 0; auto& positions = run.positions; diff --git a/src/gpu/RenderContext.cpp b/src/gpu/RenderContext.cpp index c8dd9f2f..1cacdc47 100644 --- a/src/gpu/RenderContext.cpp +++ b/src/gpu/RenderContext.cpp @@ -262,6 +262,9 @@ void RenderContext::drawColorGlyphs(std::shared_ptr glyphRunList, const MCState& state, const FillStyle& style) { auto viewMatrix = state.matrix; auto scale = viewMatrix.getMaxScale(); + if (scale <= 0) { + return; + } viewMatrix.preScale(1.0f / scale, 1.0f / scale); for (auto& glyphRun : glyphRunList->glyphRuns()) { auto glyphFace = glyphRun.glyphFace; From 09d3c05e1a2e04f7d8940d731c851b73ac38b7c6 Mon Sep 17 00:00:00 2001 From: domrjchen Date: Tue, 10 Dec 2024 16:55:44 +0800 Subject: [PATCH 16/17] Fix the FontGlyphFace::makeScale() method when the scale factor < 0. --- src/core/FontGlyphFace.cpp | 2 +- src/core/GlyphRunList.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/core/FontGlyphFace.cpp b/src/core/FontGlyphFace.cpp index e71991c7..313c2087 100644 --- a/src/core/FontGlyphFace.cpp +++ b/src/core/FontGlyphFace.cpp @@ -36,7 +36,7 @@ bool FontGlyphFace::hasOutlines() const { } std::shared_ptr FontGlyphFace::makeScaled(float scale) { - if (FloatNearlyZero(scale)) { + if (scale <= 0) { return nullptr; } auto size = _font.getSize() * scale; diff --git a/src/core/GlyphRunList.cpp b/src/core/GlyphRunList.cpp index 847ed3a9..f2275086 100644 --- a/src/core/GlyphRunList.cpp +++ b/src/core/GlyphRunList.cpp @@ -58,9 +58,7 @@ Rect GlyphRunList::getBounds(float resolutionScale) const { if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. glyphFace = glyphFace->makeScaled(resolutionScale); - if (glyphFace == nullptr) { - return Rect::MakeEmpty(); - } + DEBUG_ASSERT(glyphFace != nullptr); } size_t index = 0; auto& positions = run.positions; @@ -89,9 +87,7 @@ bool GlyphRunList::getPath(Path* path, float resolutionScale) const { if (hasScale) { // Scale the glyphs before measuring to prevent precision loss with small font sizes. glyphFace = glyphFace->makeScaled(resolutionScale); - if (glyphFace == nullptr) { - return false; - } + DEBUG_ASSERT(glyphFace != nullptr); } size_t index = 0; auto& positions = run.positions; From 7de4b86e680949de172cd367fea92d72e25af53f Mon Sep 17 00:00:00 2001 From: domrjchen Date: Tue, 10 Dec 2024 17:13:42 +0800 Subject: [PATCH 17/17] Remove an unused header. --- src/core/FontGlyphFace.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/FontGlyphFace.cpp b/src/core/FontGlyphFace.cpp index 313c2087..0d098312 100644 --- a/src/core/FontGlyphFace.cpp +++ b/src/core/FontGlyphFace.cpp @@ -17,7 +17,6 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "core/FontGlyphFace.h" -#include "utils/MathExtra.h" namespace tgfx { std::shared_ptr GlyphFace::Wrap(Font font) {