include/basegfx/tuple/Tuple2D.hxx | 6 include/vcl/devicecoordinate.hxx | 11 - include/vcl/outdev.hxx | 10 + include/vcl/vcllayout.hxx | 17 +- sw/qa/extras/layout/layout.cxx | 2 sw/source/core/inc/fntcache.hxx | 8 - sw/source/core/inc/scriptinfo.hxx | 10 - sw/source/core/text/itradj.cxx | 6 sw/source/core/text/porlay.cxx | 10 - sw/source/core/text/portxt.cxx | 4 sw/source/core/txtnode/fntcache.cxx | 201 ++++++++++--------------------- sw/source/uibase/config/usrpref.cxx | 2 vcl/inc/ImplLayoutArgs.hxx | 6 vcl/inc/impglyphitem.hxx | 4 vcl/inc/quartz/salgdi.h | 4 vcl/inc/salgdi.hxx | 11 + vcl/inc/sallayout.hxx | 18 ++ vcl/inc/skia/osx/gdiimpl.hxx | 3 vcl/inc/skia/win/gdiimpl.hxx | 4 vcl/inc/win/DWriteTextRenderer.hxx | 17 +- vcl/inc/win/salgdi.h | 2 vcl/inc/win/winlayout.hxx | 8 - vcl/qt5/QtGraphics_Text.cxx | 21 ++- vcl/quartz/salgdi.cxx | 16 +- vcl/skia/gdiimpl.cxx | 4 vcl/skia/osx/gdiimpl.cxx | 11 + vcl/skia/win/gdiimpl.cxx | 78 ++++++++++-- vcl/skia/x11/textrender.cxx | 18 ++ vcl/source/gdi/CommonSalLayout.cxx | 35 ++--- vcl/source/gdi/pdfwriter_impl.cxx | 28 ++-- vcl/source/gdi/salgdilayout.cxx | 3 vcl/source/gdi/sallayout.cxx | 102 +++++++++------ vcl/source/gdi/virdev.cxx | 2 vcl/source/outdev/font.cxx | 10 - vcl/source/outdev/map.cxx | 25 +++ vcl/source/outdev/outdev.cxx | 19 ++ vcl/source/outdev/text.cxx | 150 ++++++++++++++--------- vcl/source/outdev/textline.cxx | 18 +- vcl/source/text/ImplLayoutArgs.cxx | 18 ++ vcl/unx/generic/gdi/cairotextrender.cxx | 23 ++- vcl/unx/generic/print/genpspgraphics.cxx | 4 vcl/win/gdi/DWriteTextRenderer.cxx | 42 ++---- vcl/win/gdi/winlayout.cxx | 31 +++- 43 files changed, 618 insertions(+), 404 deletions(-)
New commits: commit f793891368d1fbe47b6dc119a89a1cd3e7a40082 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Mon Dec 20 11:38:47 2021 +0000 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Tue Mar 15 08:07:10 2022 +0100 tdf#144862 use resolution independent positions for writer's screen-rendering in favor of pushing it down to the text renderers and leave it to them to optimized as best they can the the rendering to make it look as well as possible. Change-Id: Ic0849c091a36e1a90453771b1c91b8ff706b679e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128418 Tested-by: Caolán McNamara <caol...@redhat.com> Reviewed-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit 4ed26badfd6fd9190cb6e54078b41eb38cb37dca) diff --git a/include/basegfx/tuple/Tuple2D.hxx b/include/basegfx/tuple/Tuple2D.hxx index 2007732543b6..b173ad3033c1 100644 --- a/include/basegfx/tuple/Tuple2D.hxx +++ b/include/basegfx/tuple/Tuple2D.hxx @@ -73,6 +73,12 @@ public: /// Set Y-Coordinate of 2D Tuple void setY(TYPE fY) { mnY = fY; } + /// Adjust X-Coordinate of 2D Tuple + void adjustX(TYPE fX) { mnX += fX; } + + /// Adjust Y-Coordinate of 2D Tuple + void adjustY(TYPE fY) { mnY += fY; } + // comparators with tolerance template <typename T = TYPE, std::enable_if_t<std::is_integral_v<T>, int> = 0> diff --git a/include/vcl/devicecoordinate.hxx b/include/vcl/devicecoordinate.hxx index acece32cc204..bd0bf1ee7963 100644 --- a/include/vcl/devicecoordinate.hxx +++ b/include/vcl/devicecoordinate.hxx @@ -7,23 +7,22 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef INCLUDED_VCL_DEVICE_COORDINATE_HXX -#define INCLUDED_VCL_DEVICE_COORDINATE_HXX +#pragma once #include <config_vcl.h> #include <tools/long.hxx> -#if VCL_FLOAT_DEVICE_PIXEL #include <basegfx/point/b2dpoint.hxx> +typedef basegfx::B2DPoint DevicePoint; + +#if VCL_FLOAT_DEVICE_PIXEL + typedef double DeviceCoordinate; #else /* !VCL_FLOAT_DEVICE_PIXEL */ -#include <basegfx/point/b2ipoint.hxx> typedef sal_Int32 DeviceCoordinate; #endif /* ! Carpet Cushion */ -#endif /* NDef INCLUDED_VCL_DEVICE_COORDINATE_HXX */ - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx index e8011412955c..85670e44dec3 100644 --- a/include/vcl/outdev.hxx +++ b/include/vcl/outdev.hxx @@ -242,6 +242,7 @@ private: Point maRefPoint; AntialiasingFlags mnAntialiasing; LanguageType meTextLanguage; + bool mbTextRenderModeForResolutionIndependentLayout; mutable bool mbMap : 1; mutable bool mbClipRegion : 1; @@ -489,6 +490,10 @@ public: void SetAntialiasing( AntialiasingFlags nMode ); AntialiasingFlags GetAntialiasing() const { return mnAntialiasing; } + // Render glyphs with a mode suitable for rendering of resolution-independent layout positions. + void SetTextRenderModeForResolutionIndependentLayout(bool bMode); + bool GetTextRenderModeForResolutionIndependentLayout() const { return mbTextRenderModeForResolutionIndependentLayout; } + void SetDrawMode( DrawModeFlags nDrawMode ); DrawModeFlags GetDrawMode() const { return mnDrawMode; } @@ -1244,8 +1249,9 @@ public: o3tl::span<const sal_Int32> pLogicDXArray={}, SalLayoutFlags flags = SalLayoutFlags::NONE, vcl::text::TextLayoutCache const* = nullptr, const SalLayoutGlyphs* pGlyphs = nullptr) const; + SAL_DLLPRIVATE vcl::text::ImplLayoutArgs ImplPrepareLayoutArgs( OUString&, const sal_Int32 nIndex, const sal_Int32 nLen, - DeviceCoordinate nPixelWidth, const DeviceCoordinate* pPixelDXArray, + DeviceCoordinate nPixelWidth, SalLayoutFlags flags = SalLayoutFlags::NONE, vcl::text::TextLayoutCache const* = nullptr) const; SAL_DLLPRIVATE std::unique_ptr<SalLayout> @@ -1693,6 +1699,7 @@ public: @returns Physical point on the device. */ SAL_DLLPRIVATE Point ImplLogicToDevicePixel( const Point& rLogicPt ) const; + SAL_DLLPRIVATE DevicePoint ImplLogicToDeviceFontCoordinate(const Point& rLogicPt) const; /** Convert a logical width to a width in units of device pixels. @@ -1705,6 +1712,7 @@ public: @returns Width in units of device pixels. */ SAL_DLLPRIVATE tools::Long ImplLogicWidthToDevicePixel( tools::Long nWidth ) const; + SAL_DLLPRIVATE double ImplLogicWidthToDeviceFontWidth(tools::Long nWidth) const; SAL_DLLPRIVATE DeviceCoordinate LogicWidthToDeviceCoordinate( tools::Long nWidth ) const; diff --git a/include/vcl/vcllayout.hxx b/include/vcl/vcllayout.hxx index 6ea9bc61bfbb..18d4da907375 100644 --- a/include/vcl/vcllayout.hxx +++ b/include/vcl/vcllayout.hxx @@ -70,11 +70,11 @@ class VCL_DLLPUBLIC SalLayout public: virtual ~SalLayout(); // used by upper layers - Point& DrawBase() { return maDrawBase; } - const Point& DrawBase() const { return maDrawBase; } + DevicePoint& DrawBase() { return maDrawBase; } + const DevicePoint& DrawBase() const { return maDrawBase; } Point& DrawOffset() { return maDrawOffset; } const Point& DrawOffset() const { return maDrawOffset; } - Point GetDrawPosition( const Point& rRelative = Point(0,0) ) const; + DevicePoint GetDrawPosition( const DevicePoint& rRelative = DevicePoint(0,0) ) const; virtual bool LayoutText( vcl::text::ImplLayoutArgs&, const SalLayoutGlyphsImpl* ) = 0; // first step of layouting virtual void AdjustLayout( vcl::text::ImplLayoutArgs& ); // adjusting after fallback etc. @@ -84,6 +84,11 @@ public: int GetUnitsPerPixel() const { return mnUnitsPerPixel; } Degree10 GetOrientation() const { return mnOrientation; } + void SetTextRenderModeForResolutionIndependentLayout(bool bTextRenderModeForResolutionIndependentLayout) + { + mbTextRenderModeForResolutionIndependentLayout = bTextRenderModeForResolutionIndependentLayout; + } + // methods using string indexing virtual sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const = 0; virtual DeviceCoordinate FillDXArray( std::vector<DeviceCoordinate>* pDXArray ) const = 0; @@ -92,7 +97,7 @@ public: virtual bool IsKashidaPosValid ( int /*nCharPos*/ ) const { return true; } // i60594 // methods using glyph indexing - virtual bool GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart, + virtual bool GetNextGlyph(const GlyphItem** pGlyph, DevicePoint& rPos, int& nStart, const LogicalFontInstance** ppGlyphFont = nullptr, const vcl::font::PhysicalFontFace** pFallbackFont = nullptr) const = 0; virtual bool GetOutline(basegfx::B2DPolyPolygonVector&) const; @@ -116,7 +121,9 @@ protected: Degree10 mnOrientation; mutable Point maDrawOffset; - Point maDrawBase; + DevicePoint maDrawBase; + + bool mbTextRenderModeForResolutionIndependentLayout; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx index 94edf650a359..267c20770bef 100644 --- a/sw/qa/extras/layout/layout.cxx +++ b/sw/qa/extras/layout/layout.cxx @@ -2823,7 +2823,7 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testBtlrCell) // Without the accompanying fix in place, this test would have failed with 'Expected: 1979; // Actual : 2129', i.e. the gray background of the "AAA2." text was too close to the right edge // of the text portion. Now it's exactly behind the text portion. - assertXPath(pXmlDoc, "//rect[@top='2159']", "left", "1979"); + assertXPath(pXmlDoc, "(//rect)[2]", "left", "1979"); // Without the accompanying fix in place, this test would have failed with 'Expected: 269; // Actual : 0', i.e. the AAA2 frame was not visible due to 0 width. diff --git a/sw/source/core/inc/fntcache.hxx b/sw/source/core/inc/fntcache.hxx index 0bdc4757d9b3..4285165a3336 100644 --- a/sw/source/core/inc/fntcache.hxx +++ b/sw/source/core/inc/fntcache.hxx @@ -66,13 +66,13 @@ extern SwFntObj *pLastFont; */ struct SwTextGlyphsKey { - VclPtr<OutputDevice> m_pOutputDevice; + VclPtr<const OutputDevice> m_pOutputDevice; OUString m_aText; sal_Int32 m_nIndex; sal_Int32 m_nLength; size_t mnHashCode; - SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength); + SwTextGlyphsKey(const OutputDevice* pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength); bool operator==(SwTextGlyphsKey const & rhs) const; }; struct SwTextGlyphsKeyHash @@ -113,6 +113,10 @@ class SwFntObj final : public SwCacheObj /// Cache of already calculated layout glyphs and text widths. SwTextGlyphsMap m_aTextGlyphs; + void GetTextArray(const OutputDevice& rOutputDevice, const OUString& rStr, + std::vector<sal_Int32>& rDXAry, sal_Int32 nIndex, sal_Int32 nLen, + bool bCaching); + static tools::Long s_nPixWidth; static MapMode *s_pPixMap; diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index cd479034ed06..cfe9ef3e55fb 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -281,8 +281,6 @@ public: positions in the kerning array. @param pKernArray The printers kerning array. Optional. - @param pScrArray - The screen kerning array. Optional. @param nStt Start referring to the paragraph. @param nLen @@ -291,7 +289,7 @@ public: The value which has to be added to a kashida opportunity. @return The number of kashida opportunities in the given range */ - sal_Int32 KashidaJustify( sal_Int32* pKernArray, sal_Int32* pScrArray, + sal_Int32 KashidaJustify( sal_Int32* pKernArray, TextFrameIndex nStt, TextFrameIndex nLen, tools::Long nSpaceAdd = 0) const; /** Clears array of kashidas marked as invalid @@ -354,8 +352,6 @@ public: The String @param pKernArray The printers kerning array. Optional. - @param pScrArray - The screen kerning array. Optional. @param nIdx Start referring to the paragraph. @param nLen @@ -365,7 +361,7 @@ public: @return The number of extra spaces in the given range */ static TextFrameIndex ThaiJustify( const OUString& rText, sal_Int32* pKernArray, - sal_Int32* pScrArray, TextFrameIndex nIdx, + TextFrameIndex nIdx, TextFrameIndex nLen, TextFrameIndex nNumberOfBlanks = TextFrameIndex(0), tools::Long nSpaceAdd = 0 ); @@ -374,7 +370,7 @@ public: TextFrameIndex nPos, TextFrameIndex nEnd, LanguageType aLang); static void CJKJustify( const OUString& rText, sal_Int32* pKernArray, - sal_Int32* pScrArray, TextFrameIndex nStt, + TextFrameIndex nStt, TextFrameIndex nLen, LanguageType aLang, tools::Long nSpaceAdd, bool bIsSpaceStop ); diff --git a/sw/source/core/text/itradj.cxx b/sw/source/core/text/itradj.cxx index d664602bf3ce..a952ce7649c2 100644 --- a/sw/source/core/text/itradj.cxx +++ b/sw/source/core/text/itradj.cxx @@ -122,7 +122,7 @@ static bool lcl_CheckKashidaPositions( SwScriptInfo& rSI, SwTextSizeInfo& rInf, // total number of kashida positions, or the number of kashida positions after some positions // have been dropped. // Here we want the clean total, which is OK: We have called ClearKashidaInvalid() before. - rKashidas = rSI.KashidaJustify ( nullptr, nullptr, rItr.GetStart(), rItr.GetLength() ); + rKashidas = rSI.KashidaJustify(nullptr, rItr.GetStart(), rItr.GetLength()); if (rKashidas <= 0) // nothing to do return true; @@ -147,7 +147,7 @@ static bool lcl_CheckKashidaPositions( SwScriptInfo& rSI, SwTextSizeInfo& rInf, if (nNext == TextFrameIndex(COMPLETE_STRING) || nNext > nEnd) nNext = nEnd; - sal_Int32 nKashidasInAttr = rSI.KashidaJustify ( nullptr, nullptr, nIdx, nNext - nIdx ); + sal_Int32 nKashidasInAttr = rSI.KashidaJustify(nullptr, nIdx, nNext - nIdx); if (nKashidasInAttr > 0) { // Kashida glyph looks suspicious, skip Kashida justification @@ -212,7 +212,7 @@ static bool lcl_CheckKashidaWidth ( SwScriptInfo& rSI, SwTextSizeInfo& rInf, SwT if (nNext == TextFrameIndex(COMPLETE_STRING) || nNext > nEnd) nNext = nEnd; - sal_Int32 nKashidasInAttr = rSI.KashidaJustify ( nullptr, nullptr, nIdx, nNext - nIdx ); + sal_Int32 nKashidasInAttr = rSI.KashidaJustify(nullptr, nIdx, nNext - nIdx); tools::Long nFontMinKashida = rInf.GetOut()->GetMinKashida(); if ( nFontMinKashida && nKashidasInAttr > 0 && SwScriptInfo::IsArabicText( rInf.GetText(), nIdx, nNext - nIdx ) ) diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 3db5d2ab0ac3..bd9d6a0e143c 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -2183,7 +2183,6 @@ tools::Long SwScriptInfo::Compress(sal_Int32* pKernArray, TextFrameIndex nIdx, T // have been dropped, depending on the state of the m_KashidaInvalid set. sal_Int32 SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, - sal_Int32* pScrArray, TextFrameIndex const nStt, TextFrameIndex const nLen, tools::Long nSpaceAdd ) const @@ -2253,8 +2252,6 @@ sal_Int32 SwScriptInfo::KashidaJustify( sal_Int32* pKernArray, while ( nArrayPos < nArrayEnd ) { pKernArray[ sal_Int32(nArrayPos) ] += nKashAdd; - if ( pScrArray ) - pScrArray[ sal_Int32(nArrayPos) ] += nKashAdd; ++nArrayPos; } nKashAdd += nSpaceAdd; @@ -2442,7 +2439,7 @@ void SwScriptInfo::MarkKashidasInvalid(sal_Int32 const nCnt, } TextFrameIndex SwScriptInfo::ThaiJustify( const OUString& rText, sal_Int32* pKernArray, - sal_Int32* pScrArray, TextFrameIndex const nStt, + TextFrameIndex const nStt, TextFrameIndex const nLen, TextFrameIndex nNumberOfBlanks, tools::Long nSpaceAdd ) @@ -2474,7 +2471,6 @@ TextFrameIndex SwScriptInfo::ThaiJustify( const OUString& rText, sal_Int32* pKer } if ( pKernArray ) pKernArray[ nI ] += nSpaceSum; - if ( pScrArray ) pScrArray[ nI ] += nSpaceSum; } return nCnt; @@ -2775,7 +2771,7 @@ TextFrameIndex SwScriptInfo::CountCJKCharacters(const OUString &rText, } void SwScriptInfo::CJKJustify( const OUString& rText, sal_Int32* pKernArray, - sal_Int32* pScrArray, TextFrameIndex const nStt, + TextFrameIndex const nStt, TextFrameIndex const nLen, LanguageType aLang, tools::Long nSpaceAdd, bool bIsSpaceStop ) { @@ -2798,8 +2794,6 @@ void SwScriptInfo::CJKJustify( const OUString& rText, sal_Int32* pKernArray, nSpaceSum += nSpaceAdd; } pKernArray[ nI ] += nSpaceSum; - if ( pScrArray ) - pScrArray[ nI ] += nSpaceSum; } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx index 7def7badcc7a..219036aa834d 100644 --- a/sw/source/core/text/portxt.cxx +++ b/sw/source/core/text/portxt.cxx @@ -113,7 +113,7 @@ static TextFrameIndex lcl_AddSpace(const SwTextSizeInfo &rInf, { if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() ) { - const sal_Int32 nKashRes = pSI->KashidaJustify( nullptr, nullptr, nPos, nEnd - nPos ); + const sal_Int32 nKashRes = pSI->KashidaJustify(nullptr, nPos, nEnd - nPos); // i60591: need to check result of KashidaJustify // determine if kashida justification is applicable if (nKashRes != -1) @@ -129,7 +129,7 @@ static TextFrameIndex lcl_AddSpace(const SwTextSizeInfo &rInf, if ( LANGUAGE_THAI == aLang ) { - nCnt = SwScriptInfo::ThaiJustify( *pStr, nullptr, nullptr, nPos, nEnd - nPos ); + nCnt = SwScriptInfo::ThaiJustify(*pStr, nullptr, nPos, nEnd - nPos); const SwLinePortion* pPor = rPor.GetNextPortion(); if ( pPor && ( pPor->IsKernPortion() || diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx index 93e83c2013e9..6ceaeaf99206 100644 --- a/sw/source/core/txtnode/fntcache.cxx +++ b/sw/source/core/txtnode/fntcache.cxx @@ -77,11 +77,11 @@ static vcl::DeleteOnDeinit< VclPtr<OutputDevice> > s_pFntObjPixOut {}; * Defines a substring on a given output device, to be used as an std::unordered_map<> * key. */ -SwTextGlyphsKey::SwTextGlyphsKey(VclPtr<OutputDevice> const& pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength) +SwTextGlyphsKey::SwTextGlyphsKey(const OutputDevice* pOutputDevice, const OUString & sText, sal_Int32 nIndex, sal_Int32 nLength) : m_pOutputDevice(pOutputDevice), m_aText(sText), m_nIndex(nIndex), m_nLength(nLength) { mnHashCode = 0; - o3tl::hash_combine(mnHashCode, pOutputDevice.get()); + o3tl::hash_combine(mnHashCode, pOutputDevice); o3tl::hash_combine(mnHashCode, m_nIndex); o3tl::hash_combine(mnHashCode, m_nLength); if(m_nLength >= 0 && m_nIndex >= 0 && m_nIndex + m_nLength <= m_aText.getLength()) @@ -855,6 +855,18 @@ static void lcl_DrawLineForWrongListData( rInf.GetOut().Pop(); } +void SwFntObj::GetTextArray(const OutputDevice& rDevice, const OUString& rStr, std::vector<sal_Int32>& rDXAry, + sal_Int32 nIndex, sal_Int32 nLen, bool bCaching) +{ + SalLayoutGlyphs* pLayoutCache = nullptr; + if (bCaching) + { + SwTextGlyphsKey aGlyphsKey{&rDevice, rStr, nIndex, nLen}; + pLayoutCache = GetCachedSalLayoutGlyphs(aGlyphsKey); + } + rDevice.GetTextArray(rStr, &rDXAry, nIndex, nLen, nullptr, pLayoutCache); +} + void SwFntObj::DrawText( SwDrawTextInfo &rInf ) { OSL_ENSURE( rInf.GetShell(), "SwFntObj::DrawText without shell" ); @@ -1031,11 +1043,11 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) std::vector<sal_Int32> aKernArray; if ( m_pPrinter ) - m_pPrinter->GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false); else - rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false); // Change the average width per character to an appropriate grid width // basically get the ratio of the avg width to the grid unit width, then @@ -1138,11 +1150,11 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) std::vector<sal_Int32> aKernArray; if ( m_pPrinter ) - m_pPrinter->GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false); else - rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false); if ( bSwitchH2V ) rInf.GetFrame()->SwitchHorizontalToVertical( aTextOriginPos ); if ( rInf.GetSpace() || rInf.GetKanaComp()) @@ -1278,8 +1290,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if( rInf.GetSpace() || rInf.GetKanaComp() ) { std::vector<sal_Int32> aKernArray; - rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false); if( bStretch ) { @@ -1337,7 +1349,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if (!MsLangId::isKorean(aLang)) { - SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(), nullptr, + SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() ); bSpecialJust = true; @@ -1351,7 +1363,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) { if ( pSI && pSI->CountKashida() && - pSI->KashidaJustify( aKernArray.data(), nullptr, rInf.GetIdx(), + pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ) != -1 ) { bSpecialJust = true; @@ -1369,7 +1381,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) { // Use rInf.GetSpace() because it has more precision than // nSpaceAdd: - SwScriptInfo::ThaiJustify( rInf.GetText(), aKernArray.data(), nullptr, + SwScriptInfo::ThaiJustify( rInf.GetText(), aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), rInf.GetNumberOfBlanks(), rInf.GetSpace() ); @@ -1478,6 +1490,10 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) else { + const bool bOrigTextRenderModeForResolutionIndependentLayout(rInf.GetOut().GetTextRenderModeForResolutionIndependentLayout()); + // set text render mode to suit use of resolution independent text layout + rInf.GetOut().SetTextRenderModeForResolutionIndependentLayout(true); + const OUString* pStr = &rInf.GetText(); OUString aStr; @@ -1487,14 +1503,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) bBullet = false; std::vector<sal_Int32> aKernArray; CreateScrFont( *rInf.GetShell(), rInf.GetOut() ); - tools::Long nScrPos; - - // get screen array - std::vector<sal_Int32> aScrArray; - SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) }; - SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); - rInf.GetOut().GetTextArray( rInf.GetText(), &aScrArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs); // OLE: no printer available // OSL_ENSURE( pPrinter, "DrawText needs pPrinter" ) @@ -1506,15 +1514,13 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) ) m_pPrinter->SetFont( *m_pPrtFont ); } - aGlyphsKey = SwTextGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) }; - pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); - m_pPrinter->GetTextArray(rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs); + GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), true); } else { - rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), true); } // Modify Printer and ScreenArrays for special justifications @@ -1532,10 +1538,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) pSI && pSI->CountCompChg() && lcl_IsMonoSpaceFont( rInf.GetOut() ) ) { - Point aTmpPos( aTextOriginPos ); - pSI->Compress( aScrArray.data(), rInf.GetIdx(), rInf.GetLen(), - rInf.GetKanaComp(), - o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTmpPos ); pSI->Compress( aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), rInf.GetKanaComp(), o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()), lcl_IsFullstopCentered( rInf.GetOut() ), &aTextOriginPos ); @@ -1548,7 +1550,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if (!MsLangId::isKorean(aLang)) { - SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(), aScrArray.data(), + SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() ); nSpaceAdd = 0; @@ -1561,7 +1563,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) { if ( pSI && pSI->CountKashida() && - pSI->KashidaJustify( aKernArray.data(), aScrArray.data(), rInf.GetIdx(), + pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ) != -1 ) nSpaceAdd = 0; else @@ -1577,7 +1579,7 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) if ( LANGUAGE_THAI == aLang ) { SwScriptInfo::ThaiJustify( rInf.GetText(), aKernArray.data(), - aScrArray.data(), rInf.GetIdx(), + rInf.GetIdx(), rInf.GetLen(), rInf.GetNumberOfBlanks(), rInf.GetSpace() ); @@ -1588,8 +1590,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) } } - nScrPos = aScrArray[ 0 ]; - if( bBullet ) { // !!! HACK !!! @@ -1661,13 +1661,6 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) } else { - sal_Unicode nCh; - - // In case of Pair Kerning the printer influence on the positioning - // grows - const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3; - const int nDiv = nMul+1; - // nSpaceSum contains the sum of the intermediate space distributed // among Spaces by the Justification. // The Spaces themselves will be positioned in the middle of the @@ -1686,43 +1679,25 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) nSpaceSum = nHalfSpace; for (sal_Int32 i = 1; i < sal_Int32(nCnt); ++i, nKernSum += rInf.GetKern()) { - nCh = rInf.GetText()[sal_Int32(rInf.GetIdx()) + i]; - - tools::Long nScr = aScrArray[ i ] - aScrArray[ i - 1 ]; + sal_Unicode nCh = rInf.GetText()[sal_Int32(rInf.GetIdx()) + i]; - // If there is an (ex-)Space before us, position optimally, - // i.e., our right margin to the 100% printer position; - // if we _are_ an ex-Space, position us left-aligned to the - // printer position. - if ( nCh == CH_BLANK ) + // Apply SpaceSum + if (cChPrev == CH_BLANK) { - nScrPos = aKernArray[i-1] + nScr; + // no Pixel is lost: + nSpaceSum += nOtherHalf; + } - if ( cChPrev == CH_BLANK ) - nSpaceSum += nOtherHalf; + if (nCh == CH_BLANK) + { if (i + 1 == sal_Int32(nCnt)) nSpaceSum += nSpaceAdd; else nSpaceSum += nHalfSpace; } - else - { - if ( cChPrev == CH_BLANK ) - { - nScrPos = aKernArray[i-1] + nScr; - // no Pixel is lost: - nSpaceSum += nOtherHalf; - } - else if ( cChPrev == '-' ) - nScrPos = aKernArray[i-1] + nScr; - else - { - nScrPos += nScr; - nScrPos = ( nMul * nScrPos + aKernArray[i] ) / nDiv; - } - } + cChPrev = nCh; - aKernArray[i-1] = nScrPos - nScr + nKernSum + nSpaceSum; + aKernArray[i-1] += nKernSum + nSpaceSum; // In word line mode and for Arabic, we disabled the half space trick. If a portion // ends with a blank, the full nSpaceAdd value has been added to the character in // front of the blank. This leads to painting artifacts, therefore we remove the @@ -1843,8 +1818,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) sal_Int32 nTmpIdx = bBullet ? (rInf.GetIdx() ? 1 : 0) : sal_Int32(rInf.GetIdx()); - aGlyphsKey = SwTextGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, nLen }; - pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); + SwTextGlyphsKey aGlyphsKey{ &rInf.GetOut(), *pStr, nTmpIdx, nLen }; + SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); rInf.GetOut().DrawTextArray( aTextOriginPos, *pStr, aKernArray, nTmpIdx , nLen, SalLayoutFlags::NONE, pGlyphs ); if (bBullet) @@ -1894,6 +1869,8 @@ void SwFntObj::DrawText( SwDrawTextInfo &rInf ) } } } + + rInf.GetOut().SetTextRenderModeForResolutionIndependentLayout(bOrigTextRenderModeForResolutionIndependentLayout); } } @@ -1997,17 +1974,14 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) { if( !m_pPrtFont->IsSameInstance( m_pPrinter->GetFont() ) ) m_pPrinter->SetFont(*m_pPrtFont); - aTextSize.setWidth( m_pPrinter->GetTextWidth( rInf.GetText(), - sal_Int32(rInf.GetIdx()), sal_Int32(nLn))); aTextSize.setHeight( m_pPrinter->GetTextHeight() ); std::vector<sal_Int32> aKernArray; CreateScrFont( *rInf.GetShell(), rInf.GetOut() ); if( !GetScrFont()->IsSameInstance( rInf.GetOut().GetFont() ) ) rInf.GetOut().SetFont( *m_pScrFont ); - tools::Long nScrPos; - m_pPrinter->GetTextArray(rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(nLn)); + GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(nLn), false); if( bCompress ) rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( aKernArray.data(), rInf.GetIdx(), nLn, rInf.GetKanaComp(), @@ -2015,50 +1989,7 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) else rInf.SetKanaDiff( 0 ); - if ( rInf.GetKanaDiff() ) - nScrPos = aKernArray[ sal_Int32(nLn) - 1 ]; - else - { - std::vector<sal_Int32> aScrArray; - rInf.GetOut().GetTextArray( rInf.GetText(), &aScrArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); - nScrPos = aScrArray[ 0 ]; - TextFrameIndex nCnt(rInf.GetText().getLength()); - if ( nCnt < rInf.GetIdx() ) - nCnt = TextFrameIndex(0); // assert??? - else - nCnt = nCnt - rInf.GetIdx(); - nCnt = std::min(nCnt, nLn); - sal_Unicode nChPrev = rInf.GetText()[ sal_Int32(rInf.GetIdx()) ]; - - sal_Unicode nCh; - - // In case of Pair Kerning the printer influence on the positioning - // grows - const int nMul = m_pPrtFont->GetKerning() != FontKerning::NONE ? 1 : 3; - const int nDiv = nMul+1; - for (sal_Int32 i = 1; i < sal_Int32(nCnt); i++) - { - nCh = rInf.GetText()[ sal_Int32(rInf.GetIdx()) + i ]; - tools::Long nScr = aScrArray[ i ] - aScrArray[ i - 1 ]; - if ( nCh == CH_BLANK ) - nScrPos = aKernArray[i-1]+nScr; - else - { - if ( nChPrev == CH_BLANK || nChPrev == '-' ) - nScrPos = aKernArray[i-1]+nScr; - else - { - nScrPos += nScr; - nScrPos = ( nMul * nScrPos + aKernArray[i] ) / nDiv; - } - } - nChPrev = nCh; - aKernArray[i-1] = nScrPos - nScr; - } - } - - aTextSize.setWidth( nScrPos ); + aTextSize.setWidth(aKernArray[sal_Int32(nLn) - 1]); } else { @@ -2067,8 +1998,8 @@ Size SwFntObj::GetTextSize( SwDrawTextInfo& rInf ) if( bCompress ) { std::vector<sal_Int32> aKernArray; - rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(nLn)); + GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(nLn), false); rInf.SetKanaDiff( rInf.GetScriptInfo()->Compress( aKernArray.data(), rInf.GetIdx(), nLn, rInf.GetKanaComp(), o3tl::narrowing<sal_uInt16>(m_aFont.GetFontSize().Height()) ,lcl_IsFullstopCentered( rInf.GetOut() ) ) ); @@ -2110,14 +2041,14 @@ TextFrameIndex SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf) { m_pPrinter->SetLayoutMode( rInf.GetOut().GetLayoutMode() ); m_pPrinter->SetDigitLanguage( rInf.GetOut().GetDigitLanguage() ); - SwTextGlyphsKey aGlyphsKey{ m_pPrinter, rInf.GetText(), sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()) }; - SalLayoutGlyphs* pGlyphs = GetCachedSalLayoutGlyphs(aGlyphsKey); - m_pPrinter->GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), nullptr, pGlyphs); + GetTextArray(*m_pPrinter, rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), true); } else - rInf.GetOut().GetTextArray( rInf.GetText(), &aKernArray, - sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen())); + { + GetTextArray(rInf.GetOut(), rInf.GetText(), aKernArray, + sal_Int32(rInf.GetIdx()), sal_Int32(rInf.GetLen()), false); + } const SwScriptInfo* pSI = rInf.GetScriptInfo(); if ( rInf.GetFont() && rInf.GetLen() ) @@ -2142,7 +2073,7 @@ TextFrameIndex SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf) if (!MsLangId::isKorean(aLang)) { - SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(), nullptr, + SwScriptInfo::CJKJustify( rInf.GetText(), aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), aLang, nSpaceAdd, rInf.IsSpaceStop() ); nSpaceAdd = 0; @@ -2156,7 +2087,7 @@ TextFrameIndex SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf) if ( SwScriptInfo::IsArabicText( rInf.GetText(), rInf.GetIdx(), rInf.GetLen() ) ) { if ( pSI && pSI->CountKashida() && - pSI->KashidaJustify( aKernArray.data(), nullptr, rInf.GetIdx(), rInf.GetLen(), + pSI->KashidaJustify( aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), nSpaceAdd ) != -1 ) nSpaceAdd = 0; } @@ -2169,7 +2100,7 @@ TextFrameIndex SwFntObj::GetModelPositionForViewPoint(SwDrawTextInfo &rInf) if ( LANGUAGE_THAI == aLang ) { - SwScriptInfo::ThaiJustify( rInf.GetText(), aKernArray.data(), nullptr, + SwScriptInfo::ThaiJustify( rInf.GetText(), aKernArray.data(), rInf.GetIdx(), rInf.GetLen(), rInf.GetNumberOfBlanks(), rInf.GetSpace() ); diff --git a/sw/source/uibase/config/usrpref.cxx b/sw/source/uibase/config/usrpref.cxx index 0c759a78cf94..e7b43df54c34 100644 --- a/sw/source/uibase/config/usrpref.cxx +++ b/sw/source/uibase/config/usrpref.cxx @@ -388,7 +388,7 @@ void SwLayoutViewConfig::Load() case 16: m_rParent.SetViewLayoutBookMode(bSet); break;// "ViewLayout/BookMode", case 17: m_rParent.SetDefaultPageMode(bSet,true); break;// "Other/IsSquaredPageMode", case 18: m_rParent.SetApplyCharUnit(bSet, true); break;// "Other/ApplyUserChar" - case 19: m_rParent.SetShowScrollBarTips(bSet); break;// "Window/ShowScrollBarTips", + case 29: m_rParent.SetShowScrollBarTips(bSet); break;// "Window/ShowScrollBarTips", } } } diff --git a/vcl/inc/ImplLayoutArgs.hxx b/vcl/inc/ImplLayoutArgs.hxx index 865470b7897a..fa94562ca86c 100644 --- a/vcl/inc/ImplLayoutArgs.hxx +++ b/vcl/inc/ImplLayoutArgs.hxx @@ -35,7 +35,8 @@ public: vcl::text::TextLayoutCache const* m_pTextLayoutCache; // positioning related inputs - const DeviceCoordinate* mpDXArray; // in pixel units + const DeviceCoordinate* mpDXArray; // in integer pixel units + const double* mpAltNaturalDXArray; // in floating point pixel units DeviceCoordinate mnLayoutWidth; // in pixel units Degree10 mnOrientation; // in 0-3600 system @@ -48,12 +49,15 @@ public: void SetLayoutWidth(DeviceCoordinate nWidth); void SetDXArray(const DeviceCoordinate* pDXArray); + void SetAltNaturalDXArray(const double* pDXArray); void SetOrientation(Degree10 nOrientation); void ResetPos(); bool GetNextPos(int* nCharPos, bool* bRTL); bool GetNextRun(int* nMinRunPos, int* nEndRunPos, bool* bRTL); void AddFallbackRun(int nMinRunPos, int nEndRunPos, bool bRTL); + bool HasDXArray() const { return mpDXArray || mpAltNaturalDXArray; } + // methods used by BiDi and glyph fallback bool HasFallbackRun() const; bool PrepareFallback(const SalLayoutGlyphsImpl* pGlyphsImpl); diff --git a/vcl/inc/impglyphitem.hxx b/vcl/inc/impglyphitem.hxx index ca9f7cf5c052..4fc48f1ca2a2 100644 --- a/vcl/inc/impglyphitem.hxx +++ b/vcl/inc/impglyphitem.hxx @@ -58,10 +58,10 @@ class VCL_DLLPUBLIC GlyphItem GlyphItemFlags m_nFlags; public: - Point m_aLinearPos; // absolute position of non rotated string + DevicePoint m_aLinearPos; // absolute position of non rotated string sal_Int32 m_nNewWidth; // width after adjustments - GlyphItem(int nCharPos, int nCharCount, sal_GlyphId aGlyphId, const Point& rLinearPos, + GlyphItem(int nCharPos, int nCharCount, sal_GlyphId aGlyphId, const DevicePoint& rLinearPos, GlyphItemFlags nFlags, int nOrigWidth, int nXOffset) : m_nOrigWidth(nOrigWidth) , m_nCharPos(nCharPos) diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index f0aa925c6083..569a14a6d3fc 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -297,7 +297,7 @@ public: const tools::Rectangle &rControlRegion, ControlState nState, const ImplControlValue &aValue) = 0; - virtual void drawTextLayout(const GenericSalLayout& layout) = 0; + virtual void drawTextLayout(const GenericSalLayout& layout, bool bTextRenderModeForResolutionIndependentLayout) = 0; virtual void Flush() {} virtual void Flush( const tools::Rectangle& ) {} protected: @@ -446,7 +446,7 @@ public: ControlState nState, const ImplControlValue &aValue) override; - virtual void drawTextLayout(const GenericSalLayout& layout) override; + virtual void drawTextLayout(const GenericSalLayout& layout, bool bTextRenderModeForResolutionIndependentLayout) override; bool supportsOperation(OutDevSupportType eType) const override; }; diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 716c9aa934a6..6f9ee67f69a4 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -96,6 +96,16 @@ public: return m_bAntiAlias; } + void setTextRenderModeForResolutionIndependentLayout(bool bNew) + { + m_bTextRenderModeForResolutionIndependentLayout = bNew; + } + + bool getTextRenderModeForResolutionIndependentLayoutEnabled() const + { + return m_bTextRenderModeForResolutionIndependentLayout; + } + // public SalGraphics methods, the interface to the independent vcl part // get device resolution @@ -631,6 +641,7 @@ private: protected: /// flags which hold the SetAntialiasing() value from OutputDevice bool m_bAntiAlias : 1; + bool m_bTextRenderModeForResolutionIndependentLayout : 1; inline tools::Long GetDeviceWidth(const OutputDevice& rOutDev) const; diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx index ab29a2022985..847c22ace091 100644 --- a/vcl/inc/sallayout.hxx +++ b/vcl/inc/sallayout.hxx @@ -64,7 +64,7 @@ public: sal_Int32 GetTextBreak(DeviceCoordinate nMaxWidth, DeviceCoordinate nCharExtra, int nFactor) const override; DeviceCoordinate FillDXArray(std::vector<DeviceCoordinate>* pDXArray) const override; void GetCaretPositions(int nArraySize, sal_Int32* pCaretXArray) const override; - bool GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart, + bool GetNextGlyph(const GlyphItem** pGlyph, DevicePoint& rPos, int& nStart, const LogicalFontInstance** ppGlyphFont = nullptr, const vcl::font::PhysicalFontFace** pFallbackFont = nullptr) const override; bool GetOutline(basegfx::B2DPolyPolygonVector&) const override; @@ -82,7 +82,11 @@ public: void SetIncomplete(bool bIncomplete); -public: + template<typename DC> + void ImplAdjustMultiLayout(vcl::text::ImplLayoutArgs& rArgs, + vcl::text::ImplLayoutArgs& rMultiArgs, + const DC* pMultiDXArray); + virtual ~MultiSalLayout() override; private: @@ -97,7 +101,10 @@ private: class VCL_DLLPUBLIC GenericSalLayout : public SalLayout { - friend void MultiSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs&); + template<typename DC> friend void MultiSalLayout::ImplAdjustMultiLayout( + vcl::text::ImplLayoutArgs& rArgs, + vcl::text::ImplLayoutArgs& rMultiArgs, + const DC* pMultiDXArray); public: GenericSalLayout(LogicalFontInstance&); @@ -121,7 +128,7 @@ public: LogicalFontInstance& GetFont() const { return *m_GlyphItems.GetFont(); } - bool GetNextGlyph(const GlyphItem** pGlyph, Point& rPos, int& nStart, + bool GetNextGlyph(const GlyphItem** pGlyph, DevicePoint& rPos, int& nStart, const LogicalFontInstance** ppGlyphFont = nullptr, const vcl::font::PhysicalFontFace** pFallbackFont = nullptr) const override; @@ -136,7 +143,8 @@ private: GenericSalLayout( const GenericSalLayout& ) = delete; GenericSalLayout& operator=( const GenericSalLayout& ) = delete; - void ApplyDXArray(const DeviceCoordinate*, SalLayoutFlags nLayoutFlags); + template<typename DC> + void ApplyDXArray(const DC*, SalLayoutFlags nLayoutFlags); void Justify(DeviceCoordinate nNewWidth); void ApplyAsianKerning(const OUString& rStr); diff --git a/vcl/inc/skia/osx/gdiimpl.hxx b/vcl/inc/skia/osx/gdiimpl.hxx index e59aa60f56df..71baf24625fc 100644 --- a/vcl/inc/skia/osx/gdiimpl.hxx +++ b/vcl/inc/skia/osx/gdiimpl.hxx @@ -38,7 +38,8 @@ public: const tools::Rectangle& rControlRegion, ControlState nState, const ImplControlValue& aValue) override; - virtual void drawTextLayout(const GenericSalLayout& layout) override; + virtual void drawTextLayout(const GenericSalLayout& layout, + bool bTextRenderModeForResolutionIndependentLayout) override; virtual void Flush() override; virtual void Flush(const tools::Rectangle&) override; diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx index 58043e5f6a83..a8897d0d7c20 100644 --- a/vcl/inc/skia/win/gdiimpl.hxx +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -25,6 +25,8 @@ #include <SkFont.h> #include <SkFontMgr.h> +#include <dwrite_3.h> + class SkTypeface; class ControlCacheKey; @@ -64,6 +66,8 @@ protected: static void initFontInfo(); inline static sal::systools::COMReference<IDWriteFactory> dwriteFactory; inline static sal::systools::COMReference<IDWriteGdiInterop> dwriteGdiInterop; + inline static sal::systools::COMReference<IDWriteFontSetBuilder> dwriteFontSetBuilder; + inline static sal::systools::COMReference<IDWriteFontCollection1> dwritePrivateCollection; inline static sk_sp<SkFontMgr> dwriteFontMgr; inline static bool dwriteDone = false; static SkFont::Edging fontEdging; diff --git a/vcl/inc/win/DWriteTextRenderer.hxx b/vcl/inc/win/DWriteTextRenderer.hxx index 6e097546d1e2..b64cc48a1c6a 100644 --- a/vcl/inc/win/DWriteTextRenderer.hxx +++ b/vcl/inc/win/DWriteTextRenderer.hxx @@ -37,12 +37,13 @@ enum class D2DTextAntiAliasMode class D2DWriteTextOutRenderer : public TextOutRenderer { public: - explicit D2DWriteTextOutRenderer(); + explicit D2DWriteTextOutRenderer(bool bRenderingModeNatural); virtual ~D2DWriteTextOutRenderer() override; - bool operator ()(GenericSalLayout const &rLayout, + bool operator()(GenericSalLayout const &rLayout, SalGraphics &rGraphics, - HDC hDC) override; + HDC hDC, + bool bRenderingModeNatural) override; HRESULT BindDC(HDC hDC, tools::Rectangle const & rRect = tools::Rectangle(0, 0, 1, 1)); @@ -54,12 +55,13 @@ public: IDWriteFontFace * GetFontFace() const { return mpFontFace; } float GetEmHeight() const { return mlfEmHeight; } - HRESULT CreateRenderTarget(); + HRESULT CreateRenderTarget(bool bRenderingModeNatural); bool Ready() const; - void applyTextAntiAliasMode(); - void changeTextAntiAliasMode(D2DTextAntiAliasMode eMode); + void applyTextAntiAliasMode(bool bRenderingModeNatural); + + bool GetRenderingModeNatural() const { return mbRenderingModeNatural; } private: // This is a singleton object disable copy ctor and assignment operator @@ -67,7 +69,7 @@ private: D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete; bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const; - bool performRender(GenericSalLayout const &rLayout, SalGraphics &rGraphics, HDC hDC, bool& bRetry); + bool performRender(GenericSalLayout const &rLayout, SalGraphics &rGraphics, HDC hDC, bool& bRetry, bool bRenderingModeNatural); ID2D1Factory * mpD2DFactory; IDWriteFactory * mpDWriteFactory; @@ -78,6 +80,7 @@ private: IDWriteFontFace * mpFontFace; float mlfEmHeight; HDC mhDC; + bool mbRenderingModeNatural; D2DTextAntiAliasMode meTextAntiAliasMode; }; diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index b472ece0a256..7833f988bd18 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -316,7 +316,7 @@ public: private: // local helpers - void DrawTextLayout(const GenericSalLayout&, HDC, bool bUseDWrite); + void DrawTextLayout(const GenericSalLayout&, HDC, bool bUseDWrite, bool bRenderingModeNatural); public: // public SalGraphics methods, the interface to the independent vcl part diff --git a/vcl/inc/win/winlayout.hxx b/vcl/inc/win/winlayout.hxx index 0b43ef4eeca1..5f56fe6b0c5e 100644 --- a/vcl/inc/win/winlayout.hxx +++ b/vcl/inc/win/winlayout.hxx @@ -75,13 +75,14 @@ protected: TextOutRenderer & operator = (const TextOutRenderer &) = delete; public: - static TextOutRenderer & get(bool bUseDWrite); + static TextOutRenderer & get(bool bUseDWrite, bool bRenderingModeNatural); virtual ~TextOutRenderer() = default; virtual bool operator ()(GenericSalLayout const &rLayout, SalGraphics &rGraphics, - HDC hDC) = 0; + HDC hDC, + bool bRenderingModeNatural) = 0; }; class ExTextOutRenderer : public TextOutRenderer @@ -94,7 +95,8 @@ public: bool operator ()(GenericSalLayout const &rLayout, SalGraphics &rGraphics, - HDC hDC) override; + HDC hDC, + bool bRenderingModeNatural) override; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qt5/QtGraphics_Text.cxx b/vcl/qt5/QtGraphics_Text.cxx index b509c2a946bd..02158fca29db 100644 --- a/vcl/qt5/QtGraphics_Text.cxx +++ b/vcl/qt5/QtGraphics_Text.cxx @@ -294,11 +294,26 @@ std::unique_ptr<GenericSalLayout> QtGraphics::GetTextLayout(int nFallbackLevel) return std::make_unique<QtCommonSalLayout>(*m_pTextStyle[nFallbackLevel]); } +static QRawFont GetRawFont(const QFont& rFont, bool bWithoutHintingInTextDirection) +{ + QFont::HintingPreference eHinting = rFont.hintingPreference(); + bool bAllowedHintStyle + = !bWithoutHintingInTextDirection + || (eHinting == QFont::PreferNoHinting || eHinting == QFont::PreferVerticalHinting); + if (bWithoutHintingInTextDirection && !bAllowedHintStyle) + { + QFont aFont(rFont); + aFont.setHintingPreference(QFont::PreferVerticalHinting); + return QRawFont::fromFont(aFont); + } + return QRawFont::fromFont(rFont); +} + void QtGraphics::DrawTextLayout(const GenericSalLayout& rLayout) { const QtFont* pFont = static_cast<const QtFont*>(&rLayout.GetFont()); assert(pFont); - QRawFont aRawFont(QRawFont::fromFont(*pFont)); + QRawFont aRawFont(GetRawFont(*pFont, getTextRenderModeForResolutionIndependentLayoutEnabled())); QVector<quint32> glyphIndexes; QVector<QPointF> positions; @@ -311,13 +326,13 @@ void QtGraphics::DrawTextLayout(const GenericSalLayout& rLayout) if (nOrientation) pQtLayout->SetOrientation(0_deg10); - Point aPos; + DevicePoint aPos; const GlyphItem* pGlyph; int nStart = 0; while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) { glyphIndexes.push_back(pGlyph->glyphId()); - positions.push_back(QPointF(aPos.X(), aPos.Y())); + positions.push_back(QPointF(aPos.getX(), aPos.getY())); } // seems to be common to try to layout an empty string... diff --git a/vcl/quartz/salgdi.cxx b/vcl/quartz/salgdi.cxx index 9928cc4df3a2..b8a3ac375655 100644 --- a/vcl/quartz/salgdi.cxx +++ b/vcl/quartz/salgdi.cxx @@ -363,10 +363,10 @@ bool AquaSalGraphics::AddTempDevFont(vcl::font::PhysicalFontCollection*, void AquaSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout) { - mpBackend->drawTextLayout(rLayout); + mpBackend->drawTextLayout(rLayout, getTextRenderModeForResolutionIndependentLayoutEnabled()); } -void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout) +void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout, bool bTextRenderModeForResolutionIndependentLayout) { #ifdef IOS if (!mrShared.checkContext()) @@ -387,7 +387,7 @@ void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout) CTFontRef pFont = static_cast<CTFontRef>(CFDictionaryGetValue(rStyle.GetStyleDict(), kCTFontAttributeName)); CGAffineTransform aRotMatrix = CGAffineTransformMakeRotation(-rStyle.mfFontRotation); - Point aPos; + DevicePoint aPos; const GlyphItem* pGlyph; std::vector<CGGlyph> aGlyphIds; std::vector<CGPoint> aGlyphPos; @@ -395,7 +395,7 @@ void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout) int nStart = 0; while (rLayout.GetNextGlyph(&pGlyph, aPos, nStart)) { - CGPoint aGCPos = CGPointMake(aPos.X(), -aPos.Y()); + CGPoint aGCPos = CGPointMake(aPos.getX(), -aPos.getY()); // Whether the glyph should be upright in vertical mode or not bool bUprightGlyph = false; @@ -460,6 +460,14 @@ void AquaGraphicsBackend::drawTextLayout(const GenericSalLayout& rLayout) CGContextSetTextDrawingMode(mrShared.maContextHolder.get(), kCGTextFillStroke); } + if (bTextRenderModeForResolutionIndependentLayout) + { + CGContextSetAllowsFontSubpixelQuantization(mrShared.maContextHolder.get(), false); + CGContextSetShouldSubpixelQuantizeFonts(mrShared.maContextHolder.get(), false); + CGContextSetAllowsFontSubpixelPositioning(mrShared.maContextHolder.get(), true); + CGContextSetShouldSubpixelPositionFonts(mrShared.maContextHolder.get(), true); + } + auto aIt = aGlyphOrientation.cbegin(); while (aIt != aGlyphOrientation.cend()) { diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 55fed5b84e72..6d027a6f860a 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -2206,7 +2206,7 @@ void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Colo glyphIds.reserve(256); glyphForms.reserve(256); verticals.reserve(256); - Point aPos; + DevicePoint aPos; const GlyphItem* pGlyph; int nStart = 0; while (layout.GetNextGlyph(&pGlyph, aPos, nStart)) @@ -2215,7 +2215,7 @@ void SkiaSalGraphicsImpl::drawGenericLayout(const GenericSalLayout& layout, Colo Degree10 angle = layout.GetOrientation(); if (pGlyph->IsVertical()) angle += 900_deg10; - SkRSXform form = SkRSXform::Make(toCos(angle), toSin(angle), aPos.X(), aPos.Y()); + SkRSXform form = SkRSXform::Make(toCos(angle), toSin(angle), aPos.getX(), aPos.getY()); glyphForms.emplace_back(std::move(form)); verticals.emplace_back(pGlyph->IsVertical()); } diff --git a/vcl/skia/osx/gdiimpl.cxx b/vcl/skia/osx/gdiimpl.cxx index 126f43bb6ac3..4c9ae86dbadf 100644 --- a/vcl/skia/osx/gdiimpl.cxx +++ b/vcl/skia/osx/gdiimpl.cxx @@ -261,7 +261,8 @@ bool AquaSkiaSalGraphicsImpl::drawNativeControl(ControlType nType, ControlPart n return bOK; } -void AquaSkiaSalGraphicsImpl::drawTextLayout(const GenericSalLayout& rLayout) +void AquaSkiaSalGraphicsImpl::drawTextLayout(const GenericSalLayout& rLayout, + bool bSubpixelPositioning) { const CoreTextStyle& rStyle = *static_cast<const CoreTextStyle*>(&rLayout.GetFont()); const vcl::font::FontSelectPattern& rFontSelect = rStyle.GetFontSelectPattern(); @@ -295,8 +296,12 @@ void AquaSkiaSalGraphicsImpl::drawTextLayout(const GenericSalLayout& rLayout) // font.setScaleX(rStyle.mfFontStretch); TODO if (rStyle.mbFauxBold) font.setEmbolden(true); - font.setEdging(!mrShared.mbNonAntialiasedText ? SkFont::Edging::kAntiAlias - : SkFont::Edging::kAlias); + + SkFont::Edging ePreferredAliasing + = bSubpixelPositioning ? SkFont::Edging::kSubpixelAntiAlias : SkFont::Edging::kAntiAlias; + if (bSubpixelPositioning) + font.setSubpixel(true); + font.setEdging(mrShared.mbNonAntialiasedText ? SkFont::Edging::kAlias : ePreferredAliasing); // Vertical font, use width as "height". SkFont verticalFont(font); diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index a10351888eac..e9074340e66e 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -163,11 +163,7 @@ sk_sp<SkTypeface> WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO // different version of the same font installed system-wide). // For that CreateFromFaceFromHdc() is necessary. The simpler // CreateFontFromLOGFONT() seems to search for the best matching font, - // which may not be the exact font. Our private fonts are installed - // using AddFontResourceExW( FR_PRIVATE ) and that apparently does - // not make them available to DirectWrite (at least, they are not - // included the DWrite system font collection). For such cases, we'll - // need to fall back to Skia's GDI-based font rendering. + // which may not be the exact font. HFONT oldFont = SelectFont(hdc, hfont); sal::systools::COMReference<IDWriteFontFace> fontFace; if (FAILED(CHECKHR(dwriteGdiInterop->CreateFontFaceFromHdc(hdc, &fontFace)))) @@ -175,6 +171,7 @@ sk_sp<SkTypeface> WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO SelectFont(hdc, oldFont); return nullptr; } + SelectFont(hdc, oldFont); sal::systools::COMReference<IDWriteFontCollection> collection; if (FAILED(CHECKHR(dwriteFactory->GetSystemFontCollection(&collection)))) @@ -182,7 +179,66 @@ sk_sp<SkTypeface> WinSkiaSalGraphicsImpl::createDirectWriteTypeface(HDC hdc, HFO sal::systools::COMReference<IDWriteFont> font; // Do not use CHECKHR() here, as said above, this fails for our fonts. if (FAILED(collection->GetFontFromFontFace(fontFace.get(), &font))) - return nullptr; + { + // If not found in system collection, try our private font collection. + // If that's not possible we'll fall back to Skia's GDI-based font rendering. + if (!dwritePrivateCollection + || FAILED(dwritePrivateCollection->GetFontFromFontFace(fontFace.get(), &font))) + { + // Our private fonts are installed using AddFontResourceExW( FR_PRIVATE ) + // and that does not make them available to the DWrite system font + // collection. For such cases attempt to update a collection of + // private fonts with this newly used font. + + sal::systools::COMReference<IDWriteFactory3> dwriteFactory3; + if (FAILED(dwriteFactory->QueryInterface<IDWriteFactory3>(&dwriteFactory3))) + return nullptr; + + if (!dwriteFontSetBuilder + && FAILED(dwriteFactory3->CreateFontSetBuilder(&dwriteFontSetBuilder))) + return nullptr; + + UINT32 numberOfFiles; + if (FAILED(fontFace->GetFiles(&numberOfFiles, nullptr)) || numberOfFiles != 1) + return nullptr; + + sal::systools::COMReference<IDWriteFontFile> fontFile; + if (FAILED(fontFace->GetFiles(&numberOfFiles, &fontFile))) + return nullptr; + + BOOL isSupported; + DWRITE_FONT_FILE_TYPE fileType; + UINT32 numberOfFonts; + if (FAILED(fontFile->Analyze(&isSupported, &fileType, nullptr, &numberOfFonts)) + || !isSupported) + return nullptr; + + // For each font within the font file, get a font face reference and add to the builder. + for (UINT32 fontIndex = 0; fontIndex < numberOfFonts; ++fontIndex) + { + sal::systools::COMReference<IDWriteFontFaceReference> fontFaceReference; + if (FAILED(dwriteFactory3->CreateFontFaceReference(fontFile.get(), fontIndex, + DWRITE_FONT_SIMULATIONS_NONE, + &fontFaceReference))) + continue; + + // Leave it to DirectWrite to read properties directly out of the font files + dwriteFontSetBuilder->AddFontFaceReference(fontFaceReference.get()); + } + + dwritePrivateCollection.clear(); + sal::systools::COMReference<IDWriteFontSet> fontSet; + if (SUCCEEDED(CHECKHR(dwriteFontSetBuilder->CreateFontSet(&fontSet)))) + dwriteFactory3->CreateFontCollectionFromFontSet(fontSet.get(), + &dwritePrivateCollection); + } + + if (!dwritePrivateCollection) + return nullptr; + // CHECKHR because we expect to succeed here + if (FAILED(CHECKHR(dwritePrivateCollection->GetFontFromFontFace(fontFace.get(), &font)))) + return nullptr; + } sal::systools::COMReference<IDWriteFontFamily> fontFamily; if (FAILED(CHECKHR(font->GetFontFamily(&fontFamily)))) return nullptr; @@ -231,8 +287,14 @@ bool WinSkiaSalGraphicsImpl::DrawTextLayout(const GenericSalLayout& rLayout) } SkFont font(typeface); + + bool bSubpixelPositioning = mWinParent.getTextRenderModeForResolutionIndependentLayoutEnabled(); + SkFont::Edging ePreferredAliasing + = bSubpixelPositioning ? SkFont::Edging::kSubpixelAntiAlias : fontEdging; + if (bSubpixelPositioning) + font.setSubpixel(true); font.setEdging(logFont.lfQuality == NONANTIALIASED_QUALITY ? SkFont::Edging::kAlias - : fontEdging); + : ePreferredAliasing); const vcl::font::FontSelectPattern& rFSD = pWinFont->GetFontSelectPattern(); int nHeight = rFSD.mnHeight; @@ -296,6 +358,8 @@ void WinSkiaSalGraphicsImpl::initFontInfo() void WinSkiaSalGraphicsImpl::ClearDevFontCache() { dwriteFontMgr.reset(); + dwriteFontSetBuilder.clear(); + dwritePrivateCollection.clear(); dwriteFactory.clear(); dwriteGdiInterop.clear(); dwriteDone = false; diff --git a/vcl/skia/x11/textrender.cxx b/vcl/skia/x11/textrender.cxx index a2d0dcbb36f6..9fda8ba6601c 100644 --- a/vcl/skia/x11/textrender.cxx +++ b/vcl/skia/x11/textrender.cxx @@ -57,8 +57,22 @@ void SkiaTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const SalGr font.setSkewX(1.0 * -0x4000L / 0x10000L); if (rFont.NeedsArtificialBold()) font.setEmbolden(true); - font.setEdging(rFont.GetAntialiasAdvice() ? SkFont::Edging::kAntiAlias - : SkFont::Edging::kAlias); + + bool bSubpixelPositioning = rGraphics.getTextRenderModeForResolutionIndependentLayoutEnabled(); + SkFont::Edging ePreferredAliasing + = bSubpixelPositioning ? SkFont::Edging::kSubpixelAntiAlias : SkFont::Edging::kAntiAlias; + if (bSubpixelPositioning) + { + font.setSubpixel(true); + + SkFontHinting eHinting = font.getHinting(); + bool bAllowedHintStyle + = eHinting == SkFontHinting::kNone || eHinting == SkFontHinting::kSlight; + if (!bAllowedHintStyle) + font.setHinting(SkFontHinting::kSlight); + } + + font.setEdging(rFont.GetAntialiasAdvice() ? ePreferredAliasing : SkFont::Edging::kAlias); // Vertical font, use width as "height". SkFont verticalFont(font); diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx index 13bc53ebbdab..811849309d67 100644 --- a/vcl/source/gdi/CommonSalLayout.cxx +++ b/vcl/source/gdi/CommonSalLayout.cxx @@ -197,7 +197,9 @@ void GenericSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); - if (rArgs.mpDXArray) + if (rArgs.mpAltNaturalDXArray) // Used when "TextRenderModeForResolutionIndependentLayout" is set + ApplyDXArray(rArgs.mpAltNaturalDXArray, rArgs.mnFlags); + else if (rArgs.mpDXArray) // Normal case ApplyDXArray(rArgs.mpDXArray, rArgs.mnFlags); else if (rArgs.mnLayoutWidth) Justify(rArgs.mnLayoutWidth); @@ -331,7 +333,7 @@ bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay double nYScale = 0; GetFont().GetScale(&nXScale, &nYScale); - Point aCurrPos(0, 0); + DevicePoint aCurrPos(0, 0); while (true) { int nBidiMinRunPos, nBidiEndRunPos; @@ -584,12 +586,12 @@ bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLay nXOffset = std::lround(nXOffset * nXScale); nYOffset = std::lround(nYOffset * nYScale); - Point aNewPos(aCurrPos.X() + nXOffset, aCurrPos.Y() + nYOffset); + DevicePoint aNewPos(aCurrPos.getX() + nXOffset, aCurrPos.getY() + nYOffset); const GlyphItem aGI(nCharPos, nCharCount, nGlyphIndex, aNewPos, nGlyphFlags, nAdvance, nXOffset); m_GlyphItems.push_back(aGI); - aCurrPos.AdjustX(nAdvance ); + aCurrPos.adjustX(nAdvance); } } } @@ -635,12 +637,12 @@ void GenericSalLayout::GetCharWidths(std::vector<DeviceCoordinate>& rCharWidths) // * Check the above flag to decide whether to insert Kashidas or not. // * For any RTL glyph that has DX adjustment, insert enough Kashidas to // fill in the added space. - -void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutFlags nLayoutFlags) +template<typename DC> +void GenericSalLayout::ApplyDXArray(const DC* pDXArray, SalLayoutFlags nLayoutFlags) { int nCharCount = mnEndCharPos - mnMinCharPos; std::vector<DeviceCoordinate> aOldCharWidths; - std::unique_ptr<DeviceCoordinate[]> const pNewCharWidths(new DeviceCoordinate[nCharCount]); + std::unique_ptr<DC[]> const pNewCharWidths(new DC[nCharCount]); // Get the natural character widths (i.e. before applying DX adjustments). GetCharWidths(aOldCharWidths); @@ -671,7 +673,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF std::map<size_t, DeviceCoordinate> pKashidas; // The accumulated difference in X position. - DeviceCoordinate nDelta = 0; + DC nDelta = 0; // Apply the DX adjustments to glyph positions and widths. size_t i = 0; @@ -680,7 +682,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF // Accumulate the width difference for all characters corresponding to // this glyph. int nCharPos = m_GlyphItems[i].charPos() - mnMinCharPos; - DeviceCoordinate nDiff = 0; + DC nDiff = 0; for (int j = 0; j < m_GlyphItems[i].charCount(); j++) nDiff += pNewCharWidths[nCharPos + j] - aOldCharWidths[nCharPos + j]; @@ -689,14 +691,14 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF // Adjust the width and position of the first (leftmost) glyph in // the cluster. m_GlyphItems[i].m_nNewWidth += nDiff; - m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta); + m_GlyphItems[i].m_aLinearPos.adjustX(nDelta); // Adjust the position of the rest of the glyphs in the cluster. while (++i < m_GlyphItems.size()) { if (!m_GlyphItems[i].IsInCluster()) break; - m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta); + m_GlyphItems[i].m_aLinearPos.adjustX(nDelta); } } else if (m_GlyphItems[i].IsInCluster()) @@ -711,7 +713,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF // the cluster. // For RTL, we put all the adjustment to the left of the glyph. m_GlyphItems[i].m_nNewWidth += nDiff; - m_GlyphItems[i].m_aLinearPos.AdjustX(nDelta + nDiff); + m_GlyphItems[i].m_aLinearPos.adjustX(nDelta + nDiff); // Adjust the X position of all glyphs in the cluster. size_t j = i; @@ -720,7 +722,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF --j; if (!m_GlyphItems[j].IsInCluster()) break; - m_GlyphItems[j].m_aLinearPos.AdjustX(nDelta + nDiff); + m_GlyphItems[j].m_aLinearPos.adjustX(nDelta + nDiff); } // If this glyph is Kashida-justifiable, then mark this as a @@ -737,7 +739,7 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF { if (!m_GlyphItems[j].IsDiacritic()) break; - m_GlyphItems[j--].m_aLinearPos.AdjustX(nDiff); + m_GlyphItems[j--].m_aLinearPos.adjustX(nDiff); } } i++; @@ -779,15 +781,14 @@ void GenericSalLayout::ApplyDXArray(const DeviceCoordinate* pDXArray, SalLayoutF nOverlap = nExcess / (nCopies - 1); } - Point aPos(pGlyphIter->m_aLinearPos.getX() - nTotalWidth, 0); + DevicePoint aPos(pGlyphIter->m_aLinearPos.getX() - nTotalWidth, 0); int nCharPos = pGlyphIter->charPos(); GlyphItemFlags const nFlags = GlyphItemFlags::IS_IN_CLUSTER | GlyphItemFlags::IS_RTL_GLYPH; while (nCopies--) { GlyphItem aKashida(nCharPos, 0, nKashidaIndex, aPos, nFlags, nKashidaWidth, 0); pGlyphIter = m_GlyphItems.insert(pGlyphIter, aKashida); - aPos.AdjustX(nKashidaWidth ); - aPos.AdjustX( -nOverlap ); + aPos.adjustX(nKashidaWidth - nOverlap); ++pGlyphIter; ++nInserted; } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 6f10c891330d..c418baab334d 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -3895,7 +3895,7 @@ void PDFWriterImpl::createDefaultCheckBoxAppearance( PDFWidget& rBox, const PDFW // make sure OpenSymbol is embedded, and includes our checkmark const sal_Unicode cMark=0x2713; const GlyphItem aItem(0, 0, pMap->GetGlyphIndex(cMark), - Point(), GlyphItemFlags::NONE, 0, 0); + DevicePoint(), GlyphItemFlags::NONE, 0, 0); const std::vector<sal_Ucs> aCodeUnits={ cMark }; sal_uInt8 nMappedGlyph; sal_Int32 nMappedFontObject; @@ -5804,9 +5804,9 @@ void PDFWriterImpl::drawShadow( SalLayout& rLayout, const OUString& rText, bool tools::Long nOff = 1 + ((GetFontInstance()->mnLineHeight-24)/24); if( rFont.IsOutline() ) nOff++; - rLayout.DrawBase() += Point( nOff, nOff ); + rLayout.DrawBase() += DevicePoint(nOff, nOff); drawLayout( rLayout, rText, bTextLines ); - rLayout.DrawBase() -= Point( nOff, nOff ); + rLayout.DrawBase() -= DevicePoint(nOff, nOff); setFont( aSaveFont ); setTextLineColor( aSaveTextLineColor ); @@ -6129,7 +6129,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool std::vector< PDFGlyph > aGlyphs; aGlyphs.reserve( nMaxGlyphs ); // first get all the glyphs and register them; coordinates still in Pixel - Point aPos; + DevicePoint aPos; while (rLayout.GetNextGlyph(&pGlyph, aPos, nIndex, nullptr, &pFallbackFont)) { const auto* pFont = pFallbackFont ? pFallbackFont : pDevFont; @@ -6202,7 +6202,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool if (bUseActualText || pGlyph->IsInCluster()) nCharPos = pGlyph->charPos(); - aGlyphs.emplace_back(aPos, + aGlyphs.emplace_back(Point(aPos.getX(), aPos.getY()), pGlyph, nGlyphWidth, nMappedFontObject, @@ -6225,7 +6225,8 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool // The rectangle is the bounding box of the text, but also includes // ascent / descent to match the on-screen rendering. // This is the top left of the text without ascent / descent. - tools::Rectangle aRectangle(PixelToLogic(rLayout.GetDrawPosition()), + DevicePoint aDrawPosition(rLayout.GetDrawPosition()); + tools::Rectangle aRectangle(PixelToLogic(Point(aDrawPosition.getX(), aDrawPosition.getY())), Size(ImplDevicePixelToLogicWidth(rLayout.GetTextWidth()), 0)); aRectangle.AdjustTop(-aRefDevFontMetric.GetAscent()); // This includes ascent / descent. @@ -6236,7 +6237,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool { // Adapt rectangle for rotated text. tools::Polygon aPolygon(aRectangle); - aPolygon.Rotate(PixelToLogic(rLayout.GetDrawPosition()), pFontInstance->mnOrientation); + aPolygon.Rotate(PixelToLogic(Point(aDrawPosition.getX(), aDrawPosition.getY())), pFontInstance->mnOrientation); drawPolygon(aPolygon); } else @@ -6333,7 +6334,7 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool if (!pGlyph->IsSpacing()) { if( !nWidth ) - aStartPt = aPos; + aStartPt = Point(aPos.getX(), aPos.getY()); nWidth += pGlyph->m_nNewWidth; } @@ -6355,9 +6356,9 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool } else { - Point aStartPt = rLayout.GetDrawPosition(); + DevicePoint aStartPt = rLayout.GetDrawPosition(); int nWidth = rLayout.GetTextWidth() / rLayout.GetUnitsPerPixel(); - drawTextLine( PixelToLogic( aStartPt ), + drawTextLine( PixelToLogic(Point(aStartPt.getX(), aStartPt.getY()) ), ImplDevicePixelToLogicWidth( nWidth ), eStrikeout, eUnderline, eOverline, bUnderlineAbove ); } @@ -6433,9 +6434,10 @@ void PDFWriterImpl::drawLayout( SalLayout& rLayout, const OUString& rText, bool aAdjOffset -= Point( nEmphWidth2, nEmphHeight2 ); - aPos += aAdjOffset; - aPos = PixelToLogic( aPos ); - drawEmphasisMark( aPos.X(), aPos.Y(), + Point aMarkPos(aPos.getX(), aPos.getY()); + aMarkPos += aAdjOffset; + aMarkPos = PixelToLogic(aMarkPos); + drawEmphasisMark( aMarkPos.X(), aMarkPos.Y(), aEmphPoly, bEmphPolyLine, aEmphRect1, aEmphRect2 ); } diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx index 2a0d27cbc24e..34f54a8ce870 100644 --- a/vcl/source/gdi/salgdilayout.cxx +++ b/vcl/source/gdi/salgdilayout.cxx @@ -55,7 +55,8 @@ SalGraphics::SalGraphics() m_aLastMirrorW(0), m_nLastMirrorDeviceLTRButBiDiRtlTranslate(0), m_bLastMirrorDeviceLTRButBiDiRtlSet(false), - m_bAntiAlias(false) + m_bAntiAlias(false), + m_bTextRenderModeForResolutionIndependentLayout(false) { // read global RTL settings if( AllSettings::GetLayoutRTL() ) diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx index ebf10bf8e17c..abad66427491 100644 --- a/vcl/source/gdi/sallayout.cxx +++ b/vcl/source/gdi/sallayout.cxx @@ -135,7 +135,8 @@ SalLayout::SalLayout() mnEndCharPos( -1 ), mnUnitsPerPixel( 1 ), mnOrientation( 0 ), - maDrawOffset( 0, 0 ) + maDrawOffset( 0, 0 ), + mbTextRenderModeForResolutionIndependentLayout(false) {} SalLayout::~SalLayout() @@ -148,10 +149,11 @@ void SalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) mnOrientation = rArgs.mnOrientation; } -Point SalLayout::GetDrawPosition( const Point& rRelative ) const +DevicePoint SalLayout::GetDrawPosition(const DevicePoint& rRelative) const { - Point aPos = maDrawBase; - Point aOfs = rRelative + maDrawOffset; + DevicePoint aPos(maDrawBase); + DevicePoint aOfs(rRelative.getX() + maDrawOffset.X(), + rRelative.getY() + maDrawOffset.Y()); if( mnOrientation == 0_deg10 ) aPos += aOfs; @@ -168,11 +170,20 @@ Point SalLayout::GetDrawPosition( const Point& rRelative ) const fSin = sin( fRad ); } - double fX = aOfs.X(); - double fY = aOfs.Y(); - tools::Long nX = static_cast<tools::Long>( +fCos * fX + fSin * fY ); - tools::Long nY = static_cast<tools::Long>( +fCos * fY - fSin * fX ); - aPos += Point( nX, nY ); + double fX = aOfs.getX(); + double fY = aOfs.getY(); + if (mbTextRenderModeForResolutionIndependentLayout) + { + double nX = +fCos * fX + fSin * fY; + double nY = +fCos * fY - fSin * fX; + aPos += DevicePoint(nX, nY); + } + else + { + tools::Long nX = static_cast<tools::Long>( +fCos * fX + fSin * fY ); + tools::Long nY = static_cast<tools::Long>( +fCos * fY - fSin * fX ); + aPos += DevicePoint(nX, nY); + } } return aPos; @@ -185,7 +196,7 @@ bool SalLayout::GetOutline(basegfx::B2DPolyPolygonVector& rVector) const basegfx::B2DPolyPolygon aGlyphOutline; - Point aPos; + DevicePoint aPos; const GlyphItem* pGlyph; int nStart = 0; const LogicalFontInstance* pGlyphFont; @@ -198,9 +209,9 @@ bool SalLayout::GetOutline(basegfx::B2DPolyPolygonVector& rVector) const // only add non-empty outlines if( bSuccess && (aGlyphOutline.count() > 0) ) { - if( aPos.X() || aPos.Y() ) + if( aPos.getX() || aPos.getY() ) { - aGlyphOutline.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos.X(), aPos.Y())); + aGlyphOutline.transform(basegfx::utils::createTranslateB2DHomMatrix(aPos.getX(), aPos.getY())); } // insert outline at correct position @@ -218,7 +229,7 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const tools::Rectangle aRectangle; - Point aPos; + DevicePoint aPos; const GlyphItem* pGlyph; int nStart = 0; const LogicalFontInstance* pGlyphFont; @@ -228,7 +239,7 @@ bool SalLayout::GetBoundRect(tools::Rectangle& rRect) const if (pGlyph->GetGlyphBoundRect(pGlyphFont, aRectangle)) { // merge rectangle - aRectangle += aPos; + aRectangle += Point(aPos.getX(), aPos.getY()); if (rRect.IsEmpty()) rRect = aRectangle; else @@ -322,7 +333,7 @@ void GenericSalLayout::Justify( DeviceCoordinate nNewWidth ) for( pGlyphIter = m_GlyphItems.begin(); pGlyphIter != pGlyphIterRight; ++pGlyphIter ) { // move glyph to justified position - pGlyphIter->m_aLinearPos.AdjustX(nDeltaSum ); + pGlyphIter->m_aLinearPos.adjustX(nDeltaSum); // do not stretch non-stretchable glyphs if( pGlyphIter->IsDiacritic() || (nStretchable <= 0) ) @@ -438,7 +449,7 @@ void GenericSalLayout::ApplyAsianKerning(const OUString& rStr) // adjust the glyph positions to the new glyph widths if( pGlyphIter+1 != pGlyphIterEnd ) - pGlyphIter->m_aLinearPos.AdjustX(nOffset); + pGlyphIter->m_aLinearPos.adjustX(nOffset); } } @@ -491,7 +502,7 @@ sal_Int32 GenericSalLayout::GetTextBreak( DeviceCoordinate nMaxWidth, DeviceCoor } bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph, - Point& rPos, int& nStart, + DevicePoint& rPos, int& nStart, const LogicalFontInstance** ppGlyphFont, const vcl::font::PhysicalFontFace**) const { @@ -521,10 +532,10 @@ bool GenericSalLayout::GetNextGlyph(const GlyphItem** pGlyph, *ppGlyphFont = m_GlyphItems.GetFont().get(); // calculate absolute position in pixel units - Point aRelativePos = pGlyphIter->m_aLinearPos; + DevicePoint aRelativePos = pGlyphIter->m_aLinearPos; - aRelativePos.setX( aRelativePos.X() / mnUnitsPerPixel ); - aRelativePos.setY( aRelativePos.Y() / mnUnitsPerPixel ); + aRelativePos.setX( aRelativePos.getX() / mnUnitsPerPixel ); + aRelativePos.setY( aRelativePos.getY() / mnUnitsPerPixel ); rPos = GetDrawPosition( aRelativePos ); return true; @@ -550,7 +561,7 @@ void GenericSalLayout::MoveGlyph( int nStart, tools::Long nNewXPos ) { for( std::vector<GlyphItem>::iterator pGlyphIterEnd = m_GlyphItems.end(); pGlyphIter != pGlyphIterEnd; ++pGlyphIter ) { - pGlyphIter->m_aLinearPos.AdjustX(nXDelta ); + pGlyphIter->m_aLinearPos.adjustX(nXDelta); } } } @@ -637,7 +648,7 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) vcl::text::ImplLayoutArgs aMultiArgs = rArgs; std::vector<DeviceCoordinate> aJustificationArray; - if( !rArgs.mpDXArray && rArgs.mnLayoutWidth ) + if( !rArgs.HasDXArray() && rArgs.mnLayoutWidth ) { // for stretched text in a MultiSalLayout the target width needs to be // distributed by individually adjusting its virtual character widths @@ -702,6 +713,17 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) } } + if (aMultiArgs.mpAltNaturalDXArray) + ImplAdjustMultiLayout(rArgs, aMultiArgs, aMultiArgs.mpAltNaturalDXArray); + else + ImplAdjustMultiLayout(rArgs, aMultiArgs, aMultiArgs.mpDXArray); +} + +template<typename DC> +void MultiSalLayout::ImplAdjustMultiLayout(vcl::text::ImplLayoutArgs& rArgs, + vcl::text::ImplLayoutArgs& rMultiArgs, + const DC* pMultiDXArray) +{ // Compute rtl flags, since in some scripts glyphs/char order can be // reversed for a few character sequences e.g. Myanmar std::vector<bool> vRtl(rArgs.mnEndCharPos - rArgs.mnMinCharPos, false); @@ -721,17 +743,17 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) const GlyphItem* pGlyphs[MAX_FALLBACK]; bool bValid[MAX_FALLBACK] = { false }; - Point aPos; + DevicePoint aPos; int nLevel = 0, n; for( n = 0; n < mnLevel; ++n ) { // now adjust the individual components if( n > 0 ) { - aMultiArgs.maRuns = maFallbackRuns[ n-1 ]; - aMultiArgs.mnFlags |= SalLayoutFlags::ForFallback; + rMultiArgs.maRuns = maFallbackRuns[ n-1 ]; + rMultiArgs.mnFlags |= SalLayoutFlags::ForFallback; } - mpLayouts[n]->AdjustLayout( aMultiArgs ); + mpLayouts[n]->AdjustLayout( rMultiArgs ); // remove unused parts of component if( n > 0 ) @@ -830,7 +852,7 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) } // skip to end of layout run and calculate its advance width - DeviceCoordinate nRunAdvance = 0; + DC nRunAdvance = 0; bool bKeepNotDef = (nFBLevel >= nLevel); for(;;) { @@ -886,7 +908,7 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) bKeepNotDef = bNeedFallback; } // check for reordered glyphs - if (aMultiArgs.mpDXArray && + if (pMultiDXArray && nRunVisibleEndChar < mnEndCharPos && nRunVisibleEndChar >= mnMinCharPos && pGlyphs[n]->charPos() < mnEndCharPos && @@ -894,14 +916,14 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) { if (vRtl[nActiveCharPos - mnMinCharPos]) { - if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos] - >= aMultiArgs.mpDXArray[pGlyphs[n]->charPos() - mnMinCharPos]) + if (pMultiDXArray[nRunVisibleEndChar-mnMinCharPos] + >= pMultiDXArray[pGlyphs[n]->charPos() - mnMinCharPos]) { nRunVisibleEndChar = pGlyphs[n]->charPos(); } } - else if (aMultiArgs.mpDXArray[nRunVisibleEndChar-mnMinCharPos] - <= aMultiArgs.mpDXArray[pGlyphs[n]->charPos() - mnMinCharPos]) + else if (pMultiDXArray[nRunVisibleEndChar-mnMinCharPos] + <= pMultiDXArray[pGlyphs[n]->charPos() - mnMinCharPos]) { nRunVisibleEndChar = pGlyphs[n]->charPos(); } @@ -910,7 +932,7 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) // if a justification array is available // => use it directly to calculate the corresponding run width - if( aMultiArgs.mpDXArray ) + if (pMultiDXArray) { // the run advance is the width from the first char // in the run to the first char in the next run @@ -919,16 +941,16 @@ void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs ) if (nActiveCharIndex >= 0 && vRtl[nActiveCharIndex]) { if (nRunVisibleEndChar > mnMinCharPos && nRunVisibleEndChar <= mnEndCharPos) - nRunAdvance -= aMultiArgs.mpDXArray[nRunVisibleEndChar - 1 - mnMinCharPos]; + nRunAdvance -= pMultiDXArray[nRunVisibleEndChar - 1 - mnMinCharPos]; if (nLastRunEndChar > mnMinCharPos && nLastRunEndChar <= mnEndCharPos) - nRunAdvance += aMultiArgs.mpDXArray[nLastRunEndChar - 1 - mnMinCharPos]; + nRunAdvance += pMultiDXArray[nLastRunEndChar - 1 - mnMinCharPos]; } else { if (nRunVisibleEndChar >= mnMinCharPos) - nRunAdvance += aMultiArgs.mpDXArray[nRunVisibleEndChar - mnMinCharPos]; + nRunAdvance += pMultiDXArray[nRunVisibleEndChar - mnMinCharPos]; if (nLastRunEndChar >= mnMinCharPos) - nRunAdvance -= aMultiArgs.mpDXArray[nLastRunEndChar - mnMinCharPos]; + nRunAdvance -= pMultiDXArray[nLastRunEndChar - mnMinCharPos]; } nLastRunEndChar = nRunVisibleEndChar; nRunVisibleEndChar = pGlyphs[nFirstValid]->charPos(); @@ -1105,7 +1127,7 @@ void MultiSalLayout::GetCaretPositions( int nMaxIndex, sal_Int32* pCaretXArray ) } bool MultiSalLayout::GetNextGlyph(const GlyphItem** pGlyph, - Point& rPos, int& nStart, + DevicePoint& rPos, int& nStart, const LogicalFontInstance** ppGlyphFont, const vcl::font::PhysicalFontFace** pFallbackFont) const { @@ -1123,8 +1145,8 @@ bool MultiSalLayout::GetNextGlyph(const GlyphItem** pGlyph, nStart |= nFontTag; if (pFallbackFont) *pFallbackFont = pFontFace; - rPos += maDrawBase; - rPos += maDrawOffset; + rPos.adjustX(maDrawBase.getX() + maDrawOffset.X()); + rPos.adjustY(maDrawBase.getY() + maDrawOffset.Y()); return true; } } diff --git a/vcl/source/gdi/virdev.cxx b/vcl/source/gdi/virdev.cxx index 6a44cc1cd136..87721c683d77 100644 --- a/vcl/source/gdi/virdev.cxx +++ b/vcl/source/gdi/virdev.cxx @@ -379,6 +379,8 @@ bool VirtualDevice::ImplSetOutputSizePixel( const Size& rNewSize, bool bErase, mpAlphaVDev->SetMapMode( GetMapMode() ); mpAlphaVDev->SetAntialiasing( GetAntialiasing() ); + + mpAlphaVDev->SetTextRenderModeForResolutionIndependentLayout(GetTextRenderModeForResolutionIndependentLayout()); } return true; diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx index 5139f1fc03a4..71e4091e754e 100644 --- a/vcl/source/outdev/font.cxx +++ b/vcl/source/outdev/font.cxx @@ -1117,7 +1117,7 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) tools::Long nEmphasisHeight2 = nEmphasisHeight / 2; aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 ); - Point aOutPoint; + DevicePoint aOutPoint; tools::Rectangle aRectangle; const GlyphItem* pGlyph; const LogicalFontInstance* pGlyphFont; @@ -1136,10 +1136,10 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout ) Point aOriginPt(0, 0); aOriginPt.RotateAround( aAdjPoint, mpFontInstance->mnOrientation ); } - aOutPoint += aAdjPoint; - aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 ); - ImplDrawEmphasisMark( rSalLayout.DrawBase().X(), - aOutPoint.X(), aOutPoint.Y(), + aOutPoint.adjustX(aAdjPoint.X() - nEmphasisWidth2); + aOutPoint.adjustY(aAdjPoint.Y() - nEmphasisHeight2); + ImplDrawEmphasisMark( rSalLayout.DrawBase().getX(), + aOutPoint.getX(), aOutPoint.getY(), aPolyPoly, bPolyLine, aRect1, aRect2 ); } } diff --git a/vcl/source/outdev/map.cxx b/vcl/source/outdev/map.cxx index 227905f075a8..bb4683f37a19 100644 --- a/vcl/source/outdev/map.cxx +++ b/vcl/source/outdev/map.cxx @@ -1879,11 +1879,32 @@ DeviceCoordinate OutputDevice::LogicWidthToDeviceCoordinate( tools::Long nWidth return static_cast<DeviceCoordinate>(nWidth); #if VCL_FLOAT_DEVICE_PIXEL - return (double)nWidth * maMapRes.mfScaleX * mnDPIX; + return ImplLogicToPixel(static_cast<double>(nWidth), mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX); #else - return ImplLogicToPixel(nWidth, mnDPIX, maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX); #endif } +double OutputDevice::ImplLogicWidthToDeviceFontWidth(tools::Long nWidth) const +{ + if (!mbMap) + return nWidth; + + return ImplLogicToPixel(static_cast<double>(nWidth), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX); +} + +DevicePoint OutputDevice::ImplLogicToDeviceFontCoordinate(const Point& rPoint) const +{ + if (!mbMap) + return DevicePoint(rPoint.X() + mnOutOffX, rPoint.Y() + mnOutOffY); + + return DevicePoint(ImplLogicToPixel(static_cast<double>(rPoint.X() + maMapRes.mnMapOfsX), mnDPIX, + maMapRes.mnMapScNumX, maMapRes.mnMapScDenomX) + + mnOutOffX + mnOutOffOrigX, + ImplLogicToPixel(static_cast<double>(rPoint.Y() + maMapRes.mnMapOfsY), mnDPIY, + maMapRes.mnMapScNumY, maMapRes.mnMapScDenomY) + + mnOutOffY + mnOutOffOrigY); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx index 9231f7779a6b..1ad7a2e71dd0 100644 --- a/vcl/source/outdev/outdev.cxx +++ b/vcl/source/outdev/outdev.cxx @@ -105,6 +105,7 @@ OutputDevice::OutputDevice(OutDevType eOutDevType) : meRasterOp = RasterOp::OverPaint; mnAntialiasing = AntialiasingFlags::NONE; meTextLanguage = LANGUAGE_SYSTEM; // TODO: get default from configuration? + mbTextRenderModeForResolutionIndependentLayout = false; mbLineColor = true; mbFillColor = true; mbInitLineColor = true; @@ -354,16 +355,28 @@ void OutputDevice::SetAntialiasing( AntialiasingFlags nMode ) mnAntialiasing = nMode; mbInitFont = true; - if(mpGraphics) - { + if (mpGraphics) mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable)); - } } if( mpAlphaVDev ) mpAlphaVDev->SetAntialiasing( nMode ); } +void OutputDevice::SetTextRenderModeForResolutionIndependentLayout(bool bMode) +{ + if (mbTextRenderModeForResolutionIndependentLayout!= bMode) + { + mbTextRenderModeForResolutionIndependentLayout = bMode; + + if (mpGraphics) + mpGraphics->setTextRenderModeForResolutionIndependentLayout(bMode); + } + + if (mpAlphaVDev) + mpAlphaVDev->SetTextRenderModeForResolutionIndependentLayout(bMode); +} + void OutputDevice::SetDrawMode(DrawModeFlags nDrawMode) { mnDrawMode = nDrawMode; diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx index a28dc49e5ebd..3d773e56d488 100644 --- a/vcl/source/outdev/text.cxx +++ b/vcl/source/outdev/text.cxx @@ -168,9 +168,9 @@ void OutputDevice::ImplDrawTextRect( tools::Long nBaseX, tools::Long nBaseY, void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout ) { const tools::Long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel(); - const Point aBase = rSalLayout.DrawBase(); - const tools::Long nX = aBase.X(); - const tools::Long nY = aBase.Y(); + const DevicePoint aBase = rSalLayout.DrawBase(); + const tools::Long nX = aBase.getX(); + const tools::Long nY = aBase.getY(); if ( mbLineColor || mbInitLineColor ) { @@ -187,9 +187,9 @@ void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout ) tools::Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout ) const { - Point aPoint = rSalLayout.GetDrawPosition(); - tools::Long nX = aPoint.X(); - tools::Long nY = aPoint.Y(); + DevicePoint aPoint = rSalLayout.GetDrawPosition(); + tools::Long nX = aPoint.getX(); + tools::Long nY = aPoint.getY(); tools::Long nWidth = rSalLayout.GetTextWidth(); tools::Long nHeight = mpFontInstance->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent; @@ -225,11 +225,11 @@ tools::Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout ) { - tools::Long nX = rSalLayout.DrawBase().X(); - tools::Long nY = rSalLayout.DrawBase().Y(); + tools::Long nX = rSalLayout.DrawBase().getX(); + tools::Long nY = rSalLayout.DrawBase().getY(); tools::Rectangle aBoundRect; - rSalLayout.DrawBase() = Point( 0, 0 ); + rSalLayout.DrawBase() = DevicePoint( 0, 0 ); rSalLayout.DrawOffset() = Point( 0, 0 ); if (!rSalLayout.GetBoundRect(aBoundRect)) { @@ -261,7 +261,8 @@ bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout ) pVDev->ImplInitTextColor(); // draw text into upper left corner - rSalLayout.DrawBase() -= aBoundRect.TopLeft(); + rSalLayout.DrawBase().adjustX(-aBoundRect.Left()); + rSalLayout.DrawBase().adjustY(-aBoundRect.Top()); rSalLayout.DrawText( *pVDev->mpGraphics ); Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() ); @@ -302,18 +303,18 @@ void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, if( ImplDrawRotateText( rSalLayout ) ) return; - tools::Long nOldX = rSalLayout.DrawBase().X(); + auto nOldX = rSalLayout.DrawBase().getX(); if( HasMirroredGraphics() ) { tools::Long w = IsVirtual() ? mnOutWidth : mpGraphics->GetGraphicsWidth(); - tools::Long x = rSalLayout.DrawBase().X(); + auto x = rSalLayout.DrawBase().getX(); rSalLayout.DrawBase().setX( w - 1 - x ); if( !IsRTLEnabled() ) { OutputDevice *pOutDevRef = this; // mirror this window back tools::Long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX - rSalLayout.DrawBase().setX( devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ) ; + rSalLayout.DrawBase().setX( devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().getX() - devX) ) ) ; } } else if( IsRTLEnabled() ) @@ -322,7 +323,7 @@ void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, // mirror this window back tools::Long devX = pOutDevRef->mnOutOffX; // re-mirrored mnOutOffX - rSalLayout.DrawBase().setX( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX ); + rSalLayout.DrawBase().setX( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().getX() - devX) + devX ); } rSalLayout.DrawText( *mpGraphics ); @@ -345,7 +346,7 @@ void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout ) Color aOldOverlineColor = GetOverlineColor(); FontRelief eRelief = maFont.GetRelief(); - Point aOrigPos = rSalLayout.DrawBase(); ... etc. - the rest is truncated