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/winlayout.hxx | 2 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/salfont.cxx | 53 +++++++++++++++++++ vcl/win/gdi/winlayout.cxx | 14 ++++- vcl/workben/listglyphs.cxx | 2 29 files changed, 237 insertions(+), 188 deletions(-)
New commits: commit 0aa53d7f7d4aa31cd79ed27dfd20be5b13dd0815 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:21 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:21 2024 +0500 Revert "Optimize trigonometry a bit" This reverts commit dc7d9bfbfb7b46d9ac2e3bb72669da1130259f93. diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 84b625115648..7a240600be98 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 auto toCos(Degree10 degree10th) { return SkScalarCos(toRadian(degree10th)); } -static auto toSin(Degree10 degree10th) { return SkScalarSin(toRadian(degree10th)); } +static double toCos(Degree10 degree10th) { return SkScalarCos(toRadian(degree10th)); } +static double toSin(Degree10 degree10th) { return SkScalarSin(toRadian(degree10th)); } void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Color textColor, const SkFont& font, const SkFont& verticalFont) @@ -2115,16 +2115,15 @@ 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()); - 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()); + 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()); } if (glyphIds.empty()) return; commit b05c43c694435cc4a27c7bfcf103c1d3d8cfcc31 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:21 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:21 2024 +0500 Revert "Simplify a bit" This reverts commit 401ed53c66085d2442c361c43fe0180e115d6b11. diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index 04dad0123573..d063b440cf31 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -216,22 +216,20 @@ catch (const sal::systools::ComError& e) bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) { assert(dynamic_cast<const SkiaWinFontInstance*>(&rLayout.GetFont())); - 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(); + const SkiaWinFontInstance* pWinFont + = static_cast<const SkiaWinFontInstance*>(&rLayout.GetFont()); + const HFONT hLayoutFont = pWinFont->GetHFONT(); + double hScale = pWinFont->getHScale(); LOGFONTW logFont; if (GetObjectW(hLayoutFont, sizeof(logFont), &logFont) == 0) { assert(false); return false; } - sk_sp<SkTypeface> typeface = rWinFont.GetSkiaTypeface(); + sk_sp<SkTypeface> typeface = pWinFont->GetSkiaTypeface(); if (!typeface) { - typeface = createDirectWriteTypeface(&rWinFont); + typeface = createDirectWriteTypeface(pWinFont); bool dwrite = true; if (!typeface) // fall back to GDI text rendering { @@ -252,7 +250,7 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) return false; } // Cache the typeface. - const_cast<SkiaWinFontInstance&>(rWinFont).SetSkiaTypeface(typeface, dwrite); + const_cast<SkiaWinFontInstance*>(pWinFont)->SetSkiaTypeface(typeface, dwrite); } SkFont font(typeface); @@ -269,14 +267,21 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) font.setEdging(logFont.lfQuality == NONANTIALIASED_QUALITY ? SkFont::Edging::kAlias : ePreferredAliasing); - double nHeight = rFSD.mnHeight; - double nWidth = rFSD.mnWidth ? rFSD.mnWidth * rWinFont.GetAverageWidthFactor() : nHeight; + 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; font.setSize(nHeight); - font.setScaleX(nWidth / nHeight); + font.setScaleX(hScale); + // 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(nWidth); - verticalFont.setScaleX(nHeight / nWidth); + verticalFont.setSize(nHeight * hScale); + verticalFont.setScaleX(1.0 / hScale); 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 c598146be376..fed5daa8a117 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(); - if (rFSD.mnHeight == 0) + int nHeight = rFSD.mnHeight; + int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; + if (nWidth == 0 || nHeight == 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(nWidth / nHeight); + font.setScaleX(1.0 * 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(nHeight / nWidth); + verticalFont.setScaleX(1.0 * nHeight / nWidth); assert(dynamic_cast<SkiaSalGraphicsImpl*>(rGraphics.GetImpl())); SkiaSalGraphicsImpl* impl = static_cast<SkiaSalGraphicsImpl*>(rGraphics.GetImpl()); commit cd894eb00babba247ec63d8a3cba4da42d0cc3c4 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:21 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:21 2024 +0500 Revert "tdf#115321: Fix PDF position of emphasis mark in vertical text" This reverts commit 2b1e0c071dc186cd29ee2653166fdb9aa98bca2e. diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 40b6b9456266..6ea5c67f12a3 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -6982,20 +6982,11 @@ 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; @@ -7006,27 +6997,13 @@ 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, &pGlyphFont)) + while (rLayout.GetNextGlyph(&pGlyph, aPos, nIndex)) { - if (!pGlyph->GetGlyphBoundRect(pGlyphFont, aRectangle)) - continue; - if (!pGlyph->IsSpacing()) { - 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 ); - } - + DevicePoint aAdjOffset(aOffset.X(), aOffset.Y()); + aAdjOffset.adjustX((pGlyph->newWidth() - aEmphasisMark.GetWidth()) / 2); aAdjOffset = aRotScale.transform( aAdjOffset ); aAdjOffset -= DevicePoint(nEmphWidth2, nEmphHeight2); commit 43f4826ac4064e36685aec9424f6c9636c73573a Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:20 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:20 2024 +0500 Revert "vcl: Use HarfBuzz to get glyph bounding rectangle" This reverts commit cbb9d93f5396ee0842cf48fdefc98d5db6eb27c4. diff --git a/vcl/inc/font/LogicalFontInstance.hxx b/vcl/inc/font/LogicalFontInstance.hxx index 518716b5c7df..c9e837d540f1 100644 --- a/vcl/inc/font/LogicalFontInstance.hxx +++ b/vcl/inc/font/LogicalFontInstance.hxx @@ -120,6 +120,8 @@ 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 a0c2fc06287d..8cb34e74922b 100644 --- a/vcl/inc/pdf/pdfbuildin_fonts.hxx +++ b/vcl/inc/pdf/pdfbuildin_fonts.hxx @@ -49,6 +49,8 @@ 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 7d0b338c939d..e19d6de21aa2 100644 --- a/vcl/inc/qt5/QtFont.hxx +++ b/vcl/inc/qt5/QtFont.hxx @@ -33,6 +33,7 @@ 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 a255e9dc330d..6d1668c1f913 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -103,6 +103,8 @@ 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 9c61e0ff60d1..c80642b6126c 100644 --- a/vcl/inc/unx/freetype_glyphcache.hxx +++ b/vcl/inc/unx/freetype_glyphcache.hxx @@ -107,6 +107,8 @@ 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 4d21d34d05ea..9de7bd59fe6c 100644 --- a/vcl/inc/unx/glyphcache.hxx +++ b/vcl/inc/unx/glyphcache.hxx @@ -123,6 +123,7 @@ 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 18de0e684b1c..fb8e5a1c6e43 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -60,6 +60,7 @@ 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 cd9bd2c165fd..af63b29959fd 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, 2); + CPPUNIT_ASSERT_DOUBLES_EQUAL(width36, width36Rotated, 1); font = baseFont; font.SetFontSize(Size(0, 72)); diff --git a/vcl/qa/cppunit/fontmocks.hxx b/vcl/qa/cppunit/fontmocks.hxx index 8eac463c143f..7e33ce8e7e13 100644 --- a/vcl/qa/cppunit/fontmocks.hxx +++ b/vcl/qa/cppunit/fontmocks.hxx @@ -30,6 +30,9 @@ 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 12ee95762eef..2a7a5c83ac27 100644 --- a/vcl/qa/cppunit/logicalfontinstance.cxx +++ b/vcl/qa/cppunit/logicalfontinstance.cxx @@ -50,14 +50,13 @@ 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_EQUAL_MESSAGE("height of glyph of wrong", nExpectedWidth, aBoundRect.GetWidth()); - CPPUNIT_ASSERT_EQUAL_MESSAGE("width of glyph of wrong", nExpectedHeight, - aBoundRect.GetHeight()); + 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_TEST_SUITE_REGISTRATION(VclLogicalFontInstanceTest); diff --git a/vcl/qt5/QtFont.cxx b/vcl/qt5/QtFont.cxx index e3a6c0b0a9d7..384f56774ffd 100644 --- a/vcl/qt5/QtFont.cxx +++ b/vcl/qt5/QtFont.cxx @@ -187,4 +187,11 @@ 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 1cafd270552d..38112a7deb50 100644 --- a/vcl/quartz/ctfonts.cxx +++ b/vcl/quartz/ctfonts.cxx @@ -89,6 +89,27 @@ 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 6c6c95bbb6a1..6c7a7e2bde09 100644 --- a/vcl/source/font/LogicalFontInstance.cxx +++ b/vcl/source/font/LogicalFontInstance.cxx @@ -172,38 +172,7 @@ bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& r 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 (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; - } - + bool res = ImplGetGlyphBoundRect(nID, rRect, bVertical); 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 7f80bfdd030d..e387f78638d3 100644 --- a/vcl/source/gdi/pdfbuildin_fonts.cxx +++ b/vcl/source/gdi/pdfbuildin_fonts.cxx @@ -738,6 +738,11 @@ 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 bed24e081ee5..64fcb6bfc2bf 100644 --- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx +++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx @@ -564,6 +564,44 @@ 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 ac3c5e15ab73..39b10c78e123 100644 --- a/vcl/unx/generic/glyphs/glyphcache.cxx +++ b/vcl/unx/generic/glyphs/glyphcache.cxx @@ -75,6 +75,14 @@ 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 d5f41e2e8819..196932982c28 100644 --- a/vcl/win/gdi/salfont.cxx +++ b/vcl/win/gdi/salfont.cxx @@ -1156,6 +1156,59 @@ 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 30a3ab3b8cb08abee71c0ca855b4c805d9e4772c Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:20 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:20 2024 +0500 Revert "tdf#160430: Fix glyph bounds calculation, and use basegfx::B2DRectangle" This reverts commit aa5514cce0ab4e12bbf7f20a7d4dbf16b89ae58c. diff --git a/vcl/inc/font/LogicalFontInstance.hxx b/vcl/inc/font/LogicalFontInstance.hxx index e8124eac7eca..518716b5c7df 100644 --- a/vcl/inc/font/LogicalFontInstance.hxx +++ b/vcl/inc/font/LogicalFontInstance.hxx @@ -22,7 +22,6 @@ #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> @@ -102,7 +101,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, basegfx::B2DRectangle&, bool) const; + bool GetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, 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 4d197003b279..5ea19b05d9a5 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, basegfx::B2DRectangle, +typedef o3tl::lru_map<GlyphBoundRectCacheKey, tools::Rectangle, GlyphBoundRectCacheHash> GlyphBoundRectCache; class ImplFontCache @@ -86,8 +86,8 @@ public: LogicalFontInstance* pLogicalFont, int nFallbackLevel, OUString& rMissingCodes ); - bool GetCachedGlyphBoundRect(const LogicalFontInstance*, sal_GlyphId, basegfx::B2DRectangle&); - void CacheGlyphBoundRect(const LogicalFontInstance*, sal_GlyphId, basegfx::B2DRectangle&); + bool GetCachedGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); + void CacheGlyphBoundRect(const LogicalFontInstance *, sal_GlyphId, tools::Rectangle &); void Invalidate(); }; diff --git a/vcl/inc/impglyphitem.hxx b/vcl/inc/impglyphitem.hxx index a3f1b8a7a7a6..87f966bd1676 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*, basegfx::B2DRectangle&) const; + inline bool GetGlyphBoundRect(const LogicalFontInstance*, tools::Rectangle&) const; inline bool GetGlyphOutline(const LogicalFontInstance*, basegfx::B2DPolyPolygon&) const; inline void dropGlyph(); @@ -117,7 +117,7 @@ public: }; bool GlyphItem::GetGlyphBoundRect(const LogicalFontInstance* pFontInstance, - basegfx::B2DRectangle& rRect) const + tools::Rectangle& rRect) const { return pFontInstance->GetGlyphBoundRect(m_aGlyphId, rRect, IsVertical()); } diff --git a/vcl/qa/cppunit/logicalfontinstance.cxx b/vcl/qa/cppunit/logicalfontinstance.cxx index 1eaf0ebd28db..12ee95762eef 100644 --- a/vcl/qa/cppunit/logicalfontinstance.cxx +++ b/vcl/qa/cppunit/logicalfontinstance.cxx @@ -39,46 +39,25 @@ void VclLogicalFontInstanceTest::testglyphboundrect() { ScopedVclPtr<VirtualDevice> device = VclPtr<VirtualDevice>::Create(DeviceFormat::DEFAULT); device->SetOutputSizePixel(Size(1000, 1000)); - vcl::Font font("Liberation Sans", Size(0, 110)); - device->SetFont(font); + device->SetFont(vcl::Font("Liberation Sans", Size(0, 110))); const LogicalFontInstance* pFontInstance = device->GetFontInstance(); - basegfx::B2DRectangle aBoundRect; + tools::Rectangle aBoundRect; const auto LATIN_SMALL_LETTER_B = 0x0062; pFontInstance->GetGlyphBoundRect(pFontInstance->GetGlyphIndex(LATIN_SMALL_LETTER_B), aBoundRect, false); - 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); + const tools::Long nExpectedX = 7; + const tools::Long nExpectedY = -80; + const tools::Long nExpectedWidth = 51; + const tools::Long nExpectedHeight = 83; - 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_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()); } CPPUNIT_TEST_SUITE_REGISTRATION(VclLogicalFontInstanceTest); diff --git a/vcl/source/font/LogicalFontInstance.cxx b/vcl/source/font/LogicalFontInstance.cxx index 6524422397f0..6c6c95bbb6a1 100644 --- a/vcl/source/font/LogicalFontInstance.cxx +++ b/vcl/source/font/LogicalFontInstance.cxx @@ -26,8 +26,6 @@ #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)) @@ -168,39 +166,47 @@ void LogicalFontInstance::IgnoreFallbackForUnicode(sal_UCS4 cChar, FontWeight eW maUnicodeFallbackList.erase(it); } -bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, basegfx::B2DRectangle& rRect, +bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& 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; - if (!hb_font_get_glyph_extents(pHbFont, nID, &aExtents)) - return false; + bool res = hb_font_get_glyph_extents(pHbFont, nID, &aExtents); - double nXScale = 0, nYScale = 0; - GetScale(&nXScale, &nYScale); + if (res) + { + double nXScale = 0, nYScale = 0; + GetScale(&nXScale, &nYScale); - 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); + double fMinX = aExtents.x_bearing; + double fMinY = aExtents.y_bearing; + double fMaxX = aExtents.x_bearing + aExtents.width; + double fMaxY = aExtents.y_bearing + aExtents.height; - if (mnOrientation && !bVertical) - { - // Apply font rotation. - rRect.transform(basegfx::utils::createRotateB2DHomMatrix(-toRadians(mnOrientation))); + 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) + if (mpFontCache && res) mpFontCache->CacheGlyphBoundRect(this, nID, rRect); - - return true; + return res; } 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 a167f741de15..58b68baa9fe3 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, basegfx::B2DRectangle &rRect) +bool ImplFontCache::GetCachedGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, tools::Rectangle &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, basegfx::B2DRectangle &rRect) +void ImplFontCache::CacheGlyphBoundRect(const LogicalFontInstance *pFont, sal_GlyphId nID, tools::Rectangle &rRect) { if (!pFont->GetFontCache()) return; diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 5167921bd7ed..be301edcd365 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. - basegfx::B2DRectangle aRect; + tools::Rectangle aRect; // Get cached bound rect value for the font, GetFont().GetGlyphBoundRect(nGlyphIndex, aRect, true); - nXOffset = -(aRect.getMinX() / nXScale + ( pHbPositions[i].y_advance - + ( aRect.getHeight() / nXScale ) ) / 2.0 ); + nXOffset = -(aRect.Top() / nXScale + ( pHbPositions[i].y_advance + + ( aRect.GetHeight() / nXScale ) ) / 2 ); } } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 8dd72a469de1..40b6b9456266 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() ); - basegfx::B2DRectangle aRectangle; + tools::Rectangle 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 = basegfx::B2DPoint(aOffset.X(), aOffset.Y()); - aAdjOffset.adjustX(aRectangle.getMinX() + (aRectangle.getWidth() - aEmphasisMark.GetWidth()) / 2 ); + aAdjOffset = DevicePoint(aOffset.X(), aOffset.Y()); + aAdjOffset.adjustX(aRectangle.Left() + (aRectangle.GetWidth() - aEmphasisMark.GetWidth()) / 2 ); } aAdjOffset = aRotScale.transform( aAdjOffset ); diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index 7397748ecd72..ed368f04022e 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -33,7 +33,6 @@ #include <sallayout.hxx> #include <basegfx/polygon/b2dpolypolygon.hxx> #include <basegfx/matrix/b2dhommatrixtools.hxx> -#include <rtl/math.hxx> #include <i18nlangtag/lang.h> @@ -215,15 +214,12 @@ 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(); - basegfx::B2DRectangle aUnion; - basegfx::B2DRectangle aRectangle; + tools::Rectangle aRectangle; DevicePoint aPos; const GlyphItem* pGlyph; @@ -234,19 +230,22 @@ 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.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos)); + aRectangle.AdjustLeft(std::floor(aPos.getX())); + aRectangle.AdjustRight(std::ceil(aPos.getX())); + aRectangle.AdjustTop(std::floor(aPos.getY())); + aRectangle.AdjustBottom(std::ceil(aPos.getY())); + // merge rectangle - aUnion.expand(aRectangle); + if (rRect.IsEmpty()) + rRect = aRectangle; + else + rRect.Union(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 fee8021b43a9..3bfbb8f6d8ce 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 ); - basegfx::B2DPoint aOutPoint; - basegfx::B2DRectangle aRectangle; + DevicePoint aOutPoint; + tools::Rectangle 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.getMinX() + (aRectangle.getWidth() - aEmphasisMark.GetWidth()) / 2 ); + aAdjPoint.AdjustX(aRectangle.Left() + (aRectangle.GetWidth() - aEmphasisMark.GetWidth()) / 2 ); } if ( mpFontInstance->mnOrientation ) diff --git a/vcl/workben/listglyphs.cxx b/vcl/workben/listglyphs.cxx index 341006d433dd..def2ff818122 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); - basegfx::B2DRectangle aGlyphBounds; + tools::Rectangle aGlyphBounds; pFontInstance->GetGlyphBoundRect(nGlyphIndex, aGlyphBounds, false); std::cout << "Codepoint: " << pFontFace->GetGlyphName(nGlyphIndex) << "; glyph bounds: " << aGlyphBounds << " "; commit 9599b7d969cfe534c17d2249fd8f718dbb39867a Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:20 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:20 2024 +0500 Revert "tdf#160436: fix glyph bounds calculation for vertical glyphs" This reverts commit a2c412dbc17b5c9a7b12639390b58b73cc858e49. diff --git a/vcl/qa/cppunit/logicalfontinstance.cxx b/vcl/qa/cppunit/logicalfontinstance.cxx index 77de9b9b4e3f..1eaf0ebd28db 100644 --- a/vcl/qa/cppunit/logicalfontinstance.cxx +++ b/vcl/qa/cppunit/logicalfontinstance.cxx @@ -46,7 +46,6 @@ 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); @@ -55,14 +54,6 @@ 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); @@ -76,14 +67,6 @@ 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); @@ -96,14 +79,6 @@ 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 9d893b85aa70..6524422397f0 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: 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 + // 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; @@ -191,13 +191,10 @@ bool LogicalFontInstance::GetGlyphBoundRect(sal_GlyphId nID, basegfx::B2DRectang double fMaxY = -(aExtents.y_bearing + aExtents.height) * nYScale; rRect = basegfx::B2DRectangle(fMinX, fMinY, fMaxX, fMaxY); - auto orientation = mnOrientation; - if (bVertical) - orientation += 900_deg10; - if (orientation) + if (mnOrientation && !bVertical) { // Apply font rotation. - rRect.transform(basegfx::utils::createRotateB2DHomMatrix(-toRadians(orientation))); + rRect.transform(basegfx::utils::createRotateB2DHomMatrix(-toRadians(mnOrientation))); } if (mpFontCache) commit 6d49cae9c32f485ddb071f12e3ad98612251c4ef Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:20 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:20 2024 +0500 Revert "Fix UB after 8962141a12c966b2d891829925e6203bf8d51852" This reverts commit 49e6927e3bd44021796b97d1ebb7886923f6cbcc. diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index c8c2d6ca1093..7397748ecd72 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -216,10 +216,7 @@ 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::abs(n) >= 0x1p53 ? n : std::round(n * 1e5) / 1e5; -} +static double trimInsignificant(double n) { return std::round(n * 1e5) / 1e5; } bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const { @@ -246,19 +243,10 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const bRet = true; } } - 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); - } + 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; } commit a65735a23ac3cde6fbfc7b9b38dd03318a5a97ee Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Apr 9 20:55:19 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Apr 9 20:55:19 2024 +0500 Revert "Simplify and drop unused method" This reverts commit ee5584b926cd10ea600a3514242148db5a0a6f18. diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 0f253230c1b4..18de0e684b1c 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -36,6 +36,7 @@ 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 3865f2ebed66..371bdeb9642e 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -147,12 +147,22 @@ 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(); - if (!rPattern.mnHeight || !rPattern.mnWidth) + int nHeight(rPattern.mnHeight); + if (!nHeight) return 1.0; - return rPattern.mnWidth * GetAverageWidthFactor() / rPattern.mnHeight; + float nWidth(rPattern.mnWidth ? rPattern.mnWidth * GetAverageWidthFactor() : nHeight); + return nWidth / nHeight; } void WinFontInstance::ImplInitHbFont(hb_font_t* /*pHbFont*/)