vcl/inc/font/LogicalFontInstance.hxx | 5 - vcl/inc/impfontcache.hxx | 8 +- vcl/inc/impglyphitem.hxx | 6 +- vcl/inc/pdf/pdfbuildin_fonts.hxx | 2 vcl/inc/qt5/QtFont.hxx | 1 vcl/inc/quartz/salgdi.h | 2 vcl/inc/unx/freetype_glyphcache.hxx | 2 vcl/inc/unx/glyphcache.hxx | 1 vcl/inc/win/DWriteTextRenderer.hxx | 15 ----- vcl/inc/win/winlayout.hxx | 4 - vcl/qa/cppunit/cjktext.cxx | 2 vcl/qa/cppunit/fontmocks.hxx | 3 - vcl/qa/cppunit/logicalfontinstance.cxx | 67 +++++++++++++++++++++---- vcl/qt5/QtFont.cxx | 7 -- vcl/quartz/ctfonts.cxx | 21 ------- vcl/skia/gdiimpl.cxx | 15 ++--- vcl/skia/win/gdiimpl.cxx | 33 +++++------- vcl/skia/x11/textrender.cxx | 10 +-- vcl/source/font/LogicalFontInstance.cxx | 36 +++++++++++-- vcl/source/font/fontcache.cxx | 4 - vcl/source/gdi/CommonSalLayout.cxx | 6 +- vcl/source/gdi/pdfbuildin_fonts.cxx | 5 - vcl/source/gdi/pdfwriter_impl.cxx | 29 +++++++++- vcl/source/gdi/sallayout.cxx | 37 +++++++++---- vcl/source/outdev/font.cxx | 6 +- vcl/unx/generic/glyphs/freetype_glyphcache.cxx | 38 -------------- vcl/unx/generic/glyphs/glyphcache.cxx | 8 -- vcl/win/gdi/DWriteTextRenderer.cxx | 28 ++++++---- vcl/win/gdi/salfont.cxx | 53 ------------------- vcl/win/gdi/winlayout.cxx | 18 ------ vcl/workben/listglyphs.cxx | 2 31 files changed, 204 insertions(+), 270 deletions(-)
New commits: commit 36e8e419d022a9c43302efe5e702a704dea39e76 Author: Mike Kaganski <[email protected]> AuthorDate: Mon Apr 8 02:45:28 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 10:40:50 2024 +0500 Exclude getHScale from DirectWrite font rendering ... and drop it, since it's unused now. Unkike with Skia, where the ratio produces a visible effect, in DirectWrite the effect seems cancelled by transformations. Yet, it produced computational instability, noticable in small vertical text. Change-Id: I2f3b20913075d1338dc75c5a04c9cc0ef29c75ce Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165877 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/vcl/inc/win/DWriteTextRenderer.hxx b/vcl/inc/win/DWriteTextRenderer.hxx index 67094052ebb5..a655df6459ea 100644 --- a/vcl/inc/win/DWriteTextRenderer.hxx +++ b/vcl/inc/win/DWriteTextRenderer.hxx @@ -72,21 +72,6 @@ private: D2DTextAntiAliasMode meTextAntiAliasMode; }; -/** - * Sets and unsets the needed DirectWrite transform to support the font's horizontal scaling and - * rotation. - */ -class WinFontTransformGuard -{ -public: - WinFontTransformGuard(ID2D1RenderTarget* pRenderTarget, float fHScale, const GenericSalLayout& rLayout, const D2D1_POINT_2F& rBaseline, bool bIsVertical); - ~WinFontTransformGuard(); - -private: - ID2D1RenderTarget* mpRenderTarget; - D2D1::Matrix3x2F maTransform; -}; - #endif // INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 0f253230c1b4..ac70e42b66cf 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -36,8 +36,6 @@ class WinFontInstance : public LogicalFontInstance public: ~WinFontInstance() override; - float getHScale() const; - void SetGraphics(WinSalGraphics*); WinSalGraphics* GetGraphics() const { return m_pGraphics; } diff --git a/vcl/win/gdi/DWriteTextRenderer.cxx b/vcl/win/gdi/DWriteTextRenderer.cxx index b7d7c03e9995..321587db8137 100644 --- a/vcl/win/gdi/DWriteTextRenderer.cxx +++ b/vcl/win/gdi/DWriteTextRenderer.cxx @@ -97,6 +97,20 @@ HRESULT checkResult(HRESULT hr, const char* file, size_t line) #endif +// Sets and unsets the needed DirectWrite transform to support the font's rotation. +class WinFontTransformGuard +{ +public: + WinFontTransformGuard(ID2D1RenderTarget* pRenderTarget, + const GenericSalLayout& rLayout, const D2D1_POINT_2F& rBaseline, + bool bIsVertical); + ~WinFontTransformGuard(); + +private: + ID2D1RenderTarget* mpRenderTarget; + D2D1::Matrix3x2F maTransform; +}; + } // end anonymous namespace D2DWriteTextOutRenderer::D2DWriteTextOutRenderer(bool bRenderingModeNatural) @@ -218,7 +232,6 @@ bool D2DWriteTextOutRenderer::performRender(GenericSalLayout const & rLayout, Sa } const WinFontInstance& rWinFont = static_cast<const WinFontInstance&>(rLayout.GetFont()); - float fHScale = rWinFont.getHScale(); float lfEmHeight = 0; IDWriteFontFace* pFontFace = GetDWriteFace(rWinFont, &lfEmHeight); @@ -251,11 +264,11 @@ bool D2DWriteTextOutRenderer::performRender(GenericSalLayout const & rLayout, Sa while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) { UINT16 glyphIndices[] = { static_cast<UINT16>(pGlyph->glyphId()) }; - FLOAT glyphAdvances[] = { static_cast<FLOAT>(pGlyph->newWidth()) / fHScale }; + FLOAT glyphAdvances[] = { static_cast<FLOAT>(pGlyph->newWidth()) }; DWRITE_GLYPH_OFFSET glyphOffsets[] = { { 0.0f, 0.0f }, }; - D2D1_POINT_2F baseline = { static_cast<FLOAT>(aPos.getX() - bounds.Left()) / fHScale, + D2D1_POINT_2F baseline = { static_cast<FLOAT>(aPos.getX() - bounds.Left()), static_cast<FLOAT>(aPos.getY() - bounds.Top()) }; - WinFontTransformGuard aTransformGuard(mpRT, fHScale, rLayout, baseline, pGlyph->IsVertical()); + WinFontTransformGuard aTransformGuard(mpRT, rLayout, baseline, pGlyph->IsVertical()); DWRITE_GLYPH_RUN glyphs = { pFontFace, lfEmHeight, @@ -306,7 +319,7 @@ IDWriteFontFace* D2DWriteTextOutRenderer::GetDWriteFace(const WinFontInstance& r return pFontFace; } -WinFontTransformGuard::WinFontTransformGuard(ID2D1RenderTarget* pRenderTarget, float fHScale, +WinFontTransformGuard::WinFontTransformGuard(ID2D1RenderTarget* pRenderTarget, const GenericSalLayout& rLayout, const D2D1_POINT_2F& rBaseline, bool bIsVertical) @@ -314,11 +327,6 @@ WinFontTransformGuard::WinFontTransformGuard(ID2D1RenderTarget* pRenderTarget, f { pRenderTarget->GetTransform(&maTransform); D2D1::Matrix3x2F aTransform = maTransform; - if (fHScale != 1.0f) - { - aTransform - = aTransform * D2D1::Matrix3x2F::Scale(D2D1::Size(fHScale, 1.0f), D2D1::Point2F(0, 0)); - } Degree10 angle = rLayout.GetOrientation(); diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 3865f2ebed66..f7ac7f5ff851 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -147,14 +147,6 @@ WinFontInstance::~WinFontInstance() ::DeleteFont(m_hFont); } -float WinFontInstance::getHScale() const -{ - const vcl::font::FontSelectPattern& rPattern = GetFontSelectPattern(); - if (!rPattern.mnHeight || !rPattern.mnWidth) - return 1.0; - return rPattern.mnWidth * GetAverageWidthFactor() / rPattern.mnHeight; -} - void WinFontInstance::ImplInitHbFont(hb_font_t* /*pHbFont*/) { assert(m_pGraphics); commit ee5584b926cd10ea600a3514242148db5a0a6f18 Author: Mike Kaganski <[email protected]> AuthorDate: Thu Mar 28 19:52:00 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 02:50:13 2024 +0500 Simplify and drop unused method Change-Id: Ie987bce2bb25232d54a4a83631c609ad6dba7213 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165467 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 18de0e684b1c..0f253230c1b4 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -36,7 +36,6 @@ class WinFontInstance : public LogicalFontInstance public: ~WinFontInstance() override; - bool hasHScale() const; float getHScale() const; void SetGraphics(WinSalGraphics*); diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index 371bdeb9642e..3865f2ebed66 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -147,22 +147,12 @@ WinFontInstance::~WinFontInstance() ::DeleteFont(m_hFont); } -bool WinFontInstance::hasHScale() const -{ - const vcl::font::FontSelectPattern& rPattern = GetFontSelectPattern(); - int nHeight(rPattern.mnHeight); - int nWidth(rPattern.mnWidth ? rPattern.mnWidth * GetAverageWidthFactor() : nHeight); - return nWidth != nHeight; -} - float WinFontInstance::getHScale() const { const vcl::font::FontSelectPattern& rPattern = GetFontSelectPattern(); - int nHeight(rPattern.mnHeight); - if (!nHeight) + if (!rPattern.mnHeight || !rPattern.mnWidth) return 1.0; - float nWidth(rPattern.mnWidth ? rPattern.mnWidth * GetAverageWidthFactor() : nHeight); - return nWidth / nHeight; + return rPattern.mnWidth * GetAverageWidthFactor() / rPattern.mnHeight; } void WinFontInstance::ImplInitHbFont(hb_font_t* /*pHbFont*/) commit 49e6927e3bd44021796b97d1ebb7886923f6cbcc Author: Mike Kaganski <[email protected]> AuthorDate: Tue Apr 2 08:55:51 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 02:38:32 2024 +0500 Fix UB after 8962141a12c966b2d891829925e6203bf8d51852 (tdf#160430: Fix glyph bounds calculation, and use basegfx::B2DRectangle, 2024-04-01). As reported by Stephan in https://gerrit.libreoffice.org/c/core/+/165553/6#message-fec1e45288c0e87d43c58f777ebe51b03c534d82: `CppunitTest_sw_rtfexport CPPUNIT_TEST_NAME=testMathEqarray::TestBody` now fails with vcl/source/gdi/sallayout.cxx:245:30: runtime error: inf is outside the range of representable values of type 'long' #0 in SalLayout::GetBoundRect(tools::Rectangle&) const at vcl/source/gdi/sallayout.cxx:245:30 #1 in OutputDevice::GetTextBoundRect(tools::Rectangle&, rtl::OUString const&, int, int, int, unsigned long, KernArraySpan, std::span<unsigned char const, 18446744073709551615ul>, SalLayoutGlyphs const*) const at vcl/source/outdev/text.cxx:1932:28 #2 in (anonymous namespace)::SmGetGlyphBoundRect(OutputDevice const&, rtl::OUString const&, tools::Rectangle&) at starmath/source/rect.cxx:80:32 #3 in SmRect::SmRect(OutputDevice const&, SmFormat const*, rtl::OUString const&, unsigned short) at starmath/source/rect.cxx:224:21 #4 in SmMathSymbolNode::AdaptToY(OutputDevice&, unsigned long) at starmath/source/node.cxx:2122:18 #5 in SmBraceNode::Arrange(OutputDevice&, SmFormat const&) at starmath/source/node.cxx:1340:17 #6 in SmBinHorNode::Arrange(OutputDevice&, SmFormat const&) at starmath/source/node.cxx:816:13 #7 in SmLineNode::Arrange(OutputDevice&, SmFormat const&) at starmath/source/node.cxx:610:20 #8 in SmTableNode::Arrange(OutputDevice&, SmFormat const&) at starmath/source/node.cxx:534:20 #9 in SmDocShell::ArrangeFormula() at starmath/source/document.cxx:280:13 #10 in SmDocShell::GetSize() at starmath/source/document.cxx:405:9 #11 in SmDocShell::Repaint() at starmath/source/document.cxx:566:21 #12 in SmDocShell::OnDocumentPrinterChanged(Printer*) at starmath/source/document.cxx:552:5 #13 in SmDocShell::SetText(rtl::OUString const&) at starmath/source/document.cxx:188:9 #14 in SmDocShell::readFormulaOoxml(oox::formulaimport::XmlStream&) at starmath/source/document.cxx:848:5 #15 in SmModel::readFormulaOoxml(oox::formulaimport::XmlStream&) at starmath/source/unomodel.cxx:1105:22 #16 in writerfilter::rtftok::RTFDocumentImpl::beforePopState(writerfilter::rtftok::RTFParserState&) at writerfilter/source/rtftok/rtfdocumentimpl.cxx:3010:30 #17 in writerfilter::rtftok::RTFDocumentImpl::popState() at writerfilter/source/rtftok/rtfdocumentimpl.cxx:3666:23 #18 in writerfilter::rtftok::RTFTokenizer::resolveParse() at writerfilter/source/rtftok/rtftokenizer.cxx:114:37 #19 in writerfilter::rtftok::RTFDocumentImpl::resolve(writerfilter::Stream&) at writerfilter/source/rtftok/rtfdocumentimpl.cxx:856:27 #20 in (anonymous namespace)::RtfFilter::filter(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at writerfilter/source/filter/RtfFilter.cxx:163:20 #21 in SfxObjectShell::ImportFrom(SfxMedium&, com::sun::star::uno::Reference<com::sun::star::text::XTextRange> const&) at sfx2/source/doc/objstor.cxx:2392:34 #22 in SfxObjectShell::DoLoad(SfxMedium*) at sfx2/source/doc/objstor.cxx:760:23 #23 in SfxBaseModel::load(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at sfx2/source/doc/sfxbasemodel.cxx:1980:36 #24 in (anonymous namespace)::SfxFrameLoader_Impl::load(com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&, com::sun::star::uno::Reference<com::sun::star::frame::XFrame> const&) at sfx2/source/view/frmload.cxx:720:28 #25 in framework::LoadEnv::impl_loadContent() at framework/source/loadenv/loadenv.cxx:1176:37 #26 in framework::LoadEnv::start() at framework/source/loadenv/loadenv.cxx:412:20 #27 in framework::LoadEnv::startLoading(rtl::OUString const&, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&, com::sun::star::uno::Reference<com::sun::star::frame::XFrame> const&, rtl::OUString const&, int, LoadEnvFeatures) at framework/source/loadenv/loadenv.cxx:308:5 #28 in framework::LoadEnv::loadComponentFromURL(com::sun::star::uno::Reference<com::sun::star::frame::XComponentLoader> const&, com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&, rtl::OUString const&, rtl::OUString const&, int, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at framework/source/loadenv/loadenv.cxx:168:14 #29 in framework::Desktop::loadComponentFromURL(rtl::OUString const&, rtl::OUString const&, int, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at framework/source/services/desktop.cxx:591:16 #30 in non-virtual thunk to framework::Desktop::loadComponentFromURL(rtl::OUString const&, rtl::OUString const&, int, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at framework/source/services/desktop.cxx #31 in unotest::MacrosTest::loadFromDesktop(rtl::OUString const&, rtl::OUString const&, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at unotest/source/cpp/macros_test.cxx:71:62 #32 in UnoApiTest::loadWithParams(rtl::OUString const&, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at test/source/unoapi_test.cxx:126:19 #33 in UnoApiTest::load(rtl::OUString const&, char const*) at test/source/unoapi_test.cxx:108:5 #34 in SwModelTestBase::loadURL(rtl::OUString const&, char const*) at sw/qa/unit/swmodeltestbase.cxx:441:20 #35 in SwModelTestBase::loadAndReload(char const*) at sw/qa/unit/swmodeltestbase.cxx:466:5 #36 in (anonymous namespace)::testMathEqarray::TestBody() at sw/qa/extras/rtfexport/rtfexport.cxx:198:5 Change-Id: I857861f5bc51a1e43bfbf5e0c9dbce542d673ca7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165664 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index 7397748ecd72..c8c2d6ca1093 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -216,7 +216,10 @@ bool SalLayout::GetOutline(basegfx::B2DPolyPolygonVector& rVector) const } // No need to expand to the next pixel, when the character only covers its tiny fraction -static double trimInsignificant(double n) { return std::round(n * 1e5) / 1e5; } +static double trimInsignificant(double n) +{ + return std::abs(n) >= 0x1p53 ? n : std::round(n * 1e5) / 1e5; +} bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const { @@ -243,10 +246,19 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const bRet = true; } } - rRect = tools::Rectangle(rtl::math::approxFloor(trimInsignificant(aUnion.getMinX())), - rtl::math::approxFloor(trimInsignificant(aUnion.getMinY())), - rtl::math::approxCeil(trimInsignificant(aUnion.getMaxX())), - rtl::math::approxCeil(trimInsignificant(aUnion.getMaxY()))); + if (aUnion.isEmpty()) + { + rRect = {}; + } + else + { + double l = rtl::math::approxFloor(trimInsignificant(aUnion.getMinX())), + t = rtl::math::approxFloor(trimInsignificant(aUnion.getMinY())), + r = rtl::math::approxCeil(trimInsignificant(aUnion.getMaxX())), + b = rtl::math::approxCeil(trimInsignificant(aUnion.getMaxY())); + assert(std::isfinite(l) && std::isfinite(t) && std::isfinite(r) && std::isfinite(b)); + rRect = tools::Rectangle(l, t, r, b); + } return bRet; } commit a2c412dbc17b5c9a7b12639390b58b73cc858e49 Author: Mike Kaganski <[email protected]> AuthorDate: Sun Mar 31 00:45:25 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 02:36:07 2024 +0500 tdf#160436: fix glyph bounds calculation for vertical glyphs It is unclear if LogicalFontInstance::GetGlyphBoundRect can be called for both normal and rotated variants of the same glyph in the same font. If yes, then the normal and vertical variants must be cached separately, or possibly vertical variant can be not cached, but always calculated. This problem already existed before, so this change doesn't introduce a new issue. Change-Id: I9b50ef340c9e38db7bef890165519aadc96d3ffa Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165581 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/vcl/qa/cppunit/logicalfontinstance.cxx b/vcl/qa/cppunit/logicalfontinstance.cxx index 1eaf0ebd28db..77de9b9b4e3f 100644 --- a/vcl/qa/cppunit/logicalfontinstance.cxx +++ b/vcl/qa/cppunit/logicalfontinstance.cxx @@ -46,6 +46,7 @@ void VclLogicalFontInstanceTest::testglyphboundrect() basegfx::B2DRectangle aBoundRect; const auto LATIN_SMALL_LETTER_B = 0x0062; + const auto SECTION_SIGN = 0x00A7; // UTR#50: Vertical_Orientation (vo) property value U pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, false); @@ -54,6 +55,14 @@ void VclLogicalFontInstanceTest::testglyphboundrect() CPPUNIT_ASSERT_DOUBLES_EQUAL(49.5, aBoundRect.getWidth(), 0.05); CPPUNIT_ASSERT_DOUBLES_EQUAL(80.8, aBoundRect.getHeight(), 0.05); + // tdf#160436: test vertically oriented glyphs + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(SECTION_SIGN), aBoundRect, true); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-79.7, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-55.0, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(88.9, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(48.8, aBoundRect.getHeight(), 0.05); + font.SetOrientation(900_deg10); device->SetFont(font); @@ -67,6 +76,14 @@ void VclLogicalFontInstanceTest::testglyphboundrect() CPPUNIT_ASSERT_DOUBLES_EQUAL(80.8, aBoundRect.getWidth(), 0.05); CPPUNIT_ASSERT_DOUBLES_EQUAL(49.5, aBoundRect.getHeight(), 0.05); + // tdf#160436: test vertically oriented glyphs + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(SECTION_SIGN), aBoundRect, true); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-55.0, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-9.2, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(48.8, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(88.9, aBoundRect.getHeight(), 0.05); + font.SetOrientation(450_deg10); device->SetFont(font); @@ -79,6 +96,14 @@ void VclLogicalFontInstanceTest::testglyphboundrect() CPPUNIT_ASSERT_DOUBLES_EQUAL(-96.4, aBoundRect.getMinY(), 0.05); CPPUNIT_ASSERT_DOUBLES_EQUAL(92.1, aBoundRect.getWidth(), 0.05); CPPUNIT_ASSERT_DOUBLES_EQUAL(92.1, aBoundRect.getHeight(), 0.05); + + // tdf#160436: test vertically oriented glyphs + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(SECTION_SIGN), aBoundRect, true); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-95.3, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-45.4, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(97.4, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(97.4, aBoundRect.getHeight(), 0.05); } CPPUNIT_TEST_SUITE_REGISTRATION(VclLogicalFontInstanceTest); diff --git a/vcl/source/font/LogicalFontInstance.cxx b/vcl/source/font/LogicalFontInstance.cxx index 6524422397f0..9d893b85aa70 100644 --- a/vcl/source/font/LogicalFontInstance.cxx +++ b/vcl/source/font/LogicalFontInstance.cxx @@ -171,8 +171,8 @@ void LogicalFontInstance::IgnoreFallbackForUnicode(sal_UCS4 cChar, FontWeight eW bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, basegfx::B2DRectangle& rRect, bool bVertical) const { - // TODO/FIXME: bVertical handling here is highly suspicious. When it's true, it may - // return different rectangle, depending on if this glyph was cached already or not. + // TODO: find out if it's possible for the same glyph in the same font to be used both + // normally and vertically; if yes, then these two variants must be cached separately if (mpFontCache && mpFontCache->GetCachedGlyphBoundRect(this, nID, rRect)) return true; @@ -191,10 +191,13 @@ bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, basegfx::B2DRectang double fMaxY = -(aExtents.y_bearing + aExtents.height) * nYScale; rRect = basegfx::B2DRectangle(fMinX, fMinY, fMaxX, fMaxY); - if (mnOrientation && !bVertical) + auto orientation = mnOrientation; + if (bVertical) + orientation += 900_deg10; + if (orientation) { // Apply font rotation. - rRect.transform(basegfx::utils::createRotateB2DHomMatrix(-toRadians(mnOrientation))); + rRect.transform(basegfx::utils::createRotateB2DHomMatrix(-toRadians(orientation))); } if (mpFontCache) commit aa5514cce0ab4e12bbf7f20a7d4dbf16b89ae58c Author: Mike Kaganski <[email protected]> AuthorDate: Fri Mar 29 20:15:06 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 02:35:44 2024 +0500 tdf#160430: Fix glyph bounds calculation, and use basegfx::B2DRectangle ... instead of tools::Rectangle. Several problems were there: 1. First, a horizontal bounding rectangle was calculated, with due rounding; and then the result was rotated, and after that, rounded again. That made the resulting rotated rectangle coordinates very imprecise. 2. Also, ceil/floor was applied without normalization; and in case of rotated font, that meant, that sometimes the range could be not expanded to cover partially covered pixels, but instead collapsed. 3. The rotation to angles other than 90 degree multiples was done incorrectly, resulting in cut off parts of characters. 4. For 90 degrees, the imprecise result of sin/cos converted 0.0 into values like 3e-16, which then could be ceil'ed up to 1. Using B2DRectangle and its transform allows to simplify and fix the calculations easily, and avoids premature rounding. Render of rotated text of small size is more stable with this change. Change-Id: Idffd74b9937feb2418ab76a8d325fdaf4ff841b7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165553 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <[email protected]> Reviewed-by: Mike Kaganski <[email protected]> diff --git a/vcl/inc/font/LogicalFontInstance.hxx b/vcl/inc/font/LogicalFontInstance.hxx index 518716b5c7df..e8124eac7eca 100644 --- a/vcl/inc/font/LogicalFontInstance.hxx +++ b/vcl/inc/font/LogicalFontInstance.hxx @@ -22,6 +22,7 @@ #include <sal/config.h> #include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/range/b2drectangle.hxx> #include <o3tl/hash_combine.hxx> #include <rtl/ref.hxx> #include <salhelper/simplereferenceobject.hxx> @@ -101,7 +102,7 @@ public: // TODO: make data members private vcl::font::PhysicalFontFace* GetFontFace() { return m_pFontFace.get(); } const ImplFontCache* GetFontCache() const { return mpFontCache; } - bool GetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const; + bool GetGlyphBoundRect(sal_GlyphId, basegfx::B2DRectangle&, bool) const; virtual bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const = 0; bool GetGlyphOutlineUntransformed(sal_GlyphId, basegfx::B2DPolyPolygon&) const; diff --git a/vcl/inc/impfontcache.hxx b/vcl/inc/impfontcache.hxx index 5ea19b05d9a5..4d197003b279 100644 --- a/vcl/inc/impfontcache.hxx +++ b/vcl/inc/impfontcache.hxx @@ -21,10 +21,10 @@ #include <sal/config.h> +#include <basegfx/range/b2drectangle.hxx> #include <rtl/ref.hxx> #include <o3tl/lru_map.hxx> #include <o3tl/hash_combine.hxx> -#include <tools/gen.hxx> #include "font/FontSelectPattern.hxx" #include "glyphid.hxx" @@ -59,7 +59,7 @@ struct GlyphBoundRectCacheHash } }; -typedef o3tl::lru_map<GlyphBoundRectCacheKey, tools::Rectangle, +typedef o3tl::lru_map<GlyphBoundRectCacheKey, basegfx::B2DRectangle, GlyphBoundRectCacheHash> GlyphBoundRectCache; class ImplFontCache @@ -86,8 +86,8 @@ public: LogicalFontInstance* pLogicalFont, int nFallbackLevel, OUString& rMissingCodes ); - bool GetCachedGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); - void CacheGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); + bool GetCachedGlyphBoundRect(const LogicalFontInstance*, sal_GlyphId, basegfx::B2DRectangle&); + void CacheGlyphBoundRect(const LogicalFontInstance*, sal_GlyphId, basegfx::B2DRectangle&); void Invalidate(); }; diff --git a/vcl/inc/impglyphitem.hxx b/vcl/inc/impglyphitem.hxx index 87f966bd1676..a3f1b8a7a7a6 100644 --- a/vcl/inc/impglyphitem.hxx +++ b/vcl/inc/impglyphitem.hxx @@ -20,8 +20,8 @@ #ifndef INCLUDED_VCL_IMPGLYPHITEM_HXX #define INCLUDED_VCL_IMPGLYPHITEM_HXX +#include <basegfx/range/b2drectangle.hxx> #include <o3tl/typed_flags_set.hxx> -#include <tools/gen.hxx> #include <vcl/dllapi.h> #include <vcl/outdev.hxx> #include <vector> @@ -87,7 +87,7 @@ public: return bool(m_nFlags & GlyphItemFlags::IS_SAFE_TO_INSERT_KASHIDA); } - inline bool GetGlyphBoundRect(const LogicalFontInstance*, tools::Rectangle&) const; + inline bool GetGlyphBoundRect(const LogicalFontInstance*, basegfx::B2DRectangle&) const; inline bool GetGlyphOutline(const LogicalFontInstance*, basegfx::B2DPolyPolygon&) const; inline void dropGlyph(); @@ -117,7 +117,7 @@ public: }; bool GlyphItem::GetGlyphBoundRect(const LogicalFontInstance* pFontInstance, - tools::Rectangle& rRect) const + basegfx::B2DRectangle& rRect) const { return pFontInstance->GetGlyphBoundRect(m_aGlyphId, rRect, IsVertical()); } diff --git a/vcl/qa/cppunit/logicalfontinstance.cxx b/vcl/qa/cppunit/logicalfontinstance.cxx index 12ee95762eef..1eaf0ebd28db 100644 --- a/vcl/qa/cppunit/logicalfontinstance.cxx +++ b/vcl/qa/cppunit/logicalfontinstance.cxx @@ -39,25 +39,46 @@ void VclLogicalFontInstanceTest::testglyphboundrect() { ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT); device->SetOutputSizePixel(Size(1000, 1000)); - device->SetFont(vcl::Font("Liberation Sans", Size(0, 110))); + vcl::Font font("Liberation Sans", Size(0, 110)); + device->SetFont(font); const LogicalFontInstance* pFontInstance = device->GetFontInstance(); - tools::Rectangle aBoundRect; + basegfx::B2DRectangle aBoundRect; const auto LATIN_SMALL_LETTER_B = 0x0062; pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, false); - const tools::Long nExpectedX = 7; - const tools::Long nExpectedY = -80; - const tools::Long nExpectedWidth = 51; - const tools::Long nExpectedHeight = 83; + CPPUNIT_ASSERT_DOUBLES_EQUAL(7.1, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-79.7, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(49.5, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(80.8, aBoundRect.getHeight(), 0.05); - CPPUNIT_ASSERT_EQUAL_MESSAGE("x of glyph is wrong", nExpectedX, aBoundRect.getX()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("y of glyph is wrong", nExpectedY, aBoundRect.getY()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("height of glyph of wrong", nExpectedWidth, aBoundRect.GetWidth()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("width of glyph of wrong", nExpectedHeight, - aBoundRect.GetHeight()); + font.SetOrientation(900_deg10); + device->SetFont(font); + + pFontInstance = device->GetFontInstance(); + + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, + false); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-79.7, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-56.6, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(80.8, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(49.5, aBoundRect.getHeight(), 0.05); + + font.SetOrientation(450_deg10); + device->SetFont(font); + + pFontInstance = device->GetFontInstance(); + + pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, + false); + + CPPUNIT_ASSERT_DOUBLES_EQUAL(-51.3, aBoundRect.getMinX(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-96.4, aBoundRect.getMinY(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(92.1, aBoundRect.getWidth(), 0.05); + CPPUNIT_ASSERT_DOUBLES_EQUAL(92.1, aBoundRect.getHeight(), 0.05); } CPPUNIT_TEST_SUITE_REGISTRATION(VclLogicalFontInstanceTest); diff --git a/vcl/source/font/LogicalFontInstance.cxx b/vcl/source/font/LogicalFontInstance.cxx index 6c6c95bbb6a1..6524422397f0 100644 --- a/vcl/source/font/LogicalFontInstance.cxx +++ b/vcl/source/font/LogicalFontInstance.cxx @@ -26,6 +26,8 @@ #include <font/LogicalFontInstance.hxx> #include <impfontcache.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + LogicalFontInstance::LogicalFontInstance(const vcl::font::PhysicalFontFace& rFontFace, const vcl::font::FontSelectPattern& rFontSelData) : mxFontMetric(new ImplFontMetricData(rFontSelData)) @@ -166,47 +168,39 @@ void LogicalFontInstance::IgnoreFallbackForUnicode(sal_UCS4 cChar, FontWeight eW maUnicodeFallbackList.erase(it); } -bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& rRect, +bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, basegfx::B2DRectangle& rRect, bool bVertical) const { + // TODO/FIXME: bVertical handling here is highly suspicious. When it's true, it may + // return different rectangle, depending on if this glyph was cached already or not. + if (mpFontCache && mpFontCache->GetCachedGlyphBoundRect(this, nID, rRect)) return true; auto* pHbFont = const_cast<LogicalFontInstance*>(this)->GetHbFont(); hb_glyph_extents_t aExtents; - bool res = hb_font_get_glyph_extents(pHbFont, nID, &aExtents); + if (!hb_font_get_glyph_extents(pHbFont, nID, &aExtents)) + return false; - if (res) - { - double nXScale = 0, nYScale = 0; - GetScale(&nXScale, &nYScale); + double nXScale = 0, nYScale = 0; + GetScale(&nXScale, &nYScale); - double fMinX = aExtents.x_bearing; - double fMinY = aExtents.y_bearing; - double fMaxX = aExtents.x_bearing + aExtents.width; - double fMaxY = aExtents.y_bearing + aExtents.height; + double fMinX = aExtents.x_bearing * nXScale; + double fMinY = -aExtents.y_bearing * nYScale; + double fMaxX = (aExtents.x_bearing + aExtents.width) * nXScale; + double fMaxY = -(aExtents.y_bearing + aExtents.height) * nYScale; + rRect = basegfx::B2DRectangle(fMinX, fMinY, fMaxX, fMaxY); - tools::Rectangle aRect(std::floor(fMinX * nXScale), -std::ceil(fMinY * nYScale), - std::ceil(fMaxX * nXScale), -std::floor(fMaxY * nYScale)); - if (mnOrientation && !bVertical) - { - // Apply font rotation. - const double fRad = toRadians(mnOrientation); - const double fCos = cos(fRad); - const double fSin = sin(fRad); - - rRect.SetLeft(fCos * aRect.Left() + fSin * aRect.Top()); - rRect.SetTop(-fSin * aRect.Left() - fCos * aRect.Top()); - rRect.SetRight(fCos * aRect.Right() + fSin * aRect.Bottom()); - rRect.SetBottom(-fSin * aRect.Right() - fCos * aRect.Bottom()); - } - else - rRect = aRect; + if (mnOrientation && !bVertical) + { + // Apply font rotation. + rRect.transform(basegfx::utils::createRotateB2DHomMatrix(-toRadians(mnOrientation))); } - if (mpFontCache && res) + if (mpFontCache) mpFontCache->CacheGlyphBoundRect(this, nID, rRect); - return res; + + return true; } sal_GlyphId LogicalFontInstance::GetGlyphIndex(uint32_t nUnicode, uint32_t nVariationSelector) const diff --git a/vcl/source/font/fontcache.cxx b/vcl/source/font/fontcache.cxx index 58b68baa9fe3..a167f741de15 100644 --- a/vcl/source/font/fontcache.cxx +++ b/vcl/source/font/fontcache.cxx @@ -248,7 +248,7 @@ void ImplFontCache::Invalidate() m_aBoundRectCache.clear(); } -bool ImplFontCache::GetCachedGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, tools::Rectangle &rRect) +bool ImplFontCache::GetCachedGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, basegfx::B2DRectangle &rRect) { if (!pFont->GetFontCache()) return false; @@ -265,7 +265,7 @@ bool ImplFontCache::GetCachedGlyphBoundRect(const LogicalFontInstance *pFont, sa return false; } -void ImplFontCache::CacheGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, tools::Rectangle &rRect) +void ImplFontCache::CacheGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, basegfx::B2DRectangle &rRect) { if (!pFont->GetFontCache()) return; diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index be301edcd365..5167921bd7ed 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -561,12 +561,12 @@ bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay { // We need glyph's advance, top bearing, and height to // correct y offset. - tools::Rectangle aRect; + basegfx::B2DRectangle aRect; // Get cached bound rect value for the font, GetFont().GetGlyphBoundRect(nGlyphIndex, aRect, true); - nXOffset = -(aRect.Top() / nXScale + ( pHbPositions[i].y_advance - + ( aRect.GetHeight() / nXScale ) ) / 2 ); + nXOffset = -(aRect.getMinX() / nXScale + ( pHbPositions[i].y_advance + + ( aRect.getHeight() / nXScale ) ) / 2.0 ); } } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 40b6b9456266..8dd72a469de1 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -7006,7 +7006,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool else if ( eAlign == ALIGN_TOP ) aOffset.AdjustY(GetFontInstance()->mxFontMetric->GetAscent() ); - tools::Rectangle aRectangle; + basegfx::B2DRectangle aRectangle; nIndex = 0; while (rLayout.GetNextGlyph(&pGlyph, aPos, nIndex, &pGlyphFont)) { @@ -7023,8 +7023,8 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool } else { - aAdjOffset = DevicePoint(aOffset.X(), aOffset.Y()); - aAdjOffset.adjustX(aRectangle.Left() + (aRectangle.GetWidth() - aEmphasisMark.GetWidth()) / 2 ); + aAdjOffset = basegfx::B2DPoint(aOffset.X(), aOffset.Y()); + aAdjOffset.adjustX(aRectangle.getMinX() + (aRectangle.getWidth() - aEmphasisMark.GetWidth()) / 2 ); } aAdjOffset = aRotScale.transform( aAdjOffset ); diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index ed368f04022e..7397748ecd72 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -33,6 +33,7 @@ #include <sallayout.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <rtl/math.hxx> #include <i18nlangtag/lang.h> @@ -214,12 +215,15 @@ bool SalLayout::GetOutline(basegfx::B2DPolyPolygonVector& rVector) const return (bAllOk && bOneOk); } +// No need to expand to the next pixel, when the character only covers its tiny fraction +static double trimInsignificant(double n) { return std::round(n * 1e5) / 1e5; } + bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const { bool bRet = false; - rRect.SetEmpty(); - tools::Rectangle aRectangle; + basegfx::B2DRectangle aUnion; + basegfx::B2DRectangle aRectangle; DevicePoint aPos; const GlyphItem* pGlyph; @@ -230,22 +234,19 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const // get bounding rectangle of individual glyph if (pGlyph->GetGlyphBoundRect(pGlyphFont, aRectangle)) { - if (!aRectangle.IsEmpty()) + if (!aRectangle.isEmpty()) { - aRectangle.AdjustLeft(std::floor(aPos.getX())); - aRectangle.AdjustRight(std::ceil(aPos.getX())); - aRectangle.AdjustTop(std::floor(aPos.getY())); - aRectangle.AdjustBottom(std::ceil(aPos.getY())); - + aRectangle.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos)); // merge rectangle - if (rRect.IsEmpty()) - rRect = aRectangle; - else - rRect.Union(aRectangle); + aUnion.expand(aRectangle); } bRet = true; } } + rRect = tools::Rectangle(rtl::math::approxFloor(trimInsignificant(aUnion.getMinX())), + rtl::math::approxFloor(trimInsignificant(aUnion.getMinY())), + rtl::math::approxCeil(trimInsignificant(aUnion.getMaxX())), + rtl::math::approxCeil(trimInsignificant(aUnion.getMaxY()))); return bRet; } diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx index 3bfbb8f6d8ce..fee8021b43a9 100644 --- a/vcl/source/outdev/font.cxx +++ b/vcl/source/outdev/font.cxx @@ -950,8 +950,8 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) tools::Long nEmphasisHeight2 = nEmphasisHeight / 2; aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 ); - DevicePoint aOutPoint; - tools::Rectangle aRectangle; + basegfx::B2DPoint aOutPoint; + basegfx::B2DRectangle aRectangle; const GlyphItem* pGlyph; const LogicalFontInstance* pGlyphFont; int nStart = 0; @@ -971,7 +971,7 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) else { aAdjPoint = aOffset; - aAdjPoint.AdjustX(aRectangle.Left() + (aRectangle.GetWidth() - aEmphasisMark.GetWidth()) / 2 ); + aAdjPoint.AdjustX(aRectangle.getMinX() + (aRectangle.getWidth() - aEmphasisMark.GetWidth()) / 2 ); } if ( mpFontInstance->mnOrientation ) diff --git a/vcl/workben/listglyphs.cxx b/vcl/workben/listglyphs.cxx index def2ff818122..341006d433dd 100644 --- a/vcl/workben/listglyphs.cxx +++ b/vcl/workben/listglyphs.cxx @@ -120,7 +120,7 @@ int ListGlyphs::Main() nChar = pCharMap->GetNextChar(nChar)) { auto nGlyphIndex = pFontInstance->GetGlyphIndex(nChar); - tools::Rectangle aGlyphBounds; + basegfx::B2DRectangle aGlyphBounds; pFontInstance->GetGlyphBoundRect(nGlyphIndex, aGlyphBounds, false); std::cout << "Codepoint: " << pFontFace->GetGlyphName(nGlyphIndex) << "; glyph bounds: " << aGlyphBounds << " "; commit cbb9d93f5396ee0842cf48fdefc98d5db6eb27c4 Author: Khaled Hosny <[email protected]> AuthorDate: Sun Jul 16 07:37:55 2023 +0300 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 02:24:05 2024 +0500 vcl: Use HarfBuzz to get glyph bounding rectangle For consistent cross-platform results that also matches our glyph advances since platform functions might be using hints which we don’t use. Change-Id: I4aebd3e7c5f460dff584f5eba74f7a11bab0f9b1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/154388 Tested-by: Jenkins Reviewed-by: خالد حسني <[email protected]> diff --git a/vcl/inc/font/LogicalFontInstance.hxx b/vcl/inc/font/LogicalFontInstance.hxx index c9e837d540f1..518716b5c7df 100644 --- a/vcl/inc/font/LogicalFontInstance.hxx +++ b/vcl/inc/font/LogicalFontInstance.hxx @@ -120,8 +120,6 @@ protected: explicit LogicalFontInstance(const vcl::font::PhysicalFontFace&, const vcl::font::FontSelectPattern&); - virtual bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const = 0; - hb_font_t* InitHbFont(); virtual void ImplInitHbFont(hb_font_t*) {} diff --git a/vcl/inc/pdf/pdfbuildin_fonts.hxx b/vcl/inc/pdf/pdfbuildin_fonts.hxx index 8cb34e74922b..a0c2fc06287d 100644 --- a/vcl/inc/pdf/pdfbuildin_fonts.hxx +++ b/vcl/inc/pdf/pdfbuildin_fonts.hxx @@ -49,8 +49,6 @@ struct BuildinFont class BuildinFontInstance final : public LogicalFontInstance { - bool ImplGetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& rRect, bool) const override; - public: BuildinFontInstance(const vcl::font::PhysicalFontFace&, const vcl::font::FontSelectPattern&); diff --git a/vcl/inc/qt5/QtFont.hxx b/vcl/inc/qt5/QtFont.hxx index e19d6de21aa2..7d0b338c939d 100644 --- a/vcl/inc/qt5/QtFont.hxx +++ b/vcl/inc/qt5/QtFont.hxx @@ -33,7 +33,6 @@ class QtFont final : public QFont, public LogicalFontInstance QtFontFace::CreateFontInstance(const vcl::font::FontSelectPattern&) const; bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override; - bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; explicit QtFont(const vcl::font::PhysicalFontFace&, const vcl::font::FontSelectPattern&); }; diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index 6d1668c1f913..a255e9dc330d 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -103,8 +103,6 @@ public: private: explicit CoreTextFont(const CoreTextFontFace&, const vcl::font::FontSelectPattern&); - bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; - CTFontRef mpCTFont; }; diff --git a/vcl/inc/unx/freetype_glyphcache.hxx b/vcl/inc/unx/freetype_glyphcache.hxx index c80642b6126c..9c61e0ff60d1 100644 --- a/vcl/inc/unx/freetype_glyphcache.hxx +++ b/vcl/inc/unx/freetype_glyphcache.hxx @@ -107,8 +107,6 @@ class SAL_DLLPUBLIC_RTTI FreetypeFontInstance final : public LogicalFontInstance std::unique_ptr<FreetypeFont> mxFreetypeFont; - virtual bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; - explicit FreetypeFontInstance(const vcl::font::PhysicalFontFace& rPFF, const vcl::font::FontSelectPattern& rFSP); public: diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx index 9de7bd59fe6c..4d21d34d05ea 100644 --- a/vcl/inc/unx/glyphcache.hxx +++ b/vcl/inc/unx/glyphcache.hxx @@ -123,7 +123,6 @@ public: void GetFontMetric(ImplFontMetricDataRef const &) const; - bool GetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const; bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const; bool GetAntialiasAdvice() const; diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index fb8e5a1c6e43..18de0e684b1c 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -60,7 +60,6 @@ private: explicit WinFontInstance(const WinFontFace&, const vcl::font::FontSelectPattern&); virtual void ImplInitHbFont(hb_font_t*) override; - bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override; WinSalGraphics *m_pGraphics; HFONT m_hFont; diff --git a/vcl/qa/cppunit/cjktext.cxx b/vcl/qa/cppunit/cjktext.cxx index af63b29959fd..cd9bd2c165fd 100644 --- a/vcl/qa/cppunit/cjktext.cxx +++ b/vcl/qa/cppunit/cjktext.cxx @@ -178,7 +178,7 @@ void VclCjkTextTest::testVerticalText() tools::Long height36Rotated = getCharacterRightSideHeight(device, Point(99, 35)); CPPUNIT_ASSERT_DOUBLES_EQUAL(height36, height36Rotated, 1); tools::Long width36Rotated = getCharacterTopWidth(device, Point(25, 0)); - CPPUNIT_ASSERT_DOUBLES_EQUAL(width36, width36Rotated, 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(width36, width36Rotated, 2); font = baseFont; font.SetFontSize(Size(0, 72)); diff --git a/vcl/qa/cppunit/fontmocks.hxx b/vcl/qa/cppunit/fontmocks.hxx index 7e33ce8e7e13..8eac463c143f 100644 --- a/vcl/qa/cppunit/fontmocks.hxx +++ b/vcl/qa/cppunit/fontmocks.hxx @@ -30,9 +30,6 @@ public: { return true; } - -protected: - bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override { return true; } }; class TestFontFace : public vcl::font::PhysicalFontFace diff --git a/vcl/qa/cppunit/logicalfontinstance.cxx b/vcl/qa/cppunit/logicalfontinstance.cxx index 2a7a5c83ac27..12ee95762eef 100644 --- a/vcl/qa/cppunit/logicalfontinstance.cxx +++ b/vcl/qa/cppunit/logicalfontinstance.cxx @@ -50,13 +50,14 @@ void VclLogicalFontInstanceTest::testglyphboundrect() const tools::Long nExpectedX = 7; const tools::Long nExpectedY = -80; + const tools::Long nExpectedWidth = 51; + const tools::Long nExpectedHeight = 83; CPPUNIT_ASSERT_EQUAL_MESSAGE("x of glyph is wrong", nExpectedX, aBoundRect.getX()); CPPUNIT_ASSERT_EQUAL_MESSAGE("y of glyph is wrong", nExpectedY, aBoundRect.getY()); - CPPUNIT_ASSERT_MESSAGE("height of glyph of wrong", - aBoundRect.GetWidth() == 50 || aBoundRect.GetWidth() == 51); - CPPUNIT_ASSERT_MESSAGE("width of glyph of wrong", - aBoundRect.GetHeight() == 82 || aBoundRect.GetHeight() == 83); + CPPUNIT_ASSERT_EQUAL_MESSAGE("height of glyph of wrong", nExpectedWidth, aBoundRect.GetWidth()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("width of glyph of wrong", nExpectedHeight, + aBoundRect.GetHeight()); } CPPUNIT_TEST_SUITE_REGISTRATION(VclLogicalFontInstanceTest); diff --git a/vcl/qt5/QtFont.cxx b/vcl/qt5/QtFont.cxx index 384f56774ffd..e3a6c0b0a9d7 100644 --- a/vcl/qt5/QtFont.cxx +++ b/vcl/qt5/QtFont.cxx @@ -187,11 +187,4 @@ bool QtFont::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rB2DPolyP return true; } -bool QtFont::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool) const -{ - QRawFont aRawFont(QRawFont::fromFont(*this)); - rRect = toRectangle(aRawFont.boundingRect(nId).toAlignedRect()); - return true; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/ctfonts.cxx b/vcl/quartz/ctfonts.cxx index 38112a7deb50..1cafd270552d 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -89,27 +89,6 @@ void CoreTextFont::GetFontMetric( ImplFontMetricDataRef const & rxFontMetric ) rxFontMetric->SetMinKashida(GetKashidaWidth()); } -bool CoreTextFont::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bVertical) const -{ - CGGlyph nCGGlyph = nId; - - SAL_WNODEPRECATED_DECLARATIONS_PUSH //TODO: 10.11 kCTFontDefaultOrientation - const CTFontOrientation aFontOrientation = kCTFontDefaultOrientation; // TODO: horz/vert - SAL_WNODEPRECATED_DECLARATIONS_POP - CGRect aCGRect = CTFontGetBoundingRectsForGlyphs(mpCTFont, aFontOrientation, &nCGGlyph, nullptr, 1); - - // Apply font rotation to non-vertical glyphs. - if (mfFontRotation && !bVertical) - aCGRect = CGRectApplyAffineTransform(aCGRect, CGAffineTransformMakeRotation(mfFontRotation)); - - tools::Long xMin = floor(aCGRect.origin.x); - tools::Long yMin = floor(aCGRect.origin.y); - tools::Long xMax = ceil(aCGRect.origin.x + aCGRect.size.width); - tools::Long yMax = ceil(aCGRect.origin.y + aCGRect.size.height); - rRect = tools::Rectangle(xMin, -yMax, xMax, -yMin); - return true; -} - namespace { // callbacks from CTFontCreatePathForGlyph+CGPathApply for GetGlyphOutline() diff --git a/vcl/source/font/LogicalFontInstance.cxx b/vcl/source/font/LogicalFontInstance.cxx index 6c7a7e2bde09..6c6c95bbb6a1 100644 --- a/vcl/source/font/LogicalFontInstance.cxx +++ b/vcl/source/font/LogicalFontInstance.cxx @@ -172,7 +172,38 @@ bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& r if (mpFontCache && mpFontCache->GetCachedGlyphBoundRect(this, nID, rRect)) return true; - bool res = ImplGetGlyphBoundRect(nID, rRect, bVertical); + auto* pHbFont = const_cast<LogicalFontInstance*>(this)->GetHbFont(); + hb_glyph_extents_t aExtents; + bool res = hb_font_get_glyph_extents(pHbFont, nID, &aExtents); + + if (res) + { + double nXScale = 0, nYScale = 0; + GetScale(&nXScale, &nYScale); + + double fMinX = aExtents.x_bearing; + double fMinY = aExtents.y_bearing; + double fMaxX = aExtents.x_bearing + aExtents.width; + double fMaxY = aExtents.y_bearing + aExtents.height; + + tools::Rectangle aRect(std::floor(fMinX * nXScale), -std::ceil(fMinY * nYScale), + std::ceil(fMaxX * nXScale), -std::floor(fMaxY * nYScale)); + if (mnOrientation && !bVertical) + { + // Apply font rotation. + const double fRad = toRadians(mnOrientation); + const double fCos = cos(fRad); + const double fSin = sin(fRad); + + rRect.SetLeft(fCos * aRect.Left() + fSin * aRect.Top()); + rRect.SetTop(-fSin * aRect.Left() - fCos * aRect.Top()); + rRect.SetRight(fCos * aRect.Right() + fSin * aRect.Bottom()); + rRect.SetBottom(-fSin * aRect.Right() - fCos * aRect.Bottom()); + } + else + rRect = aRect; + } + if (mpFontCache && res) mpFontCache->CacheGlyphBoundRect(this, nID, rRect); return res; diff --git a/vcl/source/gdi/pdfbuildin_fonts.cxx b/vcl/source/gdi/pdfbuildin_fonts.cxx index e387f78638d3..7f80bfdd030d 100644 --- a/vcl/source/gdi/pdfbuildin_fonts.cxx +++ b/vcl/source/gdi/pdfbuildin_fonts.cxx @@ -738,11 +738,6 @@ BuildinFontInstance::BuildinFontInstance(const vcl::font::PhysicalFontFace& rFon { } -bool BuildinFontInstance::ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const -{ - return false; -} - bool BuildinFontInstance::GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const { return false; diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx index 64fcb6bfc2bf..bed24e081ee5 100644 --- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx +++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx @@ -564,44 +564,6 @@ void FreetypeFont::ApplyGlyphTransform(bool bVertical, FT_Glyph pGlyphFT ) const } } -bool FreetypeFont::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& rRect, bool bVertical) const -{ - FT_Activate_Size( maSizeFT ); - - FT_Error rc = FT_Load_Glyph(maFaceFT, nID, mnLoadFlags); - - if (rc != FT_Err_Ok) - return false; - - if (mrFontInstance.NeedsArtificialBold()) - FT_GlyphSlot_Embolden(maFaceFT->glyph); - - FT_Glyph pGlyphFT; - rc = FT_Get_Glyph(maFaceFT->glyph, &pGlyphFT); - if (rc != FT_Err_Ok) - return false; - - ApplyGlyphTransform(bVertical, pGlyphFT); - - FT_BBox aBbox; - FT_Glyph_Get_CBox( pGlyphFT, FT_GLYPH_BBOX_PIXELS, &aBbox ); - FT_Done_Glyph( pGlyphFT ); - - tools::Rectangle aRect(aBbox.xMin, -aBbox.yMax, aBbox.xMax, -aBbox.yMin); - if (mnCos != 0x10000 && mnSin != 0) - { - const double nCos = mnCos / 65536.0; - const double nSin = mnSin / 65536.0; - rRect.SetLeft( nCos*aRect.Left() + nSin*aRect.Top() ); - rRect.SetTop( -nSin*aRect.Left() - nCos*aRect.Top() ); - rRect.SetRight( nCos*aRect.Right() + nSin*aRect.Bottom() ); - rRect.SetBottom( -nSin*aRect.Right() - nCos*aRect.Bottom() ); - } - else - rRect = aRect; - return true; -} - bool FreetypeFont::GetAntialiasAdvice() const { // TODO: also use GASP info diff --git a/vcl/unx/generic/glyphs/glyphcache.cxx b/vcl/unx/generic/glyphs/glyphcache.cxx index 39b10c78e123..ac3c5e15ab73 100644 --- a/vcl/unx/generic/glyphs/glyphcache.cxx +++ b/vcl/unx/generic/glyphs/glyphcache.cxx @@ -75,14 +75,6 @@ FreetypeFontInstance::~FreetypeFontInstance() { } -bool FreetypeFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bVertical) const -{ - assert(mxFreetypeFont); - if (!mxFreetypeFont) - return false; - return mxFreetypeFont->GetGlyphBoundRect(nId, rRect, bVertical); -} - bool FreetypeFontInstance::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rPoly, bool bVertical) const { assert(mxFreetypeFont); diff --git a/vcl/win/gdi/salfont.cxx b/vcl/win/gdi/salfont.cxx index 196932982c28..d5f41e2e8819 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -1156,59 +1156,6 @@ void WinSalGraphics::ClearDevFontCache() ImplReleaseTempFonts(*GetSalData(), false); } -bool WinFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bIsVertical) const -{ - assert(m_pGraphics); - HDC hDC = m_pGraphics->getHDC(); - const HFONT hOrigFont = static_cast<HFONT>(GetCurrentObject(hDC, OBJ_FONT)); - const HFONT hFont = GetHFONT(); - if (hFont != hOrigFont) - SelectObject(hDC, hFont); - - const ::comphelper::ScopeGuard aFontRestoreScopeGuard([hFont, hOrigFont, hDC]() - { if (hFont != hOrigFont) SelectObject(hDC, hOrigFont); }); - const float fFontScale = GetScale(); - - // use unity matrix - MAT2 aMat; - const vcl::font::FontSelectPattern& rFSD = GetFontSelectPattern(); - - // Use identity matrix for fonts requested in horizontal - // writing (LTR or RTL), or rotated glyphs in vertical writing. - if (!rFSD.mbVertical || !bIsVertical) - { - aMat.eM11 = aMat.eM22 = FixedFromDouble(1.0); - aMat.eM12 = aMat.eM21 = FixedFromDouble(0.0); - } - else - { - constexpr double nCos = 0.0; - constexpr double nSin = 1.0; - aMat.eM11 = FixedFromDouble(nCos); - aMat.eM12 = FixedFromDouble(nSin); - aMat.eM21 = FixedFromDouble(-nSin); - aMat.eM22 = FixedFromDouble(nCos); - } - - UINT nGGOFlags = GGO_METRICS; - nGGOFlags |= GGO_GLYPH_INDEX; - - GLYPHMETRICS aGM; - aGM.gmptGlyphOrigin.x = aGM.gmptGlyphOrigin.y = 0; - aGM.gmBlackBoxX = aGM.gmBlackBoxY = 0; - DWORD nSize = ::GetGlyphOutlineW(hDC, nId, nGGOFlags, &aGM, 0, nullptr, &aMat); - if (nSize == GDI_ERROR) - return false; - - rRect = tools::Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ), - Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) ); - rRect.SetLeft(static_cast<int>( fFontScale * rRect.Left() )); - rRect.SetRight(static_cast<int>( fFontScale * rRect.Right() ) + 1); - rRect.SetTop(static_cast<int>( fFontScale * rRect.Top() )); - rRect.SetBottom(static_cast<int>( fFontScale * rRect.Bottom() ) + 1); - return true; -} - bool WinFontInstance::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rB2DPolyPoly, bool) const { rB2DPolyPoly.clear(); commit 2b1e0c071dc186cd29ee2653166fdb9aa98bca2e Author: Khaled Hosny <[email protected]> AuthorDate: Tue Jun 20 15:58:45 2023 +0300 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 01:55:14 2024 +0500 tdf#115321: Fix PDF position of emphasis mark in vertical text This aligns the code in PDF writer with OutputDevice::ImplDrawEmphasisMarks(). Change-Id: I404beda30ff0eb1d6c59d971a7daa59b559ef70f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153326 Tested-by: Jenkins Reviewed-by: خالد حسني <[email protected]> diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 6ea5c67f12a3..40b6b9456266 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6982,11 +6982,20 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool writeBuffer( aLine.getStr(), aLine.getLength() ); Point aOffset(0,0); + Point aOffsetVert(0,0); if ( nEmphMark & FontEmphasisMark::PosBelow ) + { aOffset.AdjustY(GetFontInstance()->mxFontMetric->GetDescent() + aEmphasisMark.GetYOffset() ); + aOffsetVert = aOffset; + } else + { aOffset.AdjustY( -(GetFontInstance()->mxFontMetric->GetAscent() + aEmphasisMark.GetYOffset()) ); + // Todo: use ideographic em-box or ideographic character face information. + aOffsetVert.AdjustY(-(GetFontInstance()->mxFontMetric->GetAscent() + + GetFontInstance()->mxFontMetric->GetDescent() + aEmphasisMark.GetYOffset())); + } tools::Long nEmphWidth2 = aEmphasisMark.GetWidth() / 2; tools::Long nEmphHeight2 = nEmphHeight / 2; @@ -6997,13 +7006,27 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool else if ( eAlign == ALIGN_TOP ) aOffset.AdjustY(GetFontInstance()->mxFontMetric->GetAscent() ); + tools::Rectangle aRectangle; nIndex = 0; - while (rLayout.GetNextGlyph(&pGlyph, aPos, nIndex)) + while (rLayout.GetNextGlyph(&pGlyph, aPos, nIndex, &pGlyphFont)) { + if (!pGlyph->GetGlyphBoundRect(pGlyphFont, aRectangle)) + continue; + if (!pGlyph->IsSpacing()) { - DevicePoint aAdjOffset(aOffset.X(), aOffset.Y()); - aAdjOffset.adjustX((pGlyph->newWidth() - aEmphasisMark.GetWidth()) / 2); + DevicePoint aAdjOffset; + if (pGlyph->IsVertical()) + { + aAdjOffset = DevicePoint(aOffsetVert.X(), aOffsetVert.Y()); + aAdjOffset.adjustX((-pGlyph->origWidth() + aEmphasisMark.GetWidth()) / 2); + } + else + { + aAdjOffset = DevicePoint(aOffset.X(), aOffset.Y()); + aAdjOffset.adjustX(aRectangle.Left() + (aRectangle.GetWidth() - aEmphasisMark.GetWidth()) / 2 ); + } + aAdjOffset = aRotScale.transform( aAdjOffset ); aAdjOffset -= DevicePoint(nEmphWidth2, nEmphHeight2); commit 401ed53c66085d2442c361c43fe0180e115d6b11 Author: Mike Kaganski <[email protected]> AuthorDate: Sun Mar 31 10:57:43 2024 +0100 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 01:48:20 2024 +0500 Simplify a bit And make font size calculations consistent between SkiaTextRender (x11) and WinSkiaSalGraphicsImpl (win). They already did ~the same, the win case just used an intermediate 'getHScale' coefficient. Change-Id: I90ad4d9c49427465ef3263843b34bd9bc0d762eb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165488 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index d063b440cf31..04dad0123573 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -216,20 +216,22 @@ catch (const sal::systools::ComError& e) bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) { assert(dynamic_cast<const SkiaWinFontInstance*>(&rLayout.GetFont())); - const SkiaWinFontInstance* pWinFont - = static_cast<const SkiaWinFontInstance*>(&rLayout.GetFont()); - const HFONT hLayoutFont = pWinFont->GetHFONT(); - double hScale = pWinFont->getHScale(); + const SkiaWinFontInstance& rWinFont + = static_cast<const SkiaWinFontInstance&>(rLayout.GetFont()); + const vcl::font::FontSelectPattern& rFSD = rWinFont.GetFontSelectPattern(); + if (rFSD.mnHeight == 0) + return false; + const HFONT hLayoutFont = rWinFont.GetHFONT(); LOGFONTW logFont; if (GetObjectW(hLayoutFont, sizeof(logFont), &logFont) == 0) { assert(false); return false; } - sk_sp<SkTypeface> typeface = pWinFont->GetSkiaTypeface(); + sk_sp<SkTypeface> typeface = rWinFont.GetSkiaTypeface(); if (!typeface) { - typeface = createDirectWriteTypeface(pWinFont); + typeface = createDirectWriteTypeface(&rWinFont); bool dwrite = true; if (!typeface) // fall back to GDI text rendering { @@ -250,7 +252,7 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) return false; } // Cache the typeface. - const_cast<SkiaWinFontInstance*>(pWinFont)->SetSkiaTypeface(typeface, dwrite); + const_cast<SkiaWinFontInstance&>(rWinFont).SetSkiaTypeface(typeface, dwrite); } SkFont font(typeface); @@ -267,21 +269,14 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) font.setEdging(logFont.lfQuality == NONANTIALIASED_QUALITY ? SkFont::Edging::kAlias : ePreferredAliasing); - const vcl::font::FontSelectPattern& rFSD = pWinFont->GetFontSelectPattern(); - int nHeight = rFSD.mnHeight; - int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; - if (nWidth == 0 || nHeight == 0) - return false; + double nHeight = rFSD.mnHeight; + double nWidth = rFSD.mnWidth ? rFSD.mnWidth * rWinFont.GetAverageWidthFactor() : nHeight; font.setSize(nHeight); - font.setScaleX(hScale); + font.setScaleX(nWidth / nHeight); - // Unlike with Freetype-based font handling, use height even in vertical mode, - // additionally multiply it by horizontal scale to get the proper - // size and then scale the width back, otherwise the height would - // not be correct. I don't know why this is inconsistent. SkFont verticalFont(font); - verticalFont.setSize(nHeight * hScale); - verticalFont.setScaleX(1.0 / hScale); + verticalFont.setSize(nWidth); + verticalFont.setScaleX(nHeight / nWidth); assert(dynamic_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl())); SkiaSalGraphicsImpl* impl = static_cast<SkiaSalGraphicsImpl*>(mWinParent.GetImpl()); diff --git a/vcl/skia/x11/textrender.cxx b/vcl/skia/x11/textrender.cxx index fed5daa8a117..c598146be376 100644 --- a/vcl/skia/x11/textrender.cxx +++ b/vcl/skia/x11/textrender.cxx @@ -35,10 +35,10 @@ void SkiaTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const SalGr const FreetypeFontInstance& rInstance = static_cast<FreetypeFontInstance&>(rLayout.GetFont()); const FreetypeFont& rFont = rInstance.GetFreetypeFont(); const vcl::font::FontSelectPattern& rFSD = rInstance.GetFontSelectPattern(); - int nHeight = rFSD.mnHeight; - int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; - if (nWidth == 0 || nHeight == 0) + if (rFSD.mnHeight == 0) return; + double nHeight = rFSD.mnHeight; + double nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; if (!fontManager) { @@ -49,7 +49,7 @@ void SkiaTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const SalGr = SkFontMgr_createTypefaceFromFcPattern(fontManager, rFont.GetFontOptions()->GetPattern()); SkFont font(typeface); font.setSize(nHeight); - font.setScaleX(1.0 * nWidth / nHeight); + font.setScaleX(nWidth / nHeight); if (rInstance.NeedsArtificialItalic()) font.setSkewX(-1.0 * ARTIFICIAL_ITALIC_SKEW); if (rInstance.NeedsArtificialBold()) @@ -76,7 +76,7 @@ void SkiaTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const SalGr // Vertical font, use width as "height". SkFont verticalFont(font); verticalFont.setSize(nWidth); - verticalFont.setScaleX(1.0 * nHeight / nWidth); + verticalFont.setScaleX(nHeight / nWidth); assert(dynamic_cast<SkiaSalGraphicsImpl*>(rGraphics.GetImpl())); SkiaSalGraphicsImpl* impl = static_cast<SkiaSalGraphicsImpl*>(rGraphics.GetImpl()); commit dc7d9bfbfb7b46d9ac2e3bb72669da1130259f93 Author: Mike Kaganski <[email protected]> AuthorDate: Sun Mar 31 07:49:23 2024 +0100 Commit: Mike Kaganski <[email protected]> CommitDate: Mon Apr 8 01:40:13 2024 +0500 Optimize trigonometry a bit Change-Id: I2b06c29f6090233325c7ca24fac6d76190d502ab Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165486 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 7a240600be98..84b625115648 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -2099,8 +2099,8 @@ bool SkiaSalGraphicsImpl::implDrawGradient(const basegfx::B2DPolyPolygon& rPolyP } static double toRadian(Degree10 degree10th) { return toRadians(3600_deg10 - degree10th); } -static double toCos(Degree10 degree10th) { return SkScalarCos(toRadian(degree10th)); } -static double toSin(Degree10 degree10th) { return SkScalarSin(toRadian(degree10th)); } +static auto toCos(Degree10 degree10th) { return SkScalarCos(toRadian(degree10th)); } +static auto toSin(Degree10 degree10th) { return SkScalarSin(toRadian(degree10th)); } void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Color textColor, const SkFont& font, const SkFont& verticalFont) @@ -2115,15 +2115,16 @@ void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Colo DevicePoint aPos; const GlyphItem* pGlyph; int nStart = 0; + auto cos = toCos(layout.GetOrientation()); + auto sin = toSin(layout.GetOrientation()); while (layout.GetNextGlyph(&pGlyph, aPos, nStart)) { glyphIds.push_back(pGlyph->glyphId()); - Degree10 angle = layout.GetOrientation(); - if (pGlyph->IsVertical()) - angle += 900_deg10; - SkRSXform form = SkRSXform::Make(toCos(angle), toSin(angle), aPos.getX(), aPos.getY()); - glyphForms.emplace_back(std::move(form)); verticals.emplace_back(pGlyph->IsVertical()); + auto cos1 = pGlyph->IsVertical() ? sin : cos; // cos (x - 90) = sin (x) + auto sin1 = pGlyph->IsVertical() ? -cos : sin; // sin (x - 90) = -cos (x) + SkRSXform form = SkRSXform::Make(cos1, sin1, aPos.getX(), aPos.getY()); + glyphForms.emplace_back(std::move(form)); } if (glyphIds.empty()) return;
